Hello! Thanks so much for maintaining rustic-mode! I'm not 100% sure if this fix should be in rust-mode or rustic-mode, but I wanted to file it and discuss. Happy to move or re-file it later 😃
In short, I believe one of the Rust modes should configure how Emacs finds the current project because Eglot uses this to start rust-analyzer.
When rust-analyzer is started, it fails to discover crates if the Cargo workspace is nested more than one directly level inside a Git repository. As far as I can tell, this is because of find_cargo_toml_in_child_dir, which says:
fn find_cargo_toml_in_child_dir(entities: ReadDir) -> Vec<ManifestPath> {
// Only one level down to avoid cycles the easy way and stop a runaway scan with large projects
The problem occurs when the Emacs and Cargo don't agree on where the project root is. Eglot relies entirely on project.el to determine the project root (see joaotavora/eglot#909). The default backend for project.el is project-vc-find-project, which simply finds the version control root (.git directory). When rust-analyzer is started with the VCS root, it cannot find the workspace members and reports an error:
[eglot] Server reports (type=1): Failed to discover workspace.
Consider adding the `Cargo.toml` of the workspace to the [`linkedProjects`](https://rust-analyzer.github.io/book/configuration.html#linkedProjects) setting.
Failed to load workspaces.
I'll suggest that rustic-mode fixes this by explicitly configuring how to find the Cargo root. I've been using the following configuration snippet for a few days now and it seems to do the job:
;;; --- Configure project.el to find Cargo project roots intelligently ---
(require 'cl-lib)
(defun mg/cargo-toml-is-workspace (dir)
"Return non-nil if DIR contains a workspace Cargo.toml file."
(let ((cargo-toml (file-name-concat dir "Cargo.toml")))
(when (file-exists-p cargo-toml)
(with-temp-buffer
(insert-file-contents-literally cargo-toml)
(goto-char (point-min))
(search-forward-regexp "^\\[workspace\\]" nil t)))))
(defun mg/project-find-rust-project (dir)
"Find a Rust project root, prioritizing workspaces."
(let ((ws-root (locate-dominating-file dir #'mg/cargo-toml-is-workspace)))
(cond
;; Priority 1: A Cargo workspace was found. Use it directly.
(ws-root (cons 'cargo-project ws-root))
;; Priority 2: No workspace, so find the nearest `Cargo.toml`.
((when-let ((cargo-dir (locate-dominating-file dir "Cargo.toml")))
(let* ((vcs-root (vc-root-dir))
(project-root
(if-let ((vcs-root-path (and vcs-root (file-name-as-directory vcs-root))))
;; A VCS root exists. Decide based on nesting depth.
(let* ((cargo-path (file-name-as-directory cargo-dir))
(relative-path (file-relative-name cargo-path vcs-root-path))
(depth (cl-count ?\/ relative-path)))
(if (> depth 1)
;; Deeper than 1 level: use the Cargo.toml dir.
cargo-dir
;; 0 or 1 level deep: use the VCS root.
vcs-root))
;; No VCS root found, so the Cargo.toml dir is the best we can do.
cargo-dir)))
(cons 'cargo-project project-root)))))))
;; Teach project.el how to extract the root from our 'cargo-project type.
(cl-defmethod project-root ((project (head cargo-project)))
(cdr project))
;; Add our new function to the front of `project-find-functions` to give it
;; priority over the default VCS-based discovery.
(add-to-list 'project-find-functions #'mg/project-find-rust-project)
The logic for finding the correct Cargo.toml file could probably be improved: calling cargo metadata and parsing out the workspace_root is probably the right solution.
The steps I used to test this locally was:
mkdir -p project-root
cd project-root
git init
mkdir -p nested
cd nested
cargo new --lib foo
To test, open project-root/nested/foo/src/lib.rs in Emacs and start Eglot.
Version Info:
- Rustic Version: 20250630.1332
- Emacs Version: 30.1 from Debian Testing
- Eglot Version: 1.17.30
- rust-analyzer Version: 1.89.0 (2948388 2025-08-04)
Hello! Thanks so much for maintaining
rustic-mode! I'm not 100% sure if this fix should be inrust-modeorrustic-mode, but I wanted to file it and discuss. Happy to move or re-file it later 😃In short, I believe one of the Rust modes should configure how Emacs finds the current project because Eglot uses this to start
rust-analyzer.When
rust-analyzeris started, it fails to discover crates if the Cargo workspace is nested more than one directly level inside a Git repository. As far as I can tell, this is because offind_cargo_toml_in_child_dir, which says:The problem occurs when the Emacs and Cargo don't agree on where the project root is. Eglot relies entirely on
project.elto determine the project root (see joaotavora/eglot#909). The default backend forproject.elisproject-vc-find-project, which simply finds the version control root (.gitdirectory). Whenrust-analyzeris started with the VCS root, it cannot find the workspace members and reports an error:I'll suggest that
rustic-modefixes this by explicitly configuring how to find the Cargo root. I've been using the following configuration snippet for a few days now and it seems to do the job:The logic for finding the correct
Cargo.tomlfile could probably be improved: callingcargo metadataand parsing out theworkspace_rootis probably the right solution.The steps I used to test this locally was:
To test, open
project-root/nested/foo/src/lib.rsin Emacs and start Eglot.Version Info: