1
0
mirror of https://github.com/sharkdp/bat.git synced 2025-03-03 17:28:50 +00:00

Merge branch 'master' into fix-readme-translation

This commit is contained in:
Keith Hall 2025-01-27 22:20:35 +02:00 committed by GitHub
commit bee08e48ae
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 1049 additions and 549 deletions

2
.cargo/audit.toml Normal file
View File

@ -0,0 +1,2 @@
[advisories]
ignore = ["RUSTSEC-2024-0320", "RUSTSEC-2024-0421"]

View File

@ -152,6 +152,7 @@ jobs:
name: cargo audit name: cargo audit
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- run: cargo install cargo-audit --locked
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: cargo audit - run: cargo audit

View File

@ -2,6 +2,26 @@
## Features ## Features
## Bugfixes
- Fix `BAT_THEME_DARK` and `BAT_THEME_LIGHT` being ignored, see issue #3171 and PR #3168 (@bash)
- Prevent `--list-themes` from outputting default theme info to stdout when it is piped, see #3189 (@einfachIrgendwer0815)
## Other
- Work around build failures when building `bat` from vendored sources #3179 (@dtolnay)
## Syntaxes
- Add syntax mapping for paru configuration files #3182 (@cyqsimon)
## Themes
## `bat` as a library
# v0.25.0
## Features
- Set terminal title to file names when Paging is not Paging::Never #2807 (@Oliver-Looney) - Set terminal title to file names when Paging is not Paging::Never #2807 (@Oliver-Looney)
- `bat --squeeze-blank`/`bat -s` will now squeeze consecutive empty lines, see #1441 (@eth-p) and #2665 (@einfachIrgendwer0815) - `bat --squeeze-blank`/`bat -s` will now squeeze consecutive empty lines, see #1441 (@eth-p) and #2665 (@einfachIrgendwer0815)
- `bat --squeeze-limit` to set the maximum number of empty consecutive when using `--squeeze-blank`, see #1441 (@eth-p) and #2665 (@einfachIrgendwer0815) - `bat --squeeze-limit` to set the maximum number of empty consecutive when using `--squeeze-blank`, see #1441 (@eth-p) and #2665 (@einfachIrgendwer0815)
@ -12,6 +32,7 @@
- Automatically choose theme based on the terminal's color scheme, see #2896 (@bash) - Automatically choose theme based on the terminal's color scheme, see #2896 (@bash)
- Add option `--binary=as-text` for printing binary content, see issue #2974 and PR #2976 (@einfachIrgendwer0815) - Add option `--binary=as-text` for printing binary content, see issue #2974 and PR #2976 (@einfachIrgendwer0815)
- Make shell completions available via `--completion <shell>`, see issue #2057 and PR #3126 (@einfachIrgendwer0815) - Make shell completions available via `--completion <shell>`, see issue #2057 and PR #3126 (@einfachIrgendwer0815)
- Syntax highlighting for puppet code blocks within Markdown files, see #3152 (@liliwilson)
## Bugfixes ## Bugfixes
@ -22,6 +43,7 @@
- Fix panel width when line 10000 wraps, see #2854 (@eth-p) - Fix panel width when line 10000 wraps, see #2854 (@eth-p)
- Fix compile issue of `time` dependency caused by standard library regression #3045 (@cyqsimon) - Fix compile issue of `time` dependency caused by standard library regression #3045 (@cyqsimon)
- Fix override behavior of --plain and --paging, see issue #2731 and PR #3108 (@einfachIrgendwer0815) - Fix override behavior of --plain and --paging, see issue #2731 and PR #3108 (@einfachIrgendwer0815)
- Fix bugs in `$LESSOPEN` support, see #2805 (@Anomalocaridid)
## Other ## Other
@ -49,6 +71,8 @@
- Support 'statically linked binary' for aarch64 in 'Release' page, see #2992 (@tzq0301) - Support 'statically linked binary' for aarch64 in 'Release' page, see #2992 (@tzq0301)
- Update options in shell completions and the man page of `bat`, see #2995 (@akinomyoga) - Update options in shell completions and the man page of `bat`, see #2995 (@akinomyoga)
- Update nix dev-dependency to v0.29.0, see #3112 (@decathorpe) - Update nix dev-dependency to v0.29.0, see #3112 (@decathorpe)
- Bump MSRV to [1.74](https://blog.rust-lang.org/2023/11/16/Rust-1.74.0.html), see #3154 (@keith-hall)
- Update clircle dependency to remove winapi transitive dependency, see #3113 (@niklasmohrin)
## Syntaxes ## Syntaxes
@ -73,6 +97,8 @@
## Themes ## Themes
- Patched/improved themes for better Manpage syntax highlighting support, see #2994 (@keith-hall).
## `bat` as a library ## `bat` as a library
- Changes to `syntax_mapping::SyntaxMapping` #2755 (@cyqsimon) - Changes to `syntax_mapping::SyntaxMapping` #2755 (@cyqsimon)

1144
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -6,11 +6,11 @@ homepage = "https://github.com/sharkdp/bat"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
name = "bat" name = "bat"
repository = "https://github.com/sharkdp/bat" repository = "https://github.com/sharkdp/bat"
version = "0.24.0" version = "0.25.0"
exclude = ["assets/syntaxes/*", "assets/themes/*"] exclude = ["assets/syntaxes/*", "assets/themes/*"]
build = "build/main.rs" build = "build/main.rs"
edition = '2021' edition = '2021'
rust-version = "1.70" rust-version = "1.74"
[features] [features]
default = ["application"] default = ["application"]
@ -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/conversions"] # 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:
@ -44,7 +44,7 @@ regex-fancy = ["syntect/regex-fancy"] # Use the rust-only "fancy-regex" engine
nu-ansi-term = "0.50.0" nu-ansi-term = "0.50.0"
ansi_colours = "^1.2" ansi_colours = "^1.2"
bincode = "1.0" bincode = "1.0"
console = "0.15.8" console = "0.15.10"
flate2 = "1.0" flate2 = "1.0"
once_cell = "1.20" once_cell = "1.20"
thiserror = "1.0" thiserror = "1.0"
@ -58,7 +58,7 @@ serde_derive = "1.0"
serde_yaml = "0.9.28" serde_yaml = "0.9.28"
semver = "1.0" semver = "1.0"
path_abs = { version = "0.5", default-features = false } path_abs = { version = "0.5", default-features = false }
clircle = "0.6" clircle = { version = "0.6.1", default-features = false }
bugreport = { version = "0.5.0", optional = true } bugreport = { version = "0.5.0", optional = true }
etcetera = { version = "0.8.0", optional = true } etcetera = { version = "0.8.0", optional = true }
grep-cli = { version = "0.1.11", optional = true } grep-cli = { version = "0.1.11", optional = true }
@ -66,12 +66,11 @@ regex = { version = "1.10.6", optional = true }
walkdir = { version = "2.5", optional = true } walkdir = { version = "2.5", optional = true }
bytesize = { version = "1.3.0" } bytesize = { version = "1.3.0" }
encoding_rs = "0.8.35" encoding_rs = "0.8.35"
os_str_bytes = { version = "~7.0", optional = true } execute = { version = "0.2.13", optional = true }
run_script = { version = "^0.10.1", optional = true}
terminal-colorsaurus = "0.4" terminal-colorsaurus = "0.4"
[dependencies.git2] [dependencies.git2]
version = "0.19" version = "0.20"
optional = true optional = true
default-features = false default-features = false
@ -93,7 +92,7 @@ plist = "1.7.0"
assert_cmd = "2.0.12" assert_cmd = "2.0.12"
expect-test = "1.5.0" expect-test = "1.5.0"
serial_test = { version = "2.0.0", default-features = false } serial_test = { version = "2.0.0", default-features = false }
predicates = "3.1.0" predicates = "3.1.3"
wait-timeout = "0.2.0" wait-timeout = "0.2.0"
tempfile = "3.8.1" tempfile = "3.8.1"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
@ -109,7 +108,7 @@ once_cell = "1.20"
regex = "1.10.6" regex = "1.10.6"
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
serde_with = { version = "3.8.1", default-features = false, features = ["macros"] } serde_with = { version = "3.12.0", default-features = false, features = ["macros"] }
toml = { version = "0.8.19", features = ["preserve_order"] } toml = { version = "0.8.19", features = ["preserve_order"] }
walkdir = "2.5" walkdir = "2.5"

View File

@ -204,24 +204,30 @@ bat main.cpp | xclip
`MANPAGER` environment variable: `MANPAGER` environment variable:
```bash ```bash
export MANPAGER="sh -c 'col -bx | bat -l man -p'" export MANPAGER="sh -c 'sed -u -e \"s/\\x1B\[[0-9;]*m//g; s/.\\x08//g\" | bat -p -lman'"
man 2 select man 2 select
``` ```
(replace `bat` with `batcat` if you are on Debian or Ubuntu) (replace `bat` with `batcat` if you are on Debian or Ubuntu)
It might also be necessary to set `MANROFFOPT="-c"` if you experience
formatting problems.
If you prefer to have this bundled in a new command, you can also use [`batman`](https://github.com/eth-p/bat-extras/blob/master/doc/batman.md). If you prefer to have this bundled in a new command, you can also use [`batman`](https://github.com/eth-p/bat-extras/blob/master/doc/batman.md).
Note that the [Manpage syntax](assets/syntaxes/02_Extra/Manpage.sublime-syntax) is developed in this repository and still needs some work. > [!WARNING]
> This will [not work](https://github.com/sharkdp/bat/issues/1145) out of the box with Mandoc's `man` implementation.
>
> Please either use `batman`, or convert the shell script to a [shebang executable](https://en.wikipedia.org/wiki/Shebang_(Unix)) and point `MANPAGER` to that.
Also, note that this will [not work](https://github.com/sharkdp/bat/issues/1145) with Mandocs `man` implementation. Note that the [Manpage syntax](assets/syntaxes/02_Extra/Manpage.sublime-syntax) is developed in this repository and still needs some work.
#### `prettier` / `shfmt` / `rustfmt` #### `prettier` / `shfmt` / `rustfmt`
The [`prettybat`](https://github.com/eth-p/bat-extras/blob/master/doc/prettybat.md) script is a wrapper that will format code and print it with `bat`. The [`prettybat`](https://github.com/eth-p/bat-extras/blob/master/doc/prettybat.md) script is a wrapper that will format code and print it with `bat`.
#### `Warp`
<a href="https://app.warp.dev/drive/folder/-Bat-Warp-Pack-lxhe7HrEwgwpG17mvrFSz1">
<img src="doc/sponsors/warp-pack-header.png" alt="Warp">
</a>
#### Highlighting `--help` messages #### Highlighting `--help` messages
You can use `bat` to colorize help text: `$ cp --help | bat -plhelp` You can use `bat` to colorize help text: `$ cp --help | bat -plhelp`
@ -455,7 +461,7 @@ binaries are also available: look for archives with `musl` in the file name.
### From source ### From source
If you want to build `bat` from source, you need Rust 1.70.0 or If you want to build `bat` from source, you need Rust 1.74.0 or
higher. You can then use `cargo` to build everything: higher. You can then use `cargo` to build everything:
```bash ```bash
@ -489,7 +495,7 @@ bat --list-themes | fzf --preview="bat --theme={} --color=always /path/to/file"
``` ```
`bat` automatically picks a fitting theme depending on your terminal's background color. `bat` automatically picks a fitting theme depending on your terminal's background color.
You can use the `--theme-light` / `--theme-light` options or the `BAT_THEME_DARK` / `BAT_THEME_LIGHT` environment variables You can use the `--theme-dark` / `--theme-light` options or the `BAT_THEME_DARK` / `BAT_THEME_LIGHT` environment variables
to customize the themes used. This is especially useful if you frequently switch between dark and light mode. to customize the themes used. This is especially useful if you frequently switch between dark and light mode.
You can also use a custom theme by following the You can also use a custom theme by following the

Binary file not shown.

22
assets/patches/1337.tmTheme.patch vendored Normal file
View File

@ -0,0 +1,22 @@
diff --git themes/1337-Scheme/1337.tmTheme themes/1337-Scheme/1337.tmTheme
index fdff5bf..8cfc888 100644
--- themes/1337-Scheme/1337.tmTheme
+++ themes/1337-Scheme/1337.tmTheme
@@ -280,7 +280,7 @@ SOFTWARE.
<key>name</key>
<string>PHP Namespaces</string>
<key>scope</key>
- <string>support.other.namespace, entity.name.type.namespace</string>
+ <string>support.other.namespace, entity.name.type.namespace, entity.name</string>
<key>settings</key>
<dict>
<key>foreground</key>
@@ -561,7 +561,7 @@ SOFTWARE.
<key>name</key>
<string>diff.header</string>
<key>scope</key>
- <string>meta.diff, meta.diff.header</string>
+ <string>meta.diff, meta.diff.header, markup.heading</string>
<key>settings</key>
<dict>
<key>foreground</key>

View File

@ -1,5 +1,5 @@
diff --git syntaxes/01_Packages/Markdown/Markdown.sublime-syntax syntaxes/01_Packages/Markdown/Markdown.sublime-syntax diff --git syntaxes/01_Packages/Markdown/Markdown.sublime-syntax syntaxes/01_Packages/Markdown/Markdown.sublime-syntax
index 19dc685d..44440c7f 100644 index 19dc685d..3a45ea05 100644
--- syntaxes/01_Packages/Markdown/Markdown.sublime-syntax --- syntaxes/01_Packages/Markdown/Markdown.sublime-syntax
+++ syntaxes/01_Packages/Markdown/Markdown.sublime-syntax +++ syntaxes/01_Packages/Markdown/Markdown.sublime-syntax
@@ -24,7 +24,6 @@ variables: @@ -24,7 +24,6 @@ variables:
@ -166,7 +166,29 @@ index 19dc685d..44440c7f 100644
- match: ^\s*$\n? - match: ^\s*$\n?
scope: invalid.illegal.non-terminated.bold-italic.markdown scope: invalid.illegal.non-terminated.bold-italic.markdown
pop: true pop: true
@@ -1152,7 +1110,7 @@ contexts: @@ -1073,6 +1031,21 @@ contexts:
escape: '{{code_fence_escape}}'
escape_captures:
0: meta.code-fence.definition.end.python.markdown-gfm
+ 1: punctuation.definition.raw.code-fence.end.markdown
+ - match: |-
+ (?x)
+ {{fenced_code_block_start}}
+ ((?i:puppet))
+ {{fenced_code_block_trailing_infostring_characters}}
+ captures:
+ 0: meta.code-fence.definition.begin.puppet.markdown-gfm
+ 2: punctuation.definition.raw.code-fence.begin.markdown
+ 5: constant.other.language-name.markdown
+ embed: scope:source.puppet
+ embed_scope: markup.raw.code-fence.puppet.markdown-gfm
+ escape: '{{code_fence_escape}}'
+ escape_captures:
+ 0: meta.code-fence.definition.end.puppet.markdown-gfm
1: punctuation.definition.raw.code-fence.end.markdown
- match: |-
(?x)
@@ -1152,7 +1125,7 @@ contexts:
- match: |- - match: |-
(?x) (?x)
{{fenced_code_block_start}} {{fenced_code_block_start}}

View File

@ -0,0 +1,47 @@
diff --git themes/onehalf/sublimetext/OneHalfDark.tmTheme themes/onehalf/sublimetext/OneHalfDark.tmTheme
index b16050c..b021071 100644
--- themes/onehalf/sublimetext/OneHalfDark.tmTheme
+++ themes/onehalf/sublimetext/OneHalfDark.tmTheme
@@ -28,7 +28,7 @@
<plist version="1.0">
<dict>
<key>name</key>
- <string>OneHalfLight</string>
+ <string>OneHalfDark</string>
<key>semanticClass</key>
<string>theme.dark.one_half_dark</string>
<key>uuid</key>
@@ -155,7 +155,7 @@
<key>name</key>
<string>Classes</string>
<key>scope</key>
- <string>support.class, entity.name.class, entity.name.type.class</string>
+ <string>support.class, entity.name.class, entity.name.type.class, entity.name</string>
<key>settings</key>
<dict>
<key>foreground</key>
@@ -188,7 +188,7 @@
<key>name</key>
<string>Storage</string>
<key>scope</key>
- <string>storage</string>
+ <string>storage, meta.mapping.key string</string>
<key>settings</key>
<dict>
<key>foreground</key>
@@ -309,7 +309,7 @@
<key>name</key>
<string>Markdown: Headings</string>
<key>scope</key>
- <string>markup.heading punctuation.definition.heading, entity.name.section</string>
+ <string>markup.heading punctuation.definition.heading, entity.name.section, markup.heading - text.html.markdown</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
@@ -660,4 +660,4 @@
</dict>
</array>
</dict>
-</plist>
\ No newline at end of file
+</plist>

View File

@ -2,6 +2,24 @@ diff --git themes/TwoDark/TwoDark.tmTheme themes/TwoDark/TwoDark.tmTheme
index 87fd358..56376d3 100644 index 87fd358..56376d3 100644
--- themes/TwoDark/TwoDark.tmTheme --- themes/TwoDark/TwoDark.tmTheme
+++ themes/TwoDark/TwoDark.tmTheme +++ themes/TwoDark/TwoDark.tmTheme
@@ -125,7 +125,7 @@
<key>name</key>
<string>Classes</string>
<key>scope</key>
- <string>support.class, entity.name.class, entity.name.type.class</string>
+ <string>support.class, entity.name.class, entity.name.type.class, entity.name</string>
<key>settings</key>
<dict>
<key>foreground</key>
@@ -290,7 +290,7 @@
<key>name</key>
<string>Headings</string>
<key>scope</key>
- <string>markup.heading punctuation.definition.heading, entity.name.section</string>
+ <string>markup.heading punctuation.definition.heading, entity.name.section, markup.heading - text.html.markdown</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
@@ -533,7 +533,7 @@ @@ -533,7 +533,7 @@
<key>name</key> <key>name</key>
<string>Json key</string> <string>Json key</string>

BIN
assets/syntaxes.bin vendored

Binary file not shown.

View File

@ -85,6 +85,9 @@ contexts:
options: options:
# command-line options like --option=value, --some-flag, or -x # command-line options like --option=value, --some-flag, or -x
- match: '^[ ]{7}(-)(?=\s)'
captures:
1: entity.name.command-line-option.man
- match: '^[ ]{7}(?=-|\+)' - match: '^[ ]{7}(?=-|\+)'
push: expect-command-line-option push: expect-command-line-option
- match: '(?:[^a-zA-Z0-9_-]|^|\s){{command_line_option}}' - match: '(?:[^a-zA-Z0-9_-]|^|\s){{command_line_option}}'

View File

@ -131,6 +131,12 @@ OPTIONS
# ^^ - variable # ^^ - variable
output NUM (default 3) lines of copied context output NUM (default 3) lines of copied context
- This is not really a switch, but indicates that standard input
# ^ entity.name.command-line-option.man
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - entity - variable
is coming from a file or a pipe and not interactively from the
command line.
EXAMPLE EXAMPLE
#include <stdio.h> #include <stdio.h>
# ^^^^^^^^ source.c meta.preprocessor.include keyword.control.import.include # ^^^^^^^^ source.c meta.preprocessor.include keyword.control.import.include

BIN
assets/themes.bin vendored

Binary file not shown.

View File

@ -69,7 +69,7 @@
<key>name</key> <key>name</key>
<string>Labels</string> <string>Labels</string>
<key>scope</key> <key>scope</key>
<string>entity.name.label</string> <string>entity.name.label, variable.parameter</string>
<key>settings</key> <key>settings</key>
<dict> <dict>
<key>foreground</key> <key>foreground</key>
@ -80,7 +80,7 @@
<key>name</key> <key>name</key>
<string>Classes</string> <string>Classes</string>
<key>scope</key> <key>scope</key>
<string>support.class, entity.name.class, entity.name.type.class</string> <string>support.class, entity.name.class, entity.name.type.class, entity.name</string>
<key>settings</key> <key>settings</key>
<dict> <dict>
<key>foreground</key> <key>foreground</key>
@ -234,7 +234,7 @@
<key>name</key> <key>name</key>
<string>Headings</string> <string>Headings</string>
<key>scope</key> <key>scope</key>
<string>markup.heading punctuation.definition.heading, entity.name.section</string> <string>markup.heading punctuation.definition.heading, entity.name.section, markup.heading - text.html.markdown</string>
<key>settings</key> <key>settings</key>
<dict> <dict>
<key>fontStyle</key> <key>fontStyle</key>

View File

@ -257,7 +257,7 @@
<key>name</key> <key>name</key>
<string>Tags</string> <string>Tags</string>
<key>scope</key> <key>scope</key>
<string>entity.name.tag</string> <string>entity.name.tag, entity.name</string>
<key>settings</key> <key>settings</key>
<dict> <dict>
<key>foreground</key> <key>foreground</key>
@ -312,7 +312,7 @@
<key>name</key> <key>name</key>
<string>Headings</string> <string>Headings</string>
<key>scope</key> <key>scope</key>
<string>markup.heading punctuation.definition.heading, entity.name.section</string> <string>markup.heading punctuation.definition.heading, entity.name.section, markup.heading - text.html.markdown</string>
<key>settings</key> <key>settings</key>
<dict> <dict>
<key>fontStyle</key> <key>fontStyle</key>

View File

@ -256,7 +256,7 @@
<key>name</key> <key>name</key>
<string>Tags</string> <string>Tags</string>
<key>scope</key> <key>scope</key>
<string>entity.name.tag</string> <string>entity.name.tag, entity.name</string>
<key>settings</key> <key>settings</key>
<dict> <dict>
<key>foreground</key> <key>foreground</key>
@ -311,7 +311,7 @@
<key>name</key> <key>name</key>
<string>Headings</string> <string>Headings</string>
<key>scope</key> <key>scope</key>
<string>markup.heading punctuation.definition.heading, entity.name.section</string> <string>markup.heading punctuation.definition.heading, entity.name.section, markup.heading - text.html.markdown</string>
<key>settings</key> <key>settings</key>
<dict> <dict>
<key>fontStyle</key> <key>fontStyle</key>

View File

@ -236,8 +236,14 @@ fn get_def_paths() -> anyhow::Result<Vec<PathBuf>> {
]; ];
let mut toml_paths = vec![]; let mut toml_paths = vec![];
for subdir in source_subdirs { for subdir_name in source_subdirs {
let wd = WalkDir::new(Path::new("src/syntax_mapping/builtins").join(subdir)); let subdir = Path::new("src/syntax_mapping/builtins").join(subdir_name);
if !subdir.try_exists()? {
// Directory might not exist due to this `cargo vendor` bug:
// https://github.com/rust-lang/cargo/issues/15080
continue;
}
let wd = WalkDir::new(subdir);
let paths = wd let paths = wd
.into_iter() .into_iter()
.filter_map_ok(|entry| { .filter_map_ok(|entry| {

View File

@ -366,7 +366,7 @@ ansible-galaxy install aeimer.install_bat
### From source ### From source
`bat` をソースからビルドしたいならば、Rust 1.70.0 以上の環境が必要です。 `bat` をソースからビルドしたいならば、Rust 1.74.0 以上の環境が必要です。
`cargo` を使用してビルドすることができます: `cargo` を使用してビルドすることができます:
```bash ```bash

View File

@ -416,7 +416,7 @@ scoop install bat
### 소스에서 ### 소스에서
`bat`의 소스를 빌드하기 위해서는, Rust 1.70.0 이상이 필요합니다. `bat`의 소스를 빌드하기 위해서는, Rust 1.74.0 이상이 필요합니다.
`cargo`를 이용해 전부 빌드할 수 있습니다: `cargo`를 이용해 전부 빌드할 수 있습니다:
```bash ```bash

View File

@ -388,7 +388,7 @@ scoop install bat
### Из исходников ### Из исходников
Если вы желаете установить `bat` из исходников, вам понадобится Rust 1.70.0 или выше. После этого используйте `cargo`, чтобы всё скомпилировать: Если вы желаете установить `bat` из исходников, вам понадобится Rust 1.74.0 или выше. После этого используйте `cargo`, чтобы всё скомпилировать:
```bash ```bash
cargo install --locked bat cargo install --locked bat

View File

@ -372,7 +372,7 @@ scoop install bat
### 从源码编译 ### 从源码编译
如果你想要自己构建`bat`那么你需要安装有高于1.70.0版本的 Rust。 如果你想要自己构建`bat`那么你需要安装有高于1.74.0版本的 Rust。
使用以下命令编译。 使用以下命令编译。

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -210,7 +210,7 @@ pub fn list_themes(
let default_theme_name = default_theme(color_scheme(detect_color_scheme).unwrap_or_default()); let default_theme_name = default_theme(color_scheme(detect_color_scheme).unwrap_or_default());
for theme in assets.themes() { for theme in assets.themes() {
let default_theme_info = if !config.loop_through && default_theme_name == theme { let default_theme_info = if default_theme_name == theme {
" (default)" " (default)"
} else if default_theme(ColorScheme::Dark) == theme { } else if default_theme(ColorScheme::Dark) == theme {
" (default dark)" " (default dark)"
@ -231,6 +231,8 @@ pub fn list_themes(
.run(vec![theme_preview_file()], None) .run(vec![theme_preview_file()], None)
.ok(); .ok();
writeln!(stdout)?; writeln!(stdout)?;
} else if config.loop_through {
writeln!(stdout, "{theme}")?;
} else { } else {
writeln!(stdout, "{theme}{default_theme_info}")?; writeln!(stdout, "{theme}{default_theme_info}")?;
} }

View File

@ -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::new(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();

View File

@ -0,0 +1,6 @@
# See https://github.com/Morganamilo/paru/blob/master/man/paru.conf.5
[mappings]
"INI" = [
"${PARU_CONF}",
"paru.conf",
]

View File

@ -10,9 +10,9 @@ pub mod env {
/// See [`crate::theme::ThemeOptions::theme`]. /// See [`crate::theme::ThemeOptions::theme`].
pub const BAT_THEME: &str = "BAT_THEME"; pub const BAT_THEME: &str = "BAT_THEME";
/// See [`crate::theme::ThemeOptions::theme_dark`]. /// See [`crate::theme::ThemeOptions::theme_dark`].
pub const BAT_THEME_DARK: &str = "BAT_THEME"; pub const BAT_THEME_DARK: &str = "BAT_THEME_DARK";
/// See [`crate::theme::ThemeOptions::theme_light`]. /// See [`crate::theme::ThemeOptions::theme_light`].
pub const BAT_THEME_LIGHT: &str = "BAT_THEME"; pub const BAT_THEME_LIGHT: &str = "BAT_THEME_LIGHT";
} }
/// Chooses an appropriate theme or falls back to a default theme /// Chooses an appropriate theme or falls back to a default theme

View File

@ -305,21 +305,28 @@ fn list_themes_without_colors() {
#[test] #[test]
fn list_themes_to_piped_output() { fn list_themes_to_piped_output() {
bat() bat().arg("--list-themes").assert().success().stdout(
.arg("--list-themes") predicate::str::contains("(default)")
.assert() .not()
.success() .and(predicate::str::contains("(default light)").not())
.stdout(predicate::str::contains("(default)").not()); .and(predicate::str::contains("(default dark)").not()),
);
} }
#[test] #[test]
#[cfg_attr(any(not(feature = "git"), target_os = "windows"), ignore)] #[cfg_attr(
any(not(feature = "git"), feature = "lessopen", target_os = "windows"),
ignore
)]
fn short_help() { fn short_help() {
test_help("-h", "../doc/short-help.txt"); test_help("-h", "../doc/short-help.txt");
} }
#[test] #[test]
#[cfg_attr(any(not(feature = "git"), target_os = "windows"), ignore)] #[cfg_attr(
any(not(feature = "git"), feature = "lessopen", target_os = "windows"),
ignore
)]
fn long_help() { fn long_help() {
test_help("--help", "../doc/long-help.txt"); test_help("--help", "../doc/long-help.txt");
} }
@ -2259,6 +2266,46 @@ fn theme_arg_overrides_env_withconfig() {
.stderr(""); .stderr("");
} }
#[test]
fn theme_light_env_var_is_respected() {
bat()
.env("BAT_THEME_LIGHT", "Coldark-Cold")
.env("COLORTERM", "truecolor")
.arg("--theme=light")
.arg("--paging=never")
.arg("--color=never")
.arg("--terminal-width=80")
.arg("--wrap=never")
.arg("--decorations=always")
.arg("--style=plain")
.arg("--highlight-line=1")
.write_stdin("Lorem Ipsum")
.assert()
.success()
.stdout("\x1B[48;2;208;218;231mLorem Ipsum\x1B[0m")
.stderr("");
}
#[test]
fn theme_dark_env_var_is_respected() {
bat()
.env("BAT_THEME_DARK", "Coldark-Dark")
.env("COLORTERM", "truecolor")
.arg("--theme=dark")
.arg("--paging=never")
.arg("--color=never")
.arg("--terminal-width=80")
.arg("--wrap=never")
.arg("--decorations=always")
.arg("--style=plain")
.arg("--highlight-line=1")
.write_stdin("Lorem Ipsum")
.assert()
.success()
.stdout("\x1B[48;2;33;48;67mLorem Ipsum\x1B[0m")
.stderr("");
}
#[test] #[test]
fn theme_env_overrides_config() { fn theme_env_overrides_config() {
bat_with_config() bat_with_config()
@ -2437,7 +2484,6 @@ fn lessopen_stdin_piped() {
#[cfg(unix)] // Expected output assumed that tests are run on a Unix-like system #[cfg(unix)] // Expected output assumed that tests are run on a Unix-like system
#[cfg(feature = "lessopen")] #[cfg(feature = "lessopen")]
#[test] #[test]
#[serial] // Randomly fails otherwise
fn lessopen_and_lessclose_file_temp() { fn lessopen_and_lessclose_file_temp() {
// This is mainly to test that $LESSCLOSE gets passed the correct file paths // This is mainly to test that $LESSCLOSE gets passed the correct file paths
// In this case, the original file and the temporary file returned by $LESSOPEN // In this case, the original file and the temporary file returned by $LESSOPEN
@ -2455,7 +2501,6 @@ fn lessopen_and_lessclose_file_temp() {
#[cfg(unix)] // Expected output assumed that tests are run on a Unix-like system #[cfg(unix)] // Expected output assumed that tests are run on a Unix-like system
#[cfg(feature = "lessopen")] #[cfg(feature = "lessopen")]
#[test] #[test]
#[serial] // Randomly fails otherwise
fn lessopen_and_lessclose_file_piped() { fn lessopen_and_lessclose_file_piped() {
// This is mainly to test that $LESSCLOSE gets passed the correct file paths // This is mainly to test that $LESSCLOSE gets passed the correct file paths
// In these cases, the original file and a dash // In these cases, the original file and a dash
@ -2482,8 +2527,6 @@ fn lessopen_and_lessclose_file_piped() {
#[cfg(unix)] // Expected output assumed that tests are run on a Unix-like system #[cfg(unix)] // Expected output assumed that tests are run on a Unix-like system
#[cfg(feature = "lessopen")] #[cfg(feature = "lessopen")]
#[test] #[test]
#[serial] // Randomly fails otherwise
#[ignore = "randomly failing on some systems"]
fn lessopen_and_lessclose_stdin_temp() { fn lessopen_and_lessclose_stdin_temp() {
// This is mainly to test that $LESSCLOSE gets passed the correct file paths // This is mainly to test that $LESSCLOSE gets passed the correct file paths
// In this case, a dash and the temporary file returned by $LESSOPEN // In this case, a dash and the temporary file returned by $LESSOPEN
@ -2501,7 +2544,6 @@ fn lessopen_and_lessclose_stdin_temp() {
#[cfg(unix)] // Expected output assumed that tests are run on a Unix-like system #[cfg(unix)] // Expected output assumed that tests are run on a Unix-like system
#[cfg(feature = "lessopen")] #[cfg(feature = "lessopen")]
#[test] #[test]
#[serial] // Randomly fails otherwise
fn lessopen_and_lessclose_stdin_piped() { fn lessopen_and_lessclose_stdin_piped() {
// This is mainly to test that $LESSCLOSE gets passed the correct file paths // This is mainly to test that $LESSCLOSE gets passed the correct file paths
// In these cases, two dashes // In these cases, two dashes