-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathswitcher.lua
243 lines (213 loc) · 6.62 KB
/
switcher.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
---
--- Modified version of dmg hammerspoon
--- credit to the original author below
local obj={}
obj.__index = obj
-- metadata
obj.name = "selectWindow"
obj.author = "dmg <[email protected]>"
obj.homepage = "https://github.com/dmgerman/selectWindow.spoon"
obj.license = "MIT - https://opensource.org/licenses/MIT"
-- things to configure
obj.rowsToDisplay = 14 -- how many rows to display in the chooser
-- -- for debugging purposes
-- function obj:print_table(t, f)
-- for i,v in ipairs(t) do
-- print(i, f(v))
-- end
-- end
--
-- -- for debugging purposes
--
-- function obj:print_windows()
-- function w_info(w)
-- return w:title() .. w:application():name()
-- end
-- obj:print_table(hs.window.visibleWindows(), w_info)
-- end
theWindows = hs.window.filter.new()
theWindows:setDefaultFilter{}
theWindows:setSortOrder(hs.window.filter.sortByFocusedLast)
obj.currentWindows = {}
obj.previousSelection = nil -- the idea is that one switches back and forth between two windows all the time
-- Start by saving all windows
for i,v in ipairs(theWindows:getWindows()) do
table.insert(obj.currentWindows, v)
end
function obj:find_window_by_title(t)
-- find a window by title.
for i,v in ipairs(obj.currentWindows) do
if string.find(v:title(), t) then
return v
end
end
return nil
end
function obj:focus_by_title(t)
-- focus the window with given title
if not t then
hs.alert.show("No string provided to focus_by_title")
return nil
end
w = obj:find_window_by_title(t)
if w then
w:focus()
end
return w
end
function obj:focus_by_app(appName)
-- find a window with that application name and jump to it
-- print(' [' .. appName ..']')
for i,v in ipairs(obj.currentWindows) do
-- print(' [' .. v:application():name() .. ']')
if string.find(v:application():name(), appName) then
-- print("Focusing window" .. v:title())
v:focus()
return v
end
end
return nil
end
-- the hammerspoon tracking of windows seems to be broken
-- we do it ourselves
local function callback_window_created(w, appName, event)
if event == "windowDestroyed" then
-- print("deleting from windows-----------------", w)
if w then
-- print("destroying window" .. w:title())
end
for i,v in ipairs(obj.currentWindows) do
if v == w then
table.remove(obj.currentWindows, i)
return
end
end
-- print("Not found .................. ", w)
-- obj:print_table0(obj.currentWindows)
-- print("Not found ............ :()", w)
return
end
if event == "windowCreated" then
if w then
-- print("creating window " .. w:title())
end
-- print("inserting into windows.........", w)
table.insert(obj.currentWindows, 1, w)
return
end
if event == "windowFocused" then
--otherwise is equivalent to delete and then create
if w then
-- print("Focusing window" .. w:title())
end
callback_window_created(w, appName, "windowDestroyed")
callback_window_created(w, appName, "windowCreated")
-- obj:print_table0(obj.currentWindows)
end
end
theWindows:subscribe(hs.window.filter.windowCreated, callback_window_created)
theWindows:subscribe(hs.window.filter.windowDestroyed, callback_window_created)
theWindows:subscribe(hs.window.filter.windowFocused, callback_window_created)
function obj:list_window_choices(onlyCurrentApp)
local windowChoices = {}
local currentWin = hs.window.focusedWindow()
local currentApp = currentWin:application()
-- print("\nstarting to populate")
-- print(currentApp)
for i,w in ipairs(obj.currentWindows) do
if w ~= currentWin then
local app = w:application()
local appImage = nil
local appName = '(none)'
if app then
appName = app:name()
appImage = hs.image.imageFromAppBundle(w:application():bundleID())
end
-- print(appName, currentApp)
if (not onlyCurrentApp) or (app == currentApp) then
-- print("inserting...")
table.insert(windowChoices, {
text = w:title() .. "--" .. appName,
subText = appName,
uuid = i,
image = appImage,
win=w})
end
end
end
return windowChoices;
end
local windowChooser = hs.chooser.new(function(choice)
if not choice then hs.alert.show("Nothing to focus"); return end
local v = choice["win"]
if v then
v:focus()
else
hs.alert.show("unable fo focus " .. name)
end
end)
function obj:selectWindow(onlyCurrentApp)
local windowChoices = obj:list_window_choices(onlyCurrentApp)
if #windowChoices == 0 then
if onlyCurrentApp then
hs.alert.show("no other window for this application ")
else
hs.alert.show("no other window available ")
end
return
end
windowChooser:choices(windowChoices)
--windowChooser:placeholderText('')
windowChooser:rows(obj.rowsToDisplay)
windowChooser:query(nil)
windowChooser:show()
end
function obj:switchWindow(onlyCurrentApp)
local windowChoices = obj:list_window_choices(onlyCurrentApp)
if #windowChoices == 0 then
if onlyCurrentApp then
hs.alert.show("no other window for this application ")
else
hs.alert.show("no other window available ")
end
return
end
local c =#windowChoices
local v = windowChoices[c]["win"]
if v then
v:focus()
end
end
function obj:previousWindow(onlyCurrentApp)
local windowChoices = obj:list_window_choices(onlyCurrentApp)
if #windowChoices == 0 then
if onlyCurrentApp then
hs.alert.show("no other window for this application ")
else
hs.alert.show("no other window available ")
end
return
end
local v = windowChoices[1]["win"]
if v then
v:focus()
end
end
-- select any other window
hs.hotkey.bind({"alt"}, "b", function()
obj:selectWindow(false)
end)
-- select any window for the same application
hs.hotkey.bind({"alt", "shift"}, "b", function()
obj:selectWindow(true)
end)
-- cycles through all widows of the frontmost app.
function switcherfunc()
return obj:switchWindow(true)
end
-- Alt-tab replacement to go to last window
hs.hotkey.bind({"ctrl", "alt", "cmd"}, "tab", function()
obj:previousWindow(false)
end)
return obj
-----------------------------------------------------------