对于一个重度代码洁癖患者, 看到下面这样的代码, 心中难免奇痒难耐, 想要给它对齐了去!
1 | local name = params.name or "Arial" |
sublime 的代码对齐插件有很多, 大家可以看这里, 我之前一直使用的是 VAlign, 事实上它在多数的情况下还是很好使的. 但是它还是有这么几个问题:
- 个别情况下代码对齐的不够理想.
- 不能多次对齐.
- 就算已经对齐, 也会使得文件变为 modified 状态.
一种造轮子的冲动涌上心头.
开干
之前一直没有尝试过类似的事情, 一上来有些发蒙, 从哪里入手呢? 仔细分析了下需求, 将功能切分为小块.
1. 一行代码的特征
什么样的代码会需要对齐? 多行相似的代码. 怎么判断相似? 有共同的特征吗? 一行代码的特征有好多, 怎么确定那个是你想要的.
最终我选择了 缩进层级
作为第一个特征, 如果两个文字的缩进层级不一致的话, 它们就不会被对齐. 第二个特征我选择了 关键字列表
, 我找出了所有关键字和它们在这一行中的位置.
1 | { [1] = {keyword : "=", position: 10}, [2] = {keyword : ",", position: 20}, ...} |
2. 找到相似行
我的做法和 Vlign 是一致的, for 循环分别加减一个游标, 代表着当前行, 获取这一行的特征数据, 如果缩进和关键字列表中的第一个元素一致的话, 则记录这一行, 否则跳出循环.
这样当 for 循环结束后, 我们就获得了一个多行数据的列表.
1 | { |
3. 删除已经对齐的keyword
按照我的设想, 应该是每调用一次对齐函数, 就找到第一个没有对齐的关键字进行对齐, 这样当一组需要对齐的文字中有多个可以对齐的关键字的话, 就需要多次调用对齐函数. 那么问题就来了? 如何判断出当前相对齐的是哪一个关键字呢?
我是这样子做的, 前面不是找到了多行数据的列表嘛, 我们遍历一下这个列表, 如果这些行的关键字列表中的第一个元素的位置是一样的, 那么这个关键字就已经对齐了, 那么我便删除它.
这样多次后, 列表中的行的关键字列表的第一个元素就是我们需要对齐的那个元素啦.
但是这样之后, 之前的行数据就会有中断的情况, 所以我们需要再次整理这些数据.
4. 去除关键字周围的空白
我举个栗子, 比如下面这两行代码:
1 | local a = 1 |
我们以 =
为关键字对齐它, 如果不去除周围的空白的话, 对齐出来的将会是这个样子的:
1 | local a = 1 |
这显然不是我们需要的, 我的实现是这个样子的, 还是 for 循环使用一个游标从关键字位置分别向前后遍历, 遇到第一个非空字符停止, 这样循环结束后便会获得一个区间. 然后我们在根据这个关键字左右是否需要空格构造一个新的关键字内容去替换掉那个区间的字符串.
5. 对齐行
真正昨晚上上面的那些处理后, 对齐这些行的逻辑其实十分简单, 甚至都不超过10行代码. 主要就是遍历一遍, 找出某个关键字在所有行中的最大位置, 然后给每行关键字的前面或后面补足与最大值的差值的空格即可.
FAlign
FAlign 是 sublime 的一个代码对齐插件, 实现了一行代码多个关键字的对齐功能.
代码开源在github: https://github.com/justbilt/sublime-falign, 大家可自行取阅.
安装
两个方法安装:
- 如果安装了 Package Control 的话, 可以搜索
FAlign
安装 - 将源码 clone 到你 sublime 插件目录
使用方法
⌘ + \
对齐第一个关键字, 再次按下对齐第二个关键字, …
示例
1 | Button = import(".utils.Button") |
1 | Button = import(".utils.Button") |
1 | dispatcher:addEventListener("mail_new", mail_new) |
1 | dispatcher:addEventListener("mail_new", mail_new) |