mirror of https://github.com/sharkdp/bat.git
Compare commits
6 Commits
a2d2aa45d4
...
c54e37c70a
Author | SHA1 | Date |
---|---|---|
Anomalocaridid | c54e37c70a | |
Stéphane Blondon | bb4d1cbd2e | |
Stéphane Blondon | 23ec433167 | |
Anomalocaridid | 1a1c4c3c4d | |
Anomalocaridid | e7f6bcb0fe | |
Anomalocaridid | 85edfa1f48 |
|
@ -15,6 +15,7 @@
|
||||||
- Fix handling of inputs with OSC ANSI escape sequences, see #2541 and #2544 (@eth-p)
|
- Fix handling of inputs with OSC ANSI escape sequences, see #2541 and #2544 (@eth-p)
|
||||||
- Fix handling of inputs with combined ANSI color and attribute sequences, see #2185 and #2856 (@eth-p)
|
- Fix handling of inputs with combined ANSI color and attribute sequences, see #2185 and #2856 (@eth-p)
|
||||||
- Fix panel width when line 10000 wraps, see #2854 (@eth-p)
|
- Fix panel width when line 10000 wraps, see #2854 (@eth-p)
|
||||||
|
- Fix bugs in `$LESSOPEN` support, see #2805 (@Anomalocaridid)
|
||||||
|
|
||||||
## Other
|
## Other
|
||||||
|
|
||||||
|
@ -34,6 +35,7 @@
|
||||||
- Relax syntax mapping rule restrictions to allow brace expansion #2865 (@cyqsimon)
|
- Relax syntax mapping rule restrictions to allow brace expansion #2865 (@cyqsimon)
|
||||||
- Apply clippy fixes #2864 (@cyqsimon)
|
- Apply clippy fixes #2864 (@cyqsimon)
|
||||||
- Faster startup by offloading glob matcher building to a worker thread #2868 (@cyqsimon)
|
- Faster startup by offloading glob matcher building to a worker thread #2868 (@cyqsimon)
|
||||||
|
- Display which theme is the default one in basic output (no colors), see #2937 (@sblondon)
|
||||||
- Display which theme is the default one in colored output, see #2838 (@sblondon)
|
- Display which theme is the default one in colored output, see #2838 (@sblondon)
|
||||||
|
|
||||||
## Syntaxes
|
## Syntaxes
|
||||||
|
|
|
@ -123,6 +123,7 @@ dependencies = [
|
||||||
"content_inspector",
|
"content_inspector",
|
||||||
"encoding_rs",
|
"encoding_rs",
|
||||||
"etcetera",
|
"etcetera",
|
||||||
|
"execute",
|
||||||
"expect-test",
|
"expect-test",
|
||||||
"flate2",
|
"flate2",
|
||||||
"git2",
|
"git2",
|
||||||
|
@ -134,12 +135,10 @@ dependencies = [
|
||||||
"nix",
|
"nix",
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"os_str_bytes",
|
|
||||||
"path_abs",
|
"path_abs",
|
||||||
"plist",
|
"plist",
|
||||||
"predicates",
|
"predicates",
|
||||||
"regex",
|
"regex",
|
||||||
"run_script",
|
|
||||||
"semver",
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
|
@ -396,12 +395,6 @@ version = "0.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dunce"
|
|
||||||
version = "1.0.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0bd4b30a6560bbd9b4620f4de34c3f14f60848e58a9b7216801afcb4c7b31c3c"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
|
@ -461,6 +454,43 @@ dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "execute"
|
||||||
|
version = "0.2.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3a82608ee96ce76aeab659e9b8d3c2b787bffd223199af88c674923d861ada10"
|
||||||
|
dependencies = [
|
||||||
|
"execute-command-macro",
|
||||||
|
"execute-command-tokens",
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "execute-command-macro"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "90dec53d547564e911dc4ff3ecb726a64cf41a6fa01a2370ebc0d95175dd08bd"
|
||||||
|
dependencies = [
|
||||||
|
"execute-command-macro-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "execute-command-macro-impl"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ce8cd46a041ad005ab9c71263f9a0ff5b529eac0fe4cc9b4a20f4f0765d8cf4b"
|
||||||
|
dependencies = [
|
||||||
|
"execute-command-tokens",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "execute-command-tokens"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "69dc321eb6be977f44674620ca3aa21703cb20ffbe560e1ae97da08401ffbcad"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "expect-test"
|
name = "expect-test"
|
||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
|
@ -522,24 +552,12 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fsio"
|
name = "generic-array"
|
||||||
version = "0.4.0"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dad0ce30be0cc441b325c5d705c8b613a0ca0d92b6a8953d41bd236dc09a36d0"
|
checksum = "fe739944a5406424e080edccb6add95685130b9f160d5407c639c7df0c5836b0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dunce",
|
"typenum",
|
||||||
"rand",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "getrandom"
|
|
||||||
version = "0.2.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"wasi",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -837,15 +855,6 @@ dependencies = [
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "os_str_bytes"
|
|
||||||
version = "6.6.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
|
@ -910,12 +919,6 @@ version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ppv-lite86"
|
|
||||||
version = "0.2.17"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "predicates"
|
name = "predicates"
|
||||||
version = "3.1.0"
|
version = "3.1.0"
|
||||||
|
@ -973,36 +976,6 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand"
|
|
||||||
version = "0.8.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"rand_chacha",
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_chacha"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
|
||||||
dependencies = [
|
|
||||||
"ppv-lite86",
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_core"
|
|
||||||
version = "0.6.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.2.16"
|
version = "0.2.16"
|
||||||
|
@ -1059,15 +1032,6 @@ dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "run_script"
|
|
||||||
version = "0.10.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "829f98fdc58d78989dd9af83be28bc15c94a7d77f9ecdb54abbbc0b1829ba9c7"
|
|
||||||
dependencies = [
|
|
||||||
"fsio",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.21"
|
version = "0.38.21"
|
||||||
|
@ -1426,6 +1390,12 @@ dependencies = [
|
||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi"
|
name = "unicode-bidi"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
|
@ -1501,12 +1471,6 @@ dependencies = [
|
||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasi"
|
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wild"
|
name = "wild"
|
||||||
version = "2.2.1"
|
version = "2.2.1"
|
||||||
|
|
|
@ -33,7 +33,7 @@ minimal-application = [
|
||||||
]
|
]
|
||||||
git = ["git2"] # Support indicating git modifications
|
git = ["git2"] # Support indicating git modifications
|
||||||
paging = ["shell-words", "grep-cli"] # Support applying a pager on the output
|
paging = ["shell-words", "grep-cli"] # Support applying a pager on the output
|
||||||
lessopen = ["run_script", "os_str_bytes"] # Support $LESSOPEN preprocessor
|
lessopen = ["execute"] # Support $LESSOPEN preprocessor
|
||||||
build-assets = ["syntect/yaml-load", "syntect/plist-load", "regex", "walkdir"]
|
build-assets = ["syntect/yaml-load", "syntect/plist-load", "regex", "walkdir"]
|
||||||
|
|
||||||
# You need to use one of these if you depend on bat as a library:
|
# You need to use one of these if you depend on bat as a library:
|
||||||
|
@ -66,8 +66,7 @@ regex = { version = "1.10.2", optional = true }
|
||||||
walkdir = { version = "2.4", optional = true }
|
walkdir = { version = "2.4", optional = true }
|
||||||
bytesize = { version = "1.3.0" }
|
bytesize = { version = "1.3.0" }
|
||||||
encoding_rs = "0.8.33"
|
encoding_rs = "0.8.33"
|
||||||
os_str_bytes = { version = "~6.6", optional = true }
|
execute = { version = "^0.2.13", optional = true }
|
||||||
run_script = { version = "^0.10.1", optional = true}
|
|
||||||
|
|
||||||
[dependencies.git2]
|
[dependencies.git2]
|
||||||
version = "0.18"
|
version = "0.18"
|
||||||
|
|
|
@ -200,14 +200,14 @@ pub fn list_themes(cfg: &Config, config_dir: &Path, cache_dir: &Path) -> Result<
|
||||||
let stdout = io::stdout();
|
let stdout = io::stdout();
|
||||||
let mut stdout = stdout.lock();
|
let mut stdout = stdout.lock();
|
||||||
|
|
||||||
if config.colored_output {
|
let default_theme = HighlightingAssets::default_theme();
|
||||||
let default_theme = HighlightingAssets::default_theme();
|
for theme in assets.themes() {
|
||||||
for theme in assets.themes() {
|
let default_theme_info = if default_theme == theme {
|
||||||
let default_theme_info = if default_theme == theme {
|
" (default)"
|
||||||
" (default)"
|
} else {
|
||||||
} else {
|
""
|
||||||
""
|
};
|
||||||
};
|
if config.colored_output {
|
||||||
writeln!(
|
writeln!(
|
||||||
stdout,
|
stdout,
|
||||||
"Theme: {}{}\n",
|
"Theme: {}{}\n",
|
||||||
|
@ -219,7 +219,12 @@ pub fn list_themes(cfg: &Config, config_dir: &Path, cache_dir: &Path) -> Result<
|
||||||
.run(vec![theme_preview_file()], None)
|
.run(vec![theme_preview_file()], None)
|
||||||
.ok();
|
.ok();
|
||||||
writeln!(stdout)?;
|
writeln!(stdout)?;
|
||||||
|
} else {
|
||||||
|
writeln!(stdout, "{theme}{default_theme_info}")?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.colored_output {
|
||||||
writeln!(
|
writeln!(
|
||||||
stdout,
|
stdout,
|
||||||
"Further themes can be installed to '{}', \
|
"Further themes can be installed to '{}', \
|
||||||
|
@ -228,10 +233,6 @@ pub fn list_themes(cfg: &Config, config_dir: &Path, cache_dir: &Path) -> Result<
|
||||||
https://github.com/sharkdp/bat#adding-new-themes",
|
https://github.com/sharkdp/bat#adding-new-themes",
|
||||||
config_dir.join("themes").to_string_lossy()
|
config_dir.join("themes").to_string_lossy()
|
||||||
)?;
|
)?;
|
||||||
} else {
|
|
||||||
for theme in assets.themes() {
|
|
||||||
writeln!(stdout, "{theme}")?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
150
src/lessopen.rs
150
src/lessopen.rs
|
@ -3,13 +3,12 @@
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufRead, BufReader, Cursor, Read, Write};
|
use std::io::{BufRead, BufReader, Cursor, Read};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::str;
|
use std::process::{ExitStatus, Stdio};
|
||||||
|
|
||||||
use clircle::{Clircle, Identifier};
|
use clircle::{Clircle, Identifier};
|
||||||
use os_str_bytes::RawOsString;
|
use execute::{shell, Execute};
|
||||||
use run_script::{IoOptions, ScriptOptions};
|
|
||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -21,7 +20,6 @@ use crate::{
|
||||||
pub(crate) struct LessOpenPreprocessor {
|
pub(crate) struct LessOpenPreprocessor {
|
||||||
lessopen: String,
|
lessopen: String,
|
||||||
lessclose: Option<String>,
|
lessclose: Option<String>,
|
||||||
command_options: ScriptOptions,
|
|
||||||
kind: LessOpenKind,
|
kind: LessOpenKind,
|
||||||
/// Whether or not data piped via stdin is to be preprocessed
|
/// Whether or not data piped via stdin is to be preprocessed
|
||||||
preprocess_stdin: bool,
|
preprocess_stdin: bool,
|
||||||
|
@ -52,7 +50,7 @@ impl LessOpenPreprocessor {
|
||||||
// Otherwise, if output is empty and exit code is nonzero, use original file contents
|
// Otherwise, if output is empty and exit code is nonzero, use original file contents
|
||||||
let (kind, lessopen) = if lessopen.starts_with("||") {
|
let (kind, lessopen) = if lessopen.starts_with("||") {
|
||||||
(LessOpenKind::Piped, lessopen.chars().skip(2).collect())
|
(LessOpenKind::Piped, lessopen.chars().skip(2).collect())
|
||||||
// "|" means pipe, but ignore exit code, always using preprocessor output
|
// "|" means pipe as above, but ignore exit code and always use preprocessor output even if empty
|
||||||
} else if lessopen.starts_with('|') {
|
} else if lessopen.starts_with('|') {
|
||||||
(
|
(
|
||||||
LessOpenKind::PipedIgnoreExitCode,
|
LessOpenKind::PipedIgnoreExitCode,
|
||||||
|
@ -70,16 +68,9 @@ impl LessOpenPreprocessor {
|
||||||
(false, lessopen)
|
(false, lessopen)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut command_options = ScriptOptions::new();
|
|
||||||
command_options.runner = env::var("SHELL").ok();
|
|
||||||
command_options.input_redirection = IoOptions::Pipe;
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
lessopen: lessopen.replacen("%s", "$1", 1),
|
lessopen,
|
||||||
lessclose: env::var("LESSCLOSE")
|
lessclose: env::var("LESSCLOSE").ok(),
|
||||||
.ok()
|
|
||||||
.map(|str| str.replacen("%s", "$1", 1).replacen("%s", "$2", 1)),
|
|
||||||
command_options,
|
|
||||||
kind,
|
kind,
|
||||||
preprocess_stdin: stdin,
|
preprocess_stdin: stdin,
|
||||||
})
|
})
|
||||||
|
@ -98,21 +89,21 @@ impl LessOpenPreprocessor {
|
||||||
None => return input.open(stdin, stdout_identifier),
|
None => return input.open(stdin, stdout_identifier),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (exit_code, lessopen_stdout, _) = match run_script::run(
|
let mut lessopen_command = shell(self.lessopen.replacen("%s", path_str, 1));
|
||||||
&self.lessopen,
|
lessopen_command.stdout(Stdio::piped());
|
||||||
&vec![path_str.to_string()],
|
|
||||||
&self.command_options,
|
let lessopen_output = match lessopen_command.execute_output() {
|
||||||
) {
|
|
||||||
Ok(output) => output,
|
Ok(output) => output,
|
||||||
Err(_) => return input.open(stdin, stdout_identifier),
|
Err(_) => return input.open(stdin, stdout_identifier),
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.fall_back_to_original_file(&lessopen_stdout, exit_code) {
|
if self.fall_back_to_original_file(&lessopen_output.stdout, lessopen_output.status)
|
||||||
|
{
|
||||||
return input.open(stdin, stdout_identifier);
|
return input.open(stdin, stdout_identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
RawOsString::from_string(lessopen_stdout),
|
lessopen_output.stdout,
|
||||||
path_str.to_string(),
|
path_str.to_string(),
|
||||||
OpenedInputKind::OrdinaryFile(path.to_path_buf()),
|
OpenedInputKind::OrdinaryFile(path.to_path_buf()),
|
||||||
)
|
)
|
||||||
|
@ -127,47 +118,31 @@ impl LessOpenPreprocessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// stdin isn't Clone, so copy it to a cloneable buffer
|
// stdin isn't Clone or AsRef<[u8]>, so move it into a cloneable buffer
|
||||||
|
// so the data can be used multiple times if necessary
|
||||||
|
// NOTE: stdin will be empty from this point onwards
|
||||||
let mut stdin_buffer = Vec::new();
|
let mut stdin_buffer = Vec::new();
|
||||||
stdin.read_to_end(&mut stdin_buffer).unwrap();
|
stdin.read_to_end(&mut stdin_buffer)?;
|
||||||
|
|
||||||
let mut lessopen_handle = match run_script::spawn(
|
let mut lessopen_command = shell(self.lessopen.replacen("%s", "-", 1));
|
||||||
&self.lessopen,
|
lessopen_command.stdout(Stdio::piped());
|
||||||
&vec!["-".to_string()],
|
|
||||||
&self.command_options,
|
|
||||||
) {
|
|
||||||
Ok(handle) => handle,
|
|
||||||
Err(_) => {
|
|
||||||
return input.open(stdin, stdout_identifier);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if lessopen_handle
|
let lessopen_output = match lessopen_command.execute_input_output(&stdin_buffer)
|
||||||
.stdin
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.write_all(&stdin_buffer.clone())
|
|
||||||
.is_err()
|
|
||||||
{
|
{
|
||||||
return input.open(stdin, stdout_identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
let lessopen_output = match lessopen_handle.wait_with_output() {
|
|
||||||
Ok(output) => output,
|
Ok(output) => output,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
return input.open(Cursor::new(stdin_buffer), stdout_identifier);
|
return input.open(Cursor::new(stdin_buffer), stdout_identifier);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if lessopen_output.stdout.is_empty()
|
if self
|
||||||
&& (!lessopen_output.status.success()
|
.fall_back_to_original_file(&lessopen_output.stdout, lessopen_output.status)
|
||||||
|| matches!(self.kind, LessOpenKind::PipedIgnoreExitCode))
|
|
||||||
{
|
{
|
||||||
return input.open(Cursor::new(stdin_buffer), stdout_identifier);
|
return input.open(Cursor::new(stdin_buffer), stdout_identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
RawOsString::assert_from_raw_vec(lessopen_output.stdout),
|
lessopen_output.stdout,
|
||||||
"-".to_string(),
|
"-".to_string(),
|
||||||
OpenedInputKind::StdIn,
|
OpenedInputKind::StdIn,
|
||||||
)
|
)
|
||||||
|
@ -184,13 +159,17 @@ impl LessOpenPreprocessor {
|
||||||
kind,
|
kind,
|
||||||
reader: InputReader::new(BufReader::new(
|
reader: InputReader::new(BufReader::new(
|
||||||
if matches!(self.kind, LessOpenKind::TempFile) {
|
if matches!(self.kind, LessOpenKind::TempFile) {
|
||||||
// Remove newline at end of temporary file path returned by $LESSOPEN
|
let lessopen_string = match String::from_utf8(lessopen_stdout) {
|
||||||
let stdout = match lessopen_stdout.strip_suffix("\n") {
|
Ok(string) => string,
|
||||||
Some(stripped) => stripped.to_owned(),
|
Err(_) => {
|
||||||
None => lessopen_stdout,
|
return input.open(stdin, stdout_identifier);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Remove newline at end of temporary file path returned by $LESSOPEN
|
||||||
|
let stdout = match lessopen_string.strip_suffix("\n") {
|
||||||
|
Some(stripped) => stripped.to_owned(),
|
||||||
|
None => lessopen_string,
|
||||||
};
|
};
|
||||||
|
|
||||||
let stdout = stdout.into_os_string();
|
|
||||||
|
|
||||||
let file = match File::open(PathBuf::from(&stdout)) {
|
let file = match File::open(PathBuf::from(&stdout)) {
|
||||||
Ok(file) => file,
|
Ok(file) => file,
|
||||||
|
@ -201,16 +180,18 @@ impl LessOpenPreprocessor {
|
||||||
|
|
||||||
Preprocessed {
|
Preprocessed {
|
||||||
kind: PreprocessedKind::TempFile(file),
|
kind: PreprocessedKind::TempFile(file),
|
||||||
lessclose: self.lessclose.clone(),
|
lessclose: self
|
||||||
command_args: vec![path_str, stdout.to_str().unwrap().to_string()],
|
.lessclose
|
||||||
command_options: self.command_options.clone(),
|
.as_ref()
|
||||||
|
.map(|s| s.replacen("%s", &path_str, 1).replacen("%s", &stdout, 1)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Preprocessed {
|
Preprocessed {
|
||||||
kind: PreprocessedKind::Piped(Cursor::new(lessopen_stdout.into_raw_vec())),
|
kind: PreprocessedKind::Piped(Cursor::new(lessopen_stdout)),
|
||||||
lessclose: self.lessclose.clone(),
|
lessclose: self
|
||||||
command_args: vec![path_str, "-".to_string()],
|
.lessclose
|
||||||
command_options: self.command_options.clone(),
|
.as_ref()
|
||||||
|
.map(|s| s.replacen("%s", &path_str, 1).replacen("%s", "-", 1)),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
|
@ -219,9 +200,9 @@ impl LessOpenPreprocessor {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fall_back_to_original_file(&self, lessopen_output: &str, exit_code: i32) -> bool {
|
fn fall_back_to_original_file(&self, lessopen_stdout: &Vec<u8>, exit_code: ExitStatus) -> bool {
|
||||||
lessopen_output.is_empty()
|
lessopen_stdout.is_empty()
|
||||||
&& (exit_code != 0 || matches!(self.kind, LessOpenKind::PipedIgnoreExitCode))
|
&& (!exit_code.success() || matches!(self.kind, LessOpenKind::PipedIgnoreExitCode))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -261,8 +242,6 @@ impl Read for PreprocessedKind {
|
||||||
pub struct Preprocessed {
|
pub struct Preprocessed {
|
||||||
kind: PreprocessedKind,
|
kind: PreprocessedKind,
|
||||||
lessclose: Option<String>,
|
lessclose: Option<String>,
|
||||||
command_args: Vec<String>,
|
|
||||||
command_options: ScriptOptions,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Read for Preprocessed {
|
impl Read for Preprocessed {
|
||||||
|
@ -273,11 +252,20 @@ impl Read for Preprocessed {
|
||||||
|
|
||||||
impl Drop for Preprocessed {
|
impl Drop for Preprocessed {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if let Some(ref command) = self.lessclose {
|
if let Some(lessclose) = self.lessclose.clone() {
|
||||||
self.command_options.output_redirection = IoOptions::Inherit;
|
let mut lessclose_command = shell(lessclose);
|
||||||
|
|
||||||
run_script::run(command, &self.command_args, &self.command_options)
|
let lessclose_output = match lessclose_command.execute_output() {
|
||||||
.expect("failed to run $LESSCLOSE to clean up file");
|
Ok(output) => output,
|
||||||
|
Err(_) => {
|
||||||
|
bat_warning!("failed to run $LESSCLOSE to clean up temporary file");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if lessclose_output.status.success() {
|
||||||
|
bat_warning!("$LESSCLOSE exited with nonzero exit code",)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,7 +289,7 @@ mod tests {
|
||||||
fn test_just_lessopen() -> Result<()> {
|
fn test_just_lessopen() -> Result<()> {
|
||||||
let preprocessor = LessOpenPreprocessor::mock_new(Some("|batpipe %s"), None)?;
|
let preprocessor = LessOpenPreprocessor::mock_new(Some("|batpipe %s"), None)?;
|
||||||
|
|
||||||
assert_eq!(preprocessor.lessopen, "batpipe $1");
|
assert_eq!(preprocessor.lessopen, "batpipe %s");
|
||||||
assert!(preprocessor.lessclose.is_none());
|
assert!(preprocessor.lessclose.is_none());
|
||||||
|
|
||||||
reset_env_vars();
|
reset_env_vars();
|
||||||
|
@ -327,8 +315,8 @@ mod tests {
|
||||||
let preprocessor =
|
let preprocessor =
|
||||||
LessOpenPreprocessor::mock_new(Some("lessopen.sh %s"), Some("lessclose.sh %s %s"))?;
|
LessOpenPreprocessor::mock_new(Some("lessopen.sh %s"), Some("lessclose.sh %s %s"))?;
|
||||||
|
|
||||||
assert_eq!(preprocessor.lessopen, "lessopen.sh $1");
|
assert_eq!(preprocessor.lessopen, "lessopen.sh %s");
|
||||||
assert_eq!(preprocessor.lessclose.unwrap(), "lessclose.sh $1 $2");
|
assert_eq!(preprocessor.lessclose.unwrap(), "lessclose.sh %s %s");
|
||||||
|
|
||||||
reset_env_vars();
|
reset_env_vars();
|
||||||
|
|
||||||
|
@ -340,13 +328,13 @@ mod tests {
|
||||||
fn test_lessopen_prefixes() -> Result<()> {
|
fn test_lessopen_prefixes() -> Result<()> {
|
||||||
let preprocessor = LessOpenPreprocessor::mock_new(Some("batpipe %s"), None)?;
|
let preprocessor = LessOpenPreprocessor::mock_new(Some("batpipe %s"), None)?;
|
||||||
|
|
||||||
assert_eq!(preprocessor.lessopen, "batpipe $1");
|
assert_eq!(preprocessor.lessopen, "batpipe %s");
|
||||||
assert!(matches!(preprocessor.kind, LessOpenKind::TempFile));
|
assert!(matches!(preprocessor.kind, LessOpenKind::TempFile));
|
||||||
assert!(!preprocessor.preprocess_stdin);
|
assert!(!preprocessor.preprocess_stdin);
|
||||||
|
|
||||||
let preprocessor = LessOpenPreprocessor::mock_new(Some("|batpipe %s"), None)?;
|
let preprocessor = LessOpenPreprocessor::mock_new(Some("|batpipe %s"), None)?;
|
||||||
|
|
||||||
assert_eq!(preprocessor.lessopen, "batpipe $1");
|
assert_eq!(preprocessor.lessopen, "batpipe %s");
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
preprocessor.kind,
|
preprocessor.kind,
|
||||||
LessOpenKind::PipedIgnoreExitCode
|
LessOpenKind::PipedIgnoreExitCode
|
||||||
|
@ -355,19 +343,19 @@ mod tests {
|
||||||
|
|
||||||
let preprocessor = LessOpenPreprocessor::mock_new(Some("||batpipe %s"), None)?;
|
let preprocessor = LessOpenPreprocessor::mock_new(Some("||batpipe %s"), None)?;
|
||||||
|
|
||||||
assert_eq!(preprocessor.lessopen, "batpipe $1");
|
assert_eq!(preprocessor.lessopen, "batpipe %s");
|
||||||
assert!(matches!(preprocessor.kind, LessOpenKind::Piped));
|
assert!(matches!(preprocessor.kind, LessOpenKind::Piped));
|
||||||
assert!(!preprocessor.preprocess_stdin);
|
assert!(!preprocessor.preprocess_stdin);
|
||||||
|
|
||||||
let preprocessor = LessOpenPreprocessor::mock_new(Some("-batpipe %s"), None)?;
|
let preprocessor = LessOpenPreprocessor::mock_new(Some("-batpipe %s"), None)?;
|
||||||
|
|
||||||
assert_eq!(preprocessor.lessopen, "batpipe $1");
|
assert_eq!(preprocessor.lessopen, "batpipe %s");
|
||||||
assert!(matches!(preprocessor.kind, LessOpenKind::TempFile));
|
assert!(matches!(preprocessor.kind, LessOpenKind::TempFile));
|
||||||
assert!(preprocessor.preprocess_stdin);
|
assert!(preprocessor.preprocess_stdin);
|
||||||
|
|
||||||
let preprocessor = LessOpenPreprocessor::mock_new(Some("|-batpipe %s"), None)?;
|
let preprocessor = LessOpenPreprocessor::mock_new(Some("|-batpipe %s"), None)?;
|
||||||
|
|
||||||
assert_eq!(preprocessor.lessopen, "batpipe $1");
|
assert_eq!(preprocessor.lessopen, "batpipe %s");
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
preprocessor.kind,
|
preprocessor.kind,
|
||||||
LessOpenKind::PipedIgnoreExitCode
|
LessOpenKind::PipedIgnoreExitCode
|
||||||
|
@ -376,7 +364,7 @@ mod tests {
|
||||||
|
|
||||||
let preprocessor = LessOpenPreprocessor::mock_new(Some("||-batpipe %s"), None)?;
|
let preprocessor = LessOpenPreprocessor::mock_new(Some("||-batpipe %s"), None)?;
|
||||||
|
|
||||||
assert_eq!(preprocessor.lessopen, "batpipe $1");
|
assert_eq!(preprocessor.lessopen, "batpipe %s");
|
||||||
assert!(matches!(preprocessor.kind, LessOpenKind::Piped));
|
assert!(matches!(preprocessor.kind, LessOpenKind::Piped));
|
||||||
assert!(preprocessor.preprocess_stdin);
|
assert!(preprocessor.preprocess_stdin);
|
||||||
|
|
||||||
|
@ -391,8 +379,8 @@ mod tests {
|
||||||
let preprocessor =
|
let preprocessor =
|
||||||
LessOpenPreprocessor::mock_new(Some("|echo File:%s"), Some("echo File:%s Temp:%s"))?;
|
LessOpenPreprocessor::mock_new(Some("|echo File:%s"), Some("echo File:%s Temp:%s"))?;
|
||||||
|
|
||||||
assert_eq!(preprocessor.lessopen, "echo File:$1");
|
assert_eq!(preprocessor.lessopen, "echo File:%s");
|
||||||
assert_eq!(preprocessor.lessclose.unwrap(), "echo File:$1 Temp:$2");
|
assert_eq!(preprocessor.lessclose.unwrap(), "echo File:%s Temp:%s");
|
||||||
|
|
||||||
reset_env_vars();
|
reset_env_vars();
|
||||||
|
|
||||||
|
|
|
@ -273,7 +273,7 @@ fn squeeze_limit_line_numbers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn list_themes() {
|
fn list_themes_with_colors() {
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
let default_theme_chunk = "Monokai Extended Light\x1B[0m (default)";
|
let default_theme_chunk = "Monokai Extended Light\x1B[0m (default)";
|
||||||
|
|
||||||
|
@ -290,6 +290,23 @@ fn list_themes() {
|
||||||
.stdout(predicate::str::contains("Output the square of a number.").normalize());
|
.stdout(predicate::str::contains("Output the square of a number.").normalize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn list_themes_without_colors() {
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
let default_theme_chunk = "Monokai Extended Light (default)";
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
let default_theme_chunk = "Monokai Extended (default)";
|
||||||
|
|
||||||
|
bat()
|
||||||
|
.arg("--color=never")
|
||||||
|
.arg("--list-themes")
|
||||||
|
.assert()
|
||||||
|
.success()
|
||||||
|
.stdout(predicate::str::contains("DarkNeon").normalize())
|
||||||
|
.stdout(predicate::str::contains(default_theme_chunk).normalize());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg_attr(any(not(feature = "git"), target_os = "windows"), ignore)]
|
#[cfg_attr(any(not(feature = "git"), target_os = "windows"), ignore)]
|
||||||
fn short_help() {
|
fn short_help() {
|
||||||
|
|
Loading…
Reference in New Issue