Add function for alignment of named port connections in module instantiations.

This commit is contained in:
2026-02-08 13:39:22 +03:00
parent 6f6e4ef29b
commit 2102adc1da
3 changed files with 236 additions and 3 deletions

View File

@@ -7,6 +7,7 @@ Align SystemVerilog ANSI-style port declarations in a contiguous block around po
- Aligns direction, type, range, name, and trailing `//` comments.
- Works on the contiguous block of port declarations above and below point.
- Stops at the first non-port line (including blank lines).
- Aligns named port connections in module instantiations via `verilog-align-ports-instantiation`.
## Installation
@@ -20,6 +21,11 @@ Align SystemVerilog ANSI-style port declarations in a contiguous block around po
1. Place point on a line that declares a port (input/output/inout).
2. Run `M-x verilog-align-ports`.
For module instantiations:
1. Place point on a named port connection line (e.g., `.clk_i (clk)` or `.full_o,`).
2. Run `M-x verilog-align-ports-instantiation`.
Example input:
```systemverilog

View File

@@ -66,6 +66,80 @@
(verilog-align-ports)
(should (string= (buffer-string) expected)))))
(ert-deftest verilog-align-ports-instantiation-aligns-block ()
(let* ((input (concat
(mapconcat
#'identity
'("fifo_sync #("
" .FifoWriteDepth(FifoWriteDepth),"
" .DataWidth(DataWidth),"
" .DataCountWidth(WrDataCountW),"
" .RdDataCountWidth(RdDataCountW)"
") dut ("
" .rst_i (rst), //rst"
" .clk_i (clk),"
" .wr_en_i (wr_en_i),"
" .d_i (d_i), // di"
" .full_o, // full"
" .data_count_o (wr_data_count_o),"
" .rd_en_i (rd_en_i),"
" .d_o () , // do"
" .empty_o , // empty"
" .valid_o (valid_o)"
");")
"\n")
"\n"))
(expected (concat
(mapconcat
#'identity
(list
"fifo_sync #("
" .FifoWriteDepth(FifoWriteDepth),"
" .DataWidth(DataWidth),"
" .DataCountWidth(WrDataCountW),"
" .RdDataCountWidth(RdDataCountW)"
") dut ("
(concat " .rst_i" (make-string 8 ?\s) "(rst),"
(make-string 13 ?\s) "//rst")
(concat " .clk_i" (make-string 8 ?\s) "(clk),")
(concat " .wr_en_i" (make-string 6 ?\s) "(wr_en_i),")
(concat " .d_i" (make-string 10 ?\s) "(d_i),"
(make-string 13 ?\s) "// di")
(concat " .full_o," (make-string 25 ?\s) "// full")
(concat " .data_count_o" (make-string 1 ?\s)
"(wr_data_count_o),")
(concat " .rd_en_i" (make-string 6 ?\s) "(rd_en_i),")
(concat " .d_o" (make-string 10 ?\s) "(),"
(make-string 16 ?\s) "// do")
(concat " .empty_o," (make-string 24 ?\s) "// empty")
(concat " .valid_o" (make-string 6 ?\s) "(valid_o)")
");")
"\n")
"\n")))
(with-temp-buffer
(insert input)
(goto-char (point-min))
(search-forward ".clk_i")
(beginning-of-line)
(should (verilog-align-ports-instantiation))
(should (string= (buffer-string) expected)))))
(ert-deftest verilog-align-ports-instantiation-returns-nil-outside ()
(with-temp-buffer
(insert (concat
(mapconcat
#'identity
'("fifo_sync #() dut ("
" .rst_i (rst),"
" .clk_i (clk)"
");")
"\n")
"\n"))
(goto-char (point-min))
(search-forward "dut (")
(beginning-of-line)
(should (not (verilog-align-ports-instantiation)))))
(provide 'verilog-align-ports-test)
;;; verilog-align-ports-test.el ends here

View File

@@ -16,6 +16,16 @@
(line-end-position))))
(string-match-p "^\\s-*\\(input\\|output\\|inout\\)\\b" line))))
(defun verilog-align-ports--line-inst-port-p (pos)
(save-excursion
(goto-char pos)
(let ((line (buffer-substring-no-properties
(line-beginning-position)
(line-end-position))))
(string-match-p
"^\\s-*\\.\\(\\\\[^[:space:]]+\\|[A-Za-z_][A-Za-z0-9_$]*\\)\\b"
line))))
(defun verilog-align-ports--split-comment (line)
(let ((pos (string-match "//" line)))
(if pos
@@ -82,6 +92,26 @@
(verilog-align-ports--line-port-p
(line-beginning-position)))
(forward-line 1))
(setq end (line-beginning-position))
(cons start end)))))
(defun verilog-align-ports--inst-bounds ()
(save-excursion
(and (verilog-align-ports--line-inst-port-p (line-beginning-position))
(let ((start (line-beginning-position))
(end nil))
(while (and (not (bobp))
(save-excursion
(forward-line -1)
(verilog-align-ports--line-inst-port-p
(line-beginning-position))))
(forward-line -1)
(setq start (line-beginning-position)))
(goto-char start)
(while (and (not (eobp))
(verilog-align-ports--line-inst-port-p
(line-beginning-position)))
(forward-line 1))
(setq end (line-beginning-position))
(cons start end)))))
@@ -99,6 +129,76 @@
(forward-line 1)))
(nreverse entries)))
(defun verilog-align-ports--find-paren-end (text start)
(let ((depth 0)
(idx start)
(len (length text))
(end nil))
(while (and (< idx len) (not end))
(let ((ch (aref text idx)))
(cond
((eq ch ?\() (setq depth (1+ depth)))
((eq ch ?\))
(setq depth (1- depth))
(when (eq depth 0)
(setq end (1+ idx))))))
(setq idx (1+ idx)))
end))
(defun verilog-align-ports--parse-inst-line (line)
(let* ((split (verilog-align-ports--split-comment line))
(code (string-trim-right (car split)))
(comment (cdr split)))
(when (string-match
"^\\(\\s-*\\)\\.\\(\\\\[^[:space:]]+\\|[A-Za-z_][A-Za-z0-9_$]*\\)\\(.*\\)$"
code)
(let* ((indent (match-string 1 code))
(name (match-string 2 code))
(rest (match-string 3 code))
(rest (if rest (string-trim-right rest) ""))
(pos (string-match "\\S-" rest))
(has-conn nil)
(conn "")
(comma nil))
(if (and pos (< pos (length rest)) (eq (aref rest pos) ?\())
(let* ((end (verilog-align-ports--find-paren-end rest pos)))
(if end
(progn
(setq has-conn t)
(setq conn (string-trim (substring rest (1+ pos) (1- end))))
(let ((after (string-trim (substring rest end))))
(when (and (> (length after) 0)
(eq (aref after 0) ?,))
(setq comma ","))))
(let ((after (string-trim rest)))
(when (and (> (length after) 0)
(string-match-p "," after))
(setq comma ",")))))
(let ((after (string-trim rest)))
(when (and (> (length after) 0)
(string-match-p "," after))
(setq comma ","))))
(list :indent indent
:name name
:has-conn has-conn
:conn conn
:comma comma
:comment comment)))))
(defun verilog-align-ports--inst-collect (start end)
(let (entries)
(save-excursion
(goto-char start)
(while (< (point) end)
(let* ((line (buffer-substring-no-properties
(line-beginning-position)
(line-end-position)))
(entry (verilog-align-ports--parse-inst-line line)))
(when entry
(push entry entries)))
(forward-line 1)))
(nreverse entries)))
(defun verilog-align-ports--max-lengths (entries)
(let ((max-dir 0)
(max-type 0)
@@ -153,9 +253,48 @@
(when has-range range-pad)
name
(when (and has-comment comment) name-pad)
(or comment ""))))
(or comment ""))))
entries)))
(defun verilog-align-ports--inst-format-lines (entries)
(let* ((base-indent (plist-get (car entries) :indent))
(max-name 0)
(has-comment nil)
left-parts
(max-left 0))
(dolist (entry entries)
(let ((name-len (+ 1 (length (plist-get entry :name)))))
(setq max-name (max max-name name-len)))
(when (plist-get entry :comment)
(setq has-comment t)))
(dolist (entry entries)
(let* ((name (plist-get entry :name))
(name-field (concat "." name))
(has-conn (plist-get entry :has-conn))
(conn (plist-get entry :conn))
(comma (plist-get entry :comma))
(pad (when has-conn
(verilog-align-ports--pad max-name (length name-field))))
(left (concat base-indent
name-field
(when has-conn pad)
(when has-conn "(")
(when has-conn conn)
(when has-conn ")")
(when comma ","))))
(push left left-parts)
(setq max-left (max max-left (length left)))))
(setq left-parts (nreverse left-parts))
(cl-mapcar
(lambda (entry left)
(let ((comment (plist-get entry :comment)))
(if (and has-comment comment)
(concat left
(verilog-align-ports--pad max-left (length left))
comment)
left)))
entries left-parts)))
(defun verilog-align-ports--apply (start lines)
(save-excursion
(goto-char start)
@@ -169,12 +308,26 @@
"Align SystemVerilog port declarations around point."
(interactive)
(let ((bounds (verilog-align-ports--bounds)))
(and bounds
(let* ((start (car bounds))
(end (cdr bounds))
(entries (verilog-align-ports--collect start end)))
(and entries
(let ((lines (verilog-align-ports--format-lines entries)))
(verilog-align-ports--apply start lines)
t))))))
;;;###autoload
(defun verilog-align-ports-instantiation ()
"Align SystemVerilog named port connections around point."
(interactive)
(let ((bounds (verilog-align-ports--inst-bounds)))
(and bounds
(let* ((start (car bounds))
(end (cdr bounds))
(entries (verilog-align-ports--collect start end)))
(entries (verilog-align-ports--inst-collect start end)))
(and entries
(let ((lines (verilog-align-ports--format-lines entries)))
(let ((lines (verilog-align-ports--inst-format-lines entries)))
(verilog-align-ports--apply start lines)
t))))))