如何为 Emacs 的主要模式添加垂直对齐功能
How to add vertical alignment feature to a major-mode for Emacs
我每天都在为 emacs 使用 verilg-mode,但代码对齐对我来说不是很好。所以想添加垂直对齐之类的东西。
首先,我希望像这样对齐声明行:
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
之类的东西是否正确?或者任何人请给我一个正确的开始方向。
您确实可以尝试 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 初始化文件中(例如 .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))
根据@homeless的回复,我做了修改:使用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
才能得到最终结果。我还没弄清楚为什么。
我每天都在为 emacs 使用 verilg-mode,但代码对齐对我来说不是很好。所以想添加垂直对齐之类的东西。
首先,我希望像这样对齐声明行:
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
之类的东西是否正确?或者任何人请给我一个正确的开始方向。
您确实可以尝试 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 初始化文件中(例如 .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))
根据@homeless的回复,我做了修改:使用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
才能得到最终结果。我还没弄清楚为什么。