The `project_name` worktree setting was added in #36713 to let users override the name shown in the window title. Its description ("The displayed name of this project. If left empty, the root directory name will be displayed.") suggests broader coverage, and #46440 reports the reasonable expectation that it should also apply in the project switcher. In practice the setting has only ever affected `Workspace::update_window_title`, so everywhere else (recent projects, the multi-worktree pane, ...) keeps falling back to the worktree root name. Rather than plumb the setting through each of those surfaces, I'm removing it. Having a project-level setting control how your editor displays the project has downsides. For example it means a checkout can dictate UI in someone else's Zed. The natural home for a custom display name is the workspace DB, set from the UI, which is what we should do if we want this feature back. If you want this back, the path forward is to store the display name in `WorkspaceDb`, expose a UI affordance to edit it, and read it from `update_window_title`, `recent_projects::get_recent_projects` / `get_open_folders`, and any other places that currently derive a display name from the worktree root. Closes #46440 Release Notes: - Removed the `project_name` project setting. It only ever affected the OS window title, and the expectation that it would show up in the project switcher and elsewhere is better served by a future UI-driven, per-workspace setting stored locally.
107 lines
3.8 KiB
Rust
107 lines
3.8 KiB
Rust
use std::path::Path;
|
|
|
|
use anyhow::Context as _;
|
|
use settings::{RegisterSetting, Settings};
|
|
use util::{
|
|
ResultExt,
|
|
paths::{PathMatcher, PathStyle},
|
|
rel_path::RelPath,
|
|
};
|
|
|
|
#[derive(Clone, PartialEq, Eq, RegisterSetting)]
|
|
pub struct WorktreeSettings {
|
|
/// Whether to prevent this project from being shared in public channels.
|
|
pub prevent_sharing_in_public_channels: bool,
|
|
pub file_scan_exclusions: PathMatcher,
|
|
pub file_scan_inclusions: PathMatcher,
|
|
/// This field contains all ancestors of the `file_scan_inclusions`. It's used to
|
|
/// determine whether to terminate worktree scanning for a given dir.
|
|
pub parent_dir_scan_inclusions: PathMatcher,
|
|
pub private_files: PathMatcher,
|
|
pub hidden_files: PathMatcher,
|
|
pub read_only_files: PathMatcher,
|
|
}
|
|
|
|
impl WorktreeSettings {
|
|
pub fn is_path_private(&self, path: &RelPath) -> bool {
|
|
path.ancestors()
|
|
.any(|ancestor| self.private_files.is_match(ancestor))
|
|
}
|
|
|
|
pub fn is_path_excluded(&self, path: &RelPath) -> bool {
|
|
path.ancestors()
|
|
.any(|ancestor| self.file_scan_exclusions.is_match(ancestor))
|
|
}
|
|
|
|
pub fn is_path_always_included(&self, path: &RelPath, is_dir: bool) -> bool {
|
|
if is_dir {
|
|
self.parent_dir_scan_inclusions.is_match(path)
|
|
} else {
|
|
self.file_scan_inclusions.is_match(path)
|
|
}
|
|
}
|
|
|
|
pub fn is_path_hidden(&self, path: &RelPath) -> bool {
|
|
path.ancestors()
|
|
.any(|ancestor| self.hidden_files.is_match(ancestor))
|
|
}
|
|
|
|
pub fn is_path_read_only(&self, path: &RelPath) -> bool {
|
|
self.read_only_files.is_match(path)
|
|
}
|
|
|
|
pub fn is_std_path_read_only(&self, path: &Path) -> bool {
|
|
self.read_only_files.is_match_std_path(path)
|
|
}
|
|
}
|
|
|
|
impl Settings for WorktreeSettings {
|
|
fn from_settings(content: &settings::SettingsContent) -> Self {
|
|
let worktree = content.project.worktree.clone();
|
|
let file_scan_exclusions = worktree.file_scan_exclusions.unwrap();
|
|
let file_scan_inclusions = worktree.file_scan_inclusions.unwrap();
|
|
let private_files = worktree.private_files.unwrap().0;
|
|
let hidden_files = worktree.hidden_files.unwrap();
|
|
let read_only_files = worktree.read_only_files.unwrap_or_default();
|
|
let parsed_file_scan_inclusions: Vec<String> = file_scan_inclusions
|
|
.iter()
|
|
.flat_map(|glob| {
|
|
Path::new(glob)
|
|
.ancestors()
|
|
.skip(1)
|
|
.map(|a| a.to_string_lossy().into())
|
|
})
|
|
.filter(|p: &String| !p.is_empty())
|
|
.collect();
|
|
|
|
Self {
|
|
prevent_sharing_in_public_channels: worktree.prevent_sharing_in_public_channels,
|
|
file_scan_exclusions: path_matchers(file_scan_exclusions, "file_scan_exclusions")
|
|
.log_err()
|
|
.unwrap_or_default(),
|
|
parent_dir_scan_inclusions: path_matchers(
|
|
parsed_file_scan_inclusions,
|
|
"file_scan_inclusions",
|
|
)
|
|
.unwrap(),
|
|
file_scan_inclusions: path_matchers(file_scan_inclusions, "file_scan_inclusions")
|
|
.unwrap(),
|
|
private_files: path_matchers(private_files, "private_files")
|
|
.log_err()
|
|
.unwrap_or_default(),
|
|
hidden_files: path_matchers(hidden_files, "hidden_files")
|
|
.log_err()
|
|
.unwrap_or_default(),
|
|
read_only_files: path_matchers(read_only_files, "read_only_files")
|
|
.log_err()
|
|
.unwrap_or_default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn path_matchers(mut values: Vec<String>, context: &'static str) -> anyhow::Result<PathMatcher> {
|
|
values.sort();
|
|
PathMatcher::new(values, PathStyle::local())
|
|
.with_context(|| format!("Failed to parse globs from {}", context))
|
|
}
|