@@ -730,29 +730,38 @@ impl Element for TerminalElement {
let background_color = theme.colors().terminal_background;
- let (last_hovered_word, hover_target) = self.terminal.update(cx, |terminal, cx| {
- terminal.set_size(dimensions);
- terminal.sync(window, cx);
-
- if window.modifiers().secondary()
- && bounds.contains(&window.mouse_position())
- && self.terminal_view.read(cx).hover_target_tooltip.is_some()
- {
- let hover_target = self.terminal_view.read(cx).hover_target_tooltip.clone();
- let last_hovered_word = terminal.last_content.last_hovered_word.clone();
- (last_hovered_word, hover_target)
- } else {
- (None, None)
- }
- });
+ let (last_hovered_word, hover_tooltip) =
+ self.terminal.update(cx, |terminal, cx| {
+ terminal.set_size(dimensions);
+ terminal.sync(window, cx);
+
+ if window.modifiers().secondary()
+ && bounds.contains(&window.mouse_position())
+ && self.terminal_view.read(cx).hover.is_some()
+ {
+ let registered_hover = self.terminal_view.read(cx).hover.as_ref();
+ if terminal.last_content.last_hovered_word.as_ref()
+ == registered_hover.map(|hover| &hover.hovered_word)
+ {
+ (
+ terminal.last_content.last_hovered_word.clone(),
+ registered_hover.map(|hover| hover.tooltip.clone()),
+ )
+ } else {
+ (None, None)
+ }
+ } else {
+ (None, None)
+ }
+ });
let scroll_top = self.terminal_view.read(cx).scroll_top;
- let hyperlink_tooltip = hover_target.as_ref().map(|hover_target| {
+ let hyperlink_tooltip = hover_tooltip.map(|hover_tooltip| {
let offset = bounds.origin + point(gutter, px(0.)) - point(px(0.), scroll_top);
let mut element = div()
.size_full()
.id("terminal-element")
- .tooltip(Tooltip::text(hover_target.clone()))
+ .tooltip(Tooltip::text(hover_tooltip))
.into_any_element();
element.prepaint_as_root(offset, bounds.size.into(), window, cx);
element
@@ -922,7 +931,7 @@ impl Element for TerminalElement {
self.register_mouse_listeners(layout.mode, &layout.hitbox, window);
if window.modifiers().secondary()
&& bounds.contains(&window.mouse_position())
- && self.terminal_view.read(cx).hover_target_tooltip.is_some()
+ && self.terminal_view.read(cx).hover.is_some()
{
window.set_cursor_style(gpui::CursorStyle::PointingHand, Some(&layout.hitbox));
} else {
@@ -15,9 +15,9 @@ use persistence::TERMINAL_DB;
use project::{Entry, Metadata, Project, search::SearchQuery, terminals::TerminalKind};
use schemars::JsonSchema;
use terminal::{
- Clear, Copy, Event, MaybeNavigationTarget, Paste, ScrollLineDown, ScrollLineUp, ScrollPageDown,
- ScrollPageUp, ScrollToBottom, ScrollToTop, ShowCharacterPalette, TaskState, TaskStatus,
- Terminal, TerminalBounds, ToggleViMode,
+ Clear, Copy, Event, HoveredWord, MaybeNavigationTarget, Paste, ScrollLineDown, ScrollLineUp,
+ ScrollPageDown, ScrollPageUp, ScrollToBottom, ScrollToTop, ShowCharacterPalette, TaskState,
+ TaskStatus, Terminal, TerminalBounds, ToggleViMode,
alacritty_terminal::{
index::Point,
term::{TermMode, search::RegexSearch},
@@ -112,7 +112,7 @@ pub struct TerminalView {
cwd_serialized: bool,
blinking_paused: bool,
blink_epoch: usize,
- hover_target_tooltip: Option<String>,
+ hover: Option<HoverTarget>,
hover_tooltip_update: Task<()>,
workspace_id: Option<WorkspaceId>,
show_breadcrumbs: bool,
@@ -126,6 +126,12 @@ pub struct TerminalView {
_terminal_subscriptions: Vec<Subscription>,
}
+#[derive(Debug)]
+struct HoverTarget {
+ tooltip: String,
+ hovered_word: HoveredWord,
+}
+
impl EventEmitter<Event> for TerminalView {}
impl EventEmitter<ItemEvent> for TerminalView {}
impl EventEmitter<SearchEvent> for TerminalView {}
@@ -196,7 +202,7 @@ impl TerminalView {
blinking_terminal_enabled: false,
blinking_paused: false,
blink_epoch: 0,
- hover_target_tooltip: None,
+ hover: None,
hover_tooltip_update: Task::ready(()),
embedded,
workspace_id,
@@ -881,54 +887,79 @@ fn subscribe_for_terminal_events(
}
Event::NewNavigationTarget(maybe_navigation_target) => {
- match maybe_navigation_target.as_ref() {
- None => {
- terminal_view.hover_target_tooltip = None;
- terminal_view.hover_tooltip_update = Task::ready(());
+ match maybe_navigation_target
+ .as_ref()
+ .zip(terminal.read(cx).last_content.last_hovered_word.as_ref())
+ {
+ Some((MaybeNavigationTarget::Url(url), hovered_word)) => {
+ if Some(hovered_word)
+ != terminal_view
+ .hover
+ .as_ref()
+ .map(|hover| &hover.hovered_word)
+ {
+ terminal_view.hover = Some(HoverTarget {
+ tooltip: url.clone(),
+ hovered_word: hovered_word.clone(),
+ });
+ terminal_view.hover_tooltip_update = Task::ready(());
+ cx.notify();
+ }
}
- Some(MaybeNavigationTarget::Url(url)) => {
- terminal_view.hover_target_tooltip = Some(url.clone());
- terminal_view.hover_tooltip_update = Task::ready(());
+ Some((MaybeNavigationTarget::PathLike(path_like_target), hovered_word)) => {
+ if Some(hovered_word)
+ != terminal_view
+ .hover
+ .as_ref()
+ .map(|hover| &hover.hovered_word)
+ {
+ let valid_files_to_open_task = possible_open_target(
+ &workspace,
+ &path_like_target.terminal_dir,
+ &path_like_target.maybe_path,
+ cx,
+ );
+ let hovered_word = hovered_word.clone();
+
+ terminal_view.hover = None;
+ terminal_view.hover_tooltip_update =
+ cx.spawn(async move |terminal_view, cx| {
+ let file_to_open = valid_files_to_open_task.await;
+ terminal_view
+ .update(cx, |terminal_view, _| match file_to_open {
+ Some(
+ OpenTarget::File(path, _)
+ | OpenTarget::Worktree(path, _),
+ ) => {
+ terminal_view.hover = Some(HoverTarget {
+ tooltip: path.to_string(|path| {
+ path.to_string_lossy().to_string()
+ }),
+ hovered_word,
+ });
+ }
+ None => {
+ terminal_view.hover = None;
+ }
+ })
+ .ok();
+ });
+ cx.notify();
+ }
}
- Some(MaybeNavigationTarget::PathLike(path_like_target)) => {
- let valid_files_to_open_task = possible_open_target(
- &workspace,
- &path_like_target.terminal_dir,
- &path_like_target.maybe_path,
- cx,
- );
-
- terminal_view.hover_tooltip_update =
- cx.spawn(async move |terminal_view, cx| {
- let file_to_open = valid_files_to_open_task.await;
- terminal_view
- .update(cx, |terminal_view, _| match file_to_open {
- Some(
- OpenTarget::File(path, _)
- | OpenTarget::Worktree(path, _),
- ) => {
- terminal_view.hover_target_tooltip =
- Some(path.to_string(|path| {
- path.to_string_lossy().to_string()
- }));
- }
- None => {
- terminal_view.hover_target_tooltip = None;
- }
- })
- .ok();
- });
+ None => {
+ terminal_view.hover = None;
+ terminal_view.hover_tooltip_update = Task::ready(());
+ cx.notify();
}
}
-
- cx.notify()
}
Event::Open(maybe_navigation_target) => match maybe_navigation_target {
MaybeNavigationTarget::Url(url) => cx.open_url(url),
MaybeNavigationTarget::PathLike(path_like_target) => {
- if terminal_view.hover_target_tooltip.is_none() {
+ if terminal_view.hover.is_none() {
return;
}
let task_workspace = workspace.clone();