diff --git a/crates/nu-command/src/viewers/table.rs b/crates/nu-command/src/viewers/table.rs index b703249c98..0da5dc9929 100644 --- a/crates/nu-command/src/viewers/table.rs +++ b/crates/nu-command/src/viewers/table.rs @@ -9,12 +9,14 @@ use nu_protocol::{ }; use nu_table::{Alignments, StyledString, TableTheme, TextStyle}; use nu_utils::get_ls_colors; -use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use std::time::Instant; +use std::{ + path::PathBuf, + sync::atomic::{AtomicBool, Ordering}, +}; use terminal_size::{Height, Width}; - -//use super::lscolor_ansiterm::ToNuAnsiStyle; +use url::Url; const STREAM_PAGE_SIZE: usize = 1000; const STREAM_TIMEOUT_CHECK_INTERVAL: usize = 100; @@ -258,6 +260,7 @@ fn handle_row_stream( None => None, }; let ls_colors = get_ls_colors(ls_colors_env_str); + let show_clickable_links = config.show_clickable_links_in_ls; ListStream::from_stream( stream.map(move |(mut x, _)| match &mut x { @@ -279,9 +282,20 @@ fn handle_row_stream( .unwrap_or_default(); let use_ls_colors = config.use_ls_colors; + let full_path = PathBuf::from(path.clone()) + .canonicalize() + .unwrap_or_else(|_| PathBuf::from(path)); + let full_path_link = make_clickable_link( + full_path.display().to_string(), + Some(&path.clone()), + show_clickable_links, + ); + if use_ls_colors { vals[idx] = Value::String { - val: ansi_style.apply(path).to_string(), + val: ansi_style + .apply(full_path_link) + .to_string(), span: *span, }; } @@ -294,9 +308,20 @@ fn handle_row_stream( .unwrap_or_default(); let use_ls_colors = config.use_ls_colors; + let full_path = PathBuf::from(path.clone()) + .canonicalize() + .unwrap_or_else(|_| PathBuf::from(path)); + let full_path_link = make_clickable_link( + full_path.display().to_string(), + Some(&path.clone()), + show_clickable_links, + ); + if use_ls_colors { vals[idx] = Value::String { - val: ansi_style.apply(path).to_string(), + val: ansi_style + .apply(full_path_link) + .to_string(), span: *span, }; } @@ -341,6 +366,30 @@ fn handle_row_stream( }) } +fn make_clickable_link( + full_path: String, + link_name: Option<&str>, + show_clickable_links: bool, +) -> String { + // uri's based on this https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda + + if show_clickable_links { + format!( + "\x1b]8;;{}\x1b\\{}\x1b]8;;\x1b\\", + match Url::from_file_path(full_path.clone()) { + Ok(url) => url.to_string(), + Err(_) => full_path.clone(), + }, + link_name.unwrap_or(full_path.as_str()) + ) + } else { + match link_name { + Some(link_name) => link_name.to_string(), + None => full_path, + } + } +} + fn convert_to_table( row_offset: usize, input: &[Value], diff --git a/crates/nu-protocol/src/config.rs b/crates/nu-protocol/src/config.rs index 7493a5532a..25900e0e68 100644 --- a/crates/nu-protocol/src/config.rs +++ b/crates/nu-protocol/src/config.rs @@ -82,6 +82,7 @@ pub struct Config { pub enable_external_completion: bool, pub trim_strategy: TrimStrategy, pub show_banner: bool, + pub show_clickable_links_in_ls: bool, } impl Default for Config { @@ -117,6 +118,7 @@ impl Default for Config { enable_external_completion: true, trim_strategy: TRIM_STRATEGY_DEFAULT, show_banner: true, + show_clickable_links_in_ls: true, } } } @@ -397,6 +399,13 @@ impl Value { eprintln!("$config.show_banner is not a bool") } } + "show_clickable_links_in_ls" => { + if let Ok(b) = value.as_bool() { + config.show_clickable_links_in_ls = b; + } else { + eprintln!("$config.show_clickable_links_in_ls is not a bool") + } + } x => { eprintln!("$config.{} is an unknown config setting", x) } diff --git a/crates/nu-utils/src/sample_config/default_config.nu b/crates/nu-utils/src/sample_config/default_config.nu index a225c8a9f2..8fcf904268 100644 --- a/crates/nu-utils/src/sample_config/default_config.nu +++ b/crates/nu-utils/src/sample_config/default_config.nu @@ -266,6 +266,7 @@ let-env config = { # truncating_suffix: "..." } show_banner: true # true or false to enable or disable the banner + show_clickable_links_in_ls: true # true or false to enable or disable clickable links in the ls listing. your terminal has to support links. hooks: { pre_prompt: [{