Skip to content

Commit

Permalink
First commit of personal utilities
Browse files Browse the repository at this point in the history
  • Loading branch information
dabrady committed Mar 28, 2018
0 parents commit c01239b
Show file tree
Hide file tree
Showing 10 changed files with 433 additions and 0 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# lua-utils
A collection of utilities I've built as-needed for progamming in Lua and working with [Hammerspoon](hammerspoon.org).

Utilities compatible with vanilla Lua 5.3 are at the top level, while those intended for working with and/or extending Hammerspoon core libraries are nested within the `hs` directory.
59 changes: 59 additions & 0 deletions hs/application.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
-- Provide the ability to encapsulate the extensions into a different table.
local module = ... or require('hs.application')
assert(type(module) == 'table', 'must provide a table to extend')

require('hs.applescript')
require('hs.task')

function module.tell(application, message)
if message == nil then return nil end
if application == nil then return nil end

local function _tellMessage(app)
if app == nil then
-- print("Something's wrong: application could not be found!")
return nil
end

-- print("App is running! Commanding it to do things.")

local ok, _ = hs.applescript('tell application "'..app:name()..'" to '..message)
if ok then
return app
else
return nil
end
end

if type(application) == 'userdata' then return _tellMessage(application) end
if type(application) == 'string' then
-- print('Converting app string')

local app = hs.application.get(application)
if app == nil then
-- print("App not running: attempting to start it in the background")

local function _tellOnOpen()
local function sleep(n)
local t0 = os.clock()
while os.clock() - t0 <= n do end
end
app = hs.application.get(application)
sleep(1)
-- print('Opened! Commanding application to do things')
_tellMessage(app)
end

-- Launch the application in the background and wait a reasonable amount of time
-- for it to become responsive before telling it anything.
hs.task.new('/usr/bin/open', _tellOnOpen, function() end, {'-ga', application}):start():waitUntilExit()

return app
else
return _tellMessage(app)
end
end
end

-----------
return module
61 changes: 61 additions & 0 deletions hs/canvas.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
-- Provide the ability to encapsulate the extensions into a different table.
local module = ... or require('hs.canvas')
assert(type(module) == 'table', 'must provide a table to extend')

require('hs.timer')
requrie('hs.fnutils')

---- Rolling my own 'show and hide with fade-out': need to be able to cancel the animation.
module.flashable = {}
function module.flashable.new(canvasObj, options)
options = options or {}
local _fade -- Forward declaration for closure
local fader = hs.timer.delayed.new(options.fadeSpeed or 0.07, function() _fade() end)
local hider = hs.timer.delayed.new(options.showDuration or 1, hs.fnutils.partial(fader.start, fader))

-- A sentinel representing the exit condition for our background 'fader'
local cancelFade = false

local function _abortFade()
-- Set the exit condition for any ongoing fade
cancelFade = true
-- Cancel any ongoing fade timer
fader:stop()
-- Reset canvas to maximum visibility
canvasObj:alpha(1.0)
end

_fade = function()
local exit = cancelFade or (canvasObj:alpha() == 0)
if exit then
canvasObj:hide()
_abortFade()
else
local lowerAlpha = canvasObj:alpha() - 0.1
canvasObj:alpha(lowerAlpha)

-- Go around again
fader:start()
end
end

local function _hideCanvas()
cancelFade = false
hider:start()
end

return {
canvas = canvasObj,
flash = function()
-- Show the canvas if it's not already visible, then hide it according to configuration.
_abortFade()
canvasObj:show()
_hideCanvas()
end
}
end

setmetatable(module.flashable, {__call = function(_, ...) return module.flashable.new(...) end})

-----------
return module
21 changes: 21 additions & 0 deletions hs/chooser.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-- Provide the ability to encapsulate the extensions into a different table.
local module = ... or require('hs.chooser')
assert(type(module) == 'table', 'must provide a table to extend')

-- Takes a list of strings and creates a choice table formatted such that
-- it is acceptable by hs.chooser:choices
function module.generateChoiceTable(list)
if list == nil or #list == 0 then
return {}
end

local choiceTable = {}
for _,item in ipairs(list) do
table.insert(choiceTable, { text = item..'' })
end

return choiceTable
end

-----------
return module
50 changes: 50 additions & 0 deletions hs/fs.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
-- Provide the ability to encapsulate the extensions into a different table.
local module = ... or require('hs.fs')
assert(type(module) == 'table', 'must provide a table to extend')

require '../string'

-- Returns a list of directories in the given path.
function module.dirs(path)
local _,directoryContents = hs.fs.dir(path)
local directories = {}
repeat
local filename = directoryContents:next()
if (
filename and
filename:match("^%.") == nil and -- Exclude dotfiles
hs.fs.attributes(path..filename, 'mode') == 'directory'
) then

table.insert(directories, filename)
end
until filename == nil
directoryContents:close()

return directories
end

-- Load each file in a given directory, with any arguments given.
function module.loadAllFiles(rootDir, ...)
-- Make sure our root ends with a directory marker.
rootDir = rootDir:endsWith('/') and rootDir or rootDir..'/'

local loadedScripts = {}
local _,scripts = hs.fs.dir(rootDir)
repeat
local filename = scripts:next()
if filename and filename ~= '.' and filename ~= '..' then
print('\t\tloading script: '..filename)
-- Load the script, passing the given arguments as parameters to the Lua chunk.
-- Using `assert(loadfile(...))` instead of `require` to be compatible with Spoons.
local script = assert(loadfile(rootDir..filename))(...)
local basename = filename:match("^(.+)%.") -- Matches everything up to the first '.'
loadedScripts[basename] = script
end
until filename == nil

return loadedScripts
end

-----------
return module
24 changes: 24 additions & 0 deletions hs/location.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
-- Provide the ability to encapsulate the extensions into a different table.
local module = ... or require('hs.location')
assert(type(module) == 'table', 'must provide a table to extend')
if not module.geocoder then module.geocoder = {} end

-- Looks up a region table for the given location query.
function module.geocoder.lookupRegion(query, callback)
local function callWithRegion(state, result)
if state then
callback(state, result[1].region)
else
callback(state, result)
end
end

if type(query) == 'string' then
return hs.location.geocoder.lookupAddress(query, callWithRegion)
else
return hs.location.geocoder.lookupLocation(query, callWithRegion)
end
end

-----------
return module
11 changes: 11 additions & 0 deletions hs/spotify.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
local module = ... or {}
assert(type(module) == 'table', 'must provide a table to extend')

local tell = require('./application').tell

module.tell = function(...)
tell('Spotify', ...)
end

-----------
return module
20 changes: 20 additions & 0 deletions math.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-- Provide the ability to encapsulate the extensions into a different table.
local module = ... or math
assert(type(module) == 'table', 'must provide a table to extend')

-- Round the given number to the given number of decimal places.
function module.round(num, numPlaces)
local mult = 10^(numPlaces or 0)
return math.floor(num * mult + 0.5) / mult
end

-- Degree/radian conversions
function module.toRadians(degrees)
return degrees * math.pi / 180;
end
function module.toDegrees(radians)
return radians * 180 / math.pi;
end

-----------
return module
24 changes: 24 additions & 0 deletions string.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
-- Provide the ability to encapsulate the extensions into a different table.
local module = ... or string
assert(type(module) == 'table', 'must provide a table to extend')

--- Recipes for common string manipulations in Lua ---

-- Returns true if the given string starts with another, otherwise returns false.
function module.startsWith(str, query)
return string.sub(str, 1, string.len(query)) == query
end

-- Returns true if the given string ends with another, otherwise returns false.
function module.endsWith(str, query)
return query == '' or string.sub(str, -string.len(query)) == query
end

-- Removes initial and trailing whitespace
-- @see http://lua-users.org/wiki/StringTrim, 'trim6' implementation
function module.trim(str)
return str:match'^()%s*$' and '' or str:match'^%s*(.*%S)'
end

-----------
return module
Loading

0 comments on commit c01239b

Please sign in to comment.