diff --git a/.gitignore b/.gitignore index c5a6cd9..759898f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ +.DS_Store *~ tty.alfred3workflow diff --git a/README.md b/README.md index c545b4b..cd5b1a1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ^tty workflow for Alfred -A JXA-based workflow for [Alfred](http://www.alfredapp.com/) Powerpack users to quickly switch between or close iTerm windows, tabs and panes based on title and tty. +A JXA-based workflow for [Alfred](http://www.alfredapp.com/) Powerpack users to quickly switch between or close iTerm windows, tabs and panes based on title and tty, or trigger your preferred ssh workflow when no open session is found. ## Releases - [Latest for Alfred 3.x](https://github.com/isometry/alfred-tty/releases/latest) @@ -14,12 +14,14 @@ A JXA-based workflow for [Alfred](http://www.alfredapp.com/) Powerpack users to ## Usage -Type `tty` in Alfred followed by some characters from the title of an open window, tab or pane; press `Enter` to activate the selected window/tab/pane, or Alt-Enter` to close it. For example, enter `tty as3` to switch to a tab with the title `user@azure-server-03`. +Type `tty` in Alfred followed by some characters from the title of an open window, tab or pane; press `Enter` to activate the selected window/tab/pane, `Alt-Enter` to close it, or `Cmd-Enter` to trigger your ssh workflow. For example, enter `tty as3` to switch to a tab with the title `user@azure-server-03`. + +If no active terminal matches, or you use the Cmd-modifier, trigger your preferred ssh workflow (default: [isometry/alfred.ssh](https://github.com/isometry/alfred-ssh), version 2.3+; override by setting the `ssh_workflow` and `ssh_trigger` variables). In order to make working with more than one window/tab/pane with the same title easier, the tty is displayed beneath the result, and can be provided as a second argument to the trigger. For example, enter `tty lo 3` to select the the session with title `localhost` running on `/dev/ttys003`. To select by tty alone, use two spaces between the trigger and the tty number. For example, `tty 4` will select `/dev/ttys004`. -Optionally associate a hotkey trigger to further accelerate operation, e.g. Ctrl+Alt+T. +Optionally associate a hotkey trigger to further accelerate operation, e.g. Ctrl+Alt+T, or change the trigger word via the `keyword` variable. Combine with an [iTerm2](https://www.iterm2.com/) profile configured as ssh protocol handler (e.g. "Name"=`$$USER$$@$$HOST$$`, "Command"=`$$` and "Schemes handled"=`ssh`) and an [alfred-ssh](https://github.com/isometry/alfred-ssh) workflow to make opening and jumping between remote sessions across many windows, tabs and panes easy. diff --git a/action-tty.js b/action-tty.js index ba2c52d..ee01de6 100755 --- a/action-tty.js +++ b/action-tty.js @@ -1,29 +1,42 @@ #!/usr/bin/env osascript -l JavaScript +function getenv(name, value=null) { + ObjC.import('stdlib') + try { value = $.getenv(name); } + finally { return value; } +} + function run(args) { - args = args.join(" ").split(" ").map(function(e,i){return i==0?String(e):Number(e)}); - var app = Application("com.googlecode.iterm2"); - var action = args[0]; - var win = app.windows[args[1]]; - var tab = win.tabs[args[2]]; - var ses = tab.sessions[args[3]]; - switch (action) { - case "select": - // tab => session => window => app - tab.select(); - ses.select(); - win.select(); - app.activate(); - break; - case "close": - var old = win.currentTab(); - tab.select(); - ses.close(); - old.select(); - break; - default: - console.info(JSON.stringify({args:args, title:ses.name()})); - break; + args = args.join(" ").split(" ") + var action = String(args[0]); + if (action == "ssh") { + var host = String(args[1] || ""); + var alfred = Application("com.runningwithcrayons.Alfred-3"); + alfred.runTrigger(getenv("ssh_trigger", "ssh"), + {inWorkflow:getenv("ssh_workflow", "net.isometry.alfred.ssh"), withArgument:host}); + } else { + var iterm = Application("com.googlecode.iterm2"); + var win = iterm.windows[Number(args[1])]; + var tab = win.tabs[Number(args[2])]; + var ses = tab.sessions[Number(args[3])]; + switch (action) { + case "select": + // tab => session => window => app + tab.select(); + ses.select(); + win.select(); + iterm.activate(); + break; + case "close": + var old = win.currentTab(); + tab.select(); + ses.close(); + old.select(); + break; + default: + console.info(JSON.stringify({args:args, title:ses.name()})); + break; + } } } diff --git a/filter-tty.js b/filter-tty.js index 3a59fb7..1ac110a 100755 --- a/filter-tty.js +++ b/filter-tty.js @@ -1,13 +1,14 @@ #!/usr/bin/env osascript -l JavaScript -function sessionToObj(winId, tabId) { +function sessionToObj(winId, tabId, query) { return function(session, sesId) { return { id: [winId, tabId, sesId].join(" "), title: session.name(), tty: session.tty(), output: session.isProcessing(), - profile: session.profileName() + profile: session.profileName(), + query: query } } } @@ -24,18 +25,23 @@ function objToItem(obj) { alt: { arg: ["close", obj.id].join(" "), subtitle: ["Close", description].join(" ") + }, + cmd: { + arg: ["ssh", obj.query].join(" "), + title: ["⇄ ssh", obj.query].join(" "), + subtitle: "Switch to ssh workflow" } } } } -function allSessionObjs(app) { +function allSessionObjs(app, query) { var windows = app.windows; var results = new Array(); for (var i = 0; i < windows.length; ++i) { var tabs = windows[i].tabs; for (var j = 0; j < tabs.length; ++j) { - results.push(...tabs[j].sessions().map(sessionToObj(i, j))); + results.push(...tabs[j].sessions().map(sessionToObj(i, j, query))); } } return results; @@ -61,12 +67,26 @@ function ttyFilter(ttyNum) { function run(args) { args = args.join(" ").split(" "); - var titlePattern = String(args[0] || ""); - var ttyPattern = String(args[1] || ""); + var query = String(args[0] || ""); + var tty = String(args[1] || ""); var sessionObjs = new Array(); var app = Application("com.googlecode.iterm2"); if (app.running()) { - sessionObjs = allSessionObjs(app).filter(titleFilter(titlePattern)).filter(ttyFilter(ttyPattern)); + sessionObjs = allSessionObjs(app, query).filter(titleFilter(query)).filter(ttyFilter(tty)); + } + if (sessionObjs.length == 0) { + return JSON.stringify({ + items: + [ + { + title: ["⇄ ssh", query].join(" "), + subtitle: "No matches! Switch to ssh workflow?", + arg: ["ssh", query].join(" "), + icon: { path: "icon.png" }, + } + ] + }); + } else { + return JSON.stringify({items: sessionObjs.map(objToItem)}); } - return JSON.stringify({items: sessionObjs.map(objToItem)}); } diff --git a/info.plist b/info.plist index 1ef3ece..d1049bb 100644 --- a/info.plist +++ b/info.plist @@ -59,7 +59,7 @@ escaping 0 keyword - tty + {var:keyword} queuedelaycustom 3 queuedelayimmediatelyinitially @@ -150,6 +150,8 @@ readme Type `tty` in Alfred followed by some characters from the title of an open tab or pane; press `Enter` to activate the selected pane, or Alt-Enter` to close it. For example, enter `tty as3` to switch to a tab with the title `user@azure-server-03`. +If no active terminal matches, or you use the Cmd-modifier, trigger your preferred ssh workflow (default: [isometry/alfred.ssh](https://github.com/isometry/alfred-ssh); choose by setting the `ssh_workflow` and `ssh_trigger` Workflow Environment Variables). + In order to make working with more than one window/tab/pane with the same title easier, the TTY is displayed beneath the result, and can be provided as a second argument to the trigger, e.g. `tty lo 3` to select the the session with title `localhost` running on `/dev/ttys003`. Optionally associate a hotkey trigger to further accelerate operation, e.g. Ctrl+Alt+T. @@ -183,8 +185,17 @@ Combine with an ssh protocol handler [iTerm2](https://www.iterm2.com/) profile ( 70 + variables + + keyword + tty + ssh_trigger + ssh + ssh_workflow + net.isometry.alfred.ssh + version - 1.0 + 1.1 webaddress https://github.com/isometry/alfred-tty