diff --git a/ts-mode/verilog-ts-mode.el b/ts-mode/verilog-ts-mode.el index aa9eae0..251d944 100644 --- a/ts-mode/verilog-ts-mode.el +++ b/ts-mode/verilog-ts-mode.el @@ -92,13 +92,14 @@ Defaults to .v, .vh, .sv and .svh." (defun verilog-ts--node-identifier-name (node) "Return identifier name of NODE." - (cond ((string-match "class_constructor" (treesit-node-type node)) - "new") - ((string-match "class_method" (treesit-node-type node)) - (or (treesit-node-text (treesit-search-subtree node "\\(function\\|task\\)_identifier") :no-prop) - "new")) - (t - (treesit-node-text (treesit-search-subtree node "simple_identifier") :no-prop)))) + (when node + (cond ((string-match "class_constructor" (treesit-node-type node)) + "new") + ((string-match "class_method" (treesit-node-type node)) + (or (treesit-node-text (treesit-search-subtree node "\\(function\\|task\\)_identifier") :no-prop) + "new")) + (t + (treesit-node-text (treesit-search-subtree node "simple_identifier") :no-prop))))) (defun verilog-ts--highest-node-at-pos (pos) "Return highest node in the hierarchy that starts at POS. diff --git a/verilog-ext-tags.el b/verilog-ext-tags.el index 744f1e9..4ec1fe5 100644 --- a/verilog-ext-tags.el +++ b/verilog-ext-tags.el @@ -28,6 +28,38 @@ (require 'verilog-ext-nav) +;;;; Common +(defun verilog-ext-tags-table-add-entry (table tag type desc &optional file parent) + "Add entry for TAG in hash-table TABLE. + +It is needed to provide TYPE, description DESC and FILE properties to add the +entry in the table. + +Optional arg PARENT is the module where TAG is defined/instantiated for dot +completion. + +If there is no entry in the table for TAG add one. Otherwise update the +existing one with current location properties." + (let ((tag-value (gethash tag table)) + locs-plist loc-new parent-value parent-items) + (if (not tag-value) + ;; Add tag with properties + (puthash tag `(:items nil :locs (,(verilog-ext-tags-tag-properties type desc file))) table) + ;; Otherwise update existing tag properties + (setq locs-plist (plist-get tag-value :locs)) + (setq loc-new (verilog-ext-tags-tag-properties type desc file)) + (unless (member loc-new locs-plist) + (push loc-new locs-plist) + (plist-put tag-value :locs locs-plist) + (puthash tag `(:items ,(plist-get tag-value :items) :locs ,locs-plist) table))) + (when parent + (setq parent-value (or (gethash parent table) + (puthash parent (list :items nil :locs nil) table))) + (setq parent-items (plist-get parent-value :items)) + (unless (member tag parent-items) + (plist-put parent-value :items (append parent-items `(,tag))) + (puthash parent parent-value table))) + table)) (defmacro verilog-ext-tags-table-push-tag (table tag type desc &optional file parent) "Push TAG in hash table TABLE. @@ -40,6 +72,21 @@ completion." (declare (indent 0) (debug t)) `(setq ,table (verilog-ext-tags-table-add-entry ,table ,tag ,type ,desc ,file ,parent))) +(defun verilog-ext-tags-tag-properties (type desc &optional file) + "Return :locs properties for current tag. +These include tag TYPE and description DESC as well as FILE and current line." + `(:type ,type + :desc ,desc + :file ,(or file buffer-file-name) + :line ,(line-number-at-pos))) + +(defun verilog-ext-tags-desc () + "Return description for current TAG. +Meant to be used for `xref' backend." + (string-trim (buffer-substring-no-properties (line-beginning-position) (line-end-position)))) + + +;;;; Builtin (defmacro verilog-ext-tags-table-push-definitions (tag-type table &optional file start limit parent) "Push definitions of TAG-TYPE inside hash table TABLE. @@ -65,46 +112,9 @@ buffer." (declare (indent 0) (debug t)) `(setq ,table (verilog-ext-tags-get-references ,table ,defs-table ,file ,start ,limit))) -(defun verilog-ext-tags-tag-properties (type desc &optional file) - "Return :locs properties for current tag. -These include tag TYPE and description DESC as well as FILE and current line." - `(:type ,type - :desc ,desc - :file ,(or file buffer-file-name) - :line ,(line-number-at-pos))) - -(defun verilog-ext-tags-table-add-entry (table tag type desc &optional file parent) - "Add entry for TAG in hash-table TABLE. - -It is needed to provide TYPE, description DESC and FILE properties to add the -entry in the table. - -Optional arg PARENT is the module where TAG is defined/instantiated for dot -completion. - -If there is no entry in the table for TAG add one. Otherwise update the -existing one with current location properties." - (let ((tag-value (gethash tag table)) - locs-plist loc-new parent-value parent-items) - (if (not tag-value) - ;; Add tag with properties - (puthash tag `(:items nil :locs (,(verilog-ext-tags-tag-properties type desc file))) table) - ;; Otherwise update existing tag properties - (setq locs-plist (plist-get tag-value :locs)) - (setq loc-new (verilog-ext-tags-tag-properties type desc file)) - (unless (member loc-new locs-plist) - (push loc-new locs-plist) - (plist-put tag-value :locs locs-plist) - (puthash tag `(:items ,(plist-get tag-value :items) :locs ,locs-plist) table))) - (when parent - (setq parent-value (or (gethash parent table) - (puthash parent (list :items nil :locs nil) table))) - (setq parent-items (plist-get parent-value :items)) - (unless (member tag parent-items) - (plist-put parent-value :items (append parent-items `(,tag))) - (puthash parent parent-value table))) - table)) - +;; TODO: Do not add instances as definitions. Just add items to its parent! +;; Add arg to `verilog-ext-tags-table-add-entry' to only add items in the second part of the function +;; and set it to non-nil in caller function if it's a "module|interface_instantiation" (defun verilog-ext-tags-get-definitions (tag-type table &optional file start limit parent) "Add definitions of TAG-TYPE to hash-table TABLE for FILE. @@ -229,14 +239,9 @@ Limit search between START and LIMIT if provided." ;; Return updated table table)) -(defun verilog-ext-tags-desc () - "Return description for current TAG. -Meant to be used for `xref' backend." - (string-trim (buffer-substring-no-properties (line-beginning-position) (line-end-position)))) - -;;; Tree-sitter -(defconst verilog-ext-tags-definitions-tree-sitter-re +;;;; Tree-sitter +(defconst verilog-ext-tags-definitions-ts-re (regexp-opt '("module_declaration" "interface_declaration" @@ -248,105 +253,33 @@ Meant to be used for `xref' backend." "class_constructor_declaration" "local_parameter_declaration" "data_declaration" + "class_property" ;; INFO: These two below are only included add items to the defs table for capf "module_instantiation" - "interface_instantiation" - ))) - -;; TODO: Instead of traversing it sequentially, do similarly to how it's done for imenu with the sparse tree -;; and use the parent argument accordingly. This way should be much easier and probably more efficient. -(defun verilog-ext-tags-table-push-definitions-tree-sitter (table &optional file) - "" - (let ((nodes (verilog-ts-nodes-current-buffer verilog-ext-tags-definitions-tree-sitter-re))) - (dolist (node nodes) - (goto-char (treesit-node-start node)) - (verilog-ext-tags-table-push-tag table - ;; TODO: Might not work for some cases: e.g: @ test/files/common/uvm_component.svh:1498 - ;; TODO: Doesn't work either for external defined methods, fetches the class_qualifier instead of the - ;; e.g function void uvm_component::do_end_tr (uvm_transaction tr, -> fetches uvm_component instead of do_end_tr - (verilog-ts--node-identifier-name node) - (treesit-node-type node) - (verilog-ext-tags-desc) - file - ;; TODO: This last argument is the parent. It is used in the builtin recursive function - ;; for dot completion to populate the :items property, with elements of modules and class items/methods - (verilog-ts--node-identifier-name (verilog-ts--node-has-parent-recursive "\\(\\(class\\|package\\)_declaration\\|\\(module\\|interface\\)_")) - ;; (treesit-node-text (treesit-node-parent node) :no-prop) - )))) - -(defun verilog-ext-tags-table-push-references-tree-sitter (table &optional file) - "" - (let ((nodes (verilog-ts-nodes-current-buffer "simple_identifier")) - tag type desc data) - (dolist (node nodes) - (goto-char (treesit-node-start node)) + "interface_instantiation"))) - (verilog-ext-tags-table-push-tag table - (treesit-node-text node :no-prop) - nil - (verilog-ext-tags-desc) - file))) - ;; TODO: Filter references that already exist as definitions! - ;; Same as in `verilog-ext-tags-get-references' - ) - - -(defconst verilog-ext-tags-tree-sitter-re - (eval-when-compile - (regexp-opt - '("module_declaration" - "interface_declaration" - "program_declaration" - "package_declaration" - "class_declaration" - "function_declaration" - "task_declaration" - "class_constructor_declaration" - "class_property" - "module_instantiation" - "interface_instantiation" - "generate_region")))) - -(setq verilog-ext-tags-tree-sitter-defs-table (make-hash-table :test #'equal)) - -(defun verilog-ext-tags-table-push-definitions-tree-sitter () - "Imenu index builder function for `verilog-ts-mode'. - -NODE is the root node of the subtree you want to build an index -of. If nil, use the root node of the whole parse tree. - -Copied from Python's `python-imenu-treesit-create-index' and adapted -to SystemVerilog parser." +;; TODO: Do not add instances as definitions. Just add items to its parent! +;; Add arg to `verilog-ext-tags-table-add-entry' to only add items in the second part of the function +;; and set it to non-nil in caller function if it's a "module|interface_instantiation" +(defun verilog-ext-tags-table-push-definitions-ts (table &optional file) + "Push definitions found in FILE inside hash table TABLE using tree-sitter." (let* ((node (treesit-buffer-root-node 'verilog)) (tree (treesit-induce-sparse-tree node - verilog-ext-tags-tree-sitter-re + verilog-ext-tags-definitions-ts-re nil 1000))) - (verilog-ext-tags-table-push-definitions-tree-sitter-1 tree nil))) - -(defun verilog-ext-tags-table-push-definitions-tree-sitter-1 (node parent) - "Given a sparse tree, create an imenu alist. - -NODE is the root node of the tree returned by -`treesit-induce-sparse-tree' (not a tree-sitter node, its car is -a tree-sitter node). Walk that tree and return an imenu alist. - -Return a list of ENTRY where + (verilog-ext-tags-table-push-definitions-ts--recurse table tree nil file))) -ENTRY := (NAME . MARKER) - | (NAME . ((JUMP-LABEL . MARKER) - ENTRY - ...) +(defun verilog-ext-tags-table-push-definitions-ts--recurse (table node parent &optional file) + "Push definitions found in FILE inside hash table TABLE using tree-sitter. -NAME is the function/class's name, JUMP-LABEL is like \"*function -definition*\". +Traverse the tree starting at NODE. -Copied from Python's `python--imenu-treesit-create-index-1' and adapted to -SystemVerilog parser." +PARENT is passed as an argument to build the :items prop list of TABLE." (let* ((ts-node (car node)) (children (cdr node)) (subtrees (mapc (lambda (leaf) - (verilog-ext-tags-table-push-definitions-tree-sitter-1 leaf ts-node)) + (verilog-ext-tags-table-push-definitions-ts--recurse table leaf ts-node file)) children)) (type (treesit-node-type ts-node))) (cond @@ -354,20 +287,30 @@ SystemVerilog parser." subtrees) (t (goto-char (treesit-node-start ts-node)) - (setq verilog-ext-tags-tree-sitter-defs-table (verilog-ext-tags-table-add-entry - ;; ,table ,tag ,type ,desc ,file ,parent)) - ;; (verilog-ext-tags-table-push-tag - verilog-ext-tags-tree-sitter-defs-table + (verilog-ext-tags-table-push-tag table ;; TODO: Might not work for some cases: e.g: @ test/files/common/uvm_component.svh:1498 ;; TODO: Doesn't work either for external defined methods, fetches the class_qualifier instead of the ;; e.g function void uvm_component::do_end_tr (uvm_transaction tr, -> fetches uvm_component instead of do_end_tr (verilog-ts--node-identifier-name ts-node) type (verilog-ext-tags-desc) + file + (verilog-ts--node-identifier-name parent)))))) + +(defun verilog-ext-tags-table-push-references-ts (table &optional file) + "Push references found in FILE inside hash table TABLE using tree-sitter." + (let ((nodes (verilog-ts-nodes-current-buffer "simple_identifier"))) + (dolist (node nodes) + (goto-char (treesit-node-start node)) + ;; TODO: Filter references that already exist as definitions! + ;; Same as in `verilog-ext-tags-get-references' + (verilog-ext-tags-table-push-tag table + (treesit-node-text node :no-prop) nil - (verilog-ts--node-identifier-name parent) - ;; file - )))))) + (verilog-ext-tags-desc) + file)))) + + (provide 'verilog-ext-tags) diff --git a/verilog-ext-workspace.el b/verilog-ext-workspace.el index 78eb663..6f83c67 100644 --- a/verilog-ext-workspace.el +++ b/verilog-ext-workspace.el @@ -269,7 +269,7 @@ With current-prefix or VERBOSE, dump output log." (cond (;; Tree-sitter (eq verilog-ext-workspace-tags-backend 'tree-sitter) (verilog-ts-mode) - (verilog-ext-tags-table-push-definitions-tree-sitter table file)) + (verilog-ext-tags-table-push-definitions-ts table file)) (;; Builtin (eq verilog-ext-workspace-tags-backend 'builtin) (verilog-mode) @@ -303,7 +303,7 @@ With current-prefix or VERBOSE, dump output log." (cond (;; Tree-sitter (eq verilog-ext-workspace-tags-backend 'tree-sitter) (verilog-ts-mode) - (verilog-ext-tags-table-push-references-tree-sitter table file)) + (verilog-ext-tags-table-push-references-ts table file)) (;; Builtin (eq verilog-ext-workspace-tags-backend 'builtin) (verilog-mode) @@ -326,7 +326,8 @@ With current-prefix or VERBOSE, dump output log." `(lambda () ,(async-inject-variables verilog-ext-async-inject-variables-re) (require 'verilog-ext) - (require 'verilog-ts-mode) + (when (eq verilog-ext-workspace-tags-backend 'tree-sitter) + (require 'verilog-ts-mode)) (verilog-ext-workspace-get-tags ,verbose)) (lambda (result) (message "Finished collection tags!") @@ -678,50 +679,6 @@ INFO: Enabling this feature will override the value of (setq verilog-align-typedef-regexp verilog-ext-workspace-cache-typedefs)) -;;;; Tree-sitter pending -(defvar verilog-ts-capf-table nil) -(defconst verilog-ts-async-inject-variables-re "\\`\\(load-path\\|buffer-file-name\\)") - -;; TODO: Probably it is needed to update `verilog-ext-tags-get-definitions' and -;; `verilog-ext-tags-get-references' so that tables are populated via -;; tree-sitter instead of via built-in processing. -;; - -(defun verilog-ts-capf-create-table () - "Verilog tree-sitter create completion at point table synchronously." - (let (completions) - (dolist (file (directory-files-recursively (project-root (project-current)) "\\.[s]?v[h]?$")) - (with-temp-buffer - (message "Processing %s" file) - (insert-file-contents file) - (verilog-ts-mode) - (setq completions (append (verilog-ts-nodes-current-buffer "simple_identifier") completions)))) - (delete-dups completions) - (setq verilog-ts-capf-table completions))) - -(defun verilog-ts-capf-create-table-async () - "Verilog tree-sitter create completion at point table asynchronously." - (message "Starting tag collection for %s" (project-root (project-current))) - (async-start - `(lambda () - ,(async-inject-variables verilog-ts-async-inject-variables-re) - (require 'verilog-mode) - (require 'verilog-ts-mode) - (verilog-ts-capf-create-table)) - (lambda (result) - (message "Finished collection tags!") - (setq verilog-ts-capf-table result)))) - -(defun verilog-ts-completion-at-point () - "Verilog tree-sitter completion at point. -Complete with identifiers of current project." - (interactive) - (let* ((bds (bounds-of-thing-at-point 'symbol)) - (start (car bds)) - (end (cdr bds))) - (list start end verilog-ts-capf-table . nil))) - - (provide 'verilog-ext-workspace) diff --git a/verilog-ext-xref.el b/verilog-ext-xref.el index 9667f0c..5d058b7 100644 --- a/verilog-ext-xref.el +++ b/verilog-ext-xref.el @@ -90,8 +90,8 @@ instead of to `verilog-mode', since the first one is loaded later and overwrites the hook value. Otherwise, hooks are not ran in a specific order, and rely on the priority argument." (if disable - (remove-hook 'verilog-ext-mode-hook #'verilog-ext-xref-backend-enable :local) - (add-hook 'verilog-ext-mode-hook #'verilog-ext-xref-backend-enable nil :local))) + (remove-hook 'verilog-ext-mode-hook #'verilog-ext-xref-backend-enable) + (add-hook 'verilog-ext-mode-hook #'verilog-ext-xref-backend-enable)))