- 2021-03-22 更新
-
下面的第一个愿望已经在 formatR 1.9 中实现。
- 2021-05-27 更新
-
下面的第二个愿望已经在 formatR 1.11 中实现。
2010 年我发布了一个叫 formatR 的 R 包,它可以把乱糟糟的 R 代码自动清理成大致整齐的代码(例如自动加空格、换行等),这个包也是我当年做 knitr 的小小动力之一。虽然 formatR 是个小麻雀包,但它的开发过程中也有三个里程碑事件:
-
最早的时候,怡轩想出了一个非常聪明的黑魔法,让这个整理过程能尽量保留代码注释;
-
后来 Kohske Takahashi 大人提供了一个很漂亮的黑魔法,可以让赋值的等号自动被替换为左箭头;
-
等啊等,终于等到 R 里面出现了
getParseData()
函数,让我终于不用红着脸用正则表达式去解析代码中的注释了,而是可以大大方方用官方 API 去解析;
然而,我对这个包还有两个小小的夙愿一直没能实现。虽不至于让我晚上睡不着觉,但若能实现,那真真是极好的。第一个愿望是,我希望能(尽量)控制代码的最大宽度。目前 formatR::tidy_source()
的宽度参数 width.cutoff
源自 deparse()
函数,而这个参数的大意是尝试在多少个字符宽度之后尝试断行,而我希望能在多少个字符宽度之前断行。因为如果之后断行,万一那个位置上恰好有个很长的变量名不能被折断,那就要等到这个变量名之后才能尝试换行,于是代码可能会超出右边界很多,这对需要 PDF 印刷品输出的写作来说是个灾难,调整起来很费神。
第二个愿望是如果小括号里的参数太多的话,就在小括号之后直接断行(原因在前面的日志中解释过),比如:
my_sum = function(
a = 1, b = 2, c = 3, d = 4, e = 5,
f = 6, g = 7
) {
return(a + b + c)
}
my_sum(
a = 1, b = 2, c = 3, d = 4, e = 5,
f = 6, g = 7
)
目前 tidy_source()
函数只能做到:
my_sum = function(a = 1, b = 2, c = 3, d = 4, e = 5,
f = 6, g = 7) {
return(a + b + c)
}
my_sum(a = 1, b = 2, c = 3, d = 4, e = 5,
f = 6, g = 7)
当然这个不算糟糕,我可以忍。这两个愿望我更迫切需要实现第一个。客官们可能会想能不能给 R 里面的 deparse()
函数打个补丁,让它既支持最大宽度也支持最小宽度,如果能打补丁并且 R 核心团队愿意接受的话,那也是极好的,但显然我没有这个技能,因为 deparse()
的源代码是基于 C 的,我一看一千多行就两眼蒙圈,但我有一定的把握去游说一位核心团队成员接受它。如果想靠自己造轮子的话,那么应该就是两条可能的路1:一是 getParseData()
(注意它有坑会截断长字符串),二是用 sourcetools 包,这个我没用过,但看起来也许比 getParseData()
更容易操纵一点,而且作者是敝司的同事,有问题可以直接找他解决。
若客官们还有闲情逸致,可以顺便把这两个功能也一并实现了(#57、#62)。好了,黑客骚年们,我在世上最大的同姓交友网站上等你们的合并请求。