diff options
| -rw-r--r-- | lisp/cedet/ede.el | 5 | ||||
| -rw-r--r-- | lisp/progmodes/elisp-mode.el | 6 | ||||
| -rw-r--r-- | lisp/progmodes/project.el | 159 | ||||
| -rw-r--r-- | lisp/progmodes/xref.el | 5 |
4 files changed, 85 insertions, 90 deletions
diff --git a/lisp/cedet/ede.el b/lisp/cedet/ede.el index 2a522bcccd8..b6bdc79080a 100644 --- a/lisp/cedet/ede.el +++ b/lisp/cedet/ede.el | |||
| @@ -1520,9 +1520,12 @@ It does not apply the value to buffers." | |||
| 1520 | (when project-dir | 1520 | (when project-dir |
| 1521 | (ede-directory-get-open-project project-dir 'ROOT)))) | 1521 | (ede-directory-get-open-project project-dir 'ROOT)))) |
| 1522 | 1522 | ||
| 1523 | (cl-defmethod project-roots ((project ede-project)) | 1523 | (cl-defmethod project-directories ((project ede-project)) |
| 1524 | (list (ede-project-root-directory project))) | 1524 | (list (ede-project-root-directory project))) |
| 1525 | 1525 | ||
| 1526 | (cl-defmethod project-directory-categories ((_project ede-project) _dir) | ||
| 1527 | '(primary)) | ||
| 1528 | |||
| 1526 | (add-hook 'project-find-functions #'project-try-ede) | 1529 | (add-hook 'project-find-functions #'project-try-ede) |
| 1527 | 1530 | ||
| 1528 | (provide 'ede) | 1531 | (provide 'ede) |
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el index 12848fe02e0..3f536944f30 100644 --- a/lisp/progmodes/elisp-mode.el +++ b/lisp/progmodes/elisp-mode.el | |||
| @@ -228,7 +228,7 @@ Blank lines separate paragraphs. Semicolons start comments. | |||
| 228 | 228 | ||
| 229 | \\{emacs-lisp-mode-map}" | 229 | \\{emacs-lisp-mode-map}" |
| 230 | :group 'lisp | 230 | :group 'lisp |
| 231 | (defvar project-library-roots-function) | 231 | (defvar project-vc-directories-function) |
| 232 | (lisp-mode-variables nil nil 'elisp) | 232 | (lisp-mode-variables nil nil 'elisp) |
| 233 | (add-hook 'after-load-functions #'elisp--font-lock-flush-elisp-buffers) | 233 | (add-hook 'after-load-functions #'elisp--font-lock-flush-elisp-buffers) |
| 234 | (setq-local electric-pair-text-pairs | 234 | (setq-local electric-pair-text-pairs |
| @@ -238,7 +238,7 @@ Blank lines separate paragraphs. Semicolons start comments. | |||
| 238 | (add-function :before-until (local 'eldoc-documentation-function) | 238 | (add-function :before-until (local 'eldoc-documentation-function) |
| 239 | #'elisp-eldoc-documentation-function) | 239 | #'elisp-eldoc-documentation-function) |
| 240 | (add-hook 'xref-backend-functions #'elisp--xref-backend nil t) | 240 | (add-hook 'xref-backend-functions #'elisp--xref-backend nil t) |
| 241 | (setq-local project-library-roots-function #'elisp-library-roots) | 241 | (setq-local project-vc-directories-function #'elisp-library-roots) |
| 242 | (add-hook 'completion-at-point-functions | 242 | (add-hook 'completion-at-point-functions |
| 243 | #'elisp-completion-at-point nil 'local)) | 243 | #'elisp-completion-at-point nil 'local)) |
| 244 | 244 | ||
| @@ -795,8 +795,6 @@ non-nil result supercedes the xrefs produced by | |||
| 795 | 795 | ||
| 796 | xrefs)) | 796 | xrefs)) |
| 797 | 797 | ||
| 798 | (declare-function project-library-roots "project") | ||
| 799 | |||
| 800 | (cl-defmethod xref-backend-apropos ((_backend (eql elisp)) regexp) | 798 | (cl-defmethod xref-backend-apropos ((_backend (eql elisp)) regexp) |
| 801 | (apply #'nconc | 799 | (apply #'nconc |
| 802 | (let (lst) | 800 | (let (lst) |
diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index 40d7e03baf4..5394e8afadd 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el | |||
| @@ -38,35 +38,6 @@ Each functions on this hook is called in turn with one | |||
| 38 | argument (the directory) and should return either nil to mean | 38 | argument (the directory) and should return either nil to mean |
| 39 | that it is not applicable, or a project instance.") | 39 | that it is not applicable, or a project instance.") |
| 40 | 40 | ||
| 41 | ;; FIXME: Using the current approach, major modes are supposed to set | ||
| 42 | ;; this variable to a buffer-local value. So we don't have access to | ||
| 43 | ;; the "library roots" of language A from buffers of language B, which | ||
| 44 | ;; seems desirable in multi-language projects, at least for some | ||
| 45 | ;; potential uses, like "jump to a file in project or library". | ||
| 46 | ;; | ||
| 47 | ;; We can add a second argument to this function: a file extension, or | ||
| 48 | ;; a language name. Some projects will know the set of languages used | ||
| 49 | ;; in them; for others, like VC-based projects, we'll need | ||
| 50 | ;; auto-detection. I see two options: | ||
| 51 | ;; | ||
| 52 | ;; - That could be implemented as a separate second hook, with a | ||
| 53 | ;; list of functions that return file extensions. | ||
| 54 | ;; | ||
| 55 | ;; - This variable will be turned into a hook with "append" semantics, | ||
| 56 | ;; and each function in it will perform auto-detection when passed | ||
| 57 | ;; nil instead of an actual file extension. Then this hook will, in | ||
| 58 | ;; general, be modified globally, and not from major mode functions. | ||
| 59 | (defvar project-library-roots-function 'etags-library-roots | ||
| 60 | "Function that returns a list of library roots. | ||
| 61 | |||
| 62 | It should return a list of directories that contain source files | ||
| 63 | related to the current buffer. Depending on the language, it | ||
| 64 | should include the headers search path, load path, class path, | ||
| 65 | and so on. | ||
| 66 | |||
| 67 | The directory names should be absolute. Used in the default | ||
| 68 | implementation of `project-library-roots'.") | ||
| 69 | |||
| 70 | ;;;###autoload | 41 | ;;;###autoload |
| 71 | (defun project-current (&optional maybe-prompt dir) | 42 | (defun project-current (&optional maybe-prompt dir) |
| 72 | "Return the project instance in DIR or `default-directory'. | 43 | "Return the project instance in DIR or `default-directory'. |
| @@ -86,39 +57,39 @@ the user for a different directory to look in." | |||
| 86 | (defun project--find-in-directory (dir) | 57 | (defun project--find-in-directory (dir) |
| 87 | (run-hook-with-args-until-success 'project-find-functions dir)) | 58 | (run-hook-with-args-until-success 'project-find-functions dir)) |
| 88 | 59 | ||
| 89 | ;; FIXME: Add MODE argument, like in `ede-source-paths'? | 60 | (cl-defgeneric project-directories (project) |
| 90 | (cl-defgeneric project-library-roots (project) | 61 | "Return the list of directories related to the current project. |
| 91 | "Return the list of library roots for PROJECT. | ||
| 92 | 62 | ||
| 93 | It's the list of directories outside of the project that contain | 63 | In the simplest case, it's just one directory, which contains the |
| 94 | related source files. | 64 | project file and everything else in the project. In more |
| 65 | advanced configurations, this list can include multiple project | ||
| 66 | roots, as well as directories in specialized categories, such as | ||
| 67 | `source-roots' and `test-roots', and . | ||
| 95 | 68 | ||
| 96 | Project-specific version of `project-library-roots-function', | 69 | The directory names should be absolute.") |
| 97 | which see. Unless it knows better, a specialized implementation | ||
| 98 | should use the value returned by that function." | ||
| 99 | (project-subtract-directories | ||
| 100 | (project-combine-directories | ||
| 101 | (funcall project-library-roots-function)) | ||
| 102 | (project-roots project))) | ||
| 103 | 70 | ||
| 104 | (cl-defgeneric project-roots (project) | 71 | (cl-defgeneric project-directory-categories (project dir) |
| 105 | "Return the list of directory roots belonging to the current project. | 72 | "Return the list of categories which DIR belongs to. |
| 106 | 73 | ||
| 107 | Most often it's just one directory, which contains the project | 74 | The standard categories are: |
| 108 | file and everything else in the project. But in more advanced | ||
| 109 | configurations, a project can span multiple directories. | ||
| 110 | 75 | ||
| 111 | The rule of thumb for whether to include a directory here, and not | 76 | `primary': It means that DIR is a part of PROJECT, as opposed to |
| 112 | in `project-library-roots', is whether its contents are meant to | 77 | simply being in the headers search path, load path, class path, etc. |
| 113 | be edited together with the rest of the project. | ||
| 114 | 78 | ||
| 115 | The directory names should be absolute.") | 79 | At least one of the `project-directories' elements must belong to |
| 80 | this category. When a projects has dependencies, the backend is | ||
| 81 | allowed to designate some of them to be `primary' as well, if it | ||
| 82 | knows that they are developed together with the main project. | ||
| 83 | |||
| 84 | `sources': DIR contains files with source code. | ||
| 85 | |||
| 86 | `tests': DIR contains test files.") | ||
| 116 | 87 | ||
| 117 | (cl-defgeneric project-ignores (_project _dir) | 88 | (cl-defgeneric project-ignores (_project _dir) |
| 118 | "Return the list of glob patterns to ignore inside DIR. | 89 | "Return the list of glob patterns to ignore inside DIR. |
| 119 | Patterns can match both regular files and directories. | 90 | Patterns can match both regular files and directories. |
| 120 | To root an entry, start it with `./'. To match directories only, | 91 | To root an entry, start it with `./'. To match directories only, |
| 121 | end it with `/'. DIR must be one of `project-roots' or | 92 | end it with `/'. DIR must be one of `project-directories' or |
| 122 | `project-library-roots'." | 93 | `project-library-roots'." |
| 123 | (require 'grep) | 94 | (require 'grep) |
| 124 | (defvar grep-find-ignored-files) | 95 | (defvar grep-find-ignored-files) |
| @@ -133,36 +104,58 @@ end it with `/'. DIR must be one of `project-roots' or | |||
| 133 | "Project implementation using the VC package." | 104 | "Project implementation using the VC package." |
| 134 | :group 'tools) | 105 | :group 'tools) |
| 135 | 106 | ||
| 136 | (defcustom project-vc-library-roots nil | ||
| 137 | "List ot directories to include in `project-library-roots'. | ||
| 138 | The file names can be absolute, or relative to the project root." | ||
| 139 | :type '(repeat file) | ||
| 140 | :safe 'listp) | ||
| 141 | |||
| 142 | (defcustom project-vc-ignores nil | 107 | (defcustom project-vc-ignores nil |
| 143 | "List ot patterns to include in `project-ignores'." | 108 | "List ot patterns to include in `project-ignores'." |
| 144 | :type '(repeat string) | 109 | :type '(repeat string) |
| 145 | :safe 'listp) | 110 | :safe 'listp) |
| 146 | 111 | ||
| 112 | ;; FIXME: Using the current approach, major modes are supposed to set | ||
| 113 | ;; this variable to a buffer-local value. So we don't have access to | ||
| 114 | ;; the "related directories" of language A from buffers of language B, | ||
| 115 | ;; which seems desirable in multi-language projects, at least for some | ||
| 116 | ;; potential uses, like "jump to a file in any related directory". | ||
| 117 | ;; | ||
| 118 | ;; We can add a second argument to this function: a file extension, or | ||
| 119 | ;; a language name. Some projects will know the set of languages used | ||
| 120 | ;; in them; for others, like VC-based projects, we'll need | ||
| 121 | ;; auto-detection. I see two options: | ||
| 122 | ;; | ||
| 123 | ;; - That could be implemented as a separate second hook, with a | ||
| 124 | ;; list of functions that return file extensions. | ||
| 125 | ;; | ||
| 126 | ;; - This variable will be turned into a hook with "append" semantics, | ||
| 127 | ;; and each function in it will perform auto-detection when passed | ||
| 128 | ;; nil instead of an actual file extension. Then this hook will, in | ||
| 129 | ;; general, be modified globally, and not from major mode functions. | ||
| 130 | (defvar project-vc-directories-function 'etags-library-roots | ||
| 131 | "Function that returns a list of library roots. | ||
| 132 | |||
| 133 | It should return a list of directories that contain source files | ||
| 134 | related to the current buffer. Depending on the language, it | ||
| 135 | should include the headers search path, load path, class path, | ||
| 136 | and so on. | ||
| 137 | |||
| 138 | The directory names should be absolute. Used in the default | ||
| 139 | implementation of `project-library-roots'.") | ||
| 140 | |||
| 147 | (defun project-try-vc (dir) | 141 | (defun project-try-vc (dir) |
| 148 | (let* ((backend (ignore-errors (vc-responsible-backend dir))) | 142 | (let* ((backend (ignore-errors (vc-responsible-backend dir))) |
| 149 | (root (and backend (ignore-errors | 143 | (root (and backend (ignore-errors |
| 150 | (vc-call-backend backend 'root dir))))) | 144 | (vc-call-backend backend 'root dir))))) |
| 151 | (and root (cons 'vc root)))) | 145 | (and root (cons 'vc root)))) |
| 152 | 146 | ||
| 153 | (cl-defmethod project-roots ((project (head vc))) | 147 | (cl-defmethod project-directories ((project (head vc))) |
| 154 | (list (cdr project))) | 148 | (let ((root (cdr project))) |
| 149 | (cons | ||
| 150 | (cdr project) | ||
| 151 | (funcall | ||
| 152 | (project--value-in-dir 'project-vc-directories-function root))))) | ||
| 155 | 153 | ||
| 156 | (cl-defmethod project-library-roots ((project (head vc))) | 154 | (cl-defmethod project-directory-categories ((project (head vc)) dir) |
| 157 | (project-subtract-directories | 155 | (let ((root (cdr project))) |
| 158 | (project-combine-directories | 156 | (if (file-in-directory-p dir root) |
| 159 | (append | 157 | '(primary) |
| 160 | (let ((root (cdr project))) | 158 | '()))) |
| 161 | (mapcar | ||
| 162 | (lambda (dir) (file-name-as-directory (expand-file-name dir root))) | ||
| 163 | (project--value-in-dir 'project-vc-library-roots root))) | ||
| 164 | (funcall project-library-roots-function))) | ||
| 165 | (project-roots project))) | ||
| 166 | 159 | ||
| 167 | (cl-defmethod project-ignores ((project (head vc)) dir) | 160 | (cl-defmethod project-ignores ((project (head vc)) dir) |
| 168 | (let* ((root (cdr project)) | 161 | (let* ((root (cdr project)) |
| @@ -179,16 +172,22 @@ The file names can be absolute, or relative to the project root." | |||
| 179 | (project--value-in-dir 'project-vc-ignores root) | 172 | (project--value-in-dir 'project-vc-ignores root) |
| 180 | (cl-call-next-method)))) | 173 | (cl-call-next-method)))) |
| 181 | 174 | ||
| 182 | (defun project-combine-directories (&rest lists-of-dirs) | 175 | (defun project-directories-in-categories (project &rest categories) |
| 183 | "Return a sorted and culled list of directory names. | 176 | (project-combine-directories |
| 184 | Appends the elements of LISTS-OF-DIRS together, removes | 177 | (cl-delete-if |
| 185 | non-existing directories, as well as directories a parent of | 178 | (lambda (dir) |
| 186 | whose is already in the list." | 179 | (cl-set-difference categories (project-directory-categories project dir))) |
| 180 | (project-directories project)))) | ||
| 181 | |||
| 182 | (defun project-combine-directories (dirs) | ||
| 183 | "Return a sorted and culled list of directory names in PROJECT. | ||
| 184 | It takes DIRS, removes non-existing directories, as well as | ||
| 185 | directories a parent of whose is already in the list." | ||
| 187 | (let* ((dirs (sort | 186 | (let* ((dirs (sort |
| 188 | (mapcar | 187 | (mapcar |
| 189 | (lambda (dir) | 188 | (lambda (dir) |
| 190 | (file-name-as-directory (expand-file-name dir))) | 189 | (file-name-as-directory (expand-file-name dir))) |
| 191 | (apply #'append lists-of-dirs)) | 190 | dirs) |
| 192 | #'string<)) | 191 | #'string<)) |
| 193 | (ref dirs)) | 192 | (ref dirs)) |
| 194 | ;; Delete subdirectories from the list. | 193 | ;; Delete subdirectories from the list. |
| @@ -225,19 +224,17 @@ to search in, and the file name pattern to search for." | |||
| 225 | (dirs (if current-prefix-arg | 224 | (dirs (if current-prefix-arg |
| 226 | (list (read-directory-name "Base directory: " | 225 | (list (read-directory-name "Base directory: " |
| 227 | nil default-directory t)) | 226 | nil default-directory t)) |
| 228 | (project-roots pr)))) | 227 | (project-directories-in-categories pr 'primary)))) |
| 229 | (project--find-regexp-in dirs regexp pr))) | 228 | (project--find-regexp-in dirs regexp pr))) |
| 230 | 229 | ||
| 231 | ;;;###autoload | 230 | ;;;###autoload |
| 232 | (defun project-or-libraries-find-regexp (regexp) | 231 | (defun project-and-related-find-regexp (regexp) |
| 233 | "Find all matches for REGEXP in the current project or libraries. | 232 | "Find all matches for REGEXP in the current project or related directories. |
| 234 | With \\[universal-argument] prefix, you can specify the file name | 233 | With \\[universal-argument] prefix, you can specify the file name |
| 235 | pattern to search for." | 234 | pattern to search for." |
| 236 | (interactive (list (project--read-regexp))) | 235 | (interactive (list (project--read-regexp))) |
| 237 | (let* ((pr (project-current t)) | 236 | (let* ((pr (project-current t)) |
| 238 | (dirs (append | 237 | (dirs (project-directories-in-categories pr))) |
| 239 | (project-roots pr) | ||
| 240 | (project-library-roots pr)))) | ||
| 241 | (project--find-regexp-in dirs regexp pr))) | 238 | (project--find-regexp-in dirs regexp pr))) |
| 242 | 239 | ||
| 243 | (defun project--read-regexp () | 240 | (defun project--read-regexp () |
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index 397f379d434..b86074f99c0 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el | |||
| @@ -243,10 +243,7 @@ find a search tool; by default, this uses \"find | grep\" in the | |||
| 243 | (cl-mapcan | 243 | (cl-mapcan |
| 244 | (lambda (dir) | 244 | (lambda (dir) |
| 245 | (xref-collect-references identifier dir)) | 245 | (xref-collect-references identifier dir)) |
| 246 | (let ((pr (project-current t))) | 246 | (project-directories-in-categories (project-current t)))) |
| 247 | (append | ||
| 248 | (project-roots pr) | ||
| 249 | (project-library-roots pr))))) | ||
| 250 | 247 | ||
| 251 | (cl-defgeneric xref-backend-apropos (backend pattern) | 248 | (cl-defgeneric xref-backend-apropos (backend pattern) |
| 252 | "Find all symbols that match PATTERN. | 249 | "Find all symbols that match PATTERN. |