diff --git a/README.md b/README.md index 3f0b384..c49811e 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,38 @@ 该workflow把命令分为key -> values形式,如下所示,key属于大分类,匹配到key后会显示其下全部value. -目前支持json以及yaml格式配置 +目前支持yaml格式(推荐)以及json配置,这里以yaml为例介绍字段含义 -**json格式** +```yaml +- key: 用于搜索指令 + remark: 用于指令描述 + tags: 辅助搜索关键词,可以不填写 + values: + - cmd: 搜索命中后展示的内容 + remark: 命中后内容描述 +``` + +**eg:yaml格式** + +```yaml +- key: ss + remark: 搜索引擎 + tags: sousuo,baidu,duoji + values: + - cmd: https://www.baidu.com/s?wd={clip_0} + remark: 百度地址 + - cmd: https://www.dogedoge.com/results?q={clip_0} + remark: 多吉搜索 +- key: cc + remark: 通用命令 + values: + - cmd: git branch -r | sed 's/origin///g' | grep '/' | xargs git push origin --delete + remark: git批量删除远程分支} + - cmd: npm install --registry=http://registry.npm.alibaba-inc.com {clip_0} + remark: npm使用淘宝源安装 +``` + +**eg:json格式** ```json [ { @@ -33,54 +62,24 @@ ] ``` -**yaml格式** - -```yaml -- key: 搜索引擎 - remark: 搜索引擎 - values: - - cmd: https://www.baidu.com/s?wd={clip_0} - remark: 百度地址 -- key: git-common - remark: git通用命令 - values: - - cmd: git branch -r | sed 's/origin///g' | grep '/' | xargs git push origin --delete - remark: git批量删除远程分支} - -``` 主要功能: 1. cmd(触发关键词)->搜索key->选择value->复制到粘贴板(可以自动粘贴) 2. cmd(触发关键词)->搜索key->选择value-> 判断是网址 -> 调用浏览器打开 -3. cmd(触发关键词)->open->选择打开命令配置->调用你喜欢的编辑器打开命令配置的json(主要是alfred添加数据不太好用) +3. cmd(触发关键词)->open->选择打开命令配置->调用你喜欢的编辑器打开命令配置(需要在workflow中配置打开应用,默认是TextEdit) 支持获取粘贴板,使`{clip_0}`来代替,最终渲染时会自动进行粘贴板数据替换。比如我选择了`https://www.baidu.com/s?wd={clip_0}`,此时我粘贴板数据假设为 `张三`,那么最终打开浏览器的地址为`https://www.baidu.com/s?wd=张三`。 ### 数据保存 -该插件对应json命令数据都是外置的(便于云端保存,丢到同步盘中即可),因此自己指定一个路径后,以参数形式传入即可. +该插件对应命令数据支持外置的(便于云端保存,丢到同步盘中即可),因此自己指定一个路径后,以参数形式传入即可. -也由于json外置,如果你觉得workflow添加太麻烦的话,直接改这个json,添加对应的数据即可. - -![](http://oobu4m7ko.bkt.clouddn.com/1519546315.png) +![](https://imgblog.mrdear.cn/uPic/PJgMxW_1614003592.png) +#### 更多变量支持 +变量的支持依赖于alfred,可以在自己的脚本中配置多个变量,在后面使用`Utils`工具替换。 +![](http://imgblog.mrdear.cn/1539613678.png?imageMogr2/thumbnail/!100p) ### 演示 -![](https://github.com/mrdear/Command_Search/blob/master/img/yulan.gif) - - -### 其他问题 +![](https://github.com/mrdear/Command_Search/blob/master/assert/yulan.gif) -#### 不想要自动粘贴 - -在alfred插件中选择粘贴这个环节 - -![](http://oobu4m7ko.bkt.clouddn.com/1519546487.png) - -然后勾掉自动粘贴即可. - -![](http://oobu4m7ko.bkt.clouddn.com/1519546513.png) - -#### 更多变量支持 -变量的支持依赖于alfred,可以在自己的脚本中配置多个变量,在后面使用`Utils`工具替换。 -![](http://imgblog.mrdear.cn/1539613678.png?imageMogr2/thumbnail/!100p) diff --git a/action/KeyAction.go b/action/KeyAction.go deleted file mode 100644 index c9d083c..0000000 --- a/action/KeyAction.go +++ /dev/null @@ -1,40 +0,0 @@ -package action - -import ( - "github.com/work-helper/command-search-alfred/model" - "regexp" - "strings" -) - -var re = regexp.MustCompile("[-_\\s]") - -func SearchKeys(searchKey string, projects []model.Project) { - searchKey = re.ReplaceAllString(searchKey, "") - // 查找 - var matchCommands []model.Project - var noMatchCommands []model.Project - for _, v := range projects { - - //以key开头 - key := re.ReplaceAllString(v.Key, "") - if strings.HasPrefix(key, searchKey) { - matchCommands = append(matchCommands, v) - } else { - noMatchCommands = append(noMatchCommands, v) - } - - if strings.EqualFold(key, searchKey) { - // 找到了则直接处理 - parseCommandValue(&v) - return - } - } - //没找到完全匹配的则对部分匹配的处理 - if len(matchCommands) == 0 { - matchCommands = projects - ParseCommands(matchCommands, true) - } else { - matchCommands = append(matchCommands, noMatchCommands...) - ParseCommands(matchCommands, false) - } -} diff --git a/action/ResultParse.go b/action/ResultParse.go deleted file mode 100644 index e53b108..0000000 --- a/action/ResultParse.go +++ /dev/null @@ -1,58 +0,0 @@ -package action - -import ( - "encoding/xml" - "fmt" - "github.com/work-helper/command-search-alfred/model" - "strconv" -) - -var openItem = model.Item{ - Autocomplete: "open", - Uid: "9999999", - Arg: "open", - Title: "打开命令配置", - Subtitle: "该命令会打开当前文件", - Icon: "./icon.png", -} - -func ParseCommands(commands []model.Project, isAppendOpen bool) { - var items = make([]model.Item, 0, len(commands)) - for _, v := range commands { - var item = model.Item{ - Autocomplete: v.Key, - Arg: "", - Title: v.Key, - Subtitle: v.Remark, - Icon: "./icon.png", - } - items = append(items, item) - } - - if isAppendOpen { - items = append(items, openItem) - } - - var result = model.Items{Items: items} - marshal, _ := xml.Marshal(result) - fmt.Println(string(marshal)) -} - -func parseCommandValue(command *model.Project) { - var items = make([]model.Item, 0, len(command.Values)) - for index, v := range command.Values { - var item = model.Item{ - Autocomplete: command.Key, - Uid: strconv.Itoa(index), - Arg: v.Cmd, - Title: v.Remark, - Subtitle: v.Cmd, - Icon: "./icon.png", - } - items = append(items, item) - } - var result = model.Items{Items: items} - - marshal, _ := xml.Marshal(result) - fmt.Println(string(marshal)) -} diff --git a/action/SearchAction.go b/action/SearchAction.go new file mode 100644 index 0000000..cf5de46 --- /dev/null +++ b/action/SearchAction.go @@ -0,0 +1,94 @@ +package action + +import ( + "encoding/json" + "fmt" + "github.com/work-helper/command-search-alfred/model" + "regexp" + "strings" +) + +var re = regexp.MustCompile("[-_\\s]") +var icon = model.Path{Path: "icon.png"} + +func SearchKeysAndPrint(searchKey string, projects []model.Project) { + // 为空则默认返回 + if "" == searchKey { + parseCommands(projects) + return + } + + // 查找 + searchKey = re.ReplaceAllString(searchKey, "") + var matchCommands []model.Project + var noMatchCommands []model.Project + for _, v := range projects { + //以key开头 + key := re.ReplaceAllString(v.Key, "") + tag := re.ReplaceAllString(v.Tags, "") + if strings.Contains(key, searchKey) || strings.Contains(tag, searchKey) { + matchCommands = append(matchCommands, v) + } else { + noMatchCommands = append(noMatchCommands, v) + } + + // 完全匹配则直接处理 + if strings.EqualFold(key, searchKey) { + parseCommandValue(&v) + return + } + } + + //部分匹配的处理,匹配上的优先排序 + if len(matchCommands) == 0 { + matchCommands = projects + parseCommands(matchCommands) + } else { + matchCommands = append(matchCommands, noMatchCommands...) + parseCommands(matchCommands) + } +} + +// 解析外围指令 +func parseCommands(commands []model.Project) { + var items = make([]model.Item, 0, len(commands)) + for _, v := range commands { + var temp = "" + if "" != v.Tags { + temp = "\t\t--" + v.Tags + } + + var item = model.Item{ + Autocomplete: v.Key, + Arg: "", + Title: v.Key, + Subtitle: v.Remark + temp, + Icon: icon, + } + items = append(items, item) + } + + PrintResult(items) +} + +// 解析匹配后内部指令 +func parseCommandValue(command *model.Project) { + var items = make([]model.Item, 0, len(command.Values)) + for _, v := range command.Values { + var item = model.Item{ + Autocomplete: command.Key, + Arg: v.Cmd, + Title: v.Remark, + Subtitle: v.Cmd, + Icon: icon, + } + items = append(items, item) + } + PrintResult(items) +} + +func PrintResult(items []model.Item) { + result := model.Items{Items: items} + bytes, _ := json.Marshal(result) + fmt.Println(string(bytes)) +} diff --git a/assert/dataTpl.yaml b/assert/dataTpl.yaml new file mode 100644 index 0000000..3520a0b --- /dev/null +++ b/assert/dataTpl.yaml @@ -0,0 +1,15 @@ +- key: ss + remark: 搜索引擎 + tags: sousuo,baidu,duoji + values: + - cmd: https://www.baidu.com/s?wd={clip_0} + remark: 百度地址 + - cmd: https://www.dogedoge.com/results?q={clip_0} + remark: 多吉搜索 +- key: cc + remark: 通用命令 + values: + - cmd: git branch -r | sed 's/origin///g' | grep '/' | xargs git push origin --delete + remark: git批量删除远程分支} + - cmd: npm install --registry=http://registry.npm.alibaba-inc.com {clip_0} + remark: npm使用淘宝源安装 diff --git a/img/yulan.gif b/assert/yulan.gif similarity index 100% rename from img/yulan.gif rename to assert/yulan.gif diff --git a/data.json b/data.json deleted file mode 100644 index 1350afc..0000000 --- a/data.json +++ /dev/null @@ -1,22 +0,0 @@ -[ - { - "key": "搜索引擎", - "values": [ - { - "cmd": "https://baidu.com", - "remark": "百度地址" - } - ], - "remark": "搜索引擎" - }, - { - "key": "git-common", - "values": [ - { - "cmd": "git branch -r | sed 's/origin///g' | grep '/' | xargs git push origin --delete", - "remark": "git批量删除远程分支" - } - ], - "remark": "git通用命令" - } -] \ No newline at end of file diff --git a/go.mod b/go.mod index 2223c46..ac5e7bd 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module github.com/work-helper/command-search-alfred +go 1.15 + require gopkg.in/yaml.v2 v2.2.1 diff --git a/main.go b/main.go index 46c6173..7a6eb13 100644 --- a/main.go +++ b/main.go @@ -3,11 +3,16 @@ package main import ( "flag" "github.com/work-helper/command-search-alfred/action" + "github.com/work-helper/command-search-alfred/model" "github.com/work-helper/command-search-alfred/util" + "os" "strings" ) -const defaultDataPath = "./data.json" +const defaultDataPath = "./dataTpl.yaml" + +var errorIcon = model.Path{Path: "error.png"} +var openIcon = model.Path{Path: "open.png"} func main() { // search key @@ -15,16 +20,33 @@ func main() { dataPath := flag.String("p", defaultDataPath, "data source") flag.Parse() - projects := util.ReadProjects(*dataPath) - - if len(projects) == 0 || 0 == strings.Compare("open", *searchKey) { - projects = projects[:0] - action.ParseCommands(projects, true) + // 检查文件是否存在 + _, err := os.Stat(*dataPath) + if nil != err && !os.IsExist(err) { + item := model.Item{ + Type: "default", + Title: "配置文件不存在", + Subtitle: "请检查数据路径配置是否正确", + Icon: errorIcon, + } + action.PrintResult([]model.Item{item}) return } - // 搜索key不为空时则搜索 - if len(*searchKey) != 0 { - action.SearchKeys(*searchKey, projects) + // 判断是否为打开文件 + if 0 == strings.Compare("open", *searchKey) { + item := model.Item{ + Type: "default", + Arg: "open", + Title: "打开命令配置", + Subtitle: "该命令会打开当前文件", + Icon: openIcon, + } + action.PrintResult([]model.Item{item}) + return } + + // 进行数据搜索 + projects := util.ReadProjects(*dataPath) + action.SearchKeysAndPrint(*searchKey, projects) } diff --git a/model/commands.go b/model/commands.go index 175750a..2d0985a 100644 --- a/model/commands.go +++ b/model/commands.go @@ -2,12 +2,15 @@ package model import ( _ "encoding/json" - "encoding/xml" ) +// 数据结果 type Project struct { Key string + // 参与搜索 + Tags string + Values []Value Remark string @@ -19,18 +22,27 @@ type Value struct { Remark string } -// 结果 - +// alfred 模型 type Items struct { - XMLName xml.Name `xml:"items"` - Items []Item `xml:"item"` + Items []Item `json:"items"` } type Item struct { - Autocomplete string `xml:"autocomplete,attr"` - Uid string `xml:"uid,attr"` - Arg string `xml:"arg,attr"` - Title string `xml:"title"` - Subtitle string `xml:"subtitle"` - Icon string `xml:"icon"` + // 可选,每个 item 的唯一标识,后续 Alfred 能依托这个 uid,根据用户操作进行排序。如果想保持自己脚本返回的顺序,不用 Alfred 的排序,可以不设置这个字段。 + Uid string `json:"uid,omitempty"` + // “default” | “file” | “file:skipcheck”(可选,默认 “default”) + Type string `json:"type"` + // 顾名思义,Row 的标题。 + Title string `json:"title"` + // subtitle(可选) + Subtitle string `json:"subtitle"` + // 非常建议 item 包含这个字段,它会作为 item 的输出,传递给下一个事件。如果不包含这个字段,就无法知道用户选的是哪个。 + Arg string `json:"arg"` + Autocomplete string `json:"autocomplete,omitempty"` + // 以相对路径形式引用 workflow 沙盒中的图标 + Icon Path `json:"icon"` +} + +type Path struct { + Path string `json:"path"` }