1
0
mirror of https://github.com/sharkdp/bat synced 2026-06-09 10:03:18 +00:00

Merge branch 'master' into fix/lessclose-nonzero-warning

This commit is contained in:
Keith Hall
2026-04-28 19:24:00 +03:00
committed by GitHub
33 changed files with 425 additions and 519 deletions
+11
View File
@@ -0,0 +1,11 @@
# On Windows MSVC, statically link the C runtime so that the resulting EXE does
# not depend on the vcruntime DLL.
#
# See: https://github.com/sharkdp/bat/issues/3634
[target.x86_64-pc-windows-msvc]
rustflags = ["-C", "target-feature=+crt-static"]
[target.i686-pc-windows-msvc]
rustflags = ["-C", "target-feature=+crt-static"]
[target.aarch64-pc-windows-msvc]
rustflags = ["-C", "target-feature=+crt-static"]
+3 -3
View File
@@ -49,9 +49,6 @@
[submodule "assets/themes/zenburn"]
path = assets/themes/zenburn
url = https://github.com/colinta/zenburn.git
[submodule "assets/syntaxes/Kotlin"]
path = assets/syntaxes/02_Extra/Kotlin
url = https://github.com/vkostyukov/kotlin-sublime-package
[submodule "assets/syntaxes/Elm"]
path = assets/syntaxes/02_Extra/Elm
url = https://github.com/elm-community/SublimeElmLanguageSupport
@@ -281,3 +278,6 @@
[submodule "assets/syntaxes/02_Extra/COBOL"]
path = assets/syntaxes/02_Extra/COBOL
url = https://github.com/adukhan99/sublime_cobol.git
[submodule "assets/syntaxes/02_Extra/Kotlin"]
path = assets/syntaxes/02_Extra/Kotlin
url = https://github.com/guille/sublime-kotlin
+13
View File
@@ -1,20 +1,29 @@
# unreleased
## Other
- Add instructions for removing fish help abbreviations to README, see #3655 (@claw-explorer). Closes #3536
- Add .NET slnx extension, see #3682 (@ltrzesniewski)
## Features
- Preserve `--diff` change markers and snip separators when `--plain` is set. Closes #3630, see #3643 (@mvanhorn)
- Added support for `hidden_file_extensions` from `.sublime-syntax` files, see #3613 (@Matei02355)
- Add word wrapping mode via `--wrap=word`, see #3597 (@veeceey)
- Support configuring `--terminal-width` via `BAT_WIDTH`, see #3679 (@officialasishkumar)
- Implement `--unbuffered` mode for streaming input, allowing partial lines to display immediately (e.g. `tail -f | bat -u`). Closes #3555, see #3583 (@mainnebula)
- Added an initial `flake.nix` for a ready made development environment; see #3578 (@vorburger)
- Add `--quiet-empty` (`-E`) flag to suppress output when input is empty. Closes #1936, see #3563 (@NORMAL-EX)
- Improve native man pages and command help syntax highlighting by stripping overstriking, see #3517 (@akirk)
- Add `--fallback-syntax`/`--fallback-language` to apply syntax highlighting only when auto-detection fails, see #1341 (@Xavrir)
- Map `BUILD` case sensitively to Python (Starlark) for Bazel, see #3576 (@vorburger)
- Syntax highlighting for Python files using uv as script runner in shebang #3689 (@janlarres)
## Bugfixes
- Fix inverted `$LESSCLOSE` warning so bat warns on nonzero exit, not on success. See #3654 (@cuiweixie)
- Report initial input read errors instead of treating them as empty input. Closes #3002, see #3706 (@lawrence3699)
- Treat ZIP archives as binary content based on their magic header, see #3686 (@officialasishkumar)
- Fix i686 `.deb` package using incorrect architecture name (`i686` instead of `i386`), preventing installation on Debian. Closes #3611, see #3650 (@Sim-hu)
- Fix inconsistent `.deb` MUSL package names (aarch64-musl used `arm64` instead of `musl-linux-arm64`, and `musleabihf` target missed `bat-musl` prefix). Closes #3482, see #3642 (@mvanhorn)
- Fix incorrect text width computation when using `--binary=as-text` with non-printable characters in caret notation, see #3640 and #3631 (@eyupcanakman)
@@ -29,21 +38,25 @@
- Fixed test compatibility with future Cargo build directory changes, see #3550 (@nmacl)
- Fixed bug caused by using `--plain` and `--terminal-width=N` flags simultaneously, see #3529 (@H4k1l)
- Fixed syntax tests path, see #3610 (@foxfromworld)
- Fix zsh tab completion word-splitting language names containing spaces (e.g. `HTML (Jinja2)`, `Apache Conf`), see #3693 (@YoshKoz)
## Other
- Use git version of cross. See #3533 (@OctopusET)
- Bump MSRV to 1.88, update `time` crate to 0.3.47 to fix RUSTSEC-2026-0009, see #3581 (@NORMAL-EX)
- Allow home and end keys to be used with builtin pager, see #3651 (@keith-hall)
- Builtin syntax mapping: cleanup matcher glob parsing logic #3652 (@cyqsimon)
- Statically link the CRT for MSVC builds via Cargo config to avoid runtime DLL dependencies. Closes #3634, see #3692 (@barry3406)
## Syntaxes
- Add shebang-based detection for Tcl (`tclsh`, `wish`) and Expect (`expect`) scripts, see #3647 (@mvanhorn)
- Change the URL of Zig submodule from GitHub to Codeberg, see #3519 (@sorairolake)
- Don't color strings inside CSV files, to make it easier to tell which column they belong to, see #3521 (@keith-hall)
- Add syntax highlighting support for COBOL, see #3584 (@adukhan99)
- Fixed manpage syntax so that ANSI escape codes don't get incorrectly highlighted and thus broken, see #3586 (@BlueElectivire)
- Map several Google Cloud CLI config files to their appropriate syntax #3635 (@victor-gp)
- Map all ignore dotfiles to Git Ignore syntax #3636 (@victor-gp)
- Improved Kotlin syntax, see #3699 (@guille)
## Themes
Generated
+26 -26
View File
@@ -951,9 +951,9 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
[[package]]
name = "linux-raw-sys"
version = "0.11.0"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
[[package]]
name = "litemap"
@@ -1235,9 +1235,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.40"
version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
dependencies = [
"proc-macro2",
]
@@ -1324,14 +1324,14 @@ dependencies = [
[[package]]
name = "rustix"
version = "1.1.2"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys 0.11.0",
"linux-raw-sys 0.12.1",
"windows-sys 0.61.2",
]
@@ -1406,9 +1406,9 @@ dependencies = [
[[package]]
name = "serde_spanned"
version = "1.0.3"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392"
checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26"
dependencies = [
"serde_core",
]
@@ -1603,14 +1603,14 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.23.0"
version = "3.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16"
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
dependencies = [
"fastrand",
"getrandom",
"once_cell",
"rustix 1.1.2",
"rustix 1.1.4",
"windows-sys 0.61.2",
]
@@ -1757,9 +1757,9 @@ dependencies = [
[[package]]
name = "toml"
version = "0.9.8"
version = "1.1.1+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8"
checksum = "994b95d9e7bae62b34bab0e2a4510b801fa466066a6a8b2b57361fa1eba068ee"
dependencies = [
"indexmap",
"serde_core",
@@ -1772,27 +1772,27 @@ dependencies = [
[[package]]
name = "toml_datetime"
version = "0.7.3"
version = "1.1.1+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533"
checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
dependencies = [
"serde_core",
]
[[package]]
name = "toml_parser"
version = "1.0.4"
version = "1.1.1+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e"
checksum = "39ca317ebc49f06bd748bfba29533eac9485569dc9bf80b849024b025e814fb9"
dependencies = [
"winnow",
]
[[package]]
name = "toml_writer"
version = "1.0.4"
version = "1.1.1+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2"
checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db"
[[package]]
name = "typenum"
@@ -1808,15 +1808,15 @@ checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
[[package]]
name = "unicode-segmentation"
version = "1.12.0"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c"
[[package]]
name = "unicode-width"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
[[package]]
name = "unsafe-libyaml"
@@ -2186,9 +2186,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
version = "0.7.14"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829"
checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5"
[[package]]
name = "wit-bindgen-rt"
+5 -5
View File
@@ -56,7 +56,7 @@ minus = { version = "5.6", optional = true, features = [
"dynamic_output",
"search",
] }
unicode-width = "0.2.1"
unicode-width = "0.2.2"
globset = "0.4"
serde = "1.0"
serde_derive = "1.0"
@@ -73,7 +73,7 @@ bytesize = { version = "2.3.1" }
encoding_rs = "0.8.35"
execute = { version = "0.2.15", optional = true }
terminal-colorsaurus = "1.0"
unicode-segmentation = "1.12.0"
unicode-segmentation = "1.13.2"
itertools = "0.14.0"
[dependencies.git2]
@@ -100,7 +100,7 @@ expect-test = "1.5.0"
serial_test = { version = "2.0.0", default-features = false }
predicates = "3.1.3"
wait-timeout = "0.2.1"
tempfile = "3.23.0"
tempfile = "3.27.0"
serde = { version = "1.0", features = ["derive"] }
[target.'cfg(unix)'.dev-dependencies]
@@ -113,13 +113,13 @@ itertools = "0.14.0"
once_cell = "1.20"
prettyplease = "0.2.37"
proc-macro2 = "1.0.106"
quote = "1.0.40"
quote = "1.0.45"
regex = "1.12.2"
serde = "1.0"
serde_derive = "1.0"
serde_with = { version = "3.17.0", default-features = false, features = ["macros"] }
syn = { version = "2.0.104", features = ["full"] }
toml = { version = "0.9.8", features = ["preserve_order"] }
toml = { version = "1.1.1", features = ["preserve_order"] }
walkdir = "2.5"
[build-dependencies.clap]
+8
View File
@@ -246,6 +246,14 @@ abbr -a --position anywhere -- -h '-h | bat -plhelp'
This way, you can keep on using `cp --help`, but get colorized help pages.
> [!TIP]
> To remove these abbreviations later, run:
> ```fish
> abbr -e -- --help
> abbr -e -- -h
> ```
> The `--` before the abbreviation name is required because `--help` and `-h` start with dashes, which would otherwise be interpreted as flags to `abbr` itself.
Be aware that in some cases, `-h` may not be a shorthand of `--help` (for example with `ls`). In cases where you need to use `-h`
as a command argument you can prepend `\` to the argument (eg. `ls \-h`) to escape the aliasing defined above.
+1 -1
View File
@@ -90,7 +90,7 @@ _{{PROJECT_EXECUTABLE}}_main() {
languages)
local IFS=$'\n'
local -a languages
languages=( $({{PROJECT_EXECUTABLE}} --list-languages | awk -F':|,' '{ for (i = 1; i <= NF; ++i) printf("%s:%s\n", $i, $1) }') )
languages=( ${(f)"$({{PROJECT_EXECUTABLE}} --list-languages | awk -F':|,' '{ for (i = 1; i <= NF; ++i) printf("%s:%s\n", $i, $1) }')"} )
_describe 'language' languages && ret=0
;;
+9
View File
@@ -2,6 +2,15 @@ diff --git syntaxes/01_Packages/Python/Python.sublime-syntax syntaxes/01_Package
index 2acd86d8..86257f7b 100644
--- syntaxes/01_Packages/Python/Python.sublime-syntax
+++ syntaxes/01_Packages/Python/Python.sublime-syntax
@@ -25,7 +31,7 @@ file_extensions:
- wscript
- bazel
- bzl
-first_line_match: ^#!\s*/.*\bpython(\d(\.\d)?)?\b
+first_line_match: ^#!\s*/.*\b(python(\d(\.\d)?)?|uv)\b
scope: source.python
variables:
@@ -988,10 +988,6 @@ contexts:
- match: \}
scope: punctuation.section.mapping-or-set.end.python
+12
View File
@@ -0,0 +1,12 @@
diff --git syntaxes/01_Packages/TCL/Tcl.sublime-syntax syntaxes/01_Packages/TCL/Tcl.sublime-syntax
index 1234567..abcdefg 100644
--- syntaxes/01_Packages/TCL/Tcl.sublime-syntax
+++ syntaxes/01_Packages/TCL/Tcl.sublime-syntax
@@ -3,6 +3,7 @@
# http://www.sublimetext.com/docs/3/syntax.html
name: Tcl
file_extensions:
- tcl
+first_line_match: ^\#!.*\b(tclsh|wish|expect)\b
scope: source.tcl
variables:
-398
View File
@@ -1,398 +0,0 @@
%YAML 1.2
---
# http://www.sublimetext.com/docs/3/syntax.html
name: Kotlin
file_extensions:
- kt
- kts
scope: source.Kotlin
contexts:
main:
- include: comments
- match: '^\s*(package)\b(?:\s*([^ ;$]+)\s*)?'
captures:
1: keyword.other.kotlin
2: entity.name.package.kotlin
- include: imports
- include: statements
classes:
- match: (?<!::)(?=\b(?:companion|class|object|interface)\b)
push:
- match: '(?=$|\})'
pop: true
- include: comments
- match: \b(companion\s*)?(class|object|interface)\b
captures:
1: storage.modifier.kotlin
2: storage.modifier.kotlin
push:
- match: '(?=<|\{|\(|:|$)'
pop: true
- include: comments
- match: \w+
scope: entity.name.type.class.kotlin
- match: <
push:
- match: ">"
pop: true
- include: generics
- match: \(
push:
- match: \)
pop: true
- include: parameters
- match: (:)
captures:
1: keyword.operator.declaration.kotlin
push:
- match: "(?={|$)"
pop: true
- match: \w+
scope: entity.other.inherited-class.kotlin
- match: \(
push:
- match: \)
pop: true
- include: expressions
- match: '\{'
push:
- match: '\}'
pop: true
- include: statements
comments:
- match: /\*
captures:
0: punctuation.definition.comment.kotlin
push:
- meta_scope: comment.block.kotlin
- match: \*/
captures:
0: punctuation.definition.comment.kotlin
pop: true
- match: \s*((//).*$\n?)
captures:
1: comment.line.double-slash.kotlin
2: punctuation.definition.comment.kotlin
constants:
- match: \b(true|false|null|this|super)\b
scope: constant.language.kotlin
- match: '\b((0(x|X)[0-9a-fA-F]*)|(([0-9]+\.?[0-9]*)|(\.[0-9]+))((e|E)(\+|-)?[0-9]+)?)([LlFf])?\b'
scope: constant.numeric.kotlin
- match: '\b([A-Z][A-Z0-9_]+)\b'
scope: constant.other.kotlin
expressions:
- match: \(
push:
- match: \)
pop: true
- include: expressions
- include: types
- include: strings
- include: constants
- include: comments
- include: keywords
functions:
- match: (?=\s*\b(?:fun)\b)
push:
- match: '(?=$|\})'
pop: true
- match: \b(fun)\b
captures:
1: keyword.other.kotlin
push:
- match: (?=\()
pop: true
- match: <
push:
- match: ">"
pop: true
- include: generics
- match: '([\.<\?>\w]+\.)?(\w+)'
captures:
2: entity.name.function.kotlin
- match: \(
push:
- match: \)
pop: true
- include: parameters
- match: (:)
captures:
1: keyword.operator.declaration.kotlin
push:
- match: "(?={|=|$)"
pop: true
- include: types
- match: '\{'
push:
- match: '(?=\})'
pop: true
- include: statements
- match: (=)
captures:
1: keyword.operator.assignment.kotlin
push:
- match: (?=$)
pop: true
- include: expressions
generics:
- match: (:)
captures:
1: keyword.operator.declaration.kotlin
push:
- match: (?=,|>)
pop: true
- include: types
- include: keywords
- match: \w+
scope: storage.type.generic.kotlin
getters-and-setters:
- match: \b(get)\b\s*\(\s*\)
captures:
1: entity.name.function.kotlin
push:
- match: '\}|(?=\bset\b)|$'
pop: true
- match: (=)
captures:
1: keyword.operator.assignment.kotlin
push:
- match: (?=$|\bset\b)
pop: true
- include: expressions
- match: '\{'
push:
- match: '\}'
pop: true
- include: expressions
- match: \b(set)\b\s*(?=\()
captures:
1: entity.name.function.kotlin
push:
- match: '\}|(?=\bget\b)|$'
pop: true
- match: \(
push:
- match: \)
pop: true
- include: parameters
- match: (=)
captures:
1: keyword.operator.assignment.kotlin
push:
- match: (?=$|\bset\b)
pop: true
- include: expressions
- match: '\{'
push:
- match: '\}'
pop: true
- include: expressions
imports:
- match: '^\s*(import)\s+[^ $]+\s+(as)?'
captures:
1: keyword.other.kotlin
2: keyword.other.kotlin
keywords:
- match: \b(var|val|public|private|protected|abstract|final|sealed|enum|open|attribute|annotation|override|inline|vararg|in|out|internal|data|tailrec|operator|infix|const|yield|typealias|typeof|reified|suspend)\b
scope: storage.modifier.kotlin
- match: \b(try|catch|finally|throw)\b
scope: keyword.control.catch-exception.kotlin
- match: \b(if|else|while|for|do|return|when|where|break|continue)\b
scope: keyword.control.kotlin
- match: \b(in|is|!in|!is|as|as\?|assert)\b
scope: keyword.operator.kotlin
- match: (==|!=|===|!==|<=|>=|<|>)
scope: keyword.operator.comparison.kotlin
- match: (=)
scope: keyword.operator.assignment.kotlin
- match: (::)
scope: keyword.operator.kotlin
- match: (:)
scope: keyword.operator.declaration.kotlin
- match: \b(by)\b
scope: keyword.other.by.kotlin
- match: (\?\.)
scope: keyword.operator.safenav.kotlin
- match: (\.)
scope: keyword.operator.dot.kotlin
- match: (\?:)
scope: keyword.operator.elvis.kotlin
- match: (\-\-|\+\+)
scope: keyword.operator.increment-decrement.kotlin
- match: (\+=|\-=|\*=|\/=)
scope: keyword.operator.arithmetic.assign.kotlin
- match: (\.\.)
scope: keyword.operator.range.kotlin
- match: (\-|\+|\*|\/|%)
scope: keyword.operator.arithmetic.kotlin
- match: (!|&&|\|\|)
scope: keyword.operator.logical.kotlin
- match: (;)
scope: punctuation.terminator.kotlin
namespaces:
- match: \b(namespace)\b
scope: keyword.other.kotlin
- match: '\{'
push:
- match: '\}'
pop: true
- include: statements
parameters:
- match: (:)
captures:
1: keyword.operator.declaration.kotlin
push:
- match: (?=,|\)|=)
pop: true
- include: types
- match: (=)
captures:
1: keyword.operator.declaration.kotlin
push:
- match: (?=,|\))
pop: true
- include: expressions
- include: keywords
- match: \w+
scope: variable.parameter.function.kotlin
statements:
- include: namespaces
- include: typedefs
- include: classes
- include: functions
- include: variables
- include: getters-and-setters
- include: expressions
strings:
- match: '"""'
captures:
0: punctuation.definition.string.begin.kotlin
push:
- meta_scope: string.quoted.third.kotlin
- match: '"""'
captures:
0: punctuation.definition.string.end.kotlin
pop: true
- match: '(\$\w+|\$\{[^\}]+\})'
scope: variable.parameter.template.kotlin
- match: \\.
scope: constant.character.escape.kotlin
- match: '"'
captures:
0: punctuation.definition.string.begin.kotlin
push:
- meta_scope: string.quoted.double.kotlin
- match: '"'
captures:
0: punctuation.definition.string.end.kotlin
pop: true
- match: '(\$\w+|\$\{[^\}]+\})'
scope: variable.parameter.template.kotlin
- match: \\.
scope: constant.character.escape.kotlin
- match: "'"
captures:
0: punctuation.definition.string.begin.kotlin
push:
- meta_scope: string.quoted.single.kotlin
- match: "'"
captures:
0: punctuation.definition.string.end.kotlin
pop: true
- match: \\.
scope: constant.character.escape.kotlin
- match: "`"
captures:
0: punctuation.definition.string.begin.kotlin
push:
- meta_scope: string.quoted.single.kotlin
- match: "`"
captures:
0: punctuation.definition.string.end.kotlin
pop: true
typedefs:
- match: (?=\s*(?:type))
push:
- match: (?=$)
pop: true
- match: \b(type)\b
scope: keyword.other.kotlin
- match: <
push:
- match: ">"
pop: true
- include: generics
- include: expressions
types:
- match: \b(Nothing|Any|Unit|String|CharSequence|Int|Boolean|Char|Long|Double|Float|Short|Byte|dynamic)\b
scope: storage.type.buildin.kotlin
- match: \b(IntArray|BooleanArray|CharArray|LongArray|DoubleArray|FloatArray|ShortArray|ByteArray)\b
scope: storage.type.buildin.array.kotlin
- match: \b(Array|Collection|List|Map|Set|MutableList|MutableMap|MutableSet|Sequence)<\b
captures:
1: storage.type.buildin.collection.kotlin
push:
- match: ">"
pop: true
- include: types
- include: keywords
- match: \w+<
push:
- match: ">"
pop: true
- include: types
- include: keywords
- match: '\{'
push:
- match: '\}'
pop: true
- include: statements
- match: \(
push:
- match: \)
pop: true
- include: types
- match: (->)
scope: keyword.operator.declaration.kotlin
variables:
- match: (?=\s*\b(?:var|val)\b)
push:
- match: (?=:|=|(\b(by)\b)|$)
pop: true
- match: \b(var|val)\b
captures:
1: keyword.other.kotlin
push:
- match: (?=:|=|(\b(by)\b)|$)
pop: true
- match: <
push:
- match: ">"
pop: true
- include: generics
- match: '([\.<\?>\w]+\.)?(\w+)'
captures:
2: entity.name.variable.kotlin
- match: (:)
captures:
1: keyword.operator.declaration.kotlin
push:
- match: (?==|$)
pop: true
- include: types
- include: getters-and-setters
- match: \b(by)\b
captures:
1: keyword.other.kotlin
push:
- match: (?=$)
pop: true
- include: expressions
- match: (=)
captures:
1: keyword.operator.assignment.kotlin
push:
- match: (?=$)
pop: true
- include: expressions
- include: getters-and-setters
+2 -1
View File
@@ -77,7 +77,8 @@ Options:
--terminal-width <width>
Explicitly set the width of the terminal instead of determining it automatically. If
prefixed with '+' or '-', the value will be treated as an offset to the actual terminal
width. See also: '--wrap'.
width. This can also be configured via the BAT_WIDTH environment variable (e.g. export
BAT_WIDTH="100"). See also: '--wrap'.
-n, --number
Only show line numbers, no other decorations. This is an alias for '--style=numbers'
+6 -2
View File
@@ -240,6 +240,7 @@ pub fn build_app(interactive_output: bool) -> Command {
.arg(
Arg::new("terminal-width")
.long("terminal-width")
.overrides_with("terminal-width")
.value_name("width")
.hide_short_help(true)
.allow_hyphen_values(true)
@@ -255,10 +256,13 @@ pub fn build_app(interactive_output: bool) -> Command {
})
.map_err(|e| e.to_string())
})
.help(
.help("Explicitly set the width of the terminal instead of determining it automatically.")
.long_help(
"Explicitly set the width of the terminal instead of determining it \
automatically. If prefixed with '+' or '-', the value will be treated \
as an offset to the actual terminal width. See also: '--wrap'.",
as an offset to the actual terminal width. This can also be configured \
via the BAT_WIDTH environment variable (e.g. export BAT_WIDTH=\"100\"). \
See also: '--wrap'.",
),
)
.arg(
+1
View File
@@ -153,6 +153,7 @@ fn get_args_from_str(content: &str) -> Result<Vec<OsString>, shell_words::ParseE
pub fn get_args_from_env_vars() -> Vec<OsString> {
[
("--tabs", "BAT_TABS"),
("--terminal-width", "BAT_WIDTH"),
("--theme", bat::theme::env::BAT_THEME),
("--theme-dark", bat::theme::env::BAT_THEME_DARK),
("--theme-light", bat::theme::env::BAT_THEME_LIGHT),
+26 -1
View File
@@ -285,7 +285,28 @@ fn run_controller(inputs: Vec<Input>, config: &Config, cache_dir: &Path) -> Resu
#[cfg(feature = "bugreport")]
fn invoke_bugreport(app: &App, cache_dir: &Path) {
use bugreport::{bugreport, collector::*, format::Markdown};
use bugreport::{bugreport, collector::*, format::Markdown, report::ReportEntry};
struct ColorSchemeCollector;
impl Collector for ColorSchemeCollector {
fn description(&self) -> &str {
"Detected terminal color scheme"
}
fn collect(
&mut self,
_: &bugreport::CrateInfo,
) -> std::result::Result<ReportEntry, CollectionError> {
let color_scheme = bat::theme::color_scheme(bat::theme::DetectColorScheme::Always);
let text = match color_scheme {
Some(bat::theme::ColorScheme::Dark) => "dark",
Some(bat::theme::ColorScheme::Light) => "light",
None => "not detected",
};
Ok(ReportEntry::Text(text.to_string()))
}
}
let pager = bat::config::get_pager_executable(
app.matches.get_one::<String>("pager").map(|s| s.as_str()),
)
@@ -307,6 +328,9 @@ fn invoke_bugreport(app: &App, cache_dir: &Path) {
"BAT_STYLE",
"BAT_TABS",
"BAT_THEME",
"BAT_WIDTH",
bat::theme::env::BAT_THEME_DARK,
bat::theme::env::BAT_THEME_LIGHT,
"COLORTERM",
"LANG",
"LC_ALL",
@@ -326,6 +350,7 @@ fn invoke_bugreport(app: &App, cache_dir: &Path) {
custom_assets_metadata,
))
.info(DirectoryEntries::new("Custom assets", cache_dir))
.info(ColorSchemeCollector)
.info(CompileTimeInformation::default());
#[cfg(feature = "paging")]
+72 -15
View File
@@ -207,7 +207,7 @@ impl<'a> Input<'a> {
kind: OpenedInputKind::StdIn,
description,
metadata: self.metadata,
reader: InputReader::new(stdin),
reader: InputReader::try_new(stdin)?,
})
}
@@ -236,14 +236,14 @@ impl<'a> Input<'a> {
file = input_identifier.into_inner().expect("The file was lost in the clircle::Identifier, this should not have happened...");
}
InputReader::new(BufReader::new(file))
InputReader::try_new(BufReader::new(file))?
},
}),
InputKind::CustomReader(reader) => Ok(OpenedInput {
description,
kind: OpenedInputKind::CustomReader,
metadata: self.metadata,
reader: InputReader::new(BufReader::new(reader)),
reader: InputReader::try_new(BufReader::new(reader))?,
}),
}
}
@@ -257,28 +257,29 @@ pub(crate) struct InputReader<'a> {
}
impl<'a> InputReader<'a> {
pub(crate) fn new<R: BufRead + 'a>(mut reader: R) -> InputReader<'a> {
let mut first_line = vec![];
reader.read_until(b'\n', &mut first_line).ok();
#[cfg(test)]
pub(crate) fn new<R: BufRead + 'a>(reader: R) -> InputReader<'a> {
Self::try_new(reader).expect("reading the first line failed")
}
let content_type = if first_line.is_empty() {
None
} else {
Some(content_inspector::inspect(&first_line[..]))
};
pub(crate) fn try_new<R: BufRead + 'a>(mut reader: R) -> io::Result<InputReader<'a>> {
let mut first_line = vec![];
reader.read_until(b'\n', &mut first_line)?;
let content_type = inspect_content_type(&first_line);
if content_type == Some(ContentType::UTF_16LE) {
read_utf16_line(&mut reader, &mut first_line, 0x00, 0x0A).ok();
read_utf16_line(&mut reader, &mut first_line, 0x00, 0x0A)?;
} else if content_type == Some(ContentType::UTF_16BE) {
read_utf16_line(&mut reader, &mut first_line, 0x0A, 0x00).ok();
read_utf16_line(&mut reader, &mut first_line, 0x0A, 0x00)?;
}
InputReader {
Ok(InputReader {
inner: Box::new(reader),
first_line,
content_type,
unbuffered: false,
}
})
}
pub(crate) fn read_line(&mut self, buf: &mut Vec<u8>) -> io::Result<bool> {
@@ -319,6 +320,25 @@ impl<'a> InputReader<'a> {
}
}
fn inspect_content_type(first_line: &[u8]) -> Option<ContentType> {
if first_line.is_empty() {
return None;
}
let content_type = content_inspector::inspect(first_line);
if content_type == ContentType::UTF_8 && has_zip_signature(first_line) {
Some(ContentType::BINARY)
} else {
Some(content_type)
}
}
fn has_zip_signature(bytes: &[u8]) -> bool {
[b"PK\x03\x04", b"PK\x05\x06", b"PK\x07\x08"]
.into_iter()
.any(|signature| bytes.starts_with(signature))
}
fn read_utf16_line<R: BufRead>(
reader: &mut R,
buf: &mut Vec<u8>,
@@ -374,6 +394,43 @@ fn basic() {
assert!(buffer.is_empty());
}
#[test]
fn zip_magic_headers_are_treated_as_binary() {
for content in [b"PK\x03\x04hello", b"PK\x05\x06hello", b"PK\x07\x08hello"] {
let reader = InputReader::new(&content[..]);
assert_eq!(Some(ContentType::BINARY), reader.content_type);
}
}
#[test]
fn non_zip_pk_prefix_is_not_treated_as_binary() {
assert_eq!(
Some(ContentType::UTF_8),
inspect_content_type(b"PK\x03\x03hello")
);
}
#[test]
fn input_open_returns_initial_read_errors() {
struct FailingRead;
impl Read for FailingRead {
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
Err(io::Error::other("initial read failed"))
}
}
let input = Input::from_reader(Box::new(FailingRead));
let result = input.open(io::empty(), None);
assert!(result.is_err());
assert!(result
.err()
.unwrap()
.to_string()
.contains("initial read failed"));
}
#[test]
fn utf16le() {
let content = b"\xFF\xFE\x73\x00\x0A\x00\x64\x00";
+2 -2
View File
@@ -155,7 +155,7 @@ impl LessOpenPreprocessor {
Ok(OpenedInput {
kind,
reader: InputReader::new(BufReader::new(
reader: InputReader::try_new(BufReader::new(
if matches!(self.kind, LessOpenKind::TempFile) {
let lessopen_string = match String::from_utf8(lessopen_stdout) {
Ok(string) => string,
@@ -192,7 +192,7 @@ impl LessOpenPreprocessor {
.map(|s| s.replacen("%s", &path_str, 1).replacen("%s", "-", 1)),
}
},
)),
))?,
metadata: input.metadata,
description: input.description,
})
@@ -1,2 +1,2 @@
[mappings]
"XML" = ["*.csproj", "*.vbproj", "*.props", "*.targets"]
"XML" = ["*.csproj", "*.vbproj", "*.props", "*.targets", "*.slnx"]
+2
View File
@@ -0,0 +1,2 @@
#!/usr/bin/expect -f
set timeout 30
+2
View File
@@ -0,0 +1,2 @@
#!/usr/bin/env tclsh
puts "Hello from tclsh"
+2
View File
@@ -0,0 +1,2 @@
#!/usr/bin/wish
button .b -text "Click"
+103
View File
@@ -1047,6 +1047,57 @@ fn tabs_4_arg_overrides_env_noconfig() {
);
}
#[test]
fn terminal_width_env_var_is_respected() {
let tmp_dir = tempdir().expect("can create temporary directory");
let tmp_path = tmp_dir.path().join("long.txt");
std::fs::write(
&tmp_path,
"0123456789abcdef0123456789abcdef0123456789abcdef\n",
)
.expect("can write temporary file");
bat()
.env("BAT_WIDTH", "20")
.arg(&tmp_path)
.arg("--paging=never")
.arg("--color=never")
.arg("--style=numbers")
.arg("--decorations=always")
.arg("--wrap=character")
.assert()
.success()
.stdout(" 1 0123456789abcde\n f0123456789abcd\n ef0123456789abc\n def\n")
.stderr("");
}
#[test]
fn terminal_width_arg_overrides_env() {
let tmp_dir = tempdir().expect("can create temporary directory");
let tmp_path = tmp_dir.path().join("long.txt");
std::fs::write(
&tmp_path,
"0123456789abcdef0123456789abcdef0123456789abcdef\n",
)
.expect("can write temporary file");
bat()
.env("BAT_WIDTH", "20")
.arg(&tmp_path)
.arg("--paging=never")
.arg("--color=never")
.arg("--style=numbers")
.arg("--decorations=always")
.arg("--wrap=character")
.arg("--terminal-width=10")
.assert()
.success()
.stdout(
" 1 01234\n 56789\n abcde\n f0123\n 45678\n 9abcd\n ef012\n 34567\n 89abc\n def\n",
)
.stderr("");
}
#[test]
fn fail_non_existing() {
bat().arg("non-existing-file").assert().failure();
@@ -1474,6 +1525,7 @@ fn diagnostic_sanity_check() {
.assert()
.success()
.stdout(predicate::str::contains("BAT_PAGER="))
.stdout(predicate::str::contains("BAT_WIDTH="))
.stderr("");
}
@@ -2093,6 +2145,24 @@ fn header_binary() {
.stderr("");
}
#[test]
fn header_zip_file_is_binary() {
let tmp_dir = tempdir().expect("can create temporary directory");
let tmp_path = tmp_dir.path().join("test.zip");
std::fs::write(&tmp_path, b"PK\x03\x04hello").expect("can write temporary file");
bat()
.arg(&tmp_path)
.arg("--decorations=always")
.arg("--style=header")
.arg("-r=0:0")
.arg("--file-name=test.zip")
.assert()
.success()
.stdout("File: test.zip <BINARY>\n")
.stderr("");
}
#[test]
fn header_full_binary() {
bat()
@@ -4132,3 +4202,36 @@ fn plain_without_diff_still_works() {
.success()
.stdout("line 1\nline 2 modified\nline 3\nline 4 added\n");
}
#[test]
fn tcl_shebang_detection_tclsh() {
bat()
.arg("--color=always")
.arg("--style=plain")
.arg("--decorations=always")
.arg("regression_tests/issue_3647_tclsh")
.assert()
.success();
}
#[test]
fn tcl_shebang_detection_wish() {
bat()
.arg("--color=always")
.arg("--style=plain")
.arg("--decorations=always")
.arg("regression_tests/issue_3647_wish")
.assert()
.success();
}
#[test]
fn tcl_shebang_detection_expect() {
bat()
.arg("--color=always")
.arg("--style=plain")
.arg("--decorations=always")
.arg("regression_tests/issue_3647_expect")
.assert()
.success();
}
Vendored Executable → Regular
+12 -10
View File
@@ -4,6 +4,7 @@ import itertools
import subprocess
import pathlib
import shutil
from typing import Iterable
def generate_snapshots():
@@ -19,22 +20,23 @@ def generate_snapshots():
def generate_style_snapshot(style):
generate_snapshot(style.replace(",", "_"), "--style={}".format(style))
generate_snapshot(style.replace(",", "_"), ["--style={}".format(style)])
def generate_snapshot(name, arguments):
command = "cargo run -- --paging=never --color=never --decorations=always "
command += "{args} sample.rs > output/{name}.snapshot.txt".format(
name=name,
args=arguments
)
def generate_snapshot(name: str, arguments: Iterable[str]):
output_file = "output/{name}.snapshot.txt".format(name=name)
command = [
"cargo", "run", "--", "--paging=never", "--color=never",
"--decorations=always", *arguments, "sample.rs"
]
print("generating snapshot for {}".format(name))
subprocess.call(command, shell=True)
with open(output_file, "w") as f:
subprocess.call(command, stdout=f)
def build_bat():
print("building bat")
subprocess.call("cargo build", cwd="../..", shell=True)
subprocess.call(["cargo", "build"], cwd="../..")
def prepare_output_dir():
@@ -49,7 +51,7 @@ def modify_sample_file():
def undo_sample_file_modification():
print("undoing sample.rs modifications")
subprocess.call("git checkout -- sample.rs", shell=True)
subprocess.call(["git", "checkout", "--", "sample.rs"])
build_bat()
+52 -52
View File
@@ -1,85 +1,85 @@
import kotlin.math.*
import kotlin.math.*
data class Example(
 val name: String,
 val numbers: List<Int?>
data class Example(
 val name: String,
 val numbers: List<Int?>
)
fun interface JokeInterface {
 fun isFunny(): Boolean
fun interface JokeInterface {
 fun isFunny(): Boolean
}
abstract class AbstractJoke : JokeInterface {
 override fun isFunny() = false
 abstract fun content(): String
abstract class AbstractJoke : JokeInterface {
 override fun isFunny() = false
 abstract fun content(): String
}
class Joke : AbstractJoke() {
 override fun isFunny(): Boolean {
class Joke : AbstractJoke() {
 override fun isFunny(): Boolean {
 return true
 }
 override fun content(): String = "content of joke here, haha"
 }
 override fun content(): String = "content of joke here, haha"
}
class DelegatedJoke(val joke: Joke) : JokeInterface by joke {
 val number: Long = 123L
class DelegatedJoke(val joke: Joke) : JokeInterface by joke {
 val number: Long = 123L
 companion object {
 const val someConstant = "some constant text"
 }
 companion object {
 const val someConstant = "some constant text"
 }
}
object SomeSingleton
object SomeSingleton
sealed class Shape {
 abstract fun area(): Double
sealed class Shape {
 abstract fun area(): Double
}
data class Square(val sideLength: Double) : Shape() {
 override fun area(): Double = sideLength.pow(2)
data class Square(val sideLength: Double) : Shape() {
 override fun area(): Double = sideLength.pow(2)
}
object Point : Shape() {
 override fun area() = .0
object Point : Shape() {
 override fun area() = .0
}
class Circle(val radius: Double) : Shape() {
 override fun area(): Double {
 return PI * radius * radius
 }
class Circle(val radius: Double) : Shape() {
 override fun area(): Double {
 return PI * radius * radius
 }
}
fun String.extensionMethod() = "test"
fun String.extensionMethod() = "test"
fun main() {
 val name = """
fun main() {
 val name = """
 multiline
 string
 
 some numbers: 123123 42
 """.trimIndent()
 val example = Example(name = name, numbers = listOf(512, 42, null, -1))
 """.trimIndent()
 val example = Example(name = name, numbers = listOf(512, 42, null, -1))
 example.numbers
 .filterNotNull()
 .forEach { println(it) }
 example.numbers
 .filterNotNull()
 .forEach { println(it) }
 setOf(Joke(), DelegatedJoke(Joke()).joke)
 .filter(JokeInterface::isFunny)
 .map(AbstractJoke::content)
 .forEachIndexed { index: Int, joke ->
 println("I heard a funny joke(#${index + 1}): $joke")
 }
 setOf(Joke(), DelegatedJoke(Joke()).joke)
 .filter(JokeInterface::isFunny)
 .map(AbstractJoke::content)
 .forEachIndexed { index: Int, joke ->
 println("I heard a funny joke(#${index + 1}): $joke")
 }
 listOf(Square(12.3), Point, Circle(5.2))
 .associateWith(Shape::area)
 .toList()
 .sortedBy { it.second }
 .forEach {
 println("${it.first}: ${it.second}")
 }
 listOf(Square(12.3), Point, Circle(5.2))
 .associateWith(Shape::area)
 .toList()
 .sortedBy { it.second }
 .forEach {
 println("${it.first}: ${it.second}")
 }
 println("some string".extensionMethod())
 println("some string".extensionMethod())
 require(SomeSingleton::class.simpleName == "SomeSingletonName") { "something does not seem right..." }
 require(SomeSingleton::class.simpleName == "SomeSingletonName") { "something does not seem right..." }
}
+7
View File
@@ -0,0 +1,7 @@
#!/usr/bin/expect -f
# Expect script detected via expect shebang
set timeout 30
spawn ssh user@host
expect "password:"
send "secret\r"
expect eof
+7
View File
@@ -0,0 +1,7 @@
#!/usr/bin/env tclsh
# Tcl script detected via tclsh shebang
puts "Hello from tclsh"
set x 42
if {$x > 0} {
 puts "positive"
}
+5
View File
@@ -0,0 +1,5 @@
#!/usr/bin/wish
# Tk script detected via wish shebang
package require Tk
button .b -text "Click" -command {puts "clicked"}
pack .b
+7
View File
@@ -0,0 +1,7 @@
<Solution>
 <Folder Name="/Build/">
 <File Path="Directory.Build.props" />
 <File Path="projectname.targets" />
 </Folder>
 <Project Path="console.csproj" />
</Solution>
+7
View File
@@ -0,0 +1,7 @@
#!/usr/bin/expect -f
# Expect script detected via expect shebang
set timeout 30
spawn ssh user@host
expect "password:"
send "secret\r"
expect eof
+7
View File
@@ -0,0 +1,7 @@
#!/usr/bin/env tclsh
# Tcl script detected via tclsh shebang
puts "Hello from tclsh"
set x 42
if {$x > 0} {
puts "positive"
}
+5
View File
@@ -0,0 +1,5 @@
#!/usr/bin/wish
# Tk script detected via wish shebang
package require Tk
button .b -text "Click" -command {puts "clicked"}
pack .b
+7
View File
@@ -0,0 +1,7 @@
<Solution>
<Folder Name="/Build/">
<File Path="Directory.Build.props" />
<File Path="projectname.targets" />
</Folder>
<Project Path="console.csproj" />
</Solution>