aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lisp/cedet/ede.el5
-rw-r--r--lisp/progmodes/elisp-mode.el6
-rw-r--r--lisp/progmodes/project.el159
-rw-r--r--lisp/progmodes/xref.el5
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
38argument (the directory) and should return either nil to mean 38argument (the directory) and should return either nil to mean
39that it is not applicable, or a project instance.") 39that 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
62It should return a list of directories that contain source files
63related to the current buffer. Depending on the language, it
64should include the headers search path, load path, class path,
65and so on.
66
67The directory names should be absolute. Used in the default
68implementation 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
93It's the list of directories outside of the project that contain 63In the simplest case, it's just one directory, which contains the
94related source files. 64project file and everything else in the project. In more
65advanced configurations, this list can include multiple project
66roots, as well as directories in specialized categories, such as
67`source-roots' and `test-roots', and .
95 68
96Project-specific version of `project-library-roots-function', 69The directory names should be absolute.")
97which see. Unless it knows better, a specialized implementation
98should 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
107Most often it's just one directory, which contains the project 74The standard categories are:
108file and everything else in the project. But in more advanced
109configurations, a project can span multiple directories.
110 75
111The 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
112in `project-library-roots', is whether its contents are meant to 77simply being in the headers search path, load path, class path, etc.
113be edited together with the rest of the project.
114 78
115The directory names should be absolute.") 79At least one of the `project-directories' elements must belong to
80this category. When a projects has dependencies, the backend is
81allowed to designate some of them to be `primary' as well, if it
82knows 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.
119Patterns can match both regular files and directories. 90Patterns can match both regular files and directories.
120To root an entry, start it with `./'. To match directories only, 91To root an entry, start it with `./'. To match directories only,
121end it with `/'. DIR must be one of `project-roots' or 92end 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'.
138The 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
133It should return a list of directories that contain source files
134related to the current buffer. Depending on the language, it
135should include the headers search path, load path, class path,
136and so on.
137
138The directory names should be absolute. Used in the default
139implementation 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
184Appends the elements of LISTS-OF-DIRS together, removes 177 (cl-delete-if
185non-existing directories, as well as directories a parent of 178 (lambda (dir)
186whose 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.
184It takes DIRS, removes non-existing directories, as well as
185directories 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.
234With \\[universal-argument] prefix, you can specify the file name 233With \\[universal-argument] prefix, you can specify the file name
235pattern to search for." 234pattern 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.