From 82a9d53c8aca67ca511baf0c94300608ab6a0ec8 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Tue, 18 Jul 2023 01:13:27 +0300 Subject: [PATCH] Only highlight the openable things --- crates/terminal/src/terminal.rs | 50 ++++++++++--- crates/terminal_view/src/terminal_view.rs | 85 ++++++++++++++--------- 2 files changed, 94 insertions(+), 41 deletions(-) diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index fae79eda1d..17bfa1550e 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -33,6 +33,7 @@ use mappings::mouse::{ use procinfo::LocalProcessInfo; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use smol::channel::Sender; use util::truncate_and_trailoff; use std::{ @@ -89,10 +90,12 @@ pub enum Event { Wakeup, BlinkChanged, SelectionsChanged, - Open { - is_url: bool, - maybe_url_or_path: String, + OpenUrl(String), + ProbePathOpen { + maybe_path: String, + can_open_tx: Sender, }, + OpenPath(String), } #[derive(Clone)] @@ -874,12 +877,43 @@ impl Terminal { if let Some((maybe_url_or_path, is_url, url_match)) = found_url { if *open { - cx.emit(Event::Open { - is_url, - maybe_url_or_path, - }) + let event = if is_url { + Event::OpenUrl(maybe_url_or_path) + } else { + Event::OpenPath(maybe_url_or_path) + }; + cx.emit(event); } else { - self.update_selected_word(prev_hovered_word, maybe_url_or_path, url_match); + if is_url { + self.update_selected_word( + prev_hovered_word, + maybe_url_or_path, + url_match, + ); + } else { + let (can_open_tx, can_open_rx) = smol::channel::bounded(1); + cx.emit(Event::ProbePathOpen { + maybe_path: maybe_url_or_path.clone(), + can_open_tx, + }); + + cx.spawn(|terminal, mut cx| async move { + let can_open = can_open_rx.recv().await.unwrap_or(false); + terminal.update(&mut cx, |terminal, cx| { + if can_open { + terminal.update_selected_word( + prev_hovered_word, + maybe_url_or_path, + url_match, + ); + } else { + terminal.last_content.last_hovered_word.take(); + } + cx.notify(); + }); + }) + .detach(); + }; } } } diff --git a/crates/terminal_view/src/terminal_view.rs b/crates/terminal_view/src/terminal_view.rs index 49f334b2d9..f0371fcb3e 100644 --- a/crates/terminal_view/src/terminal_view.rs +++ b/crates/terminal_view/src/terminal_view.rs @@ -166,42 +166,27 @@ impl TerminalView { .detach(); } } - Event::Open { - is_url, - maybe_url_or_path, + Event::ProbePathOpen { + maybe_path, + can_open_tx, } => { - if *is_url { - cx.platform().open_url(maybe_url_or_path); - } else if let Some(workspace) = workspace.upgrade(cx) { - let path_like = - PathLikeWithPosition::parse_str(maybe_url_or_path.as_str(), |path_str| { - Ok::<_, std::convert::Infallible>(Path::new(path_str).to_path_buf()) - }) - .expect("infallible"); - let maybe_path = path_like.path_like; - workspace.update(cx, |workspace, cx| { - let potential_abs_paths = if maybe_path.is_absolute() { - vec![maybe_path] - } else { + let can_open = !possible_open_targets(&workspace, maybe_path, cx).is_empty(); + can_open_tx.send_blocking(can_open).ok(); + } + Event::OpenUrl(url) => cx.platform().open_url(url), + Event::OpenPath(maybe_path) => { + let potential_abs_paths = possible_open_targets(&workspace, maybe_path, cx); + if let Some(path) = potential_abs_paths.into_iter().next() { + // TODO kb change selections using path_like row & column + let visible = path.path_like.is_dir(); + if let Some(workspace) = workspace.upgrade(cx) { + workspace.update(cx, |workspace, cx| { workspace - .worktrees(cx) - .map(|worktree| worktree.read(cx).abs_path().join(&maybe_path)) - .collect() - }; - - for path in potential_abs_paths { - if path.exists() { - let visible = path.is_dir(); - workspace - .open_abs_path(path, visible, cx) - .detach_and_log_err(cx); - break; - } - } - }); + .open_abs_path(path.path_like, visible, cx) + .detach_and_log_err(cx); + }); + } } - - // TODO kb let terminal know if we cannot open the string + remove the error message when folder open returns None } _ => cx.emit(event.clone()), }) @@ -389,6 +374,40 @@ impl TerminalView { } } +fn possible_open_targets( + workspace: &WeakViewHandle, + maybe_path: &String, + cx: &mut ViewContext<'_, '_, TerminalView>, +) -> Vec> { + let path_like = PathLikeWithPosition::parse_str(maybe_path.as_str(), |path_str| { + Ok::<_, std::convert::Infallible>(Path::new(path_str).to_path_buf()) + }) + .expect("infallible"); + let maybe_path = path_like.path_like; + let potential_abs_paths = if maybe_path.is_absolute() { + vec![maybe_path] + } else if let Some(workspace) = workspace.upgrade(cx) { + workspace.update(cx, |workspace, cx| { + workspace + .worktrees(cx) + .map(|worktree| worktree.read(cx).abs_path().join(&maybe_path)) + .collect() + }) + } else { + Vec::new() + }; + + potential_abs_paths + .into_iter() + .filter(|path| path.exists()) + .map(|path| PathLikeWithPosition { + path_like: path, + row: path_like.row, + column: path_like.column, + }) + .collect() +} + pub fn regex_search_for_query(query: project::search::SearchQuery) -> Option { let searcher = match query { project::search::SearchQuery::Text { query, .. } => RegexSearch::new(&query),