Skip to content

Commit

Permalink
Add beautify support for verilog-ts-mode
Browse files Browse the repository at this point in the history
  • Loading branch information
gmlarumbe committed Aug 13, 2023
1 parent 44cd062 commit 46de44c
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 21 deletions.
131 changes: 114 additions & 17 deletions ts-mode/verilog-ts-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,13 @@
"Return non-nil if NODE is part of NODE-TYPE in the hierarchy."
(treesit-parent-until
node
(lambda (node)
(lambda (node) ; INFO: Third argument must be a function
(string-match node-type (treesit-node-type node)))))

(defun verilog-ts--node-has-child-recursive (node node-type)
"Return non-nil if NODE contains NODE-TYPE in the hierarchy."
(treesit-search-subtree node node-type))

(defun verilog-ts--node-identifier-name (node)
"Return identifier name of NODE."
(cond ((string-match "class_constructor" (treesit-node-type node))
Expand Down Expand Up @@ -112,19 +116,41 @@ Snippet fetched from `treesit--indent-1'."


;;;; Context info
(defun verilog-ts-module-at-point ()
"Return name of module at point."
(interactive)
(let ((node-at-point (treesit-node-at (point)))
module-node)
(setq module-node (verilog-ts--node-has-parent-recursive node-at-point "module_instantiation"))
(when module-node
(treesit-node-text (treesit-search-subtree module-node "simple_identifier") :no-prop))))
(defconst verilog-ts-block-at-point-re
(eval-when-compile
(regexp-opt
'("module_declaration"
"interface_declaration"
"program_declaration"
"package_declaration"
"class_declaration"
"function_declaration"
"task_declaration"
"class_constructor_declaration"
"module_instantiation"
"interface_instantiation"
"always_construct"
"initial_construct"
"final_construct"
"generate_region"))))

(defun verilog-ts-nodes-current-buffer (pred)
(defun verilog-ts-module-at-point ()
"Return node of module at point."
(let ((node-at-point (verilog-ts--node-at-point))
(module-node (verilog-ts--node-has-parent-recursive node-at-point "module_instantiation")))
module-node))

(defun verilog-ts-block-at-point ()
"Return node of block at point."
(let* ((block-re verilog-ts-block-at-point-re)
(node-at-point (verilog-ts--node-at-point))
(block-node (verilog-ts--node-has-parent-recursive node-at-point block-re)))
block-node))

(defun verilog-ts-nodes-current-buffer (pred &optional start)
"Return node names and positions that satisfy PRED in current buffer."
(interactive)
(let* ((root-node (treesit-buffer-root-node))
(let* ((root-node (or start (treesit-buffer-root-node)))
(pred-nodes (cdr (treesit-induce-sparse-tree root-node pred)))
name pos-beg pos-end nodes-alist)
(dolist (node pred-nodes)
Expand All @@ -136,34 +162,34 @@ Snippet fetched from `treesit--indent-1'."

(defun verilog-ts-class-attributes ()
"Return class attributes of current file."
(interactive)
(verilog-ts-nodes-current-buffer "class_property"))

(defun verilog-ts-class-methods ()
"Return class methods of current file."
(interactive)
(delete-dups (verilog-ts-nodes-current-buffer "class_\\(constructor\\|method\\)")))

(defun verilog-ts-class-constraints ()
"Return class constraints of current file."
(interactive)
(verilog-ts-nodes-current-buffer "constraint_declaration"))

(defun verilog-ts-module-instances ()
"Return module instances of current file."
(interactive)
(verilog-ts-nodes-current-buffer "module_instantiation"))

(defun verilog-ts-module-declarations ()
"Return module declarations of current file."
(interactive)
(verilog-ts-nodes-current-buffer "module_declaration"))

(defun verilog-ts-always-blocks ()
"Return always blocks of current file."
(interactive)
(verilog-ts-nodes-current-buffer "always_keyword"))

(defun verilog-ts-instance-nodes ()
"Return instance nodes of current buffer."
(let ((root-node (treesit-buffer-root-node)))
(mapcar #'car (cdr (treesit-induce-sparse-tree root-node
"module_instantiation")))))


;;;; Navigation
(defun verilog-ts-forward-sexp (&optional arg)
Expand Down Expand Up @@ -1023,7 +1049,10 @@ Indent parameters depending on first parameter:
"class_constructor_declaration"
"class_property"
"module_instantiation"
"interface_instantiation"
"always_construct"
"initial_construct"
"final_construct"
"generate_region"))))

(defvar verilog-ts-imenu-format-item-label-function
Expand Down Expand Up @@ -1192,6 +1221,74 @@ Return nil if there is no name or if NODE is not a defun node."
"task_declaration"
"class_method")))

;;; Beautify
(defun verilog-ts-beautify-block-at-point ()
"Beautify/indent block at point.
If block is an instance, also align parameters and ports."
(interactive)
(let ((node (verilog-ts-block-at-point))
start end type name)
(unless node
(user-error "Not inside a block"))
(setq start (treesit-node-start node))
(setq end (treesit-node-end node))
(setq type (treesit-node-type node))
(setq name (verilog-ts--node-identifier-name node))
(indent-region start end)
;; Instance: also align ports and params
(when (string-match "\\(module\\|interface\\)_instantiation" type)
(let ((re "\\(\\s-*\\)(")
params-node ports-node)
(setq node (verilog-ts-block-at-point)) ; Refresh outdated node after `indent-region'
(when (setq params-node (verilog-ts--node-has-child-recursive node "list_of_parameter_assignments"))
(align-regexp (treesit-node-start params-node) (treesit-node-end params-node) re 1 1 nil))
(when (setq ports-node (verilog-ts--node-has-child-recursive node "list_of_port_connections"))
(align-regexp (treesit-node-start ports-node) (treesit-node-end ports-node) re 1 1 nil))))
(message "%s : %s" type name)))

(defun verilog-ts-beautify-current-buffer ()
"Beautify current buffer:
- Indent whole buffer
- Beautify every instantiated module
- Untabify and delete trailing whitespace"
(interactive)
(let (node)
(indent-region (point-min) (point-max))
(save-excursion
(goto-char (point-min))
(while (setq node (treesit-search-forward (verilog-ts--node-at-point) "module_instantiation"))
(goto-char (treesit-node-start node))
(verilog-ts-beautify-block-at-point)
;; TODO: Seems a bit redundant/inefficient. Probably there's a better way to do it
;; However, it's needed to avoid and outdated node error after beautifying
(setq node (treesit-search-forward (verilog-ts--node-at-point) "module_instantiation"))
(goto-char (treesit-node-end node))
(when (not (eobp))
(forward-char))))
(untabify (point-min) (point-max))
(delete-trailing-whitespace (point-min) (point-max))))

(defun verilog-ts-beautify-files (files)
"Beautify SystemVerilog FILES.
FILES is a list of strings containing the filepaths."
(dolist (file files)
(unless (file-exists-p file)
(error "File %s does not exist! Aborting!" file)))
(save-window-excursion
(dolist (file files)
(with-temp-file file
(insert-file-contents file)
(verilog-ts-mode)
(verilog-ts-beautify-current-buffer)))))

(defun verilog-ext-beautify-dir-files (dir)
"Beautify Verilog files on DIR."
(interactive "DDirectory: ")
(let ((files (verilog-ext-dir-files dir)))
(verilog-ts-beautify-files files)))


;;; Capf
(defun verilog-ts-completion-at-point ()
"Verilog tree-sitter powered completion at point.
Expand Down
8 changes: 4 additions & 4 deletions verilog-ext-beautify.el
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,13 @@
- Beautify every instantiated module
- Untabify and delete trailing whitespace"
(interactive)
(verilog-ext-indent-region (point-min) (point-max))
(save-excursion
(verilog-ext-indent-region (point-min) (point-max))
(goto-char (point-min))
(while (verilog-ext-find-module-instance-fwd)
(verilog-ext-beautify-module-at-point))
(untabify (point-min) (point-max))
(delete-trailing-whitespace (point-min) (point-max))))
(verilog-ext-beautify-module-at-point)))
(untabify (point-min) (point-max))
(delete-trailing-whitespace (point-min) (point-max)))

(defun verilog-ext-beautify-files (files)
"Beautify Verilog FILES.
Expand Down

0 comments on commit 46de44c

Please sign in to comment.