Skip to content

Instantly share code, notes, and snippets.

@mwerner
Created November 1, 2017 20:11
Show Gist options
  • Save mwerner/49c9656ed2d5e33e140a631d47cea388 to your computer and use it in GitHub Desktop.
Save mwerner/49c9656ed2d5e33e140a631d47cea388 to your computer and use it in GitHub Desktop.
Hammerspoon scripts
function applicationWatcher(appName, eventType, appObject)
if (eventType == hs.application.watcher.activated) then
if (appName == "Finder") then
-- Bring all Finder windows forward when one gets activated
appObject:selectMenuItem({"Window", "Bring All to Front"})
end
end
end
local appWatcher = hs.application.watcher.new(applicationWatcher)
appWatcher:start()
function reloadConfig(files)
doReload = false
for _,file in pairs(files) do
if file:sub(-4) == ".lua" then
doReload = true
end
end
if doReload then
hs.reload()
end
end
hs.pathwatcher.new(os.getenv("HOME") .. "/.hammerspoon/", reloadConfig):start()
-- Manually force reload
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "R", function()
hs.reload()
notify("Config Reloaded")
end)
require 'utilities'
-- Any changes made here are automatically reloaded on save.
require 'config'
-- ~/.hammerspoon/*.lua
require 'app_watcher'
require 'jumpcut'
require 'window'
-- Window placement
hs.hotkey.bind(keys.mash, "up", setWindow(0, 0, 1, 0.5))
hs.hotkey.bind(keys.mash, "down", setWindow(0, 0.5, 1, 0.5))
hs.hotkey.bind(keys.mash, "left", setWindow(0, 0, 0.5, 1))
hs.hotkey.bind(keys.mash, "right", setWindow(0.5, 0, 0.5, 1))
hs.hotkey.bind(keys.mash, "space", setWindow(0, 0, 1, 1))
hs.hotkey.bind(keys.mash, "K", setWindow(0.25, 0.30, 0.5, 0.60))
-- Application Hotkeys
hs.hotkey.bind(keys.alt, 'S', openApplication("Spotify"))
hs.hotkey.bind(keys.alt, 'M', openApplication("Spark"))
hs.hotkey.bind(keys.apps, 'S', openApplication("Spotify"))
hs.hotkey.bind(keys.apps, ',', openApplication("System Preferences"))
hs.hotkey.bind(keys.alt, 'space', openApplication("Finder"))
hs.hotkey.bind(keys.ctrl, 'space', openApplication('iTerm'))
hs.hotkey.bind(keys.apps, 'space', openApplication('Slack'))
hs.hotkey.bind(keys.mash, 'V', function()
jumpcut:popupMenu(hs.mouse.getAbsolutePosition())
end)
--[[
This is my attempt to implement a jumpcut replacement in Lua/Hammerspoon.
It monitors the clipboard/pasteboard for changes, and stores the strings you copy to the transfer area.
You can access this history on the menu (Unicode scissors icon).
Clicking on any item will add it to your transfer area.
If you open the menu while pressing option/alt, you will enter the Direct Paste Mode. This means that the selected item will be
"typed" instead of copied to the active clipboard.
The clipboard persists across launches.
-> Ng irc suggestion: hs.settings.set("jumpCutReplacementHistory", clipboard_history)
]]--
-- Feel free to change those settings
local frequency = 0.8 -- Speed in seconds to check for clipboard changes. If you check too frequently, you will loose performance, if you check sparsely you will loose copies
local hist_size = 20 -- How many items to keep on history
local label_length = 40 -- How wide (in characters) the dropdown menu should be. Copies larger than this will have their label truncated and end with "…" (unicode for elipsis ...)
local honor_clearcontent = false --asmagill request. If any application clears the pasteboard, we also remove it from the history https://groups.google.com/d/msg/hammerspoon/skEeypZHOmM/Tg8QnEj_N68J
local pasteOnSelect = false -- Auto-type on click
-- Don't change anything bellow this line
jumpcut = hs.menubar.new()
jumpcut:setTooltip("Jumpcut replacement")
local pasteboard = require("hs.pasteboard") -- http://www.hammerspoon.org/docs/hs.pasteboard.html
local settings = require("hs.settings") -- http://www.hammerspoon.org/docs/hs.settings.html
local last_change = pasteboard.changeCount() -- displays how many times the pasteboard owner has changed // Indicates a new copy has been made
--Array to store the clipboard history
local clipboard_history = settings.get("hs.jumpcut") or {} --If no history is saved on the system, create an empty history
-- Append a history counter to the menu
function setTitle()
if (#clipboard_history == 0) then
jumpcut:setTitle("✂") -- Unicode magic
else
-- jumpcut:setTitle("✂ ("..#clipboard_history..")") -- updates the menu counter
jumpcut:setTitle("✂") -- Unicode magic
end
end
function putOnPaste(string,key)
if (pasteOnSelect) then
hs.eventtap.keyStrokes(string)
pasteboard.setContents(string)
last_change = pasteboard.changeCount()
else
if (key.alt == true) then -- If the option/alt key is active when clicking on the menu, perform a "direct paste", without changing the clipboard
hs.eventtap.keyStrokes(string) -- Defeating paste blocking http://www.hammerspoon.org/go/#pasteblock
else
pasteboard.setContents(string)
last_change = pasteboard.changeCount() -- Updates last_change to prevent item duplication when putting on paste
end
end
end
-- Clears the clipboard and history
function clearAll()
pasteboard.clearContents()
clipboard_history = {}
settings.set("hs.jumpcut",clipboard_history)
now = pasteboard.changeCount()
-- setTitle()
end
-- Clears the last added to the history
function clearLastItem()
table.remove(clipboard_history,#clipboard_history)
settings.set("hs.jumpcut",clipboard_history)
now = pasteboard.changeCount()
-- setTitle()
end
function pasteboardToClipboard(item)
-- Loop to enforce limit on qty of elements in history. Removes the oldest items
while (#clipboard_history >= hist_size) do
table.remove(clipboard_history,1)
end
table.insert(clipboard_history, item)
settings.set("hs.jumpcut",clipboard_history) -- updates the saved history
-- setTitle() -- updates the menu counter
end
-- Dynamic menu by cmsj https://github.com/Hammerspoon/hammerspoon/issues/61#issuecomment-64826257
populateMenu = function(key)
-- setTitle() -- Update the counter every time the menu is refreshed
menuData = {}
if (#clipboard_history == 0) then
table.insert(menuData, {title="None", disabled = true}) -- If the history is empty, display "None"
else
for k,v in pairs(clipboard_history) do
if (string.len(v) > label_length) then
table.insert(menuData,1, {title=string.sub(v,0,label_length).."…", fn = function() putOnPaste(v,key) end }) -- Truncate long strings
else
table.insert(menuData,1, {title=v, fn = function() putOnPaste(v,key) end })
end -- end if else
end-- end for
end-- end if else
-- footer
table.insert(menuData, {title="-"})
table.insert(menuData, {title="Clear All", fn = function() clearAll() end })
if (key.alt == true or pasteOnSelect) then
table.insert(menuData, {title="Direct Paste Mode ✍", disabled=true})
end
return menuData
end
-- If the pasteboard owner has changed, we add the current item to our history and update the counter.
function storeCopy()
now = pasteboard.changeCount()
if (now > last_change) then
current_clipboard = pasteboard.getContents()
-- asmagill requested this feature. It prevents the history from keeping items removed by password managers
if (current_clipboard == nil and honor_clearcontent) then
clearLastItem()
else
pasteboardToClipboard(current_clipboard)
end
last_change = now
end
end
--Checks for changes on the pasteboard. Is it possible to replace with eventtap?
timer = hs.timer.new(frequency, storeCopy)
timer:start()
-- setTitle() --Avoid wrong title if the user already has something on his saved history
jumpcut:setMenu(populateMenu)
local wfRedshift=hs.window.filter.new({loginwindow={visible=true, allowRoles='*'}}, 'wf-redshift')
hs.redshift.start(3600, '19:00', '7:00', '4h', false, wfRedshift)
keys = {
ctrl = {'ctrl'},
alt = {'alt'},
cmd = {'cmd'},
mash = {"ctrl", "alt", "cmd"},
apps = {"cmd", "alt"}
}
function notify(message)
hs.notify.new({title="Hammerspoon", informativeText=message}):send()
end
function openApplication(name)
return function()
hs.application.launchOrFocus(name)
end
end
-- Resize windows
hs.window.animationDuration = 0
function setWindow(x, y, w, h)
return function()
local win = hs.window.focusedWindow()
if not win then return end
local f = win:frame()
local max = win:screen():frame()
f.w = math.floor(max.w * w)
f.h = math.floor(max.h * h)
f.x = math.floor((max.w * x) + max.x)
f.y = math.floor((max.h * y) + max.y)
win:setFrame(f)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment