1
0
mirror of https://github.com/sharkdp/bat synced 2026-08-04 19:01:44 +00:00

Compare commits

..

67 Commits

Author SHA1 Message Date
dependabot[bot] b739f7d1e8 build(deps): bump softprops/action-gh-release from 2 to 3
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2 to 3.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/v2...v3)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: '3'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-01 02:12:24 +00:00
Keith Hall 7fcab0616a Merge pull request #3700 from optimistiCli/list-themes-term-probe-fix
Fixed hardcoded terminal probing when `--list-themes` is called
2026-04-30 18:09:32 +03:00
Keith Hall e157ac911b Merge branch 'master' into list-themes-term-probe-fix 2026-04-30 17:58:24 +03:00
Keith Hall b29e1d55c4 Merge pull request #3709 from mvanhorn/osc/3228-readme-style-list
docs(README): list available --style components in Output style section
2026-04-30 14:15:25 +03:00
Keith Hall 12ee94f530 Merge branch 'master' into list-themes-term-probe-fix 2026-04-30 14:13:47 +03:00
Matt Van Horn cbe7919451 docs(README): list available --style components in Output style section
The Output style section explained how to combine values into --style
without listing what those values are, so the recommended path was
either to read the man page or grep the source. Adds two tables: the
four pre-defined styles (default, full, auto, plain) and the eight
individual components (changes, header, header-filename, header-filesize,
grid, rule, numbers, snip), copying the descriptions from `bat --help`
verbatim. Also calls out the default-enabled set explicitly so the
"by default..." sentence in the existing tip block has a referent.

Closes #3228
2026-04-30 01:54:42 -07:00
David Peter 10b4f07a87 Remove sponsors 2026-04-30 10:18:58 +02:00
David Peter ebf469b99a Update README 2026-04-30 10:16:33 +02:00
Keith Hall 8fbc96a5f2 Merge pull request #3654 from cuiweixie/fix/lessclose-nonzero-warning
fix: correct $LESSCLOSE exit-status warning
2026-04-30 08:19:42 +03:00
Keith Hall 54bfc33248 Merge branch 'master' into fix/lessclose-nonzero-warning 2026-04-30 08:10:40 +03:00
Keith Hall 91aac95db2 Merge pull request #3691 from curious-rabbit/master
sanitize filenames
2026-04-28 23:24:00 +03:00
Keith Hall 5977245a23 Merge branch 'master' into fix/lessclose-nonzero-warning 2026-04-28 19:24:00 +03:00
Keith Hall 3f98e6f10f Merge branch 'master' into master 2026-04-28 19:22:51 +03:00
auto-merge-dependabot-prs[bot] 78963986e0 Merge pull request #3666 from sharkdp/dependabot/submodules/assets/syntaxes/02_Extra/Idris2-4d8eb35
build(deps): bump assets/syntaxes/02_Extra/Idris2 from `bbfe50e` to `4d8eb35`
2026-04-27 19:41:31 +00:00
dependabot[bot] de64d3a0eb build(deps): bump assets/syntaxes/02_Extra/Idris2
Bumps [assets/syntaxes/02_Extra/Idris2](https://github.com/buzden/sublime-syntax-idris2) from `bbfe50e` to `4d8eb35`.
- [Commits](https://github.com/buzden/sublime-syntax-idris2/compare/bbfe50e023e0edc74f5e0c003eb946528d49279f...4d8eb35a38254d422030e77b4933530008dd3c6e)

---
updated-dependencies:
- dependency-name: assets/syntaxes/02_Extra/Idris2
  dependency-version: 4d8eb35a38254d422030e77b4933530008dd3c6e
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-27 19:28:44 +00:00
Keith Hall 78cb14af05 Merge pull request #3699 from guille/master
Improve Kotlin syntax
2026-04-27 22:26:10 +03:00
Keith Hall 8c8ed90d6d Merge branch 'master' into master 2026-04-27 22:20:33 +03:00
guille 492c387ce7 CHANGELOG: reference PR not issue 2026-04-27 22:16:09 +03:00
guille bceb260e91 Improve Kotlin syntax 2026-04-27 22:16:09 +03:00
Keith Hall 8cadefb5cb Merge pull request #3706 from lawrence3699/fix/initial-read-errors
Propagate initial input read errors
2026-04-27 21:46:10 +03:00
lawrence3699 64567c4819 Propagate initial input read errors 2026-04-28 01:11:48 +10:00
Keith Hall de2f21562a Merge pull request #3704 from sharkdp/fix/zsh-completion-language-word-split
Fix/zsh completion language word split
2026-04-27 06:07:37 +03:00
Yoshi Tacke 5722311b2e docs(changelog): add bugfix entry for zsh completion fix 2026-04-27 05:55:48 +03:00
YoshKoz f39d63b85d fix(zsh): use newline-splitting for language completions to fix word-splitting on names with spaces
Language names like "HTML (Jinja2)" and "Apache Conf" contain spaces, which
caused $() command substitution to word-split them into garbage tokens. Use
${(f)"$(...)"}  (split on newlines only) to match the pattern already used
for theme completions on line 100.

Fixes #2897
2026-04-27 05:55:48 +03:00
Ish West 4144059e7a Fixed CHANGELOG.md entry format 2026-04-25 21:30:03 +02:00
Ish West 044d445adc Updated CHANGELOG.md 2026-04-25 21:17:02 +02:00
Ish West c3df0e6a88 Fixed a bug with hardcoded terminal probing when --list-themes is called 2026-04-25 17:37:36 +02:00
curious-rabbit 71c894e843 santize filenames 2026-04-20 14:25:49 +02:00
Keith Hall 93c52a4f88 Merge pull request #3692 from barry3406/fix/remove-crt-windows
windows: statically link the CRT to remove vcruntime dependency
2026-04-20 05:09:54 +03:00
Barry ea7fafca1e windows: statically link the CRT to remove vcruntime dependency
Add a .cargo/config.toml that sets target-feature=+crt-static for the
i686, x86_64, and aarch64 MSVC targets so bat.exe no longer depends on
the vcruntime DLL. Mirrors the fix applied to fd in sharkdp/fd#1891.

Closes #3634
2026-04-19 14:19:00 -07:00
Keith Hall e782ec125c Merge pull request #3647 from mvanhorn/osc/3513-tcl-shebang
feat: add tclsh, wish, and expect shebang detection for Tcl syntax
2026-04-19 05:52:52 +03:00
Matt Van Horn 0ecdeb28d4 test(Tcl): regenerate shebang golden files to match patched syntax
The Tcl.sublime-syntax.patch adds first_line_match so bat recognizes
tclsh/wish/expect shebang files as Tcl. With the patch applied, the
leading '#!/...' and '# comment' lines get tokenized as Tcl comments
and rendered in Monokai-Extended's comment color instead of default
foreground.

The goldens were generated against unpatched bat in the original
commit, so CI's 'Run tests with updated syntaxes and themes' job (which
runs assets/create.sh before the regression test) disagreed. Regenerate
against the patched build so the regression test passes.
2026-04-18 09:42:26 -07:00
Matt Van Horn 77ea750e66 test(Tcl): add shebang source files for regression test
CI reported FileNotFoundError for Tcl/{tclsh,expect,wish}_shebang in
tests/syntax-tests/source/Tcl/. The highlighted files existed but the
source files had been omitted, so create_highlighted_versions.py had
nothing to read from.

Source files match the shebang regression test inputs at
tests/examples/regression_tests/issue_3647_*.
2026-04-18 06:58:45 -07:00
Matt Van Horn cafad6b036 test: add highlighted outputs for Tcl shebang regression tests
Generate highlighted test outputs for tclsh, wish, and expect
shebang detection files to prevent regressions.
2026-04-18 06:39:51 -07:00
Matt Van Horn e070d105b5 test: add shebang regression tests and move changelog to Syntaxes section
Add extensionless regression test files for tclsh, wish, and expect
shebangs so syntect bumps don't silently break first-line detection.
Move changelog entry from Features to Syntaxes per reviewer suggestion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-18 06:38:44 -07:00
Matt Van Horn 1f89178fce fix: reference PR number in changelog entry 2026-04-18 06:38:27 -07:00
Matt Van Horn 52763e0205 feat: add tclsh, wish, and expect shebang detection for Tcl syntax
Add first_line_match to the Tcl syntax definition via a patch file,
enabling automatic Tcl highlighting for scripts with tclsh, wish,
or expect shebangs.

Fixes #3513
2026-04-18 06:38:18 -07:00
Keith Hall f822bd05ce Merge pull request #3689 from janlarres/python-uv
[Python] Support uv as script runner in shebang
2026-04-13 20:28:02 +03:00
Jan Larres e89c515e9a [Python] Support uv as script runner in shebang 2026-04-13 17:56:05 +12:00
Keith Hall a36b02d90f Merge pull request #3688 from orbisai0security/fix-fix-shell-injection-subprocess-call
fix: sanitize subprocess call in generate_snapshots.py
2026-04-12 16:04:47 +03:00
Kira Security Bot 6876a782da Apply code changes: @orbisai0security can you address code review comm... 2026-04-12 12:37:43 +00:00
orbisai0security db647c9813 fix: V-001 security vulnerability
Automated security fix generated by Orbis Security AI
2026-04-12 11:43:12 +00:00
Keith Hall 33045c3558 Merge pull request #3687 from officialasishkumar/support-bat-width-env
Support BAT_WIDTH for terminal width
2026-04-12 04:59:03 +03:00
Asish Kumar 01174b31f5 Update changelog entry for #3687
Signed-off-by: Asish Kumar <officialasishkumar@gmail.com>
2026-04-12 01:13:08 +05:30
Asish Kumar a9137fab05 Support BAT_WIDTH as an alias for --terminal-width
Signed-off-by: Asish Kumar <officialasishkumar@gmail.com>
2026-04-12 01:12:55 +05:30
Keith Hall a995764d23 Merge pull request #3686 from officialasishkumar/fix-zip-binary-detection
Detect ZIP archives as binary content
2026-04-10 20:30:27 +03:00
Asish Kumar b3aec318cf Update changelog entry for #3686 2026-04-10 14:37:00 +00:00
Asish Kumar 2459aa9404 Detect ZIP archives as binary content 2026-04-10 14:35:33 +00:00
Keith Hall 111aa2e10e Merge pull request #3682 from ltrzesniewski/slnx
Add .NET `slnx` extension
2026-04-08 05:20:55 +03:00
Lucas Trzesniewski c64b6761fe Add .NET slnx extension
This is the new XML-based format for solution files.
2026-04-07 23:25:40 +02:00
Keith Hall 11efacbe64 Merge pull request #3661 from sharkdp/diagnostic_themes
Update --diagnostic output with BAT_THEME_LIGHT/DARK env vars and detected theme type
2026-04-02 21:44:28 +03:00
Keith Hall 204ca18d71 Merge branch 'master' into diagnostic_themes 2026-04-02 21:36:24 +03:00
auto-merge-dependabot-prs[bot] a158f12106 Merge pull request #3669 from sharkdp/dependabot/cargo/quote-1.0.45
build(deps): bump quote from 1.0.40 to 1.0.45
2026-04-01 04:07:40 +00:00
dependabot[bot] 956f0aeb08 build(deps): bump quote from 1.0.40 to 1.0.45
Bumps [quote](https://github.com/dtolnay/quote) from 1.0.40 to 1.0.45.
- [Release notes](https://github.com/dtolnay/quote/releases)
- [Commits](https://github.com/dtolnay/quote/compare/1.0.40...1.0.45)

---
updated-dependencies:
- dependency-name: quote
  dependency-version: 1.0.45
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-01 03:54:15 +00:00
auto-merge-dependabot-prs[bot] 1a6073d2e8 Merge pull request #3668 from sharkdp/dependabot/cargo/tempfile-3.27.0
build(deps): bump tempfile from 3.23.0 to 3.27.0
2026-04-01 03:51:21 +00:00
dependabot[bot] 57e99e9bcd build(deps): bump tempfile from 3.23.0 to 3.27.0
Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.23.0 to 3.27.0.
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.23.0...v3.27.0)

---
updated-dependencies:
- dependency-name: tempfile
  dependency-version: 3.27.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-01 03:38:08 +00:00
auto-merge-dependabot-prs[bot] 68eaa96e06 Merge pull request #3664 from sharkdp/dependabot/cargo/toml-1.1.1spec-1.1.0
build(deps): bump toml from 0.9.8 to 1.1.1+spec-1.1.0
2026-04-01 03:34:35 +00:00
dependabot[bot] de9ca4ef7b build(deps): bump toml from 0.9.8 to 1.1.1+spec-1.1.0
Bumps [toml](https://github.com/toml-rs/toml) from 0.9.8 to 1.1.1+spec-1.1.0.
- [Commits](https://github.com/toml-rs/toml/compare/toml-v0.9.8...toml-v1.1.1)

---
updated-dependencies:
- dependency-name: toml
  dependency-version: 1.1.1+spec-1.1.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-01 03:13:41 +00:00
auto-merge-dependabot-prs[bot] 7bb905436b Merge pull request #3667 from sharkdp/dependabot/cargo/unicode-width-0.2.2
build(deps): bump unicode-width from 0.2.1 to 0.2.2
2026-04-01 03:11:34 +00:00
dependabot[bot] f820ad1050 build(deps): bump unicode-width from 0.2.1 to 0.2.2
Bumps [unicode-width](https://github.com/unicode-rs/unicode-width) from 0.2.1 to 0.2.2.
- [Commits](https://github.com/unicode-rs/unicode-width/compare/v0.2.1...v0.2.2)

---
updated-dependencies:
- dependency-name: unicode-width
  dependency-version: 0.2.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-01 02:41:02 +00:00
auto-merge-dependabot-prs[bot] 259e1266a8 Merge pull request #3665 from sharkdp/dependabot/cargo/unicode-segmentation-1.13.2
build(deps): bump unicode-segmentation from 1.12.0 to 1.13.2
2026-04-01 02:37:51 +00:00
dependabot[bot] 31b0a35719 build(deps): bump unicode-segmentation from 1.12.0 to 1.13.2
Bumps [unicode-segmentation](https://github.com/unicode-rs/unicode-segmentation) from 1.12.0 to 1.13.2.
- [Commits](https://github.com/unicode-rs/unicode-segmentation/compare/v1.12.0...v1.13.2)

---
updated-dependencies:
- dependency-name: unicode-segmentation
  dependency-version: 1.13.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-01 02:03:59 +00:00
Keith Hall 3e4169b8c3 cargo fmt 2026-03-31 22:35:21 +03:00
Keith Hall ba223289ce Update --diagnostic output with detected terminal color scheme type 2026-03-31 22:23:10 +03:00
Keith Hall abab6533e4 Update --diagnostic output with BAT_THEME_LIGHT/DARK env vars 2026-03-31 22:22:31 +03:00
Weixie Cui 5c3b8040db fix: add changelog entry for LESSCLOSE warning fix 2026-03-26 11:11:19 +08:00
Weixie Cui 7ff1fb3278 fix: warn when $LESSCLOSE fails, not when it succeeds
The Drop cleanup for Preprocessed inverted the exit-status check, so bat
emitted a warning when LESSCLOSE exited successfully and stayed silent on
failure. Align the condition with the intended behavior.
2026-03-26 11:10:58 +08:00
43 changed files with 545 additions and 641 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"]
+1 -1
View File
@@ -442,7 +442,7 @@ jobs:
echo "IS_RELEASE=${IS_RELEASE}" >> $GITHUB_OUTPUT
- name: Publish archives and packages
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v3
if: steps.is-release.outputs.IS_RELEASE
with:
files: |
+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
+12
View File
@@ -4,20 +4,28 @@
## 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 `--list-themes` unconditionally probing the terminal via OSC 10/11 even when `--theme` was set to an explicit value, see #3700 (regression introduced in bc42149a). (@optimistiCli)
- Fix inverted `$LESSCLOSE` warning so bat warns on nonzero exit, not on success. See #3654 (@cuiweixie)
- Sanitize control characters in filenames before displaying them in the file header, error messages, and the terminal title, preventing ANSI escape injection via crafted filenames. Closes #3054, see #3691 (@curious-rabbit)
- 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)
@@ -32,21 +40,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]
+24 -20
View File
@@ -19,20 +19,6 @@
[<a href="doc/README-ru.md">Русский</a>]
</p>
### Sponsors
A special *thank you* goes to our biggest <a href="doc/sponsors.md">sponsors</a>:<br>
<p>
<a href="https://www.warp.dev/bat">
<img src="doc/sponsors/warp-logo.png" width="200" alt="Warp">
<br>
<strong>Warp, the intelligent terminal</strong>
<br>
<sub>Available on MacOS, Linux, Windows</sub>
</a>
</p>
### Syntax highlighting
`bat` supports syntax highlighting for a large number of programming and markup
@@ -208,12 +194,6 @@ Note that the [Manpage syntax](assets/syntaxes/02_Extra/Manpage.sublime-syntax)
The [`prettybat`](https://github.com/eth-p/bat-extras/blob/master/doc/prettybat.md) script is a wrapper that will format code and print it with `bat`.
#### `Warp`
<a href="https://app.warp.dev/drive/folder/-Bat-Warp-Pack-lxhe7HrEwgwpG17mvrFSz1">
<img src="doc/sponsors/warp-pack-header.png" alt="Warp">
</a>
#### Highlighting `--help` messages
You can use `bat` to colorize help text: `$ cp --help | bat -plhelp`
@@ -527,6 +507,30 @@ and line numbers but no grid and no file header. Set the `BAT_STYLE` environment
variable to make these changes permanent or use `bat`'s
[configuration file](#configuration-file).
By default, `bat` enables `changes`, `grid`, `header-filename`, `numbers`, and `snip`.
The available pre-defined styles are:
| Style | Description |
|-------|-------------|
| `default` | Enables the recommended style components listed above. |
| `full` | Enables all available components. |
| `auto` | Same as `default`, unless the output is piped. |
| `plain` | Disables all available components. |
The available individual components are:
| Component | Description |
|-----------|-------------|
| `changes` | Show Git modification markers. |
| `header` | Alias for `header-filename`. |
| `header-filename` | Show filenames before the content. |
| `header-filesize` | Show file sizes before the content. |
| `grid` | Vertical/horizontal lines to separate the side bar and header from the content. |
| `rule` | Horizontal lines to delimit files. |
| `numbers` | Show line numbers in the side bar. |
| `snip` | Draw separation lines between distinct line ranges. |
>[!tip]
> If you specify a default style in `bat`'s config file, you can change which components
> are displayed during a single run of `bat` using the `--style` command-line argument.
+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'
-2
View File
@@ -10,5 +10,3 @@ No issue will have a different priority based on sponsorship status of the
reporter.
Contributions from anybody are most welcomed, please see our [`CONTRIBUTING.md`](../CONTRIBUTING.md) guide.
If you want to see our biggest sponsors, check the top of [`README.md`](../README.md#sponsors).
Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

+11 -5
View File
@@ -158,7 +158,9 @@ impl HighlightingAssets {
let syntax_match = mapping.get_syntax_for(path);
if let Some(MappingTarget::MapToUnknown) = syntax_match {
return Err(Error::UndetectedSyntax(path.to_string_lossy().into()));
return Err(Error::UndetectedSyntax(
crate::preprocessor::sanitize_for_terminal(&path.to_string_lossy()),
));
}
if let Some(MappingTarget::MapTo(syntax_name)) = syntax_match {
@@ -175,13 +177,17 @@ impl HighlightingAssets {
) {
(Some(syntax), _) => Ok(syntax),
(_, Some(MappingTarget::MapExtensionToUnknown)) => {
Err(Error::UndetectedSyntax(path.to_string_lossy().into()))
}
(_, Some(MappingTarget::MapExtensionToUnknown)) => Err(Error::UndetectedSyntax(
crate::preprocessor::sanitize_for_terminal(&path.to_string_lossy()),
)),
_ => self
.get_syntax_for_file_extension(file_name, &mapping.ignored_suffixes)?
.ok_or_else(|| Error::UndetectedSyntax(path.to_string_lossy().into())),
.ok_or_else(|| {
Error::UndetectedSyntax(crate::preprocessor::sanitize_for_terminal(
&path.to_string_lossy(),
))
}),
}
}
+2 -28
View File
@@ -50,11 +50,6 @@ pub struct App {
/// (not from config file or environment variables).
/// This is used to honor the flag when piping output, similar to `cat -n`.
number_from_cli: bool,
/// True if --wrap=character was passed on the command line
/// (not from config file or environment variables).
/// When piping output (non-interactive), --wrap=character is ignored unless
/// it was explicitly provided on the command line.
wrap_character_from_cli: bool,
}
impl App {
@@ -95,18 +90,6 @@ impl App {
false
});
// Check if --wrap=character was passed on the command line
// (before merging with config file and environment variables).
// This is needed to honor --wrap=character when piping output, while
// ignoring it when it comes only from the config file or BAT_OPTS.
let cli_args_vec: Vec<_> = wild::args_os().collect();
let wrap_character_from_cli = cli_args_vec
.iter()
.any(|arg| arg.to_string_lossy() == "--wrap=character")
|| cli_args_vec.windows(2).any(|pair| {
pair[0].to_string_lossy() == "--wrap" && pair[1].to_string_lossy() == "character"
});
let matches = Self::matches(interactive_output)?;
if matches.get_flag("help") {
@@ -147,7 +130,6 @@ impl App {
matches,
interactive_output,
number_from_cli,
wrap_character_from_cli,
})
}
@@ -426,15 +408,7 @@ impl App {
WrappingMode::NoWrapping(true)
} else {
match self.matches.get_one::<String>("wrap").map(|s| s.as_str()) {
Some("character") => {
if !self.interactive_output && !self.wrap_character_from_cli {
// When piping output (non-interactive), ignore --wrap=character
// unless it was explicitly provided on the command line.
WrappingMode::NoWrapping(false)
} else {
WrappingMode::Character
}
}
Some("character") => WrappingMode::Character,
Some("word") => WrappingMode::Word,
Some("never") => WrappingMode::NoWrapping(true),
Some("auto") | None => {
@@ -671,7 +645,7 @@ impl App {
Ok(styled_components)
}
fn theme_options(&self) -> ThemeOptions {
pub(crate) fn theme_options(&self) -> ThemeOptions {
Self::theme_options_from_matches(&self.matches)
}
+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),
+33 -7
View File
@@ -17,7 +17,6 @@ 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;
@@ -39,7 +38,7 @@ use bat::{
error::*,
input::Input,
style::{StyleComponent, StyleComponents},
theme::{color_scheme, default_theme, ColorScheme},
theme::{default_theme, theme, ColorScheme, ThemeOptions},
MappingTarget, PagingMode,
};
@@ -197,7 +196,7 @@ pub fn list_themes(
cfg: &Config,
config_dir: &Path,
cache_dir: &Path,
detect_color_scheme: DetectColorScheme,
theme_options: ThemeOptions,
) -> Result<()> {
let assets = assets_from_cache_or_binary(cfg.use_custom_assets, cache_dir)?;
let mut config = cfg.clone();
@@ -206,7 +205,7 @@ pub fn list_themes(
config.language = Some("Rust");
config.style_components = StyleComponents(style);
let default_theme_name = default_theme(color_scheme(detect_color_scheme).unwrap_or_default());
let default_theme_name = theme(theme_options).to_string();
let mut buf = String::new();
let mut handle = OutputHandle::FmtWrite(&mut buf);
@@ -259,7 +258,9 @@ pub fn list_themes(
fn set_terminal_title_to(new_terminal_title: String) {
let osc_command_for_setting_terminal_title = "\x1b]0;";
let osc_end_command = "\x07";
print!("{osc_command_for_setting_terminal_title}{new_terminal_title}{osc_end_command}");
// Prevent BEL/ESC/C1 bytes in the title from terminating or nesting the OSC.
let safe_title = bat::sanitize_for_terminal(&new_terminal_title);
print!("{osc_command_for_setting_terminal_title}{safe_title}{osc_end_command}");
io::stdout().flush().unwrap();
}
@@ -285,7 +286,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 +329,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 +351,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")]
@@ -401,7 +427,7 @@ fn run() -> Result<bool> {
};
run_controller(inputs, &plain_config, cache_dir)
} else if app.matches.get_flag("list-themes") {
list_themes(&config, config_dir, cache_dir, DetectColorScheme::default())?;
list_themes(&config, config_dir, cache_dir, app.theme_options())?;
Ok(true)
} else if app.matches.get_flag("config-file") {
println!("{}", config_file().to_string_lossy());
+80 -23
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)?,
})
}
@@ -216,34 +216,34 @@ impl<'a> Input<'a> {
description,
metadata: self.metadata,
reader: {
let mut file = File::open(&path)
.map_err(|e| format!("'{}': {e}", path.to_string_lossy()))?;
let path_display =
crate::preprocessor::sanitize_for_terminal(&path.to_string_lossy());
let mut file =
File::open(&path).map_err(|e| format!("'{path_display}': {e}"))?;
if file.metadata()?.is_dir() {
return Err(format!("'{}' is a directory.", path.to_string_lossy()).into());
return Err(format!("'{path_display}' is a directory.").into());
}
if let Some(stdout) = stdout_identifier {
let input_identifier = Identifier::try_from(file).map_err(|e| {
format!("{}: Error identifying file: {e}", path.to_string_lossy())
})?;
let input_identifier = Identifier::try_from(file)
.map_err(|e| format!("{path_display}: Error identifying file: {e}"))?;
if stdout.surely_conflicts_with(&input_identifier) {
return Err(format!(
"IO circle detected. The input from '{}' is also an output. Aborting to avoid infinite loop.",
path.to_string_lossy()
"IO circle detected. The input from '{path_display}' is also an output. Aborting to avoid infinite loop.",
)
.into());
}
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";
+3 -3
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,
})
@@ -261,7 +261,7 @@ impl Drop for Preprocessed {
}
};
if lessclose_output.status.success() {
if !lessclose_output.status.success() {
bat_warning!("$LESSCLOSE exited with nonzero exit code",)
};
}
+1
View File
@@ -54,6 +54,7 @@ mod vscreen;
pub(crate) mod wrapping;
pub use nonprintable_notation::{BinaryBehavior, NonprintableNotation};
pub use preprocessor::sanitize_for_terminal;
pub use preprocessor::StripAnsiMode;
pub use pretty_printer::{Input, PrettyPrinter, Syntax};
pub use syntax_mapping::{MappingTarget, SyntaxMapping};
+66
View File
@@ -149,6 +149,35 @@ pub fn strip_ansi(line: &str) -> String {
buffer
}
/// Escape C0, DEL, and C1 control characters so a string from an untrusted
/// filename or path can be safely written to the terminal.
pub fn sanitize_for_terminal(input: &str) -> String {
if !input
.chars()
.any(|c| matches!(c, '\x00'..='\x08' | '\x0A'..='\x1F' | '\x7F'..='\u{9F}'))
{
return input.to_owned();
}
let mut out = String::with_capacity(input.len() + 8);
for c in input.chars() {
match c {
'\t' => out.push('\t'),
'\x00'..='\x1F' => {
out.push('^');
out.push(char::from_u32(0x40 + c as u32).unwrap_or('?'));
}
'\x7F' => out.push_str("^?"),
'\u{80}'..='\u{9F}' => {
use std::fmt::Write as _;
let _ = write!(out, "\\u{{{:x}}}", c as u32);
}
other => out.push(other),
}
}
out
}
/// Strips overstrike sequences (backspace formatting) from input.
///
/// Overstrike formatting is used by man pages and some help output:
@@ -261,3 +290,40 @@ fn test_strip_overstrike() {
// Unicode with overstrike
assert_eq!(strip_overstrike("ä\x08äöü", 2), "äöü");
}
#[test]
fn test_sanitize_for_terminal_passthrough() {
assert_eq!(sanitize_for_terminal(""), "");
assert_eq!(sanitize_for_terminal("hello.txt"), "hello.txt");
assert_eq!(sanitize_for_terminal("résumé.pdf"), "résumé.pdf");
assert_eq!(sanitize_for_terminal("日本語.md"), "日本語.md");
assert_eq!(
sanitize_for_terminal("path/with spaces/file.log"),
"path/with spaces/file.log"
);
assert_eq!(sanitize_for_terminal("a\tb"), "a\tb");
}
#[test]
fn test_sanitize_for_terminal_c0_controls() {
assert_eq!(
sanitize_for_terminal("\x1b[31mINJECTED\x1b[0m.txt"),
"^[[31mINJECTED^[[0m.txt"
);
assert_eq!(sanitize_for_terminal("bad\x07rest"), "bad^Grest");
assert_eq!(sanitize_for_terminal("\x00\x08\n\r\x7F"), "^@^H^J^M^?");
assert_eq!(sanitize_for_terminal("\u{9b}31m"), "\\u{9b}31m");
assert_eq!(
sanitize_for_terminal("\u{9d}0;pwned\x07"),
"\\u{9d}0;pwned^G"
);
}
#[test]
fn test_sanitize_for_terminal_idempotent_on_sanitized() {
let dirty = "\x1b]0;pwned\x07file.txt";
let clean = sanitize_for_terminal(dirty);
assert_eq!(sanitize_for_terminal(&clean), clean);
assert!(!clean.contains('\x1b'));
assert!(!clean.contains('\x07'));
}
+8 -4
View File
@@ -29,7 +29,9 @@ use crate::error::*;
use crate::input::OpenedInput;
use crate::line_range::{MaxBufferedLineNumber, RangeCheckResult};
use crate::output::OutputHandle;
use crate::preprocessor::{expand_tabs, replace_nonprintable, strip_ansi, strip_overstrike};
use crate::preprocessor::{
expand_tabs, replace_nonprintable, sanitize_for_terminal, strip_ansi, strip_overstrike,
};
use crate::style::StyleComponent;
use crate::terminal::{as_terminal_escaped, to_ansi_color};
use crate::vscreen::{AnsiStyle, EscapeSequence, EscapeSequenceIterator};
@@ -489,7 +491,7 @@ impl Printer for InteractivePrinter<'_> {
(but will be present if the output of 'bat' is piped). You can use 'bat -A' \
to show the binary file contents.",
Yellow.paint("[bat warning]"),
input.description.summary(),
sanitize_for_terminal(&input.description.summary()),
)?;
} else if self.config.style_components.grid() {
self.print_horizontal_line(handle, '┬')?;
@@ -543,9 +545,11 @@ impl Printer for InteractivePrinter<'_> {
"{}{}{mode}",
description
.kind()
.map(|kind| format!("{kind}: "))
.map(|kind| format!("{}: ", sanitize_for_terminal(kind)))
.unwrap_or_else(|| "".into()),
self.colors.header_value.paint(description.title()),
self.colors
.header_value
.paint(sanitize_for_terminal(description.title())),
);
self.print_header_multiline_component(handle, &header_filename)
}
@@ -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 -47
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()
@@ -3034,53 +3104,6 @@ fn no_wrapping_with_chop_long_lines() {
wrapping_test("--chop-long-lines", false);
}
#[test]
fn line_wrapping_when_set_to_character() {
wrapping_test("--wrap=character", true);
}
#[test]
fn no_line_wrapping_when_character_wrap_from_config() {
// --wrap=character in a config file should be ignored when output is not interactive
// (e.g. when piping), since wrapping is only useful with a pager.
let tmp_dir = tempdir().expect("can create temporary directory");
let tmp_config_path = tmp_dir.path().join("wrap-character.conf");
std::fs::write(&tmp_config_path, "--wrap=character").expect("can write config file");
let expected = "abcdefghigklmnopqrstuvxyzabcdefghigklmnopqrstuvxyzabcdefghigklmnopqrstuvxyzabcdefghigklmnopqrstuvxyz\n";
bat_with_config()
.env("BAT_CONFIG_PATH", tmp_config_path.to_str().unwrap())
.arg("--style=rule")
.arg("--color=never")
.arg("--decorations=always")
.arg("--terminal-width=80")
.arg("long-single-line.txt")
.assert()
.success()
.stdout(expected)
.stderr("");
}
#[test]
fn no_line_wrapping_when_character_wrap_from_bat_opts() {
// --wrap=character in BAT_OPTS should be ignored when output is not interactive,
// since it was not explicitly provided on the command line.
let expected = "abcdefghigklmnopqrstuvxyzabcdefghigklmnopqrstuvxyzabcdefghigklmnopqrstuvxyzabcdefghigklmnopqrstuvxyz\n";
bat_with_config()
.env("BAT_OPTS", "--wrap=character")
.arg("--style=rule")
.arg("--color=never")
.arg("--decorations=always")
.arg("--terminal-width=80")
.arg("long-single-line.txt")
.assert()
.success()
.stdout(expected)
.stderr("");
}
#[test]
#[serial]
fn wrap_never_flag_respected_with_paging_always() {
@@ -4179,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>