aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexis Mousset2021-12-31 08:06:54 +0000
committerGitHub2021-12-31 08:06:54 +0000
commit8a019b423f5d51bcfc107da9cb50aa90eacff19d (patch)
tree2f5dfede14f1566ecafc5651767f9e2306f81c53
parent8fda87af2bb0625c502a23ddbd78a7447ada7bcb (diff)
Detect workspace root using language markers (#1370)
* Detect workspace root using language markers * Avoid allocating root_markers * Update helix-core/src/lib.rs Co-authored-by: Blaž Hrastnik <blaz@mxxn.io> * Update helix-core/src/lib.rs Co-authored-by: Kirawi <67773714+kirawi@users.noreply.github.com> Co-authored-by: Blaž Hrastnik <blaz@mxxn.io> Co-authored-by: Kirawi <67773714+kirawi@users.noreply.github.com>
-rw-r--r--helix-core/src/lib.rs32
-rw-r--r--helix-lsp/src/client.rs6
-rw-r--r--helix-lsp/src/lib.rs1
-rw-r--r--helix-term/src/commands.rs3
-rw-r--r--languages.toml2
5 files changed, 35 insertions, 9 deletions
diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs
index 1c78e7c0..7fd23b97 100644
--- a/helix-core/src/lib.rs
+++ b/helix-core/src/lib.rs
@@ -39,8 +39,14 @@ pub fn find_first_non_whitespace_char(line: RopeSlice) -> Option<usize> {
line.chars().position(|ch| !ch.is_whitespace())
}
-/// Find `.git` root.
-pub fn find_root(root: Option<&str>) -> Option<std::path::PathBuf> {
+/// Find project root.
+///
+/// Order of detection:
+/// * Top-most folder containing a root marker in current git repository
+/// * Git repostory root if no marker detected
+/// * Top-most folder containing a root marker if not git repository detected
+/// * Current working directory as fallback
+pub fn find_root(root: Option<&str>, root_markers: &[String]) -> Option<std::path::PathBuf> {
let current_dir = std::env::current_dir().expect("unable to determine current directory");
let root = match root {
@@ -52,16 +58,30 @@ pub fn find_root(root: Option<&str>) -> Option<std::path::PathBuf> {
current_dir.join(root)
}
}
- None => current_dir,
+ None => current_dir.clone(),
};
+ let mut top_marker = None;
for ancestor in root.ancestors() {
- // TODO: also use defined roots if git isn't found
+ for marker in root_markers {
+ if ancestor.join(marker).exists() {
+ top_marker = Some(ancestor);
+ break;
+ }
+ }
+ // don't go higher than repo
if ancestor.join(".git").is_dir() {
- return Some(ancestor.to_path_buf());
+ // Use workspace if detected from marker
+ return Some(top_marker.unwrap_or(ancestor).to_path_buf());
}
}
- None
+
+ // In absence of git repo, use workspace if detected
+ if top_marker.is_some() {
+ top_marker.map(|a| a.to_path_buf())
+ } else {
+ Some(current_dir)
+ }
}
pub fn runtime_dir() -> std::path::PathBuf {
diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs
index 43804daa..c80f70b5 100644
--- a/helix-lsp/src/client.rs
+++ b/helix-lsp/src/client.rs
@@ -31,6 +31,7 @@ pub struct Client {
pub(crate) capabilities: OnceCell<lsp::ServerCapabilities>,
offset_encoding: OffsetEncoding,
config: Option<Value>,
+ root_markers: Vec<String>,
}
impl Client {
@@ -39,6 +40,7 @@ impl Client {
cmd: &str,
args: &[String],
config: Option<Value>,
+ root_markers: Vec<String>,
id: usize,
) -> Result<(Self, UnboundedReceiver<(usize, Call)>, Arc<Notify>)> {
let process = Command::new(cmd)
@@ -68,6 +70,7 @@ impl Client {
capabilities: OnceCell::new(),
offset_encoding: OffsetEncoding::Utf8,
config,
+ root_markers,
};
Ok((client, server_rx, initialize_notify))
@@ -225,7 +228,8 @@ impl Client {
pub(crate) async fn initialize(&self) -> Result<lsp::InitializeResult> {
// TODO: delay any requests that are triggered prior to initialize
- let root = find_root(None).and_then(|root| lsp::Url::from_file_path(root).ok());
+ let root = find_root(None, &self.root_markers)
+ .and_then(|root| lsp::Url::from_file_path(root).ok());
if self.config.is_some() {
log::info!("Using custom LSP config: {}", self.config.as_ref().unwrap());
diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs
index 8fb321bc..1eb1c151 100644
--- a/helix-lsp/src/lib.rs
+++ b/helix-lsp/src/lib.rs
@@ -326,6 +326,7 @@ impl Registry {
&config.command,
&config.args,
language_config.config.clone(),
+ language_config.roots.clone(),
id,
)?;
self.incoming.push(UnboundedReceiverStream::new(incoming));
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index 6259ecb2..ed728115 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -3154,7 +3154,8 @@ fn command_mode(cx: &mut Context) {
}
fn file_picker(cx: &mut Context) {
- let root = find_root(None).unwrap_or_else(|| PathBuf::from("./"));
+ // We don't specify language markers, root will be the root of the current git repo
+ let root = find_root(None, &[]).unwrap_or_else(|| PathBuf::from("./"));
let picker = ui::file_picker(root, &cx.editor.config);
cx.push_layer(Box::new(picker));
}
diff --git a/languages.toml b/languages.toml
index 3d9bac7b..f088a3aa 100644
--- a/languages.toml
+++ b/languages.toml
@@ -3,7 +3,7 @@ name = "rust"
scope = "source.rust"
injection-regex = "rust"
file-types = ["rs"]
-roots = []
+roots = ["Cargo.toml", "Cargo.lock"]
auto-format = true
comment-token = "//"
language-server = { command = "rust-analyzer" }