mirror of
https://github.com/zed-industries/zed.git
synced 2026-05-31 19:05:00 +07:00
Preserve terminal spinners in thread titles (#57983)
Summary: - Preserve spinner/logo prefixes from live terminal titles when terminal threads have custom titles. - Store raw terminal titles and custom user titles separately, recomposing display titles on demand. - Keep spinner prefixes out of the title editor while preserving sidebar/search display behavior. Tests: - cargo test -p agent_ui test_terminal_custom_title_recomposes_with_live_spinner -- --nocapture - cargo test -p agent_ui test_terminal_title_editor_excludes_spinner_prefix -- --nocapture - cargo test -p sidebar test_agent_panel_terminals_appear_in_sidebar_and_search -- --nocapture Closes AI-304 Release Notes: - Fixed terminal thread titles to preserve animated spinner and logo prefixes after renaming.
This commit is contained in:
parent
12aacf3cea
commit
e5f5767d2c
5 changed files with 348 additions and 43 deletions
|
|
@ -38,7 +38,10 @@ use crate::ExpandMessageEditor;
|
|||
use crate::ManageProfiles;
|
||||
use crate::agent_connection_store::AgentConnectionStore;
|
||||
use crate::completion_provider::AgentContextSource;
|
||||
use crate::terminal_thread_metadata_store::{TerminalThreadMetadata, TerminalThreadMetadataStore};
|
||||
use crate::terminal_thread_metadata_store::{
|
||||
TerminalThreadMetadata, TerminalThreadMetadataStore, compose_terminal_thread_title,
|
||||
terminal_title_without_prefix,
|
||||
};
|
||||
use crate::thread_metadata_store::{ThreadId, ThreadMetadataStore, ThreadMetadataStoreEvent};
|
||||
use crate::{
|
||||
AddContextServer, AgentDiffPane, ConversationView, CopyThreadToClipboard, Follow,
|
||||
|
|
@ -870,6 +873,7 @@ struct AgentTerminal {
|
|||
title_editor_initial_title: Option<String>,
|
||||
title_editor_subscription: Option<Subscription>,
|
||||
last_known_title: String,
|
||||
last_known_terminal_title: String,
|
||||
last_observed_program: Option<String>,
|
||||
working_directory: Option<PathBuf>,
|
||||
created_at: DateTime<Utc>,
|
||||
|
|
@ -880,32 +884,58 @@ struct AgentTerminal {
|
|||
}
|
||||
|
||||
impl AgentTerminal {
|
||||
fn title(&self, cx: &App) -> SharedString {
|
||||
let view = self.view.read(cx);
|
||||
let title = if let Some(custom_title) = view.custom_title() {
|
||||
SharedString::from(custom_title)
|
||||
} else {
|
||||
let terminal = view.terminal().read(cx);
|
||||
if terminal.breadcrumb_text.is_empty() {
|
||||
let title = terminal.title(true);
|
||||
if title == "Terminal" {
|
||||
SharedString::from("")
|
||||
} else {
|
||||
title.into()
|
||||
}
|
||||
fn terminal_title_for_view(view: &TerminalView, cx: &App) -> SharedString {
|
||||
let terminal = view.terminal().read(cx);
|
||||
if terminal.breadcrumb_text.is_empty() {
|
||||
let title = terminal.title(true);
|
||||
if title == "Terminal" {
|
||||
SharedString::from("")
|
||||
} else {
|
||||
terminal.breadcrumb_text.clone().into()
|
||||
title.into()
|
||||
}
|
||||
};
|
||||
} else {
|
||||
terminal.breadcrumb_text.clone().into()
|
||||
}
|
||||
}
|
||||
|
||||
if title.is_empty() && !self.last_known_title.is_empty() {
|
||||
SharedString::from(self.last_known_title.clone())
|
||||
fn current_terminal_title(&self, cx: &App) -> SharedString {
|
||||
let view = self.view.read(cx);
|
||||
Self::terminal_title_for_view(view, cx)
|
||||
}
|
||||
|
||||
fn terminal_title(&self, cx: &App) -> SharedString {
|
||||
let title = self.current_terminal_title(cx);
|
||||
if title.is_empty() && !self.last_known_terminal_title.is_empty() {
|
||||
SharedString::from(self.last_known_terminal_title.clone())
|
||||
} else {
|
||||
title
|
||||
}
|
||||
}
|
||||
|
||||
fn title(&self, cx: &App) -> SharedString {
|
||||
let terminal_title = self.terminal_title(cx);
|
||||
let custom_title = self.custom_title(cx);
|
||||
compose_terminal_thread_title(
|
||||
terminal_title.as_ref(),
|
||||
custom_title.as_ref().map(|title| title.as_ref()),
|
||||
)
|
||||
}
|
||||
|
||||
fn editable_title(&self, cx: &App) -> SharedString {
|
||||
if let Some(custom_title) = self.custom_title(cx) {
|
||||
custom_title
|
||||
} else {
|
||||
let terminal_title = self.terminal_title(cx);
|
||||
SharedString::from(terminal_title_without_prefix(terminal_title.as_ref()).to_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn refresh_title(&mut self, cx: &mut App) -> bool {
|
||||
let terminal_title = self.current_terminal_title(cx);
|
||||
if !terminal_title.is_empty() {
|
||||
self.last_known_terminal_title = terminal_title.to_string();
|
||||
}
|
||||
|
||||
let title = self.title(cx);
|
||||
let changed = self.last_known_title != title.as_ref();
|
||||
if changed {
|
||||
|
|
@ -1981,14 +2011,16 @@ impl AgentPanel {
|
|||
},
|
||||
);
|
||||
|
||||
let last_known_terminal_title = initial_title
|
||||
.map(|title| title.to_string())
|
||||
.unwrap_or_default();
|
||||
let mut terminal = AgentTerminal {
|
||||
view: terminal_view,
|
||||
title_editor: None,
|
||||
title_editor_initial_title: None,
|
||||
title_editor_subscription: None,
|
||||
last_known_title: initial_title
|
||||
.map(|title| title.to_string())
|
||||
.unwrap_or_default(),
|
||||
last_known_title: last_known_terminal_title.clone(),
|
||||
last_known_terminal_title,
|
||||
last_observed_program: None,
|
||||
working_directory,
|
||||
created_at: created_at.unwrap_or_else(Utc::now),
|
||||
|
|
@ -2164,7 +2196,7 @@ impl AgentPanel {
|
|||
let project = self.project.read(cx);
|
||||
Some(TerminalThreadMetadata {
|
||||
terminal_id,
|
||||
title: terminal.title(cx),
|
||||
title: terminal.terminal_title(cx),
|
||||
custom_title: terminal.custom_title(cx),
|
||||
created_at: terminal.created_at,
|
||||
worktree_paths: project.worktree_paths(cx),
|
||||
|
|
@ -2242,10 +2274,7 @@ impl AgentPanel {
|
|||
}
|
||||
|
||||
fn terminal_restore_initial_title(metadata: &TerminalThreadMetadata) -> Option<SharedString> {
|
||||
metadata
|
||||
.custom_title
|
||||
.clone()
|
||||
.or_else(|| (!metadata.title.is_empty()).then(|| metadata.title.clone()))
|
||||
(!metadata.title.is_empty()).then(|| metadata.title.clone())
|
||||
}
|
||||
|
||||
fn edit_terminal_title(
|
||||
|
|
@ -2263,7 +2292,7 @@ impl AgentPanel {
|
|||
return;
|
||||
}
|
||||
|
||||
let title = terminal.title(cx).to_string();
|
||||
let title = terminal.editable_title(cx).to_string();
|
||||
let title_editor_initial_title = title.clone();
|
||||
let title_editor = cx.new(|cx| {
|
||||
let mut editor = Editor::single_line(window, cx);
|
||||
|
|
@ -2331,7 +2360,7 @@ impl AgentPanel {
|
|||
if !title_editor.read(cx).is_focused(window) {
|
||||
return;
|
||||
}
|
||||
let Some((terminal_view, initial_title)) =
|
||||
let Some((terminal_view, initial_title, terminal_title)) =
|
||||
self.terminals.get(&terminal_id).and_then(|terminal| {
|
||||
terminal
|
||||
.title_editor
|
||||
|
|
@ -2341,25 +2370,23 @@ impl AgentPanel {
|
|||
(
|
||||
terminal.view.clone(),
|
||||
terminal.title_editor_initial_title.clone(),
|
||||
terminal.terminal_title(cx),
|
||||
)
|
||||
})
|
||||
})
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let new_title = title_editor.read(cx).text(cx).trim().to_string();
|
||||
if initial_title.as_deref().map(str::trim) == Some(new_title.as_str()) {
|
||||
let new_title = title_editor.read(cx).text(cx);
|
||||
if initial_title.as_deref() == Some(new_title.as_str()) {
|
||||
return;
|
||||
}
|
||||
let label = if new_title.is_empty() {
|
||||
let label = if new_title.trim().is_empty()
|
||||
|| new_title == terminal_title_without_prefix(terminal_title.as_ref())
|
||||
{
|
||||
None
|
||||
} else {
|
||||
let terminal_title = terminal_view.read(cx).terminal().read(cx).title(true);
|
||||
if new_title == terminal_title {
|
||||
None
|
||||
} else {
|
||||
Some(new_title)
|
||||
}
|
||||
Some(new_title)
|
||||
};
|
||||
|
||||
cx.defer(move |cx| {
|
||||
|
|
@ -9008,6 +9035,182 @@ mod tests {
|
|||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_terminal_custom_title_recomposes_with_live_spinner(cx: &mut TestAppContext) {
|
||||
let (panel, mut cx) = setup_panel(cx).await;
|
||||
let terminal_id = panel
|
||||
.update_in(&mut cx, |panel, window, cx| {
|
||||
panel.insert_test_terminal("Fix bug", true, window, cx)
|
||||
})
|
||||
.expect("test terminal should be inserted");
|
||||
cx.run_until_parked();
|
||||
|
||||
let terminal_entity = panel.read_with(&cx, |panel, _cx| {
|
||||
panel
|
||||
.terminals
|
||||
.get(&terminal_id)
|
||||
.expect("terminal should remain in the panel")
|
||||
.view
|
||||
.clone()
|
||||
});
|
||||
let terminal_entity =
|
||||
terminal_entity.read_with(&cx, |terminal_view, _cx| terminal_view.terminal().clone());
|
||||
|
||||
terminal_entity.update(&mut cx, |terminal, cx| {
|
||||
terminal.breadcrumb_text = "⠋ Thinking".to_string();
|
||||
cx.emit(TerminalEvent::BreadcrumbsChanged);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
|
||||
panel.read_with(&cx, |panel, cx| {
|
||||
let terminals = panel.terminals(cx);
|
||||
assert_eq!(terminals.len(), 1);
|
||||
assert_eq!(terminals[0].title.as_ref(), "⠋ Fix bug");
|
||||
let metadata = panel
|
||||
.terminal_metadata(terminal_id, cx)
|
||||
.expect("terminal metadata should be available");
|
||||
assert_eq!(metadata.title.as_ref(), "⠋ Thinking");
|
||||
assert_eq!(
|
||||
metadata.custom_title.as_ref().map(|title| title.as_ref()),
|
||||
Some("Fix bug")
|
||||
);
|
||||
assert_eq!(metadata.display_title().as_ref(), "⠋ Fix bug");
|
||||
});
|
||||
|
||||
terminal_entity.update(&mut cx, |terminal, cx| {
|
||||
terminal.breadcrumb_text = "⠙ Thinking".to_string();
|
||||
cx.emit(TerminalEvent::BreadcrumbsChanged);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
|
||||
panel.read_with(&cx, |panel, cx| {
|
||||
let terminals = panel.terminals(cx);
|
||||
assert_eq!(terminals.len(), 1);
|
||||
assert_eq!(terminals[0].title.as_ref(), "⠙ Fix bug");
|
||||
let metadata = panel
|
||||
.terminal_metadata(terminal_id, cx)
|
||||
.expect("terminal metadata should be available");
|
||||
assert_eq!(metadata.title.as_ref(), "⠙ Thinking");
|
||||
assert_eq!(metadata.display_title().as_ref(), "⠙ Fix bug");
|
||||
});
|
||||
|
||||
terminal_entity.update(&mut cx, |terminal, cx| {
|
||||
terminal.breadcrumb_text = "Thinking".to_string();
|
||||
cx.emit(TerminalEvent::BreadcrumbsChanged);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
|
||||
panel.read_with(&cx, |panel, cx| {
|
||||
let terminals = panel.terminals(cx);
|
||||
assert_eq!(terminals.len(), 1);
|
||||
assert_eq!(terminals[0].title.as_ref(), "Fix bug");
|
||||
let metadata = panel
|
||||
.terminal_metadata(terminal_id, cx)
|
||||
.expect("terminal metadata should be available");
|
||||
assert_eq!(metadata.title.as_ref(), "Thinking");
|
||||
assert_eq!(metadata.display_title().as_ref(), "Fix bug");
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_terminal_title_editor_excludes_spinner_prefix(cx: &mut TestAppContext) {
|
||||
let (panel, mut cx) = setup_panel(cx).await;
|
||||
let terminal_id = panel
|
||||
.update_in(&mut cx, |panel, window, cx| {
|
||||
panel.insert_test_terminal("Initial Custom Title", true, window, cx)
|
||||
})
|
||||
.expect("test terminal should be inserted");
|
||||
cx.run_until_parked();
|
||||
|
||||
let terminal_view = panel.read_with(&cx, |panel, _cx| {
|
||||
panel
|
||||
.terminals
|
||||
.get(&terminal_id)
|
||||
.expect("terminal should remain in the panel")
|
||||
.view
|
||||
.clone()
|
||||
});
|
||||
terminal_view.update(&mut cx, |terminal_view, cx| {
|
||||
terminal_view.set_custom_title(None, cx);
|
||||
});
|
||||
let terminal_entity =
|
||||
terminal_view.read_with(&cx, |terminal_view, _cx| terminal_view.terminal().clone());
|
||||
terminal_entity.update(&mut cx, |terminal, cx| {
|
||||
terminal.breadcrumb_text = "⠋ Thinking".to_string();
|
||||
cx.emit(TerminalEvent::BreadcrumbsChanged);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
|
||||
panel.update_in(&mut cx, |panel, window, cx| {
|
||||
panel.edit_terminal_title(terminal_id, window, cx);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
|
||||
let title_editor = panel.read_with(&cx, |panel, cx| {
|
||||
let terminal = panel
|
||||
.terminals
|
||||
.get(&terminal_id)
|
||||
.expect("terminal should remain in the panel");
|
||||
let title_editor = terminal
|
||||
.title_editor
|
||||
.as_ref()
|
||||
.expect("terminal title editor should be active while editing")
|
||||
.clone();
|
||||
assert_eq!(title_editor.read(cx).text(cx), "Thinking");
|
||||
title_editor
|
||||
});
|
||||
|
||||
title_editor.update_in(&mut cx, |editor, window, cx| {
|
||||
editor.set_text("Fix bug", window, cx);
|
||||
editor.focus_handle(cx).focus(window, cx);
|
||||
});
|
||||
panel.update_in(&mut cx, |panel, window, cx| {
|
||||
panel.handle_terminal_title_editor_event(
|
||||
terminal_id,
|
||||
&title_editor,
|
||||
&editor::EditorEvent::BufferEdited,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
|
||||
terminal_view.read_with(&cx, |terminal_view, _cx| {
|
||||
assert_eq!(terminal_view.custom_title(), Some("Fix bug"));
|
||||
});
|
||||
panel.read_with(&cx, |panel, cx| {
|
||||
let terminals = panel.terminals(cx);
|
||||
assert_eq!(terminals.len(), 1);
|
||||
assert_eq!(terminals[0].title.as_ref(), "⠋ Fix bug");
|
||||
let metadata = panel
|
||||
.terminal_metadata(terminal_id, cx)
|
||||
.expect("terminal metadata should be available");
|
||||
assert_eq!(metadata.title.as_ref(), "⠋ Thinking");
|
||||
assert_eq!(
|
||||
metadata.custom_title.as_ref().map(|title| title.as_ref()),
|
||||
Some("Fix bug")
|
||||
);
|
||||
});
|
||||
|
||||
panel.update_in(&mut cx, |panel, window, cx| {
|
||||
panel.stop_editing_terminal_title(terminal_id, false, window, cx);
|
||||
panel.edit_terminal_title(terminal_id, window, cx);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
|
||||
panel.read_with(&cx, |panel, cx| {
|
||||
let terminal = panel
|
||||
.terminals
|
||||
.get(&terminal_id)
|
||||
.expect("terminal should remain in the panel");
|
||||
let title_editor = terminal
|
||||
.title_editor
|
||||
.as_ref()
|
||||
.expect("terminal title editor should be active while editing");
|
||||
assert_eq!(title_editor.read(cx).text(cx), "Fix bug");
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_terminal_bell_marks_and_activation_clears_notification(cx: &mut TestAppContext) {
|
||||
let (panel, mut cx) = setup_panel(cx).await;
|
||||
|
|
|
|||
|
|
@ -63,6 +63,76 @@ impl TerminalThreadMetadata {
|
|||
pub fn main_worktree_paths(&self) -> &PathList {
|
||||
self.worktree_paths.main_worktree_path_list()
|
||||
}
|
||||
|
||||
pub fn display_title(&self) -> SharedString {
|
||||
compose_terminal_thread_title(
|
||||
self.title.as_ref(),
|
||||
self.custom_title.as_ref().map(|title| title.as_ref()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compose_terminal_thread_title(
|
||||
terminal_title: &str,
|
||||
custom_title: Option<&str>,
|
||||
) -> SharedString {
|
||||
let Some(custom_title) = custom_title.filter(|title| !title.trim().is_empty()) else {
|
||||
return SharedString::from(terminal_title.to_string());
|
||||
};
|
||||
|
||||
if let Some(prefix) = terminal_title_prefix(terminal_title) {
|
||||
SharedString::from(format!("{prefix}{custom_title}"))
|
||||
} else {
|
||||
SharedString::from(custom_title.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn terminal_title_without_prefix(title: &str) -> &str {
|
||||
terminal_title_prefix(title)
|
||||
.map(|prefix| &title[prefix.len()..])
|
||||
.unwrap_or(title)
|
||||
}
|
||||
|
||||
fn terminal_title_prefix(title: &str) -> Option<&str> {
|
||||
let mut prefix_byte_len = 0;
|
||||
let mut saw_prefix_character = false;
|
||||
let mut saw_whitespace_after_prefix = false;
|
||||
|
||||
let mut chars = title.chars().peekable();
|
||||
while let Some(character) = chars.next() {
|
||||
if character.is_alphanumeric() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if character.is_whitespace() {
|
||||
if !saw_prefix_character {
|
||||
return None;
|
||||
}
|
||||
|
||||
prefix_byte_len += character.len_utf8();
|
||||
saw_whitespace_after_prefix = true;
|
||||
|
||||
while let Some(character) = chars.peek() {
|
||||
if !character.is_whitespace() {
|
||||
break;
|
||||
}
|
||||
|
||||
prefix_byte_len += character.len_utf8();
|
||||
chars.next();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
saw_prefix_character = true;
|
||||
prefix_byte_len += character.len_utf8();
|
||||
}
|
||||
|
||||
if saw_whitespace_after_prefix {
|
||||
Some(&title[..prefix_byte_len])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TerminalThreadMetadataStore {
|
||||
|
|
@ -563,6 +633,32 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_terminal_title_prefix_preserves_non_alphanumeric_prefixes() {
|
||||
assert_eq!(terminal_title_prefix("✳ Thinking"), Some("✳ "));
|
||||
assert_eq!(terminal_title_prefix(">>> Thinking"), Some(">>> "));
|
||||
assert_eq!(terminal_title_prefix("⠋ Running"), Some("⠋ "));
|
||||
assert_eq!(terminal_title_prefix("* Claude"), Some("* "));
|
||||
assert_eq!(terminal_title_prefix("✳Thinking"), None);
|
||||
assert_eq!(terminal_title_prefix("Thinking"), None);
|
||||
assert_eq!(terminal_title_prefix(" Thinking"), None);
|
||||
assert_eq!(terminal_title_prefix("✳"), None);
|
||||
assert_eq!(terminal_title_prefix("v1 Running"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_terminal_thread_display_title_combines_raw_and_custom_titles() {
|
||||
let mut metadata = metadata(
|
||||
"⠋ Thinking",
|
||||
WorktreePaths::from_folder_paths(&PathList::default()),
|
||||
);
|
||||
metadata.custom_title = Some("Fix bug".into());
|
||||
assert_eq!(metadata.display_title().as_ref(), "⠋ Fix bug");
|
||||
|
||||
metadata.title = "Thinking".into();
|
||||
assert_eq!(metadata.display_title().as_ref(), "Fix bug");
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_change_worktree_paths_reindexes_terminal_metadata(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
|
|
|||
|
|
@ -1735,7 +1735,8 @@ impl Sidebar {
|
|||
let mut matched_terminals: Vec<TerminalEntry> = Vec::new();
|
||||
for mut terminal in terminals {
|
||||
let mut terminal_matched = false;
|
||||
if let Some(positions) = fuzzy_match_positions(&query, &terminal.metadata.title)
|
||||
let terminal_title = terminal.metadata.display_title();
|
||||
if let Some(positions) = fuzzy_match_positions(&query, terminal_title.as_ref())
|
||||
{
|
||||
terminal.highlight_positions = positions;
|
||||
terminal_matched = true;
|
||||
|
|
@ -5858,7 +5859,7 @@ impl Sidebar {
|
|||
);
|
||||
let is_remote = terminal.workspace.is_remote(cx);
|
||||
|
||||
ThreadItem::new(id, terminal.metadata.title.clone())
|
||||
ThreadItem::new(id, terminal.metadata.display_title())
|
||||
.base_bg(sidebar_bg)
|
||||
.icon(IconName::Terminal)
|
||||
.is_remote(is_remote)
|
||||
|
|
|
|||
|
|
@ -595,7 +595,7 @@ fn visible_entries_as_strings(
|
|||
}
|
||||
}
|
||||
ListEntry::Terminal(terminal) => {
|
||||
let title = &terminal.metadata.title;
|
||||
let title = terminal.metadata.display_title();
|
||||
let worktree = format_linked_worktree_chips(&terminal.worktrees);
|
||||
format!(" {title}{worktree}{selected}")
|
||||
}
|
||||
|
|
@ -1712,7 +1712,7 @@ async fn test_agent_panel_terminals_appear_in_sidebar_and_search(cx: &mut TestAp
|
|||
);
|
||||
assert!(
|
||||
sidebar.contents.entries.iter().any(|entry| {
|
||||
matches!(entry, ListEntry::Terminal(terminal) if terminal.metadata.terminal_id == terminal_id && terminal.metadata.title.as_ref() == "Dev Server")
|
||||
matches!(entry, ListEntry::Terminal(terminal) if terminal.metadata.terminal_id == terminal_id && terminal.metadata.display_title().as_ref() == "Dev Server")
|
||||
}),
|
||||
"expected the inserted terminal to appear in sidebar contents",
|
||||
);
|
||||
|
|
@ -1722,7 +1722,12 @@ async fn test_agent_panel_terminals_appear_in_sidebar_and_search(cx: &mut TestAp
|
|||
let metadata = store
|
||||
.entry(terminal_id)
|
||||
.expect("terminal metadata should be persisted");
|
||||
assert_eq!(metadata.title.as_ref(), "Dev Server");
|
||||
assert_eq!(metadata.title.as_ref(), "");
|
||||
assert_eq!(
|
||||
metadata.custom_title.as_ref().map(|title| title.as_ref()),
|
||||
Some("Dev Server")
|
||||
);
|
||||
assert_eq!(metadata.display_title().as_ref(), "Dev Server");
|
||||
assert!(
|
||||
metadata
|
||||
.folder_paths()
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ impl ThreadSwitcherEntry {
|
|||
fn title(&self) -> SharedString {
|
||||
match self {
|
||||
Self::Thread(entry) => entry.title.clone(),
|
||||
Self::Terminal(entry) => entry.metadata.title.clone(),
|
||||
Self::Terminal(entry) => entry.metadata.display_title(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue