mirror of
https://github.com/sharkdp/bat.git
synced 2025-08-24 06:06:27 +02:00
Merge branch 'master' into master
This commit is contained in:
31
.github/workflows/CICD.yml
vendored
31
.github/workflows/CICD.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs:
|
needs:
|
||||||
- crate_metadata
|
- crate_metadata
|
||||||
- ensure_cargo_fmt
|
- lint
|
||||||
- min_version
|
- min_version
|
||||||
- license_checks
|
- license_checks
|
||||||
- test_with_new_syntaxes_and_themes
|
- test_with_new_syntaxes_and_themes
|
||||||
@@ -35,7 +35,7 @@ jobs:
|
|||||||
name: Extract crate metadata
|
name: Extract crate metadata
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
- name: Extract crate information
|
- name: Extract crate information
|
||||||
id: crate_metadata
|
id: crate_metadata
|
||||||
run: |
|
run: |
|
||||||
@@ -51,15 +51,16 @@ jobs:
|
|||||||
homepage: ${{ steps.crate_metadata.outputs.homepage }}
|
homepage: ${{ steps.crate_metadata.outputs.homepage }}
|
||||||
msrv: ${{ steps.crate_metadata.outputs.msrv }}
|
msrv: ${{ steps.crate_metadata.outputs.msrv }}
|
||||||
|
|
||||||
ensure_cargo_fmt:
|
lint:
|
||||||
name: Ensure 'cargo fmt' has been run
|
name: Ensure code quality
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: dtolnay/rust-toolchain@stable
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
with:
|
with:
|
||||||
components: rustfmt
|
components: rustfmt,clippy
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
- run: cargo fmt -- --check
|
- run: cargo fmt -- --check
|
||||||
|
- run: cargo clippy --locked --all-targets --all-features -- -D warnings
|
||||||
|
|
||||||
min_version:
|
min_version:
|
||||||
name: Minimum supported rust version
|
name: Minimum supported rust version
|
||||||
@@ -67,15 +68,11 @@ jobs:
|
|||||||
needs: crate_metadata
|
needs: crate_metadata
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout source code
|
- name: Checkout source code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Install rust toolchain (v${{ needs.crate_metadata.outputs.msrv }})
|
- name: Install rust toolchain (v${{ needs.crate_metadata.outputs.msrv }})
|
||||||
uses: dtolnay/rust-toolchain@master
|
uses: dtolnay/rust-toolchain@master
|
||||||
with:
|
with:
|
||||||
toolchain: ${{ needs.crate_metadata.outputs.msrv }}
|
toolchain: ${{ needs.crate_metadata.outputs.msrv }}
|
||||||
components: clippy
|
|
||||||
- name: Run clippy (on minimum supported rust version to prevent warnings we can't fix)
|
|
||||||
run: cargo clippy --locked --all-targets ${{ env.MSRV_FEATURES }}
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: cargo test --locked ${{ env.MSRV_FEATURES }}
|
run: cargo test --locked ${{ env.MSRV_FEATURES }}
|
||||||
|
|
||||||
@@ -83,7 +80,7 @@ jobs:
|
|||||||
name: License checks
|
name: License checks
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
submodules: true # we especially want to perform license checks on submodules
|
submodules: true # we especially want to perform license checks on submodules
|
||||||
- run: tests/scripts/license-checks.sh
|
- run: tests/scripts/license-checks.sh
|
||||||
@@ -93,7 +90,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Git checkout
|
- name: Git checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
submodules: true # we need all syntax and theme submodules
|
submodules: true # we need all syntax and theme submodules
|
||||||
- name: Install Rust toolchain
|
- name: Install Rust toolchain
|
||||||
@@ -122,7 +119,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Git checkout
|
- name: Git checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
- name: Prepare environment variables
|
- name: Prepare environment variables
|
||||||
run: |
|
run: |
|
||||||
echo "BAT_SYSTEM_CONFIG_PREFIX=$GITHUB_WORKSPACE/tests/examples/system_config" >> $GITHUB_ENV
|
echo "BAT_SYSTEM_CONFIG_PREFIX=$GITHUB_WORKSPACE/tests/examples/system_config" >> $GITHUB_ENV
|
||||||
@@ -138,7 +135,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Git checkout
|
- name: Git checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
- name: Install Rust toolchain
|
- name: Install Rust toolchain
|
||||||
uses: dtolnay/rust-toolchain@stable
|
uses: dtolnay/rust-toolchain@stable
|
||||||
- name: Check documentation
|
- name: Check documentation
|
||||||
@@ -153,7 +150,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- run: cargo install cargo-audit --locked
|
- run: cargo install cargo-audit --locked
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
- run: cargo audit
|
- run: cargo audit
|
||||||
|
|
||||||
build:
|
build:
|
||||||
@@ -181,7 +178,7 @@ jobs:
|
|||||||
BUILD_CMD: cargo
|
BUILD_CMD: cargo
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout source code
|
- name: Checkout source code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Install prerequisites
|
- name: Install prerequisites
|
||||||
shell: bash
|
shell: bash
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
- Add missing mappings for various bash/zsh files, see PR #3262 (@AdamGaskins)
|
- Add missing mappings for various bash/zsh files, see PR #3262 (@AdamGaskins)
|
||||||
- Send all bat errors to stderr by default, see #3336 (@JerryImMouse)
|
- Send all bat errors to stderr by default, see #3336 (@JerryImMouse)
|
||||||
- Make --map-syntax target case insensitive to match --language, see #3206 (@keith-hall)
|
- Make --map-syntax target case insensitive to match --language, see #3206 (@keith-hall)
|
||||||
|
- Correctly determine the end of the line in UTF16LE/BE input #3369 (@keith-hall)
|
||||||
|
|
||||||
## Other
|
## Other
|
||||||
|
|
||||||
|
8
Cargo.lock
generated
8
Cargo.lock
generated
@@ -906,9 +906,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.169"
|
version = "0.2.175"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
|
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libgit2-sys"
|
name = "libgit2-sys"
|
||||||
@@ -996,9 +996,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nix"
|
name = "nix"
|
||||||
version = "0.29.0"
|
version = "0.30.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
|
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
@@ -101,7 +101,7 @@ tempfile = "3.16.0"
|
|||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|
||||||
[target.'cfg(unix)'.dev-dependencies]
|
[target.'cfg(unix)'.dev-dependencies]
|
||||||
nix = { version = "0.29", default-features = false, features = ["term"] }
|
nix = { version = "0.30", default-features = false, features = ["term"] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
anyhow = "1.0.97"
|
anyhow = "1.0.97"
|
||||||
|
30
README.md
30
README.md
@@ -711,7 +711,7 @@ sidebar. Calling `bat` with `--tabs=0` will override it and let tabs be consumed
|
|||||||
|
|
||||||
### Dark mode
|
### Dark mode
|
||||||
|
|
||||||
If you make use of the dark mode feature in macOS, you might want to configure `bat` to use a different
|
If you make use of the dark mode feature in **macOS**, you might want to configure `bat` to use a different
|
||||||
theme based on the OS theme. The following snippet uses the `default` theme when in the _dark mode_
|
theme based on the OS theme. The following snippet uses the `default` theme when in the _dark mode_
|
||||||
and the `GitHub` theme when in the _light mode_.
|
and the `GitHub` theme when in the _light mode_.
|
||||||
|
|
||||||
@@ -719,6 +719,34 @@ and the `GitHub` theme when in the _light mode_.
|
|||||||
alias cat="bat --theme auto:system --theme-dark default --theme-light GitHub"
|
alias cat="bat --theme auto:system --theme-dark default --theme-light GitHub"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The same dark mode feature is now available in **GNOME** and affects the `org.gnome.desktop.interface color-scheme` setting. The following code converts the above to use said setting.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# .bashrc
|
||||||
|
sys_color_scheme_is_dark() {
|
||||||
|
condition=$(gsettings get org.gnome.desktop.interface color-scheme)
|
||||||
|
condition=$(echo "$condition" | tr -d "[:space:]'")
|
||||||
|
if [ $condition == "prefer-dark" ]; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
bat_alias_wrapper() {
|
||||||
|
#get color scheme
|
||||||
|
sys_color_scheme_is_dark
|
||||||
|
if [[ $? -eq 0 ]]; then
|
||||||
|
# bat command with dark color scheme
|
||||||
|
bat --theme=default "$@"
|
||||||
|
else
|
||||||
|
# bat command with light color scheme
|
||||||
|
bat --theme=GitHub "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
alias cat='bat_alias_wrapper'
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Configuration file
|
## Configuration file
|
||||||
|
|
||||||
|
2
assets/syntaxes/02_Extra/Fish
vendored
2
assets/syntaxes/02_Extra/Fish
vendored
Submodule assets/syntaxes/02_Extra/Fish updated: 98316d4332...ef510fd759
2
assets/theme_preview.rs
vendored
2
assets/theme_preview.rs
vendored
@@ -1,5 +1,5 @@
|
|||||||
// Output the square of a number.
|
// Output the square of a number.
|
||||||
fn print_square(num: f64) {
|
fn print_square(num: f64) {
|
||||||
let result = f64::powf(num, 2.0);
|
let result = f64::powf(num, 2.0);
|
||||||
println!("The square of {:.2} is {:.2}.", num, result);
|
println!("The square of {num:.2} is {result:.2}.");
|
||||||
}
|
}
|
||||||
|
@@ -152,7 +152,7 @@ impl HighlightingAssets {
|
|||||||
&self,
|
&self,
|
||||||
path: impl AsRef<Path>,
|
path: impl AsRef<Path>,
|
||||||
mapping: &SyntaxMapping,
|
mapping: &SyntaxMapping,
|
||||||
) -> Result<SyntaxReferenceInSet> {
|
) -> Result<SyntaxReferenceInSet<'_>> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
|
|
||||||
let syntax_match = mapping.get_syntax_for(path);
|
let syntax_match = mapping.get_syntax_for(path);
|
||||||
@@ -191,11 +191,11 @@ impl HighlightingAssets {
|
|||||||
Some(theme) => theme,
|
Some(theme) => theme,
|
||||||
None => {
|
None => {
|
||||||
if theme == "ansi-light" || theme == "ansi-dark" {
|
if theme == "ansi-light" || theme == "ansi-dark" {
|
||||||
bat_warning!("Theme '{}' is deprecated, using 'ansi' instead.", theme);
|
bat_warning!("Theme '{theme}' is deprecated, using 'ansi' instead.");
|
||||||
return self.get_theme("ansi");
|
return self.get_theme("ansi");
|
||||||
}
|
}
|
||||||
if !theme.is_empty() {
|
if !theme.is_empty() {
|
||||||
bat_warning!("Unknown theme '{}', using default.", theme)
|
bat_warning!("Unknown theme '{theme}', using default.")
|
||||||
}
|
}
|
||||||
self.get_theme_set()
|
self.get_theme_set()
|
||||||
.get(
|
.get(
|
||||||
@@ -212,7 +212,7 @@ impl HighlightingAssets {
|
|||||||
language: Option<&str>,
|
language: Option<&str>,
|
||||||
input: &mut OpenedInput,
|
input: &mut OpenedInput,
|
||||||
mapping: &SyntaxMapping,
|
mapping: &SyntaxMapping,
|
||||||
) -> Result<SyntaxReferenceInSet> {
|
) -> Result<SyntaxReferenceInSet<'_>> {
|
||||||
if let Some(language) = language {
|
if let Some(language) = language {
|
||||||
let syntax_set = self.get_syntax_set()?;
|
let syntax_set = self.get_syntax_set()?;
|
||||||
return syntax_set
|
return syntax_set
|
||||||
@@ -244,14 +244,17 @@ impl HighlightingAssets {
|
|||||||
pub(crate) fn find_syntax_by_name(
|
pub(crate) fn find_syntax_by_name(
|
||||||
&self,
|
&self,
|
||||||
syntax_name: &str,
|
syntax_name: &str,
|
||||||
) -> Result<Option<SyntaxReferenceInSet>> {
|
) -> Result<Option<SyntaxReferenceInSet<'_>>> {
|
||||||
let syntax_set = self.get_syntax_set()?;
|
let syntax_set = self.get_syntax_set()?;
|
||||||
Ok(syntax_set
|
Ok(syntax_set
|
||||||
.find_syntax_by_name(syntax_name)
|
.find_syntax_by_name(syntax_name)
|
||||||
.map(|syntax| SyntaxReferenceInSet { syntax, syntax_set }))
|
.map(|syntax| SyntaxReferenceInSet { syntax, syntax_set }))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_syntax_by_extension(&self, e: Option<&OsStr>) -> Result<Option<SyntaxReferenceInSet>> {
|
fn find_syntax_by_extension(
|
||||||
|
&self,
|
||||||
|
e: Option<&OsStr>,
|
||||||
|
) -> Result<Option<SyntaxReferenceInSet<'_>>> {
|
||||||
let syntax_set = self.get_syntax_set()?;
|
let syntax_set = self.get_syntax_set()?;
|
||||||
let extension = e.and_then(|x| x.to_str()).unwrap_or_default();
|
let extension = e.and_then(|x| x.to_str()).unwrap_or_default();
|
||||||
Ok(syntax_set
|
Ok(syntax_set
|
||||||
@@ -259,7 +262,7 @@ impl HighlightingAssets {
|
|||||||
.map(|syntax| SyntaxReferenceInSet { syntax, syntax_set }))
|
.map(|syntax| SyntaxReferenceInSet { syntax, syntax_set }))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_syntax_by_token(&self, token: &str) -> Result<Option<SyntaxReferenceInSet>> {
|
fn find_syntax_by_token(&self, token: &str) -> Result<Option<SyntaxReferenceInSet<'_>>> {
|
||||||
let syntax_set = self.get_syntax_set()?;
|
let syntax_set = self.get_syntax_set()?;
|
||||||
Ok(syntax_set
|
Ok(syntax_set
|
||||||
.find_syntax_by_token(token)
|
.find_syntax_by_token(token)
|
||||||
@@ -270,7 +273,7 @@ impl HighlightingAssets {
|
|||||||
&self,
|
&self,
|
||||||
file_name: &OsStr,
|
file_name: &OsStr,
|
||||||
ignored_suffixes: &IgnoredSuffixes,
|
ignored_suffixes: &IgnoredSuffixes,
|
||||||
) -> Result<Option<SyntaxReferenceInSet>> {
|
) -> Result<Option<SyntaxReferenceInSet<'_>>> {
|
||||||
let mut syntax = self.find_syntax_by_extension(Some(file_name))?;
|
let mut syntax = self.find_syntax_by_extension(Some(file_name))?;
|
||||||
if syntax.is_none() {
|
if syntax.is_none() {
|
||||||
syntax =
|
syntax =
|
||||||
@@ -286,7 +289,7 @@ impl HighlightingAssets {
|
|||||||
&self,
|
&self,
|
||||||
file_name: &OsStr,
|
file_name: &OsStr,
|
||||||
ignored_suffixes: &IgnoredSuffixes,
|
ignored_suffixes: &IgnoredSuffixes,
|
||||||
) -> Result<Option<SyntaxReferenceInSet>> {
|
) -> Result<Option<SyntaxReferenceInSet<'_>>> {
|
||||||
let mut syntax = self.find_syntax_by_extension(Path::new(file_name).extension())?;
|
let mut syntax = self.find_syntax_by_extension(Path::new(file_name).extension())?;
|
||||||
if syntax.is_none() {
|
if syntax.is_none() {
|
||||||
syntax =
|
syntax =
|
||||||
@@ -301,7 +304,7 @@ impl HighlightingAssets {
|
|||||||
fn get_first_line_syntax(
|
fn get_first_line_syntax(
|
||||||
&self,
|
&self,
|
||||||
reader: &mut InputReader,
|
reader: &mut InputReader,
|
||||||
) -> Result<Option<SyntaxReferenceInSet>> {
|
) -> Result<Option<SyntaxReferenceInSet<'_>>> {
|
||||||
let syntax_set = self.get_syntax_set()?;
|
let syntax_set = self.get_syntax_set()?;
|
||||||
Ok(String::from_utf8(reader.first_line.clone())
|
Ok(String::from_utf8(reader.first_line.clone())
|
||||||
.ok()
|
.ok()
|
||||||
@@ -354,8 +357,7 @@ fn asset_from_cache<T: serde::de::DeserializeOwned>(
|
|||||||
) -> Result<T> {
|
) -> Result<T> {
|
||||||
let contents = fs::read(path).map_err(|_| {
|
let contents = fs::read(path).map_err(|_| {
|
||||||
format!(
|
format!(
|
||||||
"Could not load cached {} '{}'",
|
"Could not load cached {description} '{}'",
|
||||||
description,
|
|
||||||
path.to_string_lossy()
|
path.to_string_lossy()
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
@@ -40,15 +40,15 @@ impl AssetsMetadata {
|
|||||||
/// Load metadata about the stored cache file from the given folder.
|
/// Load metadata about the stored cache file from the given folder.
|
||||||
///
|
///
|
||||||
/// There are several possibilities:
|
/// There are several possibilities:
|
||||||
/// - We find a metadata.yaml file and are able to parse it
|
/// - We find a `metadata.yaml` file and are able to parse it
|
||||||
/// => return the contained information
|
/// - return the contained information
|
||||||
/// - We find a metadata.yaml file and but are not able to parse it
|
/// - We find a `metadata.yaml` file, but are not able to parse it
|
||||||
/// => return a SerdeYamlError
|
/// - return a [`Error::SerdeYamlError`]
|
||||||
/// - We do not find a metadata.yaml file but a syntaxes.bin or themes.bin file
|
/// - We do not find a `metadata.yaml` file but a `syntaxes.bin` or `themes.bin` file
|
||||||
/// => assume that these were created by an old version of bat and return
|
/// - assume that these were created by an old version of bat and return
|
||||||
/// AssetsMetadata::default() without version information
|
/// [`AssetsMetadata::default()`] without version information
|
||||||
/// - We do not find a metadata.yaml file and no cached assets
|
/// - We do not find a `metadata.yaml` file and no cached assets
|
||||||
/// => no user provided assets are available, return None
|
/// - no user provided assets are available, return `None`
|
||||||
pub fn load_from_folder(path: &Path) -> Result<Option<Self>> {
|
pub fn load_from_folder(path: &Path) -> Result<Option<Self>> {
|
||||||
match Self::try_load_from_folder(path) {
|
match Self::try_load_from_folder(path) {
|
||||||
Ok(metadata) => Ok(Some(metadata)),
|
Ok(metadata) => Ok(Some(metadata)),
|
||||||
|
@@ -47,9 +47,8 @@ fn build_theme_set(source_dir: &Path, include_integrated_assets: bool) -> Result
|
|||||||
let res = theme_set.add_from_folder(&theme_dir);
|
let res = theme_set.add_from_folder(&theme_dir);
|
||||||
if let Err(err) = res {
|
if let Err(err) = res {
|
||||||
println!(
|
println!(
|
||||||
"Failed to load one or more themes from '{}' (reason: '{}')",
|
"Failed to load one or more themes from '{}' (reason: '{err}')",
|
||||||
theme_dir.to_string_lossy(),
|
theme_dir.to_string_lossy(),
|
||||||
err,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -162,15 +161,10 @@ fn asset_to_cache<T: serde::Serialize>(
|
|||||||
description: &str,
|
description: &str,
|
||||||
compressed: bool,
|
compressed: bool,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
print!("Writing {} to {} ... ", description, path.to_string_lossy());
|
print!("Writing {description} to {} ... ", path.to_string_lossy());
|
||||||
let contents = asset_to_contents(asset, description, compressed)?;
|
let contents = asset_to_contents(asset, description, compressed)?;
|
||||||
std::fs::write(path, &contents[..]).map_err(|_| {
|
std::fs::write(path, &contents[..])
|
||||||
format!(
|
.map_err(|_| format!("Could not save {description} to {}", path.to_string_lossy()))?;
|
||||||
"Could not save {} to {}",
|
|
||||||
description,
|
|
||||||
path.to_string_lossy()
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
println!("okay");
|
println!("okay");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@@ -96,7 +96,7 @@ impl App {
|
|||||||
Ok(clap_app::build_app(interactive_output).get_matches_from(args))
|
Ok(clap_app::build_app(interactive_output).get_matches_from(args))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn config(&self, inputs: &[Input]) -> Result<Config> {
|
pub fn config(&self, inputs: &[Input]) -> Result<Config<'_>> {
|
||||||
let style_components = self.style_components()?;
|
let style_components = self.style_components()?;
|
||||||
|
|
||||||
let extra_plain = self.matches.get_count("plain") > 1;
|
let extra_plain = self.matches.get_count("plain") > 1;
|
||||||
@@ -338,7 +338,7 @@ impl App {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inputs(&self) -> Result<Vec<Input>> {
|
pub fn inputs(&self) -> Result<Vec<Input<'_>>> {
|
||||||
let filenames: Option<Vec<&Path>> = self
|
let filenames: Option<Vec<&Path>> = self
|
||||||
.matches
|
.matches
|
||||||
.get_many::<PathBuf>("file-name")
|
.get_many::<PathBuf>("file-name")
|
||||||
|
@@ -50,7 +50,7 @@ fn clear_asset(path: PathBuf, description: &str) {
|
|||||||
println!("skipped (not present)");
|
println!("skipped (not present)");
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!("could not remove the cache file {:?}: {}", &path, err);
|
println!("could not remove the cache file {path:?}: {err}");
|
||||||
}
|
}
|
||||||
Ok(_) => println!("okay"),
|
Ok(_) => println!("okay"),
|
||||||
}
|
}
|
||||||
|
@@ -16,7 +16,7 @@ static VERSION: Lazy<String> = Lazy::new(|| {
|
|||||||
if git_version.is_empty() {
|
if git_version.is_empty() {
|
||||||
crate_version!().to_string()
|
crate_version!().to_string()
|
||||||
} else {
|
} else {
|
||||||
format!("{} ({})", crate_version!(), git_version)
|
format!("{} ({git_version})", crate_version!())
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -88,9 +88,8 @@ pub fn generate_config_file() -> bat::error::Result<()> {
|
|||||||
|
|
||||||
fs::write(&config_file, default_config).map_err(|e| {
|
fs::write(&config_file, default_config).map_err(|e| {
|
||||||
format!(
|
format!(
|
||||||
"Failed to create config file at '{}': {}",
|
"Failed to create config file at '{}': {e}",
|
||||||
config_file.to_string_lossy(),
|
config_file.to_string_lossy(),
|
||||||
e
|
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
@@ -5,7 +5,7 @@ pub fn new_file_input<'a>(file: &'a Path, name: Option<&'a Path>) -> Input<'a> {
|
|||||||
named(Input::ordinary_file(file), name.or(Some(file)))
|
named(Input::ordinary_file(file), name.or(Some(file)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_stdin_input(name: Option<&Path>) -> Input {
|
pub fn new_stdin_input(name: Option<&Path>) -> Input<'_> {
|
||||||
named(Input::stdin(), name)
|
named(Input::stdin(), name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -162,7 +162,7 @@ pub fn get_languages(config: &Config, cache_dir: &Path) -> Result<String> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for lang in languages {
|
for lang in languages {
|
||||||
write!(result, "{:width$}{}", lang.name, separator, width = longest).ok();
|
write!(result, "{:width$}{separator}", lang.name, width = longest).ok();
|
||||||
|
|
||||||
// Number of characters on this line so far, wrap before `desired_width`
|
// Number of characters on this line so far, wrap before `desired_width`
|
||||||
let mut num_chars = 0;
|
let mut num_chars = 0;
|
||||||
@@ -173,7 +173,7 @@ pub fn get_languages(config: &Config, cache_dir: &Path) -> Result<String> {
|
|||||||
let new_chars = word.len() + comma_separator.len();
|
let new_chars = word.len() + comma_separator.len();
|
||||||
if num_chars + new_chars >= desired_width {
|
if num_chars + new_chars >= desired_width {
|
||||||
num_chars = 0;
|
num_chars = 0;
|
||||||
write!(result, "\n{:width$}{}", "", separator, width = longest).ok();
|
write!(result, "\n{:width$}{separator}", "", width = longest).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
num_chars += new_chars;
|
num_chars += new_chars;
|
||||||
@@ -224,9 +224,8 @@ pub fn list_themes(
|
|||||||
if config.colored_output {
|
if config.colored_output {
|
||||||
writeln!(
|
writeln!(
|
||||||
writer,
|
writer,
|
||||||
"Theme: {}{}\n",
|
"Theme: {}{default_theme_info}\n",
|
||||||
Style::new().bold().paint(theme.to_string()),
|
Style::new().bold().paint(theme.to_string()),
|
||||||
default_theme_info
|
|
||||||
)?;
|
)?;
|
||||||
config.theme = theme.to_string();
|
config.theme = theme.to_string();
|
||||||
Controller::new(&config, &assets)
|
Controller::new(&config, &assets)
|
||||||
@@ -363,7 +362,7 @@ fn run() -> Result<bool> {
|
|||||||
"fish" => println!("{}", completions::FISH_COMPLETION),
|
"fish" => println!("{}", completions::FISH_COMPLETION),
|
||||||
"ps1" => println!("{}", completions::PS1_COMPLETION),
|
"ps1" => println!("{}", completions::PS1_COMPLETION),
|
||||||
"zsh" => println!("{}", completions::ZSH_COMPLETION),
|
"zsh" => println!("{}", completions::ZSH_COMPLETION),
|
||||||
_ => unreachable!("No completion for shell '{}' available.", shell),
|
_ => unreachable!("No completion for shell '{shell}' available."),
|
||||||
}
|
}
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
@@ -60,18 +60,16 @@ pub fn default_error_handler(error: &Error, output: &mut dyn Write) {
|
|||||||
Error::SerdeYamlError(_) => {
|
Error::SerdeYamlError(_) => {
|
||||||
writeln!(
|
writeln!(
|
||||||
output,
|
output,
|
||||||
"{}: Error while parsing metadata.yaml file: {}",
|
"{}: Error while parsing metadata.yaml file: {error}",
|
||||||
Red.paint("[bat error]"),
|
Red.paint("[bat error]"),
|
||||||
error
|
|
||||||
)
|
)
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
writeln!(
|
writeln!(
|
||||||
&mut std::io::stderr().lock(),
|
&mut std::io::stderr().lock(),
|
||||||
"{}: {}",
|
"{}: {error}",
|
||||||
Red.paint("[bat error]"),
|
Red.paint("[bat error]"),
|
||||||
error
|
|
||||||
)
|
)
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
|
92
src/input.rs
92
src/input.rs
@@ -217,14 +217,14 @@ impl<'a> Input<'a> {
|
|||||||
metadata: self.metadata,
|
metadata: self.metadata,
|
||||||
reader: {
|
reader: {
|
||||||
let mut file = File::open(&path)
|
let mut file = File::open(&path)
|
||||||
.map_err(|e| format!("'{}': {}", path.to_string_lossy(), e))?;
|
.map_err(|e| format!("'{}': {e}", path.to_string_lossy()))?;
|
||||||
if file.metadata()?.is_dir() {
|
if file.metadata()?.is_dir() {
|
||||||
return Err(format!("'{}' is a directory.", path.to_string_lossy()).into());
|
return Err(format!("'{}' is a directory.", path.to_string_lossy()).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(stdout) = stdout_identifier {
|
if let Some(stdout) = stdout_identifier {
|
||||||
let input_identifier = Identifier::try_from(file).map_err(|e| {
|
let input_identifier = Identifier::try_from(file).map_err(|e| {
|
||||||
format!("{}: Error identifying file: {}", path.to_string_lossy(), e)
|
format!("{}: Error identifying file: {e}", path.to_string_lossy())
|
||||||
})?;
|
})?;
|
||||||
if stdout.surely_conflicts_with(&input_identifier) {
|
if stdout.surely_conflicts_with(&input_identifier) {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
@@ -267,7 +267,9 @@ impl<'a> InputReader<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if content_type == Some(ContentType::UTF_16LE) {
|
if content_type == Some(ContentType::UTF_16LE) {
|
||||||
reader.read_until(0x00, &mut first_line).ok();
|
read_utf16_line(&mut reader, &mut first_line, 0x00, 0x0A).ok();
|
||||||
|
} else if content_type == Some(ContentType::UTF_16BE) {
|
||||||
|
read_utf16_line(&mut reader, &mut first_line, 0x0A, 0x00).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
InputReader {
|
InputReader {
|
||||||
@@ -283,16 +285,44 @@ impl<'a> InputReader<'a> {
|
|||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = self.inner.read_until(b'\n', buf).map(|size| size > 0)?;
|
|
||||||
|
|
||||||
if self.content_type == Some(ContentType::UTF_16LE) {
|
if self.content_type == Some(ContentType::UTF_16LE) {
|
||||||
let _ = self.inner.read_until(0x00, buf);
|
return read_utf16_line(&mut self.inner, buf, 0x00, 0x0A);
|
||||||
|
}
|
||||||
|
if self.content_type == Some(ContentType::UTF_16BE) {
|
||||||
|
return read_utf16_line(&mut self.inner, buf, 0x0A, 0x00);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let res = self.inner.read_until(b'\n', buf).map(|size| size > 0)?;
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_utf16_line<R: BufRead>(
|
||||||
|
reader: &mut R,
|
||||||
|
buf: &mut Vec<u8>,
|
||||||
|
read_until_char: u8,
|
||||||
|
preceded_by_char: u8,
|
||||||
|
) -> io::Result<bool> {
|
||||||
|
loop {
|
||||||
|
let mut temp = Vec::new();
|
||||||
|
let n = reader.read_until(read_until_char, &mut temp)?;
|
||||||
|
if n == 0 {
|
||||||
|
// EOF reached
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf.extend_from_slice(&temp);
|
||||||
|
if buf.len() >= 2
|
||||||
|
&& buf[buf.len() - 2] == preceded_by_char
|
||||||
|
&& buf[buf.len() - 1] == read_until_char
|
||||||
|
{
|
||||||
|
// end of line found
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// end of line not found, keep going
|
||||||
|
}
|
||||||
|
Ok(!buf.is_empty())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn basic() {
|
fn basic() {
|
||||||
let content = b"#!/bin/bash\necho hello";
|
let content = b"#!/bin/bash\necho hello";
|
||||||
@@ -350,3 +380,53 @@ fn utf16le() {
|
|||||||
assert!(!res.unwrap());
|
assert!(!res.unwrap());
|
||||||
assert!(buffer.is_empty());
|
assert!(buffer.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn utf16le_issue3367() {
|
||||||
|
let content = b"\xFF\xFE\x0A\x4E\x00\x4E\x0A\x4F\x00\x52\x0A\x00\
|
||||||
|
\x6F\x00\x20\x00\x62\x00\x61\x00\x72\x00\x0A\x00\
|
||||||
|
\x68\x00\x65\x00\x6C\x00\x6C\x00\x6F\x00\x20\x00\x77\x00\x6F\x00\x72\x00\x6C\x00\x64\x00";
|
||||||
|
let mut reader = InputReader::new(&content[..]);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
b"\xFF\xFE\x0A\x4E\x00\x4E\x0A\x4F\x00\x52\x0A\x00",
|
||||||
|
&reader.first_line[..]
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut buffer = vec![];
|
||||||
|
|
||||||
|
let res = reader.read_line(&mut buffer);
|
||||||
|
assert!(res.is_ok());
|
||||||
|
assert!(res.unwrap());
|
||||||
|
assert_eq!(
|
||||||
|
b"\xFF\xFE\x0A\x4E\x00\x4E\x0A\x4F\x00\x52\x0A\x00",
|
||||||
|
&buffer[..]
|
||||||
|
);
|
||||||
|
|
||||||
|
buffer.clear();
|
||||||
|
|
||||||
|
let res = reader.read_line(&mut buffer);
|
||||||
|
assert!(res.is_ok());
|
||||||
|
assert!(res.unwrap());
|
||||||
|
assert_eq!(
|
||||||
|
b"\x6F\x00\x20\x00\x62\x00\x61\x00\x72\x00\x0A\x00",
|
||||||
|
&buffer[..]
|
||||||
|
);
|
||||||
|
|
||||||
|
buffer.clear();
|
||||||
|
|
||||||
|
let res = reader.read_line(&mut buffer);
|
||||||
|
assert!(res.is_ok());
|
||||||
|
assert!(res.unwrap());
|
||||||
|
assert_eq!(
|
||||||
|
b"\x68\x00\x65\x00\x6C\x00\x6C\x00\x6F\x00\x20\x00\x77\x00\x6F\x00\x72\x00\x6C\x00\x64\x00",
|
||||||
|
&buffer[..]
|
||||||
|
);
|
||||||
|
|
||||||
|
buffer.clear();
|
||||||
|
|
||||||
|
let res = reader.read_line(&mut buffer);
|
||||||
|
assert!(res.is_ok());
|
||||||
|
assert!(!res.unwrap());
|
||||||
|
assert!(buffer.is_empty());
|
||||||
|
}
|
||||||
|
@@ -39,7 +39,7 @@ impl LessOpenPreprocessor {
|
|||||||
// Note that $LESSCLOSE has no such requirement
|
// Note that $LESSCLOSE has no such requirement
|
||||||
if lessopen.match_indices("%s").count() != 1 {
|
if lessopen.match_indices("%s").count() != 1 {
|
||||||
let error_msg = "LESSOPEN ignored: must contain exactly one %s";
|
let error_msg = "LESSOPEN ignored: must contain exactly one %s";
|
||||||
bat_warning!("{}", error_msg);
|
bat_warning!("{error_msg}");
|
||||||
return Err(error_msg.into());
|
return Err(error_msg.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ impl LessOpenPreprocessor {
|
|||||||
if self.preprocess_stdin {
|
if self.preprocess_stdin {
|
||||||
if let Some(stdout) = stdout_identifier {
|
if let Some(stdout) = stdout_identifier {
|
||||||
let input_identifier = Identifier::try_from(clircle::Stdio::Stdin)
|
let input_identifier = Identifier::try_from(clircle::Stdio::Stdin)
|
||||||
.map_err(|e| format!("Stdin: Error identifying file: {}", e))?;
|
.map_err(|e| format!("Stdin: Error identifying file: {e}"))?;
|
||||||
if stdout.surely_conflicts_with(&input_identifier) {
|
if stdout.surely_conflicts_with(&input_identifier) {
|
||||||
return Err("IO circle detected. The input from stdin is also an output. Aborting to avoid infinite loop.".into());
|
return Err("IO circle detected. The input from stdin is also an output. Aborting to avoid infinite loop.".into());
|
||||||
}
|
}
|
||||||
|
@@ -329,7 +329,7 @@ impl<'a> InteractivePrinter<'a> {
|
|||||||
self.print_horizontal_line_term(handle, self.colors.grid)?;
|
self.print_horizontal_line_term(handle, self.colors.grid)?;
|
||||||
} else {
|
} else {
|
||||||
let hline = "─".repeat(self.config.term_width - (self.panel_width + 1));
|
let hline = "─".repeat(self.config.term_width - (self.panel_width + 1));
|
||||||
let hline = format!("{}{}{}", "─".repeat(self.panel_width), grid_char, hline);
|
let hline = format!("{}{grid_char}{hline}", "─".repeat(self.panel_width));
|
||||||
writeln!(handle, "{}", self.colors.grid.paint(hline))?;
|
writeln!(handle, "{}", self.colors.grid.paint(hline))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,8 +343,7 @@ impl<'a> InteractivePrinter<'a> {
|
|||||||
|
|
||||||
let text_truncated: String = text.chars().take(self.panel_width - 1).collect();
|
let text_truncated: String = text.chars().take(self.panel_width - 1).collect();
|
||||||
let text_filled: String = format!(
|
let text_filled: String = format!(
|
||||||
"{}{}",
|
"{text_truncated}{}",
|
||||||
text_truncated,
|
|
||||||
" ".repeat(self.panel_width - 1 - text_truncated.len())
|
" ".repeat(self.panel_width - 1 - text_truncated.len())
|
||||||
);
|
);
|
||||||
if self.config.style_components.grid() {
|
if self.config.style_components.grid() {
|
||||||
@@ -400,7 +399,7 @@ impl<'a> InteractivePrinter<'a> {
|
|||||||
while content_graphemes.len() > content_width {
|
while content_graphemes.len() > content_width {
|
||||||
let (content_line, remaining) = content_graphemes.split_at(content_width);
|
let (content_line, remaining) = content_graphemes.split_at(content_width);
|
||||||
self.print_header_component_with_indent(handle, content_line.join("").as_str())?;
|
self.print_header_component_with_indent(handle, content_line.join("").as_str())?;
|
||||||
content_graphemes = remaining.iter().cloned().collect();
|
content_graphemes = remaining.to_vec();
|
||||||
}
|
}
|
||||||
self.print_header_component_with_indent(handle, content_graphemes.join("").as_str())
|
self.print_header_component_with_indent(handle, content_graphemes.join("").as_str())
|
||||||
}
|
}
|
||||||
@@ -513,13 +512,12 @@ impl Printer for InteractivePrinter<'_> {
|
|||||||
.try_for_each(|component| match component {
|
.try_for_each(|component| match component {
|
||||||
StyleComponent::HeaderFilename => {
|
StyleComponent::HeaderFilename => {
|
||||||
let header_filename = format!(
|
let header_filename = format!(
|
||||||
"{}{}{}",
|
"{}{}{mode}",
|
||||||
description
|
description
|
||||||
.kind()
|
.kind()
|
||||||
.map(|kind| format!("{kind}: "))
|
.map(|kind| format!("{kind}: "))
|
||||||
.unwrap_or_else(|| "".into()),
|
.unwrap_or_else(|| "".into()),
|
||||||
self.colors.header_value.paint(description.title()),
|
self.colors.header_value.paint(description.title()),
|
||||||
mode
|
|
||||||
);
|
);
|
||||||
self.print_header_multiline_component(handle, &header_filename)
|
self.print_header_multiline_component(handle, &header_filename)
|
||||||
}
|
}
|
||||||
@@ -701,7 +699,7 @@ impl Printer for InteractivePrinter<'_> {
|
|||||||
"{}{}",
|
"{}{}",
|
||||||
as_terminal_escaped(
|
as_terminal_escaped(
|
||||||
style,
|
style,
|
||||||
&format!("{}{}", self.ansi_style, text_trimmed),
|
&format!("{}{text_trimmed}", self.ansi_style),
|
||||||
true_color,
|
true_color,
|
||||||
colored_output,
|
colored_output,
|
||||||
italics,
|
italics,
|
||||||
@@ -791,7 +789,7 @@ impl Printer for InteractivePrinter<'_> {
|
|||||||
"{}{}\n{}",
|
"{}{}\n{}",
|
||||||
as_terminal_escaped(
|
as_terminal_escaped(
|
||||||
style,
|
style,
|
||||||
&format!("{}{}", self.ansi_style, line_buf),
|
&format!("{}{line_buf}", self.ansi_style),
|
||||||
self.config.true_color,
|
self.config.true_color,
|
||||||
self.config.colored_output,
|
self.config.colored_output,
|
||||||
self.config.use_italic_text,
|
self.config.use_italic_text,
|
||||||
@@ -818,7 +816,7 @@ impl Printer for InteractivePrinter<'_> {
|
|||||||
"{}",
|
"{}",
|
||||||
as_terminal_escaped(
|
as_terminal_escaped(
|
||||||
style,
|
style,
|
||||||
&format!("{}{}", self.ansi_style, line_buf),
|
&format!("{}{line_buf}", self.ansi_style),
|
||||||
self.config.true_color,
|
self.config.true_color,
|
||||||
self.config.colored_output,
|
self.config.colored_output,
|
||||||
self.config.use_italic_text,
|
self.config.use_italic_text,
|
||||||
|
@@ -212,15 +212,15 @@ impl Attributes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update_with_charset(&mut self, kind: char, set: impl Iterator<Item = char>) -> bool {
|
fn update_with_charset(&mut self, kind: char, set: impl Iterator<Item = char>) -> bool {
|
||||||
self.charset = format!("\x1B{}{}", kind, set.take(1).collect::<String>());
|
self.charset = format!("\x1B{kind}{}", set.take(1).collect::<String>());
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_color(color: u16, parameters: &mut dyn Iterator<Item = u16>) -> String {
|
fn parse_color(color: u16, parameters: &mut dyn Iterator<Item = u16>) -> String {
|
||||||
match color % 10 {
|
match color % 10 {
|
||||||
8 => match parameters.next() {
|
8 => match parameters.next() {
|
||||||
Some(5) /* 256-color */ => format!("\x1B[{};5;{}m", color, join(";", 1, parameters)),
|
Some(5) /* 256-color */ => format!("\x1B[{color};5;{}m", join(";", 1, parameters)),
|
||||||
Some(2) /* 24-bit color */ => format!("\x1B[{};2;{}m", color, join(";", 3, parameters)),
|
Some(2) /* 24-bit color */ => format!("\x1B[{color};2;{}m", join(";", 3, parameters)),
|
||||||
Some(c) => format!("\x1B[{color};{c}m"),
|
Some(c) => format!("\x1B[{color};{c}m"),
|
||||||
_ => "".to_owned(),
|
_ => "".to_owned(),
|
||||||
},
|
},
|
||||||
|
BIN
tests/examples/test_UTF-16BE-complicated.txt
vendored
Normal file
BIN
tests/examples/test_UTF-16BE-complicated.txt
vendored
Normal file
Binary file not shown.
BIN
tests/examples/test_UTF-16BE.txt
vendored
Normal file
BIN
tests/examples/test_UTF-16BE.txt
vendored
Normal file
Binary file not shown.
BIN
tests/examples/test_UTF-16LE-complicated.txt
vendored
Normal file
BIN
tests/examples/test_UTF-16LE-complicated.txt
vendored
Normal file
Binary file not shown.
@@ -1452,6 +1452,38 @@ fn utf16() {
|
|||||||
.assert()
|
.assert()
|
||||||
.success()
|
.success()
|
||||||
.stdout("hello world\n");
|
.stdout("hello world\n");
|
||||||
|
|
||||||
|
bat()
|
||||||
|
.arg("--plain")
|
||||||
|
.arg("--decorations=always")
|
||||||
|
.arg("test_UTF-16BE.txt")
|
||||||
|
.assert()
|
||||||
|
.success()
|
||||||
|
.stdout("hello world\nthis is a test\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn utf16le() {
|
||||||
|
bat()
|
||||||
|
.arg("--decorations=always")
|
||||||
|
.arg("--style=numbers")
|
||||||
|
.arg("--color=never")
|
||||||
|
.arg("test_UTF-16LE-complicated.txt")
|
||||||
|
.assert()
|
||||||
|
.success()
|
||||||
|
.stdout(" 1 上一伊刀\n 2 foo bar\n 3 hello world\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn utf16be() {
|
||||||
|
bat()
|
||||||
|
.arg("--decorations=always")
|
||||||
|
.arg("--style=numbers")
|
||||||
|
.arg("--color=never")
|
||||||
|
.arg("test_UTF-16BE-complicated.txt")
|
||||||
|
.assert()
|
||||||
|
.success()
|
||||||
|
.stdout(" 1 上一伊刀\n 2 foo bar\n 3 hello world\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Regression test for https://github.com/sharkdp/bat/issues/1922
|
// Regression test for https://github.com/sharkdp/bat/issues/1922
|
||||||
|
@@ -75,7 +75,7 @@ fn create_sample_directory() -> Result<TempDir, git2::Error> {
|
|||||||
|
|
||||||
// Copy over `sample.rs`
|
// Copy over `sample.rs`
|
||||||
let sample_path = temp_dir.path().join("sample.rs");
|
let sample_path = temp_dir.path().join("sample.rs");
|
||||||
println!("{:?}", &sample_path);
|
println!("{sample_path:?}");
|
||||||
fs::copy("tests/snapshots/sample.rs", &sample_path).expect("successful copy");
|
fs::copy("tests/snapshots/sample.rs", &sample_path).expect("successful copy");
|
||||||
|
|
||||||
// Commit
|
// Commit
|
||||||
|
@@ -19,7 +19,7 @@ fn get_mocked_pagers_dir() -> PathBuf {
|
|||||||
pub fn from(base: &str) -> String {
|
pub fn from(base: &str) -> String {
|
||||||
let mut cmd_and_args = shell_words::split(base).unwrap();
|
let mut cmd_and_args = shell_words::split(base).unwrap();
|
||||||
let suffix = if cfg!(windows) { ".bat" } else { "" };
|
let suffix = if cfg!(windows) { ".bat" } else { "" };
|
||||||
let mut out_cmd = format!("{}{}", cmd_and_args.first().unwrap(), suffix);
|
let mut out_cmd = format!("{}{suffix}", cmd_and_args.first().unwrap());
|
||||||
|
|
||||||
if (cmd_and_args.len() > 1) {
|
if (cmd_and_args.len() > 1) {
|
||||||
out_cmd.push(' ');
|
out_cmd.push(' ');
|
||||||
|
Reference in New Issue
Block a user