diff options
author | Riccardo Binetti | 2022-09-23 08:04:07 +0000 |
---|---|---|
committer | GitHub | 2022-09-23 08:04:07 +0000 |
commit | 888f4fef6f975412c8215c4b76871ffba6e1b41d (patch) | |
tree | d6cc3ebf96af323732c85dff0e393ef24accfd8d /helix-core/src | |
parent | 4133f1f424c6a9da71cab65dc9541e6d941ec603 (diff) |
Split helix_core::find_root and helix_loader::find_local_config_dirs (#3929)
* Split helix_core::find_root and helix_loader::find_local_config_dirs
The documentation of find_root described the following priority for
detecting a project root:
- Top-most folder containing a root marker in current git repository
- Git repository root if no marker detected
- Top-most folder containing a root marker if not git repository detected
- Current working directory as fallback
The commit contained in https://github.com/helix-editor/helix/pull/1249
extracted and changed the implementation of find_root in find_root_impl,
actually reversing its result order (since that is the order that made
sense for the local configuration merge, from innermost to outermost
ancestors).
Since the two uses of find_root_impl have different requirements (and
it's not a matter of reversing the order of results since, e.g., the top
repository dir should be used by find_root only if there's not marker in
other dirs), this PR splits the two implementations in two different
specialized functions.
In doing so, find_root_impl is removed and the implementation is moved
back in find_root, moving it closer to the documented behaviour thus
making it easier to verify it's actually correct
* helix-core: remove Option from find_root return type
It always returns some result, so Option is not needed
Diffstat (limited to 'helix-core/src')
-rw-r--r-- | helix-core/src/lib.rs | 40 |
1 files changed, 36 insertions, 4 deletions
diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs index 735a62c1..8f869e35 100644 --- a/helix-core/src/lib.rs +++ b/helix-core/src/lib.rs @@ -46,10 +46,42 @@ pub fn find_first_non_whitespace_char(line: RopeSlice) -> Option<usize> { /// * Git repository 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> { - helix_loader::find_root_impl(root, root_markers) - .first() - .cloned() +pub fn find_root(root: Option<&str>, root_markers: &[String]) -> std::path::PathBuf { + let current_dir = std::env::current_dir().expect("unable to determine current directory"); + + let root = match root { + Some(root) => { + let root = std::path::Path::new(root); + if root.is_absolute() { + root.to_path_buf() + } else { + current_dir.join(root) + } + } + None => current_dir.clone(), + }; + + let mut top_marker = None; + for ancestor in root.ancestors() { + if root_markers + .iter() + .any(|marker| ancestor.join(marker).exists()) + { + top_marker = Some(ancestor); + } + + if ancestor.join(".git").is_dir() { + // Top marker is repo root if not root marker was detected yet + if top_marker.is_none() { + top_marker = Some(ancestor); + } + // Don't go higher than repo if we're in one + break; + } + } + + // Return the found top marker or the current_dir as fallback + top_marker.map_or(current_dir, |a| a.to_path_buf()) } pub use ropey::{str_utils, Rope, RopeBuilder, RopeSlice}; |