Last active
September 13, 2024 06:52
-
-
Save RainmanNoodles/70aaff04b20763041d7acb771b0ff2b2 to your computer and use it in GitHub Desktop.
Hammerspoon Fuzzy Window Switcher
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
-- Fuzzy Window Switcher | |
_fuzzyChoices = nil | |
_fuzzyChooser = nil | |
_fuzzyLastWindow = nil | |
function fuzzyQuery(s, m) | |
s_index = 1 | |
m_index = 1 | |
match_start = nil | |
while true do | |
if s_index > s:len() or m_index > m:len() then | |
return -1 | |
end | |
s_char = s:sub(s_index, s_index) | |
m_char = m:sub(m_index, m_index) | |
if s_char == m_char then | |
if match_start == nil then | |
match_start = s_index | |
end | |
s_index = s_index + 1 | |
m_index = m_index + 1 | |
if m_index > m:len() then | |
match_end = s_index | |
s_match_length = match_end-match_start | |
score = m:len()/s_match_length | |
return score | |
end | |
else | |
s_index = s_index + 1 | |
end | |
end | |
end | |
function _fuzzyFilterChoices(query) | |
if query:len() == 0 then | |
_fuzzyChooser:choices(_fuzzyChoices) | |
return | |
end | |
pickedChoices = {} | |
for i,j in pairs(_fuzzyChoices) do | |
fullText = (j["text"] .. " " .. j["subText"]):lower() | |
score = fuzzyQuery(fullText, query:lower()) | |
if score > 0 then | |
j["fzf_score"] = score | |
table.insert(pickedChoices, j) | |
end | |
end | |
local sort_func = function( a,b ) return a["fzf_score"] > b["fzf_score"] end | |
table.sort( pickedChoices, sort_func ) | |
_fuzzyChooser:choices(pickedChoices) | |
end | |
function _fuzzyPickWindow(item) | |
if item == nil then | |
if _fuzzyLastWindow then | |
-- Workaround so last focused window stays focused after dismissing | |
_fuzzyLastWindow:focus() | |
_fuzzyLastWindow = nil | |
end | |
return | |
end | |
saveTime(6) | |
id = item["windowID"] | |
window = hs.window.get(id) | |
window:focus() | |
end | |
function windowFuzzySearch() | |
windows = hs.window.filter.default:getWindows(hs.window.filter.sortByFocusedLast) | |
-- windows = hs.window.orderedWindows() | |
_fuzzyChoices = {} | |
for i,w in pairs(windows) do | |
title = w:title() | |
app = w:application():name() | |
item = { | |
["text"] = app, | |
["subText"] = title, | |
--["image"] = w:snapshot(), | |
["windowID"] = w:id() | |
} | |
-- Handle special cases as necessary | |
--if app == "Safari" and title == "" then | |
-- skip, it's a weird empty window that shows up sometimes for some reason | |
--else | |
table.insert(_fuzzyChoices, item) | |
--end | |
end | |
_fuzzyLastWindow = hs.window.focusedWindow() | |
_fuzzyChooser = hs.chooser.new(_fuzzyPickWindow):choices(_fuzzyChoices):searchSubText(true) | |
_fuzzyChooser:queryChangedCallback(_fuzzyFilterChoices) -- Enable true fuzzy find | |
_fuzzyChooser:show() | |
end | |
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "J", function() | |
windowFuzzySearch() | |
end) |
works ok to find open apps, does need to remove "saveTime(6)", does not differentiate between windows from the same app
this works better: https://github.com/minusf/FuzzySwitcher.spoon
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
To get this working, remove the
saveTime(6)
from line 63