1 简介
utools是一个生产力工具,自由集成丰富插件,快速匹配「场景功能」,用完即走。
可以先看一下官网,和一个视频初步了解下utools:
官方文档:主页,技术文档
介绍视频:我心目中最佳的国产软件之一:全平台装机必备。_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili
以ocrg功能为例,补充介绍下用法。
需要先装插件,
推荐“长按鼠标右键”打开超级面板,
然后打开一张图片,长按右键,就有ocr功能出来了。
或者直接打开ocr功能,然后把要识别的内容截图粘贴进去。
即utools还可以代替天若ocr、文件批量重命名等一堆工具。
划词长按右键,也自带翻译功能。
可以设置一些常用功能的全局快捷键
2 快捷命令
utools有个「快捷命令」的插件:
可以用python等其他编程语言,来扩展开发自己的工具库插件。
因为我自己是python的重度用户,而且也积累了pyxllib、pyxlpr等工具包;
用「快捷命令」,就可以把windows等系统上各种应用场景,和我的python工具包做关联,实现很多强大的功能。
所以本篇文章,主要是讲「快捷命令」的原理、开发、应用。
首先要新建自己的“快捷命令”: 然后我们来详细讲解下这个窗口各个设置的含义
2.1 匹配
在什么场景下会触发出该「命令」功能菜单。
一共五种,本质上只有四种,第五种是前四种的组合:
匹配模式 | 解释 | 一些功能应用场景例子 | latex编校工作中的例子 |
---|---|---|---|
关键字 | Alt+Enter打开utools后,敲功能名使用。 | 在任意场景,随时打开find(相当于everything)查找功能等各种小工具,用完即走。查找功能的过程方便,支持拼音首字母缩写等等。 | 相当于存在winr目录里的一些脚本,然后输入texpng.py、bc.py,就可以执行对应脚本。用「快捷命令」来做的好处是不用添加winr环境变量,而且还有subinput等很多扩展功能,使用更加灵活,交互更加方便,详见后文讲解。 |
正则/划词 | 选中一段文本后,打开满足对应正则匹配的功能菜单。 | 划词翻译;匹配到如果是数学表达式,自动计算结果。 | 原来用pyqt写的剪切板监控工具,可以复制文本后,分析规则,按不同的需求进行自动处理。 |
窗口/进程 | 在资源浏览器(explorer.exe)、chrome浏览器、OneNote等等各种软件、窗口中,打开对应的功能菜单。 | 将目录下的图片进行压缩减小体积。 | 可以对texpng.py进行扩展,在当前目录打开执行,不用输入待处理的目录路径,自动将目录下所有的pdf生成出png图片。 |
复制/选中文件 | 选中部分文件、目录后进行处理。(在everything界面,选中的文件可以是不同目录里的) | 只对选中的图片进行压缩减小体积。 | 相当于我原来写的把py功能加进右键菜单,比如文件备份功能。不过那个还要改注册表,麻烦多了。有很多需要选中部分文件、目录进行处理的功能,都可以用这个模式。 |
专业模式 | 高级模式,可以通过配置文件来实现上述所有情况的匹配。 | 比如图片压缩功能,① 即可以当一个软件打开后,拖入要处理的图片,② 也可以在一个目录打开处理目录下所有图片,③ 还可以对选中的部分图片处理。那么不需要写三个接口,可以用专业模式来匹配。 |
看utools官方文档,还会看到两种模式:
img: 图片匹配,试不出来,但可以用files代替
over: 无匹配,可以用全匹配正则代替
img可以用选中文件代替,over可以用正则匹配代替,这两类不是必须的。
2.2 配置
不同的匹配模式,对应的配置方法是不同的,在不同场景,不是每个功能每次都要显示出来。
比如“图片压缩功能”,如果选中的是“txt”文件,就不应该弹出这个功能命令;
再比如Beyond Compare对比功能,只有选中2个文件时才弹出,一个文件或太多文件都没必要进行bc比较。
这些精细的控制,可以用“配置”项来完成。
匹配模式 | 类型:解释 | 补充说明 |
---|---|---|
关键字 | 关键字:多个关键字用逗号隔开 | |
正则/划词 | 正则:匹配文本的正则,如/.*?\.exe$/i | 这个正则是js的语法,也就是比py的正则,前后多了一个/,并且在末尾设置模式,例如i是不区分大小写。 |
窗口/进程 | 进程:多个窗口进程逗号隔开,留空匹配所有窗口 | 比如很多功能只是在explorer.exe资源浏览器中才是用的。在OneNote等窗口不触发该功能。 |
复制/选中文件 | 正则:匹配文件的正则,如/.*?\.exe$/i | |
专业模式 | 配置:等效于 features.cmds | 可以用一个json表达出上述4种的复杂组合规则,详细可以看官方关于features.cmds的解释: 完整配置 | uTools。不太懂也没关系,后面会有示例代码。 |
2.3 说明/标签/环境/图标
这几个项目就比较简单了,一起说。
说明:该「命令」的功能详细介绍
标签:如果开发的「命令」比较多,可以加上标签分组管理
环境:所使用的脚本语言,比如使用python脚本
图标:注意可以设置命令图标
2.4 变量
不同「匹配」模式,变量也有些许差别,写python的时候,可以这样引用内容:
cmds = dict()
# 通用属性
cmds['isWin'] = {{isWin}} # 是否Window系统, 返回1或0
cmds['LocalId'] = '{{LocalId}}' # 本机唯一ID
cmds['BrowserUrl'] = r'''{{BrowserUrl}}''' # 浏览器当前链接
cmds['ClipText'] = r'''{{ClipText}}''' # 剪切板的文本(为了避免出bug,建议用 pyperclip.paste().replace('\r\n', '\n') 实现 )
cmds['subinput'] = r'''{{subinput}}''' # 子输入框的文本
cmds['type'] = '{{type}}' # 专业模式的type
cmds['payload'] = r'''{{payload}}''' # 专业模式的payload, JSON格式字符串
# 划词可用
cmds['input'] = r'''{{input}}''' # 主输入框的文本
# 窗口可用
cmds['pwd'] = '{{pwd}}' # 文件管理器当前目录
cmds['WindowInfo'] = r'''{{WindowInfo}}''' # 当前窗口信息, JSON格式字符串
# 文件可用
cmds['MatchedFiles'] = r'''{{MatchedFiles}}''' # 匹配的文件,JSON格式字符串
注意划词、窗口、文件三种模式,都有自己专用的一些变量,在其他模式不能写出来,否则「命令」会报错保存不了。
但「专业」模式比较特别,可以使用所有变量,但也只是不会报错而已,例如“划词”模式是不存在MatchedFiles变量的,实际会以普通的’{{MatchedFiles}}’字符串传入。
注意我上述的python代码写法。
因为“变量”的实现本质,是用{{var}}的占位符来表示,在执行的时候,会将这些特殊符号直接宏展开,
然后得到一个新的py脚本文件,存储在临时文件夹里:C:\Users\chen\AppData\Local\Temp\quickcommandTempFile.py,
最后实际就是运行这个脚本。
这样的宏展开机制,有个隐患问题,如果内容本身包含了单引号,我们还额外用了单引号,整个py脚本语法解释是会出错的。
所以为了最大限度减小出错概率,我特地用r字符串、三引号模式来保存原始宏展开内容。
其中有些数值比较特别,
isWin本身是数字,所以没用引号;
LocalId是一串普通字母数字构成的,不会有歧义,所以用了单引号。
payload、WindowInfo、MatchedFiles等有时候是json结构数据,这个没关系,先存成字符串,可以后面代码再解析json结构。
补充说明:
窗口模式,还有个SelectFile变量,这个命令说是linux用不了,但是我实测在window也用不了,所以上述就没有讲解使用该变量。
这个变量无所谓的,没什么重要。
各种模式下,变量值的详细示例:
序号 | 属性 | 关键字 | 划词 | 窗口 | 文件 | 专业 |
---|---|---|---|---|---|---|
1 | isWin (是否Window系统, 返回1或0) |
1 |
||||
2 | LocalId (本机唯一ID) |
cfaf836ce6dc5930a6268d27f05612bf | ||||
3 | BrowserUrl (如果在浏览器窗口,可以获得当前网址链接) |
https://www.baidu.com | undefined | undefined | undefined | |
4 | ClipText (剪切板内容) |
1\t\n\t2\n\t5\n3\t4\n | \n百度热榜 (划词操作默认会先复制到剪切板) |
本质上是把代码宏展开,在这里运行”C:\Users\chen\AppData\Local\Temp\quickcommandTempFile.py”。 | 剪切板的文本,为了避免出bug,建议用 pyperclip.paste().replace(‘\r\n’, ‘\n’) 等价实现 | 专业模式可以用所有属性名,在某些匹配模式下,没有对应宏的不展开 |
5 | subinput (启动功能后,额外输入的内容) |
|||||
6 | type(匹配类型) | text | regex | window | files | |
7 | payload (内容同专有属性) |
快捷命令/关键字 | 百度热榜 (input内容默认会strip掉两边空白) |
{‘id’: 67464, ‘class’: ‘Framework::CFrame’, ‘title’: ‘w210329: - OneNote’, ‘x’: 56, ‘y’: -8, ‘width’: 1872, ‘height’: 1096, ‘appPath’: ‘C:\Program Files\Microsoft Office\root\Office16\ONENOTE.EXE’, ‘pid’: 11844, ‘app’: ‘ONENOTE.EXE’} | [{‘isFile‘: False, ‘isDirectory‘: True, ‘name‘: ‘组会’, ‘path‘: ‘D:\Calibre\paper\组会’}, {‘isFile’: …}] | |
8 | 专有属性 (从工程角度,推荐尽可能用专有属性名获取数据,而不是payload) |
input=百度热榜 | WindowInfo, kwargs[‘WindowInfo’] = json.loads(r’’’{{WindowInfo}}’’’.encode(‘utf8’)) |
MatchedFiles,有时候会出现D:\\\的情况,有小bug,没payload稳定,使用时推荐写:kwargs[‘MatchedFiles’] =json.loads(r’’’{{payload}}’’’.encode(‘utf8’)) | {{input}},不存在的属性没有宏展开就会存储原始字符串内容 | |
9 | 其他属性 | pwd=C:\\Users\\chen\\desktop SelectFile,我自己测,这个参数在win也不能用 |
2.5 脚本/输出/编码/参数
最后的脚本就没什么好讲啦,如果是py,就在这里写py代码就行了。
这个使用的是本机的py解释器环境,如果按照了各种包,都可以用。
“输出”有多种格式,读者自己试一下就知道效果了。
“编码设置”默认可以不管;可以设“脚本参数”。
2.6 demo/查看“快捷命令”各种匹配模式下支持的各参数值
我们来做一个可以在各种匹配模式下,查看各变量值的工具,基本配置如下:
具体的“配置”json:
[
"快捷命令/关键词",
{
"type":"regex",
"label":"快捷命令/划词",
"match":"/.{1,}/i"
},
{
"type":"window",
"label":"快捷命令/窗口"
},
{
"type":"files",
"label":"快捷命令/文件"
}
]
脚本:
from pyxllib.basic import TicToc
from pyxllib.utools import UtoolsBase
cmds = dict()
# 通用属性
cmds['isWin'] = {{isWin}} # 是否Window系统, 返回1或0
cmds['LocalId'] = '{{LocalId}}' # 本机唯一ID
cmds['BrowserUrl'] = r'''{{BrowserUrl}}''' # 浏览器当前链接
cmds['ClipText'] = r'''{{ClipText}}''' # 剪切板的文本(为了避免出bug,建议用 pyperclip.paste().replace('\r\n', '\n') 实现 )
cmds['subinput'] = r'''{{subinput}}''' # 子输入框的文本
cmds['type'] = '{{type}}' # 专业模式的type
cmds['payload'] = r'''{{payload}}''' # 专业模式的payload, JSON格式字符串
# 划词可用
cmds['input'] = r'''{{input}}''' # 主输入框的文本
# 窗口可用
cmds['pwd'] = '{{pwd}}' # 文件管理器当前目录
cmds['WindowInfo'] = r'''{{WindowInfo}}''' # 当前窗口信息, JSON格式字符串
# 文件可用
cmds['MatchedFiles'] = r'''{{MatchedFiles}}''' # 匹配的文件,JSON格式字符串
with TicToc(__name__):
UtoolsBase(cmds, outfmt='html').check_cmds()
注意要安装pip install pyxllib>=0.0.71,有版本问题的可以用anaconda来管理。
另外注意,任何改动,包括pyxllib,脚本都会第一时间更新,不需要重启utools。
运行效果,以表格的形式显示「快捷命令」支持的变量的值:
“[32m2021-04-07 20:51:41[0m”不是乱码,而是命令行里显示彩色的,这里只支持纯文本就变成这种奇怪的效果了,
我觉得问题不大,就暂时没改。不爽的人可以把with TicToc删掉。
2.7 有导入/导出/分享功能
注意右下角菜单,具体用法我这里就不累赘了。
3 通用文件批处理功能
3.1 工具接口设计理念
前面显示变量值的功能看似简单,但展示了我关于 「快捷命令」和python如何结合的一些重要框架理念。
- 首先匹配模式可以无脑选“专业”模式,只要掌握专业模式的匹配规则写法就行了。
- 所有其他模式的规则,都可以有等价的专业模式匹配写法
- 而且专业模式更加精细,可以有更多的参数可以控制,比如控制选中文件的数量为多少才激活
- 专业模式能获取所有参数值,然后可以无脑打包为kwargs的形式传入给python接口
- 变量中有”type”,如果需要,可以在py代码里再判断type后分类处理
- 这样可以把复杂性都集中到py去处理,而不用每种匹配模式都新建一个「快捷命令」,多杂难维护
- 打包的时候建议存储使用原始值,在py代码里再解析json等
- ClipText比较特别,容易出bug,可以选择不取,而在py代码用pyperclip.paste()等价方式获取
- 使用上述设计理念,可以最大限度发挥「快捷命令」的设计灵活性,用最少的扩展「命令」,实现尽可能多的py功能变种。
把复杂度都迁到py后,py这里的设计方式就很重要了,目前是在pyxllib.utools专门设计了类UtoolsBase
- 在类初始化,就可以进行所有功能执行前都要做的预处理工作。获得所有变量值
- 判断哪些变量是空值
- 如果是json,自动先解析出来
- 如果没有ClipText,用pyperclip.paste().replace(‘\r\n’, ‘\n’)更鲁棒的形式获得剪切板的内容
- 如果有pwd参数,则切换到该工作目录
- 增加subinput的简单扩展解析功能
- 新增outfmt,可以在py接口简单切换各种返回模式
- 具体pandas的DataFrame表达规则,封装_print_df_result函数来实现
- 有时候html解析失败(因为windows上默认gbk的原因),会自动切换为browser,使用浏览器打开
- 同理,很多类似的操作
- 比如要对文件操作,要对图片操作,都可以封装类似的类UtoolsFile、UtoolsImage等
- 把某类问题要统一提前预处理的部分,都在类初始化完成
- 这样要在py扩展功能就快的多
做到这个程度,已经比原来暴力一个一个功能对接开发快的多了,但还是很麻烦。
pyxllib有很多精细功能操作,如果每次稍微一点变型都要重新增加一个接口很麻烦。
为此,我们做一个更抽象高级的封装,下面以我做的文件批量处理功能为例讲解。
3.2 文件批处理
配置:
[
{
"type": "files",
"label": "文件/codefile"
},
{
"type": "window",
"label": "目录/codefile",
"match": {
"app": "explorer.exe"
}
}
]
脚本:
from pyxllib.utools import UtoolsFile
cmds = dict()
# 通用属性
cmds['isWin'] = {{isWin}} # 是否Window系统, 返回1或0
cmds['LocalId'] = '{{LocalId}}' # 本机唯一ID
cmds['subinput'] = r'''{{subinput}}''' # 子输入框的文本
cmds['type'] = '{{type}}' # 专业模式的type
cmds['payload'] = r'''{{payload}}''' # 专业模式的payload, JSON格式字符串
# 窗口可用
cmds['pwd'] = '{{pwd}}' # 文件管理器当前目录
cmds['WindowInfo'] = r'''{{WindowInfo}}''' # 当前窗口信息, JSON格式字符串
# 文件可用
cmds['MatchedFiles'] = r'''{{MatchedFiles}}''' # 匹配的文件,JSON格式字符串
UtoolsFile(cmds).codefile()
3.3 paths/files/dirs
只要3.2里那样配置一个这样的「命令」,以后就可以做很多自定义灵活的文件操作了。
这跟我的codefile功能接口实现方式有关: pyxllib v0.0.71 utools
这里并没有设计任何具体的功能。
而是预制好的一些变量。
比如 paths,这个变量以列表list的形式,存储了当前目录、或者选中的所有对象,以 pathlib.Path 类存储。
启动功能后,可以在subinput窗口写python代码执行!
比如我在一个目录下打开”目录/codefile”功能,然后输出这里文件和目录总数,一共是41个:
再比如我输出每个路径:
paths同时存储了文件和目录,也可以用只存储了文件的files,或者只存储了目录的dirs。
files里每个对象是pyxllib的File类,dirs里每个对象是pyxllib的Dir类。
3.4 rpaths/rfiles/rdirs
前面的文件只存储了当前目录下、或者选中的文件。
使用带前缀r的版本,可以递归获得所有子文件。
比如rpaths就是递归所有目录,取出所有路径,rfiles就是递归获得当前以及所有子文件。
3.5 path/file/dir、rpath/rfile/rdir
有时候需要循环处理选中的每个文件,可以不用手动操作files,直接用file变量即可,
codefile功能接口会自动去迭代运行,比如刚才输出所有paths的版本,也可以写成这样:
3.6 可以扩展更多预制 变量
比如还可以修改源码,添加imfile、rimfile、imfiles、rimfiles,只获取图片文件,然后处理。
3.7 导入自己的包扩展更多功能
可以在3.2的脚本里导入自己的更多高级工具包,然后在subinput可以自由组合,进行很多高级的文件操作。
比如from pyxllib.cv import PilImg,pyxllib库的一个图像处理类。
然后这里初始化一个图像后,执行reduce_filesize()对图片进行压缩,然后再write保存回原始路径。
因为现在手机拍的很多照片都特别大,没有压缩过,其实只要PIL打开然后重新保存,基本都能从12M降低到2M。
如果想自己精细控制图片大小上限,可以 PilImg(imfile).reduce_filesize(300*1024).write(imfile),
reduce_filesize有参数,这样写可以将图片压缩到300kb以内。
相比传统的在pycharm里写代码运行,这个好处是可以随时调出来取用,甚至可以手动选择目录下若干图片单独操作。
4 「快捷命令」改进建议
左边菜单栏不能拉宽,一些名称较长的项目就看不全了
(不紧急)支持获取完整字段值的json数据
MatchedFiles 获取的内容有 bug
subinput可以填充默认值?
直接运行,而不是还要再按一下回车?