Skip to content

Instantly share code, notes, and snippets.

@happyjake
Last active December 1, 2017 05:49
Show Gist options
  • Save happyjake/b29e6be289c72ecf7a9965b98a3baa3a to your computer and use it in GitHub Desktop.
Save happyjake/b29e6be289c72ecf7a9965b98a3baa3a to your computer and use it in GitHub Desktop.
use hammerspoon to quick add current page link to evernote
local apps = {}
-- App-specific code, runs when you launch or switch to another app
local App = {}
App.new = function(name)
log.d('new App for ',name)
local self = {}
self.name = name
self.bindings = {}
self.onActivateFn = nil
self.onDeactivateFn = nil
self.onLaunchedFn = nil
self.onTerminatedFn = nil
self.bind = function(hotkey, predicate)
table.insert(self.bindings, {key = hotkey,
predicate = predicate})
return self
end
self.onActivate = function(fn)
self.onActivateFn = fn
return self
end
self.onDeactivate = function(fn)
self.onDeactivateFn = fn
return self
end
self.onLaunched = function(fn)
self.onLaunchedFn = fn
local app = hs.application.find(self.name)
if app then
self.launch(app)
if app:isFrontmost() then
self.activate(app)
end
end
return self
end
self.onTerminated = function(fn)
self.onTerminatedFn = fn
return self
end
self.activate = function(appObject)
--log.d('activate',appObject)
if type(self.onActivateFn) == 'function' then
self:onActivateFn(appObject)
end
self:enableBinds()
end
self.deactivate = function(appObject)
if type(self.onDeactivateFn) == 'function' then
self:onDeactivateFn(appObject)
end
self:disableBinds()
end
self.launch = function(appObject)
if type(self.onLaunchedFn) == 'function' then
self:onLaunchedFn(appObject)
end
end
self.terminate = function(appObject)
if type(self.onTerminatedFn) == 'function' then
self:onTerminatedFn(appObject)
end
self:disableBinds()
end
self.enableBinds = function(self)
--log.d('enableBinds',hs.inspect(self.bindings))
hs.fnutils.each(self.bindings, function(b)
if b.predicate and not b.predicate() then
b.key:disable()
else
b.key:enable()
end
end)
end
self.disableBinds = function(self)
hs.fnutils.each(self.bindings, function(b)
if b and b.key then
b.key:disable()
end
end)
end
self.clearBinds = function(self)
log.d('clearBinds for ',hs.inspect(self))
self:disableBinds()
self.bindings = {}
end
apps[name] = self
return self
end
function invoke(keys, predicate)
return function ()
if predicate and not predicate() then
return
end
if type(keys) == 'table' then
hs.fnutils.each(keys, function (key)
if type(key) ~= 'table' then
key = {{}, key}
end
hs.eventtap.keyStroke(key[1], key[2])
end)
elseif type(keys) == 'string' then
os.execute(keys)
elseif type(keys) == 'function' then
return keys()
end
end
end
--
function appGlobalWatcher(appName, eventType, appObject)
--log.d('appGlobalWatcher',appName,eventType,appObject)
if apps[appName] then
if (eventType == hs.application.watcher.activated) then
apps[appName].activate(appObject)
elseif (eventType == hs.application.watcher.deactivated) then
apps[appName].deactivate(appObject)
elseif (eventType == hs.application.watcher.launched) then
apps[appName].launch(appObject)
elseif (eventType == hs.application.watcher.terminated) then
apps[appName].terminate(appObject)
end
end
end
App.appWatcher = hs.application.watcher.new(appGlobalWatcher):start()
log.d('App.appWatcher assign')
return App
-- for evernote
--
local module = {}
local appName = 'Evernote'
local App = require('App')
local app = App.new(appName)
local util = require('util')
local network = require('network')
local executeAppleScript = util.executeAppleScript
module.lastActivated = 0
module.activateInterval = 10
app.onActivate(function(appObject)
log.d('sync evernote')
-- sync if connected to internet
if network.isInternetReachable() then
hs.eventtap.keyStroke({'cmd','ctrl'}, 's')
end
-- focus on search if not active for a while
-- if os.time() - module.lastActivated > module.activateInterval then
-- module.lastActivated = os.time()
-- hs.eventtap.keyStroke({'cmd','alt'}, 'f')
-- end
end)
module.copyLink = function(notebookName,noteTitle,isPrepend)
local isOK, output, message = hs.osascript.javascript([[
ObjC.import('AppKit');
function run(argv) {
var res = {};
getWebLink(res);
if (res.hasOwnProperty('title') && res.hasOwnProperty('url')) {
copyToClipboard(res);
//return res.title + ' - ' + res.url;
//return res.title;
return JSON.stringify(res);
}
return 'Failed!';
}
function getWebLink(res) {
const frontmost_app_name = Application('System Events').applicationProcesses.where({ frontmost: true }).name()[0]
const frontmost_app = Application(frontmost_app_name)
if (['Google Chrome','Google Chrome Canary','Chromium','Vivaldi'].indexOf(frontmost_app_name) > -1) {
res.title = frontmost_app.windows[0].activeTab.name()
res.url = frontmost_app.windows[0].activeTab.url()
} else if (['Safari','Safari Technology Preview','Webkit'].indexOf(frontmost_app_name) > -1) {
res.title = frontmost_app.documents[0].name()
res.url = frontmost_app.documents[0].url()
} else {
throw new Error('You need a supported browser as your frontmost app')
}
}
function copyToClipboard(res) {
var pb = $.NSPasteboard.generalPasteboard;
var str1 = $.NSString.alloc.initWithUTF8String('<a href="' + res.url + '">' + res.title +'</a>');
var str2 = $.NSString.alloc.initWithUTF8String('[' + res.title + '](' + res.url + ')');
var str3 = $.NSString.alloc.initWithUTF8String('{\\rtf1\\ansi\deff0{\\field{\\*\\fldinst{HYPERLINK "' + res.url + '"}}{\\fldrslt ' + res.title + '}}}');
pb.clearContents;
pb.setStringForType(str1, $.NSPasteboardTypeHTML);
pb.setStringForType(str2, $.NSPasteboardTypeString);
pb.setStringForType(str3, $.NSPasteboardTypeRTF);
}
]])
if isOK then
local res = hs.json.decode(output)
-- hs.application(appName):activate()
local html = string.format([[set html1 to "<li><a href=\"%s\">%s</a> - "]] ,res.url ,util.html_escape(res.title)) .. [[& (do shell script "LANG=zh_CN.UTF-8 date") & "</li>"
]]
local as = html .. [[
tell application "Evernote"
synchronize
set isPrepend to ]].. tostring(isPrepend) .. [[
set notebookName to "]].. notebookName .. [["
if (not (notebook named notebookName exists)) then
set notebook1 to create notebook notebookName
end if
set notebook1 to notebook notebookName
set noteTitle to "]].. noteTitle ..[[ "
set theNotes to find notes "notebook:\"" & notebookName & "\" intitle:\"" & noteTitle & "\""
if length of theNotes is 0 then
create note with html html1 title noteTitle notebook notebook1
else
set theNote to first item of theNotes
-- tell theNote to append html html1
tell theNote
if isPrepend then
set noteHTML to html1 & (HTML content of item 1 of theNote)
set (HTML content of item 1 of theNote) to noteHTML
else
set noteHTML to (HTML content of item 1 of theNote) & html1
set (HTML content of item 1 of theNote) to noteHTML
end if
end tell
end if
end
]]
executeAppleScript(as, "prepend to evernote")
hs.alert.show("\"".. res.title .."\" copied to ".. noteTitle)
else
hs.alert.show(message['NSLocalizedDescription'])
log.d(hs.inspect.inspect(message))
end
end
-- cmd + f to search for notes
app.bind(hs.hotkey.new({'cmd'}, 'f', function()
hs.application(appName):selectMenuItem("Search Notes...")
end))
-- cmd + shift + f to search in current note
app.bind(hs.hotkey.new({'cmd', 'shift'}, 'f', function()
hs.application(appName):selectMenuItem("Find Within Note...")
end))
-- esc to not focus on search
app.bind(hs.hotkey.new({}, 'escape', 'esc', function()
if util.menuEnabled(hs.application(appName),'Paste') then
hs.application(appName):selectMenuItem("Select Note List")
end
end))
-- lost focus for search on deactive
app.onDeactivate(function()
if util.menuEnabled(hs.application(appName),'Paste') then
hs.application(appName):selectMenuItem("Select Note List")
end
end)
return module
local util = require("util")
local network = {}
network.internetReachWatcher = hs.network.reachability.internet()
network.onInternetConnected = function (event) end
network.onInternetDisconnected = function (event) end
network.internetReachWatcher:setCallback(function(watcher, flags)
-- log.d("internet reachability changed: ", flags, watcher.statusString())
if (flags & hs.network.reachability.flags.reachable) > 0 then
-- a default route exists, so an active internet connection is present
hs.alert.show("internet connected")
network.onInternetConnected(flags)
else
-- no default route exists, so no active internet connection is present
hs.alert.show("internet Disconnected")
network.onInternetDisconnected(flags)
end
end):start()
network.isInternetReachable = function()
return (network.internetReachWatcher:status() & hs.network.reachability.flags.reachable) > 0
end
return network
local module = {}
-- strings
module.startsWith = function(String,Start)
return string.sub(String,1,string.len(Start))==Start end
module.endsWith = function(String,End)
return End=='' or string.sub(String,-string.len(End))==End
end
-- table fn
module.reduce = function(t,init,fn)
return hs.fnutils.reduce(hs.fnutils.concat({init},t),function(a,b) return fn(a,b) end)
end
module.count = function(t)
local count = 0
hs.fnutils.each(t,function() count = count + 1 end)
return count
end
module.urlencode = function(str)
if (str) then
str = string.gsub (str, "\n", "\r\n")
str = string.gsub (str, "([^%w ])",
function (c) return string.format ("%%%02X", string.byte(c)) end)
str = string.gsub (str, " ", "+")
end
return str
end
module.html_escape = function (s)
assert("Expected string in argument #1.")
return (string.gsub(s, "[}{\">/<'&]", {
["&"] = "&amp;",
["<"] = "&lt;",
[">"] = "&gt;",
['"'] = "&quot;",
["'"] = "&#39;",
["/"] = "&#47;"
}))
end
--
module.selectWifi = function(ssid)
local cmd = [[
tell application "System Events"
tell process "SystemUIServer"
click (menu bar item 1 of menu bar 1 whose description contains "Wi-Fi")
click menu item "%s" of menu 1 of result
end tell
end tell]]
return hs.osascript.applescript(string.format(cmd,ssid))
end
--
module.moveFile = function(from,to)
return os.rename(from,to)
end
module.parentDir = function(str,sep)
sep=sep or'/'
return str:match("(.*"..sep..")")
end
module.filename = function(str)
return str:match("^.+/(.+)$")
end
module.fileext = function(str)
return str:match("^.+(%..+)$")
end
module.killApp = function(appName)
local app = hs.application.find(appName)
if not app then
return
end
app:kill()
end
module.launchApp = function(appName)
hs.application.open(appName)
end
module.launchAppIfNotRunning = function(appName)
local app = hs.application.find(appName)
if app and app:isRunning() then
return
end
hs.application.open(appName)
end
module.menuEnabled = function(app,menuName)
local item = app:findMenuItem(menuName)
return item and item.enabled
end
module.showApps = function()
hs.fnutils.each(hs.application.runningApplications(), function(app) print(app:bundleID(), app:title()) end)
end
-- osascript to tell an application to do something
module.applescriptTell = function(app, appCmd)
local cmd = 'tell application "'..app..'" to '..appCmd
local ok, result = hs.applescript(cmd)
if ok and result == nil then result = true end
if not ok then result = nil end
return result
end
-- Execute the given apple script and logs any errors. The context will be added
-- to the log.
-- Returns: The output of the apple script if successful, nil otherwise
module.executeAppleScript = function(script, context)
successful, output, errDesc = hs.osascript.applescript(script)
if not successful then
msg = string.format("Failed to execute AppleScript (%s)", context)
hs.alert(msg)
log:e(msg)
log:e(string.format("Script:\n%s", script))
log:e(string.format("Error:\n%s", hs.inspect(errDesc)))
return nil
end
return output
end
-- get the current URL of the focused browser window
module.getFocusedBrowserURL = function()
-- values for this table are either applescript strings to pass to
-- lib.tell(), or functions to be called. In either case, the return
-- value should be the URL of the frontmost window/tab.
local browsers = {
['Google Chrome'] = 'URL of active tab of front window',
Safari = 'URL of front document',
}
local url = nil
local app = hs.application.frontmostApplication()
local title = app:title()
if browsers[title] ~= nil then
if type(browsers[title]) == 'string' then
url = module.applescriptTell(title, browsers[title])
elseif type(browsers[title] == 'function') then
url = browsers[title]()
end
end
return url
end
module.openUrl = function(url)
return hs.urlevent.openURLWithBundle(url, '')
end
module.waitUntil = function(predicateFn, actionFn, failFn,checkInterval, maxTryCount)
local tryCount = 0
local timer = hs.timer.waitUntil(function()
tryCount = tryCount + 1
if tryCount > maxTryCount then
return true
end
return predicateFn()
end, function(tm)
if tryCount > maxTryCount then
if failFn then
return failFn(tm)
else
return
end
end
return actionFn(tm)
end, checkInterval)
return timer
end
-- Focus the last used window.
module.focusLastFocused = function()
local wf = hs.window.filter
local lastFocused = wf.defaultCurrentSpace:getWindows(wf.sortByFocusedLast)
if #lastFocused > 0 then lastFocused[1]:focus() end
end
return module
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment