init
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
/.idea/
|
||||
/*.zip
|
||||
.idea/
|
||||
build/
|
||||
@@ -0,0 +1,6 @@
|
||||
hs.configdir = os.getenv('HOME') .. '/.hammerspoon'
|
||||
package.path = hs.configdir .. '/?.lua;' .. hs.configdir .. '/?/init.lua;' .. hs.configdir .. '/Spoons/?.spoon/init.lua;' .. package.path
|
||||
~/.gitconfig~/.gitconfig
|
||||
|
||||
|
||||
require "modules/snippet"
|
||||
@@ -0,0 +1,290 @@
|
||||
---
|
||||
--- 公共函数
|
||||
--- Created by sugood(https://github.com/sugood).
|
||||
--- DateTime: 2020/10/24 14:13
|
||||
---
|
||||
local console = require("hs.console")
|
||||
version = "v0.2.0"
|
||||
configPath= "~/.hammerspoon/data/config.json"
|
||||
initConfigPath= "~/.hammerspoon/data/initConfig.json"
|
||||
config = {}
|
||||
colorDialog = hs.dialog.color
|
||||
|
||||
--检查文件是否存在
|
||||
function checkFileExist(path)
|
||||
local file = hs.fs.pathToAbsolute(path)
|
||||
return file ~= nil
|
||||
end
|
||||
|
||||
--复制文件
|
||||
function copyFile(source,destination)
|
||||
print(destination)
|
||||
local sourcefile = io.open(source, "r")
|
||||
local destinationfile = io.open(destination, "w")
|
||||
destinationfile:write(sourcefile:read("*all"))
|
||||
sourcefile:close()
|
||||
destinationfile:close()
|
||||
end
|
||||
|
||||
function switchDict()
|
||||
if config[1].dictEngine == '百度' then
|
||||
config[1].dictEngine = '有道'
|
||||
else
|
||||
config[1].dictEngine = '百度'
|
||||
end
|
||||
hs.json.write(config,configPath, true, true)
|
||||
hs.reload()
|
||||
end
|
||||
|
||||
function switchTime()
|
||||
if config[1].isSyncTime == 'on' then
|
||||
config[1].isSyncTime = 'off'
|
||||
else
|
||||
if(stringIsEmpty(config[1].rootPassword)) then
|
||||
local result,subText = hs.dialog.textPrompt("输入开机密码", "时间同步操作需要开机密码", '', "确定", "取消", true)
|
||||
if result == "确定" and stringIsEmpty(subText) == false then
|
||||
config[1].rootPassword = subText
|
||||
config[1].isSyncTime = 'on'
|
||||
end
|
||||
else
|
||||
config[1].isSyncTime = 'on'
|
||||
end
|
||||
end
|
||||
hs.json.write(config,configPath, true, true)
|
||||
hs.reload()
|
||||
end
|
||||
|
||||
function switchCaffeine()
|
||||
if config[1].caffeine == 'on' then
|
||||
config[1].caffeine = 'off'
|
||||
else
|
||||
config[1].caffeine = 'on'
|
||||
end
|
||||
hs.json.write(config,configPath, true, true)
|
||||
hs.reload()
|
||||
end
|
||||
|
||||
function switchSysInfo()
|
||||
if config[1].showSysInfo == 'on' then
|
||||
config[1].showSysInfo = 'off'
|
||||
else
|
||||
config[1].showSysInfo = 'on'
|
||||
end
|
||||
hs.json.write(config,configPath, true, true)
|
||||
hs.reload()
|
||||
end
|
||||
|
||||
--设置全局菜单栏
|
||||
function initMenu()
|
||||
macMenubar = hs.menubar.new()
|
||||
macMenubar:setTitle("")
|
||||
macMenubar:setIcon()
|
||||
macMenubar:setMenu( {
|
||||
{ title = "Reload config", fn = function()
|
||||
hs.reload()
|
||||
end },
|
||||
{ title = "Open console", fn = function() hs.openConsole() end },
|
||||
{ title = "Relaunch", fn = function() hs.relaunch() end },
|
||||
{ title = "-" },
|
||||
{ title = "翻译平台:" .. config[1].dictEngine, fn = function()
|
||||
if (hs.dialog.blockAlert("支持百度和有道翻译,确认切换?","有道翻译需先申请有道云API","确定","取消","informational") == "确定") then
|
||||
switchDict()
|
||||
end
|
||||
end },
|
||||
{ title = "输入appID", fn = function()
|
||||
if(config[1].dictEngine == '有道') then
|
||||
local result,subText = hs.dialog.textPrompt("输入appID", "请通过有道云API获取appkey", config[1].youdaoAppid, "确定", "取消", false)
|
||||
if result == "确定" then
|
||||
config[1].youdaoAppid = subText
|
||||
hs.json.write(config,configPath, true, true)
|
||||
end
|
||||
elseif(config[1].dictEngine == '百度') then
|
||||
local result,subText = hs.dialog.textPrompt("输入appID", "百度翻译可不修改", config[1].baiduAppid, "确定", "取消", true)
|
||||
if result == "确定" then
|
||||
config[1].baiduAppid = subText
|
||||
hs.json.write(config,configPath, true, true)
|
||||
end
|
||||
end
|
||||
end },
|
||||
{ title = "输入appSecret", fn = function()
|
||||
if(config[1].dictEngine == '有道') then
|
||||
local result,subText = hs.dialog.textPrompt("输入appSecret", "请通过有道云API获取appSecret", config[1].youdaoAppSecret, "确定", "取消", false)
|
||||
if result == "确定" then
|
||||
config[1].youdaoAppSecret = subText
|
||||
hs.json.write(config,configPath, true, true)
|
||||
end
|
||||
elseif(config[1].dictEngine == '百度') then
|
||||
local result,subText = hs.dialog.textPrompt("输入appSecret", "百度翻译可不修改", config[1].baiduAppSecret, "确定", "取消", true)
|
||||
if result == "确定" then
|
||||
config[1].baiduAppSecret = subText
|
||||
hs.json.write(config,configPath, true, true)
|
||||
end
|
||||
end
|
||||
end },
|
||||
{ title = "-" },
|
||||
{ title = "时间同步:" .. config[1].isSyncTime, fn = function()
|
||||
switchTime()
|
||||
end },
|
||||
{ title = "输入开机密码", fn = function()
|
||||
local result,subText = hs.dialog.textPrompt("输入开机密码", "时间同步操作需要开机密码", config[1].rootPassword, "确定", "取消", true)
|
||||
if result == "确定" then
|
||||
config[1].rootPassword = subText
|
||||
hs.json.write(config,configPath, true, true)
|
||||
end
|
||||
end },
|
||||
{ title = "-" },
|
||||
{ title = "屏幕取色", fn = function()
|
||||
openColorDialog()
|
||||
end },
|
||||
{ title = "-" },
|
||||
{ title = "咖啡因:" .. config[1].caffeine, fn = function()
|
||||
switchCaffeine()
|
||||
end },
|
||||
{ title = "-" },
|
||||
{ title = "系统状态:" .. config[1].showSysInfo, fn = function()
|
||||
switchSysInfo()
|
||||
end },
|
||||
{ title = "-" },
|
||||
{ title = "打开键盘偏好设置", fn = function() hs.osascript.applescript([[
|
||||
tell application "System Preferences"
|
||||
reveal anchor "InputSources" of pane "com.apple.preference.keyboard"
|
||||
activate
|
||||
end tell ]]
|
||||
) end },
|
||||
{ title = "-" },
|
||||
{ title = "关于", fn = function()
|
||||
if (hs.dialog.blockAlert("当前版本:"..version,"整理了一些能够提高效率的脚本,打开主页查看详细说明。","确定","取消","informational") == "确定") then
|
||||
hs.urlevent.openURL("https://github.com/sugood/hammerspoon")
|
||||
end
|
||||
end },
|
||||
})
|
||||
end
|
||||
|
||||
function initData()
|
||||
--第一次安装需要复制一个配置文件。以后更新则不会修改用户配置文件,防止被覆盖
|
||||
if(checkFileExist(configPath) == false) then
|
||||
print("初始化配置文件")
|
||||
--获取绝对路径,io.open只支持绝对路径
|
||||
local source = hs.fs.pathToAbsolute(initConfigPath)
|
||||
local destination = string.gsub(source, "initConfig.json$", "config.json")
|
||||
copyFile(source,destination)
|
||||
end
|
||||
|
||||
if hs.json.read(configPath) ~= nil then
|
||||
config = hs.json.read(configPath)
|
||||
end
|
||||
initMenu()
|
||||
-- 修改全局alert样式
|
||||
hs.alert.defaultStyle.strokeColor = {white = 1, alpha = 0}
|
||||
hs.alert.defaultStyle.fillColor = {white = 0.05, alpha = 0.50}
|
||||
hs.alert.defaultStyle.radius = 10
|
||||
--清空打印信息
|
||||
console.clearConsole()
|
||||
--
|
||||
colorDialog.mode("RGB")
|
||||
end
|
||||
|
||||
initData()
|
||||
|
||||
-- 字符串判空
|
||||
function stringIsEmpty(str)
|
||||
return str == nil or str == ''
|
||||
end
|
||||
|
||||
--生成url编码
|
||||
function decodeURI(s)
|
||||
s = string.gsub(s, "([^%w%.%- ])", function(c) return string.format("%%%02X", string.byte(c)) end)
|
||||
return string.gsub(s, " ", "+")
|
||||
end
|
||||
|
||||
--截取UTF8字符
|
||||
function SubStringUTF8(str, startIndex, endIndex)
|
||||
if startIndex < 0 then
|
||||
startIndex = SubStringGetTotalIndex(str) + startIndex + 1;
|
||||
end
|
||||
|
||||
if endIndex ~= nil and endIndex < 0 then
|
||||
endIndex = SubStringGetTotalIndex(str) + endIndex + 1;
|
||||
end
|
||||
|
||||
if endIndex == nil then
|
||||
return string.sub(str, SubStringGetTrueIndex(str, startIndex));
|
||||
else
|
||||
return string.sub(str, SubStringGetTrueIndex(str, startIndex), SubStringGetTrueIndex(str, endIndex + 1) - 1);
|
||||
end
|
||||
end
|
||||
|
||||
--获取中英混合UTF8字符串的真实字符数量
|
||||
function SubStringGetTotalIndex(str)
|
||||
local curIndex = 0;
|
||||
local i = 1;
|
||||
local lastCount = 1;
|
||||
repeat
|
||||
lastCount = SubStringGetByteCount(str, i)
|
||||
i = i + lastCount;
|
||||
curIndex = curIndex + 1;
|
||||
until(lastCount == 0);
|
||||
return curIndex - 1;
|
||||
end
|
||||
|
||||
function SubStringGetTrueIndex(str, index)
|
||||
local curIndex = 0;
|
||||
local i = 1;
|
||||
local lastCount = 1;
|
||||
repeat
|
||||
lastCount = SubStringGetByteCount(str, i)
|
||||
i = i + lastCount;
|
||||
curIndex = curIndex + 1;
|
||||
until(curIndex >= index);
|
||||
return i - lastCount;
|
||||
end
|
||||
|
||||
--返回当前字符实际占用的字符数
|
||||
function SubStringGetByteCount(str, index)
|
||||
local curByte = string.byte(str, index)
|
||||
local byteCount = 1;
|
||||
if curByte == nil then
|
||||
byteCount = 0
|
||||
elseif curByte > 0 and curByte <= 127 then
|
||||
byteCount = 1
|
||||
elseif curByte>=192 and curByte<=223 then
|
||||
byteCount = 2
|
||||
elseif curByte>=224 and curByte<=239 then
|
||||
byteCount = 3
|
||||
elseif curByte>=240 and curByte<=247 then
|
||||
byteCount = 4
|
||||
end
|
||||
return byteCount;
|
||||
end
|
||||
|
||||
--判断是否复制成功
|
||||
function isCopySuccess()
|
||||
local num = hs.pasteboard.changeCount()
|
||||
print("复制前数量:"..num)
|
||||
hs.eventtap.keyStroke({ "cmd" }, "C")
|
||||
local numAfter = hs.pasteboard.changeCount()
|
||||
print("复制后数量:"..numAfter)
|
||||
return numAfter > num
|
||||
end
|
||||
|
||||
function openColorDialog()
|
||||
hs.openConsole(true)
|
||||
colorDialog.show()
|
||||
colorDialog.mode("RGB")
|
||||
colorDialog.callback(function(a,b)
|
||||
if b then
|
||||
hs.closeConsole()
|
||||
end
|
||||
end)
|
||||
hs.closeConsole()
|
||||
end
|
||||
|
||||
--设置颜色拾取快键键
|
||||
hs.hotkey.bind(hyperCmd, "P", function ()
|
||||
openColorDialog()
|
||||
end)
|
||||
|
||||
--设置咖啡因开关
|
||||
hs.hotkey.bind(hyperCmd, "S", function ()
|
||||
switchCaffeine()
|
||||
end)
|
||||
@@ -0,0 +1,171 @@
|
||||
local chooser = require("hs.chooser")
|
||||
|
||||
local historyPath= "~/.hammerspoon/data/history.json"
|
||||
local maxLength = 1000
|
||||
local history = {}
|
||||
local mChooser
|
||||
|
||||
function initData()
|
||||
if hs.json.read(historyPath) ~= nil then
|
||||
history = hs.json.read(historyPath)
|
||||
end
|
||||
isSearck = false
|
||||
end
|
||||
-- 初始化,读取本地数据
|
||||
initData()
|
||||
-- 查重
|
||||
function duplicate(table,keys)
|
||||
for k,v in ipairs(table) do
|
||||
if v.text == keys then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- 查询text是否存在并返回索引index
|
||||
-- 等于0为没有查询到,大于0为查询到
|
||||
function searchByText(table,text)
|
||||
for k,v in ipairs(table) do
|
||||
if v.text == text then
|
||||
print("结果:"..k)
|
||||
return k
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
-- 清除收尾空格
|
||||
function trim(input)
|
||||
return (string.gsub(input, "^%s*(.-)%s*$", "%1"))
|
||||
end
|
||||
-- 字符串分割
|
||||
string.split = function(s, p)
|
||||
local rt= {}
|
||||
string.gsub(s, '[^'..p..']+', function(w) table.insert(rt, w) end )
|
||||
return rt
|
||||
end
|
||||
-- 添加片段到记录列表中
|
||||
function addToHistory()
|
||||
local item = {}
|
||||
local str = hs.pasteboard.getContents()
|
||||
if str == nil then
|
||||
hs.alert.show("文本为空,请重新选择文本!")
|
||||
end
|
||||
local list = string.split(str, "|")
|
||||
if #list >1 then
|
||||
item.subText = trim(string.sub(str,#list[1]+2,string.len(str)))
|
||||
item.text = trim(list[1])
|
||||
else
|
||||
item.subText = trim(list[1])
|
||||
item.text = trim(list[1])
|
||||
end
|
||||
|
||||
if duplicate(history, item.text) then
|
||||
hs.alert.show("片段已经存在")
|
||||
return
|
||||
end
|
||||
if #history >= maxLength then
|
||||
hs.alert.show("片段已超过:"..maxLength.."个")
|
||||
return
|
||||
end
|
||||
table.insert(history, 1, item)
|
||||
-- 排序
|
||||
table.sort(history,function(a,b) return a.subText<b.subText end )
|
||||
|
||||
hs.json.write(history,historyPath, true, true)
|
||||
hs.alert.show("成功添加片段:"..item.text)
|
||||
end
|
||||
-- 按下添加快捷键时映射到复制快捷键
|
||||
function bindCopyKey()
|
||||
hs.eventtap.keyStroke({ "cmd" }, "C")
|
||||
end
|
||||
-- 粘贴选中的片段
|
||||
local completionFn = function(result)
|
||||
if result then
|
||||
hs.pasteboard.setContents(result.text)
|
||||
hs.eventtap.keyStroke({ "cmd" }, "V")
|
||||
print("keywords:"..result.text)
|
||||
end
|
||||
end
|
||||
-- 添加片段到记录列表中
|
||||
function modifyHistory(text, subText, isText, index)
|
||||
if text and subText then
|
||||
if isText and duplicate(history, text) then
|
||||
hs.alert.show("片段已经存在")
|
||||
return
|
||||
end
|
||||
|
||||
history[index].text = text
|
||||
history[index].subText = subText
|
||||
-- 排序
|
||||
table.sort(history,function(a,b) return a.subText<b.subText end )
|
||||
|
||||
hs.json.write(history,historyPath, true, true)
|
||||
if isText then
|
||||
hs.alert.show("成功修改片段内容:"..text)
|
||||
else
|
||||
hs.alert.show("成功修改片段说明:"..subText)
|
||||
end
|
||||
else
|
||||
hs.alert.show("参数错误")
|
||||
return
|
||||
end
|
||||
end
|
||||
-- 右键弹出菜单
|
||||
local rightClickCallbackFn = function(index)
|
||||
if index and index > 0 then
|
||||
local selectResult = mChooser:selectedRowContents(index)
|
||||
if selectResult == nil or stringIsEmpty(selectResult.text) then
|
||||
return
|
||||
end
|
||||
index = searchByText(history,selectResult.text)
|
||||
if index == 0 then
|
||||
hs.alert.show("找不到片段")
|
||||
return
|
||||
end
|
||||
menubar = hs.menubar.new(false)
|
||||
menubar:setTitle("Hidden Menu")
|
||||
menubar:setMenu( {
|
||||
{ title = "菜单", fn = function() print("you clicked my menu item!") end },
|
||||
{ title = "-" },
|
||||
{ title = "修改片段内容", fn = function()
|
||||
result,text = hs.dialog.textPrompt("修改片段内容", "请输入新的内容", history[index].text, "确定", "取消")
|
||||
if result == "确定" then
|
||||
modifyHistory(text,history[index].subText,true,index)
|
||||
end
|
||||
end },
|
||||
{ title = "修改片段说明", fn = function()
|
||||
result,subText = hs.dialog.textPrompt("修改片段说明", "请输入新的说明", history[index].subText, "确定", "取消")
|
||||
if result == "确定" then
|
||||
modifyHistory(history[index].text,subText,false,index)
|
||||
end
|
||||
end },
|
||||
{ title = "-" },
|
||||
{ title = "删除当前片段", fn = function()
|
||||
if hs.dialog.blockAlert("确定删除以下片段?",history[index].text,"确定","取消","informational") == "确定" then
|
||||
table.remove(history,index)
|
||||
hs.json.write(history,historyPath, true, true)
|
||||
hs.alert.show("成功删除片段")
|
||||
end
|
||||
end },
|
||||
})
|
||||
menubar:popupMenu(hs.mouse.getAbsolutePosition(), true)
|
||||
else
|
||||
hs.alert.show("错误")
|
||||
end
|
||||
end
|
||||
-- 选取片段内容(按下快捷键时显示片段列表,点击选中的快捷键将自动粘贴)
|
||||
hs.hotkey.bind(hyperCmd, "V", function ()
|
||||
mChooser = chooser.new(completionFn)
|
||||
:choices(history)
|
||||
:rightClickCallback(rightClickCallbackFn)
|
||||
:searchSubText(true)
|
||||
:show()
|
||||
end)
|
||||
-- 添加片段(按下快捷键时做一个复制操作,并记录复制的内容到片段列表中)
|
||||
hs.hotkey.bind(hyperCmd, "X", function ()
|
||||
bindCopyKey()
|
||||
if hs.dialog.blockAlert("添加片段:‘|’为分隔符,建议按如下格式","内容|keyword|示例|说明","确定","取消","informational") == "确定" then
|
||||
addToHistory()
|
||||
end
|
||||
end)
|
||||
Reference in New Issue
Block a user