Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Beginning * Improved modals - modal.lua * Moved addState functions from `init` to their respective modules * `self.modal` instances have been renamed to `self.hotkeyModal` - to avoid confusion with `modal` module * Emacs module - capture * C-o/C-i for Preview App * Readme and changelog update
- Loading branch information
Showing
11 changed files
with
285 additions
and
174 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
local apps = {} | ||
local multimedia = require "multimedia" | ||
local windows = require "windows" | ||
local slack = require "slack" | ||
|
||
apps.addState = function(modal) | ||
modal.addState("apps", { | ||
init = function(self, fsm) | ||
self.hotkeyModal = hs.hotkey.modal.new() | ||
modal.displayModalText "e\t emacs\ng \t chrome\n i\t iTerm\n s\t slack\n b\t brave" | ||
self.hotkeyModal:bind("","escape", function() fsm:toIdle() end) | ||
self.hotkeyModal:bind({"cmd"}, "space", nil, function() fsm:toMain() end) | ||
for key, app in pairs({ | ||
i = "iTerm2", | ||
g = "Google Chrome", | ||
b = "Brave", | ||
e = "Emacs", | ||
m = multimedia.musicApp}) | ||
do | ||
self.hotkeyModal:bind("", key, function() | ||
windows.activateApp(app) | ||
fsm:toIdle() | ||
end) | ||
end | ||
|
||
slack.bind(self.hotkeyModal, fsm) | ||
self.hotkeyModal:enter() | ||
end}) | ||
end | ||
|
||
return apps |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,13 @@ | ||
[2017-06-25 Sun] | ||
- Sierra compatibility | ||
Since Karabiner is not compatible anymore (starting with Sierra), had to find ways to get similar features | ||
- ~keybdings~ module | ||
- App switcher with =Cmd+j/k= | ||
- Simple tab switcher for Chrome and iTerm2 with =Cmd+h/l= | ||
- Simple =Vi-mode= with =Alt+j/k/l/m= | ||
- App specific keybindings | ||
- Changed Slack reaction key to =C-r=, so =Cmd+i= can be used to switch between current application windows | ||
- [2017-06-25 Sun] | ||
- Sierra compatibility | ||
/*Since Karabiner is not compatible anymore (starting with Sierra), had to find a way to get similar features*/ | ||
- ~keybdings~ module | ||
- App switcher - =Cmd+j/k= | ||
- Simple tab switcher for Chrome and iTerm2 - =Cmd+h/l= | ||
- Simple =Vi-mode= - =Alt+j/k/l/m= | ||
- App specific keybindings | ||
- Changed Slack reaction key to =C-r=, so =Cmd+i= can be used to switch between current application windows | ||
- [2017-10-14 Sat] | ||
- Improved modal system - simplifies adding and extending modals | ||
- Emacs module | ||
currently invokes Emacs to enable system-wide org-capture. Accompanying emacs-lisp code can be found [[https://github.com/agzam/dot-spacemacs/blob/master/layers/ag-org/funcs.el#L144][here]] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
local emacs = {} | ||
|
||
local capture = function(isNote) | ||
local key = "" | ||
if isNote then | ||
key = "\"c\"" -- key is a string associated with org-capture template | ||
end | ||
local currentApp = hs.window.focusedWindow(); | ||
local pid = "\"" .. currentApp:pid() .. "\" " | ||
local title = "\"" .. currentApp:title() .. "\" " | ||
hs.timer.delayed.new(0.1, function() | ||
hs.execute("/usr/local/bin/emacsclient" .. | ||
" -c -F '(quote (name . \"capture\"))'" .. | ||
" -e '(activate-capture-frame " .. pid .. title .. key .. " )'") | ||
end):start() | ||
end | ||
|
||
local bind = function(hotkeyModal, fsm) | ||
hotkeyModal:bind("", "c", function() | ||
fsm:toIdle() | ||
capture() | ||
end) | ||
hotkeyModal:bind("", "n", function() | ||
fsm:toIdle() | ||
capture(true) -- note on currently clocked in | ||
end) | ||
hotkeyModal:bind("", "t", function() | ||
hs.alert.show(hs.window.focusedWindow():pid(), 2) | ||
end) | ||
end | ||
|
||
emacs.switchToApp = function(pid, title) | ||
local app = hs.application.applicationForPID(pid) | ||
if app then | ||
app:activate() | ||
end | ||
end | ||
|
||
emacs.addState = function(modal) | ||
modal.addState("emacs", { | ||
init = function(self, fsm) | ||
self.hotkeyModal = hs.hotkey.modal.new() | ||
modal.displayModalText "c \tcapture\nn\tnote" | ||
|
||
self.hotkeyModal:bind("","escape", function() fsm:toIdle() end) | ||
self.hotkeyModal:bind({"cmd"}, "space", nil, function() fsm:toMain() end) | ||
|
||
bind(self.hotkeyModal, fsm) | ||
self.hotkeyModal:enter() | ||
end | ||
}) | ||
end | ||
|
||
return emacs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,138 +1,18 @@ | ||
require "preload" | ||
local keybindings = require "keybindings" | ||
local machine = require "statemachine" | ||
local windows = require "windows" | ||
local slack = require "slack" | ||
local multimedia = require "multimedia" | ||
|
||
local modal = require "modal" | ||
require "preview-app" | ||
|
||
local displayModalText = function(txt) | ||
hs.alert.closeAll() | ||
alert(txt, 999999) | ||
end | ||
|
||
allowedApps = {"Emacs", "iTerm2"} | ||
hs.hints.style = "vimperator" | ||
hs.hints.showTitleThresh = 4 | ||
hs.hints.titleMaxSize = 10 | ||
hs.hints.fontSize = 30 | ||
|
||
local filterAllowedApps = function(w) | ||
if (not w:isStandard()) and (not utils.contains(allowedApps, w:application():name())) then | ||
return false; | ||
end | ||
return true; | ||
end | ||
|
||
modals = { | ||
main = { | ||
init = function(self, fsm) | ||
if self.modal then | ||
self.modal:enter() | ||
else | ||
self.modal = hs.hotkey.modal.new({"cmd"}, "space") | ||
end | ||
self.modal:bind("","space", nil, function() fsm:toIdle(); windows.activateApp("Alfred 3") end) | ||
self.modal:bind("","w", nil, function() fsm:toWindows() end) | ||
self.modal:bind("","a", nil, function() fsm:toApps() end) | ||
self.modal:bind("", "m", nil, function() fsm:toMedia() end) | ||
self.modal:bind("","j", nil, function() | ||
local wns = hs.fnutils.filter(hs.window.allWindows(), filterAllowedApps) | ||
hs.hints.windowHints(wns, nil, true) | ||
fsm:toIdle() end) | ||
self.modal:bind("","escape", function() fsm:toIdle() end) | ||
function self.modal:entered() displayModalText "w \t- windows\na \t- apps\n j \t- jump\nm - media" end | ||
end | ||
}, | ||
windows = { | ||
init = function(self, fsm) | ||
self.modal = hs.hotkey.modal.new() | ||
displayModalText "cmd + hjkl \t jumping\nhjkl \t\t\t\t halves\nalt + hjkl \t\t increments\nshift + hjkl \t resize\nn, p \t next, prev screen\ng \t\t\t\t\t grid\nm \t\t\t\t maximize\nu \t\t\t\t\t undo" | ||
self.modal:bind("","escape", function() fsm:toIdle() end) | ||
self.modal:bind({"cmd"}, "space", nil, function() fsm:toMain() end) | ||
windows.bind(self.modal, fsm) | ||
self.modal:enter() | ||
end | ||
}, | ||
apps = { | ||
init = function(self, fsm) | ||
self.modal = hs.hotkey.modal.new() | ||
displayModalText "e\t emacs\ng \t chrome\n i\t iTerm\n s\t slack\n b\t brave" | ||
self.modal:bind("","escape", function() fsm:toIdle() end) | ||
self.modal:bind({"cmd"}, "space", nil, function() fsm:toMain() end) | ||
for key, app in pairs({ | ||
i = "iTerm2", | ||
g = "Google Chrome", | ||
b = "Brave", | ||
e = "Emacs", | ||
m = multimedia.musicApp}) do | ||
self.modal:bind("", key, function() windows.activateApp(app); fsm:toIdle() end) | ||
end | ||
|
||
slack.bind(self.modal, fsm) | ||
self.modal:enter() | ||
end | ||
}, | ||
media = { | ||
init = function(self, fsm) | ||
self.modal = hs.hotkey.modal.new() | ||
displayModalText "h \t previous track\nl \t next track\nk \t volume up\nj \t volume down\ns \t play/pause\na \t launch player" | ||
|
||
self.modal:bind("","escape", function() fsm:toIdle() end) | ||
self.modal:bind({"cmd"}, "space", nil, function() fsm:toMain() end) | ||
|
||
multimedia.bind(self.modal, fsm) | ||
self.modal:enter() | ||
end | ||
} | ||
} | ||
|
||
local initModal = function(state, fsm) | ||
local m = modals[state] | ||
m.init(m, fsm) | ||
end | ||
|
||
exitAllModals = function() | ||
utils.each(modals, function(m) | ||
if m.modal then | ||
m.modal:exit() | ||
end | ||
end) | ||
end | ||
|
||
local fsm = machine.create({ | ||
initial = "idle", | ||
events = { | ||
{ name = "toIdle", from = "*", to = "idle" }, | ||
{ name = "toMain", from = '*', to = "main" }, | ||
{ name = "toWindows", from = {'main','idle'}, to = "windows" }, | ||
{ name = "toApps", from = {'main', 'idle'}, to = "apps" }, | ||
{ name = "toMedia", from = {'main', 'idle'}, to = "media" } | ||
}, | ||
callbacks = { | ||
onidle = function(self, event, from, to) | ||
hs.alert.closeAll() | ||
exitAllModals() | ||
end, | ||
onmain = function(self, event, from, to) | ||
-- modals[from].modal:exit() | ||
initModal(to, self) | ||
end, | ||
onwindows = function(self, event, from, to) | ||
-- modals[from].modal:exit() | ||
initModal(to, self) | ||
end, | ||
onapps = function(self, event, from, to) | ||
-- modals[from].modal:exit() | ||
initModal(to, self) | ||
end, | ||
onmedia = function(self, event, from, to) | ||
initModal(to, self) | ||
end, | ||
} | ||
}) | ||
require("windows").addState(modal) | ||
require("apps").addState(modal) | ||
require("multimedia").addState(modal) | ||
require("emacs").addState(modal) | ||
|
||
fsm:toMain() | ||
local stateMachine = modal.createMachine() | ||
stateMachine:toMain() | ||
|
||
hs.alert.show("Config Loaded") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
local modal = {} | ||
local stateMachine = require "statemachine" | ||
local utils = require "utils" | ||
local windows = require "windows" | ||
|
||
-- local log = hs.logger.new('modal-module','debug') | ||
|
||
modal.displayModalText = function(txt) | ||
hs.alert.closeAll() | ||
alert(txt, 999999) | ||
end | ||
|
||
modal.exitAllModals = function() | ||
hs.fnutils.each(modal.states, function(s) | ||
if s.hotkeyModal then s.hotkeyModal:exit() end | ||
end) | ||
end | ||
|
||
modal.addState = function(name,state) | ||
modal.states[name] = state | ||
end | ||
|
||
local filterAllowedApps = function(w) | ||
local allowedApps = {"Emacs", "iTerm2"} | ||
if (not w:isStandard()) and (not hs.fnutils.contains(allowedApps, w:application():name())) then | ||
return false; | ||
end | ||
return true; | ||
end | ||
|
||
modal.states = { | ||
idle = { | ||
from = "*", to = "idle", | ||
callback = function(self, event, from, to) | ||
hs.alert.closeAll() | ||
modal.exitAllModals() | ||
end | ||
}, | ||
main = { | ||
from = "*", to = "main", | ||
init = function(self, fsm) | ||
if self.hotkeyModal then | ||
self.hotkeyModal:enter() | ||
else | ||
self.hotkeyModal = hs.hotkey.modal.new({"cmd"}, "space") | ||
end | ||
self.hotkeyModal:bind("","space", nil, function() fsm:toIdle(); windows.activateApp("Alfred 3") end) | ||
self.hotkeyModal:bind("","w", nil, function() fsm:toWindows() end) | ||
self.hotkeyModal:bind("","a", nil, function() fsm:toApps() end) | ||
self.hotkeyModal:bind("", "m", nil, function() fsm:toMedia() end) | ||
self.hotkeyModal:bind("", "x", nil, function() fsm:toEmacs() end) | ||
self.hotkeyModal:bind("","j", nil, function() | ||
local wns = hs.fnutils.filter(hs.window.allWindows(), filterAllowedApps) | ||
hs.hints.windowHints(wns, nil, true) | ||
fsm:toIdle() end) | ||
self.hotkeyModal:bind("","escape", function() fsm:toIdle() end) | ||
function self.hotkeyModal:entered() | ||
modal.displayModalText "w \t- windows\na \t- apps\n j \t- jump\nm - media\nx\t- emacs" | ||
end | ||
end | ||
} | ||
} | ||
|
||
-- -- each modal has: name, init function | ||
modal.createMachine = function() | ||
-- build events based on modals | ||
local events = {} | ||
local params = function(fsm) | ||
local callbacks = {} | ||
for k, s in pairs (modal.states) do | ||
table.insert(events, { name = "to" .. utils.capitalize(k), | ||
from = s.from or {"main", "idle"}, | ||
to = s.to or k}) | ||
if s.callback then | ||
cFn = s.callback | ||
else | ||
cFn = function(self, event, from, to) | ||
local st = modal.states[to] | ||
st.init(st, self) | ||
end | ||
end | ||
callbacks["on" .. k] = cFn | ||
end | ||
|
||
return callbacks | ||
end | ||
|
||
return stateMachine.create({ initial = "idle", | ||
events = events, | ||
callbacks = params(self)}) | ||
end | ||
|
||
return modal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.