Support absolute disabled_globs
(#25755)
Closes: #25556 We were always comparing `disabled_globs` against the relative file path, we'll now use the absolute path if the glob is also absolute. Release Notes: - Support absolute globs in `edit_predictions.disabled_globs`
This commit is contained in:
parent
c5632f8c31
commit
6eb2ffe77a
8 changed files with 191 additions and 16 deletions
|
@ -4477,6 +4477,7 @@ impl IndentSize {
|
|||
pub struct TestFile {
|
||||
pub path: Arc<Path>,
|
||||
pub root_name: String,
|
||||
pub local_root: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
|
@ -4490,7 +4491,11 @@ impl File for TestFile {
|
|||
}
|
||||
|
||||
fn as_local(&self) -> Option<&dyn LocalFile> {
|
||||
None
|
||||
if self.local_root.is_some() {
|
||||
Some(self)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn disk_state(&self) -> DiskState {
|
||||
|
@ -4518,6 +4523,23 @@ impl File for TestFile {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
impl LocalFile for TestFile {
|
||||
fn abs_path(&self, _cx: &App) -> PathBuf {
|
||||
PathBuf::from(self.local_root.as_ref().unwrap())
|
||||
.join(&self.root_name)
|
||||
.join(self.path.as_ref())
|
||||
}
|
||||
|
||||
fn load(&self, _cx: &App) -> Task<Result<String>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn load_bytes(&self, _cx: &App) -> Task<Result<Vec<u8>>> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn contiguous_ranges(
|
||||
values: impl Iterator<Item = u32>,
|
||||
max_len: usize,
|
||||
|
|
|
@ -254,6 +254,7 @@ fn file(path: &str) -> Arc<dyn File> {
|
|||
Arc::new(TestFile {
|
||||
path: Path::new(path).into(),
|
||||
root_name: "zed".into(),
|
||||
local_root: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -231,13 +231,33 @@ pub struct EditPredictionSettings {
|
|||
/// A list of globs representing files that edit predictions should be disabled for.
|
||||
/// This list adds to a pre-existing, sensible default set of globs.
|
||||
/// Any additional ones you add are combined with them.
|
||||
pub disabled_globs: Vec<GlobMatcher>,
|
||||
pub disabled_globs: Vec<DisabledGlob>,
|
||||
/// Configures how edit predictions are displayed in the buffer.
|
||||
pub mode: EditPredictionsMode,
|
||||
/// Settings specific to GitHub Copilot.
|
||||
pub copilot: CopilotSettings,
|
||||
}
|
||||
|
||||
impl EditPredictionSettings {
|
||||
/// Returns whether edit predictions are enabled for the given path.
|
||||
pub fn enabled_for_file(&self, file: &Arc<dyn File>, cx: &App) -> bool {
|
||||
!self.disabled_globs.iter().any(|glob| {
|
||||
if glob.is_absolute {
|
||||
file.as_local()
|
||||
.map_or(false, |local| glob.matcher.is_match(local.abs_path(cx)))
|
||||
} else {
|
||||
glob.matcher.is_match(file.path())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DisabledGlob {
|
||||
matcher: GlobMatcher,
|
||||
is_absolute: bool,
|
||||
}
|
||||
|
||||
/// The mode in which edit predictions should be displayed.
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
|
@ -965,16 +985,12 @@ impl AllLanguageSettings {
|
|||
}
|
||||
|
||||
/// Returns whether edit predictions are enabled for the given path.
|
||||
pub fn inline_completions_enabled_for_path(&self, path: &Path) -> bool {
|
||||
!self
|
||||
.edit_predictions
|
||||
.disabled_globs
|
||||
.iter()
|
||||
.any(|glob| glob.is_match(path))
|
||||
pub fn edit_predictions_enabled_for_file(&self, file: &Arc<dyn File>, cx: &App) -> bool {
|
||||
self.edit_predictions.enabled_for_file(file, cx)
|
||||
}
|
||||
|
||||
/// Returns whether edit predictions are enabled for the given language and path.
|
||||
pub fn show_inline_completions(&self, language: Option<&Arc<Language>>, cx: &App) -> bool {
|
||||
pub fn show_edit_predictions(&self, language: Option<&Arc<Language>>, cx: &App) -> bool {
|
||||
self.language(None, language.map(|l| l.name()).as_ref(), cx)
|
||||
.show_edit_predictions
|
||||
}
|
||||
|
@ -1199,7 +1215,12 @@ impl settings::Settings for AllLanguageSettings {
|
|||
},
|
||||
disabled_globs: completion_globs
|
||||
.iter()
|
||||
.filter_map(|g| Some(globset::Glob::new(g).ok()?.compile_matcher()))
|
||||
.filter_map(|g| {
|
||||
Some(DisabledGlob {
|
||||
matcher: globset::Glob::new(g).ok()?.compile_matcher(),
|
||||
is_absolute: Path::new(g).is_absolute(),
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
mode: edit_predictions_mode,
|
||||
copilot: copilot_settings,
|
||||
|
@ -1357,6 +1378,8 @@ pub struct PrettierSettings {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use gpui::TestAppContext;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
|
@ -1401,6 +1424,132 @@ mod tests {
|
|||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_edit_predictions_enabled_for_file(cx: &mut TestAppContext) {
|
||||
use crate::TestFile;
|
||||
use std::path::PathBuf;
|
||||
|
||||
let cx = cx.app.borrow_mut();
|
||||
|
||||
let build_settings = |globs: &[&str]| -> EditPredictionSettings {
|
||||
EditPredictionSettings {
|
||||
disabled_globs: globs
|
||||
.iter()
|
||||
.map(|glob_str| {
|
||||
#[cfg(windows)]
|
||||
let glob_str = {
|
||||
let mut g = String::new();
|
||||
|
||||
if glob_str.starts_with('/') {
|
||||
g.push_str("C:");
|
||||
}
|
||||
|
||||
g.push_str(&glob_str.replace('/', "\\"));
|
||||
g
|
||||
};
|
||||
#[cfg(windows)]
|
||||
let glob_str = glob_str.as_str();
|
||||
|
||||
DisabledGlob {
|
||||
matcher: globset::Glob::new(glob_str).unwrap().compile_matcher(),
|
||||
is_absolute: Path::new(glob_str).is_absolute(),
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}
|
||||
};
|
||||
|
||||
const WORKTREE_NAME: &str = "project";
|
||||
let make_test_file = |segments: &[&str]| -> Arc<dyn File> {
|
||||
let mut path_buf = PathBuf::new();
|
||||
path_buf.extend(segments);
|
||||
|
||||
Arc::new(TestFile {
|
||||
path: path_buf.as_path().into(),
|
||||
root_name: WORKTREE_NAME.to_string(),
|
||||
local_root: Some(PathBuf::from(if cfg!(windows) {
|
||||
"C:\\absolute\\"
|
||||
} else {
|
||||
"/absolute/"
|
||||
})),
|
||||
})
|
||||
};
|
||||
|
||||
let test_file = make_test_file(&["src", "test", "file.rs"]);
|
||||
|
||||
// Test relative globs
|
||||
let settings = build_settings(&["*.rs"]);
|
||||
assert!(!settings.enabled_for_file(&test_file, &cx));
|
||||
let settings = build_settings(&["*.txt"]);
|
||||
assert!(settings.enabled_for_file(&test_file, &cx));
|
||||
|
||||
// Test absolute globs
|
||||
let settings = build_settings(&["/absolute/**/*.rs"]);
|
||||
assert!(!settings.enabled_for_file(&test_file, &cx));
|
||||
let settings = build_settings(&["/other/**/*.rs"]);
|
||||
assert!(settings.enabled_for_file(&test_file, &cx));
|
||||
|
||||
// Test exact path match relative
|
||||
let settings = build_settings(&["src/test/file.rs"]);
|
||||
assert!(!settings.enabled_for_file(&test_file, &cx));
|
||||
let settings = build_settings(&["src/test/otherfile.rs"]);
|
||||
assert!(settings.enabled_for_file(&test_file, &cx));
|
||||
|
||||
// Test exact path match absolute
|
||||
let settings = build_settings(&[&format!("/absolute/{}/src/test/file.rs", WORKTREE_NAME)]);
|
||||
assert!(!settings.enabled_for_file(&test_file, &cx));
|
||||
let settings = build_settings(&["/other/test/otherfile.rs"]);
|
||||
assert!(settings.enabled_for_file(&test_file, &cx));
|
||||
|
||||
// Test * glob
|
||||
let settings = build_settings(&["*"]);
|
||||
assert!(!settings.enabled_for_file(&test_file, &cx));
|
||||
let settings = build_settings(&["*.txt"]);
|
||||
assert!(settings.enabled_for_file(&test_file, &cx));
|
||||
|
||||
// Test **/* glob
|
||||
let settings = build_settings(&["**/*"]);
|
||||
assert!(!settings.enabled_for_file(&test_file, &cx));
|
||||
let settings = build_settings(&["other/**/*"]);
|
||||
assert!(settings.enabled_for_file(&test_file, &cx));
|
||||
|
||||
// Test directory/** glob
|
||||
let settings = build_settings(&["src/**"]);
|
||||
assert!(!settings.enabled_for_file(&test_file, &cx));
|
||||
|
||||
let test_file_root: Arc<dyn File> = Arc::new(TestFile {
|
||||
path: PathBuf::from("file.rs").as_path().into(),
|
||||
root_name: WORKTREE_NAME.to_string(),
|
||||
local_root: Some(PathBuf::from("/absolute/")),
|
||||
});
|
||||
assert!(settings.enabled_for_file(&test_file_root, &cx));
|
||||
|
||||
let settings = build_settings(&["other/**"]);
|
||||
assert!(settings.enabled_for_file(&test_file, &cx));
|
||||
|
||||
// Test **/directory/* glob
|
||||
let settings = build_settings(&["**/test/*"]);
|
||||
assert!(!settings.enabled_for_file(&test_file, &cx));
|
||||
let settings = build_settings(&["**/other/*"]);
|
||||
assert!(settings.enabled_for_file(&test_file, &cx));
|
||||
|
||||
// Test multiple globs
|
||||
let settings = build_settings(&["*.rs", "*.txt", "src/**"]);
|
||||
assert!(!settings.enabled_for_file(&test_file, &cx));
|
||||
let settings = build_settings(&["*.txt", "*.md", "other/**"]);
|
||||
assert!(settings.enabled_for_file(&test_file, &cx));
|
||||
|
||||
// Test dot files
|
||||
let dot_file = make_test_file(&[".config", "settings.json"]);
|
||||
let settings = build_settings(&[".*/**"]);
|
||||
assert!(!settings.enabled_for_file(&dot_file, &cx));
|
||||
|
||||
let dot_env_file = make_test_file(&[".env"]);
|
||||
let settings = build_settings(&[".env"]);
|
||||
assert!(!settings.enabled_for_file(&dot_env_file, &cx));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_resolve_language_servers() {
|
||||
fn language_server_names(names: &[&str]) -> Vec<LanguageServerName> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue