Commit 97769720 authored by Dmitry Gutov's avatar Dmitry Gutov

Rename "search path" to "library roots"

* lisp/emacs-lisp/cl-seq.el (cl-set-difference): Retain the order
of the elements from CL-LIST1.

* test/automated/cl-lib-tests.el (cl-lib-test-set-functions):
Update WRT to the above change.

* lisp/progmodes/project.el (project-search-path-function): Rename
to project-library-roots-function, update the documentation and
references.
(project-search-path): Likewise, to project-library-roots.
(project-roots): Clarify documentation.
(project-vc-search-path): Likewise, to project-vc-library-roots.
(project-library-roots): In addition to the renames, thread the
results through file-name-as-directory.
(project-prune-directories): Accept a variable number of
arguments.  Rename to project-combine-directories.
(project-subtract-directories): New function.

* lisp/progmodes/elisp-mode.el (elisp--xref-find-references):
Append project-roots and project-library-roots together.

* lisp/progmodes/etags.el (etags--xref-find-references): Ditto.
parent 267e0e80
......@@ -849,7 +849,7 @@ to avoid corrupting the original LIST1 and LIST2.
(memq (car cl-list1) cl-list2))
(push (car cl-list1) cl-res))
(pop cl-list1))
cl-res))))
(nreverse cl-res)))))
;;;###autoload
(defun cl-nset-difference (cl-list1 cl-list2 &rest cl-keys)
......
......@@ -230,7 +230,7 @@ Blank lines separate paragraphs. Semicolons start comments.
:group 'lisp
(defvar xref-find-function)
(defvar xref-identifier-completion-table-function)
(defvar project-search-path-function)
(defvar project-library-roots-function)
(lisp-mode-variables nil nil 'elisp)
(add-hook 'after-load-functions #'elisp--font-lock-flush-elisp-buffers)
(setq-local electric-pair-text-pairs
......@@ -242,7 +242,7 @@ Blank lines separate paragraphs. Semicolons start comments.
(setq-local xref-find-function #'elisp-xref-find)
(setq-local xref-identifier-completion-table-function
#'elisp--xref-identifier-completion-table)
(setq-local project-search-path-function #'elisp-search-path)
(setq-local project-library-roots-function #'elisp-library-roots)
(add-hook 'completion-at-point-functions
#'elisp-completion-at-point nil 'local))
......@@ -801,7 +801,7 @@ non-nil result supercedes the xrefs produced by
xrefs))
(declare-function project-search-path "project")
(declare-function project-library-roots "project")
(declare-function project-current "project")
(defun elisp--xref-find-references (symbol)
......@@ -809,7 +809,10 @@ non-nil result supercedes the xrefs produced by
(cl-mapcan
(lambda (dir)
(xref-collect-references symbol dir))
(project-search-path (project-current))))
(let ((pr (project-current)))
(append
(project-roots pr)
(project-library-roots pr)))))
(defun elisp--xref-find-apropos (regexp)
(apply #'nconc
......@@ -846,7 +849,7 @@ non-nil result supercedes the xrefs produced by
(cl-defmethod xref-location-group ((l xref-elisp-location))
(xref-elisp-location-file l))
(defun elisp-search-path ()
(defun elisp-library-roots ()
(defvar package-user-dir)
(cons package-user-dir load-path))
......
......@@ -2098,7 +2098,10 @@ for \\[find-tag] (which see)."
(cl-mapcan
(lambda (dir)
(xref-collect-references symbol dir))
(project-search-path (project-current))))
(let ((pr (project-current)))
(append
(project-roots pr)
(project-library-roots pr)))))
(defun etags--xref-find-definitions (pattern &optional regexp?)
;; This emulates the behaviour of `find-tag-in-order' but instead of
......@@ -2154,7 +2157,7 @@ for \\[find-tag] (which see)."
(with-slots (tag-info) l
(nth 1 tag-info)))
(defun etags-search-path ()
(defun etags-library-roots ()
(mapcar #'file-name-directory tags-table-list))
......
......@@ -23,7 +23,7 @@
;; projects, and a number of public functions: finding the current
;; root, related project directories, search path, etc.
;;
;; The goal is to make it easy for Lisp programs to operate on the
;; The goal is to make it easier for Lisp programs to operate on the
;; current project, without having to know which package handles
;; detection of that project type, parsing its config files, etc.
......@@ -38,19 +38,33 @@ Each functions on this hook is called in turn with one
argument (the directory) and should return either nil to mean
that it is not applicable, or a project instance.")
(declare-function etags-search-path "etags" ())
(defvar project-search-path-function #'etags-search-path
"Function that returns a list of source root directories.
;; FIXME: Using the current approach, we don't have access to the
;; "library roots" of language A from buffers of language B, which
;; seems desirable in multi-language projects, at least for some
;; potential uses, like "jump to a file in project or library".
;;
;; We can add a second argument to this function: a file extension, or
;; a language name. Some projects will know the set of languages used
;; in them; for others, like VC-based projects, we'll need
;; auto-detection. I see two options:
;;
;; - That could be implemented as a separate second hook, with a
;; list of functions that return file extensions.
;;
;; - This variable will be turned into a hook with "append" semantics,
;; and each function in it will perform auto-detection when passed
;; nil instead of an actual file extension. Then this hook will, in
;; general, be modified globally, and not from major mode functions.
(defvar project-library-roots-function 'etags-library-roots
"Function that returns a list of library roots.
The directories in which we can recursively look for the
declarations or other references to the symbols used in the
current buffer. Depending on the language, it should include the
headers search path, load path, class path, or so on.
It should return a list of directories that contain source files
related to the current buffer. Depending on the language, it
should include the headers search path, load path, class path,
and so on.
The directory names should be absolute. This variable is
normally set by the major mode. Used in the default
implementation of `project-search-path'.")
The directory names should be absolute. Used in the default
implementation of `project-library-roots'.")
;;;###autoload
(defun project-current (&optional dir)
......@@ -59,35 +73,39 @@ implementation of `project-search-path'.")
(run-hook-with-args-until-success 'project-find-functions dir))
;; FIXME: Add MODE argument, like in `ede-source-paths'?
(cl-defgeneric project-search-path (project)
(cl-defgeneric project-library-roots (project)
"Return the list of source root directories.
Any directory roots where source (or header, etc) files used by
the current project may be found, inside or outside of the
current project tree(s). The directory names should be absolute.
Unless it really knows better, a specialized implementation
should take into account the value returned by
`project-search-path-function' and call
`project-prune-directories' on the result."
(project-prune-directories
(append
;; We don't know the project layout, like where the sources are,
;; so we simply include the roots.
(project-roots project)
(funcall project-search-path-function))))
It's the list of directories outside of the current project that
contain related source files.
Project-specific version of `project-library-roots-function',
which see. Unless it knows better, a specialized implementation
should use the value returned by that function."
(project-subtract-directories
(project-combine-directories
(funcall project-library-roots-function))
(project-roots project)))
(cl-defgeneric project-roots (project)
"Return the list of directory roots related to the current project.
It should include the current project root, as well as the roots
of any other currently open projects, if they're meant to be
edited together. The directory names should be absolute.")
"Return the list of directory roots belonging to the current project.
Most often it's just one directory, which contains the project
file and everything else in the project. But in more advanced
configurations, a project can span multiple directories.
The rule of tumb for whether to include a directory here, and not
in `project-library-roots', is whether its contents are meant to
be edited together with the rest of the project.
The directory names should be absolute.")
(cl-defgeneric project-ignores (_project _dir)
"Return the list of glob patterns to ignore inside DIR.
Patterns can match both regular files and directories.
To root an entry, start it with `./'. To match directories only,
end it with `/'. DIR must be either one of `project-roots', or
an element of `project-search-path'."
end it with `/'. DIR must be one of `project-roots' or
`project-library-roots'."
(require 'grep)
(defvar grep-find-ignored-files)
(nconc
......@@ -101,8 +119,8 @@ an element of `project-search-path'."
"Project implementation using the VC package."
:group 'tools)
(defcustom project-vc-search-path nil
"List ot directories to include in `project-search-path'.
(defcustom project-vc-library-roots nil
"List ot directories to include in `project-library-roots'.
The file names can be absolute, or relative to the project root."
:type '(repeat file)
:safe 'listp)
......@@ -121,12 +139,12 @@ The file names can be absolute, or relative to the project root."
(cl-defmethod project-roots ((project (head vc)))
(list (cdr project)))
(cl-defmethod project-search-path ((project (head vc)))
(cl-defmethod project-library-roots ((project (head vc)))
(append
(let ((root (cdr project)))
(mapcar
(lambda (dir) (expand-file-name dir root))
(project--value-in-dir 'project-vc-search-path root)))
(lambda (dir) (file-name-as-directory (expand-file-name dir root)))
(project--value-in-dir 'project-vc-library-roots root)))
(cl-call-next-method)))
(cl-defmethod project-ignores ((project (head vc)) dir)
......@@ -150,13 +168,16 @@ The file names can be absolute, or relative to the project root."
(cl-defmethod project-roots ((project (head user)))
(list (cdr project)))
(defun project-prune-directories (dirs)
"Returns a copy of DIRS sorted, without subdirectories or non-existing ones."
(defun project-combine-directories (&rest lists-of-dirs)
"Return a sorted and culled list of directory names.
Appends the elements of LISTS-OF-DIRS together, removes
non-existing directories, as well as directories a parent of
whose is already in the list."
(let* ((dirs (sort
(mapcar
(lambda (dir)
(file-name-as-directory (expand-file-name dir)))
dirs)
(apply #'append lists-of-dirs))
#'string<))
(ref dirs))
;; Delete subdirectories from the list.
......@@ -166,6 +187,12 @@ The file names can be absolute, or relative to the project root."
(setq ref (cdr ref))))
(cl-delete-if-not #'file-exists-p dirs)))
(defun project-subtract-directories (files dirs)
"Return a list of elements from FILES that are outside of DIRS.
DIRS must contain directory names."
(cl-set-difference files dirs
:test (lambda (file dir) (string-prefix-p dir file))))
(defun project--value-in-dir (var dir)
(with-temp-buffer
(setq default-directory dir)
......
......@@ -802,10 +802,9 @@ to search in, and the file name pattern to search for."
(dirs (if current-prefix-arg
(list (read-directory-name "Base directory: "
nil default-directory t))
(project-prune-directories
(append
(project-roots proj)
(project-search-path proj)))))
(append
(project-roots proj)
(project-library-roots proj))))
(xref-find-function
(lambda (_kind regexp)
(cl-mapcan
......
......@@ -117,8 +117,8 @@
(should (equal (cl-set-difference b b) e))
;; Note: this test (and others) is sensitive to the order of the
;; result, which is not documented.
(should (equal (cl-set-difference a b) (list c2 "x" "" nil 'a)))
(should (equal (cl-set-difference b a) (list 'x 'y)))
(should (equal (cl-set-difference a b) (list 'a nil "" "x" c2)))
(should (equal (cl-set-difference b a) (list 'y 'x)))
;; We aren't testing whether this is really using `eq' rather than `eql'.
(should (equal (cl-set-difference e e :test 'eq) e))
......@@ -128,8 +128,8 @@
(should (equal (cl-set-difference b e :test 'eq) b))
(should (equal (cl-set-difference e b :test 'eq) e))
(should (equal (cl-set-difference b b :test 'eq) e))
(should (equal (cl-set-difference a b :test 'eq) (list c2 "x" "" nil 'a)))
(should (equal (cl-set-difference b a :test 'eq) (list 'x 'y)))
(should (equal (cl-set-difference a b :test 'eq) (list 'a nil "" "x" c2)))
(should (equal (cl-set-difference b a :test 'eq) (list 'y 'x)))
(should (equal (cl-union e e) e))
(should (equal (cl-union a e) a))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment