diff options
Diffstat (limited to '.config/emacs/lisp/dumb-jump.el')
| -rw-r--r-- | .config/emacs/lisp/dumb-jump.el | 5706 |
1 files changed, 0 insertions, 5706 deletions
diff --git a/.config/emacs/lisp/dumb-jump.el b/.config/emacs/lisp/dumb-jump.el deleted file mode 100644 index 39e1f63..0000000 --- a/.config/emacs/lisp/dumb-jump.el +++ /dev/null @@ -1,5706 +0,0 @@ -;;; dumb-jump.el --- Jump to definition for 60+ languages without configuration -*- lexical-binding: t; -*- -;; Copyright (C) 2015-2026 jack angers -;; Author: jack angers and contributors -;; Url: https://github.com/jacktasia/dumb-jump -;; Version: 0.5.5 -;; Package-Requires: ((emacs "26.1")) -;; Keywords: programming - -;; Dumb Jump is free software; you can redistribute it and/or modify it -;; under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 3, or (at your option) -;; any later version. -;; -;; Dumb Jump is distributed in the hope that it will be useful, but WITHOUT -;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -;; License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with Dumb Jump. If not, see http://www.gnu.org/licenses. - -;;; Commentary: - -;; Dumb Jump is an Emacs "jump to definition" package with support for 60+ programming languages that favors -;; "just working" over speed or accuracy. This means minimal -- and ideally zero -- configuration with absolutely -;; no stored indexes (TAGS) or persistent background processes. -;; -;; Dumb Jump provides a xref-based interface for jumping to -;; definitions. It is based on tools such as grep, the silver searcher -;; (https://geoff.greer.fm/ag/), ripgrep -;; (https://github.com/BurntSushi/ripgrep) or git-grep -;; (https://git-scm.com/docs/git-grep). -;; -;; To enable Dumb Jump, add the following to your initialisation file: -;; -;; (add-hook 'xref-backend-functions #'dumb-jump-xref-activate) -;; -;; Now pressing M-. on an identifier should open a buffer at the place -;; where it is defined, or a list of candidates if uncertain. This -;; list can be navigated using M-g M-n (next-error) and M-g M-p -;; (previous-error). -;;; Code: -(require 'xref) -(require 'cl-generic) -(require 'cl-lib) -(require 'seq) -(require 'subr-x) -(require 'json) -(require 'project nil 'noerror) - -(defun dumb-jump--chop-prefix (prefix text) - "Remove PREFIX from TEXT when present." - (if (and (stringp prefix) - (stringp text) - (string-prefix-p prefix text)) - (substring text (length prefix)) - text)) - -(defun dumb-jump--contains-p (needle text &optional ignore-case) - "Return non-nil when TEXT contains NEEDLE as a literal substring. -When IGNORE-CASE is non-nil, match without case sensitivity." - (and (stringp needle) - (stringp text) - (save-match-data - (let ((case-fold-search ignore-case)) - (if (string-match-p (regexp-quote needle) text) t nil))))) - -(defun dumb-jump--index-of (needle text) - "Return the index of NEEDLE in TEXT, or nil when not found." - (when (and (stringp needle) (stringp text)) - (save-match-data - (string-match-p (regexp-quote needle) text)))) - -(defun dumb-jump--join (separator strings) - "Join STRINGS using SEPARATOR." - (mapconcat #'identity strings separator)) - -(defun dumb-jump--match (regexp text &optional start) - "Return list of REGEXP matches in TEXT from START, or nil." - (when (and (stringp regexp) - (stringp text)) - (save-match-data - (when (string-match regexp text start) - (let* ((group-count (/ (length (match-data t)) 2)) - (i 0) - matches) - (while (< i group-count) - (push (match-string i text) matches) - (setq i (1+ i))) - (nreverse matches)))))) - -(defun dumb-jump--matched-positions-all (regexp text &optional start) - "Return a list of match ranges for REGEXP in TEXT from START. -Each element is a cons cell of the form (START . END)." - (when (and (stringp regexp) (stringp text)) - (save-match-data - (let ((pos (or start 0)) - matches) - (while (string-match regexp text pos) - (let ((beg (match-beginning 0)) - (end (match-end 0))) - (push (cons beg end) matches) - ;; Avoid infinite loops if REGEXP can match empty strings. - (setq pos (if (= beg end) (1+ end) end)))) - (nreverse matches))))) - -(defun dumb-jump--replace (old new text) - "Replace all OLD literal matches in TEXT with NEW." - (replace-regexp-in-string (regexp-quote old) (or new "") (or text "") t t)) - -(defun dumb-jump--split (regexp text &optional omit-nulls) - "Split TEXT on REGEXP and optionally OMIT-NULLS." - (split-string (or text "") regexp omit-nulls)) - -(defun dumb-jump--trim (text) - "Trim leading and trailing whitespace from TEXT." - (string-trim (or text ""))) - -(defun dumb-jump--select-choice (choices &optional prompt) - "Choose one of CHOICES with `completing-read'. -PROMPT defaults to \"Jump to: \"." - (completing-read (or prompt "Jump to: ") choices nil t)) - -(defun dumb-jump--show-preview (text) - "Display TEXT preview to the user." - (message "%s" text)) - -(defun dumb-jump--find-index (pred list) - "Return index of first element in LIST satisfying PRED, or nil." - (let ((i 0)) - (catch 'found - (dolist (elem list) - (when (funcall pred elem) - (throw 'found i)) - (setq i (1+ i))) - nil))) - -(defun dumb-jump--zip-pair (list1 list2) - "Return list of cons pairs from LIST1 and LIST2." - (cl-mapcar #'cons list1 list2)) - -(defun dumb-jump--splice (pred rep list) - "Replace elements in LIST matching PRED with result of calling REP on them. -REP can return a list to splice in multiple elements." - (apply #'append - (mapcar (lambda (it) - (if (funcall pred it) - (funcall rep it) - (list it))) - list))) - -(defgroup dumb-jump nil - "Easily jump to project function and variable definitions." - :group 'tools - :group 'convenience) - -;;;###autoload -(defvar dumb-jump-mode-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "C-M-g") 'dumb-jump-go) - (define-key map (kbd "C-M-p") 'dumb-jump-back) - (define-key map (kbd "C-M-q") 'dumb-jump-quick-look) - map)) - -(defvar dumb-jump--search-mode 'definitions - "Current search mode: `definitions' (default) or `references'.") - -(defcustom dumb-jump-window - 'current - "Which window to use when jumping. -Valid options are \\='current (default) or \\='other." - :group 'dumb-jump - :type '(choice (const :tag "Current window" current) - (const :tag "Other window" other))) - -(defcustom dumb-jump-use-visible-window - t - "If true will jump in a visible window that shows the opened file." - :group 'dumb-jump - :type 'boolean) - -(defcustom dumb-jump-selector - 'completing-read - "Which selector to use when there is multiple choices. -The available selectors are: -- helm : https://emacs-helm.github.io/helm/ -- ivy : https://github.com/abo-abo/swiper -- Completing Read: Emacs default `completing-read'. - -When selecting helm or ivy, if the corresponding package is not installed, -the selector falls back to `completing-read'." - :group 'dumb-jump - :type '(choice (const :tag "Helm" helm) - (const :tag "Ivy" ivy) - (const :tag "Completing Read" completing-read))) - -(defcustom dumb-jump-ivy-jump-to-selected-function - #'dumb-jump-ivy-jump-to-selected - "Prompts user for a choice using ivy then dumb-jump to that choice." - :group 'dumb-jump - :type 'function) - -(defcustom dumb-jump-prefer-searcher nil - "The preferred searcher command line tool to use. -The available choices are: -- \\='ag : https://github.com/ggreer/the_silver_searcher -- \\='rg : https://github.com/BurntSushi/ripgrep -- \\='grep : https://en.wikipedia.org/wiki/Grep -- \\='gnu-grep : https://www.gnu.org/software/grep/manual/grep.html -- \\='git-grep : https://git-scm.com/docs/git-grep -- \\='git-grep-plus-ag - -If nil, select the most optimal searcher at runtime, looking for all -tools listed above except for git-grep in the order of that list. -However, the choice is overridden by `dumb-jump-force-searcher' selection -unless that is nil." - :group 'dumb-jump - :type '(choice (const :tag "Best Available" nil) - (const :tag "ag" ag) - (const :tag "rg" rg) - (const :tag "grep" grep) - (const :tag "gnu-grep" gnu-grep) - (const :tag "git grep" git-grep) - (const :tag "git grep + ag" git-grep-plus-ag))) - -(defcustom dumb-jump-force-searcher nil - "Search tool override of `dumb-jump-prefer-searcher' selection. - -By default this is nil to honour the choice made by `dumb-jump-prefer-searcher'. - -However, you may want to override that choice for some projects by identifying -one of two preferred choice overriding methods: -- Override preferred via user-specified function: - Enter the name of a function that takes the current directory and return the - search tool symbol to use for this project or nil if the choice made in - `dumb-jump-prefer-searcher' must be honoured. -- Override preferred for directories needing git-grep: - Specify one or more project directories where the git-grep search tool must - be used. -- Override to a specific tool. That is mostly useful to set the overriding - inside the .dir-locals.el of the directory. - The choices are: \\='ag, \\='rg, \\='grep, \\='gnu-grep, \\='git-grep, or - \\='git-grep-plus-ag." - :group 'dumb-jump - :type '(choice (const - :tag "nil: honour `dumb-jump-prefer-searcher' choice." nil) - (function - :tag "Override preferred via user-specified function") - (repeat - :tag "Override preferred for directories needing git-grep" - (directory :tag "Repo root")) - (const :tag "ag" ag) - (const :tag "rg" rg) - (const :tag "grep" grep) - (const :tag "gnu grep" gnu-grep) - (const :tag "git grep" git-grep) - (const :tag "git grep + ag" git-grep-plus-ag))) - -(defcustom dumb-jump-grep-prefix - "LANG=C" - "Prefix to grep command. Seemingly makes it faster for pure text." - :group 'dumb-jump - :type 'string) - -(defcustom dumb-jump-grep-cmd - "grep" - "The path to grep. By default assumes it is in path." - :group 'dumb-jump - :type 'string) - -(defcustom dumb-jump-ag-cmd - "ag" - "The path to the silver searcher. By default assumes it is in path." - :group 'dumb-jump - :type 'string) - -(defcustom dumb-jump-rg-cmd - "rg" - "The path to ripgrep. By default assumes it is in path." - :group 'dumb-jump - :type 'string) - -(defcustom dumb-jump-git-grep-cmd - "git grep" - "The path to git grep. By default assumes it is in path." - :group 'dumb-jump - :type 'string) - -;; --------------------------------------------------------------------------- -;; Dumb Jump Regular Expressions (see `dumb-jump-find-rules' docstring) - -(defcustom dumb-jump-force-using-space-bracket-exp - (eq system-type 'windows-nt) - "When t the `\\\\s` in regexp code strings is replaced by `[[:space:]]`. -Otherwise it is left in the regular expression. -Defaults to t under Windows because older gnu grep versions have problem -dealing with `\\\\s` to match end of words due to the 2 bytes used to -identify the end of line." - :group 'dumb-jump - :type 'boolean) - -(defun dumb-jump-use-space-bracket-exp-for (variant) - "Return t when `\\\\s` must be replaced by `[[:space]]` for VARIANT. -VARIANT must be a one of the following symbols: ag, rg, grep, gnu-grep, -git-grep or git-grep-plus-ag." - (and dumb-jump-force-using-space-bracket-exp - (memq variant '(grep gnu-grep git-grep git-grep-plus-ag)))) - -;; word-boundary regexps: they replace the "\\j" in dumb-jump regexes. -;; [:todo 2026-01-29, by Pierre Rouleau: Should we not exclude '_' from word boundary?] -(defcustom dumb-jump-ag-word-boundary - "(?![a-zA-Z0-9\\?\\*-])" - "Regexp that replaces `\\j` in dumb-jump regexes for ag search. -`\\b` thinks `-` is a word boundary. -When this matters use `\\j` instead and ag will use this value." - :group 'dumb-jump - :type 'string) - -;; [:todo 2026-01-29, by Pierre Rouleau: Should we not exclude '_' from word boundary?] -(defcustom dumb-jump-rg-word-boundary - "($|[^a-zA-Z0-9\\?\\*-])" - "Regexp that replaces `\\j` in dumb-jump regexes for rg search. -`\\b` thinks `-` is a word boundary. -When this matters use `\\j` instead and rg will use this value." - :group 'dumb-jump - :type 'string) - -;; [:todo 2026-01-29, by Pierre Rouleau: Should we not exclude '_' from word boundary?] -(defcustom dumb-jump-git-grep-word-boundary - "($|[^a-zA-Z0-9\\?\\*-])" - "Regexp that replaces `\\j` in dumb-jump regexes for git-grep search. -`\\b` thinks `-` is a word boundary. -When this matters use `\\j` instead and git grep will use this value." - :group 'dumb-jump - :type 'string) - -;; [:todo 2026-01-29, by Pierre Rouleau: Should we not exclude '_' from word boundary?] -(defcustom dumb-jump-grep-word-boundary - "($|[^a-zA-Z0-9\\?\\*-])" - "Regexp that replaces `\\j` in dumb-jump regexes for grep search. -`\\b` thinks `-` is a word boundary. -When this matters use `\\j` instead and grep will use this value." - :group 'dumb-jump - :type 'string) - -;; [:todo 2026-01-29, by Pierre Rouleau: Should we not exclude '_' from word boundary?] -(defcustom dumb-jump-gnu-grep-word-boundary - "($|[^a-zA-Z0-9\\?\\*-])" - "Regexp that replaces `\\j` in dumb-jump regexes for gnu grep search. -`\\b` thinks `-` is a word boundary. -When this matters use `\\j` instead and grep will use this value." - :group 'dumb-jump - :type 'string) - -;; -- - -(defcustom dumb-jump-fallback-regex - "\\bJJJ\\j" - "When `dumb-jump-fallback-search' is t use this regex. -Defaults to boundary search of symbol under point." - :group 'dumb-jump - :type 'string) - -(defcustom dumb-jump-fallback-search - t - "If nothing is found with normal search fallback searching fallback regex." - :group 'dumb-jump - :type 'boolean) - -(defcustom dumb-jump-zgrep-cmd - "zgrep" - "The path to grep to use for gzipped files. -By default assumes it is in path." - :group 'dumb-jump - :type 'string) - -(defcustom dumb-jump-grep-args "-REn" - "Grep command args [R]ecursive, [E]xtended regexes, and show line [n]umbers." - :group 'dumb-jump - :type 'string) - -(defcustom dumb-jump-gnu-grep-args "-rEn" - "Grep command args [r]ecursive and [E]xtended regexes, and show line [n]umbers." - :group 'dumb-jump - :type 'string) - -(defcustom dumb-jump-max-find-time - 2 - "Number of seconds a grep/find command can take before issuing a warning. -The warning recommend using a faster search tool and config." - :group 'dumb-jump - :type 'integer) - -(defcustom dumb-jump-functions-only - nil - "Should we only jump to functions?" - :group 'dumb-jump - :type 'boolean) - -(defcustom dumb-jump-quiet - nil - "If non-nil Dumb Jump will not log anything to *Messages*. -Note that it prevents printing when `dumb-jump-debug' is non-nil." - :group 'dumb-jump - :type 'boolean) - -(defcustom dumb-jump-ignore-context - nil - "If non-nil Dumb Jump will ignore the context of point when jumping." - :group 'dumb-jump - :type 'boolean) - -(defcustom dumb-jump-git-grep-search-untracked - t - "If non-nil Dumb Jump will also search untracked files when using git-grep." - :group 'dumb-jump - :type 'boolean) - -(defcustom dumb-jump-git-grep-search-args - "" - "Appends the passed arguments to the git-grep search function. -Default: \"\"." - :group 'dumb-jump - :type 'string) - -(defcustom dumb-jump-ag-search-args - "" - "Appends the passed arguments to the ag search function. -Default: \"\"." - :group 'dumb-jump - :type 'string) - -(defcustom dumb-jump-rg-search-args - "--pcre2" - "Appends the passed arguments to the rg search function. -Default: \"--pcre2\"." - :group 'dumb-jump - :type 'string) - -(defcustom dumb-jump-search-type-org-only-org - t - "If non nil restrict type ag/rg to org file. -If nil add also the language type of current src block." - :group 'dumb-jump - :type 'boolean) - -;; [:todo 2026-01-29, by Pierre Rouleau: Why 3 backslashes in front of '('? ] -(defcustom dumb-jump-find-rules - ;;-- elisp - '((:language "elisp" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\((defun|cl-defun|cl-defgeneric|cl-defmethod|cl-defsubst)\\s+JJJ\\j" - :tests ("(defun test (blah)" - "(defun test\n" - "(cl-defun test (blah)" - "(cl-defun test\n") - :not ("(defun test-asdf (blah)" - "(defun test-blah\n" - "(cl-defun test-asdf (blah)" - "(cl-defun test-blah\n" - "(defun tester (blah)" - "(defun test? (blah)" - "(defun test- (blah)")) - - (:language "elisp" :type "function" ; macros - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\((defmacro|cl-defmacro|cl-define-compiler-macro)\\s+JJJ\\j" - :tests ("(defmacro test (blah)" - "(defmacro test\n") - :not ("(defmacro test-asdf (blah)" - "(defmacro test-blah\n" - "(defmacro tester (blah)" - "(defmacro test? (blah)" - "(defmacro test- (blah)")) - - (:language "elisp" :type "function" ; hydras - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\(defhydra\\b\\s*JJJ\\j" - :tests ("(defhydra test " - "(defhydra test\n" - "(defhydra test (blah\n" - "(defhydra test (blah)") - :not ("(defhydra tester" - "(defhydra test?" - "(defhydra test-" - "(defhydra test? (blah\n" - "(defhydra test? (blah)")) - - (:language "elisp" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\(defvar(-local)?\\b\\s*JJJ\\j" - :tests ("(defvar test " - "(defvar test\n" - "(defvar-local test" - "(defvar-local test\n") - :not ("(defvar tester" - "(defvar test?" - "(defvar test-" - "(defvar-local tester" - "(defvar-local test?" - "(defvar-local test-")) - - (:language "elisp" :type "variable" - :supports ("ag" "grep" "rg" "ugrep" "git-grep") - :regex "\\(defconst\\b\\s*JJJ\\j" - :tests ("(defconst test " - "(defconst test\n") - :not ("(defconst tester" - "(defconst test?" - "(defconst test-")) - - (:language "elisp" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\(defcustom\\b\\s*JJJ\\j" - :tests ("(defcustom test " - "(defcustom test\n") - :not ("(defcustom tester" - "(defcustom test?" - "(defcustom test-")) - - (:language "elisp" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\(setq\\b\\s*JJJ\\j" - :tests ("(setq test 123)") - :not ("setq test-blah 123)" - "(setq tester" - "(setq test?" "(setq test-")) - - (:language "elisp" :type "variable" ; let bound variables - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\(JJJ\\s+" - :skip-ref-filter t - :tests ("(let ((test 123)))" - "(let* ((test 123)))") - :not ("(let ((test-2 123)))" - "(let* ((test-2 123)))")) - - (:language "elisp" :type "type" ; cl-lib structured type definitions - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\((cl-defstruct|cl-deftype)\\s+JJJ\\j" - :tests ("(cl-defstruct test " - "(cl-defstruct test\n" - "(cl-deftype test " - "(cl-deftype test\n") - :not ("(cl-defstruct test-asdf (blah)" - "(cl-defstruct test-blah\n" - "(cl-deftype test-asdf (blah)" - "(cl-deftype test-blah\n")) - - (:language "elisp" :type "variable" ;; variable in method signature - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\((defun|cl-defun|cl-defgeneric|cl-defmethod)\\s*.+\\(?\\s*JJJ\\j\\s*\\)?" - :tests ("(defun blah (test)" - "(defun blah (test blah)" - "(defun (blah test)") - :not ("(defun blah (test-1)" - "(defun blah (test-2 blah)" - "(defun (blah test-3)")) - - ;;-- common lisp - (:language "commonlisp" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\\(def(un|macro|generic|method|setf)\\s+JJJ\\j" - ;; \\j usage see `dumb-jump-ag-word-boundary` - :tests ("(defun test (blah)" - "(defun test\n" - "(defmacro test (blah)" - "(defmacro test\n" - "(defgeneric test (blah)" - "(defgeneric test\n" - "(defmethod test (blah)" - "(defmethod test\n" - "(defsetf test (blah)" - "(defsetf test\n") - :not ("(defun test-asdf (blah)" - "(defun test-blah\n" - "(defun tester (blah)" - "(defun test? (blah)" - "(defun test- (blah)" - "(defmacro test-asdf (blah)" - "(defmacro test-blah\n" - "(defmacro tester (blah)" - "(defmacro test? (blah)" - "(defmacro test- (blah)" - "(defgeneric test-asdf (blah)" - "(defgeneric test-blah\n" - "(defgeneric tester (blah)" - "(defgeneric test? (blah)" - "(defun test- (blah)" - "(defmethod test-asdf (blah)" - "(defmethod test-blah\n" - "(defmethod tester (blah)" - "(defmethod test? (blah)" - "(defun test- (blah)" - "(defsetf test-asdf (blah)" - "(defsetf test-blah\n" - "(defsetf tester (blah)" - "(defsetf test? (blah)" - "(defun test- (blah)")) - - (:language "commonlisp" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\\(define-(modify-macro|compiler-macro|setf-expander)\\s+JJJ\\j" - ;; \\j usage see `dumb-jump-ag-word-boundary` - :tests ("(define-modify-macro test (blah)" - "(define-modify-macro test\n" - "(define-compiler-macro test (blah)" - "(define-compiler-macro test\n") - :not ("(define-modify-macro test-asdf (blah)" - "(define-modify-macro test-blah\n" - "(define-modify-macro tester (blah)" - "(define-modify-macro test? (blah)" - "(define-modify-macro test- (blah)" - "(define-compiler-macro test-asdf (blah)" - "(define-compiler-macro test-blah\n" - "(define-compiler-macro tester (blah)" - "(define-compiler-macro test? (blah)" - "(define-compiler-macro test- (blah)")) - - (:language "commonlisp" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\\(def(var|parameter|constant)\\b\\s*JJJ\\j" - :tests ("(defvar test " - "(defvar test\n" - "(defparameter test " - "(defparameter test\n" - "(defconstant test " - "(defconstant test\n") - :not ("(defvar tester" - "(defvar test?" - "(defvar test-" - "(defparameter tester" - "(defparameter test?" - "(defparameter test-" - "(defconstant tester" - "(defconstant test?" - "(defconstant test-")) - - (:language "commonlisp" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\\(define-symbol-macro\\b\\s*JJJ\\j" - :tests ("(define-symbol-macro test " - "(define-symbol-macro test\n") - :not ("(define-symbol-macro tester" - "(define-symbol-macro test?" - "(define-symbol-macro test-")) - - (:language "commonlisp" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\\(def(class|struct|type)\\b\\s*JJJ\\j" - :tests ("(defclass test " - "(defclass test\n" - "(defstruct test " - "(defstruct test\n" - "(deftype test " - "(deftype test\n") - :not ("(defclass tester" - "(defclass test?" - "(defclass test-" - "(defstruct tester" - "(defstruct test?" - "(defstruct test-" - "(deftype tester" - "(deftype test?" - "(deftype test-")) - - (:language "commonlisp" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\\(define-condition\\b\\s*JJJ\\j" - :tests ("(define-condition test " - "(define-condition test\n") - :not ("(define-condition tester" - "(define-condition test?" - "(define-condition test-")) - - ;;-- racket - (:language "racket" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\\(define\\s+\\(\\s*JJJ\\j" - :tests ("(define (test blah)" - "(define (test\n") - :not ("(define test blah" - "(define (test-asdf blah)" - "(define test (lambda (blah")) - - (:language "racket" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\\(define\\s+JJJ\\s*\\\(\\s*lambda" - :tests ("(define test (lambda (blah" - "(define test (lambda\n") - :not ("(define test blah" - "(define test-asdf (lambda (blah)" - "(define (test)" - "(define (test blah) (lambda (foo")) - - (:language "racket" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\\(let\\s+JJJ\\s*(\\\(|\\\[)*" - :tests ("(let test ((blah foo) (bar bas))" - "(let test\n" - "(let test [(foo") - :not ("(let ((test blah")) - - (:language "racket" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\\(define\\s+JJJ\\j" - :tests ("(define test " "(define test\n") - :not ("(define (test")) - - (:language "racket" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(\\\(|\\\[)\\s*JJJ\\s+" - :tests ("(let ((test 'foo" - "(let [(test 'foo" - "(let [(test 'foo" - "(let [[test 'foo" - "(let ((blah 'foo) (test 'bar)") - :not ("{test foo")) - - (:language "racket" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\\(lambda\\s+\\\(?[^\(\)]*\\s*JJJ\\j\\s*\\\)?" - :tests ("(lambda (test)" - "(lambda (foo test)" - "(lambda test (foo)") - :not ("(lambda () test")) - - (:language "racket" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\\(define\\s+\\\([^\(\)]+\\s*JJJ\\j\\s*\\\)?" - :tests ("(define (foo test)" - "(define (foo test bar)") - :not ("(define foo test" - "(define (test foo" - "(define (test)")) - - (:language "racket" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\(struct\\s+JJJ\\j" - :tests ("(struct test (a b)")) - - ;;-- scheme - (:language "scheme" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\\(define\\s+\\(\\s*JJJ\\j" - :tests ("(define (test blah)" - "(define (test\n") - :not ("(define test blah" - "(define (test-asdf blah)" - "(define test (lambda (blah")) - - (:language "scheme" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\\(define\\s+JJJ\\s*\\\(\\s*lambda" - :tests ("(define test (lambda (blah" - "(define test (lambda\n") - :not ("(define test blah" - "(define test-asdf (lambda (blah)" - "(define (test)" - "(define (test blah) (lambda (foo")) - - (:language "scheme" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\\(let\\s+JJJ\\s*(\\\(|\\\[)*" - :tests ("(let test ((blah foo) (bar bas))" - "(let test\n" - "(let test [(foo") - :not ("(let ((test blah")) - - (:language "scheme" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\\(define\\s+JJJ\\j" - :tests ("(define test " - "(define test\n") - :not ("(define (test")) - - (:language "scheme" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(\\\(|\\\[)\\s*JJJ\\s+" - :tests ("(let ((test 'foo" - "(let [(test 'foo" - "(let [(test 'foo" - "(let [[test 'foo" - "(let ((blah 'foo) (test 'bar)") - :not ("{test foo")) - - (:language "scheme" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\\(lambda\\s+\\\(?[^\(\)]*\\s*JJJ\\j\\s*\\\)?" - :tests ("(lambda (test)" - "(lambda (foo test)" - "(lambda test (foo)") - :not ("(lambda () test")) - - (:language "scheme" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\\(define\\s+\\\([^\(\)]+\\s*JJJ\\j\\s*\\\)?" - :tests ("(define (foo test)" - "(define (foo test bar)") - :not ("(define foo test" - "(define (test foo" - "(define (test)")) - - ;;-- janet - (:language "janet" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\(\(de\)?f\\s+JJJ\\j" - :tests ("(def test (foo)")) - - (:language "janet" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\(var\\s+JJJ\\j" - :tests ("(var test (foo)")) - - (:language "janet" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\(\(de\)fn-?\\s+JJJ\\j" - :tests ("(defn test [foo]" - "(defn- test [foo]") - :not ("(defn test? [foo]" - "(defn- test? [foo]")) - - (:language "janet" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\(defmacro\\s+JJJ\\j" - :tests ("(defmacro test [foo]")) - - ;;-- c++ - (:language "c++" :type "function" - :supports ("ag" "rg" "git-grep") - :regex "\\bJJJ(\\s|\\))*\\((\\w|[,&*.<>:]|\\s)*(\\))\\s*(const|->|\\{|$)|typedef\\s+(\\w|[(*]|\\s)+JJJ(\\)|\\s)*\\(" - :tests ("int test(){" - "my_struct (*test)(int a, int b){" - "auto MyClass::test ( Builder::Builder& reference, ) -> decltype( builder.func() ) {" - "int test( int *random_argument) const {" - "test::test() {" - "typedef int (*test)(int);") - :not ("return test();)" - "int test(a, b);" - "if( test() ) {" - "else test();")) - - ;; (:language "c++" :type "variable" - ;; :supports ("grep") - ;; :regex "(\\b\\w+|[,>])([*&]|\\s)+JJJ\\s*(\\[([0-9]|\\s)*\\])*\\s*([=,){;]|:\\s*[0-9])|#define\\s+JJJ\\b" - ;; :tests ("int test=2;" "char *test;" "int x = 1, test = 2" "int test[20];" "#define test" "unsigned int test:2;")) - - (:language "c++" :type "variable" - :supports ("ag" "rg") - :regex "\\b(?!(class\\b|struct\\b|return\\b|else\\b|delete\\b))(\\w+|[,>])([*&]|\\s)+JJJ\\s*(\\[(\\d|\\s)*\\])*\\s*([=,(){;]|:\\s*\\d)|#define\\s+JJJ\\b" - :tests ("int test=2;" - "char *test;" - "int x = 1, test = 2" - "int test[20];" - "#define test" - "typedef int test;" - "unsigned int test:2") - :not ("return test;" - "#define NOT test" - "else test=2;")) - - (:language "c++" :type "type" - :supports ("ag" "rg" "git-grep") - :regex "\\b(class|struct|enum|union)\\b\\s*JJJ\\b\\s*(final\\s*)?(:((\\s*\\w+\\s*::)*\\s*\\w*\\s*<?(\\s*\\w+\\s*::)*\\w+>?\\s*,*)+)?((\\{|$))|}\\s*JJJ\\b\\s*;" - :tests ("typedef struct test {" - "enum test {" - "} test;" - "union test {" - "class test final: public Parent1, private Parent2{" - "class test : public std::vector<int> {") - :not("union test var;" - "struct test function() {")) - - ;;-- clojure - (:language "clojure" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\(def.*\ JJJ\\j" - :tests ("(def test (foo)" - "(defn test [foo]" - "(defn ^:some-data test [foo]" - "(defn- test [foo]" - "(defmacro test [foo]" - "(deftask test [foo]" - "(deftype test [foo]" - "(defmulti test fn" - "(defmethod test type" - "(definterface test (foo)" - "(defprotocol test (foo)" - "(defrecord test [foo]" - "(deftest test")) - - ;;-- coffeescript - (:language "coffeescript" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^\\s*JJJ\\s*[=:].*[-=]>" - :tests ("test = () =>" - "test= =>" - "test = ->" - "test=()->" - "test : () =>" - "test: =>" - "test : ->" - "test:()->") - :not ("# test = =>" - "test = 1")) - - (:language "coffeescript" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^\\s*JJJ\\s*[:=][^:=-][^>]+$" - :tests ("test = $" - "test : [" - "test = {" - "test = a") - :not ("test::a" - "test: =>" - "test == 1" - "# test = 1")) - - (:language "coffeescript" :type "class" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^\\s*\\bclass\\s+JJJ" - :tests ("class test" - "class test extends") - :not ("# class")) - - ;;-- objc : Objective-C - (:language "objc" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\\)\\s*JJJ(:|\\b|\\s)" - :tests ("- (void)test" - "- (void)test:(UIAlertView *)alertView") - :not ("- (void)testnot" - "- (void)testnot:(UIAlertView *)alertView")) - - (:language "objc" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\b\\*?JJJ\\s*=[^=\\n]+" - :tests ("NSString *test = @\"asdf\"") - :not ("NSString *testnot = @\"asdf\"" - "NSString *nottest = @\"asdf\"")) - - (:language "objc" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(@interface|@protocol|@implementation)\\b\\s*JJJ\\b\\s*" - :tests ("@interface test: UIWindow") - :not ("@interface testnon: UIWindow")) - - - (:language "objc" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "typedef\\b\\s+(NS_OPTIONS|NS_ENUM)\\b\\([^,]+?,\\s*JJJ\\b\\s*" - :tests ("typedef NS_ENUM(NSUInteger, test)") - :not ("typedef NS_ENUMD(NSUInteger, test)")) - - ;;-- swift - (:language "swift" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(let|var)\\s*JJJ\\s*(=|:)[^=:\\n]+" - :tests ("let test = 1234" - "var test = 1234" - "private lazy var test: UITapGestureRecognizer") - :not ("if test == 1234:")) - - (:language "swift" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "func\\s+JJJ\\b\\s*(<[^>]*>)?\\s*\\(" - :tests ("func test(asdf)" - "func test()" - "func test<Value: Protocol>()") - :not ("func testnot(asdf)" - "func testnot()")) - - (:language "swift" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(class|struct|protocol|enum)\\s+JJJ\\b\\s*?" - :tests ("struct test" - "struct test: Codable" - "struct test<Value: Codable>" - "class test:" - "class test: UIWindow" - "class test<Value: Codable>") - :not ("class testnot:" - "class testnot(object):" - "struct testnot(object)")) - - (:language "swift" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(typealias)\\s+JJJ\\b\\s*?=" - :tests ("typealias test =") - :not ("typealias testnot")) - - ;;-- csharp : C# - (:language "csharp" :type "function" - :supports ("ag" "rg") - :regex "^\\s*(?:[\\w\\[\\]]+\\s+){1,3}JJJ\\s*\\\(" - :tests ("int test()" - "int test(param)" - "static int test()" - "static int test(param)" - "public static MyType test()" - "private virtual SomeType test(param)" - "static int test()") - :not ("test()" - "testnot()" - "blah = new test()")) - - (:language "csharp" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*\\bJJJ\\s*=[^=\\n)]+" - :tests ("int test = 1234") - :not ("if test == 1234:" - "int nottest = 44")) - - (:language "csharp" :type "variable" - :supports ("ag" "rg") - :regex "\\bforeach\\s*\\(\\s*[\\w\\[\\]<>,\\.?]+\\s+JJJ\\s+in\\b" - :tests ("foreach (int test in items)" - "foreach (var test in items)" - "foreach (string test in items)" - "foreach (List<int> test in items)") - :not ("foreach (int nottest in items)" - "test in items")) - - (:type "type" - :supports ("ag" "grep" "rg" "git-grep") - :language "csharp" - :regex "(class|interface)\\s*JJJ\\b" - :tests ("class test:" - "public class test : IReadableChannel, I") - :not ("class testnot:" - "public class testnot : IReadableChannel, I")) - - ;;-- java (literally the same regexes as c#, but different tests) - (:language "java" :type "function" - :supports ("ag" "rg") - :regex "^\\s*(?:[\\w\\[\\]]+\\s+){1,3}JJJ\\s*\\\(" - :tests ("int test()" - "int test(param)" - "static int test()" - "static int test(param)" - "public static MyType test()" - "private virtual SomeType test(param)" - "static int test()" - "private foo[] test()") - :not ("test()" - "testnot()" - "blah = new test()" - "foo bar = test()")) - - (:language "java" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*\\bJJJ\\s*=[^=\\n)]+" - :tests ("int test = 1234") - :not ("if test == 1234:" - "int nottest = 44")) - - (:language "java" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(class|interface)\\s*JJJ\\b" - :tests ("class test:" - "public class test implements Something") - :not ("class testnot:" - "public class testnot implements Something")) - - (:language "java" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\benum\\s+JJJ\\b" - :tests ("enum test {" - "public enum test {") - :not ("enum testnot {")) - - (:language "java" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "@interface\\s+JJJ\\b" - :tests ("@interface test {" - "public @interface test {") - :not ("@interface testnot {")) - - ;; grep/git-grep fallback: requires access modifier because grep lacks - ;; PCRE features (?:...) and {n,m} used by the ag/rg rule above. - (:language "java" :type "function" - :supports ("grep" "git-grep") - :regex "(public|protected|private|static)[^(]+JJJ\\s*\\\(" - :tests ("public int test()" - "private static String test(param)" - "protected List<String> test()") - :not ("test()" - "new test()")) - - ;;-- vala (again just like c#, exactly the same..) - (:language "vala" :type "function" - :supports ("ag" "rg") - :regex "^\\s*(?:[\\w\\[\\]]+\\s+){1,3}JJJ\\s*\\\(" - :tests ("int test()" - "int test(param)" - "static int test()" - "static int test(param)" - "public static MyType test()" - "private virtual SomeType test(param)" - "static int test()") - :not ("test()" - "testnot()" - "blah = new test()")) - - (:language "vala" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*\\bJJJ\\s*=[^=\\n)]+" - :tests ("int test = 1234") - :not ("if test == 1234:" - "int nottest = 44")) - - (:language "vala" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(class|interface)\\s*JJJ\\b" - :tests ("class test:" - "public class test : IReadableChannel, I") - :not ("class testnot:" - "public class testnot : IReadableChannel, I")) - - ;;-- coq (renamed Rocq in March 2025) - (:language "coq" :type "function" - :supports ("ag" "rg" "grep" "git-grep") - :regex "\\s*Variable\\s+JJJ\\b" - :tests ("Variable test") - :not ("Variable testx")) - - (:language "coq" :type "function" - :supports ("ag" "rg" "grep" "git-grep") - :regex "\\s*Inductive\\s+JJJ\\b" - :tests ("Inductive test") - :not ("Inductive testx")) - - (:language "coq" :type "function" - :supports ("ag" "rg" "grep" "git-grep") - :regex "\\s*Lemma\\s+JJJ\\b" - :tests ("Lemma test") - :not ("Lemma testx")) - - (:language "coq" :type "function" - :supports ("ag" "rg" "grep" "git-grep") - :regex "\\s*Definition\\s+JJJ\\b" - :tests ("Definition test") - :not ("Definition testx")) - - (:language "coq" :type "function" - :supports ("ag" "rg" "grep" "git-grep") - :regex "\\s*Hypothesis\\s+JJJ\\b" - :tests ("Hypothesis test") - :not ("Hypothesis testx")) - - (:language "coq" :type "function" - :supports ("ag" "rg" "grep" "git-grep") - :regex "\\s*Theorem\\s+JJJ\\b" - :tests ("Theorem test") - :not ("Theorem testx")) - - (:language "coq" :type "function" - :supports ("ag" "rg" "grep" "git-grep") - :regex "\\s*Fixpoint\\s+JJJ\\b" - :tests ("Fixpoint test") - :not ("Fixpoint testx")) - - (:language "coq" :type "function" - :supports ("ag" "rg" "grep" "git-grep") - :regex "\\s*Module\\s+JJJ\\b" - :tests ("Module test") - :not ("Module testx")) - - (:language "coq" :type "function" - :supports ("ag" "rg" "git-grep") - :regex "\\s*CoInductive\\s+JJJ\\b" - :tests ("CoInductive test") - :not ("CoInductive testx")) - - ;;-- python - (:language "python" :type "variable" - :supports ("ag" "rg") - :regex "\\s*\\bJJJ\\b(\\s*:[^=\\n]+)?\\s*=[^=\\n]+" - :tests ("test = 1234" - "test: int = 1234" - "test: int | None = 1234" - "test: List[Optional[int]] = [1234, None]") - :not ("if test == 1234:" - "_test = 1234" - "if (test := 3):" - "while test:" - "test['key'] = 1234")) - - (:language "python" :type "variable" - :supports ("grep" "git-grep") - :regex "\\s*\\bJJJ\\b(\\s*:[^=]+)?\\s*=[^=]+" - :tests ("test = 1234" - "test: int = 1234" - "test: int | None = 1234" - "test: List[Optional[int]] = [1234, None]") - :not ("if test == 1234:" - "_test = 1234" - "if (test := 3):" - "while test:" - "test['key'] = 1234")) - - (:language "python" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "def\\s*JJJ\\b\\s*\\\(" - :tests ("\tdef test(asdf)" - "def test()") - :not ("\tdef testnot(asdf)" - "def testnot()")) - - (:language "python" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "class\\s*JJJ\\b\\s*\\\(?" - :tests ("class test(object):" - "class test:") - :not ("class testnot:" - "class testnot(object):")) - - (:language "python" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "async\\s+def\\s*JJJ\\b\\s*\\\(" - :tests ("async def test(param)" - "async def test()") - :not ("async def testnot(param)" - "async def testnot()")) - - (:language "python" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^\\s*JJJ\\s*=\\s*lambda\\b" - :tests ("test = lambda x: x" - "test = lambda: None") - :not ("testnot = lambda x: x" - "foo(test=lambda x: x)")) - - ;;-- matlab - (:language "matlab" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^\\s*\\bJJJ\\s*=[^=\\n]+" - :tests ("test = 1234") - :not ("for test = 1:2:" - "_test = 1234")) - - (:language "matlab" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^\\s*function\\s*[^=]+\\s*=\\s*JJJ\\b" - :tests ("\tfunction y = test(asdf)" - "function x = test()" - "function [x, losses] = test(A, y, lambda, method, qtile)") - :not ("\tfunction testnot(asdf)" - "function testnot()")) - - (:language "matlab" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^\\s*classdef\\s*JJJ\\b\\s*" - :tests ("classdef test") - :not ("classdef testnot")) - - ;;-- nim - (:language "nim" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(const|let|var)\\s*JJJ\\*?\\s*(=|:)[^=:\\n]+" - :tests ("let test = 1234" - "var test = 1234" - "var test: Stat" - "const test = 1234" - "const test* = 1234") - :not ("if test == 1234:")) - - (:language "nim" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(proc|func|macro|template)\\s*`?JJJ`?\\b\\*?\\s*\\\(" - :tests ("\tproc test(asdf)" - "proc test()" - "func test()" - "macro test()" - "template test()" - "proc test*()") - :not ("\tproc testnot(asdf)" - "proc testnot()")) - - (:language "nim" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "type\\s*JJJ\\b\\*?\\s*(\\{[^}]+\\})?\\s*=\\s*\\w+" - :tests ("type test = object" - "type test {.pure.} = enum" - "type test* = ref object") - :not ("type testnot = object")) - - ;;-- nix - (:language "nix" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\b\\s*JJJ\\s*=[^=;]+" - :tests ("test = 1234;" - "test = 123;" - "test=123") - :not ("testNot = 1234;" - "Nottest = 1234;" - "AtestNot = 1234;")) - - ;;-- org - ;; org named blocks - (:language "org" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^\\s*#\\+[nN][aA][mM][eE]:\\s*JJJ\\j" - :tests ("#+name: test" - "#+NAME: test" - "#+Name: test" - " #+name: test" - "#+name:test") - :not ("#+name: tester" - "#+name: test-block" - "some #+name: test")) - - ;; org call references (#+call: block-name) - (:language "org" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^\\s*#\\+[cC][aA][lL][lL]:\\s*JJJ\\j" - :tests ("#+call: test" - "#+CALL: test" - "#+Call: test" - " #+call: test" - "#+call: test()" - "#+call: test(x=1)") - :not ("#+call: tester" - "#+call: test-other" - "some #+call: test")) - - ;; org headings (* Heading text) - (:language "org" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^\\*+\\s+JJJ\\j" - :tests ("* test" - "** test" - "*** test" - "**** test" - "* test heading" - "** test with more words") - :not ("* tester" - "** testing" - "* test-other" - "not a * test heading")) - - ;; org custom ID (:CUSTOM_ID: value in property drawers) - (:language "org" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^\\s*:CUSTOM_ID:\\s*JJJ\\j" - :tests (":CUSTOM_ID: test" - ":CUSTOM_ID: test" - " :CUSTOM_ID: test" - ":CUSTOM_ID:test") - :not (":CUSTOM_ID: tester" - ":CUSTOM_ID: test-other" - "inline :CUSTOM_ID: test text")) - - ;;-- ruby - (:language "ruby" :type "variable" - :supports ("ag" "rg" "git-grep") - :regex "^\\s*((\\w+[.])*\\w+,\\s*)*JJJ(,\\s*(\\w+[.])*\\w+)*\\s*=([^=>~]|$)" - :tests ("test = 1234" - "self.foo, test, bar = args") - :not ("if test == 1234" - "foo_test = 1234")) - - (:language "ruby" :type "function" - :supports ("ag" "rg" "git-grep") - :regex "(^|[^\\w.])((private|public|protected)\\s+)?def\\s+(\\w+(::|[.]))*JJJ($|[^\\w|:])" - :tests ("def test(foo)" - "def test()" - "def test foo" - "def test; end" - "def self.test()" - "def MODULE::test()" - "private def test") - :not ("def test_foo")) - - (:language "ruby" :type "function" - :supports ("ag" "rg" "git-grep") - :regex "(^|\\W)define(_singleton|_instance)?_method(\\s|[(])\\s*:JJJ($|[^\\w|:])" - :tests ("define_method(:test, &body)" - "mod.define_instance_method(:test) { body }")) - - (:language "ruby" :type "type" - :supports ("ag" "rg" "git-grep") - :regex "(^|[^\\w.])class\\s+(\\w*::)*JJJ($|[^\\w|:])" - :tests ("class test" - "class Foo::test")) - - (:language "ruby" :type "type" - :supports ("ag" "rg" "git-grep") - :regex "(^|[^\\w.])module\\s+(\\w*::)*JJJ($|[^\\w|:])" - :tests ("module test" - "module Foo::test")) - - (:language "ruby" :type "function" - :supports ("ag" "rg" "git-grep") - :regex "(^|\\W)alias(_method)?\\W+JJJ(\\W|$)" - :tests ("alias test some_method" - "alias_method :test, :some_method" - "alias_method 'test' 'some_method'" - "some_class.send(:alias_method, :test, :some_method)") - :not ("alias some_method test" - "alias_method :some_method, :test" - "alias test_foo test")) - - ;;-- Groovy - (:language "groovy" :type "variable" - :supports ("ag" "rg" "git-grep") - :regex "^\\s*((\\w+[.])*\\w+,\\s*)*JJJ(,\\s*(\\w+[.])*\\w+)*\\s*=([^=>~]|$)" - :tests ("test = 1234" - "self.foo, test, bar = args") - :not ("if test == 1234" - "foo_test = 1234")) - - (:language "groovy" :type "function" - :supports ("ag" "rg" "git-grep") - :regex "(^|[^\\w.])((private|public)\\s+)?def\\s+(\\w+(::|[.]))*JJJ($|[^\\w|:])" - :tests ("def test(foo)" - "def test()" - "def test foo" - "def test; end" - "def self.test()" - "def MODULE::test()" - "private def test") - :not ("def test_foo")) - - (:language "groovy" :type "type" - :supports ("ag" "rg" "git-grep") - :regex "(^|[^\\w.])class\\s+(\\w*::)*JJJ($|[^\\w|:])" - :tests ("class test" - "class Foo::test")) - - ;;-- crystal - (:language "crystal" :type "variable" - :supports ("ag" "rg" "git-grep") - :regex "^\\s*((\\w+[.])*\\w+,\\s*)*JJJ(,\\s*(\\w+[.])*\\w+)*\\s*=([^=>~]|$)" - :tests ("test = 1234" - "self.foo, test, bar = args") - :not ("if test == 1234" - "foo_test = 1234")) - - (:language "crystal" :type "function" - :supports ("ag" "rg" "git-grep") - :regex "(^|[^\\w.])((private|public|protected)\\s+)?def\\s+(\\w+(::|[.]))*JJJ($|[^\\w|:])" - :tests ("def test(foo)" - "def test()" - "def test foo" - "def test; end" - "def self.test()" - "def MODULE::test()" - "private def test") - :not ("def test_foo")) - - (:language "crystal" :type "type" - :supports ("ag" "rg" "git-grep") - :regex "(^|[^\\w.])class\\s+(\\w*::)*JJJ($|[^\\w|:])" - :tests ("class test" - "class Foo::test")) - - (:language "crystal" :type "type" - :supports ("ag" "rg" "git-grep") - :regex "(^|[^\\w.])module\\s+(\\w*::)*JJJ($|[^\\w|:])" - :tests ("module test" - "module Foo::test")) - - (:language "crystal" :type "type" - :supports ("ag" "rg" "git-grep") - :regex "(^|[^\\w.])struct\\s+(\\w*::)*JJJ($|[^\\w|:])" - :tests ("struct test" - "struct Foo::test")) - - (:language "crystal" :type "type" - :supports ("ag" "rg" "git-grep") - :regex "(^|[^\\w.])alias\\s+(\\w*::)*JJJ($|[^\\w|:])" - :tests ("alias test" - "alias Foo::test")) - - ;;-- scad - (:language "scad" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*\\bJJJ\\s*=[^=\\n]+" - :tests ("test = 1234") - :not ("if test == 1234 {")) - - (:language "scad" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "function\\s*JJJ\\s*\\\(" - :tests ("function test()" - "function test ()")) - - (:language "scad" :type "module" - :supports ("ag" "grep" "rg" "git-grep") - :regex "module\\s*JJJ\\s*\\\(" - :tests ("module test()" - "module test ()")) - - ;;-- scala - (:language "scala" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bval\\s*JJJ\\s*=[^=\\n]+" - :tests ("val test = 1234") - :not ("case test => 1234")) - - (:language "scala" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bvar\\s*JJJ\\s*=[^=\\n]+" - :tests ("var test = 1234") - :not ("case test => 1234")) - - (:language "scala" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\btype\\s*JJJ\\s*=[^=\\n]+" - :tests ("type test = 1234") - :not ("case test => 1234")) - - (:language "scala" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bdef\\s*JJJ\\s*\\\(" - :tests ("def test(asdf)" "def test()")) - - (:language "scala" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "class\\s*JJJ\\s*\\\(?" - :tests ("class test(object)")) - - (:language "scala" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "trait\\s*JJJ\\s*\\\(?" - :tests ("trait test(object)")) - - (:language "scala" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "object\\s*JJJ\\s*\\\(?" - :tests ("object test(object)")) - - ;;-- solidity - (:language "solidity" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "function\\s*JJJ\\s*\\\(" - :tests ("function test() internal" - "function test (uint x, address y)" - "function test() external")) - - (:language "solidity" :type "modifier" - :supports ("ag" "grep" "rg" "git-grep") - :regex "modifier\\s*JJJ\\s*\\\(" - :tests ("modifier test()" - "modifier test ()")) - - (:language "solidity" :type "event" - :supports ("ag" "grep" "rg" "git-grep") - :regex "event\\s*JJJ\\s*\\\(" - :tests ("event test();" - "event test (uint indexed x)" - "event test(uint x, address y)")) - - (:language "solidity" :type "error" - :supports ("ag" "grep" "rg" "git-grep") - :regex "error\\s*JJJ\\s*\\\(" - :tests ("error test();" - "error test (uint x)" - "error test(uint x, address y)")) - - (:language "solidity" :type "contract" - :supports ("ag" "grep" "rg" "git-grep") - :regex "contract\\s*JJJ\\s*(is|\\\{)" - :tests ("contract test{" - "contract test {" - "contract test is foo")) - - (:language "solidity" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "struct\\s*JJJ\\s*\\\{" - :tests ("struct test{" - "struct test {")) - - ;;-- R - (:language "r" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bJJJ\\s*=[^=><]" - :tests ("test = 1234") - :not ("if (test == 1234)")) - - (:language "r" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bJJJ\\s*<-\\s*function\\b" - :tests ("test <- function" - "test <- function(") - :not ("test <- functionX")) - - ;;-- perl - (:language "perl" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "sub\\s*JJJ\\s*(\\{|\\()" - :tests ("sub test{" - "sub test {" - "sub test(" "sub test (")) - - (:language "perl" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "JJJ\\s*=\\s*" - :tests ("$test = 1234")) - - ;;-- Tcl - (:language "tcl" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "proc\\s+JJJ\\s*\\{" - :tests ("proc test{" "proc test {")) - - (:language "tcl" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "set\\s+JJJ" - :tests ("set test 1234")) - - (:language "tcl" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(variable|global)\\s+JJJ" - :tests ("variable test" "global test")) - - ;;-- shell - (:language "shell" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "function\\s*JJJ\\s*" - :tests ("function test{" - "function test {" - "function test () {") - :not ("function nottest {")) - - (:language "shell" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "JJJ\\\(\\\)\\s*\\{" - :tests ("test() {") - :not ("testx() {")) - - (:language "shell" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bJJJ\\s*=\\s*" - :tests ("test = 1234") - :not ("blahtest = 1234")) - - ;;-- php - (:language "php" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "function\\s*JJJ\\s*\\\(" - :tests ("function test()" - "function test ()")) - - (:language "php" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\*\\s@method\\s+[^ \t]+\\s+JJJ\\(" - :tests ("/** @method string|false test($a)" - " * @method bool test()")) - - (:language "php" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(\\s|->|\\$|::)JJJ\\s*=\\s*" - :tests ("$test = 1234" - "$foo->test = 1234")) - - (:language "php" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\*\\s@property(-read|-write)?\\s+([^ \t]+\\s+)&?\\$JJJ(\\s+|$)" - :tests ("/** @property string $test" - "/** @property string $test description for $test property" - " * @property-read bool|bool $test" - " * @property-write \\ArrayObject<string,resource[]> $test")) - - (:language "php" :type "trait" - :supports ("ag" "grep" "rg" "git-grep") - :regex "trait\\s*JJJ\\s*\\\{" - :tests ("trait test{" - "trait test {")) - - (:language "php" :type "interface" - :supports ("ag" "grep" "rg" "git-grep") - :regex "interface\\s*JJJ\\s*(extends|\\\{)" - :tests ("interface test{" - "interface test {") - "interface test extends test2") - - (:language "php" :type "class" - :supports ("ag" "grep" "rg" "git-grep") - :regex "class\\s*JJJ\\s*(extends|implements|\\\{)" - :tests ("class test{" - "class test {" - "class test extends foo" - "class test implements foo")) - - ;; PHP 8.1+ enum definition - (:language "php" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\benum\\s+JJJ\\b\\s*(:\\s*(int|string))?\\s*(implements[^{]+)?\\{" - :tests ("enum test {" - "enum test: int {" - "enum test: string {" - "enum test implements Stringable {" - "enum test: int implements JsonSerializable {") - :not ("// enum test" "$enum = 'test'")) - - ;; PHP 8.1+ enum case - (:language "php" :type "constant" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^\\s*case\\s+JJJ\\s*(;|=)" - :tests (" case test;" - "case test = 1;" - "case test = 'value';") - :not ("case 'test':" "case \"test\":" "default:")) - - ;; PHP abstract class - (:language "php" :type "class" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\babstract\\s+class\\s+JJJ\\s*(extends|implements|\\\{)" - :tests ("abstract class test {" - "abstract class test extends Base {" - "abstract class test implements Foo {") - :not ("// abstract class test")) - - ;; PHP final class (including final readonly) - (:language "php" :type "class" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bfinal\\s+(readonly\\s+)?class\\s+JJJ\\s*(extends|implements|\\\{)" - :tests ("final class test {" - "final readonly class test {" - "final class test extends Base {") - :not ("// final class test")) - - ;; PHP readonly class (including readonly final) - (:language "php" :type "class" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\breadonly\\s+(final\\s+)?class\\s+JJJ\\s*(extends|implements|\\\{)" - :tests ("readonly class test {" - "readonly final class test {" - "readonly class test implements Serializable {") - :not ("// readonly class test")) - - ;; PHP class constant with optional visibility/final - (:language "php" :type "constant" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(final\\s+)?(public|protected|private)?\\s*const\\s+JJJ\\s*=" - :tests ("const test = 'value';" - "public const test = 100;" - "private const test = 'secret';" - "protected const test = [];" - "final public const test = 42;" - "final const test = true;") - :not ("$const = 'test'" "// const test")) - - ;; PHP global const (outside class) - (:language "php" :type "constant" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^const\\s+JJJ\\s*=" - :tests ("const test = 'app_name';" - "const test = 42;" - "const test = [];") - :not (" const test =" "public const test =")) - - ;; PHP define() function - (:language "php" :type "constant" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^\\s*define\\s*\\(\\s*['\"]JJJ['\"]" - :tests ("define('test', 100);" - "define(\"test\", 'value');" - "define('test',") - :not ("// define('test'" "$define = 'test'")) - - ;; PHP typed property declaration - (:language "php" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(public|protected|private)\\s+(static\\s+)?(readonly\\s+)?\\??[A-Za-z_][A-Za-z0-9_\\\\|&]*\\s+\\$JJJ\\s*(;|=|,)" - :tests ("public int $test;" - "private string $test = '';" - "protected ?array $test = null;" - "public readonly string $test;" - "private static int $test = 0;" - "public DateTime $test;") - :not ("public function foo(int $test)" "return $test;")) - - ;; PHP static property (without explicit type) - (:language "php" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(public|protected|private)?\\s*static\\s+\\$JJJ\\s*(;|=)" - :tests ("static $test;" - "public static $test = [];" - "private static $test = null;") - :not ("static function test()" "static::$test")) - - ;; PHP namespace declaration - (:language "php" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bnamespace\\s+([A-Za-z_][A-Za-z0-9_]*\\\\)*JJJ\\s*[;{]" - :tests ("namespace test;" - "namespace App\\test;" - "namespace App\\Services\\test {") - :not ("// namespace test" "use App\\test;")) - - ;; PHP use statement for class imports - (:language "php" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\buse\\s+([A-Za-z_][A-Za-z0-9_]*\\\\)*JJJ\\s*(;|,|\\s+as\\s+)" - :tests ("use test;" - "use App\\test;" - "use App\\Models\\test as TestModel;" - "use App\\test, App\\Other;") - :not ("use function test;" "use const test;")) - - ;;-- dart - (:language "dart" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bJJJ\\s*\\([^()]*\\)\\s*[{]" - :tests ("test(foo) {" - "test (foo){" - "test(foo){")) - - (:language "dart" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "class\\s*JJJ\\s*[\\\(\\\{]" - :tests ("class test(object) {" - "class test{")) - - ;;-- dlang - (:language "dlang" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^[[:space:]]*([][[:alnum:]_!.*<>]+[[:space:]]+)+JJJ[[:space:]]*\\\([^;{}]*\\\)([[:space:]]+@?[[:alnum:]_]+)*[[:space:]]*[{]" - :tests ("void test() {" - "public static int test(int value) {" - "auto test(T)(T value) {" - "void test() pure {" - "void test() @safe {") - :not ("return test();" - "auto value = test(arg);" - "test();")) - - (:language "dlang" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*\\bJJJ\\s*=[^=\\n)]+" - :tests ("int test = 1234;" - "immutable test = 1;" - "auto test = foo();") - :not ("if (test == 1234)" - "int nottest = 44;")) - - (:language "dlang" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(class|interface|struct|union|enum|alias)\\s+JJJ\\b" - :tests ("class test {" - "struct test {" - "alias test = int;") - :not ("class testnot {" - "alias nottest = test;")) - - ;;-- faust - (:language "faust" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bJJJ\(\\\(.+\\\)\)*\\s*=" - :tests ("test = osc + 0.5;" - "test(freq) = osc(freq) + 0.5;")) - - ;;-- fennel - (:language "fennel" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\((local|var)\\s+JJJ\\j" - :tests ("(local test (foo)" - "(var test (foo)")) - - (:language "fennel" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\(fn\\s+JJJ\\j" - :tests ("(fn test [foo]") - :not ("(fn test? [foo]")) - - (:language "fennel" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\(macro\\s+JJJ\\j" - :tests ("(macro test [foo]")) - - ;;-- fortran - (:language "fortran" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*\\bJJJ\\s*=[^=\\n]+" - :tests ("test = 1234") - :not ("if (test == 1234)")) - - (:language "fortran" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\b(function|subroutine|FUNCTION|SUBROUTINE)\\s+JJJ\\b\\s*\\\(" - :tests ("function test (foo)" - "integer function test(foo)" - "subroutine test (foo, bar)" - "FUNCTION test (foo)" - "INTEGER FUNCTION test(foo)" - "SUBROUTINE test (foo, bar)") - :not ("end function test" - "end subroutine test" - "END FUNCTION test" - "END SUBROUTINE test")) - - (:language "fortran" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^\\s*(interface|INTERFACE)\\s+JJJ\\b" - :tests ("interface test" - "INTERFACE test") - :not ("interface test2" - "end interface test" - "INTERFACE test2" - "END INTERFACE test")) - - (:language "fortran" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^\\s*(module|MODULE)\\s+JJJ\\s*" - :tests ("module test" - "MODULE test") - :not ("end module test" - "END MODULE test")) - - ;;-- go - (:language "go" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*\\bJJJ\\s*=[^=\\n]+" - :tests ("test = 1234") - :not ("if test == 1234 {")) - - (:language "go" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*\\bJJJ\\s*:=\\s*" - :tests ("test := 1234")) - - (:language "go" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "func\\s+\\\([^\\\)]*\\\)\\s+JJJ\\s*\\\(" - :tests ("func (s *blah) test(filename string) string {")) - - (:language "go" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "func\\s+JJJ\\s*\\\(" - :tests ("func test(url string) (string, error)")) - - (:language "go" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "type\\s+JJJ\\s+struct\\s+\\\{" - :tests ("type test struct {")) - - (:language "go" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "type\\s+JJJ(\\\[[^]]+\\\])?\\s+interface\\s*\\\{" - :tests ("type test interface {" - "type test[T comparable] interface {") - :not ("type testnot interface {")) - - (:language "go" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "type\\s+JJJ(\\\[[^]]+\\\])?\\s+" - :tests ("type test int" - "type test[T any] []byte" - "type test = string" - "type test []byte" - "type test string") - :not ("type testnot int")) - - ;;-- javascript extended - (:language "javascript" :tags ("angular") :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(service|factory)\\\(['\"]JJJ['\"]" - :tests ("module.factory('test', [\"$rootScope\", function($rootScope) {")) - - (:language "javascript" :tags ("es6") :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bJJJ\\s*[=:]\\s*\\\([^\\\)]*\\\)\\s+=>" - :tests ("const test = (foo) => " "test: (foo) => {" " test: (foo) => {")) - - (:language "javascript" :tags ("es6") :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bJJJ\\s*\\([^()]*\\)\\s*[{]" - :tests ("test(foo) {" "test (foo){" "test(foo){") - :not ("test = blah.then(function(){")) - - (:language "javascript" :tags ("es6") :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "class\\s*JJJ\\s*[\\\(\\\{]" - :tests ("class test(object) {" "class test{")) - - (:language "javascript" :tags ("es6") :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "class\\s*JJJ\\s+extends" - :tests ("class test extends Component{")) - - ;;-- javascript - (:language "javascript" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*\\bJJJ\\s*=[^=\\n]+" - :tests ("test = 1234" - "const test = props =>") - :not ("if (test === 1234)")) - - (:language "javascript" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bfunction\\b[^\\(]*\\\(\\s*[^\\)]*\\bJJJ\\b\\s*,?\\s*\\\)?" - :tests ("function (test)" - "function (test, blah)" - "function somefunc(test, blah) {" - "function(blah, test)") - :not ("function (testLen)" - "function (test1, blah)" - "function somefunc(testFirst, blah) {" - "function(blah, testLast)" - "function (Lentest)" - "function (blahtest, blah)" - "function somefunc(Firsttest, blah) {" - "function(blah, Lasttest)")) - - (:language "javascript" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "function\\s*JJJ\\s*\\\(" - :tests ("function test()" - "function test ()")) - - (:language "javascript" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bJJJ\\s*:\\s*function\\s*\\\(" - :tests ("test: function()")) - - (:language "javascript" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bJJJ\\s*=\\s*function\\s*\\\(" - :tests ("test = function()")) - - ;;-- hcl terraform - (:language "hcl" :type "block" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(variable|output|module)\\s*\"JJJ\"\\s*\\\{" - :tests ("variable \"test\" {" - "output \"test\" {" - "module \"test\" {")) - - (:language "hcl" :type "block" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(data|resource)\\s*\"\\w+\"\\s*\"JJJ\"\\s*\\\{" - :tests ("data \"openstack_images_image_v2\" \"test\" {" - "resource \"google_compute_instance\" \"test\" {")) - - ;;-- typescript - (:language "typescript" :tags ("angular") :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(service|factory)\\\(['\"]JJJ['\"]" - :tests ("module.factory('test', [\"$rootScope\", function($rootScope) {")) - - (:language "typescript" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bJJJ\\s*[=:]\\s*\\\([^\\\)]*\\\)\\s+=>" - :tests ("const test = (foo) => " - "test: (foo) => {" - " test: (foo) => {")) - - (:language "typescript" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bJJJ\\s*\\([^()]*\\)\\s*[{]" - :tests ("test(foo) {" - "test (foo){" - "test(foo){") - :not ("test = blah.then(function(){")) - - (:language "typescript" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "class\\s*JJJ(\\s*<[^>]*>)?\\s*[\\\(\\\{]" - :tests ("class test{" - "class test<T>{")) - - (:language "typescript" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "class\\s*JJJ(\\s*<[^>]*>)?\\s+extends" - :tests ("class test extends Component{" - "class test<T> extends Component{")) - - (:language "typescript" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "class\\s*JJJ(\\s*<[^>]*>)?\\s*[\\\(\\\{]" - :tests ("class test{" - "class test<T>{")) - - (:language "typescript" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "class\\s*JJJ(\\s*<[^>]*>)?\\s+extends" - :tests ("class test extends Component{" - "class test<T> extends Component{")) - - (:language "typescript" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(export\\s+)?interface\\s+JJJ\\b" - :tests ("interface test{" - "interface test extends Thing{" - "export interface test{") - :not ("interface testnot{")) - - (:language "typescript" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(export\\s+)?type\\s+JJJ\\b" - :tests ("type test = number" - "type test<T> = T" - "export type test = number") - :not ("type testnot = number")) - - (:language "typescript" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(export\\s+)?enum\\s+JJJ\\b" - :tests ("enum test{" - "export enum test{") - :not ("enum testnot{")) - - (:language "typescript" :type "module" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(declare\\s+)?namespace\\s+JJJ\\b" - :tests ("declare namespace test" - "namespace test") - :not ("declare testnot")) - - (:language "typescript" :type "module" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(export\\s+)?module\\s+JJJ\\b" - :tests ("export module test" - "module test") - :not ("module testnot")) - - (:language "typescript" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "function\\s*JJJ\\s*\\\(" - :tests ("function test()" - "function test ()")) - - (:language "typescript" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bJJJ\\s*:\\s*function\\s*\\\(" - :tests ("test: function()")) - - (:language "typescript" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bJJJ\\s*=\\s*function\\s*\\\(" - :tests ("test = function()")) - - (:language "typescript" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*\\bJJJ\\s*=[^=\\n]+" - :tests ("test = 1234" "const test = props =>") - :not ("if (test === 1234)")) - - (:language "typescript" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bfunction\\b[^\\(]*\\\(\\s*[^\\)]*\\bJJJ\\b\\s*,?\\s*\\\)?" - :tests ("function (test)" - "function (test, blah)" - "function somefunc(test, blah) {" - "function(blah, test)") - :not ("function (testLen)" - "function (test1, blah)" - "function somefunc(testFirst, blah) {" - "function(blah, testLast)" - "function (Lentest)" - "function (blahtest, blah)" - "function somefunc(Firsttest, blah) {" - "function(blah, Lasttest)")) - - ;;-- julia - (:language "julia" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(@noinline|@inline)?\\s*function\\s*JJJ(\\{[^\\}]*\\})?\\(" - :tests ("function test()" - "@inline function test()" - "function test{T}(h)")) - - (:language "julia" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(@noinline|@inline)?JJJ(\\{[^\\}]*\\})?\\([^\\)]*\\)\s*=" - :tests ("test(a)=1" - "test(a,b)=1*8" - "@noinline test()=1" - "test{T}(x)=x")) - - (:language "julia" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "macro\\s*JJJ\\(" - :tests ("macro test(a)=1" - " macro test(a,b)=1*8")) - - (:language "julia" :type "variable" - :supports ("ag" "rg") - :regex "const\\s+JJJ\\b" - :tests ("const test = ")) - - (:language "julia" :type "type" - :supports ("ag" "rg") - :regex "(mutable)?\\s*struct\\s*JJJ" - :tests ("struct test")) - - (:language "julia" :type "type" - :supports ("ag" "rg") - :regex "(type|immutable|abstract)\\s*JJJ" - :tests ("type test" - "immutable test" - "abstract test <:Testable" )) - - ;;-- haskell - (:language "haskell" :type "module" - :supports ("ag" "rg" "grep" "git-grep") - :regex "^module\\s+JJJ\\s+" - :tests ("module test (exportA, exportB) where") - :not ("-- module test" "import test")) - - ; TODO Doesn't support any '=' in arguments. E.g. 'foo A{a = b,..} = bar'. - (:language "haskell" :type "top level function" - :supports ("ag" "rg") - :regex "^\\bJJJ(?!(\\s+::))\\s+((.|\\s)*?)=\\s+" - :tests ("test n = n * 2" - "test X{..} (Y a b c) \n bcd \n =\n x * y" - "test ab cd e@Datatype {..} (Another thing, inTheRow) = \n undefined" - "test = runRealBasedMode @ext @ctx identity identity" - "test unwrap wrap nr@Naoeu {..} (Action action, specSpecs) = \n undefined") - :not ("nottest n = n * 2" - "let testnot x y = x * y" - "test $ y z" - "let test a o = mda" - "test :: Sometype -> AnotherType aoeu kek = undefined")) - - (:language "haskell" :type "type-like" - :supports ("ag" "rg" "grep" "git-grep") - :regex "^\\s*((data(\\s+family)?)|(newtype)|(type(\\s+family)?))\\s+JJJ\\s+" - :tests ("newtype test a = Something { b :: Kek }" - "data test a b = Somecase a | Othercase b" - "type family test (x :: *) (xs :: [*]) :: Nat where" - "data family test " - "type test = TestAlias") - :not ("newtype nottest a = nottest (Not a)" - "data testnot b = Aoeu")) - - ; datatype contstuctor that doesn't match type definition. - (:language "haskell" :type "(data)type constructor 1" - :supports ("ag" "rg") - :regex "(data|newtype)\\s{1,3}(?!JJJ\\s+)([^=]{1,40})=((\\s{0,3}JJJ\\s+)|([^=]{0,500}?((?<!(-- ))\\|\\s{0,3}JJJ\\s+)))" - :tests ("data Something a = test { b :: Kek }" - "data Mem a = TrueMem { b :: Kek } | test (Mem Int) deriving Mda" - "newtype SafeTest a = test (Kek a) deriving (YonedaEmbedding)") - :not ("data test = test { b :: Kek }")) - - - (:language "haskell" :type "data/newtype record field" - :supports ("ag" "rg") - :regex "(data|newtype)([^=]*)=[^=]*?({([^=}]*?)(\\bJJJ)\\s+::[^=}]+})" - :tests ("data Mem = Mem { \n mda :: A \n , test :: Kek \n , \n aoeu :: E \n }" - "data Mem = Mem { \n test :: A \n , mda :: Kek \n , \n aoeu :: E \n }" - "data Mem = Mem { \n mda :: A \n , aoeu :: Kek \n , \n test :: E \n }" - "data Mem = Mem { test :: Kek } deriving Mda" - "data Mem = Mem { \n test :: Kek \n } deriving Mda" - "newtype Mem = Mem { \n test :: Kek \n } deriving (Eq)" - "newtype Mem = Mem { -- | Some docs \n test :: Kek -- ^ More docs } deriving Eq" - "newtype Mem = Mem { test :: Kek } deriving (Eq,Monad)" - "newtype NewMem = OldMem { test :: [Tx] }" - "newtype BlockHeaderList ssc = BHL\n { test :: ([Aoeu a], [Ssss])\n } deriving (Eq)") - :not ("data Heh = Mda { sometest :: Kek, testsome :: Mem }")) - - (:language "haskell" :type "typeclass" - :supports ("ag" "rg" "grep" "git-grep") - :regex "^class\\s+(.+=>\\s*)?JJJ\\s+" - :tests ( - "class (Constr1 m, Constr 2) => test (Kek a) where" - "class test (Veryovka a) where ") - :not ("class test2 (Kek a) where" - "class maketest (AoeuTest x y z) where")) - - ;;-- ocaml - (:language "ocaml" :type "type" - :supports ("ag" "rg" "grep" "git-grep") - :regex "^\\s*(and|type)\\s+.*\\bJJJ\\b" - :tests ("type test =" - "and test =" - "type 'a test =" - "type ('a, _, 'c) test")) - - (:language "ocaml" :type "variable" - :supports ("ag" "rg" "grep" "git-grep") - :regex "let\\s+JJJ\\b" - :tests ("let test =" - "let test x y =")) - - (:language "ocaml" :type "variable" - :supports ("ag" "rg" "grep" "git-grep") - :regex "let\\s+rec\\s+JJJ\\b" - :tests ("let rec test =" - "let rec test x y =")) - - (:language "ocaml" :type "variable" - :supports ("ag" "rg" "grep" "git-grep") - :regex "\\s*val\\s*\\bJJJ\\b\\s*" - :tests ("val test")) - - (:language "ocaml" :type "module" - :supports ("ag" "rg" "grep" "git-grep") - :regex "^\\s*module\\s*\\bJJJ\\b" - :tests ("module test =")) - - (:language "ocaml" :type "module" - :supports ("ag" "rg" "grep" "git-grep") - :regex "^\\s*module\\s*type\\s*\\bJJJ\\b" - :tests ("module type test =")) - - ;;-- purescript - (:language "purescript" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^\\s*\\bJJJ\\b\\s+(::|[^=]*\\s=[^=])" - :tests ("test :: Int -> String" - "test :: Number -> Number -> Number" - " test :: Int -> String" - "test x y = x + y" - "test (Just x) = x" - "test { x } = x") - :not ("nottest :: Int -> String" - "testing x = 1" - "test x == y" - "test >>= bar")) - - (:language "purescript" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^\\s*\\bJJJ\\s*=[^=]" - :tests ("test = 42" - "test = \\x -> x + 1" - " test = compute x") - :not ("test == 42" - "-- test = 42")) - - (:language "purescript" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\blet\\s+JJJ\\s*(\\::|=[^=])" - :tests ("let test = 42" - "let test :: Int") - :not ("let testing = 42" - "let test == 42")) - - (:language "purescript" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^\\s*(type|newtype|data)\\s+JJJ\\b" - :tests ("type test = Int" - "newtype test = test Int" - "data test = test Int | Other String") - :not ("type testOther = Int" - "data testOther = testOther Int")) - - ;; lua - (:language "lua" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*\\bJJJ\\s*=[^=\\n]+" - :tests ("test = 1234") - :not ("if test === 1234")) - - (:language "lua" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bfunction\\b[^\\(]*\\\(\\s*[^\\)]*\\bJJJ\\b\\s*,?\\s*\\\)?" - :tests ("function (test)" - "function (test, blah)" - "function somefunc(test, blah)" - "function(blah, test)") - :not ("function (testLen)" - "function (test1, blah)" - "function somefunc(testFirst, blah)" - "function(blah, testLast)" - "function (Lentest)" - "function (blahtest, blah)" - "function somefunc(Firsttest, blah)" - "function(blah, Lasttest)")) - - (:language "lua" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "function\\s*JJJ\\s*\\\(" - :tests ("function test()" "function test ()")) - - (:language "lua" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "function\\s*.+[.:]JJJ\\s*\\\(" - :tests ("function MyClass.test()" - "function MyClass.test ()" - "function MyClass:test()" - "function MyClass:test ()")) - - (:language "lua" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bJJJ\\s*=\\s*function\\s*\\\(" - :tests ("test = function()")) - - (:language "lua" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\b.+\\.JJJ\\s*=\\s*function\\s*\\\(" - :tests ("MyClass.test = function()")) - - ;;-- rust - (:language "rust" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\blet\\s+(\\\([^=\\n]*)?(mut\s+)?JJJ([^=\\n]*\\\))?(:\\s*[^=\\n]+)?\\s*=\\s*[^=\\n]+" - :tests ("let test = 1234;" - "let test: u32 = 1234;" - "let test: Vec<u32> = Vec::new();" - "let mut test = 1234;" - "let mut test: Vec<u32> = Vec::new();" - "let (a, test, b) = (1, 2, 3);" - "let (a, mut test, mut b) = (1, 2, 3);" - "let (mut a, mut test): (u32, usize) = (1, 2);")) - - (:language "rust" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bconst\\s+JJJ:\\s*[^=\\n]+\\s*=[^=\\n]+" - :tests ("const test: u32 = 1234;")) - - (:language "rust" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bstatic\\s+(mut\\s+)?JJJ:\\s*[^=\\n]+\\s*=[^=\\n]+" - :tests ("static test: u32 = 1234;" - "static mut test: u32 = 1234;")) - - ;; variable in method signature - (:language "rust" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bfn\\s+.+\\s*\\\((.+,\\s+)?JJJ:\\s*[^=\\n]+\\s*(,\\s*.+)*\\\)" - :tests ("fn abc(test: u32) -> u32 {" - "fn abc(x: u32, y: u32, test: Vec<u32>, z: Vec<Foo>)" - "fn abc(x: u32, y: u32, test: &mut Vec<u32>, z: Vec<Foo>)")) - - ;; "if let" and "while let" desugaring - (:language "rust" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(if|while)\\s+let\\s+([^=\\n]+)?(mut\\s+)?JJJ([^=\\n\\\(]+)?\\s*=\\s*[^=\\n]+" - :tests ("if let Some(test) = abc() {" - "if let Some(mut test) = abc() {" - "if let Ok(test) = abc() {" - "if let Ok(mut test) = abc() {" - "if let Foo(mut test) = foo {" - "if let test = abc() {" - "if let Some(test) = abc()" - "if let Some((a, test, b)) = abc()" - "while let Some(test) = abc() {" - "while let Some(mut test) = abc() {" - "while let Ok(test) = abc() {" - "while let Ok(mut test) = abc() {") - :not ("while let test(foo) = abc() {")) - - ;; structure fields - (:language "rust" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "struct\\s+[^\\n{]+[{][^}]*(\\s*JJJ\\s*:\\s*[^\\n},]+)[^}]*}" - :tests ("struct Foo { abc: u32, test: Vec<String>, b: PathBuf }" - "struct Foo<T>{test:Vec<T>}" - "struct FooBar<'a> { test: Vec<String> }") - :not ("struct Foo { abc: u32, b: Vec<String> }" - "/// ... construct the equivalent ...\nfn abc() {\n")) - - ;; enum variants - (:language "rust" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "enum\\s+[^\\n{]+\\s*[{][^}]*\\bJJJ\\b[^}]*}" - :tests ("enum Foo { VariantA, test, VariantB(u32) }" - "enum Foo<T> { test(T) }" - "enum BadStyle{test}" - "enum Foo32 { Bar, testing, test(u8) }") - :not ("enum Foo { testing }")) - - (:language "rust" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bfn\\s+JJJ\\s*\\\(" - :tests ("fn test(asdf: u32)" - "fn test()" - "pub fn test()")) - - (:language "rust" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bmacro_rules!\\s+JJJ" - :tests ("macro_rules! test")) - - (:language "rust" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "struct\\s+JJJ\\s*[{\\\(]?" - :tests ("struct test(u32, u32)" - "struct test;" - "struct test { abc: u32, def: Vec<String> }")) - - (:language "rust" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "trait\\s+JJJ\\s*[{]?" - :tests ("trait test;" "trait test { fn abc() -> u32; }")) - - (:language "rust" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\btype\\s+JJJ([^=\\n]+)?\\s*=[^=\\n]+;" - :tests ("type test<T> = Rc<RefCell<T>>;" - "type test = Arc<RwLock<Vec<u32>>>;")) - - (:language "rust" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "impl\\s+((\\w+::)*\\w+\\s+for\\s+)?(\\w+::)*JJJ\\s+[{]?" - :tests ("impl test {" - "impl abc::test {" - "impl std::io::Read for test {" - "impl std::io::Read for abc::test {")) - - (:language "rust" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "mod\\s+JJJ\\s*[{]?" - :tests ("mod test;" "pub mod test {")) - - ;; enum definitions - (:language "rust" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\benum\\s+JJJ\\b\\s*[{]?" - :tests ("enum test { A, B, C }" - "enum test {" - "pub enum test<T> {" - "pub enum test<T> { A, B }" - "pub enum test<T: Clone + Debug> {" - "enum test { Variant1, Variant2(Type) }" - "pub(crate) enum test { Variant }") - :not ("enum testing { A, B }" - "enum Foo { test, Bar }")) - - ;;-- elixir - (:language "elixir" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bdef(p)?\\s+JJJ\\s*[ ,\\\(]" - :tests ("def test do" - "def test, do:" - "def test() do" - "def test(), do:" - "def test(foo, bar) do" - "def test(foo, bar), do:" - "defp test do" - "defp test(), do:")) - - (:language "elixir" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*JJJ\\s*=[^=\\n]+" - :tests ("test = 1234") - :not ("if test == 1234")) - - (:language "elixir" :type "module" - :supports ("ag" "grep" "rg" "git-grep") - :regex "defmodule\\s+(\\w+\\.)*JJJ\\s+" - :tests ("defmodule test do" - "defmodule Foo.Bar.test do")) - - (:language "elixir" :type "module" - :supports ("ag" "grep" "rg" "git-grep") - :regex "defprotocol\\s+(\\w+\\.)*JJJ\\s+" - :tests ("defprotocol test do" - "defprotocol Foo.Bar.test do")) - - ;;-- erlang - (:language "erlang" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^JJJ\\b\\s*\\\(" - :tests ("test() ->" - "test()->" - "test(Foo) ->" - "test (Foo,Bar) ->" - "test(Foo, Bar)->")) - - (:language "erlang" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*JJJ\\s*=[^:=\\n]+" - :tests ("test = 1234") - :not ("if test =:= 1234" - "if test == 1234")) - - (:language "erlang" :type "module" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^-module\\\(JJJ\\\)" - :tests ("-module(test).")) - - ;;-- scss - (:language "scss" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "@mixin\\sJJJ\\b\\s*\\\(" - :tests ("@mixin test()")) - - (:language "scss" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "@function\\sJJJ\\b\\s*\\\(" - :tests ("@function test()")) - - (:language "scss" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "JJJ\\s*:\\s*" - :tests ("test :")) - - ;;-- sml - (:language "sml" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*(data)?type\\s+.*\\bJJJ\\b" - :tests ("datatype test =" - "datatype test=" - "datatype 'a test =" - "type test =" - "type 'a test =" - "type 'a test" - "type test") - :not ("datatypetest =")) - - (:language "sml" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*val\\s+\\bJJJ\\b" - :tests ("val test =" - "val test=" - "val test : bool")) - - (:language "sml" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*fun\\s+\\bJJJ\\b.*\\s*=" - :tests ("fun test list =" - "fun test (STRING_NIL, a) =" - "fun test ((s1,s2): 'a queue) : 'a * 'a queue =" - "fun test (var : q) : int =" - "fun test f e xs =")) - - (:language "sml" :type "module" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*(structure|signature|functor)\\s+\\bJJJ\\b" - :tests ("structure test =" - "structure test : MYTEST =" - "signature test =" - "functor test (T:TEST) =" - "functor test(T:TEST) =")) - - ;;-- sql - (:language "sql" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(CREATE|create)\\s+(.+?\\s+)?(FUNCTION|function|PROCEDURE|procedure)\\s+JJJ\\s*\\\(" - :tests ("CREATE FUNCTION test(i INT) RETURNS INT" - "create or replace function test (int)" - "CREATE PROCEDURE test (OUT p INT)" - "create definer = 'test'@'localhost' procedure test()")) - - (:language "sql" :type "table" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(CREATE|create)\\s+(.+?\\s+)?(TABLE|table)(\\s+(IF NOT EXISTS|if not exists))?\\s+JJJ\\b" - :tests ("CREATE TABLE test (" - "create temporary table if not exists test" - "CREATE TABLE IF NOT EXISTS test (" - "create global temporary table test")) - - (:language "sql" :type "view" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(CREATE|create)\\s+(.+?\\s+)?(VIEW|view)\\s+JJJ\\b" - :tests ("CREATE VIEW test (" - "create sql security definer view test" - "CREATE OR REPLACE VIEW test AS foo")) - - (:language "sql" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(CREATE|create)\\s+(.+?\\s+)?(TYPE|type)\\s+JJJ\\b" - :tests ("CREATE TYPE test" - "CREATE OR REPLACE TYPE test AS foo (" - "create type test as (")) - - ;;-- systemverilog - (:language "systemverilog" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*class\\s+\\bJJJ\\b" - :tests ("virtual class test;" - "class test;" - "class test extends some_class") - :not ("virtual class testing;" - "class test2;" - "class some_test" - "class some_class extends test")) - - (:language "systemverilog" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*task\\s+\\bJJJ\\b" - :tests ("task test (" - "task test(") - :not ("task testing (" - "task test2(")) - - (:language "systemverilog" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*\\bJJJ\\b\\s*=" - :tests ("assign test =" - "assign test=" - "int test =" - "int test=") - :not ("assign testing =" - "assign test2=")) - - (:language "systemverilog" :type "function" : - supports ("ag" "rg" "git-grep") - :regex "function\\s[^\\s]+\\s*\\bJJJ\\b" - :tests ("function Matrix test ;" - "function Matrix test;") - :not ("function test blah")) - - ;; matches SV class handle declarations - (:language "systemverilog" :type "function" - :supports ("ag" "rg" "git-grep") - :regex "^\\s*[^\\s]*\\s*[^\\s]+\\s+\\bJJJ\\b" - :tests ("some_class_name test" - " another_class_name test ;" - "some_class test[];" - "some_class #(1) test") - :not ("test some_class_name" - "class some_class extends test")) - - ;;-- vhdl - (:language "vhdl" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*type\\s+\\bJJJ\\b" - :tests ("type test is" - "type test is") - :not ("type testing is" - "type test2 is")) - - (:language "vhdl" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*constant\\s+\\bJJJ\\b" - :tests ("constant test :" - "constant test:") - :not ("constant testing " - "constant test2:")) - - (:language "vhdl" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "function\\s*\"?JJJ\"?\\s*\\\(" - :tests ("function test(signal)" - "function test (signal)" - "function \"test\" (signal)") - :not ("function testing(signal")) - - ;;-- latex - (:language "tex" :type "command" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\\\.*newcommand\\\*?\\s*\\\{\\s*(\\\\)JJJ\\s*}" - :tests ("\\newcommand{\\test}" - "\\renewcommand{\\test}" - "\\renewcommand*{\\test}" - "\\newcommand*{\\test}" - "\\renewcommand{ \\test }") - :not("\\test" "test")) - - (:language "tex" :type "command" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\\\.*newcommand\\\*?\\s*(\\\\)JJJ\\j" - :tests ("\\newcommand\\test {}" - "\\renewcommand\\test{}" - "\\newcommand \\test") - :not("\\test" - "test")) - - (:language "tex" :type "length" : - supports ("ag" "grep" "rg" "git-grep") - :regex "\\\\(s)etlength\\s*\\\{\\s*(\\\\)JJJ\\s*}" - :tests ("\\setlength { \\test}" - "\\setlength{\\test}" - "\\setlength{\\test}{morecommands}" ) - :not("\\test" - "test")) - - (:language "tex" :type "counter" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\\\newcounter\\\{\\s*JJJ\\s*}" - :tests ("\\newcounter{test}" ) - :not("\\test" - "test")) - - (:language "tex" :type "environment" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\\\.*newenvironment\\s*\\\{\\s*JJJ\\s*}" - :tests ("\\newenvironment{test}" - "\\newenvironment {test}{morecommands}" - "\\lstnewenvironment{test}" - "\\newenvironment {test}" ) - :not("\\test" - "test" )) - - ;;-- pascal (todo: var, type, const) - (:language "pascal" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bfunction\\s+JJJ\\b" - :tests (" function test : ")) - - (:language "pascal" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bprocedure\\s+JJJ\\b" - :tests (" procedure test ; ")) - - ;;-- f# - (:language "fsharp" :type "variable" - :supports ("ag" "rg" "grep" "git-grep") - :regex "let\\s+JJJ\\b.*\\\=" - :tests ("let test = 1234" - "let test() = 1234" - "let test abc def = 1234") - :not ("let testnot = 1234" - "let testnot() = 1234" - "let testnot abc def = 1234")) - - (:language "fsharp" :type "interface" - :supports ("ag" "rg" "grep" "git-grep") - :regex "member(\\b.+\\.|\\s+)JJJ\\b.*\\\=" - :tests ("member test = 1234" - "member this.test = 1234") - :not ("member testnot = 1234" - "member this.testnot = 1234")) - - (:language "fsharp" :type "type" - :supports ("ag" "rg" "grep" "git-grep") - :regex "type\\s+JJJ\\b.*\\\=" - :tests ("type test = 1234") - :not ("type testnot = 1234")) - - ;;-- kotlin - (:language "kotlin" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "fun\\s*(<[^>]*>)?\\s*JJJ\\s*\\(" - :tests ("fun test()" "fun <T> test()")) - - (:language "kotlin" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(val|var)\\s*JJJ\\b" - :not ("val testval" - "var testvar") - :tests ("val test " - "var test")) - - (:language "kotlin" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(class|interface)\\s*JJJ\\b" - :tests ("class test" - "class test : SomeInterface" - "interface test")) - - ;;-- zig - (:language "zig" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "fn\\s+JJJ\\b" - :tests ("fn test() void {" - "fn test(a: i32) i32 {" - "pub fn test(a: i32) i32 {" - "export fn test(a: i32) i32 {" - "extern \"c\" fn test(a: i32) i32 {" - "inline fn test(a: i32) i32 {")) - - (:language "zig" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(var|const)\\s+JJJ\\b" - :tests ("const test: i32 = 3;" - "var test: i32 = 3;" - "pub const test: i32 = 3;")) - - ;;-- protobuf - (:language "protobuf" :type "message" - :supports ("ag" "grep" "rg" "git-grep") - :regex "message\\s+JJJ\\s*\\\{" - :tests ("message test{" "message test {")) - - (:language "protobuf" :type "enum" - :supports ("ag" "grep" "rg" "git-grep") - :regex "enum\\s+JJJ\\s*\\\{" - :tests ("enum test{" "enum test {")) - - ;;-- apex (literally the same regexes as java) - (:language "apex" :type "function" - :supports ("ag" "rg") - :regex "^\\s*(?:[\\w\\[\\]]+\\s+){1,3}JJJ\\s*\\\(" - :tests ("int test()" - "int test(param)" - "static int test()" - "static int test(param)" - "public static MyType test()" - "private virtual SomeType test(param)" - "static int test()" - "private foo[] test()") - :not ("test()" "testnot()" - "blah = new test()" - "foo bar = test()")) - - (:language "apex" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*\\bJJJ\\s*=[^=\\n)]+" :tests ("int test = 1234") - :not ("if test == 1234:" "int nottest = 44")) - - (:language "apex" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "(class|interface)\\s*JJJ\\b" - :tests ("class test:" - "public class test implements Something") - :not ("class testnot:" - "public class testnot implements Something")) - - ;;-- jai - (:language "jai" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bJJJ\\s*::" - :tests ("test ::")) - (:language "jai" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bJJJ\\s*(:|:\\s*=|::)" - :tests ("test: Type" "test : Type = Val" "test :: Val")) - (:language "jai" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bJJJ\\s*::" - :tests ("test ::")) - - ;;-- odin - (:language "odin" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\s*\\bJJJ\\s*:\\s*([^=\\n]+\\s*:|:|[^=\\n]+\\s*=|=)" - :tests ("test :: struct" - "test ::enum" - "test:: union" - "test: : custom_type" - "test :: [2]f32" - "test : f32 : 20" - "test: i32 : 10" - "test := 20" - "test : f32 = 20" - "test: i32 = 10" - "test: i32= 10" - "test :i32= 10" - "test :: proc()" - "test ::proc() {" - "test:: proc(a: i32) -> i32 {" - "test::proc{}" - "test: :proc \"contextless\" {}")) - - (:language "odin" :type "function" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bJJJ\\s*:\\s*:\\s*proc\\s*[({]" - :tests ("test :: proc(a: int)" - "test ::proc()" - "test:: proc(a: i32) -> i32 {" - "test::proc{}") - :not ("testnot :: proc()" - "test: proc()")) - - (:language "odin" :type "type" - :supports ("ag" "grep" "rg" "git-grep") - :regex "\\bJJJ\\s*:\\s*:\\s*(struct|enum|union|bit_set|bit_field)\\b" - :tests ("test :: struct {" - "test :: enum {" - "test :: union {" - "test :: bit_set {" - "test :: bit_field {") - :not ("testnot :: struct {" - "test :: structure_builder")) - - ;;-- cobol - (:language "cobol" :type "variable" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^(.{6}[^*/])?\\s*([frs]d|[[:digit:]]{1,2})\\s+JJJ([\\. ]|$)" - :tests (" 01 test." - "000350 10 test pic x." - " 88 test value '10'." - "fd test." - " sd test.") - :not (" *01 test" - " 05 test-01" - " 05 testing")) - - (:language "cobol" :type "section" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^(.{6}[^*/])?JJJ(\\s+section)?\\." - :tests (" test." - " test section." - "test." - "test section.") - :not (" test." - " *test section.")) - - (:language "cobol" :type "submodule" - :supports ("ag" "grep" "rg" "git-grep") - :regex "^(.{6}[^*/])?program-id\\.\\s*[\"']?JJJ[\"']?.*\\." - :tests (" program-id. test." - " program-id. 'test'." - "program-id. \"test\".") - :not (" test."))) - - "List of search regex pattern templates organized by language and type. -Used for generating the grep tool search commands. - -For a given language, a regular expression is only used by Dumb Jump when -the currently used search tool is identified in the :supports value. - -The regex string is a template filled by `dumb-jump-populate-regex' and -should contain the \"JJJ\" string, a marker for the searched identifier. - -It may also contain the following: - -- \"\\\\j\" : a marker for word-boundary regular-expression to use instead - of \"\\\\b\" when word boundary concept must support Lisp language - family and must not include the characters '-', '?' and '*'. - In the Lisp family of programming languages a large number of - characters are allowed in identifiers, including '-', '?' and - '*'. - This marker is replaced by value of the search tool specific - dumb-jump-TOOL-word-boundary, like `dumb-jump-ag-word-boundary' for - ag. - -- \"\\\\s\" : for a single white space character. - Replaced by \"[[:space:]]\" for some search tools as identified by - `dumb-jump-use-space-bracket-exp-for' returning t for a tool variant. - -The language types supported are listed in the linked page below: -- Ag: - URL \ `https://github.com/ggreer/the_silver_searcher/blob/master/tests/list_file_types.t' -- rg: - URL \ `https://github.com/BurntSushi/ripgrep/blob/master/crates/ignore/src/default_types.rs#L12' - -More information using the search tool command line help." - :group 'dumb-jump - :type - '(repeat - (plist :options ((:language string) - (:type string) - (:supports string) - (:regex string) - (:tests (repeat string)) - (:not (repeat string)))))) - -(defcustom dumb-jump-language-file-exts - ;; dumb-jump language file extension ag type rg type - '((:language "elisp" :ext "el" :agtype "elisp" :rgtype "elisp") - (:language "elisp" :ext "el.gz" :agtype "elisp" :rgtype "elisp") - (:language "commonlisp" :ext "lisp" :agtype "lisp" :rgtype "lisp") - (:language "commonlisp" :ext "lsp" :agtype "lisp" :rgtype "lisp") - (:language "c++" :ext "c" :agtype "cc" :rgtype "c") - (:language "c++" :ext "h" :agtype "cc" :rgtype "c") - (:language "c++" :ext "C" :agtype "cpp" :rgtype "cpp") - (:language "c++" :ext "H" :agtype "cpp" :rgtype "cpp") - (:language "c++" :ext "tpp" :agtype "cpp" :rgtype nil) - (:language "c++" :ext "cpp" :agtype "cpp" :rgtype "cpp") - (:language "c++" :ext "hpp" :agtype "cpp" :rgtype "cpp") - (:language "c++" :ext "cxx" :agtype "cpp" :rgtype "cpp") - (:language "c++" :ext "hxx" :agtype "cpp" :rgtype nil) - (:language "c++" :ext "cc" :agtype "cpp" :rgtype "cpp") - (:language "c++" :ext "hh" :agtype "cpp" :rgtype "cpp") - (:language "c++" :ext "c++" :agtype nil :rgtype nil) - (:language "c++" :ext "h++" :agtype nil :rgtype nil) - (:language "c++" :ext "ino" :agtype "cpp" :rgtype nil) - (:language "coq" :ext "v" :agtype nil :rgtype nil) - (:language "ocaml" :ext "ml" :agtype "ocaml" :rgtype "ocaml") - (:language "ocaml" :ext "mli" :agtype "ocaml" :rgtype "ocaml") - (:language "ocaml" :ext "mll" :agtype "ocaml" :rgtype "ocaml") - (:language "ocaml" :ext "mly" :agtype "ocaml" :rgtype "ocaml") - ;; groovy is nil type because jenkinsfile is not in searcher type lists - (:language "groovy" :ext "gradle" :agtype nil :rgtype nil) - (:language "groovy" :ext "groovy" :agtype nil :rgtype nil) - (:language "groovy" :ext "jenkinsfile" :agtype nil :rgtype nil) - (:language "haskell" :ext "hs" :agtype "haskell" :rgtype "haskell") - (:language "haskell" :ext "lhs" :agtype "haskell" :rgtype "haskell") - (:language "objc" :ext "m" :agtype "objc" :rgtype "objc") - (:language "csharp" :ext "cs" :agtype "csharp" :rgtype "csharp") - (:language "java" :ext "java" :agtype "java" :rgtype "java") - (:language "vala" :ext "vala" :agtype "vala" :rgtype "vala") - (:language "vala" :ext "vapi" :agtype "vala" :rgtype "vala") - (:language "julia" :ext "jl" :agtype "julia" :rgtype "julia") - (:language "clojure" :ext "clj" :agtype "clojure" :rgtype "clojure") - (:language "clojure" :ext "cljc" :agtype "clojure" :rgtype "clojure") - (:language "clojure" :ext "cljs" :agtype "clojure" :rgtype "clojure") - (:language "clojure" :ext "cljx" :agtype "clojure" :rgtype "clojure") - (:language "coffeescript" :ext "coffee" :agtype "coffee" :rgtype "coffeescript") - (:language "faust" :ext "dsp" :agtype nil :rgtype nil) - (:language "faust" :ext "lib" :agtype nil :rgtype nil) - (:language "fennel" :ext "fnl" :agtype nil :rgtype nil) - (:language "fortran" :ext "F" :agtype "fortran" :rgtype "fortran") - (:language "fortran" :ext "f" :agtype "fortran" :rgtype "fortran") - (:language "fortran" :ext "f77" :agtype "fortran" :rgtype "fortran") - (:language "fortran" :ext "f90" :agtype "fortran" :rgtype "fortran") - (:language "fortran" :ext "f95" :agtype "fortran" :rgtype "fortran") - (:language "fortran" :ext "F77" :agtype "fortran" :rgtype "fortran") - (:language "fortran" :ext "F90" :agtype "fortran" :rgtype "fortran") - (:language "fortran" :ext "F95" :agtype "fortran" :rgtype "fortran") - (:language "fortran" :ext "f03" :agtype "fortran" :rgtype "fortran") - (:language "fortran" :ext "for" :agtype "fortran" :rgtype "fortran") - (:language "fortran" :ext "ftn" :agtype "fortran" :rgtype "fortran") - (:language "fortran" :ext "fpp" :agtype "fortran" :rgtype "fortran") - (:language "go" :ext "go" :agtype "go" :rgtype "go") - (:language "javascript" :ext "js" :agtype "js" :rgtype "js") - (:language "javascript" :ext "jsx" :agtype "js" :rgtype "js") - (:language "javascript" :ext "vue" :agtype "js" :rgtype "js") - (:language "javascript" :ext "html" :agtype "html" :rgtype "html") - (:language "javascript" :ext "css" :agtype "css" :rgtype "css") - (:language "typescript" :ext "ts" :agtype "ts" :rgtype "ts") - (:language "typescript" :ext "tsx" :agtype "ts" :rgtype "ts") - (:language "typescript" :ext "vue" :agtype "ts" :rgtype "ts") - (:language "dart" :ext "dart" :agtype nil :rgtype "dart") - (:language "dlang" :ext "d" :agtype "dlang" :rgtype "d") - (:language "dlang" :ext "di" :agtype "dlang" :rgtype "d") - (:language "lua" :ext "lua" :agtype "lua" :rgtype "lua") - ;; the extension "m" is also used by obj-c so must use matlab-mode - ;; since obj-c will win by file extension, but here for searcher types - (:language "matlab" :ext "m" :agtype "matlab" :rgtype "matlab") - (:language "nim" :ext "nim" :agtype "nim" :rgtype "nim") - (:language "nix" :ext "nix" :agtype "nix" :rgtype "nix") - (:language "org" :ext "org" :agtype nil :rgtype "org") - (:language "perl" :ext "pl" :agtype "perl" :rgtype "perl") - (:language "perl" :ext "pm" :agtype "perl" :rgtype "perl") - (:language "perl" :ext "pm6" :agtype "perl" :rgtype nil) - (:language "perl" :ext "perl" :agtype nil :rgtype "perl") - (:language "perl" :ext "plh" :agtype nil :rgtype "perl") - (:language "perl" :ext "plx" :agtype nil :rgtype "perl") - (:language "perl" :ext "pod" :agtype "perl" :rgtype "pod") - (:language "perl" :ext "t" :agtype "perl" :rgtype nil) - (:language "php" :ext "php" :agtype "php" :rgtype "php") - (:language "php" :ext "php3" :agtype "php" :rgtype "php") - (:language "php" :ext "php4" :agtype "php" :rgtype "php") - (:language "php" :ext "php5" :agtype "php" :rgtype "php") - (:language "php" :ext "phtml" :agtype "php" :rgtype "php") - (:language "php" :ext "inc" :agtype "php" :rgtype nil) - (:language "purescript" :ext "purs" :agtype nil :rgtype nil) - (:language "python" :ext "py" :agtype "python" :rgtype "py") - (:language "r" :ext "R" :agtype "r" :rgtype "r") - (:language "r" :ext "r" :agtype "r" :rgtype "r") - (:language "r" :ext "Rmd" :agtype "r" :rgtype "r") - (:language "r" :ext "Rnw" :agtype "r" :rgtype "r") - (:language "r" :ext "Rtex" :agtype "r" :rgtype nil) - (:language "r" :ext "Rrst" :agtype "r" :rgtype nil) - (:language "racket" :ext "rkt" :agtype "racket" :rgtype "lisp") - (:language "crystal" :ext "cr" :agtype "crystal" :rgtype "crystal") - (:language "crystal" :ext "ecr" :agtype "crystal" :rgtype nil) - (:language "ruby" :ext "rb" :agtype "ruby" :rgtype "ruby") - (:language "ruby" :ext "erb" :agtype "ruby" :rgtype nil) - (:language "ruby" :ext "haml" :agtype "ruby" :rgtype nil) - (:language "ruby" :ext "rake" :agtype "ruby" :rgtype nil) - (:language "ruby" :ext "slim" :agtype "ruby" :rgtype nil) - (:language "rust" :ext "rs" :agtype "rust" :rgtype "rust") - (:language "zig" :ext "zig" :agtype nil :rgtype "zig") - (:language "scad" :ext "scad" :agtype nil :rgtype nil) - (:language "scala" :ext "scala" :agtype "scala" :rgtype "scala") - (:language "scheme" :ext "scm" :agtype "scheme" :rgtype "lisp") - (:language "scheme" :ext "ss" :agtype "scheme" :rgtype "lisp") - (:language "scheme" :ext "sld" :agtype "scheme" :rgtype "lisp") - (:language "janet" :ext "janet" :agtype "janet" :rgtype "lisp") - (:language "shell" :ext "sh" :agtype nil :rgtype nil) - (:language "shell" :ext "bash" :agtype nil :rgtype nil) - (:language "shell" :ext "csh" :agtype nil :rgtype nil) - (:language "shell" :ext "ksh" :agtype nil :rgtype nil) - (:language "shell" :ext "tcsh" :agtype nil :rgtype nil) - (:language "sml" :ext "sml" :agtype "sml" :rgtype "sml") - (:language "solidity" :ext "sol" :agtype nil :rgtype nil) - (:language "sql" :ext "sql" :agtype "sql" :rgtype "sql") - (:language "swift" :ext "swift" :agtype nil :rgtype "swift") - (:language "tex" :ext "tex" :agtype "tex" :rgtype "tex") - (:language "elixir" :ext "ex" :agtype "elixir" :rgtype "elixir") - (:language "elixir" :ext "exs" :agtype "elixir" :rgtype "elixir") - (:language "elixir" :ext "eex" :agtype "elixir" :rgtype "elixir") - (:language "erlang" :ext "erl" :agtype "erlang" :rgtype "erlang") - (:language "systemverilog" :ext "sv" :agtype "verilog" :rgtype "verilog") - (:language "systemverilog" :ext "svh" :agtype "verilog" :rgtype "verilog") - (:language "vhdl" :ext "vhd" :agtype "vhdl" :rgtype "vhdl") - (:language "vhdl" :ext "vhdl" :agtype "vhdl" :rgtype "vhdl") - (:language "scss" :ext "scss" :agtype "css" :rgtype "css") - (:language "pascal" :ext "pas" :agtype "delphi" :rgtype nil) - (:language "pascal" :ext "dpr" :agtype "delphi" :rgtype nil) - (:language "pascal" :ext "int" :agtype "delphi" :rgtype nil) - (:language "pascal" :ext "dfm" :agtype "delphi" :rgtype nil) - (:language "fsharp" :ext "fs" :agtype "fsharp" :rgtype nil) - (:language "fsharp" :ext "fsi" :agtype "fsharp" :rgtype nil) - (:language "fsharp" :ext "fsx" :agtype "fsharp" :rgtype nil) - (:language "kotlin" :ext "kt" :agtype "kotlin" :rgtype "kotlin") - (:language "kotlin" :ext "kts" :agtype "kotlin" :rgtype "kotlin") - (:language "protobuf" :ext "proto" :agtype "proto" :rgtype "protobuf") - (:language "hcl" :ext "tf" :agtype "terraform" :rgtype "tf") - (:language "hcl" :ext "tfvars" :agtype "terraform" :rgtype nil) - (:language "apex" :ext "cls" :agtype nil :rgtype nil) - (:language "apex" :ext "trigger" :agtype nil :rgtype nil) - (:language "jai" :ext "jai" :agtype nil :rgtype nil) - (:language "odin" :ext "odin" :agtype nil :rgtype nil) - (:language "cobol" :ext "cbl" :agtype nil :rgtype nil) - (:language "cobol" :ext "cob" :agtype nil :rgtype nil) - (:language "cobol" :ext "cpy" :agtype nil :rgtype nil)) - - "Map programming language to file extensions support by search tool. -The value of :agytpe, :rgtype is nil when the search tool file type does -not search for that file extension, otherwise it is the name of the file -type for that tool." - :group 'dumb-jump - :type - '(repeat - (plist - :options ((:language (string :tag "Language")) - (:ext (string :tag "Extension")) - (:agtype (string :tag "Ag type")) - (:rgtype (string :tag "Ripgrep type")))))) - -(defcustom dumb-jump-language-contexts - '((:language "javascript" :type "function" :left nil :right "^(" ) - (:language "javascript" :type "variable" :left "($" :right nil ) - (:language "javascript" :type "variable" :left "($" :right "^)" ) - (:language "javascript" :type "variable" :left nil :right "^\\." ) - (:language "javascript" :type "variable" :left nil :right "^;" ) - (:language "typescript" :type "function" :left nil :right "^(" ) - (:language "typescript" :type "type" :left "\\(?:[:<>,|&]\\|\\_<\\(?:as\\|extends\\|implements\\)\\_>\\)\\s-*$" :right nil) - (:language "typescript" :type "type" :left "\\_<\\(?:type\\|interface\\|enum\\|class\\)\\_>\\s-+$" :right nil) - (:language "perl" :type "function" :left nil :right "^(" ) - (:language "tcl" :type "function" :left "\\[$" :right nil) - (:language "tcl" :type "function" :left "^\\s*$" :right nil) - (:language "tcl" :type "variable" :left "\\$$" :right nil) - (:language "php" :type "function" :left nil :right "^(" ) - (:language "php" :type "class" :left "new\\s+" :right nil ) - (:language "elisp" :type "function" :left "($" :right nil ) - (:language "elisp" :type "variable" :left nil :right "^)" ) - (:language "scheme" :type "function" :left "($" :right nil ) - (:language "scheme" :type "variable" :left nil :right "^)" ) - (:language "jai" :type "function" :left nil :right "\\s*(" ) - (:language "jai" :type "type" :left "\\s*:\\s*" :right nil) - (:language "cobol" :type "submodule" :left "call\\s+" :right nil ) - (:language "cobol" :type "section" :left "perform\\s+" :right nil ) - (:language "cobol" :type "section" :left "go to\\s+" :right nil )) - "List of under points contexts for each language. -This helps limit the number of regular expressions we use -if we know that if there's a ( immediately to the right of -a symbol then it's probably a function call." - :group 'dumb-jump - :type - '(repeat - (plist - :options ((:language (string :tag "Language")) - (:type (choice (const "function") - (const "variable"))) - (:left (choice (const :tag "Anything" nil) - (string :tag "Regular expression"))) - (:right (choice (const :tag "Anything" nil) - (string :tag "Regular expression"))))))) - -(defcustom dumb-jump-project-denoters - '(".dumbjump" - ".projectile" - ".git" - ".hg" - ".fslckout" - ".bzr" - "_darcs" - ".svn" - "Makefile" - "PkgInfo" - "-pkg.el" - "_FOSSIL_" - "Cargo.toml") - "Files and directories that signify a directory is a project root. -If any of these denoting files are present in project sub-directories -(like Makefile) then you can either remove the culprit denoter from the -list or create a .dumbjumpignore file in the project sub-directory." - :group 'dumb-jump - :type '(repeat (string :tag "Name"))) - -(defcustom dumb-jump-default-project "~" - "Directory of default project to search within if a project root is not found." - :group 'dumb-jump - :type 'string) - -(defcustom dumb-jump-project nil - "Directory of project to search within if normal denoters will not work. -This should only be needed in the rarest of cases." - :group 'dumb-jump - :type 'string) - -(defcustom dumb-jump-rust-search-dependencies nil - "When non-nil, automatically include Rust dependency source paths. -Uses `cargo metadata' to discover crate source directories. -Requires `cargo' to be installed and a Cargo.toml in the project." - :group 'dumb-jump - :type 'boolean) - -(with-no-warnings ; don't warn about long example line - (defcustom dumb-jump-extra-search-paths-function nil - "Function to compute extra search paths for jump-to-definition lookups. -When non-nil, this function is called with two arguments: LANG (a -string naming the programming language, or nil if undetected) and -PROJ-ROOT (the project root directory). It should return a list of -directory path strings to include in the search, or nil. - -Returned paths may be absolute or relative to PROJ-ROOT (relative -entries are expanded via `expand-file-name'). Non-existent -directories and non-string entries are silently ignored. - -This is useful for dynamically adding paths such as virtualenv -site-packages, installed library sources, or SDK directories. - -Example: - - (setq dumb-jump-extra-search-paths-function - (lambda (lang proj-root) - (when (string= lang \"python\") - (let* ((default-directory proj-root) - (path (string-trim - (shell-command-to-string - \"poetry run python -c \\\"import site; print(site.getsitepackages()[0])\\\"\")))) - (when (file-directory-p path) - (list path))))))" - :group 'dumb-jump - :type '(choice (const :tag "None" nil) - function))) - -(defcustom dumb-jump-before-jump-hook nil - "Hooks called before jumping." - :group 'dumb-jump - :type 'hook) - -(defcustom dumb-jump-after-jump-hook nil - "Hooks called after jumping." - :group 'dumb-jump - :type 'hook) - -(defcustom dumb-jump-aggressive - nil - "If `t` jump aggressively with the possibility of a false positive. -If `nil` always show list of more than 1 match." - :group 'dumb-jump - :type 'boolean) - -(defcustom dumb-jump-debug - nil - "If `t` will print helpful debug information. -Also ensure that `dumb-jump-quiet' is nil for debugging!" - :group 'dumb-jump - :type 'boolean) - -(defcustom dumb-jump-confirm-jump-to-modified-file - t - "Confirm before jumping to a modified file? -If t, confirm before jumping to a modified file (which may lead to an -inaccurate jump). -If nil, jump without confirmation but print a warning." - :group 'dumb-jump - :type 'boolean) - -(defcustom dumb-jump-disable-obsolete-warnings nil - "If non-nil, don't warn about using the legacy interface." - :group 'dumb-jump - :type 'boolean) - -;; --------------------------------------------------------------------------- -;; Debugging Utilities -;; ------------------- - -(defun dumb-jump-message-prin1 (format-str &rest args) - "Helper debugging function: generate a FORMAT-STR message with all ARGS." - ;; Fist transform each of ARGS to string with `prin1-to-string' then - ;; pass them as arguments to message by making a list used the third - ;; parameter to apply. - (apply 'message format-str (mapcar #'prin1-to-string args))) - -;; --------------------------------------------------------------------------- -;; Search tool presence checkers -;; ----------------------------- -(defvar dumb-jump--detected-env-problems nil - "List of detected environment problems. -Last detected problem is first in the list.") - -(defun dumb-jump-env-problem (problem) - "Add PROBLEM string to `dumb-jump--detected-env-problems' list." - (unless (member problem dumb-jump--detected-env-problems) - (push problem dumb-jump--detected-env-problems))) - -;;;###autoload -(defun dumb-jump-show-detected-problems (keep) - "Print all problems detected by dumb-jump environment in *Message*. -Erase the accumulated list unless the command is issued with any prefix -key (such as `\\[universal-argument]')." - (interactive "P") - (if dumb-jump--detected-env-problems - (progn - (message "-- Dumb-Jump Detected Environment Problems:") - (dolist (problem (reverse dumb-jump--detected-env-problems)) - (message problem)) - (unless keep - (setq dumb-jump--detected-env-problems nil))) - (message "No problem recorded yet."))) - -;; -- - -(defvar dumb-jump--ag-installed? 'unset) -(defun dumb-jump-ag-installed? () - "Return t if ag is installed." - (if (eq dumb-jump--ag-installed? 'unset) - (setq dumb-jump--ag-installed? - (dumb-jump--contains-p "ag version" - (shell-command-to-string - (concat dumb-jump-ag-cmd " --version")))) - dumb-jump--ag-installed?)) - -(defvar dumb-jump--git-grep-plus-ag-installed? 'unset) -(defun dumb-jump-git-grep-plus-ag-installed? () - "Return t if git grep and ag is installed." - (if (eq dumb-jump--git-grep-plus-ag-installed? 'unset) - (setq dumb-jump--git-grep-plus-ag-installed? - (and (dumb-jump-git-grep-installed?) - (dumb-jump-ag-installed?))) - dumb-jump--git-grep-plus-ag-installed?)) - -(defvar dumb-jump--rg-installed? 'unset) -(defun dumb-jump-rg-installed? () - "Return t if rg 0.10 or later with PCRE2 support is installed. -Return nil otherwise. In that case store diagnostics information in the -variable `dumb-jump--detected-env-problems'." - (if (eq dumb-jump--rg-installed? 'unset) - (setq - dumb-jump--rg-installed? - (catch 'rg-problem - (unless (executable-find dumb-jump-rg-cmd) - (dumb-jump-env-problem - (format "Ripgrep not found as specified in `dumb-jump-rg-cmd': %s" - dumb-jump-rg-cmd)) - (throw 'rg-problem nil)) - (let* ((stdout (shell-command-to-string - (concat dumb-jump-rg-cmd " --version"))) - (has-version (string-match "ripgrep \\([0-9]+\\.[0-9]+\\).*" - stdout))) - (unless has-version - (dumb-jump-env-problem "Can't detect Ripgrep version.") - (throw 'rg-problem nil)) - (unless (version<= "0.10" (match-string-no-properties 1 stdout)) - (dumb-jump-env-problem "Ripgrep >= 0.10 is not available.") - (throw 'rg-problem nil)) - (unless (string-match "features:.*pcre2" stdout) - (dumb-jump-env-problem "Ripgrep does not support PCRE2.") - (throw 'rg-problem nil)) - t))) - dumb-jump--rg-installed?)) - -(defvar dumb-jump--git-grep-installed? 'unset) -(defun dumb-jump-git-grep-installed? () - "Return t if git-grep is installed." - (if (eq dumb-jump--git-grep-installed? 'unset) - (setq dumb-jump--git-grep-installed? - (dumb-jump--contains-p "fatal: no pattern given" - (shell-command-to-string - (concat dumb-jump-git-grep-cmd)))) - dumb-jump--git-grep-installed?)) - -(defvar dumb-jump--grep-installed? 'unset) -(defun dumb-jump-grep-installed? () - "Return non-nil if a grep is installed, nil otherwise. -Return \\='gnu if GNU grep is installed, \\='bsd if BSD grep is installed." - (if (eq dumb-jump--grep-installed? 'unset) - (let* ((version (shell-command-to-string - (concat dumb-jump-grep-cmd " --version"))) - (variant (cond ((dumb-jump--match "GNU grep" version) 'gnu) - ((dumb-jump--match "[0-9]+\\.[0-9]+" version) 'bsd) - (t nil)))) - (setq dumb-jump--grep-installed? variant)) - dumb-jump--grep-installed?)) - -;; --------------------------------------------------------------------------- -;; Dumb-Jump Tests -;; --------------- - -(defun dumb-jump-run-test (test cmd) - "Use TEST as the standard input for the CMD." - (with-temp-buffer - (insert test) - (shell-command-on-region (point-min) (point-max) cmd nil t) - (buffer-substring-no-properties (point-min) (point-max)))) - -(defun dumb-jump-run-test-temp-file (test thefile realcmd) - "Write TEST string to temporary file THEFILE, run shell REALCMD on it. -Return resulting string." - (with-temp-buffer - (insert test) - (write-file thefile nil) - (delete-region (point-min) (point-max)) - (shell-command realcmd t) - (set-buffer-modified-p nil) ; prevent prompt on file deletion during test - (delete-file thefile) - (buffer-substring-no-properties (point-min) (point-max)))) - -(defun dumb-jump-run-git-grep-test (test git-grep-cmd) - "Execute GIT-GREP-CMD on input TEST string written in temporary file. -Necessary because git grep must be given a file as input, not just a string." - (let ((thefile ".git.grep.test")) - (dumb-jump-run-test-temp-file test - thefile - (concat git-grep-cmd " " thefile)))) - -(defun dumb-jump-run-ag-test (test ag-cmd) - "Execute AG-CMD on input TEST written in temporary file. -The difference is that ag ignores multiline matches when passed -input from stdin, which is a crucial feature." - (let ((thefile ".ag.test")) - (dumb-jump-run-test-temp-file test - thefile - (concat ag-cmd " " thefile)))) - -;; --------------------------------------------------------------------------- -;; Test dumb-jump search rules -;; --------------------------- - -(defun dumb-jump--search-failure-msg (tool test run-not-tests resp cmd rule) - "Return search failure string adjusted to the arguments. -TOOL: search tool name. -TEST: the test string. -RUN-NO-TESTS: t to see a list of all failed rules. -RESP: response. -CMD: the search command used. -RULE: the complete `dumb-jump-find-rules' rule used for this test." - (format "%s FAILURE '%s' %s in response '%s' | CMD: '%s' | rule: '%s'" - tool - test - (if run-not-tests "IS unexpectedly" "NOT") - resp - cmd - rule)) - -(defun dumb-jump-test-grep-rules (&optional run-not-tests) - "Test all the grep rules and return count of those that fail. -Optionally pass t for RUN-NOT-TESTS to see a list of all failed rules." - (let ((variant (if (eq (dumb-jump-grep-installed?) 'gnu) 'gnu-grep 'grep))) - (mapcan - (lambda (rule) - (mapcan - (lambda (test) - (let* ((cmd (concat "grep -En -e " - (shell-quote-argument - (dumb-jump-populate-regex - (plist-get rule :regex) "test" variant)))) - (resp (dumb-jump-run-test test cmd))) - (when (or - (and (not run-not-tests) (not (dumb-jump--contains-p test resp))) - (and run-not-tests (> (length resp) 0))) - (list (dumb-jump--search-failure-msg "grep" - test - run-not-tests - resp - cmd - (plist-get rule :regex)))))) - (plist-get rule (if run-not-tests :not :tests)))) - (seq-filter (lambda (it) (member "grep" (plist-get it :supports))) dumb-jump-find-rules)))) - -(defun dumb-jump-test-ag-rules (&optional run-not-tests) - "Test all the ag rules and return count of those that fail. -Optionally pass t for RUN-NOT-TESTS to see a list of all failed rules." - (mapcan - (lambda (rule) - (mapcan - (lambda (test) - (let* ((cmd (concat "ag --nocolor --nogroup --nonumber " - (shell-quote-argument - (dumb-jump-populate-regex - (plist-get rule :regex) "test" 'ag)))) - (resp (dumb-jump-run-ag-test test cmd))) - (when (or - (and (not run-not-tests) (not (dumb-jump--contains-p test resp))) - (and run-not-tests (> (length resp) 0))) - (list (dumb-jump--search-failure-msg "ag" - test - run-not-tests - resp - cmd - rule))))) - (plist-get rule (if run-not-tests :not :tests)))) - (seq-filter (lambda (it) (member "ag" (plist-get it :supports))) dumb-jump-find-rules))) - -(defun dumb-jump-test-rg-rules (&optional run-not-tests) - "Test all the rg rules and return count of those that fail. -Optionally pass t for RUN-NOT-TESTS to see a list of all failed rules." - (mapcan - (lambda (rule) - (mapcan - (lambda (test) - (let* ((cmd (concat "rg --color never --no-heading -U --pcre2 " - (shell-quote-argument - (dumb-jump-populate-regex - (plist-get rule :regex) "test" 'rg)))) - (resp (dumb-jump-run-test test cmd))) - (when (or - (and (not run-not-tests) (not (dumb-jump--contains-p test resp))) - (and run-not-tests (> (length resp) 0))) - (list (dumb-jump--search-failure-msg "rg" - test - run-not-tests - resp - cmd - rule))))) - (plist-get rule (if run-not-tests :not :tests)))) - (seq-filter (lambda (it) (member "rg" (plist-get it :supports))) dumb-jump-find-rules))) - -(defun dumb-jump-test-git-grep-rules (&optional run-not-tests) - "Test all the git grep rules and return count of those that fail. -Optionally pass t for RUN-NOT-TESTS to see a list of all failed rules. - -Note: Tests rules that support \"grep\" since git-grep uses the same -ERE syntax. Testing actual git-grep would require temp git repos." - (mapcan - (lambda (rule) - (mapcan - (lambda (test) - (let* ((cmd (concat "git grep --color=never -h --untracked -E " - (shell-quote-argument - (dumb-jump-populate-regex - (plist-get rule :regex) "test" 'git-grep)))) - (resp (dumb-jump-run-git-grep-test test cmd))) - (when (or - (and (not run-not-tests) (not (dumb-jump--contains-p test resp))) - (and run-not-tests (> (length resp) 0))) - (list (dumb-jump--search-failure-msg "git-grep" - test - run-not-tests - resp - cmd - rule))))) - (plist-get rule (if run-not-tests :not :tests)))) - (seq-filter (lambda (it) (member "grep" (plist-get it :supports))) dumb-jump-find-rules))) - -;; --------------------------------------------------------------------------- - -(defun dumb-jump-message (str &rest args) - "Log message STR with ARGS to *Messages* if not using `dumb-jump-quiet'." - (unless dumb-jump-quiet - (apply 'message str args)) - nil) - -(defmacro dumb-jump-debug-message (&rest exprs) - "Generate a debug message to print all expressions EXPRS." - (declare (indent defun)) - (let ((i 5) frames frame) - ;; based on https://emacs.stackexchange.com/a/2312 - (while (setq frame (backtrace-frame i)) - (push frame frames) - (cl-incf i)) - ;; this is a macro-expanded version of the code in the stackexchange - ;; code from above. This version should work on emacs-24.3, since it - ;; doesn't depend on thread-last. - (let* ((frame (cl-find-if - (lambda (frame) - (ignore-errors - (and (car frame) - (eq (caaddr frame) - 'defalias)))) - (reverse frames))) - (func (cl-cadadr (cl-caddr frame))) - (defun-name (symbol-name func))) - (with-temp-buffer - (insert "DUMB JUMP DEBUG `") - (insert defun-name) - (insert "` START\n----\n\n") - (dolist (expr exprs) - (insert (prin1-to-string expr) ":\n\t%s\n\n")) - (insert "\n-----\nDUMB JUMP DEBUG `") - (insert defun-name) - (insert "` END\n-----") - `(when dumb-jump-debug - (dumb-jump-message - ,(buffer-string) - ,@exprs)))))) - -(defun dumb-jump-get-point-context (line func cur-pos) - "Get the LINE context to the left and right of FUNC using CUR-POS as hint." - (let ((loc (or (cl-search func line :start2 cur-pos) 0))) - (list :left (substring line 0 loc) - :right (substring line (+ loc (length func)))))) - -(defun dumb-jump-to-selected (results choices selected) - "With RESULTS use CHOICES to find the SELECTED choice from multiple options." - (let* ((result-index (dumb-jump--find-index (lambda (it) (string= selected it)) choices)) - (result (when result-index - (nth result-index results)))) - (when result - (dumb-jump-result-follow result)))) - -(defun dumb-jump-helm-persist-action (candidate) - "Preview CANDIDATE in temporary buffer displaying the file at matched line. -\\<helm-map> -This is the persistent action (\\[helm-execute-persistent-action]) for helm." - (let* ((file (plist-get candidate :path)) - (line (plist-get candidate :line)) - (default-directory-old default-directory)) - (switch-to-buffer (get-buffer-create " *helm dumb jump persistent*")) - (setq default-directory default-directory-old) - (fundamental-mode) - (erase-buffer) - (insert-file-contents file) - (let ((buffer-file-name file)) - (set-auto-mode) - (font-lock-fontify-region (point-min) (point-max)) - (goto-char (point-min)) - (forward-line (1- line))))) - -(defun dumb-jump--format-result (proj-root result) - "Return file:line:target formatted RESULT as a string stripped of PROJ-ROOT." - (format "%s:%s: %s" - (dumb-jump--replace proj-root "" (plist-get result :path)) - (plist-get result :line) - (dumb-jump--trim (plist-get result :context)))) - -(defun dumb-jump-ivy-jump-to-selected (results choices _proj) - "Offer CHOICES as candidates through `ivy-read'. -Then execute dumb-jump-result-follow' on the selected choice RESULTS. -Ignore _PROJ." - (if (fboundp 'ivy-read) - (ivy-read "Jump to: " (dumb-jump--zip-pair choices results) - :action (lambda (cand) - (dumb-jump-result-follow (cdr cand))) - :caller 'dumb-jump-ivy-jump-to-selected) - (error "ivy-read is unknown. Is it loaded?"))) - -(defun dumb-jump-prompt-user-for-choice (proj-root results) - "Prompt user to select one of the identified RESULTS in PROJ-ROOT. -Strip the PROJ-ROOT (project root path) from the file name shown in each entry. -Prompt with the mechanism selected by `dumb-jump-selector' user-option if -available otherwise default to `completing-read'." - (let ((choices (mapcar (lambda (it) (dumb-jump--format-result proj-root it)) results))) - (cond - ((eq dumb-jump-selector 'completing-read) - (dumb-jump-to-selected results choices - (dumb-jump--select-choice choices "Jump to: "))) - ;; - ((and (eq dumb-jump-selector 'ivy) - (fboundp 'ivy-read)) - (funcall dumb-jump-ivy-jump-to-selected-function - results choices proj-root)) - ;; - ((and (eq dumb-jump-selector 'helm) - (fboundp 'helm)) - (helm :sources - (with-no-warnings - (helm-make-source "Jump to: " 'helm-source-sync - :action '(("Jump to match" . dumb-jump-result-follow)) - :candidates (dumb-jump--zip-pair choices results) - :persistent-action 'dumb-jump-helm-persist-action)) - :buffer "*helm dumb jump choices*")) - ;; fallback for unsupported selector values - (t (dumb-jump-to-selected results choices - (dumb-jump--select-choice choices "Jump to: ")))))) - -(defun dumb-jump-get-project-root (filepath) - "Return project root holding FILEPATH. -Keep looking at the parent dir of FILEPATH until a denoter file/dir is found. -Fall back to `project.el' when available and no denoter is found. -Return a directory name without the trailing slash." - (let* ((path (expand-file-name filepath)) - (dir (if (file-directory-p path) - (file-name-as-directory path) - (file-name-directory path))) - (project-el-root - (when (and (null dumb-jump-project) - dir - (fboundp 'project-current)) - (let ((default-directory dir)) - (let ((proj (ignore-errors (project-current nil)))) - (when proj - (if (fboundp 'project-root) - (project-root proj) - (with-no-warnings - ;; On Emacs 26.1 use now obsolete `project-roots' - (car (project-roots proj)))))))))) - (directory-file-name - (expand-file-name - (or dumb-jump-project - (locate-dominating-file path #'dumb-jump-get-config) - project-el-root - dumb-jump-default-project))))) - -(defvar dumb-jump--rust-deps-cache (make-hash-table :test 'equal) - "Cache of Rust dependency paths keyed by project root.") - -(defun dumb-jump-get-rust-dependency-paths (proj-root) - "Return list of source directories for Rust dependencies in PROJ-ROOT. -Uses `cargo metadata' to discover dependency crate source paths. -Results are cached per project root." - (let ((cached (gethash proj-root dumb-jump--rust-deps-cache 'dumb-jump--no-cache))) - (if (not (eq cached 'dumb-jump--no-cache)) - cached - (let ((dep-paths - (when (file-exists-p (expand-file-name "Cargo.toml" proj-root)) - (let* ((default-directory proj-root) - (json-output (with-temp-buffer - (let ((exit-code (call-process "cargo" nil t nil - "metadata" "--format-version=1"))) - (when (eq exit-code 0) - (buffer-string))))) - (json-data (ignore-errors (when json-output (json-read-from-string json-output)))) - (packages (when json-data (cdr (assoc 'packages json-data)))) - (paths (when packages - (seq-uniq - (seq-filter - #'file-directory-p - (mapcar (lambda (pkg) - (file-name-directory - (cdr (assoc 'manifest_path pkg)))) - packages)))))) - (seq-remove - (lambda (p) (string= (directory-file-name p) - (directory-file-name proj-root))) - paths))))) - (puthash proj-root dep-paths dumb-jump--rust-deps-cache) - dep-paths)))) - -(defun dumb-jump-get-config (dir) - "If a project denoter is in DIR then return it, otherwise nil. -However, if DIR contains a `.dumbjumpignore' it returns nil to keep -looking for another root." - (if (file-exists-p (expand-file-name ".dumbjumpignore" dir)) - nil - (car (seq-filter - (lambda (it) (file-exists-p (expand-file-name it dir))) - dumb-jump-project-denoters)))) - -(defun dumb-jump-get-language (file) - "Get language from FILE extension. Fallback to using `major-mode' name." - (let* ((language (or (dumb-jump-get-language-from-mode) - (dumb-jump-get-language-by-filename file) - (dumb-jump-get-mode-base-name)))) - ; src edit buffer ? org-edit-src-exit - (if (and (fboundp 'org-src-edit-buffer-p) - (org-src-edit-buffer-p)) - (progn - (setq language "org") - (with-no-warnings - (org-edit-src-exit)) - (if (and (boundp 'org-version) - (version< org-version "9")) - (save-buffer)))) - (if (string= language "org") - (setq language (dumb-jump-get-language-in-org))) - (if (member language (seq-uniq - (mapcar (lambda (it) (plist-get it :language)) - dumb-jump-find-rules))) - language - (format ".%s file" (or (file-name-extension file) ""))))) - -(defun dumb-jump-get-language-in-org () - "Return associated language in org mode src block or \"org\" if outside src. -This assumes point is inside an org mode buffer." - (let ((lang (nth 0 (with-no-warnings (org-babel-get-src-block-info))))) - ;; if lang exists then create a composite language - (if lang - (dumb-jump-make-composite-language - "org" - (if (dumb-jump-get-language-from-aliases lang) - (dumb-jump-get-language-from-aliases lang) - lang) - "org" - "org" - "org") - "org"))) - -(defun dumb-jump-add-language-to-proplist (newlang proplist lang) - "Return nil if NEWLANG is already in PROPLIST or (if not) -return a new proplist. The new proplis is PROPLIS -where a NEWLANG plist(s) is (are) added to PROPLIST. -The plist(s) value of NEWLANG is (are) copied from -those of LANG and LANG is replaced by NEWLANG." - (unless (seq-filter (lambda (it) (string= newlang (plist-get it :language))) - proplist) - (dumb-jump--splice - (lambda (it) (string= lang (plist-get it :language))) - (lambda (it) (list it (plist-put (copy-tree it) :language newlang))) - proplist))) - -(defun dumb-jump-make-composite-language (mode lang extension agtype rgtype) - "Concat one MODE (usually the string org) with a LANG (c or python or etc) -to make a composite language of the form cPLUSorg or pythonPLUSorg or etc. -Modify `dumb-jump-find-rules' and `dumb-jump-language-file-exts' accordingly -\(using EXTENSION AGTYPE RGTYPE)" - (let* ((complang (concat lang "PLUS" mode)) - (alreadyextension (seq-filter (lambda (it) - (and - (string= complang (plist-get it :language)) - (string= extension (plist-get it :ext)) - (string= agtype (plist-get it :agtype)) - (string= rgtype (plist-get it :rgtype)))) - dumb-jump-language-file-exts)) - (newfindrule (dumb-jump-add-language-to-proplist complang dumb-jump-find-rules lang)) - (newfileexts (dumb-jump-add-language-to-proplist complang dumb-jump-language-file-exts lang))) - (when newfindrule - (set-default 'dumb-jump-find-rules newfindrule)) - (unless dumb-jump-search-type-org-only-org - (when newfileexts - (set-default 'dumb-jump-language-file-exts newfileexts))) - (unless alreadyextension - (set-default 'dumb-jump-language-file-exts - (cons `(:language ,complang - :ext ,extension - :agtype ,agtype - :rgtype ,rgtype) - dumb-jump-language-file-exts))) - complang)) - -(defcustom dumb-jump-language-aliases-alist - '(("sh" . "shell") - ("d" . "dlang") - ("cperl" . "perl") - ("octave" . "matlab") - ("emacs-lisp" . "elisp") - ("R" . "r") - ("arduino" . "c++")) - "An alist of language alias to language name. -Aliases are major mode base name sometimes used for some files. -For example: \"cperl\" for the \"perl\" language." - :group 'dumb-jump - :type '(repeat (cons - (string :tag "alias ") - (string :tag "language")))) - -(defun dumb-jump-get-language-from-aliases (lang) - "Return the dumb-jump language name for a possible alias if there is one. -Return nil if LANG is not one of the supported aliases." - (assoc-default lang dumb-jump-language-aliases-alist)) - -(defun dumb-jump-get-mode-base-name () - "Get the base name of the mode." - (dumb-jump--replace "-mode" "" (symbol-name major-mode))) - -(defun dumb-jump-get-language-from-mode () - "Extract the language from the `major-mode' name. -Currently just everything before \"-mode\"." - (dumb-jump-get-language-from-aliases (dumb-jump-get-mode-base-name))) - -(defun dumb-jump-get-language-by-filename (file) - "Get the programming language name from the specified FILE extension." - ;; Search in `dumb-jump-language-file-exts' for an entry that has the :ext - ;; attribute equal to the file extension and return the corresponding - ;; :language value. - (let* ((filename (if (string-suffix-p ".gz" file) - (file-name-sans-extension file) - file)) - (result (seq-filter - (lambda (it) (string-suffix-p (concat "." (plist-get it :ext)) filename)) - dumb-jump-language-file-exts))) - (when (and result (eq (length result) 1)) - (plist-get (car result) :language)))) - -;; -- - -(defun dumb-jump-issue-result (issue) - "Return a result property list with the ISSUE set as :issue property symbol." - `(:results nil - :lang nil - :symbol nil - :ctx-type nil - :file nil - :root nil - :issue ,(intern issue))) - -(defun dumb-jump-get-results (&optional entered-name) - "Perform the dumb-jump search for text at point, region or ENTERED-NAME. - -Runs `dumb-jump-fetch-results' under conditions adjusted to the current -context. - -Perform the search if searcher is installed, buffer is saved, and -there's a symbol under point or an item to search is specified by the -ENTERED-NAME string. - -Return the dumb-jump alist result: -- :results -- :lang : string: language name -- :symbol : string: symbol being searched -- :ctx-type: string: -- :file : string: file name -- :root : string: project root -- :issue : symbol: problem description symbol: nogrep or nosymbol." - ;; Prevent a empty string entered-name from being interpreted as user entry - ;; because `read-from-minibuffer' may return "". - (when (and entered-name (string-blank-p entered-name)) - (setq entered-name nil)) - (cond - ;; When no search tool is available just return an empty result identifying - ;; a nogrep issue. - ((not (or (dumb-jump-ag-installed?) - (dumb-jump-rg-installed?) - (dumb-jump-git-grep-installed?) - (dumb-jump-grep-installed?))) - (dumb-jump-issue-result "nogrep")) - ;; Inside a shell or eshell buffer, - ((derived-mode-p 'shell-mode 'eshell-mode) - (dumb-jump-fetch-shell-results entered-name)) - ;; When inside a normal buffer but no string specified by ENTERED-NAME, - ;; point or region does not identify something to search, - ;; just return an empty result identifying a nosymbol issue. - ((and (not entered-name) - (not (region-active-p)) - (not (thing-at-point 'symbol))) - (dumb-jump-issue-result "nosymbol")) - ;; Otherwise, perform the search for the text identified by string specified - ;; by ENTERED-NAME, point or region. - (t - (dumb-jump-fetch-file-results entered-name)))) - -(defun dumb-jump-fetch-shell-results (&optional entered-name) - "Perform search from shell buffer for text at point, region or ENTERED-NAME. -Return the dumb-jump alist result: -- :results -- :lang : string: language name -- :symbol : string: symbol being searched -- :ctx-type: string: -- :file : string: file name -- :root : string: project root." - (let* ((cur-file (buffer-name)) - (proj-root (dumb-jump-get-project-root default-directory)) - (proj-config (dumb-jump-get-config proj-root)) - (config (when (string-suffix-p ".dumbjump" proj-config) - (dumb-jump-read-config proj-root proj-config))) - (lang (or (plist-get config :language) - (car (dumb-jump-get-lang-by-shell-contents (buffer-name)))))) - (dumb-jump-fetch-results cur-file proj-root lang config entered-name))) - -(defun dumb-jump-fetch-file-results (&optional entered-name) - "Perform a file search for text at point, region or ENTERED-NAME string. -Return the dumb-jump alist result: -- :results -- :lang : string: language name -- :symbol : string: symbol being searched -- :ctx-type: string: -- :file : string: file name -- :root : string: project root." - (let* ((cur-file (or (buffer-file-name) "")) - (proj-root (dumb-jump-get-project-root cur-file)) - (proj-config (dumb-jump-get-config proj-root)) - (config (when (string-suffix-p ".dumbjump" proj-config) - (dumb-jump-read-config proj-root proj-config))) - (lang (or (plist-get config :language) - (dumb-jump-get-language cur-file)))) - (dumb-jump-fetch-results cur-file proj-root lang config entered-name))) - -;; -- -(defun dumb-jump-process-symbol-by-lang (lang look-for) - "Process and potentially transform LANG's LOOK-FOR. -For instance, remove clojure namespace prefix." - (cond - ((and (string= lang "commonlisp") - (dumb-jump--contains-p ":" look-for) - (not (string-prefix-p ":" look-for))) - (nth 1 (dumb-jump--split ":" look-for 'omit-nulls))) - ((and (string= lang "clojure") - (dumb-jump--contains-p "/" look-for)) - (nth 1 (dumb-jump--split "/" look-for))) - ((and (string= lang "fennel") - (dumb-jump--contains-p "." look-for)) - (car (last (dumb-jump--split "\\." look-for)))) - ((and (string= lang "ruby") - (dumb-jump--contains-p "::" look-for)) - (car (last (dumb-jump--split "::" look-for)))) - ((and (or (string= lang "ruby") - (string= lang "crystal")) - (string-prefix-p ":" look-for)) - (dumb-jump--chop-prefix ":" look-for)) - ((and (string= lang "systemverilog") - (string-prefix-p "`" look-for)) - (dumb-jump--chop-prefix "`" look-for)) - (t - look-for))) - -(defun dumb-jump-get-point-line () - "Get line at point." - (thing-at-point 'line t)) - -(defun dumb-jump-get-point-symbol () - "Get symbol at point." - (if (region-active-p) - (buffer-substring-no-properties (region-beginning) (region-end)) - (thing-at-point 'symbol t))) - -(defun dumb-jump--get-symbol-start () - "Get the start of symbol at point." - (- (if (region-active-p) - (region-beginning) - (car (bounds-of-thing-at-point 'symbol))) - (line-beginning-position))) - -(defun dumb-jump-get-lang-by-shell-contents (buffer) - "Return languages in BUFFER by checking if file extension is mentioned." - (let* ((buffer-contents (with-current-buffer buffer - (buffer-string))) - (found (seq-filter (lambda (it) - (dumb-jump--match (concat "\\." (regexp-quote (plist-get it :ext)) "\\b") - buffer-contents)) - dumb-jump-language-file-exts))) - (mapcar (lambda (it) (plist-get it :language)) found))) - -(defun dumb-jump-fetch-results (cur-file proj-root lang config - &optional entered-name) - "Search for symbol in ENTERED-NAME or symbol at point. - -Return a list of results based on current file context and calling the -currently selected searcher tool (grep, ag, rg, ...). - -CUR-FILE is the path of the current buffer. -PROJ-ROOT is that file's root project directory. -LANG is a string programming language with CONFIG a property list -of project configuration. -ENTERED-NAME is an optional string identifying item to search. -The returned property list has the following members: -- :results: -- :lang : string: language name -- :symbol : string: symbol being searched -- :ctx-type: string: -- :file : string: file name -- :root : string: project root." - (let* ((cur-line-num (line-number-at-pos)) - (found-symbol (or entered-name (dumb-jump-get-point-symbol))) - (look-for (dumb-jump-process-symbol-by-lang lang found-symbol)) - (pt-ctx (if entered-name - (get-text-property 0 :dumb-jump-ctx entered-name) - (dumb-jump-get-point-context - (dumb-jump-get-point-line) - look-for - (dumb-jump--get-symbol-start)))) - (ctx-type - (unless (eq dumb-jump--search-mode 'references) - (dumb-jump-get-ctx-type-by-language lang pt-ctx))) - - (gen-funcs (dumb-jump-pick-grep-variant proj-root)) - (parse-fn (plist-get gen-funcs :parse)) ; dumb-jump-parse-TOOL-response - (generate-fn (plist-get gen-funcs :generate)) - (searcher (plist-get gen-funcs :searcher)) - - (regexes (if (eq dumb-jump--search-mode 'references) - ;; Broad symbol search with a left boundary that also - ;; works for Lisp-family identifiers like *foo*. - (list "(^|[^a-zA-Z0-9\\?\\*-])JJJ\\j") - (dumb-jump-get-contextual-regexes lang ctx-type searcher))) - - ;; If selected searcher has no rules for this language, try alternatives. - ;; Only block fallback when dumb-jump-force-searcher is a direct - ;; searcher symbol. When it's a function or directory list that - ;; didn't match this project, the auto-selected searcher should - ;; still be eligible for fallback. - (_alt-searcher - (when (and (null regexes) - (not (eq dumb-jump--search-mode 'references)) - (not (memq dumb-jump-force-searcher - '(ag rg grep gnu-grep git-grep - git-grep-plus-ag)))) - (let ((alt (seq-find - (lambda (s) - (and (not (eq s searcher)) - (if (eq s 'gnu-grep) - (eq (dumb-jump-grep-installed?) 'gnu) - (funcall (plist-get - (dumb-jump-generators-by-searcher s) - :installed))) - (dumb-jump-get-rules-by-language lang s))) - '(ag rg git-grep gnu-grep grep)))) - (when alt - (setq gen-funcs (dumb-jump-generators-by-searcher alt)) - (setq parse-fn (plist-get gen-funcs :parse)) - (setq generate-fn (plist-get gen-funcs :generate)) - (setq searcher (plist-get gen-funcs :searcher)) - (setq regexes (dumb-jump-get-contextual-regexes - lang ctx-type searcher)))))) - - (exclude-paths (when config (plist-get config :exclude))) - (include-paths (when config (plist-get config :include))) - (rust-dep-paths (when (and (string= lang "rust") - dumb-jump-rust-search-dependencies) - (dumb-jump-get-rust-dependency-paths proj-root))) - (extra-paths - (when dumb-jump-extra-search-paths-function - (let* ((hook-lang (if (and (stringp lang) - (string-match "\\`\\(.+\\)PLUS" lang)) - (match-string 1 lang) - lang)) - (paths (funcall dumb-jump-extra-search-paths-function - hook-lang proj-root))) - (when (listp paths) - (mapcan - (lambda (p) - (when (stringp p) - (let ((expanded (expand-file-name p proj-root))) - (if (file-directory-p expanded) - (list expanded) - (when dumb-jump-debug - (dumb-jump-message - "Dumb Jump: extra-search-paths dropping %S (not a directory)" - expanded)) - nil)))) - paths))))) - ;; we will search proj root and all include paths - (search-paths (seq-uniq (append (list proj-root) - include-paths - (or rust-dep-paths '()) - (or extra-paths '())))) - (_search-paths-debug - (when dumb-jump-debug - (dumb-jump-message "Dumb Jump: search-paths = %S" search-paths))) - (raw-results (mapcan - (lambda (it) - (dumb-jump-run-command look-for it - regexes lang - exclude-paths cur-file - cur-line-num parse-fn - generate-fn)) - search-paths)) - - (results - (let ((deduped (delete-dups - (mapcar (lambda (it) (plist-put it :target look-for)) - raw-results)))) - (if (eq dumb-jump--search-mode 'references) - (dumb-jump-filter-definition-results deduped lang look-for searcher) - deduped)))) - - `(:results ,results - :lang ,(if (null lang) "" lang) - :symbol ,look-for - :ctx-type ,(if (null ctx-type) "" ctx-type) - :file ,cur-file - :root ,proj-root))) - -;;;###autoload -(defun dumb-jump-back () - "Jump back to where the last jump was done." - ;; Note: made obsolete by Emacs `xref-pop-marker-stack'. - (interactive) - (with-demoted-errors "Error running `dumb-jump-before-jump-hook': %S" - (run-hooks 'dumb-jump-before-jump-hook)) - (pop-tag-mark) - (with-demoted-errors "Error running `dumb-jump-after-jump-hook': %S" - (run-hooks 'dumb-jump-after-jump-hook))) - -;;;###autoload -(defun dumb-jump-quick-look () - "Run `dumb-jump-go' in quick look mode. -That is, show a tooltip of where it would jump instead." - ;; Note: independent of the Emacs xref interface. - (interactive) - (with-no-warnings - (dumb-jump-go t))) - -;;;###autoload -(defun dumb-jump-go-other-window () - "Like dumb-jump-go' but use `find-file-other-window' instead of `find-file'." - ;; Note: independent of the Emacs xref interface. - (interactive) - (let ((dumb-jump-window 'other)) - (with-no-warnings - (dumb-jump-go)))) - -;;;###autoload -(defun dumb-jump-go-current-window () - "Like `dumb-jump-go' but always use `find-file'." - ;; Note: independent of the Emacs xref interface. - (interactive) - (let ((dumb-jump-window 'current)) - (with-no-warnings - (dumb-jump-go)))) - -;;;###autoload -(defun dumb-jump-go-prefer-external () - "Like `dumb-jump-go' but prefer external matches from the current file." - ;; Note: independent of the Emacs xref interface. - (interactive) - (with-no-warnings - (dumb-jump-go nil t))) - -;;;###autoload -(defun dumb-jump-find-references () - "Find references/usages of the symbol at point. -This is the inverse of `dumb-jump-go' -- it finds where a symbol -is used rather than where it is defined." - ;; Note: independent of the Emacs xref interface. - (interactive) - (let ((dumb-jump--search-mode 'references) - (dumb-jump-aggressive nil)) - (with-no-warnings - (dumb-jump-go)))) - -;;;###autoload -(defun dumb-jump-go-prompt () - "Like `dumb-jump-go' but prompt for function instead of using under point." - ;; Note: independent of the Emacs xref interface. - (interactive) - (with-no-warnings - (dumb-jump-go nil nil (read-from-minibuffer "Jump to: ")))) - -;;;###autoload -(defun dumb-jump-go-prefer-external-other-window () - "Like `dumb-jump-go-prefer-external' but create another window. -It uses `find-file-other-window' instead of `find-file'." - ;; Note: independent of the Emacs xref interface. - (interactive) - (let ((dumb-jump-window 'other)) - (with-no-warnings - (dumb-jump-go-prefer-external)))) - -;;;###autoload -(defun dumb-jump-go (&optional use-tooltip prefer-external entered-name) - "Go to the function/variable declaration for thing at point. -When USE-TOOLTIP is t a tooltip jump preview will show instead. -When PREFER-EXTERNAL is t it will sort external matches before -current file. -The optional ENTERED-NAME string is the name of the item to jump to -manually selected by user as response to a prompt." - ;; Note: independent of the Emacs xref interface. - (interactive "P") - (let* ((start-time (float-time)) - (info (dumb-jump-get-results entered-name)) - (end-time (float-time)) - (fetch-time (- end-time start-time)) - (results (plist-get info :results)) - (look-for (or entered-name (plist-get info :symbol))) - (proj-root (plist-get info :root)) - (issue (plist-get info :issue)) - (lang (plist-get info :lang)) - (result-count (length results))) - (when (> fetch-time dumb-jump-max-find-time) - (dumb-jump-message - "Took over %ss to find '%s'. \ -Please install ag or rg, or add a .dumbjump file to '%s' with path exclusions" - (number-to-string dumb-jump-max-find-time) look-for proj-root)) - (cond - ((eq issue 'nogrep) - (dumb-jump-message "Please install ag, rg, git grep or grep!")) - ((eq issue 'nosymbol) - (dumb-jump-message "No symbol under point.")) - ((string-suffix-p " file" lang) - (dumb-jump-message "Could not find rules for '%s'." lang)) - ((= result-count 1) - (dumb-jump-result-follow (car results) use-tooltip proj-root)) - ((> result-count 1) - ;; multiple results so let the user pick from a list - ;; unless the match is in the current file - (dumb-jump-handle-results results - (plist-get info :file) - proj-root - (plist-get info :ctx-type) - look-for use-tooltip prefer-external lang)) - ((= result-count 0) - (dumb-jump-message "'%s' %s %s %s not found." - look-for - (if (string-blank-p (or lang "")) - "with unknown language so" - lang) - (plist-get info :ctx-type) - (if (eq dumb-jump--search-mode 'references) - "references" - "declaration")))))) - -(defcustom dumb-jump-language-comments - '((:comment "//" :language "c++") - (:comment "/*" :language "c++") - (:comment ";" :language "elisp") - (:comment ";" :language "commonlisp") - (:comment "//" :language "javascript") - (:comment "//" :language "typescript") - (:comment "//" :language "dart") - (:comment "//" :language "dlang") - (:comment "/*" :language "dlang") - (:comment "/+" :language "dlang") - (:comment "--" :language "haskell") - (:comment "--" :language "lua") - (:comment "//" :language "rust") - (:comment "#" :language "julia") - (:comment "//" :language "objc") - (:comment "//" :language "csharp") - (:comment "//" :language "java") - (:comment ";" :language "clojure") - (:comment "#" :language "coffeescript") - (:comment "//" :language "faust") - (:comment ";" :language "fennel") - (:comment "!" :language "fortran") - (:comment "//" :language "go") - (:comment "//" :language "zig") - (:comment "#" :language "perl") - (:comment "#" :language "tcl") - (:comment "//" :language "php") - (:comment "#" :language "php") - (:comment "--" :language "purescript") - (:comment "#" :language "python") - (:comment "%" :language "matlab") - (:comment "#" :language "r") - (:comment ";" :language "racket") - (:comment "#" :language "ruby") - (:comment "#" :language "crystal") - (:comment "#" :language "nim") - (:comment "#" :language "nix") - (:comment "//" :language "scala") - (:comment ";" :language "scheme") - (:comment "#" :language "janet") - (:comment "#" :language "shell") - (:comment "//" :language "solidity") - (:comment "//" :language "swift") - (:comment "#" :language "elixir") - (:comment "%" :language "erlang") - (:comment "%" :language "tex") - (:comment "//" :language "systemverilog") - (:comment "--" :language "vhdl") - (:comment "//" :language "scss") - (:comment "//" :language "pascal") - (:comment "//" :language "protobuf") - (:comment "#" :language "hcl") - (:comment "//" :language "apex") - (:comment "//" :language "odin") - (:comment "/*" :language "odin") - (:comment "*>" :language "cobol")) - "List of one-line comments organized by language. -A language may have more than 1 comment string." - :group 'dumb-jump - :type - '(repeat - (plist - :options ((:comment string) - (:language string))))) - -(defun dumb-jump-get-comment-by-language (lang) - "Return a list of the one-line comment or comments for the given LANG." - (let* ((entries (seq-uniq - (seq-filter (lambda (it) (string= (plist-get it :language) lang)) - dumb-jump-language-comments)))) - (if (> (length entries) 0) - (mapcar (lambda (pl) (plist-get pl :comment)) entries) - nil))) - -(defun dumb-jump--context-startswith-comment (context-string comments) - "Return t when CONTEXT-STRING starts with any COMMENTS string." - (let ((startswith-comment nil) - ;; trim leading white-space from context-string - (context-str (replace-regexp-in-string "^\\s-+" "" context-string))) - (catch 'found-one - (dolist (comment comments) - (when (string-prefix-p comment context-str) - (setq startswith-comment t) - (throw 'found-one nil)))) - startswith-comment)) - -(defun dumb-jump-filter-no-start-comments (results lang) - "Filter out RESULTS with a :context starting with a LANG comment in file." - (let ((comments (dumb-jump-get-comment-by-language lang))) - (if comments - (seq-filter (lambda (it) - (not (dumb-jump--context-startswith-comment - (plist-get it :context) - comments))) - results) - results))) - -(defun dumb-jump-handle-results (results cur-file proj-root - ctx-type look-for - use-tooltip prefer-external - &optional language) - "Handle the searchers results. -RESULTS is a list of property lists with the searcher's results. -CUR-FILE is the current file within PROJ-ROOT. -CTX-TYPE is a string of the current context. -LOOK-FOR is the symbol we're jumping for. -USE-TOOLTIP shows a preview instead of jumping. -PREFER-EXTERNAL will sort current file last. -LANGUAGE is an optional language to pass to `dumb-jump-process-results'." - (let* ((processed (dumb-jump-process-results results cur-file proj-root - ctx-type look-for use-tooltip - prefer-external language)) - (results (plist-get processed :results)) - (do-var-jump (plist-get processed :do-var-jump)) - (var-to-jump (plist-get processed :var-to-jump)) - (match-cur-file-front (plist-get processed :match-cur-file-front))) - (dumb-jump-debug-message - look-for - ctx-type - var-to-jump - (pp-to-string match-cur-file-front) - (pp-to-string results) - prefer-external - proj-root - cur-file) - (cond - (use-tooltip ;; quick-look mode - (let* ((choices (mapcar (lambda (it) (dumb-jump--format-result proj-root it)) results)) - (selected-choice (dumb-jump--select-choice choices "Matches: ")) - (selected-result (cdr (assoc selected-choice - (dumb-jump--zip-pair choices results))))) - (when selected-result - (dumb-jump--show-preview - (dumb-jump--format-result proj-root selected-result))))) - (do-var-jump - (dumb-jump-result-follow var-to-jump use-tooltip proj-root)) - (t - (dumb-jump-prompt-user-for-choice proj-root match-cur-file-front))))) - -(defun dumb-jump--candidate-x<y (x y) - "Return non-nil if candidate X should sort before candidate Y. -Order by :path length (shorter first), then by :line." - (let ((x-path-len (length (plist-get x :path))) - (y-path-len (length (plist-get y :path)))) - (if (/= x-path-len y-path-len) - (< x-path-len y-path-len) - (< (plist-get x :line) - (plist-get y :line))))) - -(defun dumb-jump-process-results (results cur-file proj-root ctx-type - _look-for _use-tooltip - prefer-external &optional language) - "Process (filter, sort, ...) the searchers results. -RESULTS is a list of property lists with the searcher's results. -CUR-FILE is the current file within PROJ-ROOT. -CTX-TYPE is a string of the current context. -LOOK-FOR is the symbol we're jumping for. -USE-TOOLTIP shows a preview instead of jumping. -PREFER-EXTERNAL will sort current file last. -LANGUAGE is the optional given language, if nil it will be found by -`dumb-jump-get-language-by-filename'. -Figure which of the RESULTS to jump to. Favoring the CUR-FILE." - (let* ((lang (if language language - (dumb-jump-get-language-by-filename cur-file))) - (match-sorted (seq-sort (lambda (x y) - (< (plist-get x :diff) (plist-get y :diff))) - results)) - (match-no-comments (dumb-jump-filter-no-start-comments match-sorted - lang)) - - ;; Find the relative current file path by the project root. - ;; In some cases the results will not be absolute but relative and - ;; the "current file" filters must match in both cases. Also works - ;; when current file is in an arbitrary sub folder. - (rel-cur-file - (cond ((and (string-prefix-p proj-root cur-file) - (string-prefix-p default-directory cur-file)) - (substring cur-file - (length default-directory) - (length cur-file))) - - ((and (string-prefix-p proj-root cur-file) - (not (string-prefix-p default-directory cur-file))) - (substring cur-file - (1+ (length proj-root)) - (length cur-file))) - - (t - cur-file))) - - ;; Moves current file results to the front of the list, unless - ;; PREFER-EXTERNAL then put them last. - (match-cur-file-front - (if (not prefer-external) - (append - (seq-filter (lambda (it) - (and (> (plist-get it :diff) 0) - (or (string= (plist-get it :path) cur-file) - (string= (plist-get it :path) rel-cur-file)))) - match-no-comments) - (seq-filter (lambda (it) - (and (<= (plist-get it :diff) 0) - (or (string= (plist-get it :path) cur-file) - (string= (plist-get it :path) rel-cur-file)))) - match-no-comments) - (seq-sort #'dumb-jump--candidate-x<y - (seq-filter (lambda (it) - (not (or (string= (plist-get it :path) cur-file) - (string= (plist-get it :path) rel-cur-file)))) - match-no-comments))) - (append - (seq-sort #'dumb-jump--candidate-x<y - (seq-filter (lambda (it) - (not (or (string= (plist-get it :path) cur-file) - (string= (plist-get it :path) rel-cur-file)))) - match-no-comments)) - (seq-filter (lambda (it) - (or (string= (plist-get it :path) cur-file) - (string= (plist-get it :path) rel-cur-file))) - match-no-comments)))) - - (matches - (if (not prefer-external) - (seq-uniq - (append - (dumb-jump-current-file-results cur-file match-cur-file-front) - (dumb-jump-current-file-results rel-cur-file match-cur-file-front))) - match-cur-file-front)) - - (var-to-jump (car matches)) - ;; TODO: handle if ctx-type is null but ALL results are variable - - ;; When non-aggressive it should only jump when there is only one - ;; match, regardless of context. - (do-var-jump - (and (or dumb-jump-aggressive - (= (length match-cur-file-front) 1)) - (or (= (length matches) 1) - (string= ctx-type "variable") - (string= ctx-type "")) - var-to-jump))) - - (list :results results - :do-var-jump do-var-jump - :var-to-jump var-to-jump - :match-cur-file-front match-cur-file-front))) - -(declare-function tramp-file-name-localname "tramp") -(declare-function tramp-dissect-file-name "tramp") - -(defun dumb-jump-read-config (root config-file) - "Load and return options (exclusions, inclusions, etc). -Ffrom the ROOT project CONFIG-FILE." - (with-temp-buffer - (insert-file-contents (expand-file-name config-file root)) - (let ((local-root (if (file-remote-p root) - (progn - (require 'tramp) - (tramp-file-name-localname - (tramp-dissect-file-name root))) - root)) - include exclude lang) - (while (not (eobp)) - (cond ((looking-at "^language \\\(.+\\\)") - (setq lang (match-string 1))) - ((looking-at "^\\+\\(.+\\)") - (push (expand-file-name (match-string 1) local-root) - include)) - ((looking-at "^-/?\\(.+\\)") - (push (expand-file-name (match-string 1) local-root) - exclude))) - (forward-line)) - (list :exclude (nreverse exclude) - :include (nreverse include) - :language lang)))) - -(defun dumb-jump-file-modified-p (path) - "Return non-nil if file at PATH is open in Emacs and has a modified buffer." - (seq-some (lambda (it) - (and (buffer-modified-p it) - (buffer-file-name it) - (file-exists-p (buffer-file-name it)) - (file-equal-p (buffer-file-name it) path))) - (buffer-list))) - -(defun dumb-jump-result-follow (result &optional use-tooltip proj) - "Jump to location identified by RESULT. -Before jumping, record the jump to be able to jump back later. - -If destination buffer was modified, prompt user to proceed if the -`dumb-jump-confirm-jump-to-modified-file' user-option is non-nil, -otherwise display a warning. - -With optional USE-TOOLTIP non-nil, pop a tool-tip showing the project -PROJ and RESULT information." - (if (dumb-jump-file-modified-p (plist-get result :path)) - (let ((target-file (plist-get result :path))) - (if dumb-jump-confirm-jump-to-modified-file - (when (y-or-n-p - (concat - target-file - " has been modified so we may have the wrong location. Continue?")) - (dumb-jump--result-follow result use-tooltip proj)) - (message - "Warning: %s has been modified so we may have the wrong location." - target-file) - (dumb-jump--result-follow result use-tooltip proj))) - (dumb-jump--result-follow result use-tooltip proj))) - -(defun dumb-jump--result-follow (result &optional use-tooltip proj) - "Jump to location identified by RESULT. -Before jumping, record the jump to be able to jump back later. - -With optional USE-TOOLTIP non-nil, pop a tool-tip showing the project -PROJ and RESULT information." - (let* ((target-boundary (dumb-jump--matched-positions-all - (concat "\\b" - (regexp-quote (plist-get result :target)) - "\\b") - (plist-get result :context))) - ;; column position is either via tpos from ag or by using the regex - ;; above or last using old dumb-jump--index-of - (column (if target-boundary - (car (car target-boundary)) - (dumb-jump--index-of (plist-get result :target) - (plist-get result :context)))) - - (result-path (plist-get result :path)) - - ;; Return value is either a string like "/ssh:user@1.2.3.4:" or nil - (tramp-path-prefix (file-remote-p default-directory)) - - ;; If result-path is an absolute path, the prefix is added to the head of it, - ;; or result-path is added to the end of default-directory - (path-for-tramp (when (and result-path tramp-path-prefix) - (if (file-name-absolute-p result-path) - (concat tramp-path-prefix result-path) - (concat default-directory result-path)))) - - (thef (or path-for-tramp result-path)) - (line (plist-get result :line))) - (when thef - (if use-tooltip - (dumb-jump--show-preview (dumb-jump--format-result proj result)) - (dumb-jump-goto-file-line thef line column))) - ;; return the file for test - thef)) - -(defun dumb-jump-goto-file-line (thefile theline column) - "Open THEFILE, move point to line THELINE at COLUMN. -Push current position to the xref marker stack. -Run the `dumb-jump-before-jump-hook' hooks before jumping and -the `dumb-jump-after-jump-hook' hooks after the jump." - (xref-push-marker-stack) - ;; Run the before-jump hooks - (with-demoted-errors "Error running `dumb-jump-before-jump-hook': %S" - (run-hooks 'dumb-jump-before-jump-hook)) - ;; Open THEFILE in a buffer and a window specified by user-options. - (let* ((visible-buffer (find-buffer-visiting thefile)) - (visible-window (when visible-buffer - (get-buffer-window visible-buffer)))) - (cond - ((and visible-window dumb-jump-use-visible-window) - (select-window visible-window)) - ((eq dumb-jump-window 'other) - (find-file-other-window thefile)) - (t (find-file thefile)))) - ;; Move point to THELINE at COLUMN - (goto-char (point-min)) - (forward-line (1- theline)) - (forward-char column) - ;; Run the after-jump hooks - (with-demoted-errors "Error running `dumb-jump-after-jump-hook': %S" - (run-hooks 'dumb-jump-after-jump-hook))) - -(defun dumb-jump-current-file-results (path results) - "Return the PATH's RESULTS." - (let ((matched (seq-filter (lambda (it) (string= path (plist-get it :path))) results))) - matched)) - -(defun dumb-jump-generators-by-searcher (searcher) - "Return action property list for specific SEARCHER. - -- SEARCHER: symbol: the name of the search tool. - One of: git-grep, ag, git-grep-plus-ag, rg, gnu-grep, grep. -The returned plist has: -- :parse : function: response parser. -- :generate : function: search command string generator. These functions - accept 6 arguments: look-for, cur-file, proj, - regexes, lang, exclude-paths. -- :installed : predicate installed? function: is searcher installed? -- :searcher : symbol : the SEARCHER (see above)." - (cond ((equal 'git-grep searcher) - `(:parse ,'dumb-jump-parse-git-grep-response - :generate ,'dumb-jump-generate-git-grep-command - :installed ,'dumb-jump-git-grep-installed? - :searcher ,searcher)) - ((equal 'ag searcher) - `(:parse ,'dumb-jump-parse-ag-response - :generate ,'dumb-jump-generate-ag-command - :installed ,'dumb-jump-ag-installed? - :searcher ,searcher)) - ((equal 'git-grep-plus-ag searcher) - `(:parse ,'dumb-jump-parse-ag-response - :generate ,'dumb-jump-generate-git-grep-plus-ag-command - :installed ,'dumb-jump-git-grep-plus-ag-installed? - :searcher ,searcher)) - ((equal 'rg searcher) - `(:parse ,'dumb-jump-parse-rg-response - :generate ,'dumb-jump-generate-rg-command - :installed ,'dumb-jump-rg-installed? - :searcher ,searcher)) - ((equal 'gnu-grep searcher) - `(:parse ,'dumb-jump-parse-grep-response - :generate ,'dumb-jump-generate-gnu-grep-command - :installed ,'dumb-jump-grep-installed? - :searcher ,searcher)) - ((equal 'grep searcher) - `(:parse ,'dumb-jump-parse-grep-response - :generate ,'dumb-jump-generate-grep-command - :installed ,'dumb-jump-grep-installed? - :searcher ,searcher)))) - -(defun dumb-jump-selected-grep-variant (&optional proj-root) - "Return search tool for current project or specified PROJ-ROOT. -Select search tool according to `dumb-jump-prefer-searcher' choice and its -possible `dumb-jump-force-searcher' overriding." - (let ((searcher-found nil)) - (cond - ;; If `dumb-jump-force-searcher' is not nil then use the searcher - ;; identified by that user-option if possible. - (dumb-jump-force-searcher - (cond - ;; Honour forced choices, they might be identified in dir-local file - ((member dumb-jump-force-searcher '(ag - rg - grep - gnu-grep - git-grep - git-grep-plus-ag)) - (setq searcher-found dumb-jump-force-searcher)) - ;; Select search tool identified by calling the user-specified function - ;; which takes the directory. - ((and (symbolp dumb-jump-force-searcher) - (fboundp dumb-jump-force-searcher)) - (let ((user-selected-search-tool - (funcall dumb-jump-force-searcher (or proj-root - (buffer-file-name))))) - (when user-selected-search-tool - (setq searcher-found user-selected-search-tool)))) - ;; Check if project root or current directory is inside one of the - ;; project roots specified - ((and (listp dumb-jump-force-searcher) - proj-root - (dumb-jump-git-grep-installed?) - (member (dumb-jump-get-project-root proj-root) - dumb-jump-force-searcher) - (file-exists-p (expand-file-name ".git" proj-root))) - ;; [:todo 2026-01-07, by Pierre Rouleau: add support for git grep + ag??] - (setq searcher-found 'git-grep))))) - - (unless searcher-found - ;; When `dumb-jump-force-searcher' does not override the selection, then - ;; select the searcher based on the value of `dumb-jump-force-searcher'. - (cond - ;; If `dumb-jump-prefer-searcher' identifies a searcher use it if it's - ;; installed. - ((and dumb-jump-prefer-searcher - (funcall (plist-get (dumb-jump-generators-by-searcher - dumb-jump-prefer-searcher) - :installed))) - (setq searcher-found dumb-jump-prefer-searcher)) - - ;; Fallback searcher order. - ((dumb-jump-ag-installed?) (setq searcher-found 'ag)) - ((dumb-jump-rg-installed?) (setq searcher-found 'rg)) - ((eq (dumb-jump-grep-installed?) 'gnu) (setq searcher-found 'gnu-grep)) - (t (setq searcher-found 'grep)))) - ;; return the symbol identifying the selected search tool - searcher-found)) - -(defun dumb-jump-pick-grep-variant (&optional proj-root) - "Get action search property list for current project or specified PROJ-ROOT. -Select search tool according to `dumb-jump-prefer-searcher' choice and its -possible `dumb-jump-force-searcher' overriding." - (dumb-jump-generators-by-searcher - (dumb-jump-selected-grep-variant proj-root))) - -(defun dumb-jump-shell-command-switch () - "Return current shell command switch prevent loading shell profile/RC. -Using that switch speeds shell command execution. -The `shell-file-name' identifies the current shell." - (let ((base-name (downcase (file-name-base shell-file-name)))) - (cond - ((or (string-equal "zsh" base-name) - (string-equal "csh" base-name) - (string-equal "tcsh" base-name)) - "-icf") - ;; - ((string-equal "bash" base-name) - "-c") - ;; - (t - shell-command-switch)))) - -(defconst dumb-jump--case-insensitive-languages - '("commonlisp" - "cobol") - "List of case insensitive languages.") - -;; TODO: rename dumb-jump-run-definition-command -(defun dumb-jump-run-command (look-for proj regexes lang - exclude-args cur-file - line-num parse-fn generate-fn) - "Run the grep search command based on LOOK-FOR in the directory TOSEARCH. -The parameters are: -- LOOK-FOR: string: searched symbol -- PROJ: string: directory path -- REGEXES: list of strings: each string is a dumb-jump generic regular - expression. -- LANG: string: handled language name specified in `dumb-jump-find-rules'. -- EXCLUDE-ARGS: -- CUR-FILE string: current file name. -- LINE-NUM: integer: current line number. -- PARSE-FN: the parse function; something like `dumb-jump-parse-grep-response'. -- GENERATE-FN: the generate function; - something like `dumb-jump-generate-ag-command'." - (let* ((proj-root (if (file-remote-p proj) - (directory-file-name - (tramp-file-name-localname (tramp-dissect-file-name proj))) - proj)) - (cmd (funcall generate-fn look-for cur-file proj-root regexes lang exclude-args)) - (shell-command-switch (dumb-jump-shell-command-switch)) - (rawresults "")) - - (dumb-jump-debug-message cmd) - (setq rawresults (shell-command-to-string cmd)) - (dumb-jump-debug-message rawresults) - (when (string-match-p "^PCRE2 is not available" rawresults) - (dumb-jump-message "dumb-jump: Ripgrep PCRE2 support is not available. Install ripgrep with PCRE2 support or customize `dumb-jump-rg-search-args' to remove \"--pcre2\".") - (dumb-jump-env-problem "Ripgrep PCRE2 support is not available in the current build.")) - (when (and (string-blank-p rawresults) - dumb-jump-fallback-search - (not (eq dumb-jump--search-mode 'references))) - (setq regexes (list dumb-jump-fallback-regex)) - (setq cmd (funcall generate-fn - look-for cur-file - proj-root regexes - lang exclude-args)) - (dumb-jump-debug-message cmd) - (setq rawresults (shell-command-to-string cmd)) - (dumb-jump-debug-message rawresults)) - (unless (string-blank-p (or cmd "")) - (let ((results (funcall parse-fn rawresults cur-file line-num)) - (ignore-case (member lang dumb-jump--case-insensitive-languages))) - (seq-filter (lambda (it) - (dumb-jump--contains-p look-for - (plist-get it :context) ignore-case)) - results))))) - -(defun dumb-jump-parse-response-line (resp-line cur-file) - "Parse a search program's single RESP-LINE for CUR-FILE. -Return a list of (path line context)." - (let* ((parts (seq-remove (lambda (it) (string= it "")) - (dumb-jump--split "\\(?:^\\|:\\)[0-9]+:" resp-line))) - (line-num-raw (dumb-jump--match "\\(?:^\\|:\\)\\([0-9]+\\):" resp-line)) - (line-num (and line-num-raw - (> (length line-num-raw) 1) - (nth 1 line-num-raw)))) - - (cond - ;; fixes rare bug where context is blank but file is defined "/somepath/file.txt:14:" - ;; OR: (and (= (length parts) 1) (file-name-exists (nth 0 parts))) - ((dumb-jump--match ":[0-9]+:$" resp-line) - nil) - ((and parts line-num) - (if (= (length parts) 2) - (list (let ((path (expand-file-name (nth 0 parts)))) - (if (file-name-absolute-p (nth 0 parts)) - path - (file-relative-name path))) - line-num (nth 1 parts)) - ; this case is when they are searching a particular file... - (list (let ((path (expand-file-name cur-file))) - (if (file-name-absolute-p cur-file) - path - (file-relative-name path))) - line-num (nth 0 parts))))))) - -;; -- -;; Parse Search Tool Results: indirectly called by `dumb-jump-run-command' -;; ----------------------------------------------------------------------- -;; - `dumb-jump-parse-grep-response' -;; - `dumb-jump-parse-ag-response' -;; - `dumb-jump-parse-rg-response' -;; - `dumb-jump-parse-git-grep-response' -;; - `dumb-jump-parse-response-lines' - -(defun dumb-jump-parse-response-lines (parsed cur-file cur-line-num) - "Turn PARSED response lines into a list of property lists. -Using CUR-FILE and CUR-LINE-NUM to exclude jump origin." - (let* ((records (mapcan - (lambda (it) - (when it - (let* ((line-num (string-to-number (nth 1 it))) - (diff (- cur-line-num line-num))) - (list `(:path ,(nth 0 it) - :line ,line-num - :context ,(nth 2 it) - :diff ,diff))))) - parsed)) - (results (delq nil records))) - (seq-filter - (lambda (it) - (not (and - (string= (plist-get it :path) cur-file) - (= (plist-get it :line) cur-line-num)))) - results))) - -(defun dumb-jump-parse-grep-response (resp cur-file cur-line-num) - "Parse raw grep search response RESP into a list of plists. -- CUR-FILE: current file. -- CUR-LINE-NUM: current line number." - (let* ((resp-no-warnings - (seq-filter (lambda (it) - (and (not (string-prefix-p "grep:" it)) - (not (dumb-jump--contains-p "No such file or" it)))) - (dumb-jump--split "\n" (dumb-jump--trim resp)))) - (parsed (mapcar (lambda (it) (dumb-jump-parse-response-line it cur-file)) - resp-no-warnings))) - (dumb-jump-parse-response-lines parsed cur-file cur-line-num))) - -(defun dumb-jump--clean-wsl-response (resp) - "Clean up RESP for Windows WSL/UNC path issues. -Filters CMD.exe UNC path warnings and fixes /wsl$/ to //wsl$/." - (let* ((cleaned (replace-regexp-in-string - "CMD\\.EXE was started with the above path as the current directory\\.\nUNC paths are not supported\\..*?\n" - "" resp)) - (fixed (replace-regexp-in-string "^/wsl\\$/" "//wsl$/" cleaned))) - (replace-regexp-in-string "\n/wsl\\$/" "\n//wsl$/" fixed))) - -(defun dumb-jump-parse-ag-response (resp cur-file cur-line-num) - "Parse raw ag search response RESP into a list of plists. -- CUR-FILE: current file. -- CUR-LINE-NUM: current line number." - (let* ((cleaned (dumb-jump--clean-wsl-response resp)) - (resp-lines (dumb-jump--split "\n" (dumb-jump--trim cleaned))) - (parsed (mapcar (lambda (it) (dumb-jump-parse-response-line it cur-file)) - resp-lines))) - (dumb-jump-parse-response-lines parsed cur-file cur-line-num))) - -(defun dumb-jump-parse-rg-response (resp cur-file cur-line-num) - "Parse raw rg search response RESP into a list of plists. -- CUR-FILE: current file. -- CUR-LINE-NUM: current line number." - (let* ((resp-lines (dumb-jump--split "\n" (dumb-jump--trim resp))) - (parsed (mapcar (lambda (it) (dumb-jump-parse-response-line it cur-file)) - resp-lines))) - (dumb-jump-parse-response-lines parsed cur-file cur-line-num))) - -(defun dumb-jump-parse-git-grep-response (resp cur-file cur-line-num) - "Parse raw git grep response RESP into a list of plists. -- CUR-FILE: current file. -- CUR-LINE-NUM: current line number." - (let* ((resp-lines (dumb-jump--split "\n" (dumb-jump--trim resp))) - (parsed (mapcar (lambda (it) (dumb-jump-parse-response-line it cur-file)) - resp-lines))) - (dumb-jump-parse-response-lines parsed cur-file cur-line-num))) - -;; -- - -(defun dumb-jump-re-match (re s) - "Does regular expression RE match string S. If RE is nil return nil." - (when (and re s) - (dumb-jump--match re s))) - -(defun dumb-jump-get-ctx-type-by-language (lang pt-ctx) - "Detect the type of context by the language LANG and its context PT-CTX. -PT-CTX is assumed to be a property list with the :left and :right attributes -that are both strings." - (let* ((contexts (seq-filter (lambda (it) - (string= (plist-get it ':language) lang)) - dumb-jump-language-contexts)) - (usable-ctxs - (when (> (length contexts) 0) - (seq-filter (lambda (it) - (and (or (null (plist-get it :left)) - (dumb-jump-re-match (plist-get it :left) - (plist-get pt-ctx :left))) - (or (null (plist-get it :right)) - (dumb-jump-re-match (plist-get it :right) - (plist-get pt-ctx :right))))) - contexts))) - (use-ctx (= (length (seq-filter - (lambda (it) - (string= (plist-get it ':type) - (and usable-ctxs (plist-get (car usable-ctxs) :type)))) - usable-ctxs)) - (length usable-ctxs)))) - - (when (and usable-ctxs use-ctx) - (plist-get (car usable-ctxs) :type)))) - -(defun dumb-jump-get-ext-includes (language) - "Return the --include grep argument of file extensions for LANGUAGE." - (let ((exts (dumb-jump-get-file-exts-by-language language))) - (dumb-jump-arg-joiner - "--include" - (mapcar (lambda (it) (format "\\*.%s" it)) exts)))) - -(defun dumb-jump-arg-joiner (prefix values) - "Helper to generate command arg with its PREFIX for each value in VALUES." - (let* ((normalized-values (mapcar (lambda (it) (dumb-jump--trim (or it ""))) values)) - (non-empty-values (seq-filter (lambda (it) (> (length it) 0)) normalized-values)) - (args (dumb-jump--join (format " %s " prefix) non-empty-values))) - (if non-empty-values - (format " %s %s " prefix args) - ""))) - -(defun dumb-jump-get-contextual-regexes (lang ctx-type searcher) - "Get list of search regular expressions by LANG and CTX-TYPE. -The arguments are: -- LANG: string: the language. -- CTX-TYPE: variable, function, etc. -- SEARCHER: symbol: the name of the search tool. - One of: git-grep, ag, git-grep-plus-ag, rg, gnu-grep, grep." - (let* ((raw-rules (dumb-jump-get-rules-by-language lang searcher)) - (ctx-type (unless dumb-jump-ignore-context ctx-type)) - (ctx-rules - (if ctx-type - (seq-filter (lambda (it) (string= (plist-get it :type) ctx-type)) raw-rules) - raw-rules)) - (rules (or ctx-rules raw-rules)) - (regexes (mapcar (lambda (it) (plist-get it :regex)) rules))) - regexes)) - -(defun dumb-jump-populate-regex (it look-for variant) - "Populate IT regex template with LOOK-FOR for the specific search VARIANT. -Replace the dumb-jump generic regular expression meta concepts with the -one required for the search variant tool. -The arguments are: -- IT : string: the dumb-jump generic regular expression. -- LOOK-FOR: string: the searched item. -- VARIANT : symbol: the search tool variant, - one of: ag, rg, grep, gnu-grep, git-grep-plus-ag, git-grep." - (let ((boundary - (cond ((eq variant 'rg) dumb-jump-rg-word-boundary) - ((eq variant 'ag) dumb-jump-ag-word-boundary) - ((eq variant 'git-grep-plus-ag) dumb-jump-ag-word-boundary) - ((eq variant 'git-grep) dumb-jump-git-grep-word-boundary) - (t dumb-jump-grep-word-boundary)))) - (let ((text it)) - (setq text (dumb-jump--replace "\\j" boundary text)) - (when (dumb-jump-use-space-bracket-exp-for variant) - (setq text (dumb-jump--replace "\\s" "[[:space:]]" text))) - (setq text (dumb-jump--replace "JJJ" (regexp-quote look-for) text)) - text))) - -(defun dumb-jump-populate-regexes (look-for regexes variant) - "Return list of VARIANT specific regexes from the dumb-jump generic REGEXES. -Update the generic regexes, populate the target identified in LOOK-FOR. -The arguments are: -- LOOK-FOR: string: the searched item. -- REGEXES: list of strings: each string is a dumb-jump generic regular - expression. -- VARIANT: symbol: the search tool variant, - one of: ag, rg, git-grep-plus-ag, git-grep." - (mapcar - (lambda (it) - (dumb-jump-populate-regex it look-for variant)) - regexes)) - -(defun dumb-jump-pcre-to-emacs (regex) - "Convert a PCRE-style REGEX string to Emacs regex syntax. -In PCRE and Emacs, +, ?, *, ., ^, $, [ are special without escaping. -But (, ), |, {, } differ: special unescaped in PCRE, special escaped in Emacs. -This function swaps the literal/special meaning of (, ), |, {, and }." - (let ((i 0) - (len (length regex)) - (out (list))) - (while (< i len) - (let ((ch (aref regex i))) - (cond - ;; Backslash sequence - ((and (= ch ?\\) (< (1+ i) len)) - (let ((next (aref regex (1+ i)))) - (cond - ((memq next '(?\( ?\) ?| ?{ ?})) - ;; \X (literal in PCRE) → X (literal in Emacs) - (push (char-to-string next) out) - (setq i (+ i 2))) - (t - ;; Other backslash sequences (\b, \w, \+, \?, etc.) pass through - (push (substring regex i (+ i 2)) out) - (setq i (+ i 2)))))) - ;; (? prefixed groups: (?:, (?!, (?=, (?<=, (?<!, etc. - ;; Emit \(? which in Emacs starts a shy group for (?: - ;; and produces a valid (if semantically different) group for others. - ((and (= ch ?\() - (< (1+ i) len) - (= (aref regex (1+ i)) ??)) - (push "\\(?" out) - (setq i (+ i 2))) - ;; Unescaped chars that differ between PCRE and Emacs - ((= ch ?\() (push "\\(" out) (cl-incf i)) - ((= ch ?\)) (push "\\)" out) (cl-incf i)) - ((= ch ?|) (push "\\|" out) (cl-incf i)) - ((= ch ?{) (push "\\{" out) (cl-incf i)) - ((= ch ?}) (push "\\}" out) (cl-incf i)) - ;; Everything else passes through (including +, ?, *, ., etc.) - (t (push (char-to-string ch) out) (cl-incf i))))) - (apply #'concat (nreverse out)))) - -(defun dumb-jump-populate-regex-for-emacs (regex look-for) - "Populate dumb-jump generic REGEX to match LOOK-FOR with `string-match-p'. -Replaces dumb-jump meta-patterns and converts PCRE syntax to Emacs regex. -The \\=\\j boundary is replaced after PCRE conversion with a character class -matching the tool boundaries: not followed by [a-zA-Z0-9?*-]." - (let ((text regex)) - (setq text (dumb-jump--replace "\\s" "[[:space:]]" text)) - (setq text (dumb-jump--replace "JJJ" (regexp-quote look-for) text)) - (setq text (dumb-jump-pcre-to-emacs text)) - ;; Replace \j after PCRE conversion since the replacement is Emacs syntax. - ;; Mirrors the tool boundaries: (?![a-zA-Z0-9\?\*-]) for ag, - ;; ($|[^a-zA-Z0-9\?\*-]) for rg/grep. - (setq text (dumb-jump--replace "\\j" "\\(?:[^a-zA-Z0-9?*-]\\|$\\)" text)) - text)) - -(defun dumb-jump-filter-definition-results (results lang look-for _searcher) - "Remove from RESULTS any that match definition patterns for LANG. -LOOK-FOR is the symbol being searched. _SEARCHER is unused but kept for API." - (let* ((raw-rules (seq-remove - (lambda (it) (plist-get it :skip-ref-filter)) - (seq-filter (lambda (it) - (string= (plist-get it :language) lang)) - dumb-jump-find-rules))) - (def-regexes (seq-uniq (mapcar (lambda (it) (plist-get it :regex)) raw-rules))) - (emacs-regexes (mapcar (lambda (re) - (dumb-jump-populate-regex-for-emacs re look-for)) - def-regexes))) - (seq-filter - (lambda (r) - (let ((ctx (plist-get r :context))) - (not (seq-some (lambda (re) - (condition-case nil - (string-match-p re ctx) - (invalid-regexp nil))) - emacs-regexes)))) - results))) - -;; -- -(defun dumb-jump-generate-ag-command (look-for - cur-file proj - regexes lang - exclude-paths) - "Return the ag command to search for LOOK-FOR in the PROJ directory. -The arguments are: -- LOOK-FOR: string: the searched item. -- CUR-FILE: string: current file name. Used to check if it's compressed. -- PROJ: string: project root path. -- REGEXES: list of strings: each string is a dumb-jump generic regular - expression. -- LANG: string: handled language. -- EXCLUDE-PATHS: list of strings: directories to exclude from search." - (let* ((filled-regexes (dumb-jump-populate-regexes look-for regexes 'ag)) - (agtypes (dumb-jump-get-ag-type-by-language lang)) - (lang-exts (dumb-jump-get-file-exts-by-language lang)) - (proj-dir (file-name-as-directory proj)) - ;; TODO: --search-zip always? in case the include is the in gz area - ;; like emacs lisp code. - (cmd (concat dumb-jump-ag-cmd - " --nocolor --nogroup" - (if (member lang dumb-jump--case-insensitive-languages) - " --ignore-case" - "") - (if (string-suffix-p ".gz" cur-file) - " --search-zip" - "") - (unless (string-blank-p dumb-jump-ag-search-args) - (concat " " dumb-jump-ag-search-args)) - (if agtypes - (dumb-jump--join "" (mapcar (lambda (it) (format " --%s" it)) agtypes)) - (concat " -G '(" - (dumb-jump--join "|" - (mapcar (lambda (it) (format "\\.%s" it)) lang-exts)) - ")$'")))) - (exclude-args (dumb-jump-arg-joiner - "--ignore-dir" - (mapcar - (lambda (it) - (shell-quote-argument (dumb-jump--replace proj-dir "" it))) - exclude-paths))) - (regex-args (shell-quote-argument (dumb-jump--join "|" filled-regexes)))) - (if (null regexes) - "" - (dumb-jump-concat-command cmd exclude-args "--" regex-args (shell-quote-argument proj))))) - -;; -- -(defun dumb-jump-get-git-grep-files-matching-symbol (symbol proj-root) - "Return a list of file names in PROJ-ROOT holding the literal SYMBOL. -Search for matching files using git grep." - (let* ((cmd (format "git grep --full-name -F -c %s %s" - (shell-quote-argument symbol) (shell-quote-argument proj-root))) - (result (dumb-jump--trim (shell-command-to-string cmd))) - ;; result: '\n\ separated lines of: "path-name:count" - ;; extract the name of files and return them in a list. - (matched-files (mapcar - (lambda (it) - (cl-first (dumb-jump--split ":" it))) - (dumb-jump--split "\n" result)))) - matched-files)) - -(defun dumb-jump-format-files-as-ag-arg (files proj-root) - "Take a list of FILES and their PROJ-ROOT and return a `ag -G` argument." - (format "'(%s)'" (dumb-jump--join "|" (mapcar (lambda (it) - (file-relative-name - (expand-file-name it proj-root))) - files)))) - -(defun dumb-jump-get-git-grep-files-matching-symbol-as-ag-arg (symbol proj-root) - "Return optimized `ag -G` argument string to search for SYMBOL in PROJ-ROOT. -Limit the ag search to files matching SYMBOL in PROJ-ROOT by first getting the -list of files with `git grep`. -The string does not contain the `ag -G`, just its argument." - (dumb-jump-format-files-as-ag-arg - (dumb-jump-get-git-grep-files-matching-symbol symbol proj-root) - proj-root)) - - -;; git-grep plus ag only recommended for huge repos like the linux kernel. -(defun dumb-jump-generate-git-grep-plus-ag-command (look-for - cur-file proj - regexes lang - exclude-paths) - "Return the ag command to search for LOOK-FOR in the PROJ directory. -Using ag to search only the files found via git-grep literal symbol search. -Note: Only recommended for huge repos like the linux kernel. -The arguments are: -- LOOK-FOR: string: the searched text -- CUR-FILE: -- PROJ: string: project root path. -- REGEXES: list of strings: each string is a dumb-jump generic regular - expression. -- LANG: string: handled language. -- EXCLUDE_PATHS: list of strings: directories to exclude from search." - (let* ((filled-regexes (dumb-jump-populate-regexes look-for regexes 'ag)) - (proj-dir (file-name-as-directory proj)) - (ag-files-arg - (dumb-jump-get-git-grep-files-matching-symbol-as-ag-arg - look-for proj-dir)) - (cmd (concat dumb-jump-ag-cmd - " --nocolor --nogroup" - (if (member lang dumb-jump--case-insensitive-languages) - " --ignore-case" - "") - (if (string-suffix-p ".gz" cur-file) - " --search-zip" - "") - " -G " ag-files-arg - " ")) - (exclude-args (dumb-jump-arg-joiner - "--ignore-dir" - (mapcar - (lambda (it) - (shell-quote-argument (dumb-jump--replace proj-dir "" it))) - exclude-paths))) - (regex-args (shell-quote-argument (dumb-jump--join "|" filled-regexes)))) - (if (null regexes) - "" - (dumb-jump-concat-command cmd exclude-args regex-args (shell-quote-argument proj))))) - -;; -- -(defun dumb-jump-generate-rg-command (look-for - _cur-file proj - regexes lang - exclude-paths) - "Return the rg command to search for LOOK-FOR in the PROJ directory. -The arguments are: -- LOOK-FOR: string: the searched item. -- CUR-FILE: -- PROJ: string: project root path. -- REGEXES: list of strings: each string is a dumb-jump generic regular - expression. -- LANG: string: handled language. -- EXCLUDE-PATHS: list of strings: directories to exclude from search." - (let* ((filled-regexes (dumb-jump-populate-regexes look-for regexes 'rg)) - (rgtypes (dumb-jump-get-rg-type-by-language lang)) - (rg-nontype-exts (dumb-jump-get-rg-nontype-exts-by-language lang)) - (proj-dir (file-name-as-directory proj)) - (cmd (concat dumb-jump-rg-cmd - " --color never --no-heading --line-number -U" - (if (member lang dumb-jump--case-insensitive-languages) - " --ignore-case" - "") - (unless (string-blank-p dumb-jump-rg-search-args) - (concat " " dumb-jump-rg-search-args)) - (dumb-jump--join "" (mapcar (lambda (it) (format " --type %s" it)) rgtypes)) - (if rgtypes "" - (dumb-jump--join "" (mapcar (lambda (it) (format " -g \"*.%s\"" it)) rg-nontype-exts))))) - (exclude-args (dumb-jump-arg-joiner - "-g" - (mapcar - (lambda (it) - (shell-quote-argument - (concat "!" (dumb-jump--replace proj-dir "" it)))) - exclude-paths))) - (regex-args (shell-quote-argument (dumb-jump--join "|" filled-regexes)))) - (if (null regexes) - "" - (dumb-jump-concat-command cmd exclude-args "--" regex-args (shell-quote-argument proj))))) - -(defun dumb-jump-generate-git-grep-command (look-for - cur-file proj - regexes lang - exclude-paths) - "Return the git grep command to search for LOOK-FOR in the PROJ directory. -The arguments are: -- LOOK-FOR: string: the searched text -- CUR-FILE: string: current file name. Used to check the file extension and - restrict search to file extensions of the matching LANG. -- PROJ: string: project root path. -- REGEXES: list of strings: each string is a dumb-jump generic regular - expression. -- LANG: string: handled language. -- EXCLUDE_PATHS:list of strings: directories to exclude from search." - (let* ((filled-regexes (dumb-jump-populate-regexes look-for regexes 'git-grep)) - (ggtypes (when (file-name-extension cur-file) - (dumb-jump-get-git-grep-type-by-language lang))) - (cmd (concat dumb-jump-git-grep-cmd - " --color=never --line-number" - (if (member lang dumb-jump--case-insensitive-languages) - " --ignore-case" - "") - (when dumb-jump-git-grep-search-untracked - " --untracked") - (unless (string-blank-p dumb-jump-git-grep-search-args) - (concat " " dumb-jump-git-grep-search-args)) - " -E")) - (fileexps (dumb-jump--join " " - (or - (mapcar (lambda (it) - (shell-quote-argument - (format "%s/*.%s" proj it))) - ggtypes) - '(":/")))) - (exclude-args (dumb-jump--join " " - (mapcar (lambda (it) - (shell-quote-argument - (concat ":(exclude)" it))) - exclude-paths))) - (regex-args (shell-quote-argument (dumb-jump--join "|" filled-regexes)))) - (if (null regexes) - "" - (dumb-jump-concat-command cmd regex-args "--" fileexps exclude-args)))) - -(defun dumb-jump-generate-grep-command (look-for - cur-file proj - regexes lang - exclude-paths) - "Return the grep command to search for LOOK-FOR in PROJ directory. -The arguments are: -- LOOK-FOR: string: the searched item. -- CUR-FILE: string: current file name. Used to check if it's compressed. -- PROJ: string: project root path. -- REGEXES: list of strings: each string is a dumb-jump generic regular - expression. -- LANG: string: handled language. -- EXCLUDE-PATHS: list of strings: directories to exclude from search." - (let* ((filled-regexes - (mapcar (lambda (it) (shell-quote-argument it)) - (dumb-jump-populate-regexes look-for regexes 'grep))) - (cmd (concat - (if (eq system-type 'windows-nt) - "" - (concat dumb-jump-grep-prefix " ")) - (if (string-suffix-p ".gz" cur-file) - dumb-jump-zgrep-cmd - dumb-jump-grep-cmd))) - (case-args (if (member lang dumb-jump--case-insensitive-languages) - " --ignore-case" - "")) - (proj-dir (file-name-as-directory proj)) - (exclude-args (dumb-jump-arg-joiner - "--exclude-dir" - (mapcar - (lambda (it) - (dumb-jump--replace proj-dir "" it)) - exclude-paths))) - (include-args (dumb-jump-get-ext-includes lang)) - (regex-args (dumb-jump-arg-joiner "-e" filled-regexes))) - (if (null regexes) - "" - (dumb-jump-concat-command cmd dumb-jump-grep-args - case-args exclude-args - include-args regex-args (shell-quote-argument proj))))) - -(defun dumb-jump-generate-gnu-grep-command (look-for - cur-file proj - regexes lang - _exclude-paths) - "Return the GNU grep command to search for LOOK-FOR in PROJ directory. -The arguments are: -- LOOK-FOR: string: the searched item. -- CUR-FILE: string: current file name. Used to check if it's compressed. -- PROJ: string: project root path. -- REGEXES: list of strings: each string is a dumb-jump generic regular - expression. -- LANG: string: handled language. -- EXCLUDE-PATHS: list of strings: directories to exclude from search." - (let* ((filled-regexes - (mapcar (lambda (it) (shell-quote-argument it)) - (dumb-jump-populate-regexes look-for regexes 'gnu-grep))) - (cmd (concat - (if (eq system-type 'windows-nt) - "" - (concat dumb-jump-grep-prefix " ")) - (if (string-suffix-p ".gz" cur-file) - dumb-jump-zgrep-cmd - dumb-jump-grep-cmd))) - (case-args (if (member lang dumb-jump--case-insensitive-languages) - " --ignore-case" - "")) - ;; TODO: GNU grep doesn't support these, so skip them - (exclude-args "") - (include-args "") - (regex-args (dumb-jump-arg-joiner "-e" filled-regexes))) - (if (null regexes) - "" - (dumb-jump-concat-command cmd dumb-jump-gnu-grep-args - case-args exclude-args - include-args regex-args (shell-quote-argument proj))))) - -;; --------------------------------------------------------------------------- - -(defun dumb-jump-concat-command (&rest parts) - "Concat the PARTS of a command if each part has a length." - (let* ((normalized-parts (mapcar (lambda (it) (dumb-jump--trim (or it ""))) parts)) - (non-empty-parts (seq-filter (lambda (it) (> (length it) 0)) normalized-parts))) - (dumb-jump--join " " non-empty-parts))) - -(defun dumb-jump-get-file-exts-by-language (language) - "Return list of file extensions for a LANGUAGE." - (mapcar (lambda (it) (plist-get it :ext)) - (seq-filter (lambda (it) (string= (plist-get it :language) language)) - dumb-jump-language-file-exts))) - -(defun dumb-jump-get-ag-type-by-language (language) - "Return list of ag type argument for a LANGUAGE." - (seq-uniq (mapcar (lambda (it) (plist-get it :agtype)) - (seq-filter (lambda (it) - (and - (plist-get it :agtype) - (string= (plist-get it :language) language))) - dumb-jump-language-file-exts)))) - -(defun dumb-jump-get-rg-type-by-language (language) - "Return list of rg type argument for a LANGUAGE." - (seq-uniq (mapcar (lambda (it) (plist-get it :rgtype)) - (seq-filter (lambda (it) - (and - (plist-get it :rgtype) - (string= (plist-get it :language) language))) - dumb-jump-language-file-exts)))) - -(defun dumb-jump-get-rg-nontype-exts-by-language (language) - "Return list of file extensions for a LANGUAGE that have no rgtype. -These extensions need to be explicitly added as glob patterns since -they are not covered by ripgrep's built-in type definitions." - (seq-uniq (mapcar (lambda (it) (plist-get it :ext)) - (seq-filter (lambda (it) - (and - (plist-get it :ext) - (null (plist-get it :rgtype)) - (string= (plist-get it :language) language))) - dumb-jump-language-file-exts)))) - -(defun dumb-jump-get-git-grep-type-by-language (language) - "Return list of git grep type argument for a LANGUAGE." - (seq-uniq (mapcar (lambda (it) (plist-get it :ext)) - (seq-filter (lambda (it) - (and - (plist-get it :ext) - (string= (plist-get it :language) language))) - dumb-jump-language-file-exts)))) - -(defun dumb-jump-get-rules-by-language (language searcher) - "Return a list of rules for the LANGUAGE by SEARCHER." - (let* ((searcher-str (cond ((eq 'git-grep searcher) "git-grep") - ((eq 'rg searcher) "rg") - ((eq 'ag searcher) "ag") - ((eq 'git-grep-plus-ag searcher) "ag") - (t "grep"))) - (results (seq-filter (lambda (it) - (and - (string= (plist-get it ':language) language) - (member searcher-str (plist-get it ':supports)))) - dumb-jump-find-rules))) - (if dumb-jump-functions-only - (seq-filter (lambda (it) (string= (plist-get it ':type) "function")) results) - results))) - -;;;###autoload -(define-minor-mode dumb-jump-local-mode - "Buffer-local minor mode for jumping to variable and function definitions. -Use this to selectively enable dumb-jump in specific major modes, e.g.: - (add-hook \\='python-mode-hook #\\='dumb-jump-local-mode) -For enabling globally, use `dumb-jump-mode' instead." - :global nil - :keymap dumb-jump-mode-map) - -;;;###autoload -(define-minor-mode dumb-jump-mode - "Minor mode for jumping to variable and function definitions." - ;; Note: independent of the Emacs xref interface. - :global t - :keymap dumb-jump-mode-map) - - -;; ----------------------------------------------------------------------------- -;;; Xref Backend - -(unless dumb-jump-disable-obsolete-warnings - (dolist (obsolete - '(dumb-jump-mode - dumb-jump-go - dumb-jump-go-prefer-external-other-window - dumb-jump-go-prompt - dumb-jump-quick-look - dumb-jump-go-other-window - dumb-jump-go-current-window - dumb-jump-go-prefer-external)) - (make-obsolete - obsolete - (format "`%s' has been obsoleted by the xref interface." - obsolete) - "2020-06-26")) - (make-obsolete 'dumb-jump-back - "`dumb-jump-back' has been obsoleted by `xref-pop-marker-stack'." - "2020-06-26")) - -(cl-defmethod xref-backend-identifier-at-point ((_backend (eql dumb-jump))) - (let ((bounds (bounds-of-thing-at-point 'symbol))) - (and bounds (let* ((ident (dumb-jump-get-point-symbol)) - (start (car bounds)) - (col (- start (line-beginning-position))) - (line (dumb-jump-get-point-line)) - (ctx (dumb-jump-get-point-context line ident col))) - (propertize ident :dumb-jump-ctx ctx))))) - -(cl-defmethod xref-backend-definitions ((_backend (eql dumb-jump)) - entered-name) - (let* ((info (dumb-jump-get-results entered-name)) - (results (plist-get info :results)) - (look-for (or entered-name (plist-get info :symbol))) - (proj-root (plist-get info :root)) - (issue (plist-get info :issue)) - (lang (plist-get info :lang)) - (processed (dumb-jump-process-results - results - (plist-get info :file) - proj-root - (plist-get info :ctx-type) - look-for - nil - nil - lang)) - (results (plist-get processed :results)) - (do-var-jump (plist-get processed :do-var-jump)) - (var-to-jump (plist-get processed :var-to-jump)) - (match-cur-file-front (plist-get processed :match-cur-file-front))) - - (dumb-jump-debug-message - look-for - (plist-get info :ctx-type) - var-to-jump - (pp-to-string match-cur-file-front) - (pp-to-string results) - match-cur-file-front - proj-root - (plist-get info :file)) - (cond ((eq issue 'nogrep) - (dumb-jump-message "Please install ag, rg, git grep or grep!")) - ((eq issue 'nosymbol) - (dumb-jump-message "No symbol under point.")) - ((string-suffix-p " file" lang) - (dumb-jump-message "Could not find rules for '%s'." lang)) - ((= (length results) 0) - (dumb-jump-message "'%s' %s %s declaration not found." - look-for - (if (string-blank-p (or lang "")) - "with unknown language so" - lang) - (plist-get info :ctx-type))) - (t (mapcar (lambda (res) - (with-no-warnings - (xref-make - (plist-get res :context) - (xref-make-file-location - (let* ((path (plist-get res :path)) - (remote-prefix (file-remote-p default-directory))) - (if remote-prefix - (if (file-name-absolute-p path) - (concat remote-prefix path) - (concat default-directory path)) - (expand-file-name path))) - (plist-get res :line) - 0)))) - (if do-var-jump - (list var-to-jump) - match-cur-file-front)))))) - -(cl-defmethod xref-backend-references ((_backend (eql dumb-jump)) - entered-name) - (let* ((dumb-jump--search-mode 'references) - (info (dumb-jump-get-results entered-name)) - (results (plist-get info :results)) - (look-for (or entered-name (plist-get info :symbol))) - (proj-root (plist-get info :root)) - (issue (plist-get info :issue)) - (lang (plist-get info :lang)) - (processed (dumb-jump-process-results - results - (plist-get info :file) - proj-root - (plist-get info :ctx-type) - look-for - nil - nil - lang)) - (results (plist-get processed :results)) - (match-cur-file-front (plist-get processed :match-cur-file-front))) - - (cond ((eq issue 'nogrep) - (dumb-jump-message "Please install ag, rg, git grep or grep!")) - ((eq issue 'nosymbol) - (dumb-jump-message "No symbol under point.")) - ((string-suffix-p " file" lang) - (dumb-jump-message "Could not find rules for '%s'." lang)) - ((= (length results) 0) - (dumb-jump-message "'%s' %s references not found." - look-for - (if (string-blank-p (or lang "")) - "with unknown language so" - lang))) - (t (mapcar (lambda (res) - (with-no-warnings - (xref-make - (plist-get res :context) - (xref-make-file-location - (let* ((path (plist-get res :path)) - (remote-prefix (file-remote-p default-directory))) - (if remote-prefix - (if (file-name-absolute-p path) - (concat remote-prefix path) - (concat default-directory path)) - (expand-file-name path))) - (plist-get res :line) - 0)))) - match-cur-file-front))))) - -(cl-defmethod xref-backend-apropos ((_backend (eql dumb-jump)) pattern) - (xref-backend-definitions 'dumb-jump pattern)) - -(cl-defmethod xref-backend-identifier-completion-table - ((_backend (eql dumb-jump))) - nil) - -;;;###autoload -(defun dumb-jump-xref-activate () - "Function to activate xref backend. -Add this function to `xref-backend-functions' to dumb jump to be -activated, whenever it finds a project. It is recommended to add -it to the end, so that it only gets activated when no better -option is found." - (and (dumb-jump-get-project-root default-directory) - 'dumb-jump)) - -(provide 'dumb-jump) -;;; dumb-jump.el ends here |
