diff --git a/.cargo/audit.toml b/.cargo/audit.toml
new file mode 100644
index 00000000..90a57848
--- /dev/null
+++ b/.cargo/audit.toml
@@ -0,0 +1,2 @@
+[advisories]
+ignore = ["RUSTSEC-2024-0320", "RUSTSEC-2024-0421"]
diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml
index 68515f3d..5d2d27ae 100644
--- a/.github/workflows/CICD.yml
+++ b/.github/workflows/CICD.yml
@@ -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 }
diff --git a/.github/workflows/require-changelog-for-PRs.yml b/.github/workflows/require-changelog-for-PRs.yml
index 9b9d7cde..346ed385 100644
--- a/.github/workflows/require-changelog-for-PRs.yml
+++ b/.github/workflows/require-changelog-for-PRs.yml
@@ -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"
diff --git a/.gitignore b/.gitignore
index a3ea8cff..fbfe6ac6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
**/*.rs.bk
# Generated files
+/assets/completions/_bat.ps1
/assets/completions/bat.bash
/assets/completions/bat.fish
/assets/completions/bat.zsh
diff --git a/.gitmodules b/.gitmodules
index fe159da8..2c096761 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -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
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 09a46b22..ccfee8fa 100644
--- a/CHANGELOG.md
+++ b/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 `, 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
diff --git a/Cargo.lock b/Cargo.lock
index 1168501a..f836e3eb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3,16 +3,16 @@
version = 3
[[package]]
-name = "adler"
-version = "1.0.2"
+name = "adler2"
+version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
[[package]]
name = "aho-corasick"
-version = "1.1.2"
+version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
@@ -28,67 +28,69 @@ dependencies = [
[[package]]
name = "anstream"
-version = "0.6.4"
+version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44"
+checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
+ "is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
-version = "1.0.0"
+version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d"
+checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
[[package]]
name = "anstyle-parse"
-version = "0.2.0"
+version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee"
+checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
-version = "1.0.0"
+version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
+checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
dependencies = [
- "windows-sys 0.48.0",
+ "windows-sys 0.59.0",
]
[[package]]
name = "anstyle-wincon"
-version = "3.0.1"
+version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
+checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
dependencies = [
"anstyle",
- "windows-sys 0.48.0",
+ "windows-sys 0.59.0",
]
[[package]]
name = "anyhow"
-version = "1.0.86"
+version = "1.0.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
+checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
[[package]]
name = "assert_cmd"
-version = "2.0.12"
+version = "2.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88903cb14723e4d4003335bb7f8a14f27691649105346a0f0957466c096adfe6"
+checksum = "dc1835b7f27878de8525dc71410b5a31cdcc5f230aed5ba5df968e09c201b23d"
dependencies = [
"anstyle",
"bstr",
"doc-comment",
+ "libc",
"predicates",
"predicates-core",
"predicates-tree",
@@ -97,19 +99,19 @@ dependencies = [
[[package]]
name = "autocfg"
-version = "1.1.0"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "base64"
-version = "0.21.0"
+version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bat"
-version = "0.24.0"
+version = "0.25.0"
dependencies = [
"ansi_colours",
"anyhow",
@@ -123,6 +125,7 @@ dependencies = [
"content_inspector",
"encoding_rs",
"etcetera",
+ "execute",
"expect-test",
"flate2",
"git2",
@@ -130,16 +133,15 @@ dependencies = [
"grep-cli",
"home",
"indexmap",
- "itertools",
+ "itertools 0.13.0",
+ "itertools 0.14.0",
"nix",
"nu-ansi-term",
"once_cell",
- "os_str_bytes",
"path_abs",
"plist",
"predicates",
"regex",
- "run_script",
"semver",
"serde",
"serde_derive",
@@ -149,9 +151,11 @@ dependencies = [
"shell-words",
"syntect",
"tempfile",
- "thiserror",
+ "terminal-colorsaurus",
+ "thiserror 2.0.11",
"toml",
- "unicode-width",
+ "unicode-segmentation",
+ "unicode-width 0.1.14",
"wait-timeout",
"walkdir",
"wild",
@@ -189,15 +193,15 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
-version = "2.4.0"
+version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "bstr"
-version = "1.8.0"
+version = "1.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c"
+checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0"
dependencies = [
"memchr",
"regex-automata",
@@ -206,20 +210,20 @@ dependencies = [
[[package]]
name = "bugreport"
-version = "0.5.0"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "535120b8182547808081a66f1f77a64533c780b23da26763e0ee34dfb94f98c9"
+checksum = "f280f65ce85b880919349bbfcb204930291251eedcb2e5f84ce2f51df969c162"
dependencies = [
"git-version",
"shell-escape",
- "sys-info",
+ "sysinfo",
]
[[package]]
name = "bytemuck"
-version = "1.12.1"
+version = "1.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f5715e491b5a1598fc2bef5a606847b5dc1d48ea625bd3c02c00de8285591da"
+checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3"
[[package]]
name = "bytesize"
@@ -229,12 +233,13 @@ checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc"
[[package]]
name = "cc"
-version = "1.0.83"
+version = "1.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
+checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7"
dependencies = [
"jobserver",
"libc",
+ "shlex",
]
[[package]]
@@ -244,19 +249,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
-name = "clap"
-version = "4.4.12"
+name = "cfg_aliases"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcfab8ba68f3668e89f6ff60f5b205cea56aa7b769451a59f34b8682f51c056d"
+checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
+
+[[package]]
+name = "clap"
+version = "4.5.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9560b07a799281c7e0958b9296854d6fafd4c5f31444a7e5bb1ad6dde5ccf1bd"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
-version = "4.4.12"
+version = "4.5.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9"
+checksum = "874e0dd3eb68bf99058751ac9712f622e61e6f393a94f7128fa26e3f02f5c7cd"
dependencies = [
"anstream",
"anstyle",
@@ -267,40 +278,37 @@ dependencies = [
[[package]]
name = "clap_lex"
-version = "0.6.0"
+version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
+checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
[[package]]
name = "clircle"
-version = "0.5.0"
+version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec0b92245ea62a7a751db4b0e4a583f8978e508077ef6de24fcc0d0dc5311a8d"
+checksum = "7d9334f725b46fb9bed8580b9b47a932587e044fadb344ed7fa98774b067ac1a"
dependencies = [
"cfg-if",
- "libc",
- "serde",
- "serde_derive",
- "winapi",
+ "windows 0.56.0",
]
[[package]]
name = "colorchoice"
-version = "1.0.0"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
+checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "console"
-version = "0.15.8"
+version = "0.15.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
+checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b"
dependencies = [
"encode_unicode",
- "lazy_static",
"libc",
- "unicode-width",
- "windows-sys 0.52.0",
+ "once_cell",
+ "unicode-width 0.2.0",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -313,19 +321,50 @@ dependencies = [
]
[[package]]
-name = "crc32fast"
-version = "1.3.2"
+name = "core-foundation-sys"
+version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
+[[package]]
+name = "crc32fast"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
dependencies = [
"cfg-if",
]
[[package]]
-name = "darling"
-version = "0.20.3"
+name = "crossbeam-deque"
+version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
+checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
+dependencies = [
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
+
+[[package]]
+name = "darling"
+version = "0.20.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
dependencies = [
"darling_core",
"darling_macro",
@@ -333,9 +372,9 @@ dependencies = [
[[package]]
name = "darling_core"
-version = "0.20.3"
+version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
+checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
dependencies = [
"fnv",
"ident_case",
@@ -347,9 +386,9 @@ dependencies = [
[[package]]
name = "darling_macro"
-version = "0.20.3"
+version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
+checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
dependencies = [
"darling_core",
"quote",
@@ -358,12 +397,12 @@ dependencies = [
[[package]]
name = "dashmap"
-version = "5.4.0"
+version = "5.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc"
+checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
dependencies = [
"cfg-if",
- "hashbrown 0.12.3",
+ "hashbrown 0.14.5",
"lock_api",
"once_cell",
"parking_lot_core",
@@ -385,10 +424,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
[[package]]
-name = "dissimilar"
-version = "1.0.5"
+name = "displaydoc"
+version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd5f0c7e4bd266b8ab2550e6238d2e74977c23c15536ac7be45e9c95e2e3fbbb"
+checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "dissimilar"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59f8e79d1fbf76bdfbde321e902714bf6c49df88a7dda6fc682fc2979226962d"
[[package]]
name = "doc-comment"
@@ -396,29 +446,23 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
-[[package]]
-name = "dunce"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bd4b30a6560bbd9b4620f4de34c3f14f60848e58a9b7216801afcb4c7b31c3c"
-
[[package]]
name = "either"
-version = "1.8.0"
+version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
+checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "encode_unicode"
-version = "0.3.6"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
+checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
[[package]]
name = "encoding_rs"
-version = "0.8.34"
+version = "0.8.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59"
+checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
dependencies = [
"cfg-if",
]
@@ -431,41 +475,67 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "errno"
-version = "0.3.3"
+version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd"
+checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
dependencies = [
- "errno-dragonfly",
- "libc",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "errno-dragonfly"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
-dependencies = [
- "cc",
"libc",
+ "windows-sys 0.59.0",
]
[[package]]
name = "etcetera"
-version = "0.8.0"
+version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943"
+checksum = "26c7b13d0780cb82722fd59f6f57f925e143427e4a75313a6c77243bf5326ae6"
dependencies = [
"cfg-if",
"home",
- "windows-sys 0.48.0",
+ "windows-sys 0.59.0",
]
[[package]]
-name = "expect-test"
-version = "1.5.0"
+name = "execute"
+version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e0be0a561335815e06dab7c62e50353134c796e7a6155402a64bcff66b6a5e0"
+checksum = "3a82608ee96ce76aeab659e9b8d3c2b787bffd223199af88c674923d861ada10"
+dependencies = [
+ "execute-command-macro",
+ "execute-command-tokens",
+ "generic-array",
+]
+
+[[package]]
+name = "execute-command-macro"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90dec53d547564e911dc4ff3ecb726a64cf41a6fa01a2370ebc0d95175dd08bd"
+dependencies = [
+ "execute-command-macro-impl",
+]
+
+[[package]]
+name = "execute-command-macro-impl"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce8cd46a041ad005ab9c71263f9a0ff5b529eac0fe4cc9b4a20f4f0765d8cf4b"
+dependencies = [
+ "execute-command-tokens",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "execute-command-tokens"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69dc321eb6be977f44674620ca3aa21703cb20ffbe560e1ae97da08401ffbcad"
+
+[[package]]
+name = "expect-test"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63af43ff4431e848fb47472a920f14fa71c24de13255a5692e93d4e90302acb0"
dependencies = [
"dissimilar",
"once_cell",
@@ -483,15 +553,15 @@ dependencies = [
[[package]]
name = "fastrand"
-version = "2.0.0"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]]
name = "flate2"
-version = "1.0.30"
+version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae"
+checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c"
dependencies = [
"crc32fast",
"miniz_oxide",
@@ -499,9 +569,9 @@ dependencies = [
[[package]]
name = "float-cmp"
-version = "0.9.0"
+version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
+checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8"
dependencies = [
"num-traits",
]
@@ -514,32 +584,32 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "form_urlencoded"
-version = "1.1.0"
+version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
dependencies = [
"percent-encoding",
]
[[package]]
-name = "fsio"
-version = "0.4.0"
+name = "generic-array"
+version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dad0ce30be0cc441b325c5d705c8b613a0ca0d92b6a8953d41bd236dc09a36d0"
+checksum = "2cb8bc4c28d15ade99c7e90b219f30da4be5c88e586277e8cbe886beeb868ab2"
dependencies = [
- "dunce",
- "rand",
+ "typenum",
]
[[package]]
name = "getrandom"
-version = "0.2.7"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
+checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
dependencies = [
"cfg-if",
"libc",
- "wasi",
+ "wasi 0.13.3+wasi-0.2.2",
+ "windows-targets",
]
[[package]]
@@ -564,11 +634,11 @@ dependencies = [
[[package]]
name = "git2"
-version = "0.18.3"
+version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "232e6a7bfe35766bf715e55a88b39a700596c0ccfd88cd3680b4cdb40d66ef70"
+checksum = "3fda788993cc341f69012feba8bf45c0ba4f3291fcc08e214b4d5a7332d88aff"
dependencies = [
- "bitflags 2.4.0",
+ "bitflags 2.6.0",
"libc",
"libgit2-sys",
"log",
@@ -577,15 +647,15 @@ dependencies = [
[[package]]
name = "glob"
-version = "0.3.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]]
name = "globset"
-version = "0.4.14"
+version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
+checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19"
dependencies = [
"aho-corasick",
"bstr",
@@ -596,9 +666,9 @@ dependencies = [
[[package]]
name = "grep-cli"
-version = "0.1.10"
+version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea40788c059ab8b622c4d074732750bfb3bd2912e2dd58eabc11798a4d5ad725"
+checksum = "47f1288f0e06f279f84926fa4c17e3fcd2a22b357927a82f2777f7be26e4cec0"
dependencies = [
"bstr",
"globset",
@@ -610,15 +680,15 @@ dependencies = [
[[package]]
name = "hashbrown"
-version = "0.12.3"
+version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "hashbrown"
-version = "0.14.1"
+version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12"
+checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
[[package]]
name = "home"
@@ -629,6 +699,124 @@ dependencies = [
"windows-sys 0.52.0",
]
+[[package]]
+name = "icu_collections"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid_transform"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
+dependencies = [
+ "displaydoc",
+ "icu_locid",
+ "icu_locid_transform_data",
+ "icu_provider",
+ "tinystr",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid_transform_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
+
+[[package]]
+name = "icu_normalizer"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "utf16_iter",
+ "utf8_iter",
+ "write16",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
+
+[[package]]
+name = "icu_properties"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_locid_transform",
+ "icu_properties_data",
+ "icu_provider",
+ "tinystr",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
+
+[[package]]
+name = "icu_provider"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
+dependencies = [
+ "displaydoc",
+ "icu_locid",
+ "icu_provider_macros",
+ "stable_deref_trait",
+ "tinystr",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_provider_macros"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "ident_case"
version = "1.0.1"
@@ -637,25 +825,42 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
-version = "0.3.0"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
+checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
dependencies = [
- "unicode-bidi",
- "unicode-normalization",
+ "idna_adapter",
+ "smallvec",
+ "utf8_iter",
+]
+
+[[package]]
+name = "idna_adapter"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
+dependencies = [
+ "icu_normalizer",
+ "icu_properties",
]
[[package]]
name = "indexmap"
-version = "2.3.0"
+version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0"
+checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
dependencies = [
"equivalent",
- "hashbrown 0.14.1",
+ "hashbrown 0.15.2",
"serde",
]
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+
[[package]]
name = "itertools"
version = "0.13.0"
@@ -666,37 +871,46 @@ dependencies = [
]
[[package]]
-name = "itoa"
-version = "1.0.3"
+name = "itertools"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
+checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
[[package]]
name = "jobserver"
-version = "0.1.25"
+version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b"
+checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
dependencies = [
"libc",
]
[[package]]
name = "lazy_static"
-version = "1.4.0"
+version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
-version = "0.2.149"
+version = "0.2.169"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
+checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
[[package]]
name = "libgit2-sys"
-version = "0.16.2+1.7.2"
+version = "0.18.0+1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee4126d8b4ee5c9d9ea891dd875cfdc1e9d0950437179104b183d7d8a74d24e8"
+checksum = "e1a117465e7e1597e8febea8bb0c410f1c7fb93b1e1cddf34363f8390367ffec"
dependencies = [
"cc",
"libc",
@@ -706,9 +920,9 @@ dependencies = [
[[package]]
name = "libz-sys"
-version = "1.1.8"
+version = "1.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf"
+checksum = "df9b68e50e6e0b26f672573834882eb57759f6db9b3be2ea3c35c91188bb4eaa"
dependencies = [
"cc",
"libc",
@@ -716,15 +930,6 @@ dependencies = [
"vcpkg",
]
-[[package]]
-name = "line-wrap"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9"
-dependencies = [
- "safemem",
-]
-
[[package]]
name = "linked-hash-map"
version = "0.5.6"
@@ -733,15 +938,21 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
name = "linux-raw-sys"
-version = "0.4.10"
+version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
+checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
+
+[[package]]
+name = "litemap"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
[[package]]
name = "lock_api"
-version = "0.4.9"
+version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
+checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
dependencies = [
"autocfg",
"scopeguard",
@@ -749,33 +960,45 @@ dependencies = [
[[package]]
name = "log"
-version = "0.4.20"
+version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "memchr"
-version = "2.6.4"
+version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "miniz_oxide"
-version = "0.7.1"
+version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
+checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394"
dependencies = [
- "adler",
+ "adler2",
+]
+
+[[package]]
+name = "mio"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
+dependencies = [
+ "libc",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+ "windows-sys 0.52.0",
]
[[package]]
name = "nix"
-version = "0.26.4"
+version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b"
+checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
dependencies = [
- "bitflags 1.3.2",
+ "bitflags 2.6.0",
"cfg-if",
+ "cfg_aliases",
"libc",
]
@@ -786,12 +1009,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
[[package]]
-name = "nu-ansi-term"
-version = "0.50.0"
+name = "ntapi"
+version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd2800e1520bdc966782168a627aa5d1ad92e33b984bf7c7615d31280c83ff14"
+checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
dependencies = [
- "windows-sys 0.48.0",
+ "winapi",
+]
+
+[[package]]
+name = "nu-ansi-term"
+version = "0.50.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399"
+dependencies = [
+ "windows-sys 0.52.0",
]
[[package]]
@@ -802,18 +1034,18 @@ checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num-traits"
-version = "0.2.15"
+version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
-version = "1.19.0"
+version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]]
name = "onig"
@@ -837,20 +1069,11 @@ dependencies = [
"pkg-config",
]
-[[package]]
-name = "os_str_bytes"
-version = "7.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ac44c994af577c799b1b4bd80dc214701e349873ad894d6cdf96f4f7526e0b9"
-dependencies = [
- "memchr",
-]
-
[[package]]
name = "parking_lot"
-version = "0.12.1"
+version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
+checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
dependencies = [
"lock_api",
"parking_lot_core",
@@ -858,15 +1081,15 @@ dependencies = [
[[package]]
name = "parking_lot_core"
-version = "0.9.7"
+version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
+checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
"cfg-if",
"libc",
- "redox_syscall 0.2.16",
+ "redox_syscall",
"smallvec",
- "windows-sys 0.45.0",
+ "windows-targets",
]
[[package]]
@@ -880,25 +1103,24 @@ dependencies = [
[[package]]
name = "percent-encoding"
-version = "2.2.0"
+version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "pkg-config"
-version = "0.3.25"
+version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
+checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "plist"
-version = "1.6.0"
+version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5699cc8a63d1aa2b1ee8e12b9ad70ac790d65788cd36101fa37f87ea46c4cef"
+checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016"
dependencies = [
"base64",
"indexmap",
- "line-wrap",
"quick-xml",
"serde",
"time",
@@ -910,17 +1132,11 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
-[[package]]
-name = "ppv-lite86"
-version = "0.2.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
-
[[package]]
name = "predicates"
-version = "3.1.0"
+version = "3.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8"
+checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573"
dependencies = [
"anstyle",
"difflib",
@@ -932,15 +1148,15 @@ dependencies = [
[[package]]
name = "predicates-core"
-version = "1.0.6"
+version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174"
+checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa"
[[package]]
name = "predicates-tree"
-version = "1.0.5"
+version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d86de6de25020a36c6d3643a86d9a6a9f552107c0559c60ea03551b5e16c032"
+checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c"
dependencies = [
"predicates-core",
"termtree",
@@ -948,84 +1164,65 @@ dependencies = [
[[package]]
name = "proc-macro2"
-version = "1.0.79"
+version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
+checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quick-xml"
-version = "0.31.0"
+version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33"
+checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2"
dependencies = [
"memchr",
]
[[package]]
name = "quote"
-version = "1.0.35"
+version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
+checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
dependencies = [
"proc-macro2",
]
[[package]]
-name = "rand"
-version = "0.8.5"
+name = "rayon"
+version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
dependencies = [
- "libc",
- "rand_chacha",
- "rand_core",
+ "either",
+ "rayon-core",
]
[[package]]
-name = "rand_chacha"
-version = "0.3.1"
+name = "rayon-core"
+version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
dependencies = [
- "ppv-lite86",
- "rand_core",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.6.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
-dependencies = [
- "getrandom",
+ "crossbeam-deque",
+ "crossbeam-utils",
]
[[package]]
name = "redox_syscall"
-version = "0.2.16"
+version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
+checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
dependencies = [
- "bitflags 1.3.2",
-]
-
-[[package]]
-name = "redox_syscall"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
-dependencies = [
- "bitflags 1.3.2",
+ "bitflags 2.6.0",
]
[[package]]
name = "regex"
-version = "1.10.2"
+version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
@@ -1035,9 +1232,9 @@ dependencies = [
[[package]]
name = "regex-automata"
-version = "0.4.3"
+version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
@@ -1046,52 +1243,37 @@ dependencies = [
[[package]]
name = "regex-syntax"
-version = "0.8.2"
+version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rgb"
-version = "0.8.34"
+version = "0.8.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3603b7d71ca82644f79b5a06d1220e9a58ede60bd32255f698cb1af8838b8db3"
+checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a"
dependencies = [
"bytemuck",
]
-[[package]]
-name = "run_script"
-version = "0.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "829f98fdc58d78989dd9af83be28bc15c94a7d77f9ecdb54abbbc0b1829ba9c7"
-dependencies = [
- "fsio",
-]
-
[[package]]
name = "rustix"
-version = "0.38.21"
+version = "0.38.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
+checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6"
dependencies = [
- "bitflags 2.4.0",
+ "bitflags 2.6.0",
"errno",
"libc",
"linux-raw-sys",
- "windows-sys 0.48.0",
+ "windows-sys 0.59.0",
]
[[package]]
name = "ryu"
-version = "1.0.11"
+version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
-
-[[package]]
-name = "safemem"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "same-file"
@@ -1104,30 +1286,30 @@ dependencies = [
[[package]]
name = "scopeguard"
-version = "1.1.0"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "semver"
-version = "1.0.23"
+version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
+checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03"
[[package]]
name = "serde"
-version = "1.0.199"
+version = "1.0.217"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a"
+checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.199"
+version = "1.0.217"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc"
+checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
dependencies = [
"proc-macro2",
"quote",
@@ -1136,29 +1318,30 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.85"
+version = "1.0.135"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
+checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9"
dependencies = [
"itoa",
+ "memchr",
"ryu",
"serde",
]
[[package]]
name = "serde_spanned"
-version = "0.6.5"
+version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
+checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
dependencies = [
"serde",
]
[[package]]
name = "serde_with"
-version = "3.8.1"
+version = "3.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20"
+checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa"
dependencies = [
"serde",
"serde_derive",
@@ -1167,9 +1350,9 @@ dependencies = [
[[package]]
name = "serde_with_macros"
-version = "3.8.1"
+version = "3.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2"
+checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e"
dependencies = [
"darling",
"proc-macro2",
@@ -1179,9 +1362,9 @@ dependencies = [
[[package]]
name = "serde_yaml"
-version = "0.9.29"
+version = "0.9.34+deprecated"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a15e0ef66bf939a7c890a0bf6d5a733c70202225f9888a89ed5c62298b019129"
+checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
dependencies = [
"indexmap",
"itoa",
@@ -1226,10 +1409,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
[[package]]
-name = "smallvec"
-version = "1.10.0"
+name = "shlex"
+version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "smallvec"
+version = "1.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "std_prelude"
@@ -1239,21 +1434,32 @@ checksum = "8207e78455ffdf55661170876f88daf85356e4edd54e0a3dbc79586ca1e50cbe"
[[package]]
name = "strsim"
-version = "0.10.0"
+version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
-version = "2.0.57"
+version = "2.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35"
+checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
+[[package]]
+name = "synstructure"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "syntect"
version = "5.2.0"
@@ -1272,73 +1478,123 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
- "thiserror",
+ "thiserror 1.0.69",
"walkdir",
"yaml-rust",
]
[[package]]
-name = "sys-info"
-version = "0.9.1"
+name = "sysinfo"
+version = "0.33.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b3a0d0aba8bf96a0e1ddfdc352fc53b3df7f39318c71854910c3c4b024ae52c"
+checksum = "4fc858248ea01b66f19d8e8a6d55f41deaf91e9d495246fd01368d99935c6c01"
dependencies = [
- "cc",
+ "core-foundation-sys",
"libc",
+ "memchr",
+ "ntapi",
+ "rayon",
+ "windows 0.57.0",
]
[[package]]
name = "tempfile"
-version = "3.8.1"
+version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5"
+checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91"
dependencies = [
"cfg-if",
"fastrand",
- "redox_syscall 0.4.1",
+ "getrandom",
+ "once_cell",
"rustix",
- "windows-sys 0.48.0",
+ "windows-sys 0.59.0",
]
[[package]]
name = "termcolor"
-version = "1.4.0"
+version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449"
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
dependencies = [
"winapi-util",
]
[[package]]
-name = "terminal_size"
-version = "0.3.0"
+name = "terminal-colorsaurus"
+version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7"
+checksum = "858625398bdd5da7a96e8ad33a10031a50c3a5ad50d5aaa81a2827369a9c216c"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "memchr",
+ "mio",
+ "terminal-trx",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "terminal-trx"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57a5b836e7f4f81afe61b5cd399eee774f25edcfd47009a76e29f53bb6487833"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "terminal_size"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9"
dependencies = [
"rustix",
- "windows-sys 0.48.0",
+ "windows-sys 0.59.0",
]
[[package]]
name = "termtree"
-version = "0.2.4"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b"
+checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683"
[[package]]
name = "thiserror"
-version = "1.0.61"
+version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
- "thiserror-impl",
+ "thiserror-impl 1.0.69",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc"
+dependencies = [
+ "thiserror-impl 2.0.11",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.61"
+version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2"
dependencies = [
"proc-macro2",
"quote",
@@ -1347,9 +1603,9 @@ dependencies = [
[[package]]
name = "time"
-version = "0.3.36"
+version = "0.3.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
+checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21"
dependencies = [
"deranged",
"itoa",
@@ -1368,34 +1624,29 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
-version = "0.2.18"
+version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
+checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de"
dependencies = [
"num-conv",
"time-core",
]
[[package]]
-name = "tinyvec"
-version = "1.6.0"
+name = "tinystr"
+version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
+checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
dependencies = [
- "tinyvec_macros",
+ "displaydoc",
+ "zerovec",
]
-[[package]]
-name = "tinyvec_macros"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
-
[[package]]
name = "toml"
-version = "0.8.9"
+version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6a4b9e8023eb94392d3dca65d717c53abc5dad49c07cb65bb8fcd87115fa325"
+checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
dependencies = [
"indexmap",
"serde",
@@ -1406,18 +1657,18 @@ dependencies = [
[[package]]
name = "toml_datetime"
-version = "0.6.5"
+version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
+checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
-version = "0.21.1"
+version = "0.22.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
+checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
dependencies = [
"indexmap",
"serde",
@@ -1427,43 +1678,46 @@ dependencies = [
]
[[package]]
-name = "unicode-bidi"
-version = "0.3.8"
+name = "typenum"
+version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
+checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicode-ident"
-version = "1.0.4"
+version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
+checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
[[package]]
-name = "unicode-normalization"
-version = "0.1.22"
+name = "unicode-segmentation"
+version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
-dependencies = [
- "tinyvec",
-]
+checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]]
name = "unicode-width"
-version = "0.1.13"
+version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
+checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
+
+[[package]]
+name = "unicode-width"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
[[package]]
name = "unsafe-libyaml"
-version = "0.2.10"
+version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b"
+checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
[[package]]
name = "url"
-version = "2.3.1"
+version = "2.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
+checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
dependencies = [
"form_urlencoded",
"idna",
@@ -1471,10 +1725,22 @@ dependencies = [
]
[[package]]
-name = "utf8parse"
-version = "0.2.1"
+name = "utf16_iter"
+version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
+checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
+
+[[package]]
+name = "utf8_iter"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "vcpkg"
@@ -1507,6 +1773,15 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+[[package]]
+name = "wasi"
+version = "0.13.3+wasi-0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
+dependencies = [
+ "wit-bindgen-rt",
+]
+
[[package]]
name = "wild"
version = "2.2.1"
@@ -1534,11 +1809,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
-version = "0.1.6"
+version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
+checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
- "winapi",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -1548,21 +1823,100 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
-name = "windows-sys"
-version = "0.45.0"
+name = "windows"
+version = "0.56.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132"
dependencies = [
- "windows-targets 0.42.1",
+ "windows-core 0.56.0",
+ "windows-targets",
]
[[package]]
-name = "windows-sys"
-version = "0.48.0"
+name = "windows"
+version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
dependencies = [
- "windows-targets 0.48.0",
+ "windows-core 0.57.0",
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4698e52ed2d08f8658ab0c39512a7c00ee5fe2688c65f8c0a4f06750d729f2a6"
+dependencies = [
+ "windows-implement 0.56.0",
+ "windows-interface 0.56.0",
+ "windows-result",
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.57.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
+dependencies = [
+ "windows-implement 0.57.0",
+ "windows-interface 0.57.0",
+ "windows-result",
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.57.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.57.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
+dependencies = [
+ "windows-targets",
]
[[package]]
@@ -1571,189 +1925,112 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
- "windows-targets 0.52.0",
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
]
[[package]]
name = "windows-targets"
-version = "0.42.1"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
- "windows_aarch64_gnullvm 0.42.1",
- "windows_aarch64_msvc 0.42.1",
- "windows_i686_gnu 0.42.1",
- "windows_i686_msvc 0.42.1",
- "windows_x86_64_gnu 0.42.1",
- "windows_x86_64_gnullvm 0.42.1",
- "windows_x86_64_msvc 0.42.1",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
-dependencies = [
- "windows_aarch64_gnullvm 0.48.0",
- "windows_aarch64_msvc 0.48.0",
- "windows_i686_gnu 0.48.0",
- "windows_i686_msvc 0.48.0",
- "windows_x86_64_gnu 0.48.0",
- "windows_x86_64_gnullvm 0.48.0",
- "windows_x86_64_msvc 0.48.0",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
-dependencies = [
- "windows_aarch64_gnullvm 0.52.0",
- "windows_aarch64_msvc 0.52.0",
- "windows_i686_gnu 0.52.0",
- "windows_i686_msvc 0.52.0",
- "windows_x86_64_gnu 0.52.0",
- "windows_x86_64_gnullvm 0.52.0",
- "windows_x86_64_msvc 0.52.0",
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
-version = "0.42.1"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
-version = "0.42.1"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
-version = "0.42.1"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
-name = "windows_i686_gnu"
-version = "0.48.0"
+name = "windows_i686_gnullvm"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
-version = "0.42.1"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
-version = "0.42.1"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
-version = "0.42.1"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
-version = "0.42.1"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
-version = "0.5.18"
+version = "0.6.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "176b6138793677221d420fd2f0aeeced263f197688b36484660da767bca2fa32"
+checksum = "39281189af81c07ec09db316b302a3e67bf9bd7cbf6c820b50e35fee9c2fa980"
dependencies = [
"memchr",
]
+[[package]]
+name = "wit-bindgen-rt"
+version = "0.33.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
+dependencies = [
+ "bitflags 2.6.0",
+]
+
+[[package]]
+name = "write16"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
+
+[[package]]
+name = "writeable"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
+
[[package]]
name = "yaml-rust"
version = "0.4.5"
@@ -1762,3 +2039,70 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]
+
+[[package]]
+name = "yoke"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
+dependencies = [
+ "serde",
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
+name = "zerofrom"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
+name = "zerovec"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
+dependencies = [
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
diff --git a/Cargo.toml b/Cargo.toml
index 76234d5b..bd7bd912 100644
--- a/Cargo.toml
+++ b/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]
diff --git a/README.md b/README.md
index 016fe834..3b3c8ec4 100644
--- a/README.md
+++ b/README.md
@@ -21,25 +21,14 @@
### Sponsors
-A special *thank you* goes to our biggest sponsors :
-
-
-
- Your app, enterprise-ready.
-
- Start selling to enterprise customers with just a few lines of code.
-
- Add Single Sign-On (and more) in minutes instead of months.
-
+A special *thank you* goes to our biggest sponsor :
-
+
- Warp is a modern, Rust-based terminal with AI built in so you and your team can build great software, faster.
+ Warp, the intelligent terminal
- Feel more productive on the command line with parameterized commands,
-
- autosuggestions, and an IDE-like text editor.
+ Available on MacOS, Linux, Windows
### 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`
+
+
+
+
+
#### 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
+# 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.
diff --git a/assets/acknowledgements.bin b/assets/acknowledgements.bin
index 578a4f82..d62426dd 100644
Binary files a/assets/acknowledgements.bin and b/assets/acknowledgements.bin differ
diff --git a/assets/completions/_bat.ps1.in b/assets/completions/_bat.ps1.in
index c0c151e1..b6f62aae 100644
--- a/assets/completions/_bat.ps1.in
+++ b/assets/completions/_bat.ps1.in
@@ -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.')
diff --git a/assets/completions/bat.bash.in b/assets/completions/bat.bash.in
index f314bb25..90931f24 100644
--- a/assets/completions/bat.bash.in
+++ b/assets/completions/bat.bash.in
@@ -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
diff --git a/assets/completions/bat.fish.in b/assets/completions/bat.fish.in
index 788f71b0..e2712706 100644
--- a/assets/completions/bat.fish.in
+++ b/assets/completions/bat.fish.in
@@ -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 , +, or -" -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
diff --git a/assets/completions/bat.zsh.in b/assets/completions/bat.zsh.in
index 7d03abb3..dfe1e1b9 100644
--- a/assets/completions/bat.zsh.in
+++ b/assets/completions/bat.zsh.in
@@ -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
;;
diff --git a/assets/manual/bat.1.in b/assets/manual/bat.1.in
index 2bc0a3a5..ccc70629 100644
--- a/assets/manual/bat.1.in
+++ b/assets/manual/bat.1.in
@@ -152,9 +152,38 @@ will use JSON syntax, and ignore '.dev'
.HP
\fB\-\-theme\fR
.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
+.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
+.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"
diff --git a/assets/patches/1337.tmTheme.patch b/assets/patches/1337.tmTheme.patch
new file mode 100644
index 00000000..b927a74f
--- /dev/null
+++ b/assets/patches/1337.tmTheme.patch
@@ -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.
+ name
+ PHP Namespaces
+ scope
+- support.other.namespace, entity.name.type.namespace
++ support.other.namespace, entity.name.type.namespace, entity.name
+ settings
+
+ foreground
+@@ -561,7 +561,7 @@ SOFTWARE.
+ name
+ diff.header
+ scope
+- meta.diff, meta.diff.header
++ meta.diff, meta.diff.header, markup.heading
+ settings
+
+ foreground
diff --git a/assets/patches/Markdown.sublime-syntax.patch b/assets/patches/Markdown.sublime-syntax.patch
index 600b6b11..a295334c 100644
--- a/assets/patches/Markdown.sublime-syntax.patch
+++ b/assets/patches/Markdown.sublime-syntax.patch
@@ -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}}
diff --git a/assets/patches/Monokai-Extended.tmTheme.patch b/assets/patches/Monokai-Extended.tmTheme.patch
index 106b584d..ece5d49c 100644
--- a/assets/patches/Monokai-Extended.tmTheme.patch
+++ b/assets/patches/Monokai-Extended.tmTheme.patch
@@ -21,11 +21,26 @@ index 9c2aa3e..180cbbf 100644
Invalid
scope
- invalid
-+ invalid, markup.error
++ invalid, meta.annotation.error-line
settings
background
-@@ -1042,7 +1042,7 @@
+@@ -1038,11 +1038,22 @@
+ #f8f8f0
+
+
++
++ name
++ Error
++ scope
++ markup.error
++ settings
++
++ foreground
++ #dd2020
++
++
+
name
Invalid deprecated
scope
diff --git a/assets/patches/OneHalfDark.tmTheme.patch b/assets/patches/OneHalfDark.tmTheme.patch
new file mode 100644
index 00000000..1ac3e5e8
--- /dev/null
+++ b/assets/patches/OneHalfDark.tmTheme.patch
@@ -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 @@
+
+
+ name
+- OneHalfLight
++ OneHalfDark
+ semanticClass
+ theme.dark.one_half_dark
+ uuid
+@@ -155,7 +155,7 @@
+ name
+ Classes
+ scope
+- support.class, entity.name.class, entity.name.type.class
++ support.class, entity.name.class, entity.name.type.class, entity.name
+ settings
+
+ foreground
+@@ -188,7 +188,7 @@
+ name
+ Storage
+ scope
+- storage
++ storage, meta.mapping.key string
+ settings
+
+ foreground
+@@ -309,7 +309,7 @@
+ name
+ Markdown: Headings
+ scope
+- markup.heading punctuation.definition.heading, entity.name.section
++ markup.heading punctuation.definition.heading, entity.name.section, markup.heading - text.html.markdown
+ settings
+
+ fontStyle
+@@ -660,4 +660,4 @@
+
+
+
+-
+\ No newline at end of file
++
diff --git a/assets/patches/TwoDark.tmTheme.patch b/assets/patches/TwoDark.tmTheme.patch
index 05f1fc69..b6570fbc 100644
--- a/assets/patches/TwoDark.tmTheme.patch
+++ b/assets/patches/TwoDark.tmTheme.patch
@@ -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 @@
+ name
+ Classes
+ scope
+- support.class, entity.name.class, entity.name.type.class
++ support.class, entity.name.class, entity.name.type.class, entity.name
+ settings
+
+ foreground
+@@ -290,7 +290,7 @@
+ name
+ Headings
+ scope
+- markup.heading punctuation.definition.heading, entity.name.section
++ markup.heading punctuation.definition.heading, entity.name.section, markup.heading - text.html.markdown
+ settings
+
+ fontStyle
@@ -533,7 +533,7 @@
name
Json key
diff --git a/assets/syntaxes.bin b/assets/syntaxes.bin
index 7a5cd310..21043c5e 100644
Binary files a/assets/syntaxes.bin and b/assets/syntaxes.bin differ
diff --git a/assets/syntaxes/02_Extra/Apache b/assets/syntaxes/02_Extra/Apache
index 163bc03a..cf6cefc5 160000
--- a/assets/syntaxes/02_Extra/Apache
+++ b/assets/syntaxes/02_Extra/Apache
@@ -1 +1 @@
-Subproject commit 163bc03ae8998a237dfb4be353d0aea198ea17f5
+Subproject commit cf6cefc51ebb46b1b54906433edbae0fe9c71cad
diff --git a/assets/syntaxes/02_Extra/Assembly (ARM) b/assets/syntaxes/02_Extra/Assembly_(ARM)
similarity index 100%
rename from assets/syntaxes/02_Extra/Assembly (ARM)
rename to assets/syntaxes/02_Extra/Assembly_(ARM)
diff --git a/assets/syntaxes/02_Extra/CSV.sublime-syntax b/assets/syntaxes/02_Extra/CSV/CSV-comma.sublime-syntax
similarity index 71%
rename from assets/syntaxes/02_Extra/CSV.sublime-syntax
rename to assets/syntaxes/02_Extra/CSV/CSV-comma.sublime-syntax
index cca7cd2c..f23751ac 100644
--- a/assets/syntaxes/02_Extra/CSV.sublime-syntax
+++ b/assets/syntaxes/02_Extra/CSV/CSV-comma.sublime-syntax
@@ -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
diff --git a/assets/syntaxes/02_Extra/CSV/CSV-pipe.sublime-syntax b/assets/syntaxes/02_Extra/CSV/CSV-pipe.sublime-syntax
new file mode 100644
index 00000000..52103fde
--- /dev/null
+++ b/assets/syntaxes/02_Extra/CSV/CSV-pipe.sublime-syntax
@@ -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
diff --git a/assets/syntaxes/02_Extra/CSV/CSV-semi-colon.sublime-syntax b/assets/syntaxes/02_Extra/CSV/CSV-semi-colon.sublime-syntax
new file mode 100644
index 00000000..e0547ce0
--- /dev/null
+++ b/assets/syntaxes/02_Extra/CSV/CSV-semi-colon.sublime-syntax
@@ -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
diff --git a/assets/syntaxes/02_Extra/CSV/CSV.sublime-syntax b/assets/syntaxes/02_Extra/CSV/CSV.sublime-syntax
new file mode 100644
index 00000000..8ce83acb
--- /dev/null
+++ b/assets/syntaxes/02_Extra/CSV/CSV.sublime-syntax
@@ -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
diff --git a/assets/syntaxes/02_Extra/CSV/TSV.sublime-syntax b/assets/syntaxes/02_Extra/CSV/TSV.sublime-syntax
new file mode 100644
index 00000000..fdca0c31
--- /dev/null
+++ b/assets/syntaxes/02_Extra/CSV/TSV.sublime-syntax
@@ -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
diff --git a/assets/syntaxes/02_Extra/Docker b/assets/syntaxes/02_Extra/Docker
index 0f6b7bc8..c001fb28 160000
--- a/assets/syntaxes/02_Extra/Docker
+++ b/assets/syntaxes/02_Extra/Docker
@@ -1 +1 @@
-Subproject commit 0f6b7bc87acf684f7b0790fd480731ffb4615b87
+Subproject commit c001fb280561d7c16f0f2837d76af493cf6c3bf8
diff --git a/assets/syntaxes/02_Extra/GDScript-sublime b/assets/syntaxes/02_Extra/GDScript-sublime
new file mode 160000
index 00000000..96f5dcf2
--- /dev/null
+++ b/assets/syntaxes/02_Extra/GDScript-sublime
@@ -0,0 +1 @@
+Subproject commit 96f5dcf29728aa987123321e2544330eed991a3e
diff --git a/assets/syntaxes/02_Extra/HTML (Twig) b/assets/syntaxes/02_Extra/HTML_(Twig)
similarity index 100%
rename from assets/syntaxes/02_Extra/HTML (Twig)
rename to assets/syntaxes/02_Extra/HTML_(Twig)
diff --git a/assets/syntaxes/02_Extra/Idris2 b/assets/syntaxes/02_Extra/Idris2
new file mode 160000
index 00000000..7c1bf44c
--- /dev/null
+++ b/assets/syntaxes/02_Extra/Idris2
@@ -0,0 +1 @@
+Subproject commit 7c1bf44c4f9092b7b1e274b1332cf32a089b2b99
diff --git a/assets/syntaxes/02_Extra/JavaScript (Babel) b/assets/syntaxes/02_Extra/JavaScript_(Babel)
similarity index 100%
rename from assets/syntaxes/02_Extra/JavaScript (Babel)
rename to assets/syntaxes/02_Extra/JavaScript_(Babel)
diff --git a/assets/syntaxes/02_Extra/Manpage.sublime-syntax b/assets/syntaxes/02_Extra/Manpage.sublime-syntax
index 2475da8a..0779ce04 100644
--- a/assets/syntaxes/02_Extra/Manpage.sublime-syntax
+++ b/assets/syntaxes/02_Extra/Manpage.sublime-syntax
@@ -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}}'
diff --git a/assets/syntaxes/02_Extra/Nix b/assets/syntaxes/02_Extra/Nix
index 9032bd61..48c497c7 160000
--- a/assets/syntaxes/02_Extra/Nix
+++ b/assets/syntaxes/02_Extra/Nix
@@ -1 +1 @@
-Subproject commit 9032bd613746b9c135223fd6f26a5fa555f18946
+Subproject commit 48c497c709c66a2fb118c534a8de8e4e1c4c401d
diff --git a/assets/syntaxes/02_Extra/Org mode b/assets/syntaxes/02_Extra/Org mode
deleted file mode 160000
index 4976d8f8..00000000
--- a/assets/syntaxes/02_Extra/Org mode
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 4976d8f84eeecd94df7da872bf404c125df04c73
diff --git a/assets/syntaxes/02_Extra/Org_mode b/assets/syntaxes/02_Extra/Org_mode
new file mode 160000
index 00000000..bb6e5d84
--- /dev/null
+++ b/assets/syntaxes/02_Extra/Org_mode
@@ -0,0 +1 @@
+Subproject commit bb6e5d848151135ab8f87bdcb997437b2308718a
diff --git a/assets/syntaxes/02_Extra/PowerShell b/assets/syntaxes/02_Extra/PowerShell
index c0372a1d..a08b55bf 160000
--- a/assets/syntaxes/02_Extra/PowerShell
+++ b/assets/syntaxes/02_Extra/PowerShell
@@ -1 +1 @@
-Subproject commit c0372a1d2df136ca6b3d1a9f7b85031dedf117f9
+Subproject commit a08b55bf1146c210f58e844be53c2aa78fd5e610
diff --git a/assets/syntaxes/02_Extra/TOML b/assets/syntaxes/02_Extra/TOML
index fd0bf3e5..f5a57e8b 160000
--- a/assets/syntaxes/02_Extra/TOML
+++ b/assets/syntaxes/02_Extra/TOML
@@ -1 +1 @@
-Subproject commit fd0bf3e5d6c9e6397c0dc9639a0514d9bf55b800
+Subproject commit f5a57e8bff694a4e6c52a491dae579aabc7427cf
diff --git a/assets/syntaxes/02_Extra/Zig b/assets/syntaxes/02_Extra/Zig
index 1a4a3844..8a4a3fe4 160000
--- a/assets/syntaxes/02_Extra/Zig
+++ b/assets/syntaxes/02_Extra/Zig
@@ -1 +1 @@
-Subproject commit 1a4a38445fec495817625bafbeb01e79c44abcba
+Subproject commit 8a4a3fe4a051f85c4752b82f586d395cab843c06
diff --git a/assets/syntaxes/02_Extra/apt-source-list.sublime-syntax b/assets/syntaxes/02_Extra/apt-source-list.sublime-syntax
new file mode 100644
index 00000000..d5ede5b5
--- /dev/null
+++ b/assets/syntaxes/02_Extra/apt-source-list.sublime-syntax
@@ -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
diff --git a/assets/syntaxes/02_Extra/cmd-help b/assets/syntaxes/02_Extra/cmd-help
index 209559b7..c71ba410 160000
--- a/assets/syntaxes/02_Extra/cmd-help
+++ b/assets/syntaxes/02_Extra/cmd-help
@@ -1 +1 @@
-Subproject commit 209559b72f7e8848c988828088231b3a4d8b6838
+Subproject commit c71ba410bdfcc8f627df3219f14e3f2be4fe68ba
diff --git a/assets/syntaxes/02_Extra/log.sublime-syntax b/assets/syntaxes/02_Extra/log.sublime-syntax
index a68c7e83..0ce01f10 100644
--- a/assets/syntaxes/02_Extra/log.sublime-syntax
+++ b/assets/syntaxes/02_Extra/log.sublime-syntax
@@ -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:
diff --git a/assets/syntaxes/02_Extra/sublime-odin b/assets/syntaxes/02_Extra/sublime-odin
new file mode 160000
index 00000000..5d6a0ed4
--- /dev/null
+++ b/assets/syntaxes/02_Extra/sublime-odin
@@ -0,0 +1 @@
+Subproject commit 5d6a0ed41e41ec3709ec74f40686dc3761d6596e
diff --git a/assets/syntaxes/02_Extra/syntax_test_man.man b/assets/syntaxes/02_Extra/syntax_test_man.man
index 01ce1c55..5dfee5be 100644
--- a/assets/syntaxes/02_Extra/syntax_test_man.man
+++ b/assets/syntaxes/02_Extra/syntax_test_man.man
@@ -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
# ^^^^^^^^ source.c meta.preprocessor.include keyword.control.import.include
diff --git a/assets/syntaxes/02_Extra/syslog.sublime-syntax b/assets/syntaxes/02_Extra/syslog.sublime-syntax
index 1efad346..01ed58db 100644
--- a/assets/syntaxes/02_Extra/syslog.sublime-syntax
+++ b/assets/syntaxes/02_Extra/syslog.sublime-syntax
@@ -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
diff --git a/assets/themes.bin b/assets/themes.bin
index c9dfcde1..b42fa8f3 100644
Binary files a/assets/themes.bin and b/assets/themes.bin differ
diff --git a/assets/themes/Nord-sublime b/assets/themes/Nord-sublime
index 0d655b23..bf92a9e4 160000
--- a/assets/themes/Nord-sublime
+++ b/assets/themes/Nord-sublime
@@ -1 +1 @@
-Subproject commit 0d655b23d6b300e691676d9b90a68d92b267f7ec
+Subproject commit bf92a9e4457dc2f97efebc59bbeac95933ec6515
diff --git a/assets/themes/ansi.tmTheme b/assets/themes/ansi.tmTheme
index 957f42bb..f103b418 100644
--- a/assets/themes/ansi.tmTheme
+++ b/assets/themes/ansi.tmTheme
@@ -69,7 +69,7 @@
name
Labels
scope
- entity.name.label
+ entity.name.label, variable.parameter
settings
foreground
@@ -80,7 +80,7 @@
name
Classes
scope
- support.class, entity.name.class, entity.name.type.class
+ support.class, entity.name.class, entity.name.type.class, entity.name
settings
foreground
@@ -234,7 +234,7 @@
name
Headings
scope
- markup.heading punctuation.definition.heading, entity.name.section
+ markup.heading punctuation.definition.heading, entity.name.section, markup.heading - text.html.markdown
settings
fontStyle
diff --git a/assets/themes/base16-256.tmTheme b/assets/themes/base16-256.tmTheme
index a4547e56..b64b444e 100644
--- a/assets/themes/base16-256.tmTheme
+++ b/assets/themes/base16-256.tmTheme
@@ -257,7 +257,7 @@
name
Tags
scope
- entity.name.tag
+ entity.name.tag, entity.name
settings
foreground
@@ -312,7 +312,7 @@
name
Headings
scope
- markup.heading punctuation.definition.heading, entity.name.section
+ markup.heading punctuation.definition.heading, entity.name.section, markup.heading - text.html.markdown
settings
fontStyle
diff --git a/assets/themes/base16.tmTheme b/assets/themes/base16.tmTheme
index 7b030068..b49f8117 100644
--- a/assets/themes/base16.tmTheme
+++ b/assets/themes/base16.tmTheme
@@ -256,7 +256,7 @@
name
Tags
scope
- entity.name.tag
+ entity.name.tag, entity.name
settings
foreground
@@ -311,7 +311,7 @@
name
Headings
scope
- markup.heading punctuation.definition.heading, entity.name.section
+ markup.heading punctuation.definition.heading, entity.name.section, markup.heading - text.html.markdown
settings
fontStyle
diff --git a/assets/themes/sublime-snazzy b/assets/themes/sublime-snazzy
index 70343201..48f43a73 160000
--- a/assets/themes/sublime-snazzy
+++ b/assets/themes/sublime-snazzy
@@ -1 +1 @@
-Subproject commit 70343201f1d7539adbba3c79e2fe81c2559a0431
+Subproject commit 48f43a735037195021fa69d99c1180bf12f38f78
diff --git a/assets/themes/zenburn b/assets/themes/zenburn
index 86d4ee7a..9c588ebc 160000
--- a/assets/themes/zenburn
+++ b/assets/themes/zenburn
@@ -1 +1 @@
-Subproject commit 86d4ee7a1f884851a1d21d66249687f527fced32
+Subproject commit 9c588ebc11c3e6487b081bd54528af08baa8a09a
diff --git a/build/application.rs b/build/application.rs
index 459aa5b1..addbae0e 100644
--- a/build/application.rs
+++ b/build/application.rs
@@ -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(())
}
diff --git a/build/syntax_mapping.rs b/build/syntax_mapping.rs
index 91a448f6..48468b9a 100644
--- a/build/syntax_mapping.rs
+++ b/build/syntax_mapping.rs
@@ -236,8 +236,14 @@ fn get_def_paths() -> anyhow::Result> {
];
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| {
diff --git a/doc/README-ja.md b/doc/README-ja.md
index b0d52712..c906b3ec 100644
--- a/doc/README-ja.md
+++ b/doc/README-ja.md
@@ -366,7 +366,7 @@ ansible-galaxy install aeimer.install_bat
### From source
-`bat` をソースからビルドしたいならば、Rust 1.70.0 以上の環境が必要です。
+`bat` をソースからビルドしたいならば、Rust 1.74.0 以上の環境が必要です。
`cargo` を使用してビルドすることができます:
```bash
diff --git a/doc/README-ko.md b/doc/README-ko.md
index 8a10fd68..6edb8ffe 100644
--- a/doc/README-ko.md
+++ b/doc/README-ko.md
@@ -416,7 +416,7 @@ scoop install bat
### 소스에서
-`bat`의 소스를 빌드하기 위해서는, Rust 1.70.0 이상이 필요합니다.
+`bat`의 소스를 빌드하기 위해서는, Rust 1.74.0 이상이 필요합니다.
`cargo`를 이용해 전부 빌드할 수 있습니다:
```bash
diff --git a/doc/README-ru.md b/doc/README-ru.md
index 4ed91cb1..06093077 100644
--- a/doc/README-ru.md
+++ b/doc/README-ru.md
@@ -3,11 +3,11 @@
- Клон утилиты cat(1) с поддержкой выделения синтаксиса и Git
+ Клон утилиты cat(1) с поддержкой подсветки синтаксиса и Git
- Ключевые возможности •
+ Ключевые возможности •
Использование •
Установка •
Кастомизация •
@@ -19,11 +19,11 @@
[Русский]
-### Выделение синтаксиса
+### Подсветка синтаксиса
-`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
+# 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 (на выбор пользователя).
diff --git a/doc/README-zh.md b/doc/README-zh.md
index 007afb3e..b3d2f5df 100644
--- a/doc/README-zh.md
+++ b/doc/README-zh.md
@@ -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) 文件。
diff --git a/doc/assets.md b/doc/assets.md
index a06a1e67..032a7883 100644
--- a/doc/assets.md
+++ b/doc/assets.md
@@ -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.
diff --git a/doc/long-help.txt b/doc/long-help.txt
index 2b03490f..17d3395b 100644
--- a/doc/long-help.txt
+++ b/doc/long-help.txt
@@ -20,6 +20,13 @@ Options:
* unicode (␇, ␊, ␀, ..)
* caret (^G, ^J, ^@, ..)
+ --binary
+ 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
+ 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
+ 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
+ Show shell completion for a certain shell. [possible values: bash, fish, zsh, ps1]
+
--diagnostic
Show diagnostic information for bug reports.
diff --git a/doc/short-help.txt b/doc/short-help.txt
index 305bbf3d..d67a51d0 100644
--- a/doc/short-help.txt
+++ b/doc/short-help.txt
@@ -11,6 +11,8 @@ Options:
Show non-printable characters (space, tab, newline, ..).
--nonprintable-notation
Set notation for non-printable characters.
+ --binary
+ How to treat binary content. (default: no-printing)
-p, --plain...
Show plain style (alias for '--style=plain').
-l, --language
@@ -41,6 +43,10 @@ Options:
Use the specified syntax for files matching the glob pattern ('*.cpp:C++').
--theme
Set the color theme for syntax highlighting.
+ --theme-light
+ Sets the color theme for syntax highlighting used for light backgrounds.
+ --theme-dark
+ 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
+ Show shell completion for a certain shell. [possible values: bash, fish, zsh, ps1]
-h, --help
Print help (see more with '--help')
-V, --version
diff --git a/doc/sponsors/warp-logo.png b/doc/sponsors/warp-logo.png
index 4795a2b9..f99dd38c 100644
Binary files a/doc/sponsors/warp-logo.png and b/doc/sponsors/warp-logo.png differ
diff --git a/doc/sponsors/warp-pack-header.png b/doc/sponsors/warp-pack-header.png
new file mode 100644
index 00000000..ed7efe6a
Binary files /dev/null and b/doc/sponsors/warp-pack-header.png differ
diff --git a/doc/sponsors/workos-logo-white-bg.svg b/doc/sponsors/workos-logo-white-bg.svg
deleted file mode 100644
index 3c9bb24c..00000000
--- a/doc/sponsors/workos-logo-white-bg.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/examples/buffer.rs b/examples/buffer.rs
index 839689d4..eefdb249 100644
--- a/examples/buffer.rs
+++ b/examples/buffer.rs
@@ -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}");
diff --git a/src/assets.rs b/src/assets.rs
index 9655553d..e6c50219 100644
--- a/src/assets.rs
+++ b/src/assets.rs
@@ -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 and
- /// 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 {
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(
.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(),
diff --git a/src/assets/build_assets/acknowledgements.rs b/src/assets/build_assets/acknowledgements.rs
index c4fde919..db9b5c69 100644
--- a/src/assets/build_assets/acknowledgements.rs
+++ b/src/assets/build_assets/acknowledgements.rs
@@ -60,7 +60,7 @@ fn to_path_and_stem(source_dir: &Path, entry: DirEntry) -> Option {
fn handle_file(path_and_stem: &PathAndStem) -> Result> {
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)
diff --git a/src/bin/bat/app.rs b/src/bin/bat/app.rs
index d6628668..946ce5b1 100644
--- a/src/bin/bat/app.rs
+++ b/src/bin/bat/app.rs
@@ -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 {
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::("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::("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::("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::("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::("theme")
+ .map(|t| ThemePreference::from_str(t).unwrap())
+ .unwrap_or_default();
+ let theme_dark = self
+ .matches
+ .get_one::("theme-dark")
+ .map(|t| ThemeName::from_str(t).unwrap());
+ let theme_light = self
+ .matches
+ .get_one::("theme-light")
+ .map(|t| ThemeName::from_str(t).unwrap());
+ ThemeOptions {
+ theme,
+ theme_dark,
+ theme_light,
+ }
+ }
}
diff --git a/src/bin/bat/clap_app.rs b/src/bin/bat/clap_app.rs
index 33dde980..de2db078 100644
--- a/src/bin/bat/clap_app.rs
+++ b/src/bin/bat/clap_app.rs
@@ -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
diff --git a/src/bin/bat/completions.rs b/src/bin/bat/completions.rs
new file mode 100644
index 00000000..9b63a3e9
--- /dev/null
+++ b/src/bin/bat/completions.rs
@@ -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"));
diff --git a/src/bin/bat/config.rs b/src/bin/bat/config.rs
index 6fa18f09..a0ee7ba3 100644
--- a/src/bin/bat/config.rs
+++ b/src/bin/bat/config.rs
@@ -140,7 +140,9 @@ fn get_args_from_str(content: &str) -> Result, shell_words::ParseE
pub fn get_args_from_env_vars() -> Vec {
[
("--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"),
diff --git a/src/bin/bat/main.rs b/src/bin/bat/main.rs
index 4528a60b..4496032b 100644
--- a/src/bin/bat/main.rs
+++ b/src/bin/bat/main.rs
@@ -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 {
return Ok(true);
}
+ #[cfg(feature = "application")]
+ if let Some(shell) = app.matches.get_one::("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 {
};
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());
diff --git a/src/config.rs b/src/config.rs
index 8ff49ec1..622a6ca6 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -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,
diff --git a/src/controller.rs b/src/controller.rs
index 25ee2995..57720ab0 100644
--- a/src/controller.rs
+++ b/src/controller.rs
@@ -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,
}
-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 ,
- output_buffer: Option<&mut dyn std::fmt::Write>,
- ) -> Result {
- self.run_with_error_handler(inputs, output_buffer, default_error_handler)
+ pub fn run(&self, inputs: Vec , output_handle: Option>) -> Result {
+ self.run_with_error_handler(inputs, output_handle, default_error_handler)
}
pub fn run_with_error_handler(
&self,
inputs: Vec ,
- output_buffer: Option<&mut dyn std::fmt::Write>,
+ output_handle: Option>,
mut handle_error: impl FnMut(&Error, &mut dyn Write),
) -> Result {
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;
diff --git a/src/input.rs b/src/input.rs
index 0ebaa4ce..b36204df 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -75,7 +75,7 @@ pub(crate) enum InputKind<'a> {
CustomReader(Box),
}
-impl<'a> InputKind<'a> {
+impl InputKind<'_> {
pub fn description(&self) -> InputDescription {
match self {
InputKind::OrdinaryFile(ref path) => InputDescription::new(path.to_string_lossy()),
diff --git a/src/lessopen.rs b/src/lessopen.rs
index c8f5225d..79f977af 100644
--- a/src/lessopen.rs
+++ b/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,
- 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,
- command_args: Vec,
- 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();
diff --git a/src/lib.rs b/src/lib.rs
index 23c4a800..4c60f10e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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};
diff --git a/src/nonprintable_notation.rs b/src/nonprintable_notation.rs
index ff09aca6..9f8d7cb8 100644
--- a/src/nonprintable_notation.rs
+++ b/src/nonprintable_notation.rs
@@ -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,
+}
diff --git a/src/output.rs b/src/output.rs
index dc75d6e7..bb9a45d5 100644
--- a/src/output.rs
+++ b/src/output.rs
@@ -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),
+ }
+ }
+}
diff --git a/src/pretty_printer.rs b/src/pretty_printer.rs
index eb123ea3..4979bab5 100644
--- a/src/pretty_printer.rs
+++ b/src/pretty_printer.rs
@@ -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) -> &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 {
+ self.print_with_writer(None::<&mut dyn std::fmt::Write>)
+ }
+
+ /// Pretty-print all specified inputs to a specified writer.
+ pub fn print_with_writer(&mut self, writer: Option) -> Result {
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)
+ }
}
}
diff --git a/src/printer.rs b/src/printer.rs
index 64e89e76..369431ef 100644
--- a/src/printer.rs
+++ b/src/printer.rs
@@ -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;
diff --git a/src/style.rs b/src/style.rs
index b8d8b09f..d6343c94 100644
--- a/src/style.rs
+++ b/src/style.rs
@@ -225,7 +225,7 @@ impl FromStr for StyleComponentList {
fn from_str(s: &str) -> Result {
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::>>()?,
))
diff --git a/src/syntax_mapping.rs b/src/syntax_mapping.rs
index a149f9bb..0cd2d655 100644
--- a/src/syntax_mapping.rs
+++ b/src/syntax_mapping.rs
@@ -61,7 +61,7 @@ pub struct SyntaxMapping<'a> {
halt_glob_build: Arc,
}
-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);
}
diff --git a/src/syntax_mapping/builtins/common/50-citation.toml b/src/syntax_mapping/builtins/common/50-citation.toml
new file mode 100644
index 00000000..aa06b5b9
--- /dev/null
+++ b/src/syntax_mapping/builtins/common/50-citation.toml
@@ -0,0 +1,2 @@
+[mappings]
+"YAML" = ["CITATION.cff"]
diff --git a/src/syntax_mapping/builtins/common/50-diff.toml b/src/syntax_mapping/builtins/common/50-diff.toml
new file mode 100644
index 00000000..2998d9c5
--- /dev/null
+++ b/src/syntax_mapping/builtins/common/50-diff.toml
@@ -0,0 +1,3 @@
+# .debdiff is the extension used for diffs in Debian packaging
+[mappings]
+"Diff" = ["*.debdiff"]
diff --git a/src/syntax_mapping/builtins/common/50-dotnet-xml.toml b/src/syntax_mapping/builtins/common/50-dotnet-xml.toml
new file mode 100644
index 00000000..1e3a860a
--- /dev/null
+++ b/src/syntax_mapping/builtins/common/50-dotnet-xml.toml
@@ -0,0 +1,2 @@
+[mappings]
+"XML" = ["*.csproj", "*.vbproj", "*.props", "*.targets"]
diff --git a/src/syntax_mapping/builtins/common/50-json.toml b/src/syntax_mapping/builtins/common/50-json.toml
index 7d33b6fe..6b3252e8 100644
--- a/src/syntax_mapping/builtins/common/50-json.toml
+++ b/src/syntax_mapping/builtins/common/50-json.toml
@@ -1,3 +1,3 @@
# JSON Lines is a simple variation of JSON #2535
[mappings]
-"JSON" = ["*.jsonl", "*.jsonc", "*.jsonld"]
+"JSON" = ["*.jsonl", "*.jsonc", "*.jsonld", "*.geojson", "*.ndjson"]
diff --git a/src/syntax_mapping/builtins/common/50-markdown.toml b/src/syntax_mapping/builtins/common/50-markdown.toml
new file mode 100644
index 00000000..aa0531d2
--- /dev/null
+++ b/src/syntax_mapping/builtins/common/50-markdown.toml
@@ -0,0 +1,2 @@
+[mappings]
+"Markdown" = ["*.mkd"]
diff --git a/src/syntax_mapping/builtins/common/50-nix.toml b/src/syntax_mapping/builtins/common/50-nix.toml
new file mode 100644
index 00000000..e2d2fcbb
--- /dev/null
+++ b/src/syntax_mapping/builtins/common/50-nix.toml
@@ -0,0 +1,2 @@
+[mappings]
+"JSON" = ["flake.lock"]
diff --git a/src/syntax_mapping/builtins/linux/50-kubernetes.toml b/src/syntax_mapping/builtins/linux/50-kubernetes.toml
new file mode 100644
index 00000000..6a81a35a
--- /dev/null
+++ b/src/syntax_mapping/builtins/linux/50-kubernetes.toml
@@ -0,0 +1,2 @@
+[mappings]
+"YAML" = ["/etc/kubernetes/*.conf"]
diff --git a/src/syntax_mapping/builtins/linux/50-pacman.toml b/src/syntax_mapping/builtins/linux/50-pacman.toml
index 655118c5..2f4ee71f 100644
--- a/src/syntax_mapping/builtins/linux/50-pacman.toml
+++ b/src/syntax_mapping/builtins/linux/50-pacman.toml
@@ -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",
+]
diff --git a/src/syntax_mapping/builtins/linux/50-paru.toml b/src/syntax_mapping/builtins/linux/50-paru.toml
new file mode 100644
index 00000000..2706a36e
--- /dev/null
+++ b/src/syntax_mapping/builtins/linux/50-paru.toml
@@ -0,0 +1,6 @@
+# See https://github.com/Morganamilo/paru/blob/master/man/paru.conf.5
+[mappings]
+"INI" = [
+ "${PARU_CONF}",
+ "paru.conf",
+]
diff --git a/src/syntax_mapping/builtins/unix-family/50-apache.toml b/src/syntax_mapping/builtins/unix-family/50-apache.toml
index dfb920f3..7394dafc 100644
--- a/src/syntax_mapping/builtins/unix-family/50-apache.toml
+++ b/src/syntax_mapping/builtins/unix-family/50-apache.toml
@@ -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"]
diff --git a/src/syntax_mapping/builtins/unix-family/50-shell.toml b/src/syntax_mapping/builtins/unix-family/50-shell.toml
index d015ca81..cd59a84e 100644
--- a/src/syntax_mapping/builtins/unix-family/50-shell.toml
+++ b/src/syntax_mapping/builtins/unix-family/50-shell.toml
@@ -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"
]
diff --git a/src/theme.rs b/src/theme.rs
new file mode 100644
index 00000000..b2903b86
--- /dev/null
+++ b/src/theme.rs
@@ -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 {
+ 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,
+ /// 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,
+}
+
+/// 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) -> 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 {
+ 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) -> 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 {
+ 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,
+}
+
+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, 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 {
+ match color_scheme {
+ ColorScheme::Dark => options.theme_dark,
+ ColorScheme::Light => options.theme_light,
+ }
+}
+
+fn color_scheme_impl(
+ when: DetectColorScheme,
+ detector: &dyn ColorSchemeDetector,
+) -> Option {
+ 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;
+}
+
+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 {
+ 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 {
+ crate::bat_warning!(
+ "Theme 'auto:system' is only supported on macOS, \
+ using default."
+ );
+ None
+}
+
+#[cfg(target_os = "macos")]
+fn color_scheme_from_system() -> Option {
+ 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 {
+ fn should_detect(&self) -> bool {
+ true
+ }
+
+ fn detect(&self) -> Option {
+ *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,
+ was_called: Cell,
+ }
+
+ impl DetectorStub {
+ fn should_detect(color_scheme: Option) -> 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 {
+ self.was_called.set(true);
+ self.color_scheme
+ }
+ }
+
+ struct ConstantDetector(Option);
+
+ impl ColorSchemeDetector for ConstantDetector {
+ fn should_detect(&self) -> bool {
+ true
+ }
+
+ fn detect(&self) -> Option {
+ self.0
+ }
+ }
+
+ fn optional(value: impl Iterator- ) -> impl Iterator
- > {
+ value.map(Some).chain(iter::once(None))
+ }
+
+ fn color_schemes() -> impl Iterator
- {
+ [Dark, Light].into_iter()
+ }
+}
diff --git a/src/vscreen.rs b/src/vscreen.rs
index 9e29f9cc..06cc038a 100644
--- a/src/vscreen.rs
+++ b/src/vscreen.rs
@@ -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
{
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),
- };
+ }
}
}
diff --git a/tests/examples/test.A—B가 b/tests/examples/test.A—B가
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/github-actions.rs b/tests/github-actions.rs
index c902f10b..d697ddf8 100644
--- a/tests/github-actions.rs
+++ b/tests/github-actions.rs
@@ -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::>();
diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs
index 1502c7c1..5a97c517 100644
--- a/tests/integration_tests.rs
+++ b/tests/integration_tests.rs
@@ -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
diff --git a/tests/syntax-tests/compare_highlighted_versions.py b/tests/syntax-tests/compare_highlighted_versions.py
index 9cf67e46..ad142e9f 100755
--- a/tests/syntax-tests/compare_highlighted_versions.py
+++ b/tests/syntax-tests/compare_highlighted_versions.py
@@ -12,13 +12,15 @@ def compare_highlighted_versions(root_old, root_new):
print(" -", root_old)
print(" -", root_new)
has_changes = False
+ # Used to check for newly added files that don't have a test
+ unknown_files = {strip_root(p) for p in glob.glob(path.join(root_new, "*", "*"))}
+
for path_old in glob.glob(path.join(root_old, "*", "*")):
- filename = path.basename(path_old)
- dirname = path.basename(path.dirname(path_old))
+ rel_path = strip_root(path_old)
+ unknown_files.discard(rel_path)
+ path_new = path.join(root_new, rel_path)
- path_new = path.join(root_new, dirname, filename)
-
- print("\n========== {}/{}".format(dirname, filename))
+ print("\n========== {}".format(rel_path))
with open(path_old) as file_old:
lines_old = file_old.readlines()
@@ -39,11 +41,21 @@ def compare_highlighted_versions(root_old, root_new):
has_changes = True
else:
print("No changes")
- print()
+ for f in unknown_files:
+ print("\n========== {}: No fixture for this language, run update.sh".format(f))
+ has_changes = True
+
+ print()
return has_changes
+def strip_root(p: str) -> str:
+ filename = path.basename(p)
+ dirname = path.basename(path.dirname(p))
+ return path.join(dirname, filename)
+
+
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="This script compares two directories that were created "
diff --git a/tests/syntax-tests/highlighted/CSV/comma-delimited.csv b/tests/syntax-tests/highlighted/CSV/comma-delimited.csv
new file mode 100644
index 00000000..05285a7c
--- /dev/null
+++ b/tests/syntax-tests/highlighted/CSV/comma-delimited.csv
@@ -0,0 +1,3 @@
+[3;38;2;253;151;31mfoo[0m[38;2;253;151;31m,[0m[38;2;102;217;239mbar[0m[38;2;253;151;31m,[0m[38;2;190;132;255mbaz[0m[38;2;253;151;31m,[0m[38;2;249;38;114mthis|that[0m[38;2;253;151;31m,[0m[38;2;230;219;116mtest[0m[38;2;253;151;31m,[0m[3;38;2;253;151;31mcolors[0m[38;2;253;151;31m,[0m[38;2;102;217;239mcycle[0m
+[3;38;2;253;151;31m1.2[0m[38;2;253;151;31m,[0m[38;2;102;217;239m1.7[0m[38;2;253;151;31m,[0m[38;2;190;132;255m2.5[0m[38;2;253;151;31m,[0m[38;2;249;38;114mblah;cool[0m[38;2;253;151;31m,[0m[38;2;230;219;116mtest[0m[38;2;253;151;31m,[0m[3;38;2;253;151;31mcolors[0m[38;2;253;151;31m,[0m[38;2;102;217;239mcycle[0m
+
diff --git a/tests/syntax-tests/highlighted/CSV/comma_in_quotes.csv b/tests/syntax-tests/highlighted/CSV/comma_in_quotes.csv
index 9bd0da1a..8f4004a0 100644
--- a/tests/syntax-tests/highlighted/CSV/comma_in_quotes.csv
+++ b/tests/syntax-tests/highlighted/CSV/comma_in_quotes.csv
@@ -1,7 +1,7 @@
-[3;38;2;166;226;46mfirst[0m[38;2;253;151;31m,[0m[38;2;102;217;239mlast[0m[38;2;253;151;31m,[0m[38;2;190;132;255maddress[0m[38;2;253;151;31m,[0m[38;2;249;38;114mcity[0m[38;2;253;151;31m,[0m[3;38;2;166;226;46mzip[0m
-[3;38;2;166;226;46mJohn[0m[38;2;253;151;31m,[0m[38;2;102;217;239mDoe[0m[38;2;253;151;31m,[0m[38;2;190;132;255m120 any st.[0m[38;2;253;151;31m,[0m[38;2;230;219;116m"[0m[38;2;230;219;116mAnytown, WW[0m[38;2;230;219;116m"[0m[38;2;253;151;31m,[0m[3;38;2;166;226;46m08123[0m
-[3;38;2;166;226;46ma[0m[38;2;253;151;31m,[0m[38;2;102;217;239mb[0m
-[3;38;2;166;226;46m1[0m[38;2;253;151;31m,[0m[38;2;230;219;116m"[0m[38;2;230;219;116mha [0m
+[3;38;2;253;151;31mfirst[0m[38;2;253;151;31m,[0m[38;2;102;217;239mlast[0m[38;2;253;151;31m,[0m[38;2;190;132;255maddress[0m[38;2;253;151;31m,[0m[38;2;249;38;114mcity[0m[38;2;253;151;31m,[0m[38;2;230;219;116mzip[0m
+[3;38;2;253;151;31mJohn[0m[38;2;253;151;31m,[0m[38;2;102;217;239mDoe[0m[38;2;253;151;31m,[0m[38;2;190;132;255m120 any st.[0m[38;2;253;151;31m,[0m[38;2;230;219;116m"[0m[38;2;230;219;116mAnytown, WW[0m[38;2;230;219;116m"[0m[38;2;253;151;31m,[0m[38;2;230;219;116m08123[0m
+[3;38;2;253;151;31ma[0m[38;2;253;151;31m,[0m[38;2;102;217;239mb[0m
+[3;38;2;253;151;31m1[0m[38;2;253;151;31m,[0m[38;2;230;219;116m"[0m[38;2;230;219;116mha [0m
[38;2;190;132;255m""[0m[38;2;230;219;116mha[0m[38;2;190;132;255m""[0m[38;2;230;219;116m [0m
-[38;2;230;219;116mha[0m[38;2;230;219;116m"[0m[38;2;253;151;31m,[0m[38;2;190;132;255m120 any st.[0m[38;2;253;151;31m,[0m[38;2;230;219;116m"[0m[38;2;230;219;116mAnytown, WW[0m[38;2;230;219;116m"[0m[38;2;253;151;31m,[0m[3;38;2;166;226;46m08123[0m
-[3;38;2;166;226;46m3[0m[38;2;253;151;31m,[0m[38;2;102;217;239m4[0m[38;2;253;151;31m,[0m[38;2;190;132;255m120 any st.[0m[38;2;253;151;31m,[0m[38;2;230;219;116m"[0m[38;2;230;219;116mAnytown, WW[0m[38;2;230;219;116m"[0m[38;2;253;151;31m,[0m[3;38;2;166;226;46m08123[0m
+[38;2;230;219;116mha[0m[38;2;230;219;116m"[0m[38;2;253;151;31m,[0m[38;2;190;132;255m120 any st.[0m[38;2;253;151;31m,[0m[38;2;230;219;116m"[0m[38;2;230;219;116mAnytown, WW[0m[38;2;230;219;116m"[0m[38;2;253;151;31m,[0m[38;2;230;219;116m08123[0m
+[3;38;2;253;151;31m3[0m[38;2;253;151;31m,[0m[38;2;102;217;239m4[0m[38;2;253;151;31m,[0m[38;2;190;132;255m120 any st.[0m[38;2;253;151;31m,[0m[38;2;230;219;116m"[0m[38;2;230;219;116mAnytown, WW[0m[38;2;230;219;116m"[0m[38;2;253;151;31m,[0m[38;2;230;219;116m08123[0m
diff --git a/tests/syntax-tests/highlighted/CSV/decimals_comma_decimal_point_pipe_delimited.csv b/tests/syntax-tests/highlighted/CSV/decimals_comma_decimal_point_pipe_delimited.csv
new file mode 100644
index 00000000..843264e6
--- /dev/null
+++ b/tests/syntax-tests/highlighted/CSV/decimals_comma_decimal_point_pipe_delimited.csv
@@ -0,0 +1,3 @@
+[3;38;2;253;151;31mfoo[0m[38;2;253;151;31m|[0m[38;2;102;217;239mbar[0m[38;2;253;151;31m|[0m[38;2;190;132;255mbaz[0m
+[3;38;2;253;151;31m1,2[0m[38;2;253;151;31m|[0m[38;2;102;217;239m1,7[0m[38;2;253;151;31m|[0m[38;2;190;132;255m2,7[0m
+[3;38;2;253;151;31m1,5[0m[38;2;253;151;31m|[0m[38;2;102;217;239m8,5[0m[38;2;253;151;31m|[0m[38;2;190;132;255m-5,5[0m
diff --git a/tests/syntax-tests/highlighted/CSV/decimals_comma_decimal_point_semicolon_delimited.csv b/tests/syntax-tests/highlighted/CSV/decimals_comma_decimal_point_semicolon_delimited.csv
new file mode 100644
index 00000000..da1b0704
--- /dev/null
+++ b/tests/syntax-tests/highlighted/CSV/decimals_comma_decimal_point_semicolon_delimited.csv
@@ -0,0 +1,3 @@
+[3;38;2;253;151;31mfoo[0m[38;2;253;151;31m;[0m[38;2;102;217;239mbar[0m[38;2;253;151;31m;[0m[38;2;190;132;255mbaz[0m
+[3;38;2;253;151;31m1,2[0m[38;2;253;151;31m;[0m[38;2;102;217;239m1,7[0m[38;2;253;151;31m;[0m[38;2;190;132;255m2,7[0m
+[3;38;2;253;151;31m1,5[0m[38;2;253;151;31m;[0m[38;2;102;217;239m8,5[0m[38;2;253;151;31m;[0m[38;2;190;132;255m-5,5[0m
diff --git a/tests/syntax-tests/highlighted/CSV/simple.tsv b/tests/syntax-tests/highlighted/CSV/simple.tsv
new file mode 100644
index 00000000..7dd1a9de
--- /dev/null
+++ b/tests/syntax-tests/highlighted/CSV/simple.tsv
@@ -0,0 +1,3 @@
+[3;38;2;253;151;31mfoo[0m[38;2;253;151;31m [0m[38;2;102;217;239mbar[0m[38;2;253;151;31m [0m[38;2;190;132;255mbaz|;,[0m[38;2;253;151;31m [0m[38;2;249;38;114mtest[0m[38;2;253;151;31m [0m[38;2;230;219;116mhello world[0m[38;2;253;151;31m [0m[3;38;2;253;151;31mtsv[0m
+[3;38;2;253;151;31m1,2[0m[38;2;253;151;31m [0m[38;2;102;217;239m1,7[0m[38;2;253;151;31m [0m[38;2;190;132;255m2,7[0m[38;2;253;151;31m [0m[38;2;249;38;114ma b c[0m[38;2;253;151;31m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mhello again[0m[38;2;230;219;116m"[0m[38;2;253;151;31m [0m[3;38;2;253;151;31mtsv[0m
+[3;38;2;230;219;116m"[0m[3;38;2;230;219;116m;|,[0m[3;38;2;230;219;116m"[0m[38;2;253;151;31m [0m[38;2;102;217;239m;|,[0m[38;2;253;151;31m [0m[38;2;190;132;255mbaz[0m[38;2;253;151;31m [0m[38;2;249;38;114mtest[0m[38;2;253;151;31m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mhello world[0m[38;2;230;219;116m"[0m[38;2;253;151;31m [0m[3;38;2;253;151;31mtsv[0m
diff --git a/tests/syntax-tests/highlighted/GDScript/test.gd b/tests/syntax-tests/highlighted/GDScript/test.gd
new file mode 100644
index 00000000..4ea498cf
--- /dev/null
+++ b/tests/syntax-tests/highlighted/GDScript/test.gd
@@ -0,0 +1,71 @@
+[38;2;249;38;114mextends[0m[3;4;38;2;166;226;46m Node[0m
+
+[3;38;2;102;217;239msignal[0m[38;2;248;248;242m [0m[38;2;166;226;46mcustom_signal[0m[38;2;248;248;242m([0m[3;38;2;253;151;31mparam[0m[38;2;248;248;242m)[0m
+
+[3;38;2;102;217;239mconst[0m[38;2;248;248;242m [0m[38;2;255;255;255mPI[0m[38;2;248;248;242m [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;190;132;255m3.14159[0m
+
+[3;38;2;102;217;239mvar[0m[38;2;248;248;242m [0m[38;2;255;255;255muntyped_var[0m[38;2;248;248;242m [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mHello, World![0m[38;2;230;219;116m"[0m
+[3;38;2;102;217;239mvar[0m[38;2;248;248;242m [0m[38;2;255;255;255mtyped_int[0m[38;2;248;248;242m: [0m[3;38;2;102;217;239mint[0m[38;2;248;248;242m [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;190;132;255m42[0m
+[3;38;2;102;217;239mvar[0m[38;2;248;248;242m [0m[38;2;255;255;255mtyped_float[0m[38;2;248;248;242m: [0m[3;38;2;102;217;239mfloat[0m[38;2;248;248;242m [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;190;132;255m3.14[0m
+[3;38;2;102;217;239mvar[0m[38;2;248;248;242m [0m[38;2;255;255;255mtyped_string[0m[38;2;248;248;242m: [0m[3;38;2;102;217;239mString[0m[38;2;248;248;242m [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mGDScript Test[0m[38;2;230;219;116m"[0m
+[3;38;2;102;217;239mvar[0m[38;2;248;248;242m [0m[38;2;255;255;255mtyped_array[0m[38;2;248;248;242m: [0m[3;38;2;102;217;239mArray[0m[38;2;248;248;242m [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [[0m[38;2;190;132;255m1[0m[38;2;248;248;242m, [0m[38;2;190;132;255m2[0m[38;2;248;248;242m, [0m[38;2;190;132;255m3[0m[38;2;248;248;242m, [0m[38;2;190;132;255m4[0m[38;2;248;248;242m][0m
+[3;38;2;102;217;239mvar[0m[38;2;248;248;242m [0m[38;2;255;255;255mtyped_dict[0m[38;2;248;248;242m: [0m[3;38;2;102;217;239mDictionary[0m[38;2;248;248;242m [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;248;248;242m{[0m[38;2;230;219;116m"[0m[38;2;230;219;116mkey[0m[38;2;230;219;116m"[0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mvalue[0m[38;2;230;219;116m"[0m[38;2;248;248;242m,[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mnumber[0m[38;2;230;219;116m"[0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;190;132;255m100[0m[38;2;248;248;242m}[0m
+
+[38;2;249;38;114monready[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mvar[0m[38;2;248;248;242m [0m[38;2;255;255;255mlabel[0m[38;2;248;248;242m [0m[38;2;249;38;114m=[0m[38;2;248;248;242m $Label[0m
+
+[3;38;2;102;217;239mfunc[0m[38;2;248;248;242m [0m[38;2;166;226;46msay_hello[0m[38;2;248;248;242m([0m[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mvoid[0m[38;2;248;248;242m:[0m
+[38;2;248;248;242m [0m[38;2;248;248;242mprint[0m[38;2;248;248;242m([0m[38;2;230;219;116m"[0m[38;2;230;219;116mHello from GDScript![0m[38;2;230;219;116m"[0m[38;2;248;248;242m)[0m
+
+[3;38;2;102;217;239mfunc[0m[38;2;248;248;242m [0m[38;2;166;226;46madd_numbers[0m[38;2;248;248;242m([0m[3;38;2;253;151;31ma[0m[38;2;248;248;242m: [0m[3;38;2;253;151;31mint[0m[38;2;248;248;242m,[0m[38;2;248;248;242m [0m[3;38;2;253;151;31mb[0m[38;2;248;248;242m: [0m[3;38;2;253;151;31mint[0m[38;2;248;248;242m = 10[0m[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mint[0m[38;2;248;248;242m:[0m
+[38;2;248;248;242m [0m[38;2;249;38;114mreturn[0m[38;2;248;248;242m a [0m[38;2;249;38;114m+[0m[38;2;248;248;242m b[0m
+
+[3;38;2;102;217;239mfunc[0m[38;2;248;248;242m [0m[38;2;166;226;46mprocess_value[0m[38;2;248;248;242m([0m[3;38;2;253;151;31mvalue[0m[38;2;248;248;242m: [0m[3;38;2;253;151;31mint[0m[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mString[0m[38;2;248;248;242m:[0m
+[38;2;248;248;242m [0m[38;2;249;38;114mif[0m[38;2;248;248;242m value [0m[38;2;249;38;114m<[0m[38;2;248;248;242m [0m[38;2;190;132;255m0[0m[38;2;248;248;242m:[0m
+[38;2;248;248;242m [0m[38;2;249;38;114mreturn[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mNegative[0m[38;2;230;219;116m"[0m
+[38;2;248;248;242m [0m[38;2;249;38;114melif[0m[38;2;248;248;242m value [0m[38;2;249;38;114m==[0m[38;2;248;248;242m [0m[38;2;190;132;255m0[0m[38;2;248;248;242m:[0m
+[38;2;248;248;242m [0m[38;2;249;38;114mreturn[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mZero[0m[38;2;230;219;116m"[0m
+[38;2;248;248;242m [0m[38;2;249;38;114melse[0m[38;2;248;248;242m:[0m
+[38;2;248;248;242m [0m[38;2;249;38;114mreturn[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mPositive[0m[38;2;230;219;116m"[0m
+
+[3;38;2;102;217;239mfunc[0m[38;2;248;248;242m [0m[38;2;166;226;46msum_array[0m[38;2;248;248;242m([0m[3;38;2;253;151;31marr[0m[38;2;248;248;242m: [0m[3;38;2;253;151;31mArray[0m[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mint[0m[38;2;248;248;242m:[0m
+[38;2;248;248;242m [0m[3;38;2;102;217;239mvar[0m[38;2;248;248;242m [0m[38;2;255;255;255mtotal[0m[38;2;248;248;242m: [0m[3;38;2;102;217;239mint[0m[38;2;248;248;242m [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;190;132;255m0[0m
+[38;2;248;248;242m [0m[38;2;249;38;114mfor[0m[38;2;248;248;242m num [0m[38;2;249;38;114min[0m[38;2;248;248;242m arr:[0m
+[38;2;248;248;242m total [0m[38;2;249;38;114m+=[0m[38;2;248;248;242m num[0m
+[38;2;248;248;242m [0m[38;2;249;38;114mreturn[0m[38;2;248;248;242m total[0m
+
+[3;38;2;102;217;239mfunc[0m[38;2;248;248;242m [0m[38;2;166;226;46mdescribe_number[0m[38;2;248;248;242m([0m[3;38;2;253;151;31mnum[0m[38;2;248;248;242m: [0m[3;38;2;253;151;31mint[0m[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mString[0m[38;2;248;248;242m:[0m
+[38;2;248;248;242m [0m[38;2;249;38;114mmatch[0m[38;2;248;248;242m num:[0m
+[38;2;248;248;242m [0m[38;2;190;132;255m0[0m[38;2;248;248;242m:[0m
+[38;2;248;248;242m [0m[38;2;249;38;114mreturn[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mZero[0m[38;2;230;219;116m"[0m
+[38;2;248;248;242m [0m[38;2;190;132;255m1[0m[38;2;248;248;242m, [0m[38;2;190;132;255m2[0m[38;2;248;248;242m, [0m[38;2;190;132;255m3[0m[38;2;248;248;242m:[0m
+[38;2;248;248;242m [0m[38;2;249;38;114mreturn[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mSmall number[0m[38;2;230;219;116m"[0m
+[38;2;248;248;242m _:[0m
+[38;2;248;248;242m [0m[38;2;249;38;114mreturn[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mLarge number[0m[38;2;230;219;116m"[0m
+
+[3;38;2;102;217;239mfunc[0m[38;2;248;248;242m [0m[38;2;166;226;46mlong_description[0m[38;2;248;248;242m([0m[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mString[0m[38;2;248;248;242m:[0m
+[38;2;248;248;242m [0m[38;2;249;38;114mreturn[0m[38;2;248;248;242m [0m[38;2;230;219;116m"""[0m[38;2;230;219;116mThis is a test file for GDScript.[0m
+[38;2;230;219;116mIt covers variables, functions, control structures, loops, signals, inner classes,[0m
+[38;2;230;219;116mmultiline strings, arrays, and dictionaries.[0m[38;2;230;219;116m"""[0m
+
+[3;38;2;102;217;239mclass[0m[38;2;248;248;242m [0m[38;2;166;226;46mInnerExample[0m[38;2;248;248;242m:[0m
+[38;2;248;248;242m [0m[3;38;2;102;217;239mvar[0m[38;2;248;248;242m [0m[38;2;255;255;255minner_value[0m[38;2;248;248;242m: [0m[3;38;2;102;217;239mint[0m[38;2;248;248;242m [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;190;132;255m99[0m
+[38;2;248;248;242m [0m[3;38;2;102;217;239mfunc[0m[38;2;248;248;242m [0m[38;2;166;226;46mshow_value[0m[38;2;248;248;242m([0m[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mvoid[0m[38;2;248;248;242m:[0m
+[38;2;248;248;242m [0m[38;2;248;248;242mprint[0m[38;2;248;248;242m([0m[38;2;230;219;116m"[0m[38;2;230;219;116mInner value is:[0m[38;2;230;219;116m"[0m[38;2;248;248;242m,[0m[38;2;248;248;242m inner_value[0m[38;2;248;248;242m)[0m
+
+[3;38;2;102;217;239mfunc[0m[38;2;248;248;242m [0m[38;2;166;226;46mtest_inner_class[0m[38;2;248;248;242m([0m[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mvoid[0m[38;2;248;248;242m:[0m
+[38;2;248;248;242m [0m[3;38;2;102;217;239mvar[0m[38;2;248;248;242m [0m[38;2;255;255;255minner[0m[38;2;248;248;242m [0m[38;2;249;38;114m=[0m[38;2;248;248;242m InnerExample.[0m[38;2;248;248;242mnew[0m[38;2;248;248;242m([0m[38;2;248;248;242m)[0m
+[38;2;248;248;242m inner.[0m[38;2;248;248;242mshow_value[0m[38;2;248;248;242m([0m[38;2;248;248;242m)[0m
+
+[3;38;2;102;217;239mfunc[0m[38;2;248;248;242m [0m[38;2;166;226;46mtrigger_signal[0m[38;2;248;248;242m([0m[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mvoid[0m[38;2;248;248;242m:[0m
+[38;2;248;248;242m [0m[38;2;248;248;242memit_signal[0m[38;2;248;248;242m([0m[38;2;230;219;116m"[0m[38;2;230;219;116mcustom_signal[0m[38;2;230;219;116m"[0m[38;2;248;248;242m,[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mTestParam[0m[38;2;230;219;116m"[0m[38;2;248;248;242m)[0m
+
+[3;38;2;102;217;239mfunc[0m[38;2;248;248;242m [0m[38;2;166;226;46m_ready[0m[38;2;248;248;242m([0m[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mvoid[0m[38;2;248;248;242m:[0m
+[38;2;248;248;242m [0m[38;2;248;248;242msay_hello[0m[38;2;248;248;242m([0m[38;2;248;248;242m)[0m
+[38;2;248;248;242m [0m[3;38;2;102;217;239mvar[0m[38;2;248;248;242m [0m[38;2;255;255;255mresult_add[0m[38;2;248;248;242m [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;248;248;242madd_numbers[0m[38;2;248;248;242m([0m[38;2;190;132;255m5[0m[38;2;248;248;242m)[0m
+[38;2;248;248;242m [0m[38;2;248;248;242mprint[0m[38;2;248;248;242m([0m[38;2;230;219;116m"[0m[38;2;230;219;116mAdd result:[0m[38;2;230;219;116m"[0m[38;2;248;248;242m,[0m[38;2;248;248;242m result_add[0m[38;2;248;248;242m)[0m
+[38;2;248;248;242m [0m[38;2;248;248;242mprint[0m[38;2;248;248;242m([0m[38;2;230;219;116m"[0m[38;2;230;219;116mProcess value for -5:[0m[38;2;230;219;116m"[0m[38;2;248;248;242m,[0m[38;2;248;248;242m [0m[38;2;248;248;242mprocess_value[0m[38;2;248;248;242m([0m[38;2;249;38;114m-[0m[38;2;190;132;255m5[0m[38;2;248;248;242m)[0m[38;2;248;248;242m)[0m
+[38;2;248;248;242m [0m[38;2;248;248;242mprint[0m[38;2;248;248;242m([0m[38;2;230;219;116m"[0m[38;2;230;219;116mSum of array [10, 20, 30]:[0m[38;2;230;219;116m"[0m[38;2;248;248;242m,[0m[38;2;248;248;242m [0m[38;2;248;248;242msum_array[0m[38;2;248;248;242m([0m[38;2;248;248;242m[[0m[38;2;190;132;255m10[0m[38;2;248;248;242m,[0m[38;2;248;248;242m [0m[38;2;190;132;255m20[0m[38;2;248;248;242m,[0m[38;2;248;248;242m [0m[38;2;190;132;255m30[0m[38;2;248;248;242m][0m[38;2;248;248;242m)[0m[38;2;248;248;242m)[0m
+[38;2;248;248;242m [0m[38;2;248;248;242mprint[0m[38;2;248;248;242m([0m[38;2;230;219;116m"[0m[38;2;230;219;116mDescription for 2:[0m[38;2;230;219;116m"[0m[38;2;248;248;242m,[0m[38;2;248;248;242m [0m[38;2;248;248;242mdescribe_number[0m[38;2;248;248;242m([0m[38;2;190;132;255m2[0m[38;2;248;248;242m)[0m[38;2;248;248;242m)[0m
+[38;2;248;248;242m [0m[38;2;248;248;242mprint[0m[38;2;248;248;242m([0m[38;2;230;219;116m"[0m[38;2;230;219;116mLong description:\n[0m[38;2;230;219;116m"[0m[38;2;248;248;242m,[0m[38;2;248;248;242m [0m[38;2;248;248;242mlong_description[0m[38;2;248;248;242m([0m[38;2;248;248;242m)[0m[38;2;248;248;242m)[0m
+[38;2;248;248;242m [0m[38;2;248;248;242mtest_inner_class[0m[38;2;248;248;242m([0m[38;2;248;248;242m)[0m
+[38;2;248;248;242m [0m[38;2;248;248;242mtrigger_signal[0m[38;2;248;248;242m([0m[38;2;248;248;242m)[0m
diff --git a/tests/syntax-tests/highlighted/Idris2/test.idr b/tests/syntax-tests/highlighted/Idris2/test.idr
new file mode 100644
index 00000000..04691268
--- /dev/null
+++ b/tests/syntax-tests/highlighted/Idris2/test.idr
@@ -0,0 +1,107 @@
+[38;2;117;113;94m-- some code in Idris[0m
+[38;2;249;38;114mmodule[0m[38;2;248;248;242m [0m[38;2;166;226;46mXX.X'''[0m
+
+[38;2;249;38;114mimport[0m[38;2;248;248;242m [0m[38;2;166;226;46mData.Nat[0m
+
+[38;2;249;38;114mdata[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mX[0m[38;2;248;248;242m [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mA[0m[38;2;248;248;242m [0m[38;2;249;38;114m|[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mB[0m
+
+[38;2;249;38;114mnamespace[0m[38;2;248;248;242m [0m[38;2;166;226;46mX[0m
+[38;2;248;248;242m [0m[38;2;117;113;94m||| Documentation[0m
+[38;2;248;248;242m [0m[38;2;249;38;114mrecord[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mY[0m[38;2;248;248;242m [0m[38;2;249;38;114mwhere[0m
+[38;2;248;248;242m [0m[38;2;249;38;114m[[0m[38;2;248;248;242mnoHints[0m[38;2;249;38;114m][0m
+[38;2;248;248;242m [0m[38;2;249;38;114mconstructor[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mMkY'[0m
+[38;2;248;248;242m [0m[38;2;166;226;46mfield1[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mNat[0m
+[38;2;248;248;242m [0m[38;2;248;248;242m{[0m[38;2;249;38;114mauto[0m[38;2;248;248;242m [0m[3;38;2;253;151;31mx[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mNat[0m[38;2;248;248;242m}[0m
+
+[38;2;249;38;114mnamespace[0m[38;2;248;248;242m [0m[38;2;166;226;46mX'[0m[38;2;248;248;242m [0m[38;2;249;38;114m{[0m
+[38;2;248;248;242m [0m[38;2;249;38;114mparameters[0m[38;2;248;248;242m [0m[38;2;248;248;242m([0m[3;38;2;253;151;31mx[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mA[0m[38;2;248;248;242m [0m[38;2;249;38;114m([0m[3;38;2;102;217;239mMaybe[0m[38;2;248;248;242m b[0m[38;2;249;38;114m)[0m[38;2;248;248;242m)[0m
+[38;2;248;248;242m [0m[38;2;166;226;46mx[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mNat[0m
+[38;2;249;38;114m}[0m
+
+[38;2;166;226;46mu[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239m()[0m
+[38;2;248;248;242mu [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[3;38;2;102;217;239m()[0m
+
+[38;2;166;226;46mk[0m[38;2;248;248;242m, [0m[38;2;166;226;46mw[0m[38;2;248;248;242m, [0m[38;2;166;226;46mu[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mChar[0m
+[38;2;248;248;242mk [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;190;132;255m'[0m[38;2;190;132;255m\NUL[0m[38;2;190;132;255m'[0m
+[38;2;248;248;242mw [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;190;132;255m'[0m[38;2;190;132;255mw[0m[38;2;190;132;255m'[0m
+
+[38;2;248;248;242mx [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;249;38;114m[[0m[38;2;190;132;255m1[0m[38;2;249;38;114m,[0m[38;2;248;248;242m [0m[38;2;190;132;255m0[0m[38;2;249;38;114m,[0m[38;2;248;248;242m [0m[38;2;190;132;255m3[0m[38;2;249;38;114m,[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116msdf[0m[38;2;248;248;242m\{[0m[38;2;248;248;242md[0m[38;2;248;248;242m}[0m[38;2;230;219;116m"[0m[38;2;249;38;114m,[0m[38;2;248;248;242m [0m[38;2;190;132;255m0xFF[0m[38;2;249;38;114m,[0m[38;2;248;248;242m [0m[38;2;190;132;255m0o77[0m[38;2;249;38;114m,[0m[38;2;248;248;242m [0m[38;2;190;132;255m0b10_1[0m[38;2;249;38;114m,[0m[38;2;248;248;242m [0m[38;2;190;132;255m100_100[0m[38;2;249;38;114m][0m
+
+[38;2;166;226;46mf[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mInt[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mInt[0m
+[38;2;248;248;242mf [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;249;38;114mif[0m[38;2;248;248;242m x [0m[38;2;249;38;114m>[0m[38;2;248;248;242m [0m[38;2;190;132;255m0[0m[38;2;248;248;242m [0m[38;2;249;38;114mthen[0m[38;2;248;248;242m x [0m[38;2;249;38;114melse[0m[38;2;248;248;242m [0m[38;2;190;132;255m0[0m[38;2;248;248;242m [0m[3;38;2;102;217;239m()[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mSS[0m[38;2;248;248;242m [0m[38;2;249;38;114m`[0m[38;2;249;38;114melem[0m[38;2;249;38;114m`[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mS[0m[38;2;248;248;242m [0m[38;2;249;38;114m$[0m[38;2;248;248;242m [0m[38;2;249;38;114mdo[0m
+[38;2;248;248;242m x [0m[38;2;249;38;114m<-[0m[38;2;248;248;242m a [0m[38;2;249;38;114m[[0m[38;2;190;132;255m1[0m[38;2;249;38;114m,[0m[38;2;248;248;242m [0m[38;2;190;132;255m2[0m[38;2;249;38;114m,[0m[38;2;248;248;242m [0m[38;2;190;132;255m3[0m[38;2;249;38;114m][0m
+[38;2;248;248;242m [0m[38;2;249;38;114mlet[0m[38;2;248;248;242m ukuk [0m[38;2;249;38;114m=[0m[38;2;248;248;242m akak[0m
+[38;2;248;248;242m [0m[38;2;249;38;114mrewrite[0m[38;2;248;248;242m [0m[38;2;249;38;114m$[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mWow[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mWow[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mWow[0m[38;2;248;248;242m [0m[38;2;166;226;46mWow.[0m[3;38;2;102;217;239mWow[0m[38;2;248;248;242m b [0m[3;38;2;102;217;239mW[0m[38;2;248;248;242m [0m[38;2;249;38;114m([0m[3;38;2;102;217;239mW[0m[38;2;249;38;114m)[0m
+[38;2;248;248;242m pure [0m[38;2;249;38;114m$[0m[38;2;248;248;242m f [0m[3;38;2;102;217;239mA[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mB[0m[38;2;248;248;242m c [0m[3;38;2;102;217;239mD[0m[38;2;248;248;242m [0m[38;2;249;38;114m([0m[3;38;2;102;217;239mEE[0m[38;2;249;38;114m)[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mE[0m
+
+[38;2;166;226;46m(&&&)[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mNat[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mNat[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mNat[0m
+[38;2;248;248;242mz [0m[38;2;249;38;114m&&&[0m[38;2;248;248;242m y [0m[38;2;249;38;114m=[0m[38;2;248;248;242m d [0m[38;2;249;38;114m+[0m[38;2;248;248;242m [0m[38;2;248;248;242m?foo[0m
+[38;2;249;38;114m([0m[38;2;248;248;242m&&&[0m[38;2;249;38;114m)[0m[38;2;248;248;242m x y [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;248;248;242m?asfda[0m
+
+[38;2;249;38;114mpublic[0m[38;2;248;248;242m [0m[38;2;249;38;114mexport[0m[38;2;248;248;242m [0m[38;2;249;38;114mcovering[0m
+[38;2;166;226;46m(.fun)[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mX[0m[38;2;248;248;242m a [0m[3;38;2;102;217;239mY[0m[38;2;248;248;242m b [0m[38;2;249;38;114m=>[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mNat[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mNat[0m
+[3;38;2;102;217;239mZ[0m[38;2;248;248;242m [0m[38;2;249;38;114m.[0m[38;2;248;248;242mfun [0m[38;2;249;38;114m=[0m[38;2;248;248;242m haha[0m[38;2;249;38;114m.[0m[38;2;248;248;242mfun haha [0m[38;2;249;38;114m.[0m[38;2;248;248;242mN[0m
+[38;2;249;38;114m([0m[38;2;249;38;114m.[0m[38;2;248;248;242mfun[0m[38;2;249;38;114m)[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mZ[0m[38;2;248;248;242m [0m[38;2;249;38;114m=[0m[38;2;248;248;242m ahah [0m[38;2;249;38;114m$[0m[38;2;248;248;242m [0m[38;2;249;38;114m\case[0m
+[38;2;248;248;242m x[0m[38;2;249;38;114m@[0m[38;2;249;38;114m([0m[38;2;248;248;242mx[0m[38;2;249;38;114m,[0m[38;2;248;248;242m y[0m[38;2;249;38;114m)[0m[38;2;248;248;242m [0m[38;2;249;38;114m=>[0m[38;2;248;248;242m [0m[38;2;166;226;46mPrelude.Types.[0m[38;2;248;248;242mahahah[0m
+
+[38;2;166;226;46m(.N)[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mNat[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mNat[0m
+[3;38;2;102;217;239mZ[0m[38;2;248;248;242m [0m[38;2;249;38;114m.[0m[38;2;248;248;242mN [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mZ[0m
+[38;2;249;38;114m([0m[38;2;249;38;114m.[0m[38;2;248;248;242mN[0m[38;2;249;38;114m)[0m[38;2;248;248;242m [0m[38;2;249;38;114m([0m[3;38;2;102;217;239mS[0m[38;2;248;248;242m n[0m[38;2;249;38;114m)[0m[38;2;248;248;242m [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;249;38;114m([0m[38;2;249;38;114m.[0m[38;2;248;248;242mN[0m[38;2;249;38;114m)[0m[38;2;248;248;242m n[0m
+
+[38;2;166;226;46mxx[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mName[0m
+[38;2;248;248;242mxx [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;249;38;114m`{[0m[38;2;166;226;46mFull.[0m[3;38;2;102;217;239mName[0m[38;2;249;38;114m}[0m
+
+[38;2;249;38;114minfixr[0m[38;2;248;248;242m [0m[38;2;190;132;255m0[0m[38;2;248;248;242m [0m[38;2;249;38;114m^^^[0m[38;2;249;38;114m,[0m[38;2;248;248;242m [0m[38;2;249;38;114m&&&[0m
+
+[38;2;166;226;46mxxx[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[38;2;248;248;242m?[0m
+[38;2;248;248;242mxxx [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;249;38;114mcase[0m[38;2;248;248;242m x [0m[38;2;249;38;114mof[0m
+[38;2;248;248;242m [0m[3;38;2;102;217;239mZ[0m[38;2;248;248;242m [0m[38;2;249;38;114m=>[0m[38;2;248;248;242m lalalaCamelCase[0m
+[38;2;248;248;242m z [0m[38;2;249;38;114m=>[0m[38;2;248;248;242m alalalCamelCase[0m
+
+[38;2;166;226;46mff[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mNat[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mTTImp[0m
+[38;2;248;248;242mff [0m[38;2;190;132;255m0[0m[38;2;248;248;242m [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;249;38;114mlet[0m[38;2;248;248;242m x [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;190;132;255m0[0m[38;2;248;248;242m [0m[38;2;249;38;114min[0m[38;2;248;248;242m val[0m
+[38;2;248;248;242mff [0m[38;2;190;132;255m_[0m[38;2;248;248;242m [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;249;38;114m`([0m[38;2;249;38;114mlet[0m[38;2;248;248;242m x [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;190;132;255m0[0m[38;2;248;248;242m [0m[38;2;249;38;114min[0m[38;2;248;248;242m [0m[38;2;249;38;114m~[0m[38;2;248;248;242mval [0m[38;2;249;38;114m^~^[0m[38;2;248;248;242m [0m[38;2;249;38;114m~[0m[38;2;249;38;114m([0m[38;2;248;248;242mabc[0m[38;2;249;38;114m)[0m[38;2;249;38;114m)[0m
+[38;2;248;248;242mff [0m[38;2;190;132;255m_[0m[38;2;248;248;242m [0m[38;2;249;38;114m=[0m[38;2;248;248;242m f [0m[38;2;249;38;114m`([0m[38;2;249;38;114mlet[0m[38;2;248;248;242m x [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;190;132;255m0[0m[38;2;248;248;242m [0m[38;2;249;38;114min[0m[38;2;248;248;242m [0m[38;2;249;38;114m~[0m[38;2;248;248;242mval [0m[38;2;249;38;114m^~^[0m[38;2;248;248;242m [0m[38;2;249;38;114m~[0m[38;2;249;38;114m([0m[38;2;248;248;242mabc[0m[38;2;249;38;114m)[0m[38;2;249;38;114m)[0m[38;2;248;248;242m x[0m
+
+[38;2;249;38;114m%language[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mElabReflection[0m
+[38;2;249;38;114m%runElab[0m[38;2;248;248;242m [0m[38;2;166;226;46mX.[0m[38;2;248;248;242msf ads[0m
+
+[38;2;249;38;114m%macro[0m[38;2;248;248;242m [0m[38;2;249;38;114m%inline[0m
+[38;2;166;226;46mfff[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mList[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mDecl[0m
+[38;2;248;248;242mfff [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;249;38;114m`[[0m
+[38;2;248;248;242m [0m[38;2;166;226;46mf[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mNat[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mNat[0m
+
+[38;2;248;248;242m f [0m[3;38;2;102;217;239mZ[0m[38;2;248;248;242m [0m[38;2;249;38;114m=[0m[38;2;248;248;242m haha [0m[38;2;249;38;114m%runElab[0m[38;2;248;248;242m [0m[38;2;249;38;114m%search[0m[38;2;248;248;242m [0m[38;2;249;38;114m@[0m[38;2;249;38;114m{[0m[38;2;249;38;114m%World[0m[38;2;249;38;114m}[0m
+[38;2;249;38;114m][0m
+
+[38;2;249;38;114mprivate[0m[38;2;248;248;242m [0m[38;2;249;38;114minfixr[0m[38;2;248;248;242m [0m[38;2;190;132;255m4[0m[38;2;248;248;242m [0m[38;2;249;38;114m^--^[0m
+
+[38;2;249;38;114m([0m[38;2;249;38;114m^--^[0m[38;2;249;38;114m)[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mNat[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mNat[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mNat[0m
+[38;2;249;38;114m([0m[38;2;249;38;114m^--^[0m[38;2;249;38;114m)[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mZ[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mZ[0m[38;2;248;248;242m [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mZ[0m
+[38;2;248;248;242mx [0m[38;2;249;38;114m^--^[0m[38;2;248;248;242m y [0m[38;2;249;38;114m=[0m[38;2;248;248;242m x [0m[38;2;249;38;114m+[0m[38;2;248;248;242m y[0m
+
+[38;2;166;226;46mx[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[38;2;248;248;242m([0m[3;38;2;253;151;31my[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mVect[0m[38;2;248;248;242m n [0m[38;2;249;38;114m([0m[3;38;2;102;217;239mMaybe[0m[38;2;248;248;242m [0m[38;2;249;38;114m([0m[3;38;2;102;217;239mMaybe[0m[38;2;248;248;242m [0m[38;2;249;38;114m([0m[38;2;248;248;242m&&&[0m[38;2;249;38;114m)[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mNat[0m[38;2;249;38;114m)[0m[38;2;249;38;114m)[0m[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m
+[38;2;248;248;242m [0m[38;2;248;248;242m{[0m[3;38;2;253;151;31mx[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mNat[0m[38;2;248;248;242m}[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m[38;2;248;248;242m [0m[38;2;248;248;242m{[0m[38;2;249;38;114mauto[0m[38;2;248;248;242m [0m[3;38;2;253;151;31m_[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mMonoid[0m[38;2;248;248;242m a[0m[38;2;248;248;242m}[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m
+[38;2;248;248;242m [0m[38;2;248;248;242m{[0m[38;2;249;38;114mdefault [0m[38;2;249;38;114m4[0m[38;2;248;248;242m [0m[3;38;2;253;151;31mxx[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mNat[0m[38;2;248;248;242m}[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m
+[38;2;248;248;242m [0m[38;2;248;248;242m{[0m[38;2;249;38;114mdefault [0m[38;2;249;38;114m(f x Y)[0m[38;2;248;248;242m [0m[3;38;2;253;151;31mxx'[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mNat[0m[38;2;248;248;242m}[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m
+[38;2;248;248;242m [0m[3;38;2;102;217;239mString[0m
+[38;2;248;248;242mx [0m[3;38;2;102;217;239mZ[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mS[0m[38;2;248;248;242m [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;248;248;242m?foo[0m
+[38;2;248;248;242mx y [0m[38;2;190;132;255m_[0m[38;2;248;248;242m [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116ma b [0m[38;2;248;248;242m\{[0m[38;2;248;248;242mshow [0m[38;2;249;38;114m$[0m[38;2;248;248;242m [0m[38;2;249;38;114mlet[0m[38;2;248;248;242m x [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;190;132;255m0[0m[38;2;248;248;242m [0m[38;2;249;38;114min[0m[38;2;248;248;242m y[0m[38;2;248;248;242m}[0m[38;2;230;219;116m y >>= z[0m[38;2;230;219;116m"[0m
+
+[38;2;166;226;46mmultiline[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mString[0m
+[38;2;248;248;242mmultiline [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116m"[0m[38;2;230;219;116m"[0m
+[38;2;230;219;116m A multiline string[0m[38;2;190;132;255m\NUL[0m
+[38;2;230;219;116m [0m[38;2;230;219;116m"[0m[38;2;230;219;116m"[0m[38;2;230;219;116m"[0m
+
+[38;2;166;226;46mf'[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mNat[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mNat[0m
+[38;2;248;248;242mf' [0m[38;2;249;38;114m=[0m[38;2;248;248;242m x' [0m[38;2;190;132;255m4[0m
+
+[38;2;166;226;46mx[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mChar[0m
+[38;2;248;248;242mx [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;190;132;255m'[0m[38;2;190;132;255m\BEL[0m[38;2;190;132;255m'[0m
+[38;2;248;248;242mx [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;190;132;255m'[0m[38;2;190;132;255m\\[0m[38;2;190;132;255m'[0m
+[38;2;248;248;242mx [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;190;132;255m'[0m[38;2;190;132;255m\'[0m[38;2;190;132;255m'[0m
+[38;2;248;248;242mx [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;190;132;255m'[0m[38;2;190;132;255m\o755[0m[38;2;190;132;255m'[0m
+[38;2;248;248;242mx [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;190;132;255m'[0m[38;2;190;132;255ma[0m[38;2;190;132;255m'[0m
+
+[38;2;166;226;46mxx[0m[38;2;248;248;242m [0m[38;2;249;38;114m:[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mInt[0m
+[38;2;248;248;242mxx [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;190;132;255m0o7_5_5[0m
diff --git a/tests/syntax-tests/highlighted/JSON/example.ndjson b/tests/syntax-tests/highlighted/JSON/example.ndjson
new file mode 100644
index 00000000..775a5218
--- /dev/null
+++ b/tests/syntax-tests/highlighted/JSON/example.ndjson
@@ -0,0 +1,3 @@
+[38;2;248;248;242m{[0m[38;2;253;151;31m"[0m[38;2;253;151;31msome[0m[38;2;253;151;31m"[0m[38;2;248;248;242m:[0m[38;2;230;219;116m"[0m[38;2;230;219;116mthing[0m[38;2;230;219;116m"[0m[38;2;248;248;242m}[0m
+[38;2;248;248;242m{[0m[38;2;253;151;31m"[0m[38;2;253;151;31mfoo[0m[38;2;253;151;31m"[0m[38;2;248;248;242m:[0m[38;2;190;132;255m17[0m[38;2;248;248;242m,[0m[38;2;253;151;31m"[0m[38;2;253;151;31mbar[0m[38;2;253;151;31m"[0m[38;2;248;248;242m:[0m[38;2;190;132;255mfalse[0m[38;2;248;248;242m,[0m[38;2;253;151;31m"[0m[38;2;253;151;31mquux[0m[38;2;253;151;31m"[0m[38;2;248;248;242m:[0m[38;2;190;132;255mtrue[0m[38;2;248;248;242m}[0m
+[38;2;248;248;242m{[0m[38;2;253;151;31m"[0m[38;2;253;151;31mmay[0m[38;2;253;151;31m"[0m[38;2;248;248;242m:[0m[38;2;248;248;242m{[0m[38;2;253;151;31m"[0m[38;2;253;151;31minclude[0m[38;2;253;151;31m"[0m[38;2;248;248;242m:[0m[38;2;230;219;116m"[0m[38;2;230;219;116mnested[0m[38;2;230;219;116m"[0m[38;2;248;248;242m,[0m[38;2;253;151;31m"[0m[38;2;253;151;31mobjects[0m[38;2;253;151;31m"[0m[38;2;248;248;242m:[0m[38;2;248;248;242m[[0m[38;2;230;219;116m"[0m[38;2;230;219;116mand[0m[38;2;230;219;116m"[0m[38;2;248;248;242m,[0m[38;2;230;219;116m"[0m[38;2;230;219;116marrays[0m[38;2;230;219;116m"[0m[38;2;248;248;242m][0m[38;2;248;248;242m}[0m[38;2;248;248;242m}[0m
diff --git a/tests/syntax-tests/highlighted/Log/example.log b/tests/syntax-tests/highlighted/Log/example.log
index f0e9754a..57e0e9a3 100644
--- a/tests/syntax-tests/highlighted/Log/example.log
+++ b/tests/syntax-tests/highlighted/Log/example.log
@@ -1,3 +1,3 @@
[38;2;190;132;255m2021-03-06[0m[38;2;248;248;242m [0m[38;2;190;132;255m23:22:21[0m[38;2;190;132;255m.[0m[38;2;190;132;255m392[0m[38;2;248;248;242m [0m[4;38;2;166;226;46mhttps://[0m[4;38;2;166;226;46m[[0m[4;38;2;190;132;255m2001[0m[4;38;2;166;226;46m:[0m[4;38;2;190;132;255mdb8[0m[4;38;2;166;226;46m:[0m[4;38;2;190;132;255m4006[0m[4;38;2;166;226;46m:[0m[4;38;2;190;132;255m812[0m[4;38;2;166;226;46m:[0m[4;38;2;166;226;46m:[0m[4;38;2;190;132;255m200e[0m[4;38;2;166;226;46m][0m[4;38;2;166;226;46m:[0m[4;38;2;190;132;255m8080[0m[4;38;2;166;226;46m/path/the[0m[4;38;2;190;132;255m%[0m[4;38;2;190;132;255m20[0m[4;38;2;166;226;46mpage[0m[4;38;2;166;226;46m.[0m[4;38;2;166;226;46mhtml[0m
[38;2;190;132;255m2021-03-06[0m[38;2;248;248;242m [0m[38;2;190;132;255m23:22:21[0m[38;2;248;248;242m [0m[4;38;2;166;226;46mhttps://[0m[4;38;2;166;226;46mexample.com[0m[4;38;2;166;226;46m:[0m[4;38;2;190;132;255m8080[0m[4;38;2;166;226;46m/path/the[0m[4;38;2;190;132;255m%[0m[4;38;2;190;132;255m20[0m[4;38;2;166;226;46mpage[0m[4;38;2;166;226;46m(with_parens)[0m[4;38;2;166;226;46m.[0m[4;38;2;166;226;46mhtml[0m
-[38;2;190;132;255m2022-03-16[0m[38;2;249;38;114mT[0m[38;2;190;132;255m17:41:02[0m[38;2;190;132;255m.[0m[38;2;190;132;255m519[0m[38;2;248;248;242m helix_term::application [[0m[38;2;248;248;240mWARN[0m[38;2;248;248;242m] unhandled window/showMessage: ShowMessageParams { typ: [0m[38;2;248;248;240mError[0m[38;2;248;248;242m, message: [0m[38;2;230;219;116m"rust-analyzer failed to load workspace: Failed to read Cargo metadata from Cargo.toml file /home/zeta/dev/raytracer/Cargo.toml, cargo 1.61.0-nightly (65c8266 2022-03-09): Failed to run `[0m[38;2;190;132;255m\"[0m[38;2;230;219;116mcargo[0m[38;2;190;132;255m\"[0m[38;2;230;219;116m [0m[38;2;190;132;255m\"[0m[38;2;230;219;116mmetadata[0m[38;2;190;132;255m\"[0m[38;2;230;219;116m [0m[38;2;190;132;255m\"[0m[38;2;230;219;116m--format-version[0m[38;2;190;132;255m\"[0m[38;2;230;219;116m [0m[38;2;190;132;255m\"[0m[38;2;230;219;116m1[0m[38;2;190;132;255m\"[0m[38;2;230;219;116m [0m[38;2;190;132;255m\"[0m[38;2;230;219;116m--manifest-path[0m[38;2;190;132;255m\"[0m[38;2;230;219;116m [0m[38;2;190;132;255m\"[0m[38;2;230;219;116m/home/zeta/dev/raytracer/Cargo.toml[0m[38;2;190;132;255m\"[0m[38;2;230;219;116m [0m[38;2;190;132;255m\"[0m[38;2;230;219;116m--filter-platform[0m[38;2;190;132;255m\"[0m[38;2;230;219;116m [0m[38;2;190;132;255m\"[0m[38;2;230;219;116mwasm32-unknown-unknown[0m[38;2;190;132;255m\"[0m[38;2;230;219;116m`: `cargo metadata` exited with an error: Updating crates.io index[0m[38;2;190;132;255m\n[0m[38;2;230;219;116merror: failed to select a version for `parking_lot`.[0m[38;2;190;132;255m\n[0m[38;2;230;219;116m ... required by package `raytracer v0.1.0 (/home/zeta/dev/raytracer)`[0m[38;2;190;132;255m\n[0m[38;2;230;219;116mversions that meet the requirements `^0.12.0` are: 0.12.0[0m[38;2;190;132;255m\n[0m[38;2;190;132;255m\n[0m[38;2;230;219;116mthe package `raytracer` depends on `parking_lot`, with features: `wasm-bindgen` but `parking_lot` does not have these features.[0m[38;2;190;132;255m\n[0m[38;2;190;132;255m\n[0m[38;2;190;132;255m\n[0m[38;2;230;219;116mfailed to select a version for `parking_lot` which could resolve this conflict[0m[38;2;190;132;255m\n[0m[38;2;230;219;116m"[0m[38;2;248;248;242m }[0m
+[38;2;190;132;255m2022-03-16[0m[38;2;249;38;114mT[0m[38;2;190;132;255m17:41:02[0m[38;2;190;132;255m.[0m[38;2;190;132;255m519[0m[38;2;248;248;240m helix_term::application [[0m[38;2;248;248;240mWARN[0m[38;2;248;248;240m] unhandled window/showMessage: ShowMessageParams { typ: [0m[38;2;221;32;32mError[0m[38;2;248;248;240m, message: [0m[38;2;230;219;116m"rust-analyzer failed to load workspace: Failed to read Cargo metadata from Cargo.toml file /home/zeta/dev/raytracer/Cargo.toml, cargo 1.61.0-nightly (65c8266 2022-03-09): Failed to run `[0m[38;2;190;132;255m\"[0m[38;2;230;219;116mcargo[0m[38;2;190;132;255m\"[0m[38;2;230;219;116m [0m[38;2;190;132;255m\"[0m[38;2;230;219;116mmetadata[0m[38;2;190;132;255m\"[0m[38;2;230;219;116m [0m[38;2;190;132;255m\"[0m[38;2;230;219;116m--format-version[0m[38;2;190;132;255m\"[0m[38;2;230;219;116m [0m[38;2;190;132;255m\"[0m[38;2;230;219;116m1[0m[38;2;190;132;255m\"[0m[38;2;230;219;116m [0m[38;2;190;132;255m\"[0m[38;2;230;219;116m--manifest-path[0m[38;2;190;132;255m\"[0m[38;2;230;219;116m [0m[38;2;190;132;255m\"[0m[38;2;230;219;116m/home/zeta/dev/raytracer/Cargo.toml[0m[38;2;190;132;255m\"[0m[38;2;230;219;116m [0m[38;2;190;132;255m\"[0m[38;2;230;219;116m--filter-platform[0m[38;2;190;132;255m\"[0m[38;2;230;219;116m [0m[38;2;190;132;255m\"[0m[38;2;230;219;116mwasm32-unknown-unknown[0m[38;2;190;132;255m\"[0m[38;2;230;219;116m`: `cargo metadata` exited with an error: Updating crates.io index[0m[38;2;190;132;255m\n[0m[38;2;230;219;116merror: failed to select a version for `parking_lot`.[0m[38;2;190;132;255m\n[0m[38;2;230;219;116m ... required by package `raytracer v0.1.0 (/home/zeta/dev/raytracer)`[0m[38;2;190;132;255m\n[0m[38;2;230;219;116mversions that meet the requirements `^0.12.0` are: 0.12.0[0m[38;2;190;132;255m\n[0m[38;2;190;132;255m\n[0m[38;2;230;219;116mthe package `raytracer` depends on `parking_lot`, with features: `wasm-bindgen` but `parking_lot` does not have these features.[0m[38;2;190;132;255m\n[0m[38;2;190;132;255m\n[0m[38;2;190;132;255m\n[0m[38;2;230;219;116mfailed to select a version for `parking_lot` which could resolve this conflict[0m[38;2;190;132;255m\n[0m[38;2;230;219;116m"[0m[38;2;248;248;240m }[0m
diff --git a/tests/syntax-tests/highlighted/Odin/test.odin b/tests/syntax-tests/highlighted/Odin/test.odin
new file mode 100644
index 00000000..ab13ed8c
--- /dev/null
+++ b/tests/syntax-tests/highlighted/Odin/test.odin
@@ -0,0 +1,27 @@
+[38;2;249;38;114mpackage[0m[38;2;248;248;242m main[0m
+
+[38;2;249;38;114mimport[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mcore:fmt[0m[38;2;230;219;116m"[0m
+[38;2;249;38;114mimport[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mcore:math[0m[38;2;230;219;116m"[0m
+
+[38;2;166;226;46mVector[0m[38;2;248;248;242m :: [0m[3;38;2;102;217;239mstruct[0m[38;2;248;248;242m {[0m
+[38;2;248;248;242m components: [0m[38;2;248;248;242m[[0m[38;2;248;248;242m][0m[3;38;2;102;217;239mf64[0m[38;2;248;248;242m,[0m
+[38;2;248;248;242m}[0m
+
+[38;2;166;226;46meuclidean_distance[0m[38;2;248;248;242m :: [0m[3;38;2;102;217;239mproc[0m[38;2;248;248;242m(v1: Vector, v2: Vector) -> [0m[3;38;2;102;217;239mf64[0m[38;2;248;248;242m {[0m
+[38;2;248;248;242m [0m[38;2;249;38;114mif[0m[38;2;248;248;242m [0m[38;2;102;217;239mlen[0m[38;2;248;248;242m(v1.components) != [0m[38;2;102;217;239mlen[0m[38;2;248;248;242m(v2.components) {[0m
+[38;2;248;248;242m [0m[38;2;102;217;239mpanic[0m[38;2;248;248;242m([0m[38;2;230;219;116m"[0m[38;2;230;219;116mVectors must be same dimension[0m[38;2;230;219;116m"[0m[38;2;248;248;242m)[0m
+[38;2;248;248;242m }[0m
+[38;2;248;248;242m sum: [0m[3;38;2;102;217;239mf64[0m[38;2;248;248;242m = [0m[38;2;190;132;255m0.0[0m[38;2;248;248;242m;[0m
+[38;2;248;248;242m [0m[38;2;249;38;114mfor[0m[38;2;248;248;242m i, comp [0m[38;2;249;38;114min[0m[38;2;248;248;242m v1.components {[0m
+[38;2;248;248;242m diff := comp - v2.components[i];[0m
+[38;2;248;248;242m sum += diff * diff;[0m
+[38;2;248;248;242m }[0m
+[38;2;248;248;242m [0m[38;2;249;38;114mreturn[0m[38;2;248;248;242m math.[0m[38;2;102;217;239msqrt[0m[38;2;248;248;242m(sum);[0m
+[38;2;248;248;242m}[0m
+
+[38;2;166;226;46mmain[0m[38;2;248;248;242m :: [0m[3;38;2;102;217;239mproc[0m[38;2;248;248;242m() {[0m
+[38;2;248;248;242m v1: Vector = Vector{components = [0m[38;2;248;248;242m[[0m[38;2;248;248;242m][0m[3;38;2;102;217;239mf64[0m[38;2;248;248;242m{[0m[38;2;190;132;255m1.0[0m[38;2;248;248;242m, [0m[38;2;190;132;255m2.0[0m[38;2;248;248;242m, [0m[38;2;190;132;255m3.0[0m[38;2;248;248;242m}};[0m
+[38;2;248;248;242m v2: Vector = Vector{components = [0m[38;2;248;248;242m[[0m[38;2;248;248;242m][0m[3;38;2;102;217;239mf64[0m[38;2;248;248;242m{[0m[38;2;190;132;255m4.0[0m[38;2;248;248;242m, [0m[38;2;190;132;255m6.0[0m[38;2;248;248;242m, [0m[38;2;190;132;255m8.0[0m[38;2;248;248;242m}};[0m
+[38;2;248;248;242m dist: [0m[3;38;2;102;217;239mf64[0m[38;2;248;248;242m = [0m[38;2;102;217;239meuclidean_distance[0m[38;2;248;248;242m(v1, v2);[0m
+[38;2;248;248;242m fmt.[0m[38;2;102;217;239mprintln[0m[38;2;248;248;242m([0m[38;2;230;219;116m"[0m[38;2;230;219;116mDistance:[0m[38;2;230;219;116m"[0m[38;2;248;248;242m, dist);[0m
+[38;2;248;248;242m}[0m
diff --git a/tests/syntax-tests/highlighted/Syslog/example.syslog b/tests/syntax-tests/highlighted/Syslog/example.syslog
index 0c200c33..78c45a12 100644
--- a/tests/syntax-tests/highlighted/Syslog/example.syslog
+++ b/tests/syntax-tests/highlighted/Syslog/example.syslog
@@ -1,16 +1,17 @@
-[38;2;190;132;255mApr 4[0m[38;2;190;132;255m [0m[38;2;190;132;255m00:00:01[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239msystemd[0m[38;2;248;248;242m[[0m[38;2;190;132;255m1[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m logrotate.service: Succeeded.[0m
-[38;2;190;132;255mApr 4[0m[38;2;190;132;255m [0m[38;2;190;132;255m00:00:01[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239msystemd[0m[38;2;248;248;242m[[0m[38;2;190;132;255m1[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m Finished Rotate log files.[0m
-[38;2;190;132;255mApr 4[0m[38;2;190;132;255m [0m[38;2;190;132;255m00:00:01[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239mcolord[0m[38;2;248;248;242m[[0m[38;2;190;132;255m920[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;248;248;240mfailed[0m[38;2;248;248;242m to get session [pid [0m[38;2;190;132;255m137485[0m[38;2;248;248;242m]: No data available[0m
-[38;2;190;132;255mApr 4[0m[38;2;190;132;255m [0m[38;2;190;132;255m00:00:21[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239mkernel[0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;248;248;242m[[0m[3;38;2;253;151;31m55604[0m[38;2;248;248;242m.[0m[3;38;2;253;151;31m908232[0m[38;2;248;248;242m][0m[38;2;248;248;242m audit: [0m[3;38;2;253;151;31mtype[0m[38;2;249;38;114m=[0m[38;2;190;132;255m1400[0m[38;2;248;248;242m audit([0m[38;2;190;132;255m1617483621[0m[38;2;190;132;255m.[0m[38;2;190;132;255m094[0m[38;2;248;248;242m:[0m[38;2;190;132;255m28[0m[38;2;248;248;242m): [0m[3;38;2;253;151;31mapparmor[0m[38;2;249;38;114m=[0m[38;2;230;219;116m"DENIED[0m[38;2;230;219;116m"[0m[38;2;248;248;242m [0m[3;38;2;253;151;31moperation[0m[38;2;249;38;114m=[0m[38;2;230;219;116m"capable[0m[38;2;230;219;116m"[0m[38;2;248;248;242m [0m[3;38;2;253;151;31mprofile[0m[38;2;249;38;114m=[0m[38;2;230;219;116m"/usr/sbin/cups-browsed[0m[38;2;230;219;116m"[0m[38;2;248;248;242m [0m[3;38;2;253;151;31mpid[0m[38;2;249;38;114m=[0m[38;2;190;132;255m59311[0m[38;2;248;248;242m [0m[3;38;2;253;151;31mcomm[0m[38;2;249;38;114m=[0m[38;2;230;219;116m"cups-browsed[0m[38;2;230;219;116m"[0m[38;2;248;248;242m [0m[3;38;2;253;151;31mcapability[0m[38;2;249;38;114m=[0m[38;2;190;132;255m23[0m[38;2;248;248;242m [0m[3;38;2;253;151;31mcapname[0m[38;2;249;38;114m=[0m[38;2;230;219;116m"sys_nice[0m[38;2;230;219;116m"[0m
-[38;2;190;132;255mApr 4[0m[38;2;190;132;255m [0m[38;2;190;132;255m00:01:38[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239msystemd-resolved[0m[38;2;248;248;242m[[0m[38;2;190;132;255m721[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m Server returned [0m[38;2;248;248;240merror[0m[38;2;248;248;242m NXDOMAIN, mitigating potential DNS violation DVE-[0m[38;2;190;132;255m2018[0m[38;2;248;248;242m-[0m[38;2;190;132;255m0001[0m[38;2;248;248;242m, retrying transaction with reduced feature level UDP.[0m
-[38;2;190;132;255mApr 4[0m[38;2;190;132;255m [0m[38;2;190;132;255m00:04:46[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239mntpd[0m[38;2;248;248;242m[[0m[38;2;190;132;255m952[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m Soliciting pool server [0m[38;2;190;132;255m255[0m[38;2;248;248;242m.[0m[38;2;190;132;255m76[0m[38;2;248;248;242m.[0m[38;2;190;132;255m59[0m[38;2;248;248;242m.[0m[38;2;190;132;255m37[0m
-[38;2;190;132;255mApr 4[0m[38;2;190;132;255m [0m[38;2;190;132;255m00:05:21[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239mntpd[0m[38;2;248;248;242m[[0m[38;2;190;132;255m952[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;248;248;242m:[0m[38;2;248;248;242m:[0m[38;2;190;132;255m1[0m[38;2;248;248;242m local addr [0m[38;2;190;132;255m0[0m[38;2;248;248;242m:[0m[38;2;190;132;255m0[0m[38;2;248;248;242m:[0m[38;2;190;132;255m0[0m[38;2;248;248;242m:[0m[38;2;190;132;255m0[0m[38;2;248;248;242m:[0m[38;2;190;132;255m0[0m[38;2;248;248;242m:[0m[38;2;190;132;255m0[0m[38;2;248;248;242m:[0m[38;2;190;132;255m0[0m[38;2;248;248;242m:[0m[38;2;190;132;255m1[0m[38;2;248;248;242m -> [0m[38;2;190;132;255m[0m
-[38;2;190;132;255mApr 4[0m[38;2;190;132;255m [0m[38;2;190;132;255m00:06:29[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239mntpd[0m[38;2;248;248;242m[[0m[38;2;190;132;255m952[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m receive: Unexpected origin timestamp [0m[38;2;190;132;255m0x[0m[38;2;190;132;255me414a8d1[0m[38;2;190;132;255m.[0m[38;2;190;132;255m82e825f5[0m[38;2;248;248;242m does not match aorg [0m[38;2;190;132;255m0x[0m[38;2;190;132;255me414a8d5[0m[38;2;190;132;255m.[0m[38;2;190;132;255m82c50d8c[0m[38;2;248;248;242m from server@[0m[38;2;190;132;255m127[0m[38;2;248;248;242m.[0m[38;2;190;132;255m0[0m[38;2;248;248;242m.[0m[38;2;190;132;255m0[0m[38;2;248;248;242m.[0m[38;2;190;132;255m1[0m[38;2;248;248;242m xmt [0m[38;2;190;132;255m0x[0m[38;2;190;132;255me414a8d1[0m[38;2;190;132;255m.[0m[38;2;190;132;255me671d7c4[0m
-[38;2;190;132;255mApr 4[0m[38;2;190;132;255m [0m[38;2;190;132;255m09:30:01[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239mCRON[0m[38;2;248;248;242m[[0m[38;2;190;132;255m89278[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m (root) [0m[38;2;166;226;46mCMD[0m[38;2;248;248;242m [0m[38;2;248;248;242m([0m[38;2;102;217;239m[[0m[38;2;255;255;255m [0m[3;38;2;253;151;31m-[0m[3;38;2;253;151;31mx[0m[38;2;255;255;255m /etc/init.d/anacron [0m[38;2;102;217;239m][0m[38;2;255;255;255m [0m[38;2;249;38;114m&&[0m[38;2;255;255;255m [0m[38;2;249;38;114mif[0m[38;2;255;255;255m [0m[38;2;102;217;239m[[0m[38;2;255;255;255m [0m[38;2;249;38;114m![0m[38;2;255;255;255m [0m[3;38;2;253;151;31m-[0m[3;38;2;253;151;31md[0m[38;2;255;255;255m /run/systemd/system [0m[38;2;102;217;239m][0m[38;2;249;38;114m;[0m[38;2;255;255;255m [0m[38;2;249;38;114mthen[0m[38;2;255;255;255m [0m[38;2;255;255;255m/usr/sbin/invoke-rc.d[0m[38;2;255;255;255m anacron start [0m[38;2;249;38;114m>[0m[38;2;255;255;255m/dev/null[0m[38;2;249;38;114m;[0m[38;2;255;255;255m [0m[38;2;249;38;114mfi[0m[38;2;248;248;242m)[0m
-[38;2;190;132;255mApr 4[0m[38;2;190;132;255m [0m[38;2;190;132;255m16:32:07[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239mNetworkManager[0m[38;2;248;248;242m[[0m[38;2;190;132;255m740[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;190;132;255m[0m[38;2;248;248;242m [[0m[38;2;190;132;255m1617629527[0m[38;2;190;132;255m.[0m[38;2;190;132;255m1101[0m[38;2;248;248;242m] manager: NetworkManager state is now CONNECTED_GLOBAL[0m
-[38;2;190;132;255mApr 4[0m[38;2;190;132;255m [0m[38;2;190;132;255m22:00:45[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239mdbus-daemon[0m[38;2;248;248;242m[[0m[38;2;190;132;255m1094[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;248;248;242m[[0m[3;38;2;253;151;31msession[0m[38;2;248;248;242m [0m[3;38;2;253;151;31muid[0m[38;2;249;38;114m=[0m[38;2;190;132;255m1000[0m[38;2;248;248;242m [0m[3;38;2;253;151;31mpid[0m[38;2;249;38;114m=[0m[38;2;190;132;255m1094[0m[38;2;248;248;242m][0m[38;2;248;248;242m Successfully activated service [0m[38;2;230;219;116m'[0m[38;2;230;219;116mio.github.celluloid_player.Celluloid[0m[38;2;230;219;116m'[0m
-[38;2;190;132;255mAug 11[0m[38;2;190;132;255m [0m[38;2;190;132;255m13:29:06[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239minsomnia_insomnia.desktop[0m[38;2;248;248;242m[[0m[38;2;190;132;255m142666[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;190;132;255m13:29:06[0m[38;2;190;132;255m.[0m[38;2;190;132;255m316[0m[38;2;248;248;242m › [updater] Updater not running [0m[3;38;2;253;151;31mplatform[0m[38;2;249;38;114m=[0m[38;2;248;248;242mlinux [0m[3;38;2;253;151;31mdev[0m[38;2;249;38;114m=[0m[38;2;248;248;242mfalse[0m
-[38;2;190;132;255mAug 11[0m[38;2;190;132;255m [0m[38;2;190;132;255m13:36:34[0m[38;2;248;248;242m [0m[38;2;166;226;46m192.168.220.5[0m[38;2;248;248;242m [0m[38;2;102;217;239mnginx[0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;190;132;255m2021/08/11[0m[38;2;248;248;242m [0m[38;2;190;132;255m13:36:34[0m[38;2;248;248;242m [[0m[38;2;248;248;242mdebug[0m[38;2;248;248;242m] [0m[38;2;190;132;255m2031[0m[38;2;248;248;242m#[0m[38;2;190;132;255m2031[0m[38;2;248;248;242m: epoll add event: fd:[0m[38;2;190;132;255m6[0m[38;2;248;248;242m op:[0m[38;2;190;132;255m1[0m[38;2;248;248;242m ev:[0m[38;2;190;132;255m00002001[0m
-[38;2;190;132;255mAug 11[0m[38;2;190;132;255m [0m[38;2;190;132;255m21:31:08[0m[38;2;248;248;242m [0m[38;2;166;226;46m::1[0m[38;2;248;248;242m [0m[38;2;102;217;239mnginx[0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;190;132;255m2021/08/11[0m[38;2;248;248;242m [0m[38;2;190;132;255m21:31:08[0m[38;2;248;248;242m [[0m[38;2;248;248;242mdebug[0m[38;2;248;248;242m] [0m[38;2;190;132;255m760831[0m[38;2;248;248;242m#[0m[38;2;190;132;255m760831[0m[38;2;248;248;242m: epoll add event: fd:[0m[38;2;190;132;255m6[0m[38;2;248;248;242m op:[0m[38;2;190;132;255m1[0m[38;2;248;248;242m ev:[0m[38;2;190;132;255m10000001[0m
-[38;2;190;132;255mAug 11[0m[38;2;190;132;255m [0m[38;2;190;132;255m21:40:31[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239mscop[0m[38;2;248;248;242m [0m[38;2;248;248;242mhello[0m
-[38;2;190;132;255mAug 16[0m[38;2;190;132;255m [0m[38;2;190;132;255m21:38:21[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239msystemd[0m[38;2;248;248;242m[[0m[38;2;190;132;255m1[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m Finished Cleanup of Temporary Directories.[0m
+[38;2;190;132;255mApr 4[0m[38;2;248;248;242m [0m[38;2;190;132;255m00:00:01[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239msystemd[0m[38;2;248;248;242m[[0m[38;2;190;132;255m1[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m logrotate.service: Succeeded.[0m
+[38;2;190;132;255mApr 4[0m[38;2;248;248;242m [0m[38;2;190;132;255m00:00:01[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239msystemd[0m[38;2;248;248;242m[[0m[38;2;190;132;255m1[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m Finished Rotate log files.[0m
+[38;2;190;132;255mApr 4[0m[38;2;248;248;242m [0m[38;2;190;132;255m00:00:01[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239mcolord[0m[38;2;248;248;242m[[0m[38;2;190;132;255m920[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;221;32;32mfailed[0m[38;2;248;248;240m to get session [pid [0m[38;2;190;132;255m137485[0m[38;2;248;248;240m]: No data available[0m
+[38;2;190;132;255mApr 4[0m[38;2;248;248;242m [0m[38;2;190;132;255m00:00:21[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239mkernel[0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;248;248;242m[[0m[3;38;2;253;151;31m55604[0m[38;2;248;248;242m.[0m[3;38;2;253;151;31m908232[0m[38;2;248;248;242m][0m[38;2;248;248;242m audit: [0m[3;38;2;253;151;31mtype[0m[38;2;249;38;114m=[0m[38;2;190;132;255m1400[0m[38;2;248;248;242m audit([0m[38;2;190;132;255m1617483621[0m[38;2;190;132;255m.[0m[38;2;190;132;255m094[0m[38;2;248;248;242m:[0m[38;2;190;132;255m28[0m[38;2;248;248;242m): [0m[3;38;2;253;151;31mapparmor[0m[38;2;249;38;114m=[0m[38;2;230;219;116m"DENIED[0m[38;2;230;219;116m"[0m[38;2;248;248;242m [0m[3;38;2;253;151;31moperation[0m[38;2;249;38;114m=[0m[38;2;230;219;116m"capable[0m[38;2;230;219;116m"[0m[38;2;248;248;242m [0m[3;38;2;253;151;31mprofile[0m[38;2;249;38;114m=[0m[38;2;230;219;116m"/usr/sbin/cups-browsed[0m[38;2;230;219;116m"[0m[38;2;248;248;242m [0m[3;38;2;253;151;31mpid[0m[38;2;249;38;114m=[0m[38;2;190;132;255m59311[0m[38;2;248;248;242m [0m[3;38;2;253;151;31mcomm[0m[38;2;249;38;114m=[0m[38;2;230;219;116m"cups-browsed[0m[38;2;230;219;116m"[0m[38;2;248;248;242m [0m[3;38;2;253;151;31mcapability[0m[38;2;249;38;114m=[0m[38;2;190;132;255m23[0m[38;2;248;248;242m [0m[3;38;2;253;151;31mcapname[0m[38;2;249;38;114m=[0m[38;2;230;219;116m"sys_nice[0m[38;2;230;219;116m"[0m
+[38;2;190;132;255mApr 4[0m[38;2;248;248;242m [0m[38;2;190;132;255m00:01:38[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239msystemd-resolved[0m[38;2;248;248;242m[[0m[38;2;190;132;255m721[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;248;248;240mServer returned [0m[38;2;221;32;32merror[0m[38;2;248;248;240m NXDOMAIN, mitigating potential DNS violation DVE-[0m[38;2;190;132;255m2018[0m[38;2;248;248;240m-[0m[38;2;190;132;255m0001[0m[38;2;248;248;240m, retrying transaction with reduced feature level UDP.[0m
+[38;2;190;132;255mApr 4[0m[38;2;248;248;242m [0m[38;2;190;132;255m00:04:46[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239mntpd[0m[38;2;248;248;242m[[0m[38;2;190;132;255m952[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m Soliciting pool server [0m[38;2;190;132;255m255[0m[38;2;248;248;242m.[0m[38;2;190;132;255m76[0m[38;2;248;248;242m.[0m[38;2;190;132;255m59[0m[38;2;248;248;242m.[0m[38;2;190;132;255m37[0m
+[38;2;190;132;255mApr 4[0m[38;2;248;248;242m [0m[38;2;190;132;255m00:05:21[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239mntpd[0m[38;2;248;248;242m[[0m[38;2;190;132;255m952[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;248;248;242m:[0m[38;2;248;248;242m:[0m[38;2;190;132;255m1[0m[38;2;248;248;242m local addr [0m[38;2;190;132;255m0[0m[38;2;248;248;242m:[0m[38;2;190;132;255m0[0m[38;2;248;248;242m:[0m[38;2;190;132;255m0[0m[38;2;248;248;242m:[0m[38;2;190;132;255m0[0m[38;2;248;248;242m:[0m[38;2;190;132;255m0[0m[38;2;248;248;242m:[0m[38;2;190;132;255m0[0m[38;2;248;248;242m:[0m[38;2;190;132;255m0[0m[38;2;248;248;242m:[0m[38;2;190;132;255m1[0m[38;2;248;248;242m -> [0m[38;2;190;132;255m[0m
+[38;2;190;132;255mApr 4[0m[38;2;248;248;242m [0m[38;2;190;132;255m00:06:29[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239mntpd[0m[38;2;248;248;242m[[0m[38;2;190;132;255m952[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m receive: Unexpected origin timestamp [0m[38;2;190;132;255m0x[0m[38;2;190;132;255me414a8d1[0m[38;2;190;132;255m.[0m[38;2;190;132;255m82e825f5[0m[38;2;248;248;242m does not match aorg [0m[38;2;190;132;255m0x[0m[38;2;190;132;255me414a8d5[0m[38;2;190;132;255m.[0m[38;2;190;132;255m82c50d8c[0m[38;2;248;248;242m from server@[0m[38;2;190;132;255m127[0m[38;2;248;248;242m.[0m[38;2;190;132;255m0[0m[38;2;248;248;242m.[0m[38;2;190;132;255m0[0m[38;2;248;248;242m.[0m[38;2;190;132;255m1[0m[38;2;248;248;242m xmt [0m[38;2;190;132;255m0x[0m[38;2;190;132;255me414a8d1[0m[38;2;190;132;255m.[0m[38;2;190;132;255me671d7c4[0m
+[38;2;190;132;255mApr 4[0m[38;2;248;248;242m [0m[38;2;190;132;255m09:30:01[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239mCRON[0m[38;2;248;248;242m[[0m[38;2;190;132;255m89278[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m (root) [0m[38;2;166;226;46mCMD[0m[38;2;248;248;242m [0m[38;2;248;248;242m([0m[38;2;102;217;239m[[0m[38;2;255;255;255m [0m[3;38;2;253;151;31m-[0m[3;38;2;253;151;31mx[0m[38;2;255;255;255m /etc/init.d/anacron [0m[38;2;102;217;239m][0m[38;2;255;255;255m [0m[38;2;249;38;114m&&[0m[38;2;255;255;255m [0m[38;2;249;38;114mif[0m[38;2;255;255;255m [0m[38;2;102;217;239m[[0m[38;2;255;255;255m [0m[38;2;249;38;114m![0m[38;2;255;255;255m [0m[3;38;2;253;151;31m-[0m[3;38;2;253;151;31md[0m[38;2;255;255;255m /run/systemd/system [0m[38;2;102;217;239m][0m[38;2;249;38;114m;[0m[38;2;255;255;255m [0m[38;2;249;38;114mthen[0m[38;2;255;255;255m [0m[38;2;255;255;255m/usr/sbin/invoke-rc.d[0m[38;2;255;255;255m anacron start [0m[38;2;249;38;114m>[0m[38;2;255;255;255m/dev/null[0m[38;2;249;38;114m;[0m[38;2;255;255;255m [0m[38;2;249;38;114mfi[0m[38;2;248;248;242m)[0m
+[38;2;190;132;255mApr 4[0m[38;2;248;248;242m [0m[38;2;190;132;255m16:32:07[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239mNetworkManager[0m[38;2;248;248;242m[[0m[38;2;190;132;255m740[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;190;132;255m[0m[38;2;248;248;242m [[0m[38;2;190;132;255m1617629527[0m[38;2;190;132;255m.[0m[38;2;190;132;255m1101[0m[38;2;248;248;242m] manager: NetworkManager state is now CONNECTED_GLOBAL[0m
+[38;2;190;132;255mApr 4[0m[38;2;248;248;242m [0m[38;2;190;132;255m22:00:45[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239mdbus-daemon[0m[38;2;248;248;242m[[0m[38;2;190;132;255m1094[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;248;248;242m[[0m[3;38;2;253;151;31msession[0m[38;2;248;248;242m [0m[3;38;2;253;151;31muid[0m[38;2;249;38;114m=[0m[38;2;190;132;255m1000[0m[38;2;248;248;242m [0m[3;38;2;253;151;31mpid[0m[38;2;249;38;114m=[0m[38;2;190;132;255m1094[0m[38;2;248;248;242m][0m[38;2;248;248;242m Successfully activated service [0m[38;2;230;219;116m'[0m[38;2;230;219;116mio.github.celluloid_player.Celluloid[0m[38;2;230;219;116m'[0m
+[38;2;190;132;255mAug 11[0m[38;2;248;248;242m [0m[38;2;190;132;255m13:29:06[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239minsomnia_insomnia.desktop[0m[38;2;248;248;242m[[0m[38;2;190;132;255m142666[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;190;132;255m13:29:06[0m[38;2;190;132;255m.[0m[38;2;190;132;255m316[0m[38;2;248;248;242m › [updater] Updater not running [0m[3;38;2;253;151;31mplatform[0m[38;2;249;38;114m=[0m[38;2;248;248;242mlinux [0m[3;38;2;253;151;31mdev[0m[38;2;249;38;114m=[0m[38;2;248;248;242mfalse[0m
+[38;2;190;132;255mAug 11[0m[38;2;248;248;242m [0m[38;2;190;132;255m13:36:34[0m[38;2;248;248;242m [0m[38;2;166;226;46m192.168.220.5[0m[38;2;248;248;242m [0m[38;2;102;217;239mnginx[0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;190;132;255m2021/08/11[0m[38;2;248;248;242m [0m[38;2;190;132;255m13:36:34[0m[38;2;248;248;242m [[0m[38;2;248;248;242mdebug[0m[38;2;248;248;242m] [0m[38;2;190;132;255m2031[0m[38;2;248;248;242m#[0m[38;2;190;132;255m2031[0m[38;2;248;248;242m: epoll add event: fd:[0m[38;2;190;132;255m6[0m[38;2;248;248;242m op:[0m[38;2;190;132;255m1[0m[38;2;248;248;242m ev:[0m[38;2;190;132;255m00002001[0m
+[38;2;190;132;255mAug 11[0m[38;2;248;248;242m [0m[38;2;190;132;255m21:31:08[0m[38;2;248;248;242m [0m[38;2;166;226;46m::1[0m[38;2;248;248;242m [0m[38;2;102;217;239mnginx[0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;190;132;255m2021/08/11[0m[38;2;248;248;242m [0m[38;2;190;132;255m21:31:08[0m[38;2;248;248;242m [[0m[38;2;248;248;242mdebug[0m[38;2;248;248;242m] [0m[38;2;190;132;255m760831[0m[38;2;248;248;242m#[0m[38;2;190;132;255m760831[0m[38;2;248;248;242m: epoll add event: fd:[0m[38;2;190;132;255m6[0m[38;2;248;248;242m op:[0m[38;2;190;132;255m1[0m[38;2;248;248;242m ev:[0m[38;2;190;132;255m10000001[0m
+[38;2;190;132;255mAug 11[0m[38;2;248;248;242m [0m[38;2;190;132;255m21:40:31[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239mscop[0m[38;2;248;248;242m [0m[38;2;248;248;242mhello[0m
+[38;2;190;132;255mAug 16[0m[38;2;248;248;242m [0m[38;2;190;132;255m21:38:21[0m[38;2;248;248;242m [0m[38;2;166;226;46mhostname-here[0m[38;2;248;248;242m [0m[38;2;102;217;239msystemd[0m[38;2;248;248;242m[[0m[38;2;190;132;255m1[0m[38;2;248;248;242m][0m[38;2;248;248;242m:[0m[38;2;248;248;242m Finished Cleanup of Temporary Directories.[0m
+[38;2;190;132;255m2025-02-08[0m[38;2;248;248;240m [0m[38;2;190;132;255m20:52:11[0m[38;2;190;132;255m.[0m[38;2;190;132;255m039[0m[38;2;248;248;240m - setfont: [0m[38;2;221;32;32mERROR[0m[38;2;248;248;240m kdfontop.c:[0m[38;2;190;132;255m183[0m[38;2;248;248;240m put_font_kdfontop: Unable to load such font with such kernel version[0m
diff --git a/tests/syntax-tests/highlighted/XML/Directory.Build.props b/tests/syntax-tests/highlighted/XML/Directory.Build.props
new file mode 100644
index 00000000..bd4b97a0
--- /dev/null
+++ b/tests/syntax-tests/highlighted/XML/Directory.Build.props
@@ -0,0 +1,5 @@
+[38;2;255;255;255m<[0m[38;2;249;38;114mProject[0m[38;2;255;255;255m>[0m
+[38;2;248;248;242m [0m[38;2;255;255;255m<[0m[38;2;249;38;114mPropertyGroup[0m[38;2;255;255;255m>[0m
+[38;2;248;248;242m [0m[38;2;255;255;255m<[0m[38;2;249;38;114mOutDir[0m[38;2;255;255;255m>[0m[38;2;248;248;242mC:\output\$(MSBuildProjectName)[0m[38;2;255;255;255m[0m[38;2;249;38;114mOutDir[0m[38;2;255;255;255m>[0m
+[38;2;248;248;242m [0m[38;2;255;255;255m[0m[38;2;249;38;114mPropertyGroup[0m[38;2;255;255;255m>[0m
+[38;2;255;255;255m[0m[38;2;249;38;114mProject[0m[38;2;255;255;255m>[0m
diff --git a/tests/syntax-tests/highlighted/XML/console.csproj b/tests/syntax-tests/highlighted/XML/console.csproj
new file mode 100644
index 00000000..ee49fbf0
--- /dev/null
+++ b/tests/syntax-tests/highlighted/XML/console.csproj
@@ -0,0 +1,11 @@
+[38;2;255;255;255m<[0m[38;2;249;38;114mProject[0m[38;2;248;248;242m [0m[38;2;166;226;46mSdk[0m[38;2;248;248;242m=[0m[38;2;230;219;116m"[0m[38;2;230;219;116mMicrosoft.NET.Sdk[0m[38;2;230;219;116m"[0m[38;2;255;255;255m>[0m
+
+[38;2;248;248;242m [0m[38;2;255;255;255m<[0m[38;2;249;38;114mPropertyGroup[0m[38;2;255;255;255m>[0m
+[38;2;248;248;242m [0m[38;2;255;255;255m<[0m[38;2;249;38;114mOutputType[0m[38;2;255;255;255m>[0m[38;2;248;248;242mExe[0m[38;2;255;255;255m[0m[38;2;249;38;114mOutputType[0m[38;2;255;255;255m>[0m
+[38;2;248;248;242m [0m[38;2;255;255;255m<[0m[38;2;249;38;114mTargetFramework[0m[38;2;255;255;255m>[0m[38;2;248;248;242mnet9.0[0m[38;2;255;255;255m[0m[38;2;249;38;114mTargetFramework[0m[38;2;255;255;255m>[0m
+[38;2;248;248;242m [0m[38;2;255;255;255m<[0m[38;2;249;38;114mRootNamespace[0m[38;2;255;255;255m>[0m[38;2;248;248;242mSomeNamespace[0m[38;2;255;255;255m[0m[38;2;249;38;114mRootNamespace[0m[38;2;255;255;255m>[0m
+[38;2;248;248;242m [0m[38;2;255;255;255m<[0m[38;2;249;38;114mImplicitUsings[0m[38;2;255;255;255m>[0m[38;2;248;248;242menable[0m[38;2;255;255;255m[0m[38;2;249;38;114mImplicitUsings[0m[38;2;255;255;255m>[0m
+[38;2;248;248;242m [0m[38;2;255;255;255m<[0m[38;2;249;38;114mNullable[0m[38;2;255;255;255m>[0m[38;2;248;248;242menable[0m[38;2;255;255;255m[0m[38;2;249;38;114mNullable[0m[38;2;255;255;255m>[0m
+[38;2;248;248;242m [0m[38;2;255;255;255m[0m[38;2;249;38;114mPropertyGroup[0m[38;2;255;255;255m>[0m
+
+[38;2;255;255;255m[0m[38;2;249;38;114mProject[0m[38;2;255;255;255m>[0m
diff --git a/tests/syntax-tests/highlighted/XML/projectname.targets b/tests/syntax-tests/highlighted/XML/projectname.targets
new file mode 100644
index 00000000..0af85fbd
--- /dev/null
+++ b/tests/syntax-tests/highlighted/XML/projectname.targets
@@ -0,0 +1,8 @@
+[38;2;255;255;255m[0m[38;2;249;38;114mxml[0m[38;2;248;248;242m [0m[38;2;166;226;46mversion[0m[38;2;248;248;242m=[0m[38;2;230;219;116m"[0m[38;2;230;219;116m1.0[0m[38;2;230;219;116m"[0m[38;2;248;248;242m [0m[38;2;166;226;46mencoding[0m[38;2;248;248;242m=[0m[38;2;230;219;116m"[0m[38;2;230;219;116mutf-8[0m[38;2;230;219;116m"[0m[38;2;248;248;242m [0m[38;2;255;255;255m?>[0m
+[38;2;255;255;255m<[0m[38;2;249;38;114mProject[0m[38;2;248;248;242m [0m[38;2;166;226;46mxmlns[0m[38;2;248;248;242m=[0m[38;2;230;219;116m"[0m[38;2;230;219;116mhttp://schemas.microsoft.com/developer/msbuild/2003[0m[38;2;230;219;116m"[0m[38;2;255;255;255m>[0m
+
+[38;2;248;248;242m [0m[38;2;255;255;255m<[0m[38;2;249;38;114mTarget[0m[38;2;248;248;242m [0m[38;2;166;226;46mName[0m[38;2;248;248;242m=[0m[38;2;230;219;116m"[0m[38;2;230;219;116mTestTarget[0m[38;2;230;219;116m"[0m[38;2;248;248;242m [0m[38;2;166;226;46mAfterTargets[0m[38;2;248;248;242m=[0m[38;2;230;219;116m"[0m[38;2;230;219;116mBuild[0m[38;2;230;219;116m"[0m[38;2;255;255;255m>[0m
+[38;2;248;248;242m [0m[38;2;255;255;255m<[0m[38;2;249;38;114mMessage[0m[38;2;248;248;242m [0m[38;2;166;226;46mImportance[0m[38;2;248;248;242m=[0m[38;2;230;219;116m"[0m[38;2;230;219;116mHigh[0m[38;2;230;219;116m"[0m[38;2;248;248;242m [0m[38;2;166;226;46mText[0m[38;2;248;248;242m=[0m[38;2;230;219;116m"[0m[38;2;230;219;116m-------------MHM----------------[0m[38;2;230;219;116m"[0m[38;2;248;248;242m [0m[38;2;255;255;255m/>[0m
+[38;2;248;248;242m [0m[38;2;255;255;255m[0m[38;2;249;38;114mTarget[0m[38;2;255;255;255m>[0m
+
+[38;2;255;255;255m[0m[38;2;249;38;114mProject[0m[38;2;255;255;255m>[0m
diff --git a/tests/syntax-tests/highlighted/debsources/sources.list b/tests/syntax-tests/highlighted/debsources/sources.list
new file mode 100644
index 00000000..ef89d137
--- /dev/null
+++ b/tests/syntax-tests/highlighted/debsources/sources.list
@@ -0,0 +1,15 @@
+[38;2;117;113;94m#[0m[38;2;117;113;94m See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to[0m
+[38;2;117;113;94m#[0m[38;2;117;113;94m newer versions of the distribution.[0m
+
+[38;2;190;132;255mdeb[0m[38;2;248;248;242m [0m[4;38;2;166;226;46mhttps://deb.debian.org/debian[0m[38;2;248;248;242m [0m[3;38;2;166;226;46mbookworm[0m[38;2;248;248;242m [0m[3;38;2;166;226;46mmain[0m[38;2;248;248;242m [0m[38;2;190;132;255mnon-free-firmware[0m
+[38;2;117;113;94m#[0m[38;2;117;113;94mdeb-src https://deb.debian.org/debian bookworm main non-free-firmware[0m
+
+[38;2;117;113;94m#[0m[38;2;117;113;94m# Major bug fix updates produced after the final release of the[0m
+[38;2;117;113;94m#[0m[38;2;117;113;94m# distribution.[0m
+[38;2;117;113;94m#[0m[38;2;117;113;94m deb-src http://lt.archive.ubuntu.com/ubuntu/ xenial-updates main restricted[0m
+
+[38;2;190;132;255mdeb[0m[38;2;248;248;242m [0m[4;38;2;166;226;46mhttps://security.debian.org/debian-security[0m[38;2;248;248;242m [0m[3;38;2;166;226;46mbookworm-security[0m[38;2;248;248;242m [0m[3;38;2;166;226;46mmain[0m[38;2;248;248;242m [0m[38;2;190;132;255mnon-free-firmware[0m
+[38;2;190;132;255mdeb-src[0m[38;2;248;248;242m [0m[4;38;2;166;226;46mhttps://security.debian.org/debian-security[0m[38;2;248;248;242m [0m[3;38;2;166;226;46mbookworm-security[0m[38;2;248;248;242m [0m[3;38;2;166;226;46mmain[0m[38;2;248;248;242m [0m[38;2;190;132;255mnon-free-firmware[0m
+
+[38;2;190;132;255mdeb[0m[38;2;248;248;242m [0m[4;38;2;166;226;46mhttps://deb.debian.org/debian[0m[38;2;248;248;242m [0m[3;38;2;166;226;46mbookworm-updates[0m[38;2;248;248;242m [0m[3;38;2;166;226;46mmain[0m[38;2;248;248;242m [0m[38;2;190;132;255mnon-free-firmware[0m
+[38;2;190;132;255mdeb-src[0m[38;2;248;248;242m [0m[4;38;2;166;226;46mhttps://deb.debian.org/debian[0m[38;2;248;248;242m [0m[3;38;2;166;226;46mbookworm-updates[0m[38;2;248;248;242m [0m[3;38;2;166;226;46mmain[0m[38;2;248;248;242m [0m[38;2;190;132;255mnon-free-firmware[0m
diff --git a/tests/syntax-tests/source/CSV/comma-delimited.csv b/tests/syntax-tests/source/CSV/comma-delimited.csv
new file mode 100644
index 00000000..4d7b2ec2
--- /dev/null
+++ b/tests/syntax-tests/source/CSV/comma-delimited.csv
@@ -0,0 +1,3 @@
+foo,bar,baz,this|that,test,colors,cycle
+1.2,1.7,2.5,blah;cool,test,colors,cycle
+
diff --git a/tests/syntax-tests/source/CSV/decimals_comma_decimal_point_pipe_delimited.csv b/tests/syntax-tests/source/CSV/decimals_comma_decimal_point_pipe_delimited.csv
new file mode 100644
index 00000000..c8a46786
--- /dev/null
+++ b/tests/syntax-tests/source/CSV/decimals_comma_decimal_point_pipe_delimited.csv
@@ -0,0 +1,3 @@
+foo|bar|baz
+1,2|1,7|2,7
+1,5|8,5|-5,5
diff --git a/tests/syntax-tests/source/CSV/decimals_comma_decimal_point_semicolon_delimited.csv b/tests/syntax-tests/source/CSV/decimals_comma_decimal_point_semicolon_delimited.csv
new file mode 100644
index 00000000..63301750
--- /dev/null
+++ b/tests/syntax-tests/source/CSV/decimals_comma_decimal_point_semicolon_delimited.csv
@@ -0,0 +1,3 @@
+foo;bar;baz
+1,2;1,7;2,7
+1,5;8,5;-5,5
diff --git a/tests/syntax-tests/source/CSV/simple.tsv b/tests/syntax-tests/source/CSV/simple.tsv
new file mode 100644
index 00000000..2cf870a5
--- /dev/null
+++ b/tests/syntax-tests/source/CSV/simple.tsv
@@ -0,0 +1,3 @@
+foo bar baz|;, test hello world tsv
+1,2 1,7 2,7 a b c "hello again" tsv
+";|," ;|, baz test "hello world" tsv
diff --git a/tests/syntax-tests/source/GDScript/test.gd b/tests/syntax-tests/source/GDScript/test.gd
new file mode 100644
index 00000000..7192dfec
--- /dev/null
+++ b/tests/syntax-tests/source/GDScript/test.gd
@@ -0,0 +1,71 @@
+extends Node
+
+signal custom_signal(param)
+
+const PI = 3.14159
+
+var untyped_var = "Hello, World!"
+var typed_int: int = 42
+var typed_float: float = 3.14
+var typed_string: String = "GDScript Test"
+var typed_array: Array = [1, 2, 3, 4]
+var typed_dict: Dictionary = {"key": "value", "number": 100}
+
+onready var label = $Label
+
+func say_hello() -> void:
+ print("Hello from GDScript!")
+
+func add_numbers(a: int, b: int = 10) -> int:
+ return a + b
+
+func process_value(value: int) -> String:
+ if value < 0:
+ return "Negative"
+ elif value == 0:
+ return "Zero"
+ else:
+ return "Positive"
+
+func sum_array(arr: Array) -> int:
+ var total: int = 0
+ for num in arr:
+ total += num
+ return total
+
+func describe_number(num: int) -> String:
+ match num:
+ 0:
+ return "Zero"
+ 1, 2, 3:
+ return "Small number"
+ _:
+ return "Large number"
+
+func long_description() -> String:
+ return """This is a test file for GDScript.
+It covers variables, functions, control structures, loops, signals, inner classes,
+multiline strings, arrays, and dictionaries."""
+
+class InnerExample:
+ var inner_value: int = 99
+ func show_value() -> void:
+ print("Inner value is:", inner_value)
+
+func test_inner_class() -> void:
+ var inner = InnerExample.new()
+ inner.show_value()
+
+func trigger_signal() -> void:
+ emit_signal("custom_signal", "TestParam")
+
+func _ready() -> void:
+ say_hello()
+ var result_add = add_numbers(5)
+ print("Add result:", result_add)
+ print("Process value for -5:", process_value(-5))
+ print("Sum of array [10, 20, 30]:", sum_array([10, 20, 30]))
+ print("Description for 2:", describe_number(2))
+ print("Long description:\n", long_description())
+ test_inner_class()
+ trigger_signal()
diff --git a/tests/syntax-tests/source/Idris2/LICENSE.md b/tests/syntax-tests/source/Idris2/LICENSE.md
new file mode 100644
index 00000000..2d9d6206
--- /dev/null
+++ b/tests/syntax-tests/source/Idris2/LICENSE.md
@@ -0,0 +1,7 @@
+The `test.idr` file has been added from https://github.com/buzden/sublime-syntax-idris2 under the following license:
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
diff --git a/tests/syntax-tests/source/Idris2/test.idr b/tests/syntax-tests/source/Idris2/test.idr
new file mode 100644
index 00000000..1fada03d
--- /dev/null
+++ b/tests/syntax-tests/source/Idris2/test.idr
@@ -0,0 +1,107 @@
+-- some code in Idris
+module XX.X'''
+
+import Data.Nat
+
+data X = A | B
+
+namespace X
+ ||| Documentation
+ record Y where
+ [noHints]
+ constructor MkY'
+ field1 : Nat
+ {auto x : Nat}
+
+namespace X' {
+ parameters (x : A (Maybe b))
+ x : Nat
+}
+
+u : ()
+u = ()
+
+k, w, u : Char
+k = '\NUL'
+w = 'w'
+
+x = [1, 0, 3, "sdf\{d}", 0xFF, 0o77, 0b10_1, 100_100]
+
+f : Int -> Int
+f = if x > 0 then x else 0 () SS `elem` S $ do
+ x <- a [1, 2, 3]
+ let ukuk = akak
+ rewrite $ Wow Wow Wow Wow.Wow b W (W)
+ pure $ f A B c D (EE) E
+
+(&&&) : Nat -> Nat -> Nat
+z &&& y = d + ?foo
+(&&&) x y = ?asfda
+
+public export covering
+(.fun) : X a Y b => Nat -> Nat
+Z .fun = haha.fun haha .N
+(.fun) Z = ahah $ \case
+ x@(x, y) => Prelude.Types.ahahah
+
+(.N) : Nat -> Nat
+Z .N = Z
+(.N) (S n) = (.N) n
+
+xx : Name
+xx = `{Full.Name}
+
+infixr 0 ^^^, &&&
+
+xxx : ?
+xxx = case x of
+ Z => lalalaCamelCase
+ z => alalalCamelCase
+
+ff : Nat -> TTImp
+ff 0 = let x = 0 in val
+ff _ = `(let x = 0 in ~val ^~^ ~(abc))
+ff _ = f `(let x = 0 in ~val ^~^ ~(abc)) x
+
+%language ElabReflection
+%runElab X.sf ads
+
+%macro %inline
+fff : List Decl
+fff = `[
+ f : Nat -> Nat
+
+ f Z = haha %runElab %search @{%World}
+]
+
+private infixr 4 ^--^
+
+(^--^) : Nat -> Nat -> Nat
+(^--^) Z Z = Z
+x ^--^ y = x + y
+
+x : (y : Vect n (Maybe (Maybe (&&&) Nat))) ->
+ {x : Nat} -> {auto _ : Monoid a} ->
+ {default 4 xx : Nat} ->
+ {default (f x Y) xx' : Nat} ->
+ String
+x Z S = ?foo
+x y _ = "a b \{show $ let x = 0 in y} y >>= z"
+
+multiline : String
+multiline = """
+ A multiline string\NUL
+ """
+
+f' : Nat -> Nat
+f' = x' 4
+
+x : Char
+x = '\BEL'
+x = '\\'
+x = '\''
+x = '\o755'
+x = 'a'
+
+xx : Int
+xx = 0o7_5_5
diff --git a/tests/syntax-tests/source/JSON/example.ndjson b/tests/syntax-tests/source/JSON/example.ndjson
new file mode 100644
index 00000000..2bc459eb
--- /dev/null
+++ b/tests/syntax-tests/source/JSON/example.ndjson
@@ -0,0 +1,3 @@
+{"some":"thing"}
+{"foo":17,"bar":false,"quux":true}
+{"may":{"include":"nested","objects":["and","arrays"]}}
diff --git a/tests/syntax-tests/source/Odin/test.odin b/tests/syntax-tests/source/Odin/test.odin
new file mode 100644
index 00000000..dafcfcfd
--- /dev/null
+++ b/tests/syntax-tests/source/Odin/test.odin
@@ -0,0 +1,27 @@
+package main
+
+import "core:fmt"
+import "core:math"
+
+Vector :: struct {
+ components: []f64,
+}
+
+euclidean_distance :: proc(v1: Vector, v2: Vector) -> f64 {
+ if len(v1.components) != len(v2.components) {
+ panic("Vectors must be same dimension")
+ }
+ sum: f64 = 0.0;
+ for i, comp in v1.components {
+ diff := comp - v2.components[i];
+ sum += diff * diff;
+ }
+ return math.sqrt(sum);
+}
+
+main :: proc() {
+ v1: Vector = Vector{components = []f64{1.0, 2.0, 3.0}};
+ v2: Vector = Vector{components = []f64{4.0, 6.0, 8.0}};
+ dist: f64 = euclidean_distance(v1, v2);
+ fmt.println("Distance:", dist);
+}
diff --git a/tests/syntax-tests/source/Syslog/example.syslog b/tests/syntax-tests/source/Syslog/example.syslog
index 9dc82e7c..5b7e575b 100644
--- a/tests/syntax-tests/source/Syslog/example.syslog
+++ b/tests/syntax-tests/source/Syslog/example.syslog
@@ -14,3 +14,4 @@ Aug 11 13:36:34 192.168.220.5 nginx: 2021/08/11 13:36:34 [debug] 2031#2031: epol
Aug 11 21:31:08 ::1 nginx: 2021/08/11 21:31:08 [debug] 760831#760831: epoll add event: fd:6 op:1 ev:10000001
Aug 11 21:40:31 hostname-here scop hello
Aug 16 21:38:21 hostname-here systemd[1]: Finished Cleanup of Temporary Directories.
+2025-02-08 20:52:11.039 - setfont: ERROR kdfontop.c:183 put_font_kdfontop: Unable to load such font with such kernel version
diff --git a/tests/syntax-tests/source/XML/Directory.Build.props b/tests/syntax-tests/source/XML/Directory.Build.props
new file mode 100644
index 00000000..95da98cf
--- /dev/null
+++ b/tests/syntax-tests/source/XML/Directory.Build.props
@@ -0,0 +1,5 @@
+
+
+ C:\output\$(MSBuildProjectName)
+
+
diff --git a/tests/syntax-tests/source/XML/console.csproj b/tests/syntax-tests/source/XML/console.csproj
new file mode 100644
index 00000000..61dd6821
--- /dev/null
+++ b/tests/syntax-tests/source/XML/console.csproj
@@ -0,0 +1,11 @@
+
+
+
+ Exe
+ net9.0
+ SomeNamespace
+ enable
+ enable
+
+
+
diff --git a/tests/syntax-tests/source/XML/projectname.targets b/tests/syntax-tests/source/XML/projectname.targets
new file mode 100644
index 00000000..fc597ed2
--- /dev/null
+++ b/tests/syntax-tests/source/XML/projectname.targets
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/tests/syntax-tests/source/debsources/sources.list b/tests/syntax-tests/source/debsources/sources.list
new file mode 100644
index 00000000..2bdc6ef1
--- /dev/null
+++ b/tests/syntax-tests/source/debsources/sources.list
@@ -0,0 +1,15 @@
+# See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to
+# newer versions of the distribution.
+
+deb https://deb.debian.org/debian bookworm main non-free-firmware
+#deb-src https://deb.debian.org/debian bookworm main non-free-firmware
+
+## Major bug fix updates produced after the final release of the
+## distribution.
+# deb-src http://lt.archive.ubuntu.com/ubuntu/ xenial-updates main restricted
+
+deb https://security.debian.org/debian-security bookworm-security main non-free-firmware
+deb-src https://security.debian.org/debian-security bookworm-security main non-free-firmware
+
+deb https://deb.debian.org/debian bookworm-updates main non-free-firmware
+deb-src https://deb.debian.org/debian bookworm-updates main non-free-firmware