mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
Merge pull request #5622 from cakebaker/ls_hyperlink
ls: implement --hyperlink
This commit is contained in:
commit
d63d4a7658
6 changed files with 82 additions and 3 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -2618,6 +2618,7 @@ dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"glob",
|
"glob",
|
||||||
|
"hostname",
|
||||||
"lscolors",
|
"lscolors",
|
||||||
"number_prefix",
|
"number_prefix",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
|
|
@ -284,6 +284,7 @@ fundu = "2.0.0"
|
||||||
gcd = "2.3"
|
gcd = "2.3"
|
||||||
glob = "0.3.1"
|
glob = "0.3.1"
|
||||||
half = "2.3"
|
half = "2.3"
|
||||||
|
hostname = "0.3"
|
||||||
indicatif = "0.17"
|
indicatif = "0.17"
|
||||||
itertools = "0.12.0"
|
itertools = "0.12.0"
|
||||||
libc = "0.2.150"
|
libc = "0.2.150"
|
||||||
|
|
|
@ -16,7 +16,7 @@ path = "src/hostname.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { workspace = true }
|
clap = { workspace = true }
|
||||||
hostname = { version = "0.3", features = ["set"] }
|
hostname = { workspace = true, features = ["set"] }
|
||||||
uucore = { workspace = true, features = ["wide"] }
|
uucore = { workspace = true, features = ["wide"] }
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
|
|
|
@ -31,6 +31,7 @@ uucore = { workspace = true, features = [
|
||||||
] }
|
] }
|
||||||
once_cell = { workspace = true }
|
once_cell = { workspace = true }
|
||||||
selinux = { workspace = true, optional = true }
|
selinux = { workspace = true, optional = true }
|
||||||
|
hostname = { workspace = true }
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "ls"
|
name = "ls"
|
||||||
|
|
|
@ -155,6 +155,7 @@ pub mod options {
|
||||||
pub static GROUP_DIRECTORIES_FIRST: &str = "group-directories-first";
|
pub static GROUP_DIRECTORIES_FIRST: &str = "group-directories-first";
|
||||||
pub static ZERO: &str = "zero";
|
pub static ZERO: &str = "zero";
|
||||||
pub static DIRED: &str = "dired";
|
pub static DIRED: &str = "dired";
|
||||||
|
pub static HYPERLINK: &str = "hyperlink";
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_TERM_WIDTH: u16 = 80;
|
const DEFAULT_TERM_WIDTH: u16 = 80;
|
||||||
|
@ -418,6 +419,7 @@ pub struct Config {
|
||||||
group_directories_first: bool,
|
group_directories_first: bool,
|
||||||
line_ending: LineEnding,
|
line_ending: LineEnding,
|
||||||
dired: bool,
|
dired: bool,
|
||||||
|
hyperlink: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fields that can be removed or added to the long format
|
// Fields that can be removed or added to the long format
|
||||||
|
@ -566,6 +568,25 @@ fn extract_color(options: &clap::ArgMatches) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extracts the hyperlink option to use based on the options provided.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A boolean representing whether to hyperlink files.
|
||||||
|
fn extract_hyperlink(options: &clap::ArgMatches) -> bool {
|
||||||
|
let hyperlink = options
|
||||||
|
.get_one::<String>(options::HYPERLINK)
|
||||||
|
.unwrap()
|
||||||
|
.as_str();
|
||||||
|
|
||||||
|
match hyperlink {
|
||||||
|
"always" | "yes" | "force" => true,
|
||||||
|
"auto" | "tty" | "if-tty" => std::io::stdout().is_terminal(),
|
||||||
|
"never" | "no" | "none" => false,
|
||||||
|
_ => unreachable!("should be handled by clap"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Extracts the quoting style to use based on the options provided.
|
/// Extracts the quoting style to use based on the options provided.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
|
@ -736,10 +757,9 @@ impl Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
let sort = extract_sort(options);
|
let sort = extract_sort(options);
|
||||||
|
|
||||||
let time = extract_time(options);
|
let time = extract_time(options);
|
||||||
|
|
||||||
let mut needs_color = extract_color(options);
|
let mut needs_color = extract_color(options);
|
||||||
|
let hyperlink = extract_hyperlink(options);
|
||||||
|
|
||||||
let opt_block_size = options.get_one::<String>(options::size::BLOCK_SIZE);
|
let opt_block_size = options.get_one::<String>(options::size::BLOCK_SIZE);
|
||||||
let opt_si = opt_block_size.is_some()
|
let opt_si = opt_block_size.is_some()
|
||||||
|
@ -1020,6 +1040,7 @@ impl Config {
|
||||||
group_directories_first: options.get_flag(options::GROUP_DIRECTORIES_FIRST),
|
group_directories_first: options.get_flag(options::GROUP_DIRECTORIES_FIRST),
|
||||||
line_ending: LineEnding::from_zero_flag(options.get_flag(options::ZERO)),
|
line_ending: LineEnding::from_zero_flag(options.get_flag(options::ZERO)),
|
||||||
dired,
|
dired,
|
||||||
|
hyperlink,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1154,6 +1175,19 @@ pub fn uu_app() -> Command {
|
||||||
.help("generate output designed for Emacs' dired (Directory Editor) mode")
|
.help("generate output designed for Emacs' dired (Directory Editor) mode")
|
||||||
.action(ArgAction::SetTrue),
|
.action(ArgAction::SetTrue),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new(options::HYPERLINK)
|
||||||
|
.long(options::HYPERLINK)
|
||||||
|
.help("hyperlink file names WHEN")
|
||||||
|
.value_parser([
|
||||||
|
"always", "yes", "force", "auto", "tty", "if-tty", "never", "no", "none",
|
||||||
|
])
|
||||||
|
.require_equals(true)
|
||||||
|
.num_args(0..=1)
|
||||||
|
.default_missing_value("always")
|
||||||
|
.default_value("never")
|
||||||
|
.value_name("WHEN"),
|
||||||
|
)
|
||||||
// The next four arguments do not override with the other format
|
// The next four arguments do not override with the other format
|
||||||
// options, see the comment in Config::from for the reason.
|
// options, see the comment in Config::from for the reason.
|
||||||
// Ideally, they would use Arg::override_with, with their own name
|
// Ideally, they would use Arg::override_with, with their own name
|
||||||
|
@ -2959,6 +2993,18 @@ fn display_file_name(
|
||||||
// infer it because the color codes mess up term_grid's width calculation.
|
// infer it because the color codes mess up term_grid's width calculation.
|
||||||
let mut width = name.width();
|
let mut width = name.width();
|
||||||
|
|
||||||
|
if config.hyperlink {
|
||||||
|
let hostname = hostname::get().unwrap_or(OsString::from(""));
|
||||||
|
let hostname = hostname.to_string_lossy();
|
||||||
|
|
||||||
|
let absolute_path = fs::canonicalize(&path.p_buf).unwrap_or_default();
|
||||||
|
let absolute_path = absolute_path.to_string_lossy();
|
||||||
|
|
||||||
|
// TODO encode path
|
||||||
|
// \x1b = ESC, \x07 = BEL
|
||||||
|
name = format!("\x1b]8;;file://{hostname}{absolute_path}\x07{name}\x1b]8;;\x07");
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(ls_colors) = &config.color {
|
if let Some(ls_colors) = &config.color {
|
||||||
let md = path.md(out);
|
let md = path.md(out);
|
||||||
name = if md.is_some() {
|
name = if md.is_some() {
|
||||||
|
|
|
@ -3855,3 +3855,33 @@ fn test_posixly_correct() {
|
||||||
.succeeds()
|
.succeeds()
|
||||||
.stdout_contains_line("total 8");
|
.stdout_contains_line("total 8");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ls_hyperlink() {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let file = "a.txt";
|
||||||
|
|
||||||
|
at.touch(file);
|
||||||
|
|
||||||
|
let path = at.root_dir_resolved();
|
||||||
|
let separator = std::path::MAIN_SEPARATOR_STR;
|
||||||
|
|
||||||
|
let result = scene.ucmd().arg("--hyperlink").succeeds();
|
||||||
|
assert!(result.stdout_str().contains("\x1b]8;;file://"));
|
||||||
|
assert!(result
|
||||||
|
.stdout_str()
|
||||||
|
.contains(&format!("{path}{separator}{file}\x07{file}\x1b]8;;\x07")));
|
||||||
|
|
||||||
|
let result = scene.ucmd().arg("--hyperlink=always").succeeds();
|
||||||
|
assert!(result.stdout_str().contains("\x1b]8;;file://"));
|
||||||
|
assert!(result
|
||||||
|
.stdout_str()
|
||||||
|
.contains(&format!("{path}{separator}{file}\x07{file}\x1b]8;;\x07")));
|
||||||
|
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.arg("--hyperlink=never")
|
||||||
|
.succeeds()
|
||||||
|
.stdout_is(format!("{file}\n"));
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue