Differentiate among tabs with the same name
This commit introduces a new, optional `Item::tab_description` method that lets implementers define a description for the tab with a certain `detail`. When two or more tabs match the same description, we will increase the `detail` until tabs don't match anymore or increasing the `detail` doesn't disambiguate tabs any further. As soon as we find a valid `detail` that disambiguates tabs enough, we will pass it to `Item::tab_content`. In `Editor`, this is implemented by showing more and more of the path's suffix as `detail` is increased.
This commit is contained in:
@@ -1073,7 +1073,7 @@ impl Editor {
|
||||
&self.buffer
|
||||
}
|
||||
|
||||
pub fn title(&self, cx: &AppContext) -> String {
|
||||
pub fn title<'a>(&self, cx: &'a AppContext) -> Cow<'a, str> {
|
||||
self.buffer().read(cx).title(cx)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use crate::{Anchor, Autoscroll, Editor, Event, ExcerptId, NavigationData, ToPoint as _};
|
||||
use crate::{
|
||||
Anchor, Autoscroll, Editor, Event, ExcerptId, MultiBuffer, NavigationData, ToPoint as _,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use futures::FutureExt;
|
||||
use gpui::{
|
||||
@@ -10,7 +12,12 @@ use project::{File, Project, ProjectEntryId, ProjectPath};
|
||||
use rpc::proto::{self, update_view};
|
||||
use settings::Settings;
|
||||
use smallvec::SmallVec;
|
||||
use std::{fmt::Write, path::PathBuf, time::Duration};
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
fmt::Write,
|
||||
path::{Path, PathBuf},
|
||||
time::Duration,
|
||||
};
|
||||
use text::{Point, Selection};
|
||||
use util::TryFutureExt;
|
||||
use workspace::{FollowableItem, Item, ItemHandle, ItemNavHistory, ProjectItem, StatusItemView};
|
||||
@@ -292,9 +299,39 @@ impl Item for Editor {
|
||||
}
|
||||
}
|
||||
|
||||
fn tab_content(&self, style: &theme::Tab, cx: &AppContext) -> ElementBox {
|
||||
let title = self.title(cx);
|
||||
Label::new(title, style.label.clone()).boxed()
|
||||
fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option<Cow<'a, str>> {
|
||||
match path_for_buffer(&self.buffer, detail, true, cx)? {
|
||||
Cow::Borrowed(path) => Some(path.to_string_lossy()),
|
||||
Cow::Owned(path) => Some(path.to_string_lossy().to_string().into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn tab_content(
|
||||
&self,
|
||||
detail: Option<usize>,
|
||||
style: &theme::Tab,
|
||||
cx: &AppContext,
|
||||
) -> ElementBox {
|
||||
Flex::row()
|
||||
.with_child(
|
||||
Label::new(self.title(cx).into(), style.label.clone())
|
||||
.aligned()
|
||||
.boxed(),
|
||||
)
|
||||
.with_children(detail.and_then(|detail| {
|
||||
let path = path_for_buffer(&self.buffer, detail, false, cx)?;
|
||||
Some(
|
||||
Label::new(
|
||||
path.to_string_lossy().into(),
|
||||
style.description.text.clone(),
|
||||
)
|
||||
.contained()
|
||||
.with_style(style.description.container)
|
||||
.aligned()
|
||||
.boxed(),
|
||||
)
|
||||
}))
|
||||
.boxed()
|
||||
}
|
||||
|
||||
fn project_path(&self, cx: &AppContext) -> Option<ProjectPath> {
|
||||
@@ -534,3 +571,38 @@ impl StatusItemView for CursorPosition {
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
fn path_for_buffer<'a>(
|
||||
buffer: &ModelHandle<MultiBuffer>,
|
||||
mut depth: usize,
|
||||
include_filename: bool,
|
||||
cx: &'a AppContext,
|
||||
) -> Option<Cow<'a, Path>> {
|
||||
let file = buffer.read(cx).as_singleton()?.read(cx).file()?;
|
||||
|
||||
let mut path = file.path().as_ref();
|
||||
depth += 1;
|
||||
while depth > 0 {
|
||||
if let Some(parent) = path.parent() {
|
||||
path = parent;
|
||||
depth -= 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if depth > 0 {
|
||||
let full_path = file.full_path(cx);
|
||||
if include_filename {
|
||||
Some(full_path.into())
|
||||
} else {
|
||||
Some(full_path.parent().unwrap().to_path_buf().into())
|
||||
}
|
||||
} else {
|
||||
let mut path = file.path().strip_prefix(path).unwrap();
|
||||
if !include_filename {
|
||||
path = path.parent().unwrap();
|
||||
}
|
||||
Some(path.into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ use language::{
|
||||
use settings::Settings;
|
||||
use smallvec::SmallVec;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
cell::{Ref, RefCell},
|
||||
cmp, fmt, io,
|
||||
iter::{self, FromIterator},
|
||||
@@ -1194,14 +1195,14 @@ impl MultiBuffer {
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn title(&self, cx: &AppContext) -> String {
|
||||
if let Some(title) = self.title.clone() {
|
||||
return title;
|
||||
pub fn title<'a>(&'a self, cx: &'a AppContext) -> Cow<'a, str> {
|
||||
if let Some(title) = self.title.as_ref() {
|
||||
return title.into();
|
||||
}
|
||||
|
||||
if let Some(buffer) = self.as_singleton() {
|
||||
if let Some(file) = buffer.read(cx).file() {
|
||||
return file.file_name(cx).to_string_lossy().into();
|
||||
return file.file_name(cx).to_string_lossy();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user