mirror of
https://github.com/sharkdp/bat.git
synced 2025-05-31 06:56:56 +02:00
Merge branch 'master' into read-from-tail
This commit is contained in:
commit
e42883bf2c
2
.cargo/audit.toml
Normal file
2
.cargo/audit.toml
Normal file
@ -0,0 +1,2 @@
|
||||
[advisories]
|
||||
ignore = ["RUSTSEC-2024-0320", "RUSTSEC-2024-0421"]
|
4
.github/workflows/CICD.yml
vendored
4
.github/workflows/CICD.yml
vendored
@ -152,6 +152,7 @@ jobs:
|
||||
name: cargo audit
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: cargo install cargo-audit --locked
|
||||
- uses: actions/checkout@v4
|
||||
- run: cargo audit
|
||||
|
||||
@ -170,9 +171,8 @@ jobs:
|
||||
- { target: i686-pc-windows-msvc , os: windows-2019, }
|
||||
- { target: i686-unknown-linux-gnu , os: ubuntu-20.04, dpkg_arch: i686, use-cross: true }
|
||||
- { target: i686-unknown-linux-musl , os: ubuntu-20.04, dpkg_arch: musl-linux-i686, use-cross: true }
|
||||
- { target: x86_64-apple-darwin , os: macos-12, }
|
||||
- { target: x86_64-apple-darwin , os: macos-13, }
|
||||
- { target: aarch64-apple-darwin , os: macos-14, }
|
||||
- { target: x86_64-pc-windows-gnu , os: windows-2019, }
|
||||
- { target: x86_64-pc-windows-msvc , os: windows-2019, }
|
||||
- { target: x86_64-unknown-linux-gnu , os: ubuntu-20.04, dpkg_arch: amd64, use-cross: true }
|
||||
- { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, dpkg_arch: musl-linux-amd64, use-cross: true }
|
||||
|
@ -30,4 +30,4 @@ jobs:
|
||||
echo "Added lines in CHANGELOG.md:"
|
||||
echo "$ADDED"
|
||||
echo "Grepping for PR info (see CONTRIBUTING.md):"
|
||||
grep "#${PR_NUMBER}\\b.*@${PR_SUBMITTER}\\b" <<< "$ADDED"
|
||||
grep "#${PR_NUMBER}\\b.*${PR_SUBMITTER}\\b" <<< "$ADDED"
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,6 +2,7 @@
|
||||
**/*.rs.bk
|
||||
|
||||
# Generated files
|
||||
/assets/completions/_bat.ps1
|
||||
/assets/completions/bat.bash
|
||||
/assets/completions/bat.fish
|
||||
/assets/completions/bat.zsh
|
||||
|
17
.gitmodules
vendored
17
.gitmodules
vendored
@ -65,7 +65,7 @@
|
||||
path = assets/themes/onehalf
|
||||
url = https://github.com/sonph/onehalf
|
||||
[submodule "assets/syntaxes/JavaScript (Babel)"]
|
||||
path = assets/syntaxes/02_Extra/JavaScript (Babel)
|
||||
path = assets/syntaxes/02_Extra/JavaScript_(Babel)
|
||||
url = https://github.com/babel/babel-sublime
|
||||
[submodule "assets/syntaxes/FSharp"]
|
||||
path = assets/syntaxes/02_Extra/FSharp
|
||||
@ -89,7 +89,7 @@
|
||||
path = assets/themes/sublime-snazzy
|
||||
url = https://github.com/greggb/sublime-snazzy
|
||||
[submodule "assets/syntaxes/Assembly (ARM)"]
|
||||
path = assets/syntaxes/02_Extra/Assembly (ARM)
|
||||
path = assets/syntaxes/02_Extra/Assembly_(ARM)
|
||||
url = https://github.com/tvi/Sublime-ARM-Assembly
|
||||
[submodule "assets/syntaxes/protobuf-syntax-highlighting"]
|
||||
path = assets/syntaxes/02_Extra/Protobuf
|
||||
@ -108,7 +108,7 @@
|
||||
path = assets/syntaxes/02_Extra/Fish
|
||||
url = https://github.com/Phidica/sublime-fish.git
|
||||
[submodule "assets/syntaxes/Org mode"]
|
||||
path = assets/syntaxes/02_Extra/Org mode
|
||||
path = assets/syntaxes/02_Extra/Org_mode
|
||||
url = https://github.com/jezcope/Org.tmbundle.git
|
||||
[submodule "assets/syntaxes/DotENV"]
|
||||
path = assets/syntaxes/02_Extra/DotENV
|
||||
@ -142,7 +142,7 @@
|
||||
path = assets/themes/dracula-sublime
|
||||
url = https://github.com/dracula/sublime.git
|
||||
[submodule "assets/syntaxes/HTML (Twig)"]
|
||||
path = assets/syntaxes/02_Extra/HTML (Twig)
|
||||
path = assets/syntaxes/02_Extra/HTML_(Twig)
|
||||
url = https://github.com/Anomareh/PHP-Twig.tmbundle.git
|
||||
[submodule "assets/themes/Nord-sublime"]
|
||||
path = assets/themes/Nord-sublime
|
||||
@ -263,3 +263,12 @@
|
||||
[submodule "assets/syntaxes/02_Extra/CFML"]
|
||||
path = assets/syntaxes/02_Extra/CFML
|
||||
url = https://github.com/jcberquist/sublimetext-cfml.git
|
||||
[submodule "assets/syntaxes/02_Extra/Idris2"]
|
||||
path = assets/syntaxes/02_Extra/Idris2
|
||||
url = https://github.com/buzden/sublime-syntax-idris2
|
||||
[submodule "assets/syntaxes/02_Extra/GDScript-sublime"]
|
||||
path = assets/syntaxes/02_Extra/GDScript-sublime
|
||||
url = https://github.com/beefsack/GDScript-sublime
|
||||
[submodule "assets/syntaxes/02_Extra/sublime-odin"]
|
||||
path = assets/syntaxes/02_Extra/sublime-odin
|
||||
url = https://github.com/odin-lang/sublime-odin
|
||||
|
62
CHANGELOG.md
62
CHANGELOG.md
@ -2,6 +2,44 @@
|
||||
|
||||
## Features
|
||||
|
||||
- Add paging to `--list-themes`, see PR #3239 (@einfachIrgendwer0815)
|
||||
- Support negative relative line ranges, e.g. `bat -r :-10` / `bat -r='-10:'`, see #3068 (@ajesipow)
|
||||
|
||||
## 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)
|
||||
- Rename some submodules to fix Dependabot submodule updates, see issue #3198 and PR #3201 (@victor-gp)
|
||||
- Make highlight tests fail when new syntaxes don't have fixtures PR #3255 (@dan-hipschman)
|
||||
- Fix crash for multibyte characters in file path, see issue #3230 and PR #3245 (@HSM95)
|
||||
- Add missing mappings for various bash/zsh files, see PR #3262 (@AdamGaskins)
|
||||
|
||||
## Other
|
||||
|
||||
- Work around build failures when building `bat` from vendored sources #3179 (@dtolnay)
|
||||
- CICD: Stop building for x86_64-pc-windows-gnu which fails #3261 (Enselic)
|
||||
|
||||
## Syntaxes
|
||||
|
||||
- Add syntax mapping for `paru` configuration files #3182 (@cyqsimon)
|
||||
- Add support for [Idris 2 programming language](https://www.idris-lang.org/) #3150 (@buzden)
|
||||
- Add syntax mapping for `nix`'s '`flake.lock` lockfiles #3196 (@odilf)
|
||||
- Improvements to CSV/TSV highlighting, with autodetection of delimiter and support for TSV files, see #3186 (@keith-
|
||||
- Improve (Sys)log error highlighting, see #3205 (@keith-hall)
|
||||
- Map `ndjson` extension to JSON syntax, see #3209 (@keith-hall)
|
||||
- Map files with `csproj`, `vbproj`, `props` and `targets` extensions to XML syntax, see #3213 (@keith-hall)
|
||||
- Add debsources syntax to highlight `/etc/apt/sources.list` files, see #3215 (@keith-hall)
|
||||
- Add syntax definition and test file for GDScript highlighting, see #3236 (@chetanjangir0)
|
||||
- Add syntax test file for Odin highlighting, see #3241 (@chetanjangir0)
|
||||
|
||||
## Themes
|
||||
|
||||
## `bat` as a library
|
||||
|
||||
# v0.25.0
|
||||
|
||||
## Features
|
||||
|
||||
- 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-limit` to set the maximum number of empty consecutive when using `--squeeze-blank`, see #1441 (@eth-p) and #2665 (@einfachIrgendwer0815)
|
||||
@ -9,7 +47,10 @@
|
||||
- Syntax highlighting for JavaScript files that start with `#!/usr/bin/env bun` #2913 (@sharunkumar)
|
||||
- `bat --strip-ansi={never,always,auto}` to remove ANSI escape sequences from bat's input, see #2999 (@eth-p)
|
||||
- Add or remove individual style components without replacing all styles #2929 (@eth-p)
|
||||
- Support negative relative line ranges, e.g. `bat -r :-10` / `bat -r='-10:'`, see #3068 (@ajesipow)
|
||||
- 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)
|
||||
- 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
|
||||
|
||||
@ -19,6 +60,8 @@
|
||||
- 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 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 bugs in `$LESSOPEN` support, see #2805 (@Anomalocaridid)
|
||||
|
||||
## Other
|
||||
|
||||
@ -45,6 +88,9 @@
|
||||
- Use bat's ANSI iterator during tab expansion, see #2998 (@eth-p)
|
||||
- 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 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
|
||||
|
||||
@ -56,12 +102,21 @@
|
||||
- Associate JSON with Comments `.jsonc` with `json` syntax, see #2795 (@mxaddict)
|
||||
- Associate JSON-LD `.jsonld` files with `json` syntax, see #3037 (@vorburger)
|
||||
- Associate `.textproto` files with `ProtoBuf` syntax, see #3038 (@vorburger)
|
||||
- Associate GeoJSON `.geojson` files with `json` syntax, see #3084 (@mvaaltola)
|
||||
- Associate `.aws/{config,credentials}`, see #2795 (@mxaddict)
|
||||
- Associate Wireguard config `/etc/wireguard/*.conf`, see #2874 (@cyqsimon)
|
||||
- Add support for [CFML](https://www.adobe.com/products/coldfusion-family.html), see #3031 (@brenton-at-pieces)
|
||||
- Map `*.mkd` files to `Markdown` syntax, see issue #3060 and PR #3061 (@einfachIrgendwer0815)
|
||||
- Add syntax mapping for CITATION.cff, see #3103 (@Ugzuzg)
|
||||
- Add syntax mapping for kubernetes config files #3049 (@cyqsimon)
|
||||
- Adds support for pipe delimiter for CSV #3115 (@pratik-m)
|
||||
- Add syntax mapping for `/etc/pacman.conf` #2961 (@cyqsimon)
|
||||
- Associate `uv.lock` with `TOML` syntax, see #3132 (@fepegar)
|
||||
|
||||
## Themes
|
||||
|
||||
- Patched/improved themes for better Manpage syntax highlighting support, see #2994 (@keith-hall).
|
||||
|
||||
## `bat` as a library
|
||||
|
||||
- Changes to `syntax_mapping::SyntaxMapping` #2755 (@cyqsimon)
|
||||
@ -70,6 +125,10 @@
|
||||
- [BREAKING] `SyntaxMapping::mappings` is replaced by `SyntaxMapping::{builtin,custom,all}_mappings`
|
||||
- Make `Controller::run_with_error_handler`'s error handler `FnMut`, see #2831 (@rhysd)
|
||||
- Improve compile time by 20%, see #2815 (@dtolnay)
|
||||
- Add `theme::theme` for choosing an appropriate theme based on the
|
||||
terminal's color scheme, see #2896 (@bash)
|
||||
- [BREAKING] Remove `HighlightingAssets::default_theme`. Use `theme::default_theme` instead.
|
||||
- Add `PrettyPrinter::print_with_writer` for custom output destinations, see #3070 (@kojix2)
|
||||
|
||||
# v0.24.0
|
||||
|
||||
@ -108,6 +167,7 @@
|
||||
- Update `Julia` syntax, see #2553 (@dependabot)
|
||||
- add `NSIS` support, see #2577 (@idleberg)
|
||||
- Update `ssh-config`, see #2697 (@mrmeszaros)
|
||||
- Add syntax mapping `*.debdiff` => `diff`, see #2947 (@jacg)
|
||||
|
||||
## `bat` as a library
|
||||
|
||||
|
1396
Cargo.lock
generated
1396
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
52
Cargo.toml
52
Cargo.toml
@ -6,11 +6,12 @@ homepage = "https://github.com/sharkdp/bat"
|
||||
license = "MIT OR Apache-2.0"
|
||||
name = "bat"
|
||||
repository = "https://github.com/sharkdp/bat"
|
||||
version = "0.24.0"
|
||||
version = "0.25.0"
|
||||
exclude = ["assets/syntaxes/*", "assets/themes/*"]
|
||||
build = "build/main.rs"
|
||||
edition = '2021'
|
||||
rust-version = "1.70"
|
||||
# You are free to bump MSRV as soon as a reason for bumping emerges.
|
||||
rust-version = "1.74"
|
||||
|
||||
[features]
|
||||
default = ["application"]
|
||||
@ -33,7 +34,7 @@ minimal-application = [
|
||||
]
|
||||
git = ["git2"] # Support indicating git modifications
|
||||
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"]
|
||||
|
||||
# You need to use one of these if you depend on bat as a library:
|
||||
@ -44,10 +45,10 @@ regex-fancy = ["syntect/regex-fancy"] # Use the rust-only "fancy-regex" engine
|
||||
nu-ansi-term = "0.50.0"
|
||||
ansi_colours = "^1.2"
|
||||
bincode = "1.0"
|
||||
console = "0.15.8"
|
||||
console = "0.15.10"
|
||||
flate2 = "1.0"
|
||||
once_cell = "1.19"
|
||||
thiserror = "1.0"
|
||||
once_cell = "1.20"
|
||||
thiserror = "2.0"
|
||||
wild = { version = "2.2", optional = true }
|
||||
content_inspector = "0.2.4"
|
||||
shell-words = { version = "1.1.0", optional = true }
|
||||
@ -58,20 +59,21 @@ serde_derive = "1.0"
|
||||
serde_yaml = "0.9.28"
|
||||
semver = "1.0"
|
||||
path_abs = { version = "0.5", default-features = false }
|
||||
clircle = "0.5"
|
||||
clircle = { version = "0.6.1", default-features = false }
|
||||
bugreport = { version = "0.5.0", optional = true }
|
||||
etcetera = { version = "0.8.0", optional = true }
|
||||
grep-cli = { version = "0.1.10", optional = true }
|
||||
regex = { version = "1.10.2", optional = true }
|
||||
etcetera = { version = "0.10.0", optional = true }
|
||||
grep-cli = { version = "0.1.11", optional = true }
|
||||
regex = { version = "1.10.6", optional = true }
|
||||
walkdir = { version = "2.5", optional = true }
|
||||
bytesize = { version = "1.3.0" }
|
||||
encoding_rs = "0.8.34"
|
||||
os_str_bytes = { version = "~7.0", optional = true }
|
||||
run_script = { version = "^0.10.1", optional = true}
|
||||
encoding_rs = "0.8.35"
|
||||
execute = { version = "0.2.13", optional = true }
|
||||
terminal-colorsaurus = "0.4"
|
||||
unicode-segmentation = "1.12.0"
|
||||
itertools = "0.13.0"
|
||||
|
||||
[dependencies.git2]
|
||||
version = "0.18"
|
||||
version = "0.20"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
@ -87,30 +89,30 @@ features = ["wrap_help", "cargo"]
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
home = "0.5.9"
|
||||
plist = "1.6.0"
|
||||
plist = "1.7.0"
|
||||
|
||||
[dev-dependencies]
|
||||
assert_cmd = "2.0.12"
|
||||
expect-test = "1.5.0"
|
||||
serial_test = { version = "2.0.0", default-features = false }
|
||||
predicates = "3.1.0"
|
||||
predicates = "3.1.3"
|
||||
wait-timeout = "0.2.0"
|
||||
tempfile = "3.8.1"
|
||||
tempfile = "3.16.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
||||
[target.'cfg(unix)'.dev-dependencies]
|
||||
nix = { version = "0.26.4", default-features = false, features = ["term"] }
|
||||
nix = { version = "0.29", default-features = false, features = ["term"] }
|
||||
|
||||
[build-dependencies]
|
||||
anyhow = "1.0.86"
|
||||
indexmap = { version = "2.3.0", features = ["serde"] }
|
||||
itertools = "0.13.0"
|
||||
once_cell = "1.18"
|
||||
regex = "1.10.2"
|
||||
anyhow = "1.0.97"
|
||||
indexmap = { version = "2.8.0", features = ["serde"] }
|
||||
itertools = "0.14.0"
|
||||
once_cell = "1.20"
|
||||
regex = "1.10.6"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
serde_with = { version = "3.8.1", default-features = false, features = ["macros"] }
|
||||
toml = { version = "0.8.9", features = ["preserve_order"] }
|
||||
serde_with = { version = "3.12.0", default-features = false, features = ["macros"] }
|
||||
toml = { version = "0.8.19", features = ["preserve_order"] }
|
||||
walkdir = "2.5"
|
||||
|
||||
[build-dependencies.clap]
|
||||
|
67
README.md
67
README.md
@ -21,25 +21,14 @@
|
||||
|
||||
### Sponsors
|
||||
|
||||
A special *thank you* goes to our biggest <a href="doc/sponsors.md">sponsors</a>:<br>
|
||||
<a href="https://workos.com/?utm_campaign=github_repo&utm_medium=referral&utm_content=bat&utm_source=github">
|
||||
<img src="doc/sponsors/workos-logo-white-bg.svg" width="200" alt="WorkOS">
|
||||
<br>
|
||||
<strong>Your app, enterprise-ready.</strong>
|
||||
<br>
|
||||
<sub>Start selling to enterprise customers with just a few lines of code.</sub>
|
||||
<br>
|
||||
<sup>Add Single Sign-On (and more) in minutes instead of months.</sup>
|
||||
</a>
|
||||
A special *thank you* goes to our biggest <a href="doc/sponsors.md">sponsor</a>:<br>
|
||||
|
||||
<a href="https://www.warp.dev/?utm_source=github&utm_medium=referral&utm_campaign=bat_20231001">
|
||||
<a href="https://www.warp.dev/bat">
|
||||
<img src="doc/sponsors/warp-logo.png" width="200" alt="Warp">
|
||||
<br>
|
||||
<strong>Warp is a modern, Rust-based terminal with AI built in<br>so you and your team can build great software, faster.</strong>
|
||||
<strong>Warp, the intelligent terminal</strong>
|
||||
<br>
|
||||
<sub>Feel more productive on the command line with parameterized commands,</sub>
|
||||
<br>
|
||||
<sup>autosuggestions, and an IDE-like text editor.</sup>
|
||||
<sub>Available on MacOS, Linux, Windows</sub>
|
||||
</a>
|
||||
|
||||
### Syntax highlighting
|
||||
@ -204,24 +193,30 @@ bat main.cpp | xclip
|
||||
`MANPAGER` environment variable:
|
||||
|
||||
```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
|
||||
```
|
||||
(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).
|
||||
|
||||
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`
|
||||
|
||||
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
|
||||
|
||||
You can use `bat` to colorize help text: `$ cp --help | bat -plhelp`
|
||||
@ -245,6 +240,13 @@ alias -g -- -h='-h 2>&1 | bat --language=help --style=plain'
|
||||
alias -g -- --help='--help 2>&1 | bat --language=help --style=plain'
|
||||
```
|
||||
|
||||
For `fish`, you can use abbreviations:
|
||||
|
||||
```fish
|
||||
abbr -a --position anywhere -- --help '--help | bat -plhelp'
|
||||
abbr -a --position anywhere -- -h '-h | bat -plhelp'
|
||||
```
|
||||
|
||||
This way, you can keep on using `cp --help`, but get colorized help pages.
|
||||
|
||||
Be aware that in some cases, `-h` may not be a shorthand of `--help` (for example with `ls`).
|
||||
@ -455,7 +457,7 @@ binaries are also available: look for archives with `musl` in the file name.
|
||||
|
||||
### 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:
|
||||
|
||||
```bash
|
||||
@ -465,6 +467,12 @@ cargo install --locked bat
|
||||
Note that additional files like the man page or shell completion
|
||||
files can not be installed in this way. They will be generated by `cargo` and should be available in the cargo target folder (under `build`).
|
||||
|
||||
Shell completions are also available by running:
|
||||
```bash
|
||||
bat --completion <shell>
|
||||
# see --help for supported shells
|
||||
```
|
||||
|
||||
## Customization
|
||||
|
||||
### Highlighting theme
|
||||
@ -482,8 +490,10 @@ the following command (you need [`fzf`](https://github.com/junegunn/fzf) for thi
|
||||
bat --list-themes | fzf --preview="bat --theme={} --color=always /path/to/file"
|
||||
```
|
||||
|
||||
`bat` looks good on a dark background by default. However, if your terminal uses a
|
||||
light background, some themes like `GitHub` or `OneHalfLight` will work better for you.
|
||||
`bat` automatically picks a fitting theme depending on your terminal's background color.
|
||||
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.
|
||||
|
||||
You can also use a custom theme by following the
|
||||
['Adding new themes' section below](https://github.com/sharkdp/bat#adding-new-themes).
|
||||
|
||||
@ -681,7 +691,7 @@ theme based on the OS theme. The following snippet uses the `default` theme when
|
||||
and the `GitHub` theme when in the _light mode_.
|
||||
|
||||
```bash
|
||||
alias cat="bat --theme=\$(defaults read -globalDomain AppleInterfaceStyle &> /dev/null && echo default || echo GitHub)"
|
||||
alias cat="bat --theme auto:system --theme-dark default --theme-light GitHub"
|
||||
```
|
||||
|
||||
|
||||
@ -693,10 +703,11 @@ on your operating system. To get the default path for your system, call
|
||||
bat --config-file
|
||||
```
|
||||
|
||||
Alternatively, you can use the `BAT_CONFIG_PATH` environment variable to point `bat` to a
|
||||
non-default location of the configuration file:
|
||||
Alternatively, you can use `BAT_CONFIG_PATH` or `BAT_CONFIG_DIR` environment variables to point `bat`
|
||||
to a non-default location of the configuration file or the configuration directory respectively:
|
||||
```bash
|
||||
export BAT_CONFIG_PATH="/path/to/bat.conf"
|
||||
export BAT_CONFIG_PATH="/path/to/bat/bat.conf"
|
||||
export BAT_CONFIG_DIR="/path/to/bat"
|
||||
```
|
||||
|
||||
A default configuration file can be created with the `--generate-config-file` option.
|
||||
|
BIN
assets/acknowledgements.bin
vendored
BIN
assets/acknowledgements.bin
vendored
Binary file not shown.
2
assets/completions/_bat.ps1.in
vendored
2
assets/completions/_bat.ps1.in
vendored
@ -37,6 +37,8 @@ Register-ArgumentCompleter -Native -CommandName '{{PROJECT_EXECUTABLE}}' -Script
|
||||
[CompletionResult]::new('-m', 'm', [CompletionResultType]::ParameterName, 'Use the specified syntax for files matching the glob pattern (''*.cpp:C++'').')
|
||||
[CompletionResult]::new('--map-syntax', 'map-syntax', [CompletionResultType]::ParameterName, 'Use the specified syntax for files matching the glob pattern (''*.cpp:C++'').')
|
||||
[CompletionResult]::new('--theme', 'theme', [CompletionResultType]::ParameterName, 'Set the color theme for syntax highlighting.')
|
||||
[CompletionResult]::new('--theme-dark', 'theme', [CompletionResultType]::ParameterName, 'Set the color theme for syntax highlighting for dark backgrounds.')
|
||||
[CompletionResult]::new('--theme-light', 'theme', [CompletionResultType]::ParameterName, 'Set the color theme for syntax highlighting for light backgrounds.')
|
||||
[CompletionResult]::new('--style', 'style', [CompletionResultType]::ParameterName, 'Comma-separated list of style elements to display (*default*, auto, full, plain, changes, header, header-filename, header-filesize, grid, rule, numbers, snip).')
|
||||
[CompletionResult]::new('-r', 'r', [CompletionResultType]::ParameterName, 'Only print the lines from N to M.')
|
||||
[CompletionResult]::new('--line-range', 'line-range', [CompletionResultType]::ParameterName, 'Only print the lines from N to M.')
|
||||
|
9
assets/completions/bat.bash.in
vendored
9
assets/completions/bat.bash.in
vendored
@ -113,6 +113,13 @@ _bat() {
|
||||
return 0
|
||||
;;
|
||||
--theme)
|
||||
local IFS=$'\n'
|
||||
COMPREPLY=($(compgen -W "auto${IFS}auto:always${IFS}auto:system${IFS}dark${IFS}light${IFS}$("$1" --list-themes)" -- "$cur"))
|
||||
__bat_escape_completions
|
||||
return 0
|
||||
;;
|
||||
--theme-dark | \
|
||||
--theme-light)
|
||||
local IFS=$'\n'
|
||||
COMPREPLY=($(compgen -W "$("$1" --list-themes)" -- "$cur"))
|
||||
__bat_escape_completions
|
||||
@ -170,6 +177,8 @@ _bat() {
|
||||
--map-syntax
|
||||
--ignored-suffix
|
||||
--theme
|
||||
--theme-dark
|
||||
--theme-light
|
||||
--list-themes
|
||||
--squeeze-blank
|
||||
--squeeze-limit
|
||||
|
14
assets/completions/bat.fish.in
vendored
14
assets/completions/bat.fish.in
vendored
@ -129,6 +129,14 @@ set -l tabs_opts '
|
||||
8\t
|
||||
'
|
||||
|
||||
set -l special_themes '
|
||||
auto\tdefault,\ Choose\ a\ theme\ based\ on\ dark\ or\ light\ mode
|
||||
auto:always\tChoose\ a\ theme\ based\ on\ dark\ or\ light\ mode
|
||||
auto:system\tChoose\ a\ theme\ based\ on\ dark\ or\ light\ mode
|
||||
dark\tUse\ the\ theme\ specified\ by\ --theme-dark
|
||||
light\tUse\ the\ theme\ specified\ by\ --theme-light
|
||||
'
|
||||
|
||||
# Completions:
|
||||
|
||||
complete -c $bat -l acknowledgements -d "Print acknowledgements" -n __fish_is_first_arg
|
||||
@ -203,7 +211,11 @@ complete -c $bat -l tabs -x -a "$tabs_opts" -d "Set tab width" -n __bat_no_excl_
|
||||
|
||||
complete -c $bat -l terminal-width -x -d "Set terminal <width>, +<offset>, or -<offset>" -n __bat_no_excl_args
|
||||
|
||||
complete -c $bat -l theme -x -a "(command $bat --list-themes | command cat)" -d "Set the syntax highlighting theme" -n __bat_no_excl_args
|
||||
complete -c $bat -l theme -x -a "$special_themes(command $bat --list-themes | command cat)" -d "Set the syntax highlighting theme" -n __bat_no_excl_args
|
||||
|
||||
complete -c $bat -l theme-dark -x -a "(command $bat --list-themes | command cat)" -d "Set the syntax highlighting theme for dark backgrounds" -n __bat_no_excl_args
|
||||
|
||||
complete -c $bat -l theme-light -x -a "(command $bat --list-themes | command cat)" -d "Set the syntax highlighting theme for light backgrounds" -n __bat_no_excl_args
|
||||
|
||||
complete -c $bat -s V -l version -f -d "Show version information" -n __fish_is_first_arg
|
||||
|
||||
|
14
assets/completions/bat.zsh.in
vendored
14
assets/completions/bat.zsh.in
vendored
@ -26,7 +26,7 @@ _{{PROJECT_EXECUTABLE}}_main() {
|
||||
args=(
|
||||
'(-A --show-all)'{-A,--show-all}'[show non-printable characters (space, tab, newline, ..)]'
|
||||
--nonprintable-notation='[specify how to display non-printable characters when using --show-all]:notation:(caret unicode)'
|
||||
\*{-p,--plain}'[show plain style (alias for `--style=plain`), repeat twice to disable disable automatic paging (alias for `--paging=never`)]'
|
||||
\*{-p,--plain}'[show plain style (alias for `--style=plain`), repeat twice to disable automatic paging (alias for `--paging=never`)]'
|
||||
'(-l --language)'{-l+,--language=}'[set the language for syntax highlighting]:language:->languages'
|
||||
\*{-H+,--highlight-line=}'[highlight specified block of lines]:start\:end'
|
||||
\*--file-name='[specify the name to display for a file]:name:_files'
|
||||
@ -42,7 +42,9 @@ _{{PROJECT_EXECUTABLE}}_main() {
|
||||
--decorations='[specify when to show the decorations]:when:(auto never always)'
|
||||
--paging='[specify when to use the pager]:when:(auto never always)'
|
||||
'(-m --map-syntax)'{-m+,--map-syntax=}'[map a glob pattern to an existing syntax name]: :->syntax-maps'
|
||||
'(--theme)'--theme='[set the color theme for syntax highlighting]:theme:->themes'
|
||||
'(--theme)'--theme='[set the color theme for syntax highlighting]:theme:->theme_preferences'
|
||||
'(--theme-dark)'--theme-dark='[set the color theme for syntax highlighting for dark backgrounds]:theme:->themes'
|
||||
'(--theme-light)'--theme-light='[set the color theme for syntax highlighting for light backgrounds]:theme:->themes'
|
||||
'(: --list-themes --list-languages -L)'--list-themes'[show all supported highlighting themes]'
|
||||
--style='[comma-separated list of style elements to display]: : _values "style [default]"
|
||||
default auto full plain changes header header-filename header-filesize grid rule numbers snip'
|
||||
@ -82,7 +84,13 @@ _{{PROJECT_EXECUTABLE}}_main() {
|
||||
|
||||
themes)
|
||||
local -a themes expl
|
||||
themes=( ${(f)"$(_call_program themes {{PROJECT_EXECUTABLE}} --list-themes)"} )
|
||||
themes=(${(f)"$(_call_program themes {{PROJECT_EXECUTABLE}} --list-themes)"} )
|
||||
|
||||
_wanted themes expl 'theme' compadd -a themes && ret=0
|
||||
;;
|
||||
theme_preferences)
|
||||
local -a themes expl
|
||||
themes=(auto dark light auto:always auto:system ${(f)"$(_call_program themes {{PROJECT_EXECUTABLE}} --list-themes)"} )
|
||||
|
||||
_wanted themes expl 'theme' compadd -a themes && ret=0
|
||||
;;
|
||||
|
39
assets/manual/bat.1.in
vendored
39
assets/manual/bat.1.in
vendored
@ -152,9 +152,38 @@ will use JSON syntax, and ignore '.dev'
|
||||
.HP
|
||||
\fB\-\-theme\fR <theme>
|
||||
.IP
|
||||
Set the theme for syntax highlighting. Use '\-\-list\-themes' to see all available themes.
|
||||
To set a default theme, add the '\-\-theme="..."' option to the configuration file or
|
||||
export the BAT_THEME environment variable (e.g.: export BAT_THEME="...").
|
||||
Set the theme for syntax highlighting. Use \fB\-\-list\-themes\fP to see all available themes.
|
||||
To set a default theme, add the \fB\-\-theme="..."\fP option to the configuration file or
|
||||
export the \fBBAT_THEME\fP environment variable (e.g.: \fBexport BAT_THEME="..."\fP).
|
||||
|
||||
Special values:
|
||||
.RS
|
||||
.IP "auto (\fIdefault\fR)"
|
||||
Picks a dark or light theme depending on the terminal's colors.
|
||||
Use \fB-\-theme\-light\fR and \fB-\-theme\-dark\fR to customize the selected theme.
|
||||
.IP "auto:always"
|
||||
Variation of \fBauto\fR where where the terminal's colors are detected even when the output is redirected.
|
||||
.IP "auto:system (macOS only)"
|
||||
Variation of \fBauto\fR where the color scheme is detected from the system-wide preference instead.
|
||||
.IP "dark"
|
||||
Use the dark theme specified by \fB-\-theme-dark\fR.
|
||||
.IP "light"
|
||||
Use the light theme specified by \fB-\-theme-light\fR.
|
||||
.RE
|
||||
.HP
|
||||
\fB\-\-theme\-dark\fR <theme>
|
||||
.IP
|
||||
Sets the theme name for syntax highlighting used when the terminal uses a dark background.
|
||||
To set a default theme, add the \fB\-\-theme-dark="..."\fP option to the configuration file or
|
||||
export the \fBBAT_THEME_DARK\fP environment variable (e.g. \fBexport BAT_THEME_DARK="..."\fP).
|
||||
This option only has an effect when \fB\-\-theme\fP option is set to \fBauto\fR or \fBdark\fR.
|
||||
.HP
|
||||
\fB\-\-theme\-light\fR <theme>
|
||||
.IP
|
||||
Sets the theme name for syntax highlighting used when the terminal uses a dark background.
|
||||
To set a default theme, add the \fB\-\-theme-dark="..."\fP option to the configuration file or
|
||||
export the \fBBAT_THEME_LIGHT\fP environment variable (e.g. \fBexport BAT_THEME_LIGHT="..."\fP).
|
||||
This option only has an effect when \fB\-\-theme\fP option is set to \fBauto\fR or \fBlight\fR.
|
||||
.HP
|
||||
\fB\-\-list\-themes\fR
|
||||
.IP
|
||||
@ -307,7 +336,7 @@ To use the preprocessor, call:
|
||||
|
||||
\fB{{PROJECT_EXECUTABLE}} --lessopen\fR
|
||||
|
||||
Alternatively, the preprocessor may be enabled by default by adding the '\-\-lessopen' option to the configuration file.
|
||||
Alternatively, the preprocessor may be enabled by default by adding the '\-\-lessopen' option to the configuration file.
|
||||
|
||||
To temporarily disable the preprocessor if it is enabled by default, call:
|
||||
|
||||
@ -323,7 +352,7 @@ Enable the $LESSOPEN preprocessor.
|
||||
.IP
|
||||
Disable the $LESSOPEN preprocessor if enabled (overrides --lessopen)
|
||||
.PP
|
||||
For more information, see the "INPUT PREPROCESSOR" section of less(1).
|
||||
For more information, see the "INPUT PREPROCESSOR" section of less(1).
|
||||
|
||||
.SH "MORE INFORMATION"
|
||||
|
||||
|
22
assets/patches/1337.tmTheme.patch
vendored
Normal file
22
assets/patches/1337.tmTheme.patch
vendored
Normal 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>
|
26
assets/patches/Markdown.sublime-syntax.patch
vendored
26
assets/patches/Markdown.sublime-syntax.patch
vendored
@ -1,5 +1,5 @@
|
||||
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
|
||||
@@ -24,7 +24,6 @@ variables:
|
||||
@ -166,7 +166,29 @@ index 19dc685d..44440c7f 100644
|
||||
- match: ^\s*$\n?
|
||||
scope: invalid.illegal.non-terminated.bold-italic.markdown
|
||||
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: |-
|
||||
(?x)
|
||||
{{fenced_code_block_start}}
|
||||
|
19
assets/patches/Monokai-Extended.tmTheme.patch
vendored
19
assets/patches/Monokai-Extended.tmTheme.patch
vendored
@ -21,11 +21,26 @@ index 9c2aa3e..180cbbf 100644
|
||||
<string>Invalid</string>
|
||||
<key>scope</key>
|
||||
- <string>invalid</string>
|
||||
+ <string>invalid, markup.error</string>
|
||||
+ <string>invalid, meta.annotation.error-line</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
@@ -1042,7 +1042,7 @@
|
||||
@@ -1038,11 +1038,22 @@
|
||||
<string>#f8f8f0</string>
|
||||
</dict>
|
||||
</dict>
|
||||
+ <dict>
|
||||
+ <key>name</key>
|
||||
+ <string>Error</string>
|
||||
+ <key>scope</key>
|
||||
+ <string>markup.error</string>
|
||||
+ <key>settings</key>
|
||||
+ <dict>
|
||||
+ <key>foreground</key>
|
||||
+ <string>#dd2020</string>
|
||||
+ </dict>
|
||||
+ </dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Invalid deprecated</string>
|
||||
<key>scope</key>
|
||||
|
47
assets/patches/OneHalfDark.tmTheme.patch
vendored
Normal file
47
assets/patches/OneHalfDark.tmTheme.patch
vendored
Normal 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>
|
18
assets/patches/TwoDark.tmTheme.patch
vendored
18
assets/patches/TwoDark.tmTheme.patch
vendored
@ -2,6 +2,24 @@ diff --git themes/TwoDark/TwoDark.tmTheme themes/TwoDark/TwoDark.tmTheme
|
||||
index 87fd358..56376d3 100644
|
||||
--- 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 @@
|
||||
<key>name</key>
|
||||
<string>Json key</string>
|
||||
|
BIN
assets/syntaxes.bin
vendored
BIN
assets/syntaxes.bin
vendored
Binary file not shown.
2
assets/syntaxes/02_Extra/Apache
vendored
2
assets/syntaxes/02_Extra/Apache
vendored
@ -1 +1 @@
|
||||
Subproject commit 163bc03ae8998a237dfb4be353d0aea198ea17f5
|
||||
Subproject commit cf6cefc51ebb46b1b54906433edbae0fe9c71cad
|
@ -2,20 +2,21 @@
|
||||
---
|
||||
# See http://www.sublimetext.com/docs/3/syntax.html
|
||||
name: Comma Separated Values
|
||||
file_extensions:
|
||||
- csv
|
||||
- tsv
|
||||
scope: text.csv
|
||||
scope: text.csv.comma
|
||||
variables:
|
||||
field_separator: (?:[,;\t])
|
||||
field_separator: (?:,)
|
||||
record_separator: (?:$\n?)
|
||||
contexts:
|
||||
prototype:
|
||||
- match: (?={{record_separator}})
|
||||
pop: true
|
||||
main:
|
||||
- match: '^'
|
||||
push: fields
|
||||
|
||||
fields:
|
||||
- include: record_separator
|
||||
- match: ''
|
||||
push:
|
||||
- field_or_record_separator
|
||||
- field5
|
||||
- field_or_record_separator
|
||||
- field4
|
||||
- field_or_record_separator
|
||||
@ -24,16 +25,20 @@ contexts:
|
||||
- field2
|
||||
- field_or_record_separator
|
||||
- field1
|
||||
main:
|
||||
- meta_include_prototype: false
|
||||
- match: '^'
|
||||
set: fields
|
||||
|
||||
field_or_record_separator:
|
||||
record_separator_pop:
|
||||
- match: (?={{record_separator}})
|
||||
pop: true
|
||||
|
||||
record_separator:
|
||||
- meta_include_prototype: false
|
||||
- match: '{{record_separator}}'
|
||||
scope: punctuation.terminator.record.csv
|
||||
pop: true
|
||||
|
||||
field_or_record_separator:
|
||||
- meta_include_prototype: false
|
||||
- include: record_separator_pop
|
||||
- match: '{{field_separator}}'
|
||||
scope: punctuation.separator.sequence.csv
|
||||
pop: true
|
||||
@ -41,24 +46,16 @@ contexts:
|
||||
field_contents:
|
||||
- match: '"'
|
||||
scope: punctuation.definition.string.begin.csv
|
||||
push: double_quoted_string
|
||||
push: scope:text.csv#double_quoted_string
|
||||
|
||||
- match: (?={{field_separator}}|{{record_separator}})
|
||||
pop: true
|
||||
|
||||
double_quoted_string:
|
||||
- meta_include_prototype: false
|
||||
- meta_scope: string.quoted.double.csv
|
||||
- match: '""'
|
||||
scope: constant.character.escape.csv
|
||||
- match: '"'
|
||||
scope: punctuation.definition.string.end.csv
|
||||
- include: record_separator_pop
|
||||
- match: (?={{field_separator}})
|
||||
pop: true
|
||||
|
||||
field1:
|
||||
- match: ''
|
||||
set:
|
||||
- meta_content_scope: meta.field-1.csv support.type
|
||||
- meta_content_scope: meta.field-1.csv variable.parameter
|
||||
- include: field_contents
|
||||
field2:
|
||||
- match: ''
|
||||
@ -75,4 +72,8 @@ contexts:
|
||||
set:
|
||||
- meta_content_scope: meta.field-4.csv keyword.operator
|
||||
- include: field_contents
|
||||
|
||||
field5:
|
||||
- match: ''
|
||||
set:
|
||||
- meta_content_scope: meta.field-5.csv string.unquoted
|
||||
- include: field_contents
|
80
assets/syntaxes/02_Extra/CSV/CSV-pipe.sublime-syntax
vendored
Normal file
80
assets/syntaxes/02_Extra/CSV/CSV-pipe.sublime-syntax
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
%YAML 1.2
|
||||
---
|
||||
# See http://www.sublimetext.com/docs/3/syntax.html
|
||||
name: Pipe Separated Values
|
||||
scope: text.csv.pipe
|
||||
variables:
|
||||
field_separator: (?:\|)
|
||||
record_separator: (?:$\n?)
|
||||
|
||||
contexts:
|
||||
main:
|
||||
- match: '^'
|
||||
push: fields
|
||||
|
||||
fields:
|
||||
- include: record_separator
|
||||
- match: ''
|
||||
push:
|
||||
- field_or_record_separator
|
||||
- field5
|
||||
- field_or_record_separator
|
||||
- field4
|
||||
- field_or_record_separator
|
||||
- field3
|
||||
- field_or_record_separator
|
||||
- field2
|
||||
- field_or_record_separator
|
||||
- field1
|
||||
|
||||
record_separator_pop:
|
||||
- match: (?={{record_separator}})
|
||||
pop: true
|
||||
|
||||
record_separator:
|
||||
- meta_include_prototype: false
|
||||
- match: '{{record_separator}}'
|
||||
scope: punctuation.terminator.record.csv
|
||||
pop: true
|
||||
|
||||
field_or_record_separator:
|
||||
- meta_include_prototype: false
|
||||
- include: record_separator_pop
|
||||
- match: '{{field_separator}}'
|
||||
scope: punctuation.separator.sequence.csv
|
||||
pop: true
|
||||
|
||||
field_contents:
|
||||
- match: '"'
|
||||
scope: punctuation.definition.string.begin.csv
|
||||
push: scope:text.csv#double_quoted_string
|
||||
|
||||
- include: record_separator_pop
|
||||
- match: (?={{field_separator}})
|
||||
pop: true
|
||||
|
||||
field1:
|
||||
- match: ''
|
||||
set:
|
||||
- meta_content_scope: meta.field-1.csv variable.parameter
|
||||
- include: field_contents
|
||||
field2:
|
||||
- match: ''
|
||||
set:
|
||||
- meta_content_scope: meta.field-2.csv support.function
|
||||
- include: field_contents
|
||||
field3:
|
||||
- match: ''
|
||||
set:
|
||||
- meta_content_scope: meta.field-3.csv constant.numeric
|
||||
- include: field_contents
|
||||
field4:
|
||||
- match: ''
|
||||
set:
|
||||
- meta_content_scope: meta.field-4.csv keyword.operator
|
||||
- include: field_contents
|
||||
field5:
|
||||
- match: ''
|
||||
set:
|
||||
- meta_content_scope: meta.field-5.csv string.unquoted
|
||||
- include: field_contents
|
79
assets/syntaxes/02_Extra/CSV/CSV-semi-colon.sublime-syntax
vendored
Normal file
79
assets/syntaxes/02_Extra/CSV/CSV-semi-colon.sublime-syntax
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
%YAML 1.2
|
||||
---
|
||||
# See http://www.sublimetext.com/docs/3/syntax.html
|
||||
name: Semi-Colon Separated Values
|
||||
scope: text.csv.semi-colon
|
||||
variables:
|
||||
field_separator: (?:;)
|
||||
record_separator: (?:$\n?)
|
||||
contexts:
|
||||
main:
|
||||
- match: '^'
|
||||
push: fields
|
||||
|
||||
fields:
|
||||
- include: record_separator
|
||||
- match: ''
|
||||
push:
|
||||
- field_or_record_separator
|
||||
- field5
|
||||
- field_or_record_separator
|
||||
- field4
|
||||
- field_or_record_separator
|
||||
- field3
|
||||
- field_or_record_separator
|
||||
- field2
|
||||
- field_or_record_separator
|
||||
- field1
|
||||
|
||||
record_separator_pop:
|
||||
- match: (?={{record_separator}})
|
||||
pop: true
|
||||
|
||||
record_separator:
|
||||
- meta_include_prototype: false
|
||||
- match: '{{record_separator}}'
|
||||
scope: punctuation.terminator.record.csv
|
||||
pop: true
|
||||
|
||||
field_or_record_separator:
|
||||
- meta_include_prototype: false
|
||||
- include: record_separator_pop
|
||||
- match: '{{field_separator}}'
|
||||
scope: punctuation.separator.sequence.csv
|
||||
pop: true
|
||||
|
||||
field_contents:
|
||||
- match: '"'
|
||||
scope: punctuation.definition.string.begin.csv
|
||||
push: scope:text.csv#double_quoted_string
|
||||
|
||||
- include: record_separator_pop
|
||||
- match: (?={{field_separator}})
|
||||
pop: true
|
||||
|
||||
field1:
|
||||
- match: ''
|
||||
set:
|
||||
- meta_content_scope: meta.field-1.csv variable.parameter
|
||||
- include: field_contents
|
||||
field2:
|
||||
- match: ''
|
||||
set:
|
||||
- meta_content_scope: meta.field-2.csv support.function
|
||||
- include: field_contents
|
||||
field3:
|
||||
- match: ''
|
||||
set:
|
||||
- meta_content_scope: meta.field-3.csv constant.numeric
|
||||
- include: field_contents
|
||||
field4:
|
||||
- match: ''
|
||||
set:
|
||||
- meta_content_scope: meta.field-4.csv keyword.operator
|
||||
- include: field_contents
|
||||
field5:
|
||||
- match: ''
|
||||
set:
|
||||
- meta_content_scope: meta.field-5.csv string.unquoted
|
||||
- include: field_contents
|
113
assets/syntaxes/02_Extra/CSV/CSV.sublime-syntax
vendored
Normal file
113
assets/syntaxes/02_Extra/CSV/CSV.sublime-syntax
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
%YAML 1.2
|
||||
---
|
||||
# See http://www.sublimetext.com/docs/3/syntax.html
|
||||
name: Separated Values
|
||||
file_extensions:
|
||||
- csv
|
||||
scope: text.csv
|
||||
variables:
|
||||
field_separator_chars: ',;\t|'
|
||||
field_separator: (?:[{{field_separator_chars}}])
|
||||
record_separator: (?:$\n?)
|
||||
contexts:
|
||||
main:
|
||||
- meta_include_prototype: false
|
||||
- include: three_field_separators
|
||||
- include: single_separator_type_on_line
|
||||
- match: '^'
|
||||
push: unknown-separated-main
|
||||
|
||||
three_field_separators:
|
||||
- match: ^(?=(?:[^,]*,){3})
|
||||
set: scope:text.csv.comma
|
||||
- match: ^(?=(?:[^;]*;){3})
|
||||
set: scope:text.csv.semi-colon
|
||||
- match: ^(?=(?:[^\t]*\t){3})
|
||||
set: scope:text.csv.tab
|
||||
- match: ^(?=(?:[^|]*\|){3})
|
||||
set: scope:text.csv.pipe
|
||||
|
||||
single_separator_type_on_line:
|
||||
- match: ^(?=[^{{field_separator_chars}}]*,[^;\t|]*$)
|
||||
set: scope:text.csv.comma
|
||||
- match: ^(?=[^{{field_separator_chars}}]*;[^,\t|]*$)
|
||||
set: scope:text.csv.semi-colon
|
||||
- match: ^(?=[^{{field_separator_chars}}]*\t[^,;|]*$)
|
||||
set: scope:text.csv.tab
|
||||
- match: ^(?=[^{{field_separator_chars}}]*\|[^,;\t]*$)
|
||||
set: scope:text.csv.pipe
|
||||
|
||||
unknown-separated-main:
|
||||
- include: record_separator
|
||||
- match: ''
|
||||
push:
|
||||
- field_or_record_separator
|
||||
- field5
|
||||
- field_or_record_separator
|
||||
- field4
|
||||
- field_or_record_separator
|
||||
- field3
|
||||
- field_or_record_separator
|
||||
- field2
|
||||
- field_or_record_separator
|
||||
- field1
|
||||
|
||||
record_separator_pop:
|
||||
- match: (?={{record_separator}})
|
||||
pop: true
|
||||
|
||||
record_separator:
|
||||
- meta_include_prototype: false
|
||||
- match: '{{record_separator}}'
|
||||
scope: punctuation.terminator.record.csv
|
||||
|
||||
field_or_record_separator:
|
||||
- meta_include_prototype: false
|
||||
- include: record_separator_pop
|
||||
- match: '{{field_separator}}'
|
||||
scope: punctuation.separator.sequence.csv
|
||||
pop: true
|
||||
|
||||
field_contents:
|
||||
- match: '"'
|
||||
scope: punctuation.definition.string.begin.csv
|
||||
push: double_quoted_string
|
||||
|
||||
- include: record_separator_pop
|
||||
- match: (?={{field_separator}})
|
||||
pop: true
|
||||
|
||||
double_quoted_string:
|
||||
- meta_include_prototype: false
|
||||
- meta_scope: string.quoted.double.csv
|
||||
- match: '""'
|
||||
scope: constant.character.escape.csv
|
||||
- match: '"'
|
||||
scope: punctuation.definition.string.end.csv
|
||||
pop: true
|
||||
|
||||
field1:
|
||||
- match: ''
|
||||
set:
|
||||
- meta_content_scope: meta.field-1.csv variable.parameter
|
||||
- include: field_contents
|
||||
field2:
|
||||
- match: ''
|
||||
set:
|
||||
- meta_content_scope: meta.field-2.csv support.function
|
||||
- include: field_contents
|
||||
field3:
|
||||
- match: ''
|
||||
set:
|
||||
- meta_content_scope: meta.field-3.csv constant.numeric
|
||||
- include: field_contents
|
||||
field4:
|
||||
- match: ''
|
||||
set:
|
||||
- meta_content_scope: meta.field-4.csv keyword.operator
|
||||
- include: field_contents
|
||||
field5:
|
||||
- match: ''
|
||||
set:
|
||||
- meta_content_scope: meta.field-5.csv string.unquoted
|
||||
- include: field_contents
|
83
assets/syntaxes/02_Extra/CSV/TSV.sublime-syntax
vendored
Normal file
83
assets/syntaxes/02_Extra/CSV/TSV.sublime-syntax
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
%YAML 1.2
|
||||
---
|
||||
# See http://www.sublimetext.com/docs/3/syntax.html
|
||||
name: Tab Separated Values
|
||||
scope: text.csv.tab
|
||||
file_extensions:
|
||||
- tsv
|
||||
|
||||
variables:
|
||||
field_separator: (?:\t)
|
||||
record_separator: (?:$\n?)
|
||||
|
||||
contexts:
|
||||
main:
|
||||
- match: '^'
|
||||
push: fields
|
||||
|
||||
fields:
|
||||
- include: record_separator
|
||||
- match: ''
|
||||
push:
|
||||
- field_or_record_separator
|
||||
- field5
|
||||
- field_or_record_separator
|
||||
- field4
|
||||
- field_or_record_separator
|
||||
- field3
|
||||
- field_or_record_separator
|
||||
- field2
|
||||
- field_or_record_separator
|
||||
- field1
|
||||
|
||||
record_separator_pop:
|
||||
- match: (?={{record_separator}})
|
||||
pop: true
|
||||
|
||||
record_separator:
|
||||
- meta_include_prototype: false
|
||||
- match: '{{record_separator}}'
|
||||
scope: punctuation.terminator.record.csv
|
||||
pop: true
|
||||
|
||||
field_or_record_separator:
|
||||
- meta_include_prototype: false
|
||||
- include: record_separator_pop
|
||||
- match: '{{field_separator}}'
|
||||
scope: punctuation.separator.sequence.csv
|
||||
pop: true
|
||||
|
||||
field_contents:
|
||||
- match: '"'
|
||||
scope: punctuation.definition.string.begin.csv
|
||||
push: scope:text.csv#double_quoted_string
|
||||
|
||||
- include: record_separator_pop
|
||||
- match: (?={{field_separator}})
|
||||
pop: true
|
||||
|
||||
field1:
|
||||
- match: ''
|
||||
set:
|
||||
- meta_content_scope: meta.field-1.csv variable.parameter
|
||||
- include: field_contents
|
||||
field2:
|
||||
- match: ''
|
||||
set:
|
||||
- meta_content_scope: meta.field-2.csv support.function
|
||||
- include: field_contents
|
||||
field3:
|
||||
- match: ''
|
||||
set:
|
||||
- meta_content_scope: meta.field-3.csv constant.numeric
|
||||
- include: field_contents
|
||||
field4:
|
||||
- match: ''
|
||||
set:
|
||||
- meta_content_scope: meta.field-4.csv keyword.operator
|
||||
- include: field_contents
|
||||
field5:
|
||||
- match: ''
|
||||
set:
|
||||
- meta_content_scope: meta.field-5.csv string.unquoted
|
||||
- include: field_contents
|
2
assets/syntaxes/02_Extra/Docker
vendored
2
assets/syntaxes/02_Extra/Docker
vendored
@ -1 +1 @@
|
||||
Subproject commit 0f6b7bc87acf684f7b0790fd480731ffb4615b87
|
||||
Subproject commit c001fb280561d7c16f0f2837d76af493cf6c3bf8
|
1
assets/syntaxes/02_Extra/GDScript-sublime
vendored
Submodule
1
assets/syntaxes/02_Extra/GDScript-sublime
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 96f5dcf29728aa987123321e2544330eed991a3e
|
1
assets/syntaxes/02_Extra/Idris2
vendored
Submodule
1
assets/syntaxes/02_Extra/Idris2
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 7c1bf44c4f9092b7b1e274b1332cf32a089b2b99
|
@ -85,6 +85,9 @@ contexts:
|
||||
|
||||
options:
|
||||
# command-line options like --option=value, --some-flag, or -x
|
||||
- match: '^[ ]{7}(-)(?=\s)'
|
||||
captures:
|
||||
1: entity.name.command-line-option.man
|
||||
- match: '^[ ]{7}(?=-|\+)'
|
||||
push: expect-command-line-option
|
||||
- match: '(?:[^a-zA-Z0-9_-]|^|\s){{command_line_option}}'
|
||||
|
2
assets/syntaxes/02_Extra/Nix
vendored
2
assets/syntaxes/02_Extra/Nix
vendored
@ -1 +1 @@
|
||||
Subproject commit 9032bd613746b9c135223fd6f26a5fa555f18946
|
||||
Subproject commit 48c497c709c66a2fb118c534a8de8e4e1c4c401d
|
1
assets/syntaxes/02_Extra/Org mode
vendored
1
assets/syntaxes/02_Extra/Org mode
vendored
@ -1 +0,0 @@
|
||||
Subproject commit 4976d8f84eeecd94df7da872bf404c125df04c73
|
1
assets/syntaxes/02_Extra/Org_mode
vendored
Submodule
1
assets/syntaxes/02_Extra/Org_mode
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit bb6e5d848151135ab8f87bdcb997437b2308718a
|
2
assets/syntaxes/02_Extra/PowerShell
vendored
2
assets/syntaxes/02_Extra/PowerShell
vendored
@ -1 +1 @@
|
||||
Subproject commit c0372a1d2df136ca6b3d1a9f7b85031dedf117f9
|
||||
Subproject commit a08b55bf1146c210f58e844be53c2aa78fd5e610
|
2
assets/syntaxes/02_Extra/TOML
vendored
2
assets/syntaxes/02_Extra/TOML
vendored
@ -1 +1 @@
|
||||
Subproject commit fd0bf3e5d6c9e6397c0dc9639a0514d9bf55b800
|
||||
Subproject commit f5a57e8bff694a4e6c52a491dae579aabc7427cf
|
2
assets/syntaxes/02_Extra/Zig
vendored
2
assets/syntaxes/02_Extra/Zig
vendored
@ -1 +1 @@
|
||||
Subproject commit 1a4a38445fec495817625bafbeb01e79c44abcba
|
||||
Subproject commit 8a4a3fe4a051f85c4752b82f586d395cab843c06
|
42
assets/syntaxes/02_Extra/apt-source-list.sublime-syntax
vendored
Normal file
42
assets/syntaxes/02_Extra/apt-source-list.sublime-syntax
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
%YAML 1.2
|
||||
---
|
||||
# See http://www.sublimetext.com/docs/syntax.html
|
||||
name: debsources
|
||||
file_extensions:
|
||||
- sources.list
|
||||
scope: text.apt-source-list
|
||||
contexts:
|
||||
main:
|
||||
- include: comments
|
||||
- match: ^[\w-]+
|
||||
scope: constant.language.apt-source-list
|
||||
- match: \w+://\S+
|
||||
scope: markup.underline.link.apt-source-list
|
||||
push: distribution
|
||||
- match: \bmain\b
|
||||
scope: support.class.apt-source-list
|
||||
- match: \buniverse\b
|
||||
scope: support.constant.apt-source-list
|
||||
- match: \brestricted\b
|
||||
scope: storage.modifier.apt-source-list
|
||||
- match: \bmultiverse\b
|
||||
scope: keyword.other.apt-source-list
|
||||
- match: '[\w-]+'
|
||||
scope: constant.other.apt-source-list
|
||||
|
||||
comments:
|
||||
- match: '#'
|
||||
scope: punctuation.definition.comment.apt-source-list
|
||||
push: line_comment
|
||||
|
||||
line_comment:
|
||||
- meta_scope: comment.line.apt-source-list
|
||||
- match: $
|
||||
pop: true
|
||||
|
||||
distribution:
|
||||
- match: \S+
|
||||
scope: support.type.apt-source-list
|
||||
pop: 1
|
||||
- match: $
|
||||
pop: 1
|
2
assets/syntaxes/02_Extra/cmd-help
vendored
2
assets/syntaxes/02_Extra/cmd-help
vendored
@ -1 +1 @@
|
||||
Subproject commit 209559b72f7e8848c988828088231b3a4d8b6838
|
||||
Subproject commit c71ba410bdfcc8f627df3219f14e3f2be4fe68ba
|
24
assets/syntaxes/02_Extra/log.sublime-syntax
vendored
24
assets/syntaxes/02_Extra/log.sublime-syntax
vendored
@ -38,21 +38,21 @@ contexts:
|
||||
scope: markup.underline.link.scheme.log
|
||||
push: url-host
|
||||
log_level_lines:
|
||||
- match: ^(?=.*{{error}})
|
||||
- match: (?=.*{{error}})
|
||||
push:
|
||||
- error_line
|
||||
- error_line_meta
|
||||
- main_pop_at_eol
|
||||
- match: ^(?=.*{{warning}})
|
||||
- match: (?=.*{{warning}})
|
||||
push:
|
||||
- warning_line
|
||||
- warning_line_meta
|
||||
- main_pop_at_eol
|
||||
- match: ^(?=.*{{info}})
|
||||
- match: (?=.*{{info}})
|
||||
push:
|
||||
- info_line
|
||||
- info_line_meta
|
||||
- main_pop_at_eol
|
||||
- match: ^(?=.*{{debug}})
|
||||
- match: (?=.*{{debug}})
|
||||
push:
|
||||
- debug_line
|
||||
- debug_line_meta
|
||||
- main_pop_at_eol
|
||||
log_levels:
|
||||
- match: '{{error}}'
|
||||
@ -63,16 +63,16 @@ contexts:
|
||||
scope: markup.info.log
|
||||
- match: '{{debug}}'
|
||||
scope: markup.info.log
|
||||
error_line:
|
||||
error_line_meta:
|
||||
- meta_scope: meta.annotation.error-line.log
|
||||
- include: immediately_pop
|
||||
warning_line:
|
||||
warning_line_meta:
|
||||
- meta_scope: meta.annotation.warning-line.log
|
||||
- include: immediately_pop
|
||||
info_line:
|
||||
info_line_meta:
|
||||
- meta_scope: meta.annotation.info-line.log
|
||||
- include: immediately_pop
|
||||
debug_line:
|
||||
debug_line_meta:
|
||||
- meta_scope: meta.annotation.debug-line.log
|
||||
- include: immediately_pop
|
||||
immediately_pop:
|
||||
|
1
assets/syntaxes/02_Extra/sublime-odin
vendored
Submodule
1
assets/syntaxes/02_Extra/sublime-odin
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 5d6a0ed41e41ec3709ec74f40686dc3761d6596e
|
6
assets/syntaxes/02_Extra/syntax_test_man.man
vendored
6
assets/syntaxes/02_Extra/syntax_test_man.man
vendored
@ -131,6 +131,12 @@ OPTIONS
|
||||
# ^^ - variable
|
||||
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
|
||||
#include <stdio.h>
|
||||
# ^^^^^^^^ source.c meta.preprocessor.include keyword.control.import.include
|
||||
|
36
assets/syntaxes/02_Extra/syslog.sublime-syntax
vendored
36
assets/syntaxes/02_Extra/syslog.sublime-syntax
vendored
@ -8,10 +8,10 @@ scope: text.log.syslog
|
||||
contexts:
|
||||
main:
|
||||
- match: ^(\w+\s+\d+)\s+(\d{2}:\d{2}:\d{2})
|
||||
scope: meta.datetime.syslog constant.numeric.syslog
|
||||
scope: meta.datetime.syslog
|
||||
captures:
|
||||
1: meta.date.syslog
|
||||
2: meta.time.syslog
|
||||
1: meta.date.syslog constant.numeric.syslog
|
||||
2: meta.time.syslog constant.numeric.syslog
|
||||
push: loghost
|
||||
- match: ^
|
||||
push: text
|
||||
@ -31,22 +31,24 @@ contexts:
|
||||
structured-data:
|
||||
- match: '\['
|
||||
scope: punctuation.section.mapping.begin.syslog
|
||||
push:
|
||||
- match: \]
|
||||
scope: punctuation.section.mapping.end.syslog
|
||||
pop: true
|
||||
- match: \w+
|
||||
scope: variable.parameter.syslog
|
||||
- match: =
|
||||
scope: keyword.operator.assignment.syslog
|
||||
push:
|
||||
- match: '[^\s\]]+'
|
||||
scope: constant.other.syslog
|
||||
pop: true
|
||||
- match: (?=\])
|
||||
pop: true
|
||||
push: structured-data-contents
|
||||
- match: (?=\S)
|
||||
set: text
|
||||
structured-data-contents:
|
||||
- match: \]
|
||||
scope: punctuation.section.mapping.end.syslog
|
||||
pop: true
|
||||
- match: \w+
|
||||
scope: variable.parameter.syslog
|
||||
- match: =
|
||||
scope: keyword.operator.assignment.syslog
|
||||
push: structured-data-assignment
|
||||
structured-data-assignment:
|
||||
- match: '[^\s\]]+'
|
||||
scope: constant.other.syslog
|
||||
pop: true
|
||||
- match: (?=\])
|
||||
pop: true
|
||||
text:
|
||||
- match: $
|
||||
pop: true
|
||||
|
BIN
assets/themes.bin
vendored
BIN
assets/themes.bin
vendored
Binary file not shown.
2
assets/themes/Nord-sublime
vendored
2
assets/themes/Nord-sublime
vendored
@ -1 +1 @@
|
||||
Subproject commit 0d655b23d6b300e691676d9b90a68d92b267f7ec
|
||||
Subproject commit bf92a9e4457dc2f97efebc59bbeac95933ec6515
|
6
assets/themes/ansi.tmTheme
vendored
6
assets/themes/ansi.tmTheme
vendored
@ -69,7 +69,7 @@
|
||||
<key>name</key>
|
||||
<string>Labels</string>
|
||||
<key>scope</key>
|
||||
<string>entity.name.label</string>
|
||||
<string>entity.name.label, variable.parameter</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
@ -80,7 +80,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>
|
||||
@ -234,7 +234,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>
|
||||
|
4
assets/themes/base16-256.tmTheme
vendored
4
assets/themes/base16-256.tmTheme
vendored
@ -257,7 +257,7 @@
|
||||
<key>name</key>
|
||||
<string>Tags</string>
|
||||
<key>scope</key>
|
||||
<string>entity.name.tag</string>
|
||||
<string>entity.name.tag, entity.name</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
@ -312,7 +312,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>
|
||||
|
4
assets/themes/base16.tmTheme
vendored
4
assets/themes/base16.tmTheme
vendored
@ -256,7 +256,7 @@
|
||||
<key>name</key>
|
||||
<string>Tags</string>
|
||||
<key>scope</key>
|
||||
<string>entity.name.tag</string>
|
||||
<string>entity.name.tag, entity.name</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
@ -311,7 +311,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>
|
||||
|
2
assets/themes/sublime-snazzy
vendored
2
assets/themes/sublime-snazzy
vendored
@ -1 +1 @@
|
||||
Subproject commit 70343201f1d7539adbba3c79e2fe81c2559a0431
|
||||
Subproject commit 48f43a735037195021fa69d99c1180bf12f38f78
|
2
assets/themes/zenburn
vendored
2
assets/themes/zenburn
vendored
@ -1 +1 @@
|
||||
Subproject commit 86d4ee7a1f884851a1d21d66249687f527fced32
|
||||
Subproject commit 9c588ebc11c3e6487b081bd54528af08baa8a09a
|
@ -63,5 +63,22 @@ pub fn gen_man_and_comp() -> anyhow::Result<()> {
|
||||
out_dir.join("assets/completions/bat.zsh"),
|
||||
)?;
|
||||
|
||||
println!(
|
||||
"cargo:rustc-env=BAT_GENERATED_COMPLETION_BASH={}",
|
||||
out_dir.join("assets/completions/bat.bash").display()
|
||||
);
|
||||
println!(
|
||||
"cargo:rustc-env=BAT_GENERATED_COMPLETION_FISH={}",
|
||||
out_dir.join("assets/completions/bat.fish").display()
|
||||
);
|
||||
println!(
|
||||
"cargo:rustc-env=BAT_GENERATED_COMPLETION_PS1={}",
|
||||
out_dir.join("assets/completions/_bat.ps1").display()
|
||||
);
|
||||
println!(
|
||||
"cargo:rustc-env=BAT_GENERATED_COMPLETION_ZSH={}",
|
||||
out_dir.join("assets/completions/bat.zsh").display()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -236,8 +236,14 @@ fn get_def_paths() -> anyhow::Result<Vec<PathBuf>> {
|
||||
];
|
||||
|
||||
let mut toml_paths = vec![];
|
||||
for subdir in source_subdirs {
|
||||
let wd = WalkDir::new(Path::new("src/syntax_mapping/builtins").join(subdir));
|
||||
for subdir_name in source_subdirs {
|
||||
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
|
||||
.into_iter()
|
||||
.filter_map_ok(|entry| {
|
||||
|
@ -366,7 +366,7 @@ ansible-galaxy install aeimer.install_bat
|
||||
### From source
|
||||
|
||||
|
||||
`bat` をソースからビルドしたいならば、Rust 1.70.0 以上の環境が必要です。
|
||||
`bat` をソースからビルドしたいならば、Rust 1.74.0 以上の環境が必要です。
|
||||
`cargo` を使用してビルドすることができます:
|
||||
|
||||
```bash
|
||||
|
@ -416,7 +416,7 @@ scoop install bat
|
||||
|
||||
### 소스에서
|
||||
|
||||
`bat`의 소스를 빌드하기 위해서는, Rust 1.70.0 이상이 필요합니다.
|
||||
`bat`의 소스를 빌드하기 위해서는, Rust 1.74.0 이상이 필요합니다.
|
||||
`cargo`를 이용해 전부 빌드할 수 있습니다:
|
||||
|
||||
```bash
|
||||
|
179
doc/README-ru.md
179
doc/README-ru.md
@ -3,11 +3,11 @@
|
||||
<a href="https://github.com/sharkdp/bat/actions?query=workflow%3ACICD"><img src="https://github.com/sharkdp/bat/workflows/CICD/badge.svg" alt="Build Status"></a>
|
||||
<img src="https://img.shields.io/crates/l/bat.svg" alt="license">
|
||||
<a href="https://crates.io/crates/bat"><img src="https://img.shields.io/crates/v/bat.svg?colorB=319e8c" alt="Version info"></a><br>
|
||||
Клон утилиты <i>cat(1)</i> с поддержкой выделения синтаксиса и Git
|
||||
Клон утилиты <i>cat(1)</i> с поддержкой подсветки синтаксиса и Git
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="#выделение-синтаксиса">Ключевые возможности</a> •
|
||||
<a href="#подсветка-синтаксиса">Ключевые возможности</a> •
|
||||
<a href="#как-использовать">Использование</a> •
|
||||
<a href="#установка">Установка</a> •
|
||||
<a href="#кастомизация">Кастомизация</a> •
|
||||
@ -19,11 +19,11 @@
|
||||
[Русский]
|
||||
</p>
|
||||
|
||||
### Выделение синтаксиса
|
||||
### Подсветка синтаксиса
|
||||
|
||||
`bat` поддерживает выделение синтаксиса для огромного количества языков программирования и разметки:
|
||||
`bat` поддерживает подсветку синтаксиса для огромного количества языков программирования и разметки:
|
||||
|
||||

|
||||

|
||||
|
||||
### Интеграция с Git
|
||||
`bat` использует `git`, чтобы показать изменения в коде
|
||||
@ -31,15 +31,17 @@
|
||||
|
||||

|
||||
|
||||
### Показать непечатаемые символы
|
||||
### Показ непечатных символов
|
||||
|
||||
Вы можете использовать `-A` / `--show-all` флаг, чтобы показать символы, которые невозможно напечатать:
|
||||
Вы можете использовать флаг `-A` / `--show-all`, чтобы показать непечатные символы:
|
||||
|
||||

|
||||
|
||||
### Автоматическое разделение текста
|
||||
### Автоматический пейджинг терминала
|
||||
|
||||
`bat` умеет перенаправлять вывод в `less`, если вывод не помещается на экране полностью.
|
||||
`bat` умеет перенаправлять вывод в пейджер терминала (например, в `less`), если вывод не помещается на экране полностью.
|
||||
Если вы хотите, чтобы `bat` работал как `cat` всё время, вы можете установить опцию `--paging=never` в командной строке или в конфигурационном файле.
|
||||
Если вы намерены использовать `bat` в качестве алиаса для `cat`, вы можете установить `alias cat='bat --paging=never'`, чтобы сохранить изначальное поведение.
|
||||
|
||||
### Объединение файлов
|
||||
|
||||
@ -86,11 +88,23 @@ bat header.md content.md footer.md > document.md
|
||||
|
||||
bat -n main.rs # показываем только количество строк
|
||||
|
||||
bat f - g # выводит 'f' в stdin, а потом 'g'.
|
||||
bat f - g # выводит 'f', потом stdin, а потом 'g'.
|
||||
```
|
||||
|
||||
### Интеграция с другими утилитами
|
||||
|
||||
#### `fzf`
|
||||
|
||||
Вы можете использовать `bat` как просмотрщик для [`fzf`](https://github.com/junegunn/fzf).
|
||||
Чтобы это заработало, используйте опцию `--color=always`, чтобы вывод был всегда цветным.
|
||||
Вы можете также использовать опцию `--line-range`, чтобы уменьшить время загрузки для больших файлов:
|
||||
|
||||
```bash
|
||||
fzf --preview "bat --color=always --style=numbers --line-range=:500 {}"
|
||||
```
|
||||
|
||||
Больше деталей смотрите в [`README` программы `fzf`](https://github.com/junegunn/fzf#preview-window).
|
||||
|
||||
#### `find` или `fd`
|
||||
|
||||
Вы можете использовать флаг `-exec` в `find`, чтобы посмотреть превью всех файлов в `bat`
|
||||
@ -121,12 +135,22 @@ tail -f /var/log/pacman.log | bat --paging=never -l log
|
||||
|
||||
#### `git`
|
||||
|
||||
Вы можете использовать `bat` с `git show`, чтобы просмотреть старую версию файла с выделением синтаксиса:
|
||||
Вы можете использовать `bat` с `git show`, чтобы просмотреть старую версию файла с подсветкой синтаксиса:
|
||||
```bash
|
||||
git show v0.6.0:src/main.rs | bat -l rs
|
||||
```
|
||||
|
||||
Обратите внимание, что выделение синтаксиса не работает в `git diff` на данный момент. Если вам это нужно, посмотрите [`delta`](https://github.com/dandavison/delta).
|
||||
#### `git diff`
|
||||
|
||||
Вы можете использовать `bat` с `git diff` для просмотра строк кода вокруг изменений с подсветкой синтаксиса:
|
||||
```bash
|
||||
batdiff() {
|
||||
git diff --name-only --relative --diff-filter=d | xargs bat --diff
|
||||
}
|
||||
```
|
||||
Если вы хотите использовать это как отдельную программу, посмотрите `batdiff` из [`bat-extras`](https://github.com/eth-p/bat-extras).
|
||||
|
||||
Если вам это нужна более полная поддержка для операций с git и diff, посмотрите [`delta`](https://github.com/dandavison/delta).
|
||||
|
||||
#### `xclip`
|
||||
|
||||
@ -135,17 +159,18 @@ git show v0.6.0:src/main.rs | bat -l rs
|
||||
```bash
|
||||
bat main.cpp | xclip
|
||||
```
|
||||
`bat` обнаружит перенаправление вывода и выведет обычный текст без выделения синтаксиса.
|
||||
`bat` обнаружит перенаправление вывода и выведет обычный текст без подсветки синтаксиса.
|
||||
|
||||
#### `man`
|
||||
|
||||
`bat` может быть использован в виде выделения цвета для `man`, для этого установите переменную окружения
|
||||
`bat` может быть использован для раскрашивания вывода `man`, для этого установите переменную окружения
|
||||
`MANPAGER`:
|
||||
|
||||
```bash
|
||||
export MANPAGER="sh -c 'col -bx | bat -l man -p'"
|
||||
man 2 select
|
||||
```
|
||||
(замените `bat` на `batcat`, если у вас Debian или Ubuntu)
|
||||
|
||||
Возможно вам понадобится также установить `MANROFFOPT="-c"`, если у вас есть проблемы с форматированием.
|
||||
|
||||
@ -153,10 +178,40 @@ man 2 select
|
||||
|
||||
Обратите внимание, что [синтаксис manpage](assets/syntaxes/02_Extra/Manpage.sublime-syntax) разрабатывается в этом репозитории и все еще находится в разработке.
|
||||
|
||||
Также заметьте, что это [не заработает](https://github.com/sharkdp/bat/issues/1145) с реализацией `man` через Mandocs.
|
||||
|
||||
#### `prettier` / `shfmt` / `rustfmt`
|
||||
|
||||
[`Prettybat`](https://github.com/eth-p/bat-extras/blob/master/doc/prettybat.md) — скрипт, который форматирует код и выводит его с помощью `bat`.
|
||||
|
||||
#### Подсветка сообщений `--help`
|
||||
|
||||
Вы можете использовать `bat`, чтобы подсвечивать текст справки комманд: `$ cp --help | bat -plhelp`
|
||||
|
||||
Вы можете сделать такую вспомогательную команду для этого:
|
||||
|
||||
```bash
|
||||
# in your .bashrc/.zshrc/*rc
|
||||
alias bathelp='bat --plain --language=help'
|
||||
help() {
|
||||
"$@" --help 2>&1 | bathelp
|
||||
}
|
||||
```
|
||||
|
||||
В этом случае, вы можете просто писать `$ help cp` или `$ help git commit`.
|
||||
|
||||
Если вы используете `zsh`, вы можете объявить глобальные алиасы для `-h` и `--help`:
|
||||
|
||||
```bash
|
||||
alias -g -- -h='-h 2>&1 | bat --language=help --style=plain'
|
||||
alias -g -- --help='--help 2>&1 | bat --language=help --style=plain'
|
||||
```
|
||||
|
||||
В этом случае, вы можете продолжать использовать `cp --help`, но при этом получать подцвеченный вывод.
|
||||
|
||||
Обратите внимание, что не всегда опция `-h` является краткой формы опции `--help` (например, у `ls`).
|
||||
|
||||
Пожалуйста, сообщайте о проблемах с подсветкой справки в [этот репозиторий](https://github.com/victor-gp/cmd-help-sublime-syntax).
|
||||
|
||||
## Установка
|
||||
|
||||
@ -165,8 +220,7 @@ man 2 select
|
||||
### Ubuntu (с помощью `apt`)
|
||||
*... и другие дистрибутивы основанные на Debian.*
|
||||
|
||||
`bat` есть в репозиториях [Ubuntu](https://packages.ubuntu.com/eoan/bat) и
|
||||
[Debian](https://packages.debian.org/sid/bat) и доступен начиная с Ubuntu Eoan 19.10. На Debian `bat` пока что доступен только с нестабильной веткой "Sid".
|
||||
`bat` доступен на [Ubuntu since 20.04 ("Focal")](https://packages.ubuntu.com/search?keywords=bat&exact=1) и [Debian since August 2021 (Debian 11 - "Bullseye")](https://packages.debian.org/bullseye/bat).
|
||||
|
||||
Если ваша версия Ubuntu/Debian достаточно новая, вы можете установить `bat` так:
|
||||
|
||||
@ -245,6 +299,14 @@ cd /usr/ports/textproc/bat
|
||||
make install
|
||||
```
|
||||
|
||||
### On OpenBSD
|
||||
|
||||
Вы можете установить `bat` с помощью [`pkg_add(1)`](https://man.openbsd.org/pkg_add.1):
|
||||
|
||||
```bash
|
||||
pkg_add bat
|
||||
```
|
||||
|
||||
### С помощью nix
|
||||
|
||||
Вы можете установить `bat`, используя [nix package manager](https://nixos.org/nix):
|
||||
@ -253,6 +315,14 @@ make install
|
||||
nix-env -i bat
|
||||
```
|
||||
|
||||
### Через flox
|
||||
|
||||
Вы можете установить `bat` используя [Flox](https://flox.dev)
|
||||
|
||||
```bash
|
||||
flox install bat
|
||||
```
|
||||
|
||||
### openSUSE
|
||||
|
||||
Вы можете установить `bat` с помощью `zypper`:
|
||||
@ -261,7 +331,7 @@ nix-env -i bat
|
||||
zypper install bat
|
||||
```
|
||||
|
||||
### macOS
|
||||
### На macOS (или Linux) через Homebrew
|
||||
|
||||
Вы можете установить `bat` с помощью [Homebrew](http://braumeister.org/formula/bat):
|
||||
|
||||
@ -269,6 +339,8 @@ zypper install bat
|
||||
brew install bat
|
||||
```
|
||||
|
||||
### На macOS через MacPorts
|
||||
|
||||
Или же установить его с помощью [MacPorts](https://ports.macports.org/port/bat/summary):
|
||||
|
||||
```bash
|
||||
@ -277,7 +349,19 @@ port install bat
|
||||
|
||||
### Windows
|
||||
|
||||
Есть несколько способов установить `bat`. Как только вы установили его, посмотрите на секцию ["Использование `bat` в Windows"](#using-bat-on-windows).
|
||||
Есть несколько способов установить `bat`. Как только вы установили его, посмотрите на секцию ["Использование `bat` в Windows"](#использование-bat-в-windows).
|
||||
|
||||
#### Пререквитизы
|
||||
|
||||
Вам нужно установить пакет [Visual C++ Redistributable](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads).
|
||||
|
||||
#### С помощью WinGet
|
||||
|
||||
Вы можете установить `bat` через [WinGet](https://learn.microsoft.com/en-us/windows/package-manager/winget):
|
||||
|
||||
```bash
|
||||
winget install sharkdp.bat
|
||||
```
|
||||
|
||||
#### С помощью Chocolatey
|
||||
|
||||
@ -293,50 +377,10 @@ choco install bat
|
||||
scoop install bat
|
||||
```
|
||||
|
||||
Для этого у вас должен быть установлен [Visual C++ Redistributable](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads).
|
||||
|
||||
#### Из заранее скомпилированных файлов:
|
||||
|
||||
Их вы можете скачать на [странице релизов](https://github.com/sharkdp/bat/releases).
|
||||
|
||||
Для этого у вас должен быть установлен [Visual C++ Redistributable](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads).
|
||||
|
||||
### С помощью Docker
|
||||
|
||||
Вы можете использовать [Docker image](https://hub.docker.com/r/danlynn/bat/), чтобы запустить `bat` в контейнере:
|
||||
```bash
|
||||
docker pull danlynn/bat
|
||||
alias bat='docker run -it --rm -e BAT_THEME -e BAT_STYLE -e BAT_TABS -v "$(pwd):/myapp" danlynn/bat'
|
||||
```
|
||||
|
||||
### С помощью Ansible
|
||||
|
||||
Вы можете установить `bat` с [Ansible](https://www.ansible.com/):
|
||||
|
||||
```bash
|
||||
# Устанавливаем роль на устройстве
|
||||
ansible-galaxy install aeimer.install_bat
|
||||
```
|
||||
|
||||
```yaml
|
||||
---
|
||||
# Playbook для установки bat
|
||||
- host: all
|
||||
roles:
|
||||
- aeimer.install_bat
|
||||
```
|
||||
|
||||
- [Ansible Galaxy](https://galaxy.ansible.com/aeimer/install_bat)
|
||||
- [GitHub](https://github.com/aeimer/ansible-install-bat)
|
||||
|
||||
Этот способ должен сработать со следующими дистрибутивами:
|
||||
- Debian/Ubuntu
|
||||
- ARM (например Raspberry PI)
|
||||
- Arch Linux
|
||||
- Void Linux
|
||||
- FreeBSD
|
||||
- macOS
|
||||
|
||||
### Из скомпилированных файлов
|
||||
|
||||
Перейдите на [страницу релизов](https://github.com/sharkdp/bat/releases) для
|
||||
@ -344,15 +388,24 @@ ansible-galaxy install aeimer.install_bat
|
||||
|
||||
### Из исходников
|
||||
|
||||
Если вы желаете установить `bat` из исходников, вам понадобится Rust 1.70.0 или выше. После этого используйте `cargo`, чтобы все скомпилировать:
|
||||
Если вы желаете установить `bat` из исходников, вам понадобится Rust 1.74.0 или выше. После этого используйте `cargo`, чтобы всё скомпилировать:
|
||||
|
||||
```bash
|
||||
cargo install --locked bat
|
||||
```
|
||||
|
||||
Заметьте, что дополнительные файлы, такие как документация man и подсказки командной строки, не могут быть установлены таким способом.
|
||||
Они будут сгенерированы командой `cargo` должны быть доступны в папке сборки (в `build`).
|
||||
|
||||
Подсказки командной строки также доступны при таком запуске:
|
||||
```bash
|
||||
bat --completion <shell>
|
||||
# see --help for supported shells
|
||||
```
|
||||
|
||||
## Кастомизация
|
||||
|
||||
### Темы для выделения текста
|
||||
### Темы для подсветки синтаксиса
|
||||
|
||||
Используйте `bat --list-themes`, чтобы вывести список всех доступных тем. Для выбора темы `TwoDark` используйте `bat` с флагом
|
||||
`--theme=TwoDark` или выставьте переменную окружения `BAT_THEME` в `TwoDark`. Используйте `export BAT_THEME="TwoDark"` в конфигурационном файле вашей оболочки, чтобы изменить ее навсегда. Или же используйте [конфигурационный файл](https://github.com/sharkdp/bat#configuration-file) `bat`.
|
||||
@ -372,7 +425,7 @@ bat --list-themes | fzf --preview="bat --theme={} --color=always /путь/к/ф
|
||||
|
||||
### Добавление новых синтаксисов
|
||||
|
||||
`bat` использует [`syntect`](https://github.com/trishume/syntect/) для выделения синтаксиса. `syntect` может читать
|
||||
`bat` использует [`syntect`](https://github.com/trishume/syntect/) для подсветки синтаксиса. `syntect` может читать
|
||||
[файл `.sublime-syntax`](https://www.sublimetext.com/docs/3/syntax.html)
|
||||
и темы. Чтобы добавить новый синтаксис, сделайте следующее:
|
||||
|
||||
@ -403,7 +456,7 @@ bat cache --clear
|
||||
|
||||
### Добавление новых тем
|
||||
|
||||
Это работает похожим образом, так же как и добавление новых тем выделения синтаксиса
|
||||
Это работает похожим образом, так же как и добавление новых тем подсветки синтаксиса
|
||||
|
||||
Во-первых, создайте каталог с новыми темами для синтаксиса:
|
||||
```bash
|
||||
@ -590,7 +643,7 @@ cargo install --locked --force
|
||||
Есть очень много альтернатив `bat`. Смотрите [этот документ](doc/alternatives.md) для сравнения.
|
||||
|
||||
## Лицензия
|
||||
Copyright (c) 2018-2021 [Разработчики bat](https://github.com/sharkdp/bat).
|
||||
Copyright (c) 2018-2024 [Разработчики bat](https://github.com/sharkdp/bat).
|
||||
|
||||
`bat` распространяется под лицензиями MIT License и Apache License 2.0 (на выбор пользователя).
|
||||
|
||||
|
@ -372,7 +372,7 @@ scoop install bat
|
||||
|
||||
### 从源码编译
|
||||
|
||||
如果你想要自己构建`bat`,那么你需要安装有高于1.70.0版本的 Rust。
|
||||
如果你想要自己构建`bat`,那么你需要安装有高于1.74.0版本的 Rust。
|
||||
|
||||
使用以下命令编译。
|
||||
|
||||
@ -616,63 +616,59 @@ iconv -f ISO-8859-1 -t UTF-8 my-file.php | bat
|
||||
|
||||
注意: 当`bat`无法识别语言时你可能会需要`-l`/`--language`参数。
|
||||
|
||||
## Development
|
||||
## 开发
|
||||
|
||||
```bash
|
||||
# Recursive clone to retrieve all submodules
|
||||
# 递归 clone 以获取所有子模块
|
||||
git clone --recursive https://github.com/sharkdp/bat
|
||||
|
||||
# Build (debug version)
|
||||
# 构建(调试版本)
|
||||
cd bat
|
||||
cargo build --bins
|
||||
|
||||
# Run unit tests and integration tests
|
||||
# 运行单元测试和集成测试
|
||||
cargo test
|
||||
|
||||
# Install (release version)
|
||||
# 安装(发布版本)
|
||||
cargo install --path . --locked
|
||||
|
||||
# Build a bat binary with modified syntaxes and themes
|
||||
# 使用修改后的语法和主题构建一个 bat 二进制文件
|
||||
bash assets/create.sh
|
||||
cargo install --path . --locked --force
|
||||
```
|
||||
|
||||
If you want to build an application that uses `bat`s pretty-printing
|
||||
features as a library, check out the [the API documentation](https://docs.rs/bat/).
|
||||
Note that you have to use either `regex-onig` or `regex-fancy` as a feature
|
||||
when you depend on `bat` as a library.
|
||||
如果你想构建一个使用 `bat` 美化打印功能的应用程序,请查看 [API 文档](https://docs.rs/bat/)。请注意,当你依赖 `bat` 作为库时,必须使用 `regex-onig` 或 `regex-fancy` 作为特性。
|
||||
|
||||
## Contributing
|
||||
## 贡献指南
|
||||
|
||||
Take a look at the [`CONTRIBUTING.md`](CONTRIBUTING.md) guide.
|
||||
请查看 [`CONTRIBUTING.md`](CONTRIBUTING.md) 指南。
|
||||
|
||||
## Maintainers
|
||||
## 维护者
|
||||
|
||||
- [sharkdp](https://github.com/sharkdp)
|
||||
- [eth-p](https://github.com/eth-p)
|
||||
- [keith-hall](https://github.com/keith-hall)
|
||||
- [Enselic](https://github.com/Enselic)
|
||||
|
||||
## Security vulnerabilities
|
||||
## 安全漏洞
|
||||
|
||||
Please contact [David Peter](https://david-peter.de/) via email if you want to report a vulnerability in `bat`.
|
||||
如果你想报告 `bat` 中的漏洞,请通过邮件联系 [David Peter](https://david-peter.de/)。
|
||||
|
||||
## Project goals and alternatives
|
||||
## 项目目标和替代方案
|
||||
|
||||
`bat` tries to achieve the following goals:
|
||||
`bat` 试图实现以下目标:
|
||||
|
||||
- Provide beautiful, advanced syntax highlighting
|
||||
- Integrate with Git to show file modifications
|
||||
- Be a drop-in replacement for (POSIX) `cat`
|
||||
- Offer a user-friendly command-line interface
|
||||
- 提供美观的高级语法高亮
|
||||
- 与 Git 集成以显示文件修改
|
||||
- 成为 (POSIX) `cat` 的替代品
|
||||
- 提供用户友好的命令行界面
|
||||
|
||||
There are a lot of alternatives, if you are looking for similar programs. See
|
||||
[this document](doc/alternatives.md) for a comparison.
|
||||
如果你在寻找类似的程序,有很多替代方案。请参阅[本文档](doc/alternatives.md)进行比较。
|
||||
|
||||
## License
|
||||
## 许可证
|
||||
|
||||
Copyright (c) 2018-2021 [bat-developers](https://github.com/sharkdp/bat).
|
||||
版权所有 (c) 2018-2021 [bat-developers](https://github.com/sharkdp/bat)。
|
||||
|
||||
`bat` is made available under the terms of either the MIT License or the Apache License 2.0, at your option.
|
||||
`bat` 可根据 MIT 许可证或 Apache 许可证 2.0 的条款使用,任选其一。
|
||||
|
||||
See the [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT) files for license details.
|
||||
有关许可证的详细信息,请参阅 [LICENSE-APACHE](LICENSE-APACHE) 和 [LICENSE-MIT](LICENSE-MIT) 文件。
|
||||
|
@ -26,7 +26,7 @@ in the `.sublime-syntax` format.
|
||||
4. Re-compile `bat`. At compilation time, the `syntaxes.bin` file will be stored inside the
|
||||
`bat` binary.
|
||||
|
||||
5. Use `bat --list-languages` to check if the new languages are available.
|
||||
5. Use `bat --list-languages` to check if the new languages are available. You may want to do something like `export PATH="`pwd`/target/debug:$PATH"` to ensure the locally compiled version is the one being used.
|
||||
|
||||
6. Add a syntax test for the new language. See [below](#Syntax-tests) for details.
|
||||
|
||||
|
@ -20,6 +20,13 @@ Options:
|
||||
* unicode (␇, ␊, ␀, ..)
|
||||
* caret (^G, ^J, ^@, ..)
|
||||
|
||||
--binary <behavior>
|
||||
How to treat binary content. (default: no-printing)
|
||||
|
||||
Possible values:
|
||||
* no-printing: do not print any binary content
|
||||
* as-text: treat binary content as normal text
|
||||
|
||||
-p, --plain...
|
||||
Only show plain style, no decorations. This is an alias for '--style=plain'. When '-p' is
|
||||
used twice ('-pp'), it also disables automatic paging (alias for '--style=plain
|
||||
@ -112,6 +119,27 @@ Options:
|
||||
Set the theme for syntax highlighting. Use '--list-themes' to see all available themes. To
|
||||
set a default theme, add the '--theme="..."' option to the configuration file or export
|
||||
the BAT_THEME environment variable (e.g.: export BAT_THEME="...").
|
||||
|
||||
Special values:
|
||||
|
||||
* auto: Picks a dark or light theme depending on the terminal's colors (default).
|
||||
Use '--theme-light' and '--theme-dark' to customize the selected theme.
|
||||
* auto:always: Detect the terminal's colors even when the output is redirected.
|
||||
* auto:system: Detect the color scheme from the system-wide preference (macOS only).
|
||||
* dark: Use the dark theme specified by '--theme-dark'.
|
||||
* light: Use the light theme specified by '--theme-light'.
|
||||
|
||||
--theme-light <theme>
|
||||
Sets the theme name for syntax highlighting used when the terminal uses a light
|
||||
background. Use '--list-themes' to see all available themes. To set a default theme, add
|
||||
the '--theme-light="..." option to the configuration file or export the BAT_THEME_LIGHT
|
||||
environment variable (e.g. export BAT_THEME_LIGHT="...").
|
||||
|
||||
--theme-dark <theme>
|
||||
Sets the theme name for syntax highlighting used when the terminal uses a dark background.
|
||||
Use '--list-themes' to see all available themes. To set a default theme, add the
|
||||
'--theme-dark="..." option to the configuration file or export the BAT_THEME_DARK
|
||||
environment variable (e.g. export BAT_THEME_DARK="...").
|
||||
|
||||
--list-themes
|
||||
Display a list of supported themes for syntax highlighting.
|
||||
@ -174,6 +202,9 @@ Options:
|
||||
This option exists for POSIX-compliance reasons ('u' is for 'unbuffered'). The output is
|
||||
always unbuffered - this option is simply ignored.
|
||||
|
||||
--completion <SHELL>
|
||||
Show shell completion for a certain shell. [possible values: bash, fish, zsh, ps1]
|
||||
|
||||
--diagnostic
|
||||
Show diagnostic information for bug reports.
|
||||
|
||||
|
@ -11,6 +11,8 @@ Options:
|
||||
Show non-printable characters (space, tab, newline, ..).
|
||||
--nonprintable-notation <notation>
|
||||
Set notation for non-printable characters.
|
||||
--binary <behavior>
|
||||
How to treat binary content. (default: no-printing)
|
||||
-p, --plain...
|
||||
Show plain style (alias for '--style=plain').
|
||||
-l, --language <language>
|
||||
@ -41,6 +43,10 @@ Options:
|
||||
Use the specified syntax for files matching the glob pattern ('*.cpp:C++').
|
||||
--theme <theme>
|
||||
Set the color theme for syntax highlighting.
|
||||
--theme-light <theme>
|
||||
Sets the color theme for syntax highlighting used for light backgrounds.
|
||||
--theme-dark <theme>
|
||||
Sets the color theme for syntax highlighting used for dark backgrounds.
|
||||
--list-themes
|
||||
Display all supported highlighting themes.
|
||||
-s, --squeeze-blank
|
||||
@ -52,6 +58,8 @@ Options:
|
||||
Only print the lines from N to M.
|
||||
-L, --list-languages
|
||||
Display all supported languages.
|
||||
--completion <SHELL>
|
||||
Show shell completion for a certain shell. [possible values: bash, fish, zsh, ps1]
|
||||
-h, --help
|
||||
Print help (see more with '--help')
|
||||
-V, --version
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 130 KiB |
BIN
doc/sponsors/warp-pack-header.png
Normal file
BIN
doc/sponsors/warp-pack-header.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
@ -1,11 +0,0 @@
|
||||
<svg width="1354" height="420" viewBox="0 0 1354 420" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="1354" height="420" rx="20" fill="white"/>
|
||||
<path d="M434.751 133.122H466.637L489.595 227.729C493.852 245.585 494.697 256.219 494.697 256.219H495.128C495.128 256.219 496.61 245.808 500.867 227.729L522.757 133.122H558.9L582.066 227.729C586.53 246.223 587.598 256.219 587.598 256.219H588.236C588.236 256.219 588.666 246.223 592.907 227.729L615.02 133.122H646.907L606.523 288.313H571.017L546.576 194.344C541.474 173.936 541.044 164.801 541.044 164.801H540.614C540.614 164.801 540.183 173.936 535.512 194.344L512.553 288.313H475.996L434.751 133.122Z" fill="black"/>
|
||||
<path d="M641.583 231.934C641.583 196.428 664.541 173.47 699.202 173.47C733.639 173.47 756.597 196.428 756.597 231.934C756.597 267.647 733.639 290.828 699.202 290.828C664.557 290.812 641.583 267.647 641.583 231.934ZM726.832 231.934C726.832 208.976 715.783 195.998 699.202 195.998C681.346 195.998 671.349 210.458 671.349 231.934C671.349 255.323 682.398 268.284 699.202 268.284C717.058 268.284 726.832 253.824 726.832 231.934Z" fill="black"/>
|
||||
<path d="M770.836 175.21H799.103V196.048H799.741C804.635 185.207 816.322 174.365 836.299 174.365C839.695 174.365 841.831 174.796 843.314 175.21V203.478H842.469C842.469 203.478 839.918 202.633 832.903 202.633C811.013 202.633 799.103 215.594 799.103 239.828V288.295H770.836V175.21Z" fill="black"/>
|
||||
<path d="M856.5 133.122H884.767V182.865C884.767 212.2 884.336 217.509 884.336 217.509H884.767L926.857 175.212H962.139L912.843 224.11L970.031 288.313H936.646L895.401 241.536L884.767 251.946V288.297H856.5V133.122Z" fill="black"/>
|
||||
<path d="M970.444 211.285C970.444 163.455 1000.21 131.569 1044.85 131.569C1089.49 131.569 1119.26 163.455 1119.26 211.285C1119.26 259.114 1089.49 291.001 1044.85 291.001C1000.21 291.001 970.444 259.114 970.444 211.285ZM1088.42 211.285C1088.42 178.761 1071 156.855 1044.84 156.855C1018.67 156.855 1001.26 178.761 1001.26 211.285C1001.26 243.809 1018.69 265.715 1044.84 265.715C1070.98 265.715 1088.42 243.809 1088.42 211.285Z" fill="black"/>
|
||||
<path d="M1130.08 236.656H1162.4C1162.4 254.943 1174.95 265.146 1194.08 265.146C1210.23 265.146 1221.29 257.063 1221.29 245.584C1221.29 232.622 1212.79 229.21 1185.79 223.901C1161.12 219.007 1134.98 210.716 1134.98 178.399C1134.98 151.408 1157.93 131 1193.01 131C1229.57 131 1252.11 150.132 1252.11 179.037H1219.79C1219.79 165.007 1208.95 156.286 1193.01 156.286C1176.86 156.286 1166.86 164.146 1166.86 175.625C1166.86 187.742 1173.88 192.413 1195.56 196.878C1227.65 203.685 1254.02 207.288 1254.02 243.001C1254.02 271.3 1229.36 290.432 1193.01 290.432C1156.02 290.432 1130.08 268.957 1130.08 236.656Z" fill="black"/>
|
||||
<path d="M100 210C100 214.824 101.269 219.647 103.723 223.793L148.231 300.878C152.8 308.747 159.739 315.178 168.369 318.055C185.377 323.724 202.977 316.447 211.354 301.893L222.1 283.278L179.708 210L224.47 132.408L235.216 113.792C238.431 108.208 242.747 103.638 247.824 100H243.17H178.777C166.677 100 155.508 106.431 149.5 116.923L103.723 196.208C101.269 200.354 100 205.177 100 210Z" fill="#6363F1"/>
|
||||
<path d="M353.847 210C353.847 205.177 352.578 200.353 350.124 196.207L305.024 118.107C296.647 103.638 279.047 96.3608 262.039 101.945C253.409 104.822 246.47 111.253 241.901 119.122L231.747 136.638L274.139 210L229.378 287.592L218.632 306.208C215.416 311.708 211.101 316.362 206.024 320H210.678H275.07C287.17 320 298.34 313.569 304.347 303.077L350.124 223.792C352.578 219.646 353.847 214.823 353.847 210Z" fill="#6363F1"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 3.4 KiB |
@ -1,4 +1,6 @@
|
||||
use bat::{assets::HighlightingAssets, config::Config, controller::Controller, Input};
|
||||
use bat::{
|
||||
assets::HighlightingAssets, config::Config, controller::Controller, output::OutputHandle, Input,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
let mut buffer = String::new();
|
||||
@ -10,7 +12,10 @@ fn main() {
|
||||
let controller = Controller::new(&config, &assets);
|
||||
let input = Input::from_file(file!());
|
||||
controller
|
||||
.run(vec![input.into()], Some(&mut buffer))
|
||||
.run(
|
||||
vec![input.into()],
|
||||
Some(OutputHandle::FmtWrite(&mut buffer)),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
println!("{buffer}");
|
||||
|
@ -13,6 +13,7 @@ use crate::error::*;
|
||||
use crate::input::{InputReader, OpenedInput};
|
||||
use crate::syntax_mapping::ignored_suffixes::IgnoredSuffixes;
|
||||
use crate::syntax_mapping::MappingTarget;
|
||||
use crate::theme::{default_theme, ColorScheme};
|
||||
use crate::{bat_warning, SyntaxMapping};
|
||||
|
||||
use lazy_theme_set::LazyThemeSet;
|
||||
@ -69,57 +70,6 @@ impl HighlightingAssets {
|
||||
}
|
||||
}
|
||||
|
||||
/// The default theme.
|
||||
///
|
||||
/// ### Windows and Linux
|
||||
///
|
||||
/// Windows and most Linux distributions has a dark terminal theme by
|
||||
/// default. On these platforms, this function always returns a theme that
|
||||
/// looks good on a dark background.
|
||||
///
|
||||
/// ### macOS
|
||||
///
|
||||
/// On macOS the default terminal background is light, but it is common that
|
||||
/// Dark Mode is active, which makes the terminal background dark. On this
|
||||
/// platform, the default theme depends on
|
||||
/// ```bash
|
||||
/// defaults read -globalDomain AppleInterfaceStyle
|
||||
/// ```
|
||||
/// To avoid the overhead of the check on macOS, simply specify a theme
|
||||
/// explicitly via `--theme`, `BAT_THEME`, or `~/.config/bat`.
|
||||
///
|
||||
/// See <https://github.com/sharkdp/bat/issues/1746> and
|
||||
/// <https://github.com/sharkdp/bat/issues/1928> for more context.
|
||||
pub fn default_theme() -> &'static str {
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
Self::default_dark_theme()
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
if macos_dark_mode_active() {
|
||||
Self::default_dark_theme()
|
||||
} else {
|
||||
Self::default_light_theme()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The default theme that looks good on a dark background.
|
||||
*/
|
||||
fn default_dark_theme() -> &'static str {
|
||||
"Monokai Extended"
|
||||
}
|
||||
|
||||
/**
|
||||
* The default theme that looks good on a light background.
|
||||
*/
|
||||
#[cfg(target_os = "macos")]
|
||||
fn default_light_theme() -> &'static str {
|
||||
"Monokai Extended Light"
|
||||
}
|
||||
|
||||
pub fn from_cache(cache_path: &Path) -> Result<Self> {
|
||||
Ok(HighlightingAssets::new(
|
||||
SerializedSyntaxSet::FromFile(cache_path.join("syntaxes.bin")),
|
||||
@ -248,7 +198,10 @@ impl HighlightingAssets {
|
||||
bat_warning!("Unknown theme '{}', using default.", theme)
|
||||
}
|
||||
self.get_theme_set()
|
||||
.get(self.fallback_theme.unwrap_or_else(Self::default_theme))
|
||||
.get(
|
||||
self.fallback_theme
|
||||
.unwrap_or_else(|| default_theme(ColorScheme::Dark)),
|
||||
)
|
||||
.expect("something is very wrong if the default theme is missing")
|
||||
}
|
||||
}
|
||||
@ -399,26 +352,6 @@ fn asset_from_cache<T: serde::de::DeserializeOwned>(
|
||||
.map_err(|_| format!("Could not parse cached {description}").into())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn macos_dark_mode_active() -> bool {
|
||||
const PREFERENCES_FILE: &str = "Library/Preferences/.GlobalPreferences.plist";
|
||||
const STYLE_KEY: &str = "AppleInterfaceStyle";
|
||||
|
||||
let preferences_file = home::home_dir()
|
||||
.map(|home| home.join(PREFERENCES_FILE))
|
||||
.expect("Could not get home directory");
|
||||
|
||||
match plist::Value::from_file(preferences_file).map(|file| file.into_dictionary()) {
|
||||
Ok(Some(preferences)) => match preferences.get(STYLE_KEY).and_then(|val| val.as_string()) {
|
||||
Some(value) => value == "Dark",
|
||||
// If the key does not exist, then light theme is currently in use.
|
||||
None => false,
|
||||
},
|
||||
// Unreachable, in theory. All macOS users have a home directory and preferences file setup.
|
||||
Ok(None) | Err(_) => true,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@ -437,7 +370,7 @@ mod tests {
|
||||
pub temp_dir: TempDir,
|
||||
}
|
||||
|
||||
impl<'a> SyntaxDetectionTest<'a> {
|
||||
impl SyntaxDetectionTest<'_> {
|
||||
fn new() -> Self {
|
||||
SyntaxDetectionTest {
|
||||
assets: HighlightingAssets::from_binary(),
|
||||
|
@ -60,7 +60,7 @@ fn to_path_and_stem(source_dir: &Path, entry: DirEntry) -> Option<PathAndStem> {
|
||||
fn handle_file(path_and_stem: &PathAndStem) -> Result<Option<String>> {
|
||||
if path_and_stem.stem == "NOTICE" {
|
||||
handle_notice(&path_and_stem.path)
|
||||
} else if path_and_stem.stem.to_ascii_uppercase() == "LICENSE" {
|
||||
} else if path_and_stem.stem.eq_ignore_ascii_case("LICENSE") {
|
||||
handle_license(&path_and_stem.path)
|
||||
} else {
|
||||
Ok(None)
|
||||
|
@ -9,6 +9,8 @@ use crate::{
|
||||
config::{get_args_from_config_file, get_args_from_env_opts_var, get_args_from_env_vars},
|
||||
};
|
||||
use bat::style::StyleComponentList;
|
||||
use bat::theme::{theme, ThemeName, ThemeOptions, ThemePreference};
|
||||
use bat::BinaryBehavior;
|
||||
use bat::StripAnsiMode;
|
||||
use clap::ArgMatches;
|
||||
|
||||
@ -16,7 +18,6 @@ use console::Term;
|
||||
|
||||
use crate::input::{new_file_input, new_stdin_input};
|
||||
use bat::{
|
||||
assets::HighlightingAssets,
|
||||
bat_warning,
|
||||
config::{Config, VisibleLines},
|
||||
error::*,
|
||||
@ -97,15 +98,36 @@ impl App {
|
||||
pub fn config(&self, inputs: &[Input]) -> Result<Config> {
|
||||
let style_components = self.style_components()?;
|
||||
|
||||
let extra_plain = self.matches.get_count("plain") > 1;
|
||||
let plain_last_index = self
|
||||
.matches
|
||||
.indices_of("plain")
|
||||
.and_then(Iterator::max)
|
||||
.unwrap_or_default();
|
||||
let paging_last_index = self
|
||||
.matches
|
||||
.indices_of("paging")
|
||||
.and_then(Iterator::max)
|
||||
.unwrap_or_default();
|
||||
|
||||
let paging_mode = match self.matches.get_one::<String>("paging").map(|s| s.as_str()) {
|
||||
Some("always") => PagingMode::Always,
|
||||
Some("always") => {
|
||||
// Disable paging if the second -p (or -pp) is specified after --paging=always
|
||||
if extra_plain && plain_last_index > paging_last_index {
|
||||
PagingMode::Never
|
||||
} else {
|
||||
PagingMode::Always
|
||||
}
|
||||
}
|
||||
Some("never") => PagingMode::Never,
|
||||
Some("auto") | None => {
|
||||
// If we have -pp as an option when in auto mode, the pager should be disabled.
|
||||
let extra_plain = self.matches.get_count("plain") > 1;
|
||||
if extra_plain || self.matches.get_flag("no-paging") {
|
||||
PagingMode::Never
|
||||
} else if inputs.iter().any(Input::is_stdin) {
|
||||
} else if inputs.iter().any(Input::is_stdin)
|
||||
// ignore stdin when --list-themes is used because in that case no input will be read anyways
|
||||
&& !self.matches.get_flag("list-themes")
|
||||
{
|
||||
// If we are reading from stdin, only enable paging if we write to an
|
||||
// interactive terminal and if we do not *read* from an interactive
|
||||
// terminal.
|
||||
@ -193,6 +215,11 @@ impl App {
|
||||
Some("caret") => NonprintableNotation::Caret,
|
||||
_ => unreachable!("other values for --nonprintable-notation are not allowed"),
|
||||
},
|
||||
binary: match self.matches.get_one::<String>("binary").map(|s| s.as_str()) {
|
||||
Some("as-text") => BinaryBehavior::AsText,
|
||||
Some("no-printing") => BinaryBehavior::NoPrinting,
|
||||
_ => unreachable!("other values for --binary are not allowed"),
|
||||
},
|
||||
wrapping_mode: if self.interactive_output || maybe_term_width.is_some() {
|
||||
if !self.matches.get_flag("chop-long-lines") {
|
||||
match self.matches.get_one::<String>("wrap").map(|s| s.as_str()) {
|
||||
@ -254,18 +281,7 @@ impl App {
|
||||
Some("auto") => StripAnsiMode::Auto,
|
||||
_ => unreachable!("other values for --strip-ansi are not allowed"),
|
||||
},
|
||||
theme: self
|
||||
.matches
|
||||
.get_one::<String>("theme")
|
||||
.map(String::from)
|
||||
.map(|s| {
|
||||
if s == "default" {
|
||||
String::from(HighlightingAssets::default_theme())
|
||||
} else {
|
||||
s
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| String::from(HighlightingAssets::default_theme())),
|
||||
theme: theme(self.theme_options()).to_string(),
|
||||
visible_lines: match self.matches.try_contains_id("diff").unwrap_or_default()
|
||||
&& self.matches.get_flag("diff")
|
||||
{
|
||||
@ -412,7 +428,7 @@ impl App {
|
||||
None => StyleComponents(HashSet::from_iter(
|
||||
StyleComponent::Default
|
||||
.components(self.interactive_output)
|
||||
.into_iter()
|
||||
.iter()
|
||||
.cloned(),
|
||||
)),
|
||||
};
|
||||
@ -424,4 +440,25 @@ impl App {
|
||||
|
||||
Ok(styled_components)
|
||||
}
|
||||
|
||||
fn theme_options(&self) -> ThemeOptions {
|
||||
let theme = self
|
||||
.matches
|
||||
.get_one::<String>("theme")
|
||||
.map(|t| ThemePreference::from_str(t).unwrap())
|
||||
.unwrap_or_default();
|
||||
let theme_dark = self
|
||||
.matches
|
||||
.get_one::<String>("theme-dark")
|
||||
.map(|t| ThemeName::from_str(t).unwrap());
|
||||
let theme_light = self
|
||||
.matches
|
||||
.get_one::<String>("theme-light")
|
||||
.map(|t| ThemeName::from_str(t).unwrap());
|
||||
ThemeOptions {
|
||||
theme,
|
||||
theme_dark,
|
||||
theme_light,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -77,11 +77,26 @@ pub fn build_app(interactive_output: bool) -> Command {
|
||||
* caret (^G, ^J, ^@, ..)",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("binary")
|
||||
.long("binary")
|
||||
.action(ArgAction::Set)
|
||||
.default_value("no-printing")
|
||||
.value_parser(["no-printing", "as-text"])
|
||||
.value_name("behavior")
|
||||
.hide_default_value(true)
|
||||
.help("How to treat binary content. (default: no-printing)")
|
||||
.long_help(
|
||||
"How to treat binary content. (default: no-printing)\n\n\
|
||||
Possible values:\n \
|
||||
* no-printing: do not print any binary content\n \
|
||||
* as-text: treat binary content as normal text",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("plain")
|
||||
.overrides_with("plain")
|
||||
.overrides_with("number")
|
||||
.overrides_with("paging")
|
||||
.short('p')
|
||||
.long("plain")
|
||||
.action(ArgAction::Count)
|
||||
@ -306,7 +321,6 @@ pub fn build_app(interactive_output: bool) -> Command {
|
||||
.long("paging")
|
||||
.overrides_with("paging")
|
||||
.overrides_with("no-paging")
|
||||
.overrides_with("plain")
|
||||
.value_name("when")
|
||||
.value_parser(["auto", "never", "always"])
|
||||
.default_value("auto")
|
||||
@ -379,9 +393,40 @@ pub fn build_app(interactive_output: bool) -> Command {
|
||||
see all available themes. To set a default theme, add the \
|
||||
'--theme=\"...\"' option to the configuration file or export the \
|
||||
BAT_THEME environment variable (e.g.: export \
|
||||
BAT_THEME=\"...\").",
|
||||
BAT_THEME=\"...\").\n\n\
|
||||
Special values:\n\n \
|
||||
* auto: Picks a dark or light theme depending on the terminal's colors (default).\n \
|
||||
Use '--theme-light' and '--theme-dark' to customize the selected theme.\n \
|
||||
* auto:always: Detect the terminal's colors even when the output is redirected.\n \
|
||||
* auto:system: Detect the color scheme from the system-wide preference (macOS only).\n \
|
||||
* dark: Use the dark theme specified by '--theme-dark'.\n \
|
||||
* light: Use the light theme specified by '--theme-light'.",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("theme-light")
|
||||
.long("theme-light")
|
||||
.overrides_with("theme-light")
|
||||
.value_name("theme")
|
||||
.help("Sets the color theme for syntax highlighting used for light backgrounds.")
|
||||
.long_help(
|
||||
"Sets the theme name for syntax highlighting used when the terminal uses a light background. \
|
||||
Use '--list-themes' to see all available themes. To set a default theme, add the \
|
||||
'--theme-light=\"...\" option to the configuration file or export the BAT_THEME_LIGHT \
|
||||
environment variable (e.g. export BAT_THEME_LIGHT=\"...\")."),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("theme-dark")
|
||||
.long("theme-dark")
|
||||
.overrides_with("theme-dark")
|
||||
.value_name("theme")
|
||||
.help("Sets the color theme for syntax highlighting used for dark backgrounds.")
|
||||
.long_help(
|
||||
"Sets the theme name for syntax highlighting used when the terminal uses a dark background. \
|
||||
Use '--list-themes' to see all available themes. To set a default theme, add the \
|
||||
'--theme-dark=\"...\" option to the configuration file or export the BAT_THEME_DARK \
|
||||
environment variable (e.g. export BAT_THEME_DARK=\"...\")."),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("list-themes")
|
||||
.long("list-themes")
|
||||
@ -519,6 +564,17 @@ pub fn build_app(interactive_output: bool) -> Command {
|
||||
.help("Do not load custom assets"),
|
||||
);
|
||||
|
||||
#[cfg(feature = "application")]
|
||||
{
|
||||
app = app.arg(
|
||||
Arg::new("completion")
|
||||
.long("completion")
|
||||
.value_name("SHELL")
|
||||
.value_parser(["bash", "fish", "ps1", "zsh"])
|
||||
.help("Show shell completion for a certain shell. [possible values: bash, fish, zsh, ps1]"),
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "lessopen")]
|
||||
{
|
||||
app = app
|
||||
|
6
src/bin/bat/completions.rs
Normal file
6
src/bin/bat/completions.rs
Normal file
@ -0,0 +1,6 @@
|
||||
use std::env;
|
||||
|
||||
pub const BASH_COMPLETION: &str = include_str!(env!("BAT_GENERATED_COMPLETION_BASH"));
|
||||
pub const FISH_COMPLETION: &str = include_str!(env!("BAT_GENERATED_COMPLETION_FISH"));
|
||||
pub const PS1_COMPLETION: &str = include_str!(env!("BAT_GENERATED_COMPLETION_PS1"));
|
||||
pub const ZSH_COMPLETION: &str = include_str!(env!("BAT_GENERATED_COMPLETION_ZSH"));
|
@ -140,7 +140,9 @@ fn get_args_from_str(content: &str) -> Result<Vec<OsString>, shell_words::ParseE
|
||||
pub fn get_args_from_env_vars() -> Vec<OsString> {
|
||||
[
|
||||
("--tabs", "BAT_TABS"),
|
||||
("--theme", "BAT_THEME"),
|
||||
("--theme", bat::theme::env::BAT_THEME),
|
||||
("--theme-dark", bat::theme::env::BAT_THEME_DARK),
|
||||
("--theme-light", bat::theme::env::BAT_THEME_LIGHT),
|
||||
("--pager", "BAT_PAGER"),
|
||||
("--paging", "BAT_PAGING"),
|
||||
("--style", "BAT_STYLE"),
|
||||
|
@ -3,6 +3,8 @@
|
||||
mod app;
|
||||
mod assets;
|
||||
mod clap_app;
|
||||
#[cfg(feature = "application")]
|
||||
mod completions;
|
||||
mod config;
|
||||
mod directories;
|
||||
mod input;
|
||||
@ -14,6 +16,8 @@ use std::io::{BufReader, Write};
|
||||
use std::path::Path;
|
||||
use std::process;
|
||||
|
||||
use bat::output::{OutputHandle, OutputType};
|
||||
use bat::theme::DetectColorScheme;
|
||||
use nu_ansi_term::Color::Green;
|
||||
use nu_ansi_term::Style;
|
||||
|
||||
@ -30,12 +34,12 @@ use directories::PROJECT_DIRS;
|
||||
use globset::GlobMatcher;
|
||||
|
||||
use bat::{
|
||||
assets::HighlightingAssets,
|
||||
config::Config,
|
||||
controller::Controller,
|
||||
error::*,
|
||||
input::Input,
|
||||
style::{StyleComponent, StyleComponents},
|
||||
theme::{color_scheme, default_theme, ColorScheme},
|
||||
MappingTarget, PagingMode,
|
||||
};
|
||||
|
||||
@ -189,7 +193,12 @@ fn theme_preview_file<'a>() -> Input<'a> {
|
||||
Input::from_reader(Box::new(BufReader::new(THEME_PREVIEW_DATA)))
|
||||
}
|
||||
|
||||
pub fn list_themes(cfg: &Config, config_dir: &Path, cache_dir: &Path) -> Result<()> {
|
||||
pub fn list_themes(
|
||||
cfg: &Config,
|
||||
config_dir: &Path,
|
||||
cache_dir: &Path,
|
||||
detect_color_scheme: DetectColorScheme,
|
||||
) -> Result<()> {
|
||||
let assets = assets_from_cache_or_binary(cfg.use_custom_assets, cache_dir)?;
|
||||
let mut config = cfg.clone();
|
||||
let mut style = HashSet::new();
|
||||
@ -197,36 +206,46 @@ pub fn list_themes(cfg: &Config, config_dir: &Path, cache_dir: &Path) -> Result<
|
||||
config.language = Some("Rust");
|
||||
config.style_components = StyleComponents(style);
|
||||
|
||||
let stdout = io::stdout();
|
||||
let mut stdout = stdout.lock();
|
||||
let mut output_type =
|
||||
OutputType::from_mode(config.paging_mode, config.wrapping_mode, config.pager)?;
|
||||
let mut writer = output_type.handle()?;
|
||||
|
||||
let default_theme = HighlightingAssets::default_theme();
|
||||
let default_theme_name = default_theme(color_scheme(detect_color_scheme).unwrap_or_default());
|
||||
for theme in assets.themes() {
|
||||
let default_theme_info = if default_theme == theme {
|
||||
let default_theme_info = if default_theme_name == theme {
|
||||
" (default)"
|
||||
} else if default_theme(ColorScheme::Dark) == theme {
|
||||
" (default dark)"
|
||||
} else if default_theme(ColorScheme::Light) == theme {
|
||||
" (default light)"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
if config.colored_output {
|
||||
writeln!(
|
||||
stdout,
|
||||
writer,
|
||||
"Theme: {}{}\n",
|
||||
Style::new().bold().paint(theme.to_string()),
|
||||
default_theme_info
|
||||
)?;
|
||||
config.theme = theme.to_string();
|
||||
Controller::new(&config, &assets)
|
||||
.run(vec![theme_preview_file()], None)
|
||||
.run(
|
||||
vec![theme_preview_file()],
|
||||
Some(OutputHandle::IoWrite(&mut writer)),
|
||||
)
|
||||
.ok();
|
||||
writeln!(stdout)?;
|
||||
writeln!(writer)?;
|
||||
} else if config.loop_through {
|
||||
writeln!(writer, "{theme}")?;
|
||||
} else {
|
||||
writeln!(stdout, "{theme}{default_theme_info}")?;
|
||||
writeln!(writer, "{theme}{default_theme_info}")?;
|
||||
}
|
||||
}
|
||||
|
||||
if config.colored_output {
|
||||
writeln!(
|
||||
stdout,
|
||||
writer,
|
||||
"Further themes can be installed to '{}', \
|
||||
and are added to the cache with `bat cache --build`. \
|
||||
For more information, see:\n\n \
|
||||
@ -337,6 +356,18 @@ fn run() -> Result<bool> {
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
#[cfg(feature = "application")]
|
||||
if let Some(shell) = app.matches.get_one::<String>("completion") {
|
||||
match shell.as_str() {
|
||||
"bash" => println!("{}", completions::BASH_COMPLETION),
|
||||
"fish" => println!("{}", completions::FISH_COMPLETION),
|
||||
"ps1" => println!("{}", completions::PS1_COMPLETION),
|
||||
"zsh" => println!("{}", completions::ZSH_COMPLETION),
|
||||
_ => unreachable!("No completion for shell '{}' available.", shell),
|
||||
}
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
match app.matches.subcommand() {
|
||||
Some(("cache", cache_matches)) => {
|
||||
// If there is a file named 'cache' in the current working directory,
|
||||
@ -371,7 +402,7 @@ fn run() -> Result<bool> {
|
||||
};
|
||||
run_controller(inputs, &plain_config, cache_dir)
|
||||
} else if app.matches.get_flag("list-themes") {
|
||||
list_themes(&config, config_dir, cache_dir)?;
|
||||
list_themes(&config, config_dir, cache_dir, DetectColorScheme::default())?;
|
||||
Ok(true)
|
||||
} else if app.matches.get_flag("config-file") {
|
||||
println!("{}", config_file().to_string_lossy());
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::line_range::{HighlightedLineRanges, LineRanges};
|
||||
use crate::nonprintable_notation::NonprintableNotation;
|
||||
use crate::nonprintable_notation::{BinaryBehavior, NonprintableNotation};
|
||||
#[cfg(feature = "paging")]
|
||||
use crate::paging::PagingMode;
|
||||
use crate::style::StyleComponents;
|
||||
@ -44,6 +44,9 @@ pub struct Config<'a> {
|
||||
/// The configured notation for non-printable characters
|
||||
pub nonprintable_notation: NonprintableNotation,
|
||||
|
||||
/// How to treat binary content
|
||||
pub binary: BinaryBehavior,
|
||||
|
||||
/// The character width of the terminal
|
||||
pub term_width: usize,
|
||||
|
||||
|
@ -9,10 +9,10 @@ use crate::lessopen::LessOpenPreprocessor;
|
||||
#[cfg(feature = "git")]
|
||||
use crate::line_range::LineRange;
|
||||
use crate::line_range::{LineRanges, MaxBufferedLineNumber, RangeCheckResult};
|
||||
use crate::output::OutputType;
|
||||
use crate::output::{OutputHandle, OutputType};
|
||||
#[cfg(feature = "paging")]
|
||||
use crate::paging::PagingMode;
|
||||
use crate::printer::{InteractivePrinter, OutputHandle, Printer, SimplePrinter};
|
||||
use crate::printer::{InteractivePrinter, Printer, SimplePrinter};
|
||||
use std::collections::VecDeque;
|
||||
use std::io::{self, BufRead, Write};
|
||||
use std::mem;
|
||||
@ -26,7 +26,7 @@ pub struct Controller<'a> {
|
||||
preprocessor: Option<LessOpenPreprocessor>,
|
||||
}
|
||||
|
||||
impl<'b> Controller<'b> {
|
||||
impl Controller<'_> {
|
||||
pub fn new<'a>(config: &'a Config, assets: &'a HighlightingAssets) -> Controller<'a> {
|
||||
Controller {
|
||||
config,
|
||||
@ -36,18 +36,14 @@ impl<'b> Controller<'b> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(
|
||||
&self,
|
||||
inputs: Vec<Input>,
|
||||
output_buffer: Option<&mut dyn std::fmt::Write>,
|
||||
) -> Result<bool> {
|
||||
self.run_with_error_handler(inputs, output_buffer, default_error_handler)
|
||||
pub fn run(&self, inputs: Vec<Input>, output_handle: Option<OutputHandle<'_>>) -> Result<bool> {
|
||||
self.run_with_error_handler(inputs, output_handle, default_error_handler)
|
||||
}
|
||||
|
||||
pub fn run_with_error_handler(
|
||||
&self,
|
||||
inputs: Vec<Input>,
|
||||
output_buffer: Option<&mut dyn std::fmt::Write>,
|
||||
output_handle: Option<OutputHandle<'_>>,
|
||||
mut handle_error: impl FnMut(&Error, &mut dyn Write),
|
||||
) -> Result<bool> {
|
||||
let mut output_type;
|
||||
@ -89,8 +85,9 @@ impl<'b> Controller<'b> {
|
||||
clircle::Identifier::stdout()
|
||||
};
|
||||
|
||||
let mut writer = match output_buffer {
|
||||
Some(buf) => OutputHandle::FmtWrite(buf),
|
||||
let mut writer = match output_handle {
|
||||
Some(OutputHandle::FmtWrite(w)) => OutputHandle::FmtWrite(w),
|
||||
Some(OutputHandle::IoWrite(w)) => OutputHandle::IoWrite(w),
|
||||
None => OutputHandle::IoWrite(output_type.handle()?),
|
||||
};
|
||||
let mut no_errors: bool = true;
|
||||
|
@ -75,7 +75,7 @@ pub(crate) enum InputKind<'a> {
|
||||
CustomReader(Box<dyn Read + 'a>),
|
||||
}
|
||||
|
||||
impl<'a> InputKind<'a> {
|
||||
impl InputKind<'_> {
|
||||
pub fn description(&self) -> InputDescription {
|
||||
match self {
|
||||
InputKind::OrdinaryFile(ref path) => InputDescription::new(path.to_string_lossy()),
|
||||
|
152
src/lessopen.rs
152
src/lessopen.rs
@ -1,15 +1,12 @@
|
||||
#![cfg(feature = "lessopen")]
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::env;
|
||||
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::str;
|
||||
use std::process::{ExitStatus, Stdio};
|
||||
|
||||
use clircle::{Clircle, Identifier};
|
||||
use os_str_bytes::RawOsString;
|
||||
use run_script::{IoOptions, ScriptOptions};
|
||||
use execute::{shell, Execute};
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::{
|
||||
@ -21,7 +18,6 @@ use crate::{
|
||||
pub(crate) struct LessOpenPreprocessor {
|
||||
lessopen: String,
|
||||
lessclose: Option<String>,
|
||||
command_options: ScriptOptions,
|
||||
kind: LessOpenKind,
|
||||
/// Whether or not data piped via stdin is to be preprocessed
|
||||
preprocess_stdin: bool,
|
||||
@ -52,7 +48,7 @@ impl LessOpenPreprocessor {
|
||||
// Otherwise, if output is empty and exit code is nonzero, use original file contents
|
||||
let (kind, lessopen) = if lessopen.starts_with("||") {
|
||||
(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('|') {
|
||||
(
|
||||
LessOpenKind::PipedIgnoreExitCode,
|
||||
@ -70,16 +66,9 @@ impl LessOpenPreprocessor {
|
||||
(false, lessopen)
|
||||
};
|
||||
|
||||
let mut command_options = ScriptOptions::new();
|
||||
command_options.runner = env::var("SHELL").ok();
|
||||
command_options.input_redirection = IoOptions::Pipe;
|
||||
|
||||
Ok(Self {
|
||||
lessopen: lessopen.replacen("%s", "$1", 1),
|
||||
lessclose: env::var("LESSCLOSE")
|
||||
.ok()
|
||||
.map(|str| str.replacen("%s", "$1", 1).replacen("%s", "$2", 1)),
|
||||
command_options,
|
||||
lessopen,
|
||||
lessclose: env::var("LESSCLOSE").ok(),
|
||||
kind,
|
||||
preprocess_stdin: stdin,
|
||||
})
|
||||
@ -98,21 +87,21 @@ impl LessOpenPreprocessor {
|
||||
None => return input.open(stdin, stdout_identifier),
|
||||
};
|
||||
|
||||
let (exit_code, lessopen_stdout, _) = match run_script::run(
|
||||
&self.lessopen,
|
||||
&vec![path_str.to_string()],
|
||||
&self.command_options,
|
||||
) {
|
||||
let mut lessopen_command = shell(self.lessopen.replacen("%s", path_str, 1));
|
||||
lessopen_command.stdout(Stdio::piped());
|
||||
|
||||
let lessopen_output = match lessopen_command.execute_output() {
|
||||
Ok(output) => output,
|
||||
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);
|
||||
}
|
||||
|
||||
(
|
||||
RawOsString::from_string(lessopen_stdout),
|
||||
lessopen_output.stdout,
|
||||
path_str.to_string(),
|
||||
OpenedInputKind::OrdinaryFile(path.to_path_buf()),
|
||||
)
|
||||
@ -127,47 +116,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();
|
||||
stdin.read_to_end(&mut stdin_buffer).unwrap();
|
||||
stdin.read_to_end(&mut stdin_buffer)?;
|
||||
|
||||
let mut lessopen_handle = match run_script::spawn(
|
||||
&self.lessopen,
|
||||
&vec!["-".to_string()],
|
||||
&self.command_options,
|
||||
) {
|
||||
Ok(handle) => handle,
|
||||
Err(_) => {
|
||||
return input.open(stdin, stdout_identifier);
|
||||
}
|
||||
};
|
||||
let mut lessopen_command = shell(self.lessopen.replacen("%s", "-", 1));
|
||||
lessopen_command.stdout(Stdio::piped());
|
||||
|
||||
if lessopen_handle
|
||||
.stdin
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.write_all(&stdin_buffer.clone())
|
||||
.is_err()
|
||||
let lessopen_output = match lessopen_command.execute_input_output(&stdin_buffer)
|
||||
{
|
||||
return input.open(stdin, stdout_identifier);
|
||||
}
|
||||
|
||||
let lessopen_output = match lessopen_handle.wait_with_output() {
|
||||
Ok(output) => output,
|
||||
Err(_) => {
|
||||
return input.open(Cursor::new(stdin_buffer), stdout_identifier);
|
||||
}
|
||||
};
|
||||
|
||||
if lessopen_output.stdout.is_empty()
|
||||
&& (!lessopen_output.status.success()
|
||||
|| matches!(self.kind, LessOpenKind::PipedIgnoreExitCode))
|
||||
if self
|
||||
.fall_back_to_original_file(&lessopen_output.stdout, lessopen_output.status)
|
||||
{
|
||||
return input.open(Cursor::new(stdin_buffer), stdout_identifier);
|
||||
}
|
||||
|
||||
(
|
||||
RawOsString::assert_from_raw_vec(lessopen_output.stdout),
|
||||
lessopen_output.stdout,
|
||||
"-".to_string(),
|
||||
OpenedInputKind::StdIn,
|
||||
)
|
||||
@ -184,13 +157,17 @@ impl LessOpenPreprocessor {
|
||||
kind,
|
||||
reader: InputReader::new(BufReader::new(
|
||||
if matches!(self.kind, LessOpenKind::TempFile) {
|
||||
// Remove newline at end of temporary file path returned by $LESSOPEN
|
||||
let stdout = match lessopen_stdout.strip_suffix("\n") {
|
||||
Some(stripped) => stripped.to_owned(),
|
||||
None => lessopen_stdout,
|
||||
let lessopen_string = match String::from_utf8(lessopen_stdout) {
|
||||
Ok(string) => string,
|
||||
Err(_) => {
|
||||
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)) {
|
||||
Ok(file) => file,
|
||||
@ -201,16 +178,18 @@ impl LessOpenPreprocessor {
|
||||
|
||||
Preprocessed {
|
||||
kind: PreprocessedKind::TempFile(file),
|
||||
lessclose: self.lessclose.clone(),
|
||||
command_args: vec![path_str, stdout.to_str().unwrap().to_string()],
|
||||
command_options: self.command_options.clone(),
|
||||
lessclose: self
|
||||
.lessclose
|
||||
.as_ref()
|
||||
.map(|s| s.replacen("%s", &path_str, 1).replacen("%s", &stdout, 1)),
|
||||
}
|
||||
} else {
|
||||
Preprocessed {
|
||||
kind: PreprocessedKind::Piped(Cursor::new(lessopen_stdout.into_raw_vec())),
|
||||
lessclose: self.lessclose.clone(),
|
||||
command_args: vec![path_str, "-".to_string()],
|
||||
command_options: self.command_options.clone(),
|
||||
kind: PreprocessedKind::Piped(Cursor::new(lessopen_stdout)),
|
||||
lessclose: self
|
||||
.lessclose
|
||||
.as_ref()
|
||||
.map(|s| s.replacen("%s", &path_str, 1).replacen("%s", "-", 1)),
|
||||
}
|
||||
},
|
||||
)),
|
||||
@ -219,9 +198,9 @@ impl LessOpenPreprocessor {
|
||||
})
|
||||
}
|
||||
|
||||
fn fall_back_to_original_file(&self, lessopen_output: &str, exit_code: i32) -> bool {
|
||||
lessopen_output.is_empty()
|
||||
&& (exit_code != 0 || matches!(self.kind, LessOpenKind::PipedIgnoreExitCode))
|
||||
fn fall_back_to_original_file(&self, lessopen_stdout: &[u8], exit_code: ExitStatus) -> bool {
|
||||
lessopen_stdout.is_empty()
|
||||
&& (!exit_code.success() || matches!(self.kind, LessOpenKind::PipedIgnoreExitCode))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -261,8 +240,6 @@ impl Read for PreprocessedKind {
|
||||
pub struct Preprocessed {
|
||||
kind: PreprocessedKind,
|
||||
lessclose: Option<String>,
|
||||
command_args: Vec<String>,
|
||||
command_options: ScriptOptions,
|
||||
}
|
||||
|
||||
impl Read for Preprocessed {
|
||||
@ -273,11 +250,20 @@ impl Read for Preprocessed {
|
||||
|
||||
impl Drop for Preprocessed {
|
||||
fn drop(&mut self) {
|
||||
if let Some(ref command) = self.lessclose {
|
||||
self.command_options.output_redirection = IoOptions::Inherit;
|
||||
if let Some(lessclose) = self.lessclose.clone() {
|
||||
let mut lessclose_command = shell(lessclose);
|
||||
|
||||
run_script::run(command, &self.command_args, &self.command_options)
|
||||
.expect("failed to run $LESSCLOSE to clean up file");
|
||||
let lessclose_output = match lessclose_command.execute_output() {
|
||||
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 +287,7 @@ mod tests {
|
||||
fn test_just_lessopen() -> Result<()> {
|
||||
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());
|
||||
|
||||
reset_env_vars();
|
||||
@ -327,8 +313,8 @@ mod tests {
|
||||
let preprocessor =
|
||||
LessOpenPreprocessor::mock_new(Some("lessopen.sh %s"), Some("lessclose.sh %s %s"))?;
|
||||
|
||||
assert_eq!(preprocessor.lessopen, "lessopen.sh $1");
|
||||
assert_eq!(preprocessor.lessclose.unwrap(), "lessclose.sh $1 $2");
|
||||
assert_eq!(preprocessor.lessopen, "lessopen.sh %s");
|
||||
assert_eq!(preprocessor.lessclose.unwrap(), "lessclose.sh %s %s");
|
||||
|
||||
reset_env_vars();
|
||||
|
||||
@ -340,13 +326,13 @@ mod tests {
|
||||
fn test_lessopen_prefixes() -> Result<()> {
|
||||
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!(!preprocessor.preprocess_stdin);
|
||||
|
||||
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::PipedIgnoreExitCode
|
||||
@ -355,19 +341,19 @@ mod tests {
|
||||
|
||||
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!(!preprocessor.preprocess_stdin);
|
||||
|
||||
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!(preprocessor.preprocess_stdin);
|
||||
|
||||
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::PipedIgnoreExitCode
|
||||
@ -376,7 +362,7 @@ mod tests {
|
||||
|
||||
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!(preprocessor.preprocess_stdin);
|
||||
|
||||
@ -391,8 +377,8 @@ mod tests {
|
||||
let preprocessor =
|
||||
LessOpenPreprocessor::mock_new(Some("|echo File:%s"), Some("echo File:%s Temp:%s"))?;
|
||||
|
||||
assert_eq!(preprocessor.lessopen, "echo File:$1");
|
||||
assert_eq!(preprocessor.lessclose.unwrap(), "echo File:$1 Temp:$2");
|
||||
assert_eq!(preprocessor.lessopen, "echo File:%s");
|
||||
assert_eq!(preprocessor.lessclose.unwrap(), "echo File:%s Temp:%s");
|
||||
|
||||
reset_env_vars();
|
||||
|
||||
|
@ -38,7 +38,7 @@ mod less;
|
||||
mod lessopen;
|
||||
pub mod line_range;
|
||||
pub(crate) mod nonprintable_notation;
|
||||
mod output;
|
||||
pub mod output;
|
||||
#[cfg(feature = "paging")]
|
||||
mod pager;
|
||||
#[cfg(feature = "paging")]
|
||||
@ -49,10 +49,11 @@ pub(crate) mod printer;
|
||||
pub mod style;
|
||||
pub(crate) mod syntax_mapping;
|
||||
mod terminal;
|
||||
pub mod theme;
|
||||
mod vscreen;
|
||||
pub(crate) mod wrapping;
|
||||
|
||||
pub use nonprintable_notation::NonprintableNotation;
|
||||
pub use nonprintable_notation::{BinaryBehavior, NonprintableNotation};
|
||||
pub use preprocessor::StripAnsiMode;
|
||||
pub use pretty_printer::{Input, PrettyPrinter, Syntax};
|
||||
pub use syntax_mapping::{MappingTarget, SyntaxMapping};
|
||||
|
@ -10,3 +10,15 @@ pub enum NonprintableNotation {
|
||||
#[default]
|
||||
Unicode,
|
||||
}
|
||||
|
||||
/// How to treat binary content
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
|
||||
#[non_exhaustive]
|
||||
pub enum BinaryBehavior {
|
||||
/// Do not print any binary content
|
||||
#[default]
|
||||
NoPrinting,
|
||||
|
||||
/// Treat binary content as normal text
|
||||
AsText,
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
use std::fmt;
|
||||
use std::io::{self, Write};
|
||||
#[cfg(feature = "paging")]
|
||||
use std::process::Child;
|
||||
@ -162,3 +163,17 @@ impl Drop for OutputType {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum OutputHandle<'a> {
|
||||
IoWrite(&'a mut dyn io::Write),
|
||||
FmtWrite(&'a mut dyn fmt::Write),
|
||||
}
|
||||
|
||||
impl OutputHandle<'_> {
|
||||
pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<()> {
|
||||
match self {
|
||||
Self::IoWrite(handle) => handle.write_fmt(args).map_err(Into::into),
|
||||
Self::FmtWrite(handle) => handle.write_fmt(args).map_err(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ use crate::{
|
||||
error::Result,
|
||||
input,
|
||||
line_range::{HighlightedLineRanges, LineRange, LineRanges},
|
||||
output::OutputHandle,
|
||||
style::StyleComponent,
|
||||
StripAnsiMode, SyntaxMapping, WrappingMode,
|
||||
};
|
||||
@ -245,7 +246,9 @@ impl<'a> PrettyPrinter<'a> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Specify the highlighting theme
|
||||
/// Specify the highlighting theme.
|
||||
/// You can use [`crate::theme::theme`] to pick a theme based on user preferences
|
||||
/// and the terminal's background color.
|
||||
pub fn theme(&mut self, theme: impl AsRef<str>) -> &mut Self {
|
||||
self.config.theme = theme.as_ref().to_owned();
|
||||
self
|
||||
@ -279,6 +282,11 @@ impl<'a> PrettyPrinter<'a> {
|
||||
/// If you want to call 'print' multiple times, you have to call the appropriate
|
||||
/// input_* methods again.
|
||||
pub fn print(&mut self) -> Result<bool> {
|
||||
self.print_with_writer(None::<&mut dyn std::fmt::Write>)
|
||||
}
|
||||
|
||||
/// Pretty-print all specified inputs to a specified writer.
|
||||
pub fn print_with_writer<W: std::fmt::Write>(&mut self, writer: Option<W>) -> Result<bool> {
|
||||
let highlight_lines = std::mem::take(&mut self.highlighted_lines);
|
||||
self.config.highlighted_lines = HighlightedLineRanges(LineRanges::from(highlight_lines));
|
||||
self.config.term_width = self
|
||||
@ -315,7 +323,16 @@ impl<'a> PrettyPrinter<'a> {
|
||||
|
||||
// Run the controller
|
||||
let controller = Controller::new(&self.config, &self.assets);
|
||||
controller.run(inputs.into_iter().map(|i| i.into()).collect(), None)
|
||||
|
||||
// If writer is provided, pass it to the controller, otherwise pass None
|
||||
if let Some(mut w) = writer {
|
||||
controller.run(
|
||||
inputs.into_iter().map(|i| i.into()).collect(),
|
||||
Some(OutputHandle::FmtWrite(&mut w)),
|
||||
)
|
||||
} else {
|
||||
controller.run(inputs.into_iter().map(|i| i.into()).collect(), None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,3 @@
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::vec::Vec;
|
||||
|
||||
use nu_ansi_term::Color::{Fixed, Green, Red, Yellow};
|
||||
@ -17,6 +15,7 @@ use content_inspector::ContentType;
|
||||
|
||||
use encoding_rs::{UTF_16BE, UTF_16LE};
|
||||
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
use unicode_width::UnicodeWidthChar;
|
||||
|
||||
use crate::assets::{HighlightingAssets, SyntaxReferenceInSet};
|
||||
@ -29,12 +28,14 @@ use crate::diff::LineChanges;
|
||||
use crate::error::*;
|
||||
use crate::input::OpenedInput;
|
||||
use crate::line_range::{MaxBufferedLineNumber, RangeCheckResult};
|
||||
use crate::output::OutputHandle;
|
||||
use crate::preprocessor::strip_ansi;
|
||||
use crate::preprocessor::{expand_tabs, replace_nonprintable};
|
||||
use crate::style::StyleComponent;
|
||||
use crate::terminal::{as_terminal_escaped, to_ansi_color};
|
||||
use crate::vscreen::{AnsiStyle, EscapeSequence, EscapeSequenceIterator};
|
||||
use crate::wrapping::WrappingMode;
|
||||
use crate::BinaryBehavior;
|
||||
use crate::StripAnsiMode;
|
||||
|
||||
const ANSI_UNDERLINE_ENABLE: EscapeSequence = EscapeSequence::CSI {
|
||||
@ -67,20 +68,6 @@ const EMPTY_SYNTECT_STYLE: syntect::highlighting::Style = syntect::highlighting:
|
||||
font_style: FontStyle::empty(),
|
||||
};
|
||||
|
||||
pub enum OutputHandle<'a> {
|
||||
IoWrite(&'a mut dyn io::Write),
|
||||
FmtWrite(&'a mut dyn fmt::Write),
|
||||
}
|
||||
|
||||
impl<'a> OutputHandle<'a> {
|
||||
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<()> {
|
||||
match self {
|
||||
Self::IoWrite(handle) => handle.write_fmt(args).map_err(Into::into),
|
||||
Self::FmtWrite(handle) => handle.write_fmt(args).map_err(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait Printer {
|
||||
fn print_header(
|
||||
&mut self,
|
||||
@ -116,7 +103,7 @@ impl<'a> SimplePrinter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Printer for SimplePrinter<'a> {
|
||||
impl Printer for SimplePrinter<'_> {
|
||||
fn print_header(
|
||||
&mut self,
|
||||
_handle: &mut OutputHandle,
|
||||
@ -145,7 +132,7 @@ impl<'a> Printer for SimplePrinter<'a> {
|
||||
// Skip squeezed lines.
|
||||
if let Some(squeeze_limit) = self.config.squeeze_lines {
|
||||
if String::from_utf8_lossy(line_buffer)
|
||||
.trim_end_matches(|c| c == '\r' || c == '\n')
|
||||
.trim_end_matches(['\r', '\n'])
|
||||
.is_empty()
|
||||
{
|
||||
self.consecutive_empty_lines += 1;
|
||||
@ -268,9 +255,10 @@ impl<'a> InteractivePrinter<'a> {
|
||||
let is_printing_binary = input
|
||||
.reader
|
||||
.content_type
|
||||
.map_or(false, |c| c.is_binary() && !config.show_nonprintable);
|
||||
.is_some_and(|c| c.is_binary() && !config.show_nonprintable);
|
||||
|
||||
let needs_to_match_syntax = !is_printing_binary
|
||||
let needs_to_match_syntax = (!is_printing_binary
|
||||
|| matches!(config.binary, BinaryBehavior::AsText))
|
||||
&& (config.colored_output || config.strip_ansi == StripAnsiMode::Auto);
|
||||
|
||||
let (is_plain_text, highlighter_from_set) = if needs_to_match_syntax {
|
||||
@ -403,14 +391,18 @@ impl<'a> InteractivePrinter<'a> {
|
||||
handle: &mut OutputHandle,
|
||||
content: &str,
|
||||
) -> Result<()> {
|
||||
let mut content = content;
|
||||
let content_width = self.config.term_width - self.get_header_component_indent_length();
|
||||
while content.len() > content_width {
|
||||
let (content_line, remaining) = content.split_at(content_width);
|
||||
self.print_header_component_with_indent(handle, content_line)?;
|
||||
content = remaining;
|
||||
if content.chars().count() <= content_width {
|
||||
return self.print_header_component_with_indent(handle, content);
|
||||
}
|
||||
self.print_header_component_with_indent(handle, content)
|
||||
|
||||
let mut content_graphemes: Vec<&str> = content.graphemes(true).collect();
|
||||
while content_graphemes.len() > content_width {
|
||||
let (content_line, remaining) = content_graphemes.split_at(content_width);
|
||||
self.print_header_component_with_indent(handle, content_line.join("").as_str())?;
|
||||
content_graphemes = remaining.iter().cloned().collect();
|
||||
}
|
||||
self.print_header_component_with_indent(handle, content_graphemes.join("").as_str())
|
||||
}
|
||||
|
||||
fn highlight_regions_for_line<'b>(
|
||||
@ -432,7 +424,7 @@ impl<'a> InteractivePrinter<'a> {
|
||||
.highlight_line(for_highlighting, highlighter_from_set.syntax_set)?;
|
||||
|
||||
if too_long {
|
||||
highlighted_line[0].1 = &line;
|
||||
highlighted_line[0].1 = line;
|
||||
}
|
||||
|
||||
Ok(highlighted_line)
|
||||
@ -448,7 +440,7 @@ impl<'a> InteractivePrinter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Printer for InteractivePrinter<'a> {
|
||||
impl Printer for InteractivePrinter<'_> {
|
||||
fn print_header(
|
||||
&mut self,
|
||||
handle: &mut OutputHandle,
|
||||
@ -460,7 +452,10 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
||||
}
|
||||
|
||||
if !self.config.style_components.header() {
|
||||
if Some(ContentType::BINARY) == self.content_type && !self.config.show_nonprintable {
|
||||
if Some(ContentType::BINARY) == self.content_type
|
||||
&& !self.config.show_nonprintable
|
||||
&& !matches!(self.config.binary, BinaryBehavior::AsText)
|
||||
{
|
||||
writeln!(
|
||||
handle,
|
||||
"{}: Binary content from {} will not be printed to the terminal \
|
||||
@ -541,7 +536,10 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
||||
})?;
|
||||
|
||||
if self.config.style_components.grid() {
|
||||
if self.content_type.map_or(false, |c| c.is_text()) || self.config.show_nonprintable {
|
||||
if self.content_type.is_some_and(|c| c.is_text())
|
||||
|| self.config.show_nonprintable
|
||||
|| matches!(self.config.binary, BinaryBehavior::AsText)
|
||||
{
|
||||
self.print_horizontal_line(handle, '┼')?;
|
||||
} else {
|
||||
self.print_horizontal_line(handle, '┴')?;
|
||||
@ -553,7 +551,9 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
||||
|
||||
fn print_footer(&mut self, handle: &mut OutputHandle, _input: &OpenedInput) -> Result<()> {
|
||||
if self.config.style_components.grid()
|
||||
&& (self.content_type.map_or(false, |c| c.is_text()) || self.config.show_nonprintable)
|
||||
&& (self.content_type.is_some_and(|c| c.is_text())
|
||||
|| self.config.show_nonprintable
|
||||
|| matches!(self.config.binary, BinaryBehavior::AsText))
|
||||
{
|
||||
self.print_horizontal_line(handle, '┴')
|
||||
} else {
|
||||
@ -602,7 +602,9 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
||||
.into()
|
||||
} else {
|
||||
let mut line = match self.content_type {
|
||||
Some(ContentType::BINARY) | None => {
|
||||
Some(ContentType::BINARY) | None
|
||||
if !matches!(self.config.binary, BinaryBehavior::AsText) =>
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
Some(ContentType::UTF_16LE) => UTF_16LE.decode_with_bom_removal(line_buffer).0,
|
||||
@ -635,7 +637,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
||||
|
||||
// Skip squeezed lines.
|
||||
if let Some(squeeze_limit) = self.config.squeeze_lines {
|
||||
if line.trim_end_matches(|c| c == '\r' || c == '\n').is_empty() {
|
||||
if line.trim_end_matches(['\r', '\n']).is_empty() {
|
||||
self.consecutive_empty_lines += 1;
|
||||
if self.consecutive_empty_lines > squeeze_limit {
|
||||
return Ok(());
|
||||
@ -692,7 +694,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
||||
// Regular text.
|
||||
EscapeSequence::Text(text) => {
|
||||
let text = self.preprocess(text, &mut cursor_total);
|
||||
let text_trimmed = text.trim_end_matches(|c| c == '\r' || c == '\n');
|
||||
let text_trimmed = text.trim_end_matches(['\r', '\n']);
|
||||
|
||||
write!(
|
||||
handle,
|
||||
@ -746,10 +748,8 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
||||
match chunk {
|
||||
// Regular text.
|
||||
EscapeSequence::Text(text) => {
|
||||
let text = self.preprocess(
|
||||
text.trim_end_matches(|c| c == '\r' || c == '\n'),
|
||||
&mut cursor_total,
|
||||
);
|
||||
let text = self
|
||||
.preprocess(text.trim_end_matches(['\r', '\n']), &mut cursor_total);
|
||||
|
||||
let mut max_width = cursor_max - cursor;
|
||||
|
||||
|
@ -225,7 +225,7 @@ impl FromStr for StyleComponentList {
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
Ok(StyleComponentList(
|
||||
s.split(",")
|
||||
.map(|s| ComponentAction::extract_from_str(s)) // If the component starts with "-", it's meant to be removed
|
||||
.map(ComponentAction::extract_from_str) // If the component starts with "-", it's meant to be removed
|
||||
.map(|(a, s)| Ok((a, StyleComponent::from_str(s)?)))
|
||||
.collect::<Result<Vec<(ComponentAction, StyleComponent)>>>()?,
|
||||
))
|
||||
|
@ -61,7 +61,7 @@ pub struct SyntaxMapping<'a> {
|
||||
halt_glob_build: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl<'a> Drop for SyntaxMapping<'a> {
|
||||
impl Drop for SyntaxMapping<'_> {
|
||||
fn drop(&mut self) {
|
||||
// signal the offload thread to halt early
|
||||
self.halt_glob_build.store(true, Ordering::Relaxed);
|
||||
@ -153,7 +153,7 @@ impl<'a> SyntaxMapping<'a> {
|
||||
if glob.is_match_candidate(&candidate)
|
||||
|| candidate_filename
|
||||
.as_ref()
|
||||
.map_or(false, |filename| glob.is_match_candidate(filename))
|
||||
.is_some_and(|filename| glob.is_match_candidate(filename))
|
||||
{
|
||||
return Some(*syntax);
|
||||
}
|
||||
|
2
src/syntax_mapping/builtins/common/50-citation.toml
Normal file
2
src/syntax_mapping/builtins/common/50-citation.toml
Normal file
@ -0,0 +1,2 @@
|
||||
[mappings]
|
||||
"YAML" = ["CITATION.cff"]
|
3
src/syntax_mapping/builtins/common/50-diff.toml
Normal file
3
src/syntax_mapping/builtins/common/50-diff.toml
Normal file
@ -0,0 +1,3 @@
|
||||
# .debdiff is the extension used for diffs in Debian packaging
|
||||
[mappings]
|
||||
"Diff" = ["*.debdiff"]
|
2
src/syntax_mapping/builtins/common/50-dotnet-xml.toml
Normal file
2
src/syntax_mapping/builtins/common/50-dotnet-xml.toml
Normal file
@ -0,0 +1,2 @@
|
||||
[mappings]
|
||||
"XML" = ["*.csproj", "*.vbproj", "*.props", "*.targets"]
|
@ -1,3 +1,3 @@
|
||||
# JSON Lines is a simple variation of JSON #2535
|
||||
[mappings]
|
||||
"JSON" = ["*.jsonl", "*.jsonc", "*.jsonld"]
|
||||
"JSON" = ["*.jsonl", "*.jsonc", "*.jsonld", "*.geojson", "*.ndjson"]
|
||||
|
2
src/syntax_mapping/builtins/common/50-markdown.toml
Normal file
2
src/syntax_mapping/builtins/common/50-markdown.toml
Normal file
@ -0,0 +1,2 @@
|
||||
[mappings]
|
||||
"Markdown" = ["*.mkd"]
|
2
src/syntax_mapping/builtins/common/50-nix.toml
Normal file
2
src/syntax_mapping/builtins/common/50-nix.toml
Normal file
@ -0,0 +1,2 @@
|
||||
[mappings]
|
||||
"JSON" = ["flake.lock"]
|
2
src/syntax_mapping/builtins/linux/50-kubernetes.toml
Normal file
2
src/syntax_mapping/builtins/linux/50-kubernetes.toml
Normal file
@ -0,0 +1,2 @@
|
||||
[mappings]
|
||||
"YAML" = ["/etc/kubernetes/*.conf"]
|
@ -1,3 +1,8 @@
|
||||
[mappings]
|
||||
# pacman hooks
|
||||
"INI" = ["/usr/share/libalpm/hooks/*.hook", "/etc/pacman.d/hooks/*.hook"]
|
||||
"INI" = [
|
||||
# config
|
||||
"/etc/pacman.conf",
|
||||
# hooks
|
||||
"/usr/share/libalpm/hooks/*.hook",
|
||||
"/etc/pacman.d/hooks/*.hook",
|
||||
]
|
||||
|
6
src/syntax_mapping/builtins/linux/50-paru.toml
Normal file
6
src/syntax_mapping/builtins/linux/50-paru.toml
Normal file
@ -0,0 +1,6 @@
|
||||
# See https://github.com/Morganamilo/paru/blob/master/man/paru.conf.5
|
||||
[mappings]
|
||||
"INI" = [
|
||||
"${PARU_CONF}",
|
||||
"paru.conf",
|
||||
]
|
@ -1,2 +1,2 @@
|
||||
[mappings]
|
||||
"Apache Conf" = ["/etc/apache2/**/*.conf", "/etc/apache2/sites-*/**/*"]
|
||||
"Apache Conf" = ["/etc/apache2/**/*.conf", "/etc/apache2/sites-*/**/*", "/etc/httpd/conf/**/*.conf"]
|
||||
|
@ -2,4 +2,24 @@
|
||||
"Bourne Again Shell (bash)" = [
|
||||
# used by lots of shells
|
||||
"/etc/profile",
|
||||
|
||||
"bashrc",
|
||||
"*.bashrc",
|
||||
"bash_profile",
|
||||
"*.bash_profile",
|
||||
"bash_login",
|
||||
"*.bash_login",
|
||||
"bash_logout",
|
||||
"*.bash_logout",
|
||||
|
||||
"zshrc",
|
||||
"*.zshrc",
|
||||
"zprofile",
|
||||
"*.zprofile",
|
||||
"zlogin",
|
||||
"*.zlogin",
|
||||
"zlogout",
|
||||
"*.zlogout",
|
||||
"zshenv",
|
||||
"*.zshenv"
|
||||
]
|
||||
|
570
src/theme.rs
Normal file
570
src/theme.rs
Normal file
@ -0,0 +1,570 @@
|
||||
//! Utilities for choosing an appropriate theme for syntax highlighting.
|
||||
|
||||
use std::convert::Infallible;
|
||||
use std::fmt;
|
||||
use std::io::IsTerminal as _;
|
||||
use std::str::FromStr;
|
||||
|
||||
/// Environment variable names.
|
||||
pub mod env {
|
||||
/// See [`crate::theme::ThemeOptions::theme`].
|
||||
pub const BAT_THEME: &str = "BAT_THEME";
|
||||
/// See [`crate::theme::ThemeOptions::theme_dark`].
|
||||
pub const BAT_THEME_DARK: &str = "BAT_THEME_DARK";
|
||||
/// See [`crate::theme::ThemeOptions::theme_light`].
|
||||
pub const BAT_THEME_LIGHT: &str = "BAT_THEME_LIGHT";
|
||||
}
|
||||
|
||||
/// Chooses an appropriate theme or falls back to a default theme
|
||||
/// based on the user-provided options and the color scheme of the terminal.
|
||||
///
|
||||
/// Intentionally returns a [`ThemeResult`] instead of a simple string so
|
||||
/// that downstream consumers such as `delta` can easily apply their own
|
||||
/// default theme and can use the detected color scheme elsewhere.
|
||||
pub fn theme(options: ThemeOptions) -> ThemeResult {
|
||||
theme_impl(options, &TerminalColorSchemeDetector)
|
||||
}
|
||||
|
||||
/// The default theme, suitable for the given color scheme.
|
||||
/// Use [`theme`] if you want to automatically detect the color scheme from the terminal.
|
||||
pub const fn default_theme(color_scheme: ColorScheme) -> &'static str {
|
||||
match color_scheme {
|
||||
ColorScheme::Dark => "Monokai Extended",
|
||||
ColorScheme::Light => "Monokai Extended Light",
|
||||
}
|
||||
}
|
||||
|
||||
/// Detects the color scheme from the terminal.
|
||||
pub fn color_scheme(when: DetectColorScheme) -> Option<ColorScheme> {
|
||||
color_scheme_impl(when, &TerminalColorSchemeDetector)
|
||||
}
|
||||
|
||||
/// Options for configuring the theme used for syntax highlighting.
|
||||
/// Used together with [`theme`].
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq)]
|
||||
pub struct ThemeOptions {
|
||||
/// Configures how the theme is chosen. If set to a [`ThemePreference::Fixed`] value,
|
||||
/// then the given theme is used regardless of the terminal's background color.
|
||||
/// This corresponds with the `BAT_THEME` environment variable and the `--theme` option.
|
||||
pub theme: ThemePreference,
|
||||
/// The theme to use in case the terminal uses a dark background with light text.
|
||||
/// This corresponds with the `BAT_THEME_DARK` environment variable and the `--theme-dark` option.
|
||||
pub theme_dark: Option<ThemeName>,
|
||||
/// The theme to use in case the terminal uses a light background with dark text.
|
||||
/// This corresponds with the `BAT_THEME_LIGHT` environment variable and the `--theme-light` option.
|
||||
pub theme_light: Option<ThemeName>,
|
||||
}
|
||||
|
||||
/// What theme should `bat` use?
|
||||
///
|
||||
/// The easiest way to construct this is from a string:
|
||||
/// ```
|
||||
/// # use bat::theme::{ThemePreference, DetectColorScheme};
|
||||
/// let preference = ThemePreference::new("auto:system");
|
||||
/// assert_eq!(ThemePreference::Auto(DetectColorScheme::System), preference);
|
||||
/// ```
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum ThemePreference {
|
||||
/// Choose between [`ThemeOptions::theme_dark`] and [`ThemeOptions::theme_light`]
|
||||
/// based on the terminal's color scheme.
|
||||
Auto(DetectColorScheme),
|
||||
/// Always use the same theme regardless of the terminal's color scheme.
|
||||
Fixed(ThemeName),
|
||||
/// Use a dark theme.
|
||||
Dark,
|
||||
/// Use a light theme.
|
||||
Light,
|
||||
}
|
||||
|
||||
impl Default for ThemePreference {
|
||||
fn default() -> Self {
|
||||
ThemePreference::Auto(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl ThemePreference {
|
||||
/// Creates a theme preference from a string.
|
||||
pub fn new(s: impl Into<String>) -> Self {
|
||||
use ThemePreference::*;
|
||||
let s = s.into();
|
||||
match s.as_str() {
|
||||
"auto" => Auto(Default::default()),
|
||||
"auto:always" => Auto(DetectColorScheme::Always),
|
||||
"auto:system" => Auto(DetectColorScheme::System),
|
||||
"dark" => Dark,
|
||||
"light" => Light,
|
||||
_ => Fixed(ThemeName::new(s)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for ThemePreference {
|
||||
type Err = Infallible;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(ThemePreference::new(s))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ThemePreference {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use ThemePreference::*;
|
||||
match self {
|
||||
Auto(DetectColorScheme::Auto) => f.write_str("auto"),
|
||||
Auto(DetectColorScheme::Always) => f.write_str("auto:always"),
|
||||
Auto(DetectColorScheme::System) => f.write_str("auto:system"),
|
||||
Fixed(theme) => theme.fmt(f),
|
||||
Dark => f.write_str("dark"),
|
||||
Light => f.write_str("light"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The name of a theme or the default theme.
|
||||
///
|
||||
/// ```
|
||||
/// # use bat::theme::ThemeName;
|
||||
/// assert_eq!(ThemeName::Default, ThemeName::new("default"));
|
||||
/// assert_eq!(ThemeName::Named("example".to_string()), ThemeName::new("example"));
|
||||
/// ```
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum ThemeName {
|
||||
Named(String),
|
||||
Default,
|
||||
}
|
||||
|
||||
impl ThemeName {
|
||||
/// Creates a theme name from a string.
|
||||
pub fn new(s: impl Into<String>) -> Self {
|
||||
let s = s.into();
|
||||
if s == "default" {
|
||||
ThemeName::Default
|
||||
} else {
|
||||
ThemeName::Named(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for ThemeName {
|
||||
type Err = Infallible;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(ThemeName::new(s))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ThemeName {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
ThemeName::Named(t) => f.write_str(t),
|
||||
ThemeName::Default => f.write_str("default"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum DetectColorScheme {
|
||||
/// Only query the terminal for its colors when appropriate (i.e. when the output is not redirected).
|
||||
#[default]
|
||||
Auto,
|
||||
/// Always query the terminal for its colors.
|
||||
Always,
|
||||
/// Detect the system-wide dark/light preference (macOS only).
|
||||
System,
|
||||
}
|
||||
|
||||
/// The color scheme used to pick a fitting theme. Defaults to [`ColorScheme::Dark`].
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum ColorScheme {
|
||||
#[default]
|
||||
Dark,
|
||||
Light,
|
||||
}
|
||||
|
||||
/// The resolved theme and the color scheme as determined from
|
||||
/// the terminal, OS or fallback.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ThemeResult {
|
||||
/// The theme selected according to the [`ThemeOptions`].
|
||||
pub theme: ThemeName,
|
||||
/// Either the user's chosen color scheme, the terminal's color scheme, the OS's
|
||||
/// color scheme or `None` if the color scheme was not detected because the user chose a fixed theme.
|
||||
pub color_scheme: Option<ColorScheme>,
|
||||
}
|
||||
|
||||
impl fmt::Display for ThemeResult {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match &self.theme {
|
||||
ThemeName::Named(name) => f.write_str(name),
|
||||
ThemeName::Default => f.write_str(default_theme(self.color_scheme.unwrap_or_default())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn theme_impl(options: ThemeOptions, detector: &dyn ColorSchemeDetector) -> ThemeResult {
|
||||
// Implementation note: This function is mostly pure (i.e. it has no side effects) for the sake of testing.
|
||||
// All the side effects (e.g. querying the terminal for its colors) are performed in the detector.
|
||||
match options.theme {
|
||||
ThemePreference::Fixed(theme) => ThemeResult {
|
||||
theme,
|
||||
color_scheme: None,
|
||||
},
|
||||
ThemePreference::Dark => choose_theme_opt(Some(ColorScheme::Dark), options),
|
||||
ThemePreference::Light => choose_theme_opt(Some(ColorScheme::Light), options),
|
||||
ThemePreference::Auto(when) => choose_theme_opt(color_scheme_impl(when, detector), options),
|
||||
}
|
||||
}
|
||||
|
||||
fn choose_theme_opt(color_scheme: Option<ColorScheme>, options: ThemeOptions) -> ThemeResult {
|
||||
ThemeResult {
|
||||
color_scheme,
|
||||
theme: color_scheme
|
||||
.and_then(|c| choose_theme(options, c))
|
||||
.unwrap_or(ThemeName::Default),
|
||||
}
|
||||
}
|
||||
|
||||
fn choose_theme(options: ThemeOptions, color_scheme: ColorScheme) -> Option<ThemeName> {
|
||||
match color_scheme {
|
||||
ColorScheme::Dark => options.theme_dark,
|
||||
ColorScheme::Light => options.theme_light,
|
||||
}
|
||||
}
|
||||
|
||||
fn color_scheme_impl(
|
||||
when: DetectColorScheme,
|
||||
detector: &dyn ColorSchemeDetector,
|
||||
) -> Option<ColorScheme> {
|
||||
let should_detect = match when {
|
||||
DetectColorScheme::Auto => detector.should_detect(),
|
||||
DetectColorScheme::Always => true,
|
||||
DetectColorScheme::System => return color_scheme_from_system(),
|
||||
};
|
||||
should_detect.then(|| detector.detect()).flatten()
|
||||
}
|
||||
|
||||
trait ColorSchemeDetector {
|
||||
fn should_detect(&self) -> bool;
|
||||
|
||||
fn detect(&self) -> Option<ColorScheme>;
|
||||
}
|
||||
|
||||
struct TerminalColorSchemeDetector;
|
||||
|
||||
impl ColorSchemeDetector for TerminalColorSchemeDetector {
|
||||
fn should_detect(&self) -> bool {
|
||||
// Querying the terminal for its colors via OSC 10 / OSC 11 requires "exclusive" access
|
||||
// since we read/write from the terminal and enable/disable raw mode.
|
||||
// This causes race conditions with pagers such as less when they are attached to the
|
||||
// same terminal as us.
|
||||
//
|
||||
// This is usually only an issue when the output is manually piped to a pager.
|
||||
// For example: `bat Cargo.toml | less`.
|
||||
// Otherwise, if we start the pager ourselves, then there's no race condition
|
||||
// since the pager is started *after* the color is detected.
|
||||
std::io::stdout().is_terminal()
|
||||
}
|
||||
|
||||
fn detect(&self) -> Option<ColorScheme> {
|
||||
use terminal_colorsaurus::{color_scheme, ColorScheme as ColorsaurusScheme, QueryOptions};
|
||||
match color_scheme(QueryOptions::default()).ok()? {
|
||||
ColorsaurusScheme::Dark => Some(ColorScheme::Dark),
|
||||
ColorsaurusScheme::Light => Some(ColorScheme::Light),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
fn color_scheme_from_system() -> Option<ColorScheme> {
|
||||
crate::bat_warning!(
|
||||
"Theme 'auto:system' is only supported on macOS, \
|
||||
using default."
|
||||
);
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn color_scheme_from_system() -> Option<ColorScheme> {
|
||||
const PREFERENCES_FILE: &str = "Library/Preferences/.GlobalPreferences.plist";
|
||||
const STYLE_KEY: &str = "AppleInterfaceStyle";
|
||||
|
||||
let preferences_file = home::home_dir()
|
||||
.map(|home| home.join(PREFERENCES_FILE))
|
||||
.expect("Could not get home directory");
|
||||
|
||||
match plist::Value::from_file(preferences_file).map(|file| file.into_dictionary()) {
|
||||
Ok(Some(preferences)) => match preferences.get(STYLE_KEY).and_then(|val| val.as_string()) {
|
||||
Some("Dark") => Some(ColorScheme::Dark),
|
||||
// If the key does not exist, then light theme is currently in use.
|
||||
Some(_) | None => Some(ColorScheme::Light),
|
||||
},
|
||||
// Unreachable, in theory. All macOS users have a home directory and preferences file setup.
|
||||
Ok(None) | Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl ColorSchemeDetector for Option<ColorScheme> {
|
||||
fn should_detect(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn detect(&self) -> Option<ColorScheme> {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ColorScheme::*;
|
||||
use super::*;
|
||||
use std::cell::Cell;
|
||||
use std::iter;
|
||||
|
||||
mod color_scheme_detection {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn not_called_for_dark_or_light() {
|
||||
for theme in [ThemePreference::Dark, ThemePreference::Light] {
|
||||
let detector = DetectorStub::should_detect(Some(Dark));
|
||||
let options = ThemeOptions {
|
||||
theme,
|
||||
..Default::default()
|
||||
};
|
||||
_ = theme_impl(options, &detector);
|
||||
assert!(!detector.was_called.get());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn called_for_always() {
|
||||
let detectors = [
|
||||
DetectorStub::should_detect(Some(Dark)),
|
||||
DetectorStub::should_not_detect(),
|
||||
];
|
||||
for detector in detectors {
|
||||
let options = ThemeOptions {
|
||||
theme: ThemePreference::Auto(DetectColorScheme::Always),
|
||||
..Default::default()
|
||||
};
|
||||
_ = theme_impl(options, &detector);
|
||||
assert!(detector.was_called.get());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn called_for_auto_if_should_detect() {
|
||||
let detector = DetectorStub::should_detect(Some(Dark));
|
||||
_ = theme_impl(ThemeOptions::default(), &detector);
|
||||
assert!(detector.was_called.get());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_called_for_auto_if_not_should_detect() {
|
||||
let detector = DetectorStub::should_not_detect();
|
||||
_ = theme_impl(ThemeOptions::default(), &detector);
|
||||
assert!(!detector.was_called.get());
|
||||
}
|
||||
}
|
||||
|
||||
mod precedence {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn theme_is_preferred_over_light_or_dark_themes() {
|
||||
for color_scheme in optional(color_schemes()) {
|
||||
for options in [
|
||||
ThemeOptions {
|
||||
theme: ThemePreference::Fixed(ThemeName::Named("Theme".to_string())),
|
||||
..Default::default()
|
||||
},
|
||||
ThemeOptions {
|
||||
theme: ThemePreference::Fixed(ThemeName::Named("Theme".to_string())),
|
||||
theme_dark: Some(ThemeName::Named("Dark Theme".to_string())),
|
||||
theme_light: Some(ThemeName::Named("Light Theme".to_string())),
|
||||
},
|
||||
] {
|
||||
let detector = ConstantDetector(color_scheme);
|
||||
assert_eq!("Theme", theme_impl(options, &detector).to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn detector_is_not_called_if_theme_is_present() {
|
||||
let options = ThemeOptions {
|
||||
theme: ThemePreference::Fixed(ThemeName::Named("Theme".to_string())),
|
||||
..Default::default()
|
||||
};
|
||||
let detector = DetectorStub::should_detect(Some(Dark));
|
||||
_ = theme_impl(options, &detector);
|
||||
assert!(!detector.was_called.get());
|
||||
}
|
||||
}
|
||||
|
||||
mod default_theme {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn default_dark_if_unable_to_detect_color_scheme() {
|
||||
let detector = ConstantDetector(None);
|
||||
assert_eq!(
|
||||
default_theme(ColorScheme::Dark),
|
||||
theme_impl(ThemeOptions::default(), &detector).to_string()
|
||||
);
|
||||
}
|
||||
|
||||
// For backwards compatibility, if the default theme is requested
|
||||
// explicitly through BAT_THEME, we always pick the default dark theme.
|
||||
#[test]
|
||||
fn default_dark_if_requested_explicitly_through_theme() {
|
||||
for color_scheme in optional(color_schemes()) {
|
||||
let options = ThemeOptions {
|
||||
theme: ThemePreference::Fixed(ThemeName::Default),
|
||||
..Default::default()
|
||||
};
|
||||
let detector = ConstantDetector(color_scheme);
|
||||
assert_eq!(
|
||||
default_theme(ColorScheme::Dark),
|
||||
theme_impl(options, &detector).to_string()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn varies_depending_on_color_scheme() {
|
||||
for color_scheme in color_schemes() {
|
||||
for options in [
|
||||
ThemeOptions::default(),
|
||||
ThemeOptions {
|
||||
theme_dark: Some(ThemeName::Default),
|
||||
theme_light: Some(ThemeName::Default),
|
||||
..Default::default()
|
||||
},
|
||||
] {
|
||||
let detector = ConstantDetector(Some(color_scheme));
|
||||
assert_eq!(
|
||||
default_theme(color_scheme),
|
||||
theme_impl(options, &detector).to_string()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod choosing {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn chooses_default_theme_if_unknown() {
|
||||
let options = ThemeOptions {
|
||||
theme_dark: Some(ThemeName::Named("Dark".to_string())),
|
||||
theme_light: Some(ThemeName::Named("Light".to_string())),
|
||||
..Default::default()
|
||||
};
|
||||
let detector = ConstantDetector(None);
|
||||
assert_eq!(
|
||||
default_theme(ColorScheme::default()),
|
||||
theme_impl(options, &detector).to_string()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn chooses_dark_theme_if_dark_or_unknown() {
|
||||
let options = ThemeOptions {
|
||||
theme_dark: Some(ThemeName::Named("Dark".to_string())),
|
||||
theme_light: Some(ThemeName::Named("Light".to_string())),
|
||||
..Default::default()
|
||||
};
|
||||
let detector = ConstantDetector(Some(ColorScheme::Dark));
|
||||
assert_eq!("Dark", theme_impl(options, &detector).to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn chooses_light_theme_if_light() {
|
||||
let options = ThemeOptions {
|
||||
theme_dark: Some(ThemeName::Named("Dark".to_string())),
|
||||
theme_light: Some(ThemeName::Named("Light".to_string())),
|
||||
..Default::default()
|
||||
};
|
||||
let detector = ConstantDetector(Some(ColorScheme::Light));
|
||||
assert_eq!("Light", theme_impl(options, &detector).to_string());
|
||||
}
|
||||
}
|
||||
|
||||
mod theme_preference {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn values_roundtrip_via_display() {
|
||||
let prefs = [
|
||||
ThemePreference::Auto(DetectColorScheme::Auto),
|
||||
ThemePreference::Auto(DetectColorScheme::Always),
|
||||
ThemePreference::Auto(DetectColorScheme::System),
|
||||
ThemePreference::Fixed(ThemeName::Default),
|
||||
ThemePreference::Fixed(ThemeName::new("foo")),
|
||||
ThemePreference::Dark,
|
||||
ThemePreference::Light,
|
||||
];
|
||||
for pref in prefs {
|
||||
assert_eq!(pref, ThemePreference::new(pref.to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct DetectorStub {
|
||||
should_detect: bool,
|
||||
color_scheme: Option<ColorScheme>,
|
||||
was_called: Cell<bool>,
|
||||
}
|
||||
|
||||
impl DetectorStub {
|
||||
fn should_detect(color_scheme: Option<ColorScheme>) -> Self {
|
||||
DetectorStub {
|
||||
should_detect: true,
|
||||
color_scheme,
|
||||
was_called: Cell::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn should_not_detect() -> Self {
|
||||
DetectorStub {
|
||||
should_detect: false,
|
||||
color_scheme: None,
|
||||
was_called: Cell::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ColorSchemeDetector for DetectorStub {
|
||||
fn should_detect(&self) -> bool {
|
||||
self.should_detect
|
||||
}
|
||||
|
||||
fn detect(&self) -> Option<ColorScheme> {
|
||||
self.was_called.set(true);
|
||||
self.color_scheme
|
||||
}
|
||||
}
|
||||
|
||||
struct ConstantDetector(Option<ColorScheme>);
|
||||
|
||||
impl ColorSchemeDetector for ConstantDetector {
|
||||
fn should_detect(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn detect(&self) -> Option<ColorScheme> {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
fn optional<T>(value: impl Iterator<Item = T>) -> impl Iterator<Item = Option<T>> {
|
||||
value.map(Some).chain(iter::once(None))
|
||||
}
|
||||
|
||||
fn color_schemes() -> impl Iterator<Item = ColorScheme> {
|
||||
[Dark, Light].into_iter()
|
||||
}
|
||||
}
|
@ -360,10 +360,10 @@ pub struct EscapeSequenceOffsetsIterator<'a> {
|
||||
|
||||
impl<'a> EscapeSequenceOffsetsIterator<'a> {
|
||||
pub fn new(text: &'a str) -> EscapeSequenceOffsetsIterator<'a> {
|
||||
return EscapeSequenceOffsetsIterator {
|
||||
EscapeSequenceOffsetsIterator {
|
||||
text,
|
||||
chars: text.char_indices().peekable(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes values from the iterator while the predicate returns true.
|
||||
@ -539,7 +539,7 @@ impl<'a> EscapeSequenceOffsetsIterator<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for EscapeSequenceOffsetsIterator<'a> {
|
||||
impl Iterator for EscapeSequenceOffsetsIterator<'_> {
|
||||
type Item = EscapeSequenceOffsets;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.chars.peek() {
|
||||
@ -564,10 +564,10 @@ pub struct EscapeSequenceIterator<'a> {
|
||||
|
||||
impl<'a> EscapeSequenceIterator<'a> {
|
||||
pub fn new(text: &'a str) -> EscapeSequenceIterator<'a> {
|
||||
return EscapeSequenceIterator {
|
||||
EscapeSequenceIterator {
|
||||
text,
|
||||
offset_iter: EscapeSequenceOffsetsIterator::new(text),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
0
tests/examples/test.A—B가
vendored
Normal file
0
tests/examples/test.A—B가
vendored
Normal file
@ -35,13 +35,7 @@ fn all_jobs_not_missing_any_jobs() {
|
||||
.as_mapping()
|
||||
.unwrap()
|
||||
.keys()
|
||||
.filter_map(|k| {
|
||||
if exceptions.contains(&k.as_str().unwrap_or_default()) {
|
||||
None
|
||||
} else {
|
||||
Some(k)
|
||||
}
|
||||
})
|
||||
.filter(|k| !exceptions.contains(&k.as_str().unwrap_or_default()))
|
||||
.map(ToOwned::to_owned)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
@ -9,7 +9,6 @@ use tempfile::tempdir;
|
||||
mod unix {
|
||||
pub use std::fs::File;
|
||||
pub use std::io::{self, Write};
|
||||
pub use std::os::unix::io::FromRawFd;
|
||||
pub use std::path::PathBuf;
|
||||
pub use std::process::Stdio;
|
||||
pub use std::thread;
|
||||
@ -314,11 +313,8 @@ fn squeeze_limit_line_numbers() {
|
||||
|
||||
#[test]
|
||||
fn list_themes_with_colors() {
|
||||
#[cfg(target_os = "macos")]
|
||||
let default_theme_chunk = "Monokai Extended Light\x1B[0m (default)";
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let default_theme_chunk = "Monokai Extended\x1B[0m (default)";
|
||||
let default_light_theme_chunk = "Monokai Extended Light\x1B[0m (default light)";
|
||||
|
||||
bat()
|
||||
.arg("--color=always")
|
||||
@ -327,34 +323,50 @@ fn list_themes_with_colors() {
|
||||
.success()
|
||||
.stdout(predicate::str::contains("DarkNeon").normalize())
|
||||
.stdout(predicate::str::contains(default_theme_chunk).normalize())
|
||||
.stdout(predicate::str::contains(default_light_theme_chunk).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)";
|
||||
let default_light_theme_chunk = "Monokai Extended Light (default light)";
|
||||
|
||||
bat()
|
||||
.arg("--color=never")
|
||||
.arg("--decorations=always") // trick bat into setting `Config::loop_through` to false
|
||||
.arg("--list-themes")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("DarkNeon").normalize())
|
||||
.stdout(predicate::str::contains(default_theme_chunk).normalize());
|
||||
.stdout(predicate::str::contains(default_theme_chunk).normalize())
|
||||
.stdout(predicate::str::contains(default_light_theme_chunk).normalize());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(any(not(feature = "git"), target_os = "windows"), ignore)]
|
||||
fn list_themes_to_piped_output() {
|
||||
bat().arg("--list-themes").assert().success().stdout(
|
||||
predicate::str::contains("(default)")
|
||||
.not()
|
||||
.and(predicate::str::contains("(default light)").not())
|
||||
.and(predicate::str::contains("(default dark)").not()),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(
|
||||
any(not(feature = "git"), feature = "lessopen", target_os = "windows"),
|
||||
ignore
|
||||
)]
|
||||
fn short_help() {
|
||||
test_help("-h", "../doc/short-help.txt");
|
||||
}
|
||||
|
||||
#[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() {
|
||||
test_help("--help", "../doc/long-help.txt");
|
||||
}
|
||||
@ -445,9 +457,10 @@ fn no_args_doesnt_break() {
|
||||
// as the slave end of a pseudo terminal. Although both point to the same "file", bat should
|
||||
// not exit, because in this case it is safe to read and write to the same fd, which is why
|
||||
// this test exists.
|
||||
|
||||
let OpenptyResult { master, slave } = openpty(None, None).expect("Couldn't open pty.");
|
||||
let mut master = unsafe { File::from_raw_fd(master) };
|
||||
let stdin_file = unsafe { File::from_raw_fd(slave) };
|
||||
let mut master = File::from(master);
|
||||
let stdin_file = File::from(slave);
|
||||
let stdout_file = stdin_file.try_clone().unwrap();
|
||||
let stdin = Stdio::from(stdin_file);
|
||||
let stdout = Stdio::from(stdout_file);
|
||||
@ -455,6 +468,7 @@ fn no_args_doesnt_break() {
|
||||
let mut child = bat_raw_command()
|
||||
.stdin(stdin)
|
||||
.stdout(stdout)
|
||||
.env("TERM", "dumb") // Suppresses color detection
|
||||
.spawn()
|
||||
.expect("Failed to start.");
|
||||
|
||||
@ -1050,6 +1064,31 @@ fn enable_pager_if_pp_flag_comes_before_paging() {
|
||||
.stdout(predicate::eq("pager-output\n").normalize());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn paging_does_not_override_simple_plain() {
|
||||
bat()
|
||||
.env("PAGER", "echo pager-output")
|
||||
.arg("--decorations=always")
|
||||
.arg("--plain")
|
||||
.arg("--paging=never")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::eq("hello world\n"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_plain_does_not_override_paging() {
|
||||
bat()
|
||||
.env("PAGER", "echo pager-output")
|
||||
.arg("--paging=always")
|
||||
.arg("--plain")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::eq("pager-output\n"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pager_failed_to_parse() {
|
||||
bat()
|
||||
@ -1601,6 +1640,17 @@ oken
|
||||
.stderr("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn header_narrow_terminal_with_multibyte_chars() {
|
||||
bat()
|
||||
.arg("--terminal-width=30")
|
||||
.arg("--decorations=always")
|
||||
.arg("test.A—B가")
|
||||
.assert()
|
||||
.success()
|
||||
.stderr("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "git")] // Expected output assumes git is enabled
|
||||
fn header_default() {
|
||||
@ -1833,7 +1883,7 @@ fn do_not_panic_regression_tests() {
|
||||
] {
|
||||
bat()
|
||||
.arg("--color=always")
|
||||
.arg(&format!("regression_tests/{filename}"))
|
||||
.arg(format!("regression_tests/{filename}"))
|
||||
.assert()
|
||||
.success();
|
||||
}
|
||||
@ -1846,7 +1896,7 @@ fn do_not_detect_different_syntax_for_stdin_and_files() {
|
||||
let cmd_for_file = bat()
|
||||
.arg("--color=always")
|
||||
.arg("--map-syntax=*.js:Markdown")
|
||||
.arg(&format!("--file-name={file}"))
|
||||
.arg(format!("--file-name={file}"))
|
||||
.arg("--style=plain")
|
||||
.arg(file)
|
||||
.assert()
|
||||
@ -1856,7 +1906,7 @@ fn do_not_detect_different_syntax_for_stdin_and_files() {
|
||||
.arg("--color=always")
|
||||
.arg("--map-syntax=*.js:Markdown")
|
||||
.arg("--style=plain")
|
||||
.arg(&format!("--file-name={file}"))
|
||||
.arg(format!("--file-name={file}"))
|
||||
.pipe_stdin(Path::new(EXAMPLES_DIR).join(file))
|
||||
.unwrap()
|
||||
.assert()
|
||||
@ -1875,7 +1925,7 @@ fn no_first_line_fallback_when_mapping_to_invalid_syntax() {
|
||||
bat()
|
||||
.arg("--color=always")
|
||||
.arg("--map-syntax=*.invalid-syntax:InvalidSyntax")
|
||||
.arg(&format!("--file-name={file}"))
|
||||
.arg(format!("--file-name={file}"))
|
||||
.arg("--style=plain")
|
||||
.arg(file)
|
||||
.assert()
|
||||
@ -1969,6 +2019,16 @@ fn show_all_with_unicode() {
|
||||
.stderr("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn binary_as_text() {
|
||||
bat()
|
||||
.arg("--binary=as-text")
|
||||
.arg("control_characters.txt")
|
||||
.assert()
|
||||
.stdout("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x7F")
|
||||
.stderr("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_paging_arg() {
|
||||
bat()
|
||||
@ -2257,6 +2317,46 @@ fn theme_arg_overrides_env_withconfig() {
|
||||
.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]
|
||||
fn theme_env_overrides_config() {
|
||||
bat_with_config()
|
||||
@ -2435,7 +2535,6 @@ fn lessopen_stdin_piped() {
|
||||
#[cfg(unix)] // Expected output assumed that tests are run on a Unix-like system
|
||||
#[cfg(feature = "lessopen")]
|
||||
#[test]
|
||||
#[serial] // Randomly fails otherwise
|
||||
fn lessopen_and_lessclose_file_temp() {
|
||||
// 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
|
||||
@ -2453,7 +2552,6 @@ fn lessopen_and_lessclose_file_temp() {
|
||||
#[cfg(unix)] // Expected output assumed that tests are run on a Unix-like system
|
||||
#[cfg(feature = "lessopen")]
|
||||
#[test]
|
||||
#[serial] // Randomly fails otherwise
|
||||
fn lessopen_and_lessclose_file_piped() {
|
||||
// This is mainly to test that $LESSCLOSE gets passed the correct file paths
|
||||
// In these cases, the original file and a dash
|
||||
@ -2480,8 +2578,6 @@ fn lessopen_and_lessclose_file_piped() {
|
||||
#[cfg(unix)] // Expected output assumed that tests are run on a Unix-like system
|
||||
#[cfg(feature = "lessopen")]
|
||||
#[test]
|
||||
#[serial] // Randomly fails otherwise
|
||||
#[ignore = "randomly failing on some systems"]
|
||||
fn lessopen_and_lessclose_stdin_temp() {
|
||||
// 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
|
||||
@ -2499,7 +2595,6 @@ fn lessopen_and_lessclose_stdin_temp() {
|
||||
#[cfg(unix)] // Expected output assumed that tests are run on a Unix-like system
|
||||
#[cfg(feature = "lessopen")]
|
||||
#[test]
|
||||
#[serial] // Randomly fails otherwise
|
||||
fn lessopen_and_lessclose_stdin_piped() {
|
||||
// This is mainly to test that $LESSCLOSE gets passed the correct file paths
|
||||
// In these cases, two dashes
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user