branch: externals/gtags-mode commit 1aaac5fead13dcfd19b56a8108502f6d5ce1b5c8 Author: Jimmy Aguilar Mena <kratsbinov...@gmail.com> Commit: Jimmy Aguilar Mena <kratsbinov...@gmail.com>
Simplify code to so only the needed. (global-xref--exec-sync) : (global-xref--exec-async) : Separate sync from async calls in different functions. (global-xref--buffer-to-list) : Removed because sync call always return a list. (global-xref--find-root) : Use car. (global-xref--filter-find-symbol) : Change the arguments order. (global-xref--output-format-regex) : (global-xref--output-format-options) : New cons. --- global-xref.el | 179 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 91 insertions(+), 88 deletions(-) diff --git a/global-xref.el b/global-xref.el index 54f491f4a2..e75a84bb01 100644 --- a/global-xref.el +++ b/global-xref.el @@ -48,126 +48,130 @@ "Gtags executable." :type 'string) -(defun global-xref--buffer-to-list () - "Return lines in current buffer in a list." - (let ((lines)) - (goto-char (point-min)) - (while (not (eobp)) - (push (buffer-substring-no-properties - (line-beginning-position) (line-end-position)) - lines) - (forward-line 1)) - (nreverse lines))) - -(defvar global-xref--roots-list nil) +(defvar global-xref--roots-list nil + "Full list of project Global root. +The address is absolute on remote hsts.") (put 'global-xref--roots-list 'risky-local-variable t) (defvar-local global-xref--global (executable-find global-xref-global)) (defvar-local global-xref--gtags (executable-find global-xref-gtags)) (defvar-local global-xref--project-root nil - "Project Global root for this buffer.") - -(defun global-xref--exec (command args async &optional postfunction) - "Run COMMAND-SYM with and ARGS, in ASYNC way. -When ASYNC is 'nil' executes command synchronously; returns the -output of the command as a string or calls POSTFUNCTION in the -command's buffer and returns the result. returns nil if an error -occurred. -When ASYNC is non-nil starts an async process and executes the -ignores. Returns the process handler." + "Project Global root for this buffer. +the address is relative on remote hosts.") + +(defconst global-xref--output-format-regex + "^\\([^ \t]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([^ \t\]+\\)[ \t]+\\(.*\\)" + "Regex to filter the output with `global-xref--output-format-options'.") + +(defconst global-xref--output-format-options + '("--result=ctags-x" "--path-style=absolute") + "Command line options to use with `global-xref--output-format-regex'.") + +(defun global-xref--exec-async (command args) + "Run COMMAND with ARGS asynchronously. +Starts an async process and sets an informative process sentinel. +Returns the process handler." (with-connection-local-variables - (when-let (cmd (symbol-value command)) - (if async ;; When async - (let ((process (apply #'start-file-process + (when-let* ((cmd (symbol-value command)) + (process (apply #'start-file-process (format "%s-async" cmd) (generate-new-buffer " *temp*" t) cmd args))) - (set-process-sentinel - process - (lambda (process event) - (let ((temp-buffer (process-buffer process))) - (while (accept-process-output process)) - (if (eq (process-status process) 'exit) - (and (buffer-name temp-buffer) - (kill-buffer temp-buffer)) - (with-current-buffer temp-buffer - (message "global error output:\n%s" (buffer-string))))) - (message "Async %s: %s" (process-command process) event))) - process) - (with-temp-buffer ;; When sync - (let ((status (apply #'process-file cmd nil (current-buffer) nil args))) - (if (eq status 0) - (if (functionp postfunction) - (funcall postfunction) - (string-trim (buffer-substring-no-properties (point-min) (point-max)))) - (message "global error output:\n%s" (buffer-string)) - (error "Sync %s %s: exited abnormally with code %s" cmd args status) - nil))))))) - -(defsubst global-xref--to-list (args) - "Run GLOBAL with `process-file' and ARGS; return a list." - (global-xref--exec 'global-xref--global args nil #'global-xref--buffer-to-list)) + (set-process-sentinel + process + (lambda (process event) + (let ((temp-buffer (process-buffer process))) + (while (accept-process-output process)) + (if (eq (process-status process) 'exit) + (and (buffer-name temp-buffer) + (kill-buffer temp-buffer)) + (with-current-buffer temp-buffer + (message "global error output:\n%s" (buffer-string))))) + (message "Async %s: %s" (process-command process) event))) + process))) + +(defun global-xref--exec-sync (command args) + "Run COMMAND with ARGS synchronously. +Starts a sync process returns the output of the command as a list +of strings or nil if any error occurred." + (with-connection-local-variables + (when-let ((cmd (symbol-value command))) + (with-temp-buffer ;; When sync + (let ((status (apply #'process-file cmd nil (current-buffer) nil args))) + (if (eq status 0) + (let (lines substring) + (goto-char (point-min)) + (while (not (eobp)) + (when (not (string-blank-p + (setq substring (buffer-substring-no-properties + (line-beginning-position) + (line-end-position))))) + (push substring lines)) + (forward-line 1)) + (nreverse lines)) + (message "global error output:\n%s" (buffer-string)) + (error "Sync %s %s: exited abnormally with code %s" cmd args status) + nil)))))) (defun global-xref--set-connection-locals () "Set GLOBAL connection local variables when possible." - (when-let ((host (file-remote-p default-directory 'host))) - (let ((symvars (intern (concat "global-xref-" host "-vars"))) - (criteria `(:machine ,host)) - connection-local-variables-alist) - (hack-connection-local-variables criteria) - (unless (alist-get 'global-xref--global connection-local-variables-alist) - (connection-local-set-profile-variables - symvars - `((global-xref--global . ,(executable-find (file-name-base global-xref-global) t)) - (global-xref--gtags . ,(executable-find (file-name-base global-xref-gtags) t)))) - (connection-local-set-profiles criteria symvars))))) + (when-let* ((host (file-remote-p default-directory 'host)) + (symvars (intern (concat "global-xref-" host "-vars"))) + ((not (alist-get symvars connection-local-profile-alist))) + (criteria `(:machine ,host))) + (connection-local-set-profile-variables + symvars + `((global-xref--global . ,(executable-find (file-name-base global-xref-global) t)) + (global-xref--gtags . ,(executable-find (file-name-base global-xref-gtags) t)))) + (connection-local-set-profiles criteria symvars))) (defun global-xref--find-root () "Return the GLOBAL project root. Return nil if none." - (let ((root (global-xref--exec 'global-xref--global '("--print-dbpath") nil))) + (let ((root (car (global-xref--exec-sync 'global-xref--global '("--print-dbpath"))))) (when root (add-to-list 'global-xref--roots-list (concat (file-remote-p default-directory) (file-truename root))) root))) -(defun global-xref--filter-find-symbol (creator args symbol) - "Run GNU Global and apply CREATOR to global-xref--to-list output. -Return the results as a list." +(defun global-xref--filter-find-symbol (args symbol creator) + "Run global-xref--exec-sync with ARGS on SYMBOL and filter output with CREATOR. +Returns the results as a list of CREATORS outputs similar to +mapcar. Creator should be a function with 4 input arguments: +name, code, file, line." (remove nil - (mapcar (lambda (line) - (when (string-match - "^\\([^ \t]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([^ \t\]+\\)[ \t]+\\(.*\\)" - line) - (funcall creator - (match-string 1 line) ;; name - (match-string 4 line) ;; code - (match-string 3 line) ;; file - (string-to-number (match-string 2 line)) ;; line - ))) - (global-xref--to-list - (append args (list "--result=ctags-x" "--path-style=absolute" - (shell-quote-argument symbol))))))) + (mapcar + (lambda (line) + (when (string-match global-xref--output-format-regex line) + (funcall creator + (match-string 1 line) ;; name + (match-string 4 line) ;; code + (match-string 3 line) ;; file + (string-to-number (match-string 2 line))))) ;; line + (global-xref--exec-sync + 'global-xref--global + (append args global-xref--output-format-options + (list (shell-quote-argument symbol))))))) ;; Interactive commands. (defun global-xref-create-db (root-dir) "Create a GLOBAL database in ROOT-DIR asynchronously." (interactive "DCreate db in directory: ") (let ((default-directory root-dir)) - (global-xref--exec 'global-xref--gtags nil t))) + (global-xref--exec-async 'global-xref--gtags nil))) (defun global-xref-update () "Update GLOBAL project database." (interactive) (if global-xref--project-root - (global-xref--exec 'global-xref--global '("--update") t) + (global-xref--exec-async 'global-xref--global '("--update")) (error "Not under a GLOBAL project"))) (defun global-xref--after-save-hook () "After save hook to update GLOBAL database with changed data." (when (and buffer-file-name global-xref--project-root) - (global-xref--exec - 'global-xref--global `("--single-update" ,buffer-file-name) t))) + (global-xref--exec-async + 'global-xref--global `("--single-update" ,buffer-file-name)))) (defun global-xref--find-file-hook () "Try to enable `global-xref' when opening a file. @@ -188,11 +192,11 @@ one of them." Return the results as a list of xref location objects. ARGS are any additional command line arguments to pass to GNU Global." (global-xref--filter-find-symbol + args symbol (lambda (_name code file line) (xref-make code (xref-make-file-location (concat (file-remote-p default-directory) file) - line 0))) - args symbol)) + line 0))))) (defun global-xref-xref-backend () "Global-Xref backend for Xref." @@ -200,7 +204,7 @@ any additional command line arguments to pass to GNU Global." (cl-defmethod xref-backend-identifier-completion-table ((_backend (eql global-xref))) "List all symbols." - (global-xref--to-list '("--completion"))) + (global-xref--exec-sync 'global-xref--global '("--completion"))) (cl-defmethod xref-backend-definitions ((_backend (eql global-xref)) symbol) "List all definitions for SYMBOL." @@ -225,10 +229,9 @@ any additional command line arguments to pass to GNU Global." "Make imenu use Global." (when buffer-file-name (global-xref--filter-find-symbol + '("--file") (file-name-nondirectory buffer-file-name) (lambda (name _code _file line) - (list name line #'global-xref--imenu-goto-function)) - '("--file") - (file-name-nondirectory buffer-file-name)))) + (list name line #'global-xref--imenu-goto-function))))) ;;;###autoload (define-minor-mode global-xref-mode