如何为Emacs的主模式添加垂直对齐功能



我每天都在为emacs使用verilg模式,但代码对齐对我来说不太好。所以我想添加一些类似垂直对齐的东西。

首先,我希望将申报行对齐,如下所示:

bit [1:0] a;
bit [3254:0] b;
bit unsigned [P_DWIDTH-1:0] c;
bit unsigned [P_DWIDTH-1:P_DWIDTH-4] d;
int e;

至:

bit          [         1:0         ] a;
bit          [      3254:0         ] b;
bit unsigned [P_DWIDTH-1:0         ] c;
bit unsigned [P_DWIDTH-1:P_DWIDTH-4] d;
int                                  e;

我没有太多Elisp的经验。我不确定像align-regexp这样的东西是正确的吗?或者任何人请给我一个正确的开始方向。

根据@hood的回复,我做了修改:使用narrow-to-region来避免区域边界的更改。

(defun align-decl-vertically ()
  "Align verilog declarations."
  (interactive)
  (save-excursion
    (save-restriction
      (narrow-to-region (region-beginning) (region-end))
      ;; remove spaces around ":"
      (goto-char (point-min))
      (while (re-search-forward "\s-*:\s-*" (point-max) t)
        (replace-match ":"))
      ;; align "["
      (align-regexp (point-min) (point-max) "\(\s-*\)\[" -1 1 0)
      ;; align ":"
      (align-regexp (point-min) (point-max) "\[\(.+:\)" -1 0 0)
      ;; align "]"
      (align-regexp (point-min) (point-max) "\s-*\(\]\)" -1 0 0)
      ;; align variable name
      (align-regexp (point-min) (point-max) "\(\s-+\)\S-+;" -1 1 0)
      (widen))))

还可以找到另一种更新align规则的方法来实现这一点(这并不像我所期望的那样工作,但只是在这里列出一些可能会帮助我解决它):

(add-to-list 'align-mode-rules-list                             
             '(declaration-range-field-alignment                 
               (regexp . "\(\s-*\[\)\(.*:\).*\S-+\(\s-*\]\)\(.*\)")
               (group . (1 2 3 4))                              
               (modes . '(verilog-mode))                        
               (tab-stop . nil)                                 
               (spacing . (1 0 0 1))                            
               (repeat . nil)                                   
               (justify . t)))                                  
(add-to-list 'align-mode-rules-list                             
             '(declaration-variable-name-alignment              
               (regexp . "\(\s-*\S-*\s-*;\)")                  
               (group . 1)                                      
               (modes . '(verilog-mode))                        
               (repeat . nil)                                   
               (tab-stop . nil)                                 
               (spacing . 1)                                    
               (justify . t)))          

但有时可能需要多次运行align才能得到最终结果。我还不知道为什么。

您确实可以尝试使用align-regexp。以下对您有帮助吗:

(defun align-decl-vertically ()
  "Align verilog declarations."
  (interactive)
  (let ((BEG (region-beginning))
        (END (region-end)))
    (align-regexp BEG END "\(\s-*\)\[" 1 1 0)
    (align-regexp BEG END "\(\s-*\)\]" 1 1 0)
    (align-regexp BEG END "\(\s-*\)\s-[^ ]*;" 1 0 0)))
;; declare a key binding
(add-hook 'verilg-mode-hook (lambda() (local-set-key (kbd "C-c =") 'align-decl-vertically)))

你必须将它粘贴到你的Emacs init文件(例如.Emacs或init.el)中。一旦你进入verilog-mode,你就可以高亮显示该区域,然后按C-c =来对齐声明。我用你的例子进行了测试,结果成功了。我不知道它在一般情况下是否有效,因为我不知道verilog编程语法。

更新

第一个版本不能正常工作,原因很简单,我们不应该在变量中保存区域的开始和结束,因为它们在每次align-regexp调用后都会发生变化。这里来了一个应该工作的版本:

(defun align-decl-vertically ()
  "Align verilog declarations."
  (interactive)
  (align-regexp (region-beginning) (region-end) "\(\s-*\)\[" 1 1 0)
  (align-regexp (region-beginning) (region-end) "\(\s-*\)\]" 1 1 0)
  (align-regexp (region-beginning) (region-end) "\(\s-*\)\s-[^ ]*;" 1 0 0))

最新更新