Commit 3ed96ebe authored by Josh Elsasser's avatar Josh Elsasser Committed by Fangrui Song

Prevent projectile-project-root from masking subprojects (#21)

* introduce defcustom to control ordering within cquery--get-root

Obsoletes `cquery-project-root-function` in favour of a new defcustom,
`cquery-project-root-matchers`, that allows a user to tweak how cquery.el
discovers its project root.

In the default configuration, `projectile-project-root` wil accurately
find the outermost `compile_commands.json` in the example project below:

- .git/
- Makefile
- compile_commands.json -> src/compile_commands.json
- src/
  - compile_commands.json

Removing `projectile-project-root` from the head of the list allows
users to work with  project roots within subdirectories of a git repo:

- .git/
- src/
  - Makefile
  - compile_commands.json

* fixup! introduce defcustom to control ordering within cquery--get-root
parent ad3a6e0e
......@@ -44,19 +44,24 @@
(cons (lsp--position-to-point (gethash "start" range))
(lsp--position-to-point (gethash "end" range))))
(defsubst cquery--root-from-file (file)
(-when-let (match (locate-dominating-file default-directory file))
(expand-file-name match)))
(defsubst cquery--root-from-func (func)
(and (fboundp func) (ignore-errors (funcall func))))
(cl-defun cquery--get-root ()
"Return the root directory of a cquery project."
(when cquery-project-root-function
(-when-let (root (funcall cquery-project-root-function))
(cl-return-from cquery--get-root root)))
(cl-loop for root in cquery-project-roots do
(when (string-prefix-p (expand-file-name root) buffer-file-name)
(cl-return-from cquery--get-root root)))
(and (require 'projectile nil t) (ignore-errors (projectile-project-root)))
(expand-file-name (or (locate-dominating-file default-directory "compile_commands.json")
(locate-dominating-file default-directory ".cquery")
(user-error "Could not find cquery project root")))))
(cl-loop for matcher in cquery-project-root-matchers do
(-when-let (root (cl-typecase matcher
(string (cquery--root-from-file matcher))
(function (cquery--root-from-func matcher))))
(cl-return-from cquery--get-root root)))
(user-error "Could not find cquery project root"))
(defun cquery--is-cquery-buffer(&optional buffer)
"Return non-nil if current buffer is using the cquery client"
......@@ -77,20 +77,15 @@ Relative to the project root directory."
(defcustom cquery-project-root-function
"A function used to find the project root.
The following methods are applied in order to get the project root.
* `cquery-project-root-function'
* `cquery-project-roots'
* projectile
* `.cquery' or `compile_commands.json'
:type 'function
:type '(repeat function)
:group 'cquery)
(make-obsolete-variable 'cquery-project-roots 'cquery-project-root-matchers)
(defcustom cquery-project-roots
"A list of project roots that will be matched against the source filename first
to get the project root, before consulting `projectile' or `project'.
to get the project root before consulting `cquery-project-root-matchers'.
This is useful when your project has subprojects. Otherwise `projectile' and
`project' may think the file resides in a subproject and thus the file
......@@ -99,6 +94,23 @@ does not belong to the current workspace.
:type '(repeat directory)
:group 'cquery)
(defcustom cquery-project-root-matchers
'(projectile-project-root "compile_commands.json" ".cquery")
"List of matchers that are used to locate the cquery project roots.
Each matcher is run in order, and the first successful (non-nil) matcher
determines the project root.
A `string' entry defines a dominating file that exists in either the
current working directory or a parent directory. cquery will traverse
upwards through the project directory structure and return the first
matching file.
A `function' entry define a callable function that either returns workspace's
root location or `nil' if another matcher should be used instead.
:type '(repeat (choice (file) (function)))
:group 'cquery)
;; ---------------------------------------------------------------------
;; Other cquery-specific methods
;; ---------------------------------------------------------------------
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