CatCoding

Emacs 自虐

2010-08-21

无意中用了一下 C#,发现 VS 下面有一个功能还是非常好的,就是每次按下回车键盘的时候,都可以把刚刚输入的那行代码自动排版一下,

看起来要清晰一些。比如

int a=0;                       ==>  int a = 0;
struct Node p=&node;          ==> struct Node p = &node;
a+=b;                          ==>  a += b;
int p=&a;                     ==>  int p = &a;
int a=b+c+d+f;                 ==>  int a = b + c + d + f;
for(a=0,b=0;a<10;a++)          ==>  for(a = 0, b=0; a< 10; a++)
if(a==b)                       ==>  if(a == b)
if(pbuf!=0)                    ==>  if(a != b)
fwrite(buf,1,size,fp);         ==>  fwrite(buf, 1, size, fp);
printf(“%d %s\n”,len,buf);     ==>  printf(“%d %s\n”, len, buf); //引号内的不变,引号外的”,”后面加空格
if(p>=allocbuf&&p<buf+size)      ==> if(p >= allocbuf && p < buf + size)
return (b!=0)?gcd_ver2(b,a%b):a;  ==> return (b != 0) ? gcd_ver2(b, a % b) : a;

同时要注意的情况,还有些情况下我不想让符号两边加空格:

#include <stdio.h>       //< > 两边不加

printf(%d%d%d\n”,n,m,k);//这个%两边不加 检测是否在引号内部
a++;                     //不加空格
int p;                  //不加空格
return manip(this);     //这个两边不加 找到前面或者后面是否为 (
strcpy(mode,“w+);       //引号里面的不变 检测是否在引号内部

我以前写代码习惯都不加空格,感觉不加要写得快一些,可是这不是个很好的习惯。linux 下有 indent 这样的工具,不过是针对于最后完成的源程序来排版。在写程序的过程中像赋值操作符两边加上空格会显得比较清晰,Emacs 里面好像还没这么个插件,那我来折腾一下自己写了一个。原来还是比较复杂的。应该好好学学正则表达式,这就是一个正则匹配和替换的过程。呜,括号看得头都晕呼呼的,不过还好,最终有这么一个东西用起来比较顺手了。

首先定一个关键字和替换列表:

(setq beautifly-line-list
      ‘(
        (“+” . “ + “)
        (“-“ . “ - “)
        (“=” . “ = “)
        (““ . “  “)
        (“/“ . “ / “)
        (“%” . “ % “)
        (“<” . “ < “)
        (“>” . “ > “)
        (“,” . “, “)
        (“+=” . “ += “)
        (“=” . “ = “)
        (“/=” . “ /= “)
        (“%=” . “ %= “)
        (“==” . “ == “)))

一个用来测试 dest 是否为上面关键字的函数,后面用 char-after 来获取一个 point 的字符,对应的是 asci 码。

(defun test-valid(dest)
  (interactive)
  (if(or (equal dest 43)
         (equal dest 45)
         (equal dest 42)
         (equal dest 47)
         (equal dest 37)
         (equal dest 62)
         (equal dest 60)) ;;<
      t
    nil))

;;打印出当前位置的字符 调试用
(defun print-pos-char ()
  (interactive)
  (setq value (char-after (point)))
  (print value))


;;从 point-pos 位置开始 到这一行的尾部,检测是否有”,即检测是否在” “内部
(defun test-in-quote (point-pos)
  (interactive)
  (move-end-of-line 1)
  (setq end-pos (point))
  (goto-char point-pos)
  (setq ret-value nil)
  (if (search-forward “\”” end-pos t)
      (setq ret-value t)
    )
  (goto-char point-pos)
  ret-value)

;;这个函数先调用我的排版函数,然后调用原来的 new-line-and-indent
(defun my-new-line-and-beautyfly ()
  (interactive)
  (beautifly-line)
  (newline-and-indent))

;;在 my-c-mode-common-hook 下面加上这么一句,表示把回车键绑定在上面那个函数上。
  (define-key c-mode-base-map [(return)] ‘my-new-line-and-beautyfly)

下面就剩下这两个函数了,写的太过复杂,可惜不会用高级一点的正则表达式,所以显得不好看。其想法比较简单,按照上面那个列表,一次查找,我要找一个两员操作符,其两边都是空格,在其两边加上空格,注意排除掉 ++,—操作。然后识别 +=,-=,*=等符号,再两边加上空格。用起来还可以。逐渐写了些 elisp,感觉特别适合自底向上的方式进行,通过一些小函数,逐步累积成一个功能,再最后只用一个上层函数来调用这个功能。每个小函数除了返回结果不改变函数外的其他变量 (无副作用)。同时写一个小的函数可以马上写一个测试函数,保证其正确无误。

最后 bueatifly_line 的代码有点点长,不贴咯。

公号同步更新,欢迎关注👻