1
0
mirror of https://github.com/sharkdp/bat synced 2026-08-03 18:51:44 +00:00

Compare commits

...

78 Commits

Author SHA1 Message Date
David Peter 1f9519d8b9 Update binary assets 2022-09-06 22:54:20 +02:00
David Peter 3c33b28507 Bump version to v0.22 2022-09-06 22:54:20 +02:00
dag-h 08386daa3a Strip BOM from output in interactive mode (#1938)
* Strip BOM from output in interactive mode

* Strip BOM when not loop_through, add regression tests

* Update CHANGELOG.md

* Only strip BOM from beginning of first line

* Fix integration test on macOS that relied on color scheme

* Fix integration test on Windows that relied on detected terminal width

* Fix syntax test that was failing due to a previously wrong (now fixed) highlighting

Co-authored-by: David Peter <mail@david-peter.de>
Co-authored-by: Martin Nordholts <enselic@gmail.com>
2022-09-06 19:08:38 +02:00
David Peter 0e03dce130 Merge pull request #1920 from rhysd/issue-1919
Add `bat::PrettyPrinter::clear_highlights`
2022-09-06 09:32:29 +02:00
David Peter 6a0ab0095a Add CHANGELOG entry 2022-09-06 09:32:06 +02:00
oidro b213949aeb Correct doc comment for list_syntaxes_and_themes example 2022-09-05 21:57:11 +02:00
rhysd 3d7817d662 Clear highlighted_lines when calling PrettyPrinter::print 2022-09-05 21:17:08 +09:00
rhysd abd69f2deb Add bat::PrettyPrinter::clear_highlights (fixes #1919) 2022-09-05 17:35:32 +09:00
David Peter 113276a62b Merge pull request #2237 from kidonng/yaml
Map `fish_history` to YAML
2022-09-04 22:46:08 +02:00
Kid 1e1fa7cde5 CHANGELOG 2022-09-04 22:23:09 +02:00
Kid d6d8b61131 Fix highlight test 2022-09-04 22:22:18 +02:00
Kid 839e62cff8 Map fish_history to YAML 2022-09-04 22:22:18 +02:00
David Peter ca9843fa83 Merge pull request #2236 from kidonng/patch-1
Add `.mts` and `.cts` to TypeScript file extensions
2022-09-04 22:20:02 +02:00
David Peter 546dcf6a55 Merge pull request #1888 from patrickpichler/feature/668/add-systemwide-config
Add systemwide config file support
2022-09-04 22:11:17 +02:00
Kid d7b6519422 Add .mts and .cts to TypeScript file extensions
See also:

https://github.com/github/linguist/pull/5905
2022-09-04 22:06:54 +02:00
Martin Nordholts 799bb1639c Try to fix all warnings 2022-09-04 21:30:14 +02:00
Martin Nordholts bc2dc0796b Move up the entry to the unreleased section in CHANGELOG.md 2022-09-04 21:03:27 +02:00
Martin Nordholts 2dd2994b2f Merge remote-tracking branch 'origin/master' into feature/668/add-systemwide-config 2022-09-04 20:44:23 +02:00
David Peter 48541b8507 Fix clippy suggestions
Leads to a performance improvement for `bat -A`:

    | Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
    |:---|---:|---:|---:|---:|
    | `./bat-master --no-config -A ./bat-master` | 259.8 ± 1.1 | 258.4 | 261.7 | 1.15 ± 0.01 |
    | `./bat-2301 --no-config -A ./bat-master` | 225.6 ± 1.8 | 224.0 | 229.5 | 1.00 |
2022-09-04 14:28:44 +02:00
Jon Eskin eab1c9eb46 update alternatives.md 2022-09-04 14:28:06 +02:00
Keith Hall c6775cc41e Syntax: [Log] scope whole line based on log level
to allow color schemes to color entire lines differently based on log level
2022-09-04 14:11:09 +02:00
David Peter 45d6b1af3b Bump MSRV to 1.60
see https://github.com/rust-lang/git2-rs/issues/838
2022-09-04 06:04:35 +02:00
dependabot[bot] b295850cb3 Bump git2 from 0.14.2 to 0.15.0
Bumps [git2](https://github.com/rust-lang/git2-rs) from 0.14.2 to 0.15.0.
- [Release notes](https://github.com/rust-lang/git2-rs/releases)
- [Commits](https://github.com/rust-lang/git2-rs/compare/0.14.2...git2-curl-0.15.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-04 06:04:35 +02:00
Ed Page 08c91a116c refactor: Parse, don't validate 2022-09-03 14:01:56 +02:00
Ed Page 3d398b35c3 refactor: Switch from is_present to actions
Because "diff" is conditionally present, we need to check for it to
avoid some of clap's stricter checks meant to prevent bugs.
2022-09-03 14:01:56 +02:00
Ed Page 6099f2c146 refactor: Move off of value_of 2022-09-03 14:01:56 +02:00
Ed Page 50bb924ee3 refactor: Replace multiple_occurrences 2022-09-03 14:01:56 +02:00
Ed Page e8e1c1d6c9 refactor: Replace allow_invalid_utf8 with PathBuf 2022-09-03 14:01:56 +02:00
Ed Page 542b3d2317 refactor: Resolve basic clap deprecations 2022-09-03 14:01:56 +02:00
Ed Page 2323804f7e refactor: Port to clap3
Ths does remove the specialization of version's description.  The way
this is done (internally through `mut_arg`) doesn't play well with
subcommands.  Clap tries to force this version of `version` into the
subcommand despite not being needed.  Clap v4 dramatically changes how
version customization works.

clap also does more error checks now to prevent programmer mistake, so
we can't have a conflict with an argument that is conditionally there,
so I swapped the condition.
2022-09-03 14:01:56 +02:00
Martin Nordholts 49875d6ce7 Make bat::PrettyPrinter::syntaxes() iterate over new bat::Syntax struct (#2222)
We can't keep `syntect::parsing::SyntaxReference` as part of the public
API, because that might prevent us from bumping to syntect 6.0.0 without
also bumping bat to v2.0.0, once we reach v1.0.0.

So introduce a new stripped down struct `Syntax` and return that
instead. Let it be fully owned to make the API simple. It is not going
to be in a hot code path anyway.

I have looked at all code of our 27 dependents but I can't find a single
instance of this method being used, so this change should be safe for
v1.0.0.
2022-09-03 12:33:38 +02:00
Martin Nordholts 8b8ff96c32 CHANGELOG: Mention minor LiveScript update 2022-09-03 07:58:22 +02:00
dependabot[bot] 3d35469414 Bump assets/syntaxes/02_Extra/LiveScript from 2575013 to d82aeb7 (#2291)
Bumps [assets/syntaxes/02_Extra/LiveScript](https://github.com/paulmillr/LiveScript.tmbundle) from `2575013` to `d82aeb7`.
- [Release notes](https://github.com/paulmillr/LiveScript.tmbundle/releases)
- [Commits](https://github.com/paulmillr/LiveScript.tmbundle/compare/25750138511925b74da9508050c766f360618055...d82aeb737d4883d1a74aba7a07053f90211d427b)

---
updated-dependencies:
- dependency-name: assets/syntaxes/02_Extra/LiveScript
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-03 07:43:07 +02:00
dependabot[bot] 3480b61eae Bump wild from 2.0.4 to 2.1.0 (#2296)
Bumps [wild](https://gitlab.com/kornelski/wild) from 2.0.4 to 2.1.0.
- [Release notes](https://gitlab.com/kornelski/wild/tags)
- [Commits](https://gitlab.com/kornelski/wild/commits/v2.1.0)

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

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-02 19:49:35 +02:00
dependabot[bot] 0167ba55dd Bump thiserror from 1.0.31 to 1.0.33 (#2295)
Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.31 to 1.0.33.
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](https://github.com/dtolnay/thiserror/compare/1.0.31...1.0.33)

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

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-02 19:36:49 +02:00
dependabot[bot] 06dcead2d5 Bump serde from 1.0.143 to 1.0.144 (#2297)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.143 to 1.0.144.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.143...v1.0.144)

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

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-02 19:36:35 +02:00
dependabot[bot] cc7df1e92b Bump once_cell from 1.13.0 to 1.13.1 (#2298)
Bumps [once_cell](https://github.com/matklad/once_cell) from 1.13.0 to 1.13.1.
- [Release notes](https://github.com/matklad/once_cell/releases)
- [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md)
- [Commits](https://github.com/matklad/once_cell/compare/v1.13.0...v1.13.1)

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

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-02 19:36:21 +02:00
Martin Nordholts 899fdbb347 Remove code that tries to handle ANSI escape inputs (#2189)
Syntax highlighting is broken when input contains ANSI escape characters
anyway, so there is not much point in trying to handle ANSI escapes in
input.
2022-08-29 18:49:29 +02:00
Z. Grace Moreau a6297b282c update CHANGELOG 2022-08-27 16:37:34 +02:00
Z. Grace Moreau 33ba136fa3 fix --pager opts display and add some examples 2022-08-27 16:37:34 +02:00
Z. Grace Moreau f36df73ac1 add a vim modeline
This will cause vim (and other properly-extended editors) to read this
as a fish script file, despite its .fish.in extension.
2022-08-27 16:37:34 +02:00
Z. Grace Moreau d14e0fe292 improve fish completions 2022-08-27 16:37:34 +02:00
Martin Nordholts 621ab6078f CI: Check MSRV without git feature enabled
git2-rs MSRV policy is to only support latest stable rust (see
https://github.com/rust-lang/git2-rs#rust-version-requirements), so it
does not make sense to run our MSRV tests with git enabled.
2022-08-25 19:27:55 +02:00
Martin Nordholts 020492f7e6 tests/tester: Do not build as tests
mod tester does not contains any tests, so do not build the module as
containing tests. Instead use the mod.rs approach described in
https://doc.rust-lang.org/book/ch11-03-test-organization.html#submodules-in-integration-tests.
2022-08-25 19:27:55 +02:00
Christopher Acosta 9a924b445b Make --map-syntax and --ignored-suffix work together (#2260)
* Make --map-syntax and --ignored-suffix work together

* Minor refactor
2022-08-16 22:42:15 +02:00
dependabot[bot] c14ce4f7ca Bump assets/syntaxes/02_Extra/Julia from 1e55f32 to 4fde0fd (#2230)
* Bump assets/syntaxes/02_Extra/Julia from `1e55f32` to `4fde0fd`

Bumps [assets/syntaxes/02_Extra/Julia](https://github.com/JuliaEditorSupport/Julia-sublime) from `1e55f32` to `4fde0fd`.
- [Release notes](https://github.com/JuliaEditorSupport/Julia-sublime/releases)
- [Commits](https://github.com/JuliaEditorSupport/Julia-sublime/compare/1e55f3211b282ffd555d54b1798668bf5097df6a...4fde0fdeddb3ca8486d3f490a2f051cba39a0a48)

---
updated-dependencies:
- dependency-name: assets/syntaxes/02_Extra/Julia
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update CHANGELOG.md

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Martin Nordholts <enselic@gmail.com>
2022-08-14 21:10:05 +02:00
Marie Katrine Ekeberg 9c7ca33929 Make --no-paging/-P override --paging=... if passed as a later arg (#2201)
* Make the no-paging option override earlier paging options

* Update CHANGELOG.md

Co-authored-by: Martin Nordholts <enselic@gmail.com>
2022-08-14 21:09:13 +02:00
David Peter 02a9d191ed Bump MSRV to 1.58 2022-08-14 16:21:45 +02:00
dependabot[bot] 71e71aa31e Bump semver from 1.0.11 to 1.0.13
Bumps [semver](https://github.com/dtolnay/semver) from 1.0.11 to 1.0.13.
- [Release notes](https://github.com/dtolnay/semver/releases)
- [Commits](https://github.com/dtolnay/semver/compare/1.0.11...1.0.13)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-13 15:58:04 +02:00
dependabot[bot] a091811be9 Bump assets/syntaxes/02_Extra/PowerShell from 742f0b5 to c0372a1
Bumps [assets/syntaxes/02_Extra/PowerShell](https://github.com/PowerShell/EditorSyntax) from `742f0b5` to `c0372a1`.
- [Release notes](https://github.com/PowerShell/EditorSyntax/releases)
- [Commits](https://github.com/PowerShell/EditorSyntax/compare/742f0b5d4b60f5930c0b47fcc1f646860521296e...c0372a1d2df136ca6b3d1a9f7b85031dedf117f9)

---
updated-dependencies:
- dependency-name: assets/syntaxes/02_Extra/PowerShell
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-13 14:16:50 +02:00
dependabot[bot] 2dd8ee97a9 Bump serde from 1.0.137 to 1.0.143
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.137 to 1.0.143.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.137...v1.0.143)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-13 14:10:34 +02:00
Martin Nordholts ab8f97b0bb Bump MSRV to 1.56.1
This is what `hashbrown` did recently: https://github.com/rust-lang/hashbrown/pull/298

And it causes CI failures for us. Examples:
* https://github.com/sharkdp/bat/pull/2266
* https://github.com/sharkdp/bat/pull/2265

The path of least resistance for us is to also bump MSRV, so let's do
that. 1.56.1 was released [9 months
ago](https://blog.rust-lang.org/2021/11/01/Rust-1.56.1.html).
2022-08-13 14:10:19 +02:00
dependabot[bot] 4514a362fa Bump regex from 1.5.6 to 1.6.0
Bumps [regex](https://github.com/rust-lang/regex) from 1.5.6 to 1.6.0.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.5.6...1.6.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-13 14:07:16 +02:00
dependabot[bot] 3a93798e8b Bump assets/syntaxes/02_Extra/cmd-help from 1e513f5 to aa47747 (#2255)
* Bump assets/syntaxes/02_Extra/cmd-help from `1e513f5` to `aa47747`

Bumps [assets/syntaxes/02_Extra/cmd-help](https://github.com/victor-gp/cmd-help-sublime-syntax) from `1e513f5` to `aa47747`.
- [Release notes](https://github.com/victor-gp/cmd-help-sublime-syntax/releases)
- [Commits](https://github.com/victor-gp/cmd-help-sublime-syntax/compare/1e513f5f194e868035d2d24952ecab6d9f49572a...aa477471c870360bd1705a1a370d67b7c6fbe731)

---
updated-dependencies:
- dependency-name: assets/syntaxes/02_Extra/cmd-help
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update CHANGELOG.md

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Martin Nordholts <enselic@gmail.com>
2022-08-12 17:08:32 +02:00
dependabot[bot] 44fa7a9af3 Bump once_cell from 1.12.0 to 1.13.0
Bumps [once_cell](https://github.com/matklad/once_cell) from 1.12.0 to 1.13.0.
- [Release notes](https://github.com/matklad/once_cell/releases)
- [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md)
- [Commits](https://github.com/matklad/once_cell/compare/v1.12.0...v1.13.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-12 17:07:10 +02:00
dependabot[bot] 00eb7480f7 Bump globset from 0.4.8 to 0.4.9
Bumps [globset](https://github.com/BurntSushi/ripgrep) from 0.4.8 to 0.4.9.
- [Release notes](https://github.com/BurntSushi/ripgrep/releases)
- [Changelog](https://github.com/BurntSushi/ripgrep/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/ripgrep/compare/globset-0.4.8...globset-0.4.9)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-12 16:44:06 +02:00
dependabot[bot] 44daae4a8f Bump console from 0.15.0 to 0.15.1
Bumps [console](https://github.com/mitsuhiko/console) from 0.15.0 to 0.15.1.
- [Release notes](https://github.com/mitsuhiko/console/releases)
- [Changelog](https://github.com/console-rs/console/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mitsuhiko/console/compare/0.15.0...0.15.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-12 16:32:02 +02:00
dependabot[bot] dd2c6e07b8 Bump nix from 0.24.1 to 0.24.2
Bumps [nix](https://github.com/nix-rust/nix) from 0.24.1 to 0.24.2.
- [Release notes](https://github.com/nix-rust/nix/releases)
- [Changelog](https://github.com/nix-rust/nix/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nix-rust/nix/compare/v0.24.1...v0.24.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-12 15:23:30 +02:00
John Higgins 7b2e0ece55 Prevent fork nightmare with PAGER=batcat (#2235)
* Added rsamuelklatchko's changes

* Added some comments and deleted redundant code

* Ran cargo fmt

* Update src/pager.rs

Co-authored-by: Martin Nordholts <enselic@gmail.com>

* Added bugfix to changelog

* src/pager.rs nitpick: arg0 -> s

I forgot to comment on this name so I figured I'd just push a commit to
take care of it.

Co-authored-by: Martin Nordholts <enselic@gmail.com>
2022-08-12 14:27:47 +02:00
yuvalmo c4d9d7561b Color fstab dump and pass fields correctly (#2246)
Was missing the number 2 as a valid option in those fields.
2022-07-25 21:33:51 +02:00
Anders Kaseorg 4583826a5b Fix documentation typo: --pager=never → --paging=never
Signed-off-by: Anders Kaseorg <andersk@mit.edu>
2022-07-07 06:09:11 +02:00
dependabot[bot] c8b11873b1 Bump semver from 1.0.9 to 1.0.11
Bumps [semver](https://github.com/dtolnay/semver) from 1.0.9 to 1.0.11.
- [Release notes](https://github.com/dtolnay/semver/releases)
- [Commits](https://github.com/dtolnay/semver/compare/1.0.9...1.0.11)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-02 14:58:12 +02:00
dependabot[bot] b48cb99805 Bump serde_yaml from 0.8.23 to 0.8.24
Bumps [serde_yaml](https://github.com/dtolnay/serde-yaml) from 0.8.23 to 0.8.24.
- [Release notes](https://github.com/dtolnay/serde-yaml/releases)
- [Commits](https://github.com/dtolnay/serde-yaml/compare/0.8.23...0.8.24)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-02 14:57:19 +02:00
Kian-Meng Ang f93d650708 Fix typos 2022-06-12 16:38:33 +02:00
Cre3per ed4997c77c Add syntax mapping from NSE to Lua (#2214) 2022-06-04 14:12:42 +02:00
dependabot[bot] 16488f3d82 Bump flate2 from 1.0.23 to 1.0.24
Bumps [flate2](https://github.com/rust-lang/flate2-rs) from 1.0.23 to 1.0.24.
- [Release notes](https://github.com/rust-lang/flate2-rs/releases)
- [Commits](https://github.com/rust-lang/flate2-rs/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-04 04:52:31 +02:00
dependabot[bot] 373b22824d Bump serde from 1.0.136 to 1.0.137
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.136 to 1.0.137.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.136...v1.0.137)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-04 04:51:00 +02:00
dependabot[bot] 17c099e589 Bump regex from 1.5.5 to 1.5.6
Bumps [regex](https://github.com/rust-lang/regex) from 1.5.5 to 1.5.6.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.5.5...1.5.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-01 07:54:18 +02:00
dependabot[bot] 7d6aa09a56 Bump once_cell from 1.10.0 to 1.12.0
Bumps [once_cell](https://github.com/matklad/once_cell) from 1.10.0 to 1.12.0.
- [Release notes](https://github.com/matklad/once_cell/releases)
- [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md)
- [Commits](https://github.com/matklad/once_cell/compare/v1.10.0...v1.12.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-01 07:52:43 +02:00
dependabot[bot] b99ada8918 Bump semver from 1.0.7 to 1.0.9
Bumps [semver](https://github.com/dtolnay/semver) from 1.0.7 to 1.0.9.
- [Release notes](https://github.com/dtolnay/semver/releases)
- [Commits](https://github.com/dtolnay/semver/compare/1.0.7...1.0.9)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-01 07:52:22 +02:00
Martin Nordholts 3339eee2dc Make the default macOS theme depend on Dark Mode (#2197)
* Make the default macOS theme depend on Dark Mode

We frequently get complaints from macOS users that bat does not work on
their default macOS terminal background, which is white.

Pay the price of slightly increased startup time to get a better default
on macOS. To avoid the slightly increased startup time, simply specify a
theme explicitly via `--theme`, `BAT_THEME`, or `~/.config/bat`.

Note that if there is an error when we check if Dark Mode is enabled, we
behave the same as on Windows and Linux; assume that the terminal
background is dark. This harmonizes behavior across platforms, and makes
bat behave the same as before, when Dark Mode was always assumed to be
enabled.

* src/assets.rs: Fix typo

* Update CHANGELOG.md
2022-05-24 19:29:03 +02:00
David Peter e9f8370b13 Refer to discussions page in issue templates. 2022-05-22 21:27:54 +02:00
David Peter 892b186ba5 Add CHANGELOG entry 2022-05-16 21:54:36 +02:00
David Peter 6db64cf050 Use cross to build x86_64-unknown-linux-gnu executables
We do this in order to link against older versions of glibc.

closes #2106
2022-05-16 21:54:36 +02:00
Martin Nordholts 5f139e5ec2 CHANGELOG.md: Remove empty Themes section for v0.21.0 2022-05-15 15:28:25 +02:00
Martin Nordholts 8b50ef87fd Post-release: Prepare an "unreleased" section at the top of CHANGELOG.md
As per `doc/release-checklist.md`.
2022-05-12 13:40:48 +02:00
Patrick Pichler 6b660ef63a Add test for systemwide config file support
There is now a new stage in the CICD workflow present, which will build
`bat` with the `BAT_SYSTEM_CONFIG_PREFIX` set to load the config file
from `/tests/examples/system_config/bat/config`, plus a basic set of
tests, to ensure the feature is working as expected. By default the
tests are set to ignored, as they need special setup before they can be
run.
2022-03-10 20:55:11 +01:00
Patrick Pichler 5ed64444e3 Add systemwide config file support
There is now support for a systemwide config file. The location of the
system wide config file is `$(BAT_SYSTEM_CONFIG_PREFIX)/bat/config`.
`$(BAT_SYSTEM_CONFIG_PREFIX)` has to be provided at compile time as an
environment variable. If the environment variable is not set, a default
is used. This default is `C:\ProgramData` for windows and `/etc` for
every other os.
2022-03-10 20:55:11 +01:00
62 changed files with 1268 additions and 852 deletions
+2
View File
@@ -7,3 +7,5 @@ assignees: ''
--- ---
<!-- Using a normal ticket is still fine, but feel free to ask your
questions about bat on https://github.com/sharkdp/bat/discussions instead. -->
+33 -5
View File
@@ -1,7 +1,7 @@
name: CICD name: CICD
env: env:
MIN_SUPPORTED_RUST_VERSION: "1.51.0" MIN_SUPPORTED_RUST_VERSION: "1.60.0"
CICD_INTERMEDIATES_DIR: "_cicd-intermediates" CICD_INTERMEDIATES_DIR: "_cicd-intermediates"
on: on:
@@ -39,6 +39,8 @@ jobs:
min_version: min_version:
name: Minimum supported rust version name: Minimum supported rust version
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
env:
MSRV_FEATURES: --no-default-features --features minimal-application,bugreport,build-assets
steps: steps:
- name: Checkout source code - name: Checkout source code
uses: actions/checkout@v2 uses: actions/checkout@v2
@@ -54,12 +56,12 @@ jobs:
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: clippy command: clippy
args: --locked --all-targets --all-features args: --locked --all-targets ${{ env.MSRV_FEATURES }}
- name: Run tests - name: Run tests
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: test command: test
args: --locked args: --locked ${{ env.MSRV_FEATURES }}
test_with_new_syntaxes_and_themes: test_with_new_syntaxes_and_themes:
name: Run tests with updated syntaxes and themes name: Run tests with updated syntaxes and themes
@@ -96,7 +98,7 @@ jobs:
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: test command: test
args: --locked --release -- --ignored args: --locked --release --test assets -- --ignored
- name: Syntax highlighting regression test - name: Syntax highlighting regression test
run: tests/syntax-tests/regression_test.sh run: tests/syntax-tests/regression_test.sh
- name: List of languages - name: List of languages
@@ -106,6 +108,32 @@ jobs:
- name: Test custom assets - name: Test custom assets
run: tests/syntax-tests/test_custom_assets.sh run: tests/syntax-tests/test_custom_assets.sh
test_with_system_config:
name: Run tests with system wide configuration
runs-on: ubuntu-20.04
steps:
- name: Git checkout
uses: actions/checkout@v2
- name: Prepare environment variables
run: |
echo "BAT_SYSTEM_CONFIG_PREFIX=$GITHUB_WORKSPACE/tests/examples/system_config" >> $GITHUB_ENV
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
default: true
profile: minimal
- name: Build and install bat
uses: actions-rs/cargo@v1
with:
command: install
args: --locked --path .
- name: Run unit tests
uses: actions-rs/cargo@v1
with:
command: test
args: --locked --test system_wide_config -- --ignored
documentation: documentation:
name: Documentation name: Documentation
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
@@ -154,7 +182,7 @@ jobs:
- { target: x86_64-apple-darwin , os: macos-10.15 } - { target: x86_64-apple-darwin , os: macos-10.15 }
- { target: x86_64-pc-windows-gnu , os: windows-2019 } - { target: x86_64-pc-windows-gnu , os: windows-2019 }
- { target: x86_64-pc-windows-msvc , os: windows-2019 } - { target: x86_64-pc-windows-msvc , os: windows-2019 }
- { target: x86_64-unknown-linux-gnu , os: ubuntu-20.04 } - { target: x86_64-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
- { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true } - { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
steps: steps:
- name: Checkout source code - name: Checkout source code
+36 -2
View File
@@ -1,3 +1,39 @@
# v0.22.0
## Features
- Make the default macOS theme depend on Dark Mode. See #2197, #1746 (@Enselic)
- Support for separate system and user config files. See #668 (@patrickpichler)
## Bugfixes
- Prevent fork nightmare with `PAGER=batcat`. See #2235 (@johnmatthiggins)
- Make `--no-paging`/`-P` override `--paging=...` if passed as a later arg, see #2201 (@themkat)
- `--map-syntax` and `--ignored-suffix` now works together, see #2093 (@czzrr)
- Strips byte order mark from output when in non-loop-through mode. See #1922 (@dag-h)
## Other
- Relaxed glibc requirements on amd64, see #2106 and #2194 (@sharkdp)
- Improved fish completions. See #2275 (@zgracem)
- Stop pre-processing ANSI escape characters. Syntax highlighting on ANSI escaped input is not supported. See #2185 and #2189 (@Enselic)
## Syntaxes
- NSE (Nmap Scripting Engine) is mapped to Lua, see #2151 (@Cre3per)
- Correctly color `fstab` dump and pass fields, see #2246 (@yuvalmo)
- Update `Command Help` syntax, see #2255
- `Julia`: Fix syntax highlighting for function name starting with `struct`, see #2230
- Minor update to `LiveScript`, see #2291
- Associate `.mts` and `.cts` files with the `TypeScript` syntax. See #2236 (@kidonng)
- Fish history is mapped to YAML. See #2237 (@kidonng)
## `bat` as a library
- Make `bat::PrettyPrinter::syntaxes()` iterate over new `bat::Syntax` struct instead of `&syntect::parsing::SyntaxReference`. See #2222 (@Enselic)
- Clear highlights after printing, see #1919 and #1920 (@rhysd)
# v0.21.0 # v0.21.0
## Features ## Features
@@ -30,8 +66,6 @@
- Slightly adjust Zig syntax. See #2136 (@Enselic) - Slightly adjust Zig syntax. See #2136 (@Enselic)
- Associate `.inf` files with the `INI` syntax. See #2190 (@Enselic) - Associate `.inf` files with the `INI` syntax. See #2190 (@Enselic)
## Themes
## `bat` as a library ## `bat` as a library
- Allow configuration of `show_nonprintable` with `PrettyPrinter`, see #2142 - Allow configuration of `show_nonprintable` with `PrettyPrinter`, see #2142
Generated
+72 -76
View File
@@ -74,7 +74,7 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]] [[package]]
name = "bat" name = "bat"
version = "0.21.0" version = "0.22.0"
dependencies = [ dependencies = [
"ansi_colours", "ansi_colours",
"ansi_term", "ansi_term",
@@ -193,18 +193,28 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "clap" name = "clap"
version = "2.34.0" version = "3.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" checksum = "23b71c3ce99b7611011217b366d923f1d0a7e07a92bb2dbf1e84508c673ca3bd"
dependencies = [ dependencies = [
"ansi_term",
"atty", "atty",
"bitflags", "bitflags",
"clap_lex",
"indexmap",
"once_cell",
"strsim", "strsim",
"term_size", "termcolor",
"terminal_size",
"textwrap", "textwrap",
"unicode-width", ]
"vec_map",
[[package]]
name = "clap_lex"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
dependencies = [
"os_str_bytes",
] ]
[[package]] [[package]]
@@ -221,14 +231,13 @@ dependencies = [
[[package]] [[package]]
name = "console" name = "console"
version = "0.15.0" version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28b32d32ca44b70c3e4acd7db1babf555fa026e385fb95f18028f88848b3c31" checksum = "89eab4d20ce20cea182308bca13088fecea9c05f6776cf287205d41a0ed3c847"
dependencies = [ dependencies = [
"encode_unicode", "encode_unicode",
"libc", "libc",
"once_cell", "once_cell",
"regex",
"terminal_size", "terminal_size",
"unicode-width", "unicode-width",
"winapi", "winapi",
@@ -382,13 +391,11 @@ dependencies = [
[[package]] [[package]]
name = "flate2" name = "flate2"
version = "1.0.23" version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af" checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6"
dependencies = [ dependencies = [
"cfg-if",
"crc32fast", "crc32fast",
"libc",
"miniz_oxide", "miniz_oxide",
] ]
@@ -452,9 +459,9 @@ dependencies = [
[[package]] [[package]]
name = "git2" name = "git2"
version = "0.14.2" version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3826a6e0e2215d7a41c2bfc7c9244123969273f3476b939a226aac0ab56e9e3c" checksum = "2994bee4a3a6a51eb90c218523be382fd7ea09b16380b9312e9dbe955ff7c7d1"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"libc", "libc",
@@ -471,9 +478,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]] [[package]]
name = "globset" name = "globset"
version = "0.4.8" version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10463d9ff00a2a068db14231982f5132edebad0d7660cd956a1c30292dbcbfbd" checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"bstr", "bstr",
@@ -588,9 +595,9 @@ checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b"
[[package]] [[package]]
name = "libgit2-sys" name = "libgit2-sys"
version = "0.13.2+1.4.2" version = "0.14.0+1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a42de9a51a5c12e00fc0e4ca6bc2ea43582fc6418488e8f615e905d886f258b" checksum = "47a00859c70c8a4f7218e6d1cc32875c4b55f6799445b842b0d8ed5e4c3d959b"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@@ -666,9 +673,9 @@ dependencies = [
[[package]] [[package]]
name = "nix" name = "nix"
version = "0.24.1" version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f17df307904acd05aa8e32e97bb20f2a0df1728bbc2d771ae8f9a90463441e9" checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cfg-if", "cfg-if",
@@ -692,9 +699,9 @@ dependencies = [
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.10.0" version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e"
[[package]] [[package]]
name = "onig" name = "onig"
@@ -718,6 +725,12 @@ dependencies = [
"pkg-config", "pkg-config",
] ]
[[package]]
name = "os_str_bytes"
version = "6.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff"
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.11.2" version = "0.11.2"
@@ -840,11 +853,11 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.36" version = "1.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f"
dependencies = [ dependencies = [
"unicode-xid", "unicode-ident",
] ]
[[package]] [[package]]
@@ -877,9 +890,9 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.5.5" version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@@ -894,9 +907,9 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.6.25" version = "0.6.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
[[package]] [[package]]
name = "remove_dir_all" name = "remove_dir_all"
@@ -951,24 +964,24 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.7" version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4" checksum = "93f6841e709003d68bb2deee8c343572bf446003ec20a583e76f7b15cebf3711"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.136" version = "1.0.144"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.136" version = "1.0.144"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -988,9 +1001,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_yaml" name = "serde_yaml"
version = "0.8.23" version = "0.8.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0" checksum = "707d15895415db6628332b737c838b88c598522e4dc70647e59b72312924aebc"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"ryu", "ryu",
@@ -1048,19 +1061,19 @@ checksum = "8207e78455ffdf55661170876f88daf85356e4edd54e0a3dbc79586ca1e50cbe"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.8.0" version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.85" version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a684ac3dcd8913827e18cd09a68384ee66c1de24157e3c556c9ab16d85695fb7" checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"unicode-xid", "unicode-ident",
] ]
[[package]] [[package]]
@@ -1111,16 +1124,6 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "term_size"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9"
dependencies = [
"libc",
"winapi",
]
[[package]] [[package]]
name = "termcolor" name = "termcolor"
version = "1.1.2" version = "1.1.2"
@@ -1148,28 +1151,27 @@ checksum = "13a4ec180a2de59b57434704ccfad967f789b12737738798fa08798cd5824c16"
[[package]] [[package]]
name = "textwrap" name = "textwrap"
version = "0.11.0" version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
dependencies = [ dependencies = [
"term_size", "terminal_size",
"unicode-width",
] ]
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.31" version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" checksum = "3d0a539a918745651435ac7db7a18761589a94cd7e94cd56999f828bf73c8a57"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.31" version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" checksum = "c251e90f708e16c49a16f4917dc2131e75222b72edfa9cb7f7c58ae56aae0c09"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -1207,6 +1209,12 @@ version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
[[package]]
name = "unicode-ident"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee"
[[package]] [[package]]
name = "unicode-normalization" name = "unicode-normalization"
version = "0.1.19" version = "0.1.19"
@@ -1222,12 +1230,6 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]] [[package]]
name = "url" name = "url"
version = "2.2.2" version = "2.2.2"
@@ -1246,12 +1248,6 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.4" version = "0.9.4"
@@ -1286,9 +1282,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]] [[package]]
name = "wild" name = "wild"
version = "2.0.4" version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "035793abb854745033f01a07647a79831eba29ec0be377205f2a25b0aa830020" checksum = "05b116685a6be0c52f5a103334cbff26db643826c7b3735fc0a3ba9871310a74"
dependencies = [ dependencies = [
"glob", "glob",
] ]
+10 -10
View File
@@ -6,7 +6,7 @@ homepage = "https://github.com/sharkdp/bat"
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
name = "bat" name = "bat"
repository = "https://github.com/sharkdp/bat" repository = "https://github.com/sharkdp/bat"
version = "0.21.0" version = "0.22.0"
exclude = ["assets/syntaxes/*", "assets/themes/*"] exclude = ["assets/syntaxes/*", "assets/themes/*"]
build = "build.rs" build = "build.rs"
edition = '2018' edition = '2018'
@@ -44,11 +44,11 @@ atty = { version = "0.2.14", optional = true }
ansi_term = "^0.12.1" ansi_term = "^0.12.1"
ansi_colours = "^1.1" ansi_colours = "^1.1"
bincode = "1.0" bincode = "1.0"
console = "0.15.0" console = "0.15.1"
flate2 = "1.0" flate2 = "1.0"
once_cell = "1.10" once_cell = "1.13"
thiserror = "1.0" thiserror = "1.0"
wild = { version = "2.0", optional = true } wild = { version = "2.1", optional = true }
content_inspector = "0.2.4" content_inspector = "0.2.4"
encoding = "0.2" encoding = "0.2"
shell-words = { version = "1.1.0", optional = true } shell-words = { version = "1.1.0", optional = true }
@@ -62,12 +62,12 @@ clircle = "0.3"
bugreport = { version = "0.5.0", optional = true } bugreport = { version = "0.5.0", optional = true }
dirs-next = { version = "2.0.0", optional = true } dirs-next = { version = "2.0.0", optional = true }
grep-cli = { version = "0.1.6", optional = true } grep-cli = { version = "0.1.6", optional = true }
regex = { version = "1.5.5", optional = true } regex = { version = "1.6.0", optional = true }
walkdir = { version = "2.0", optional = true } walkdir = { version = "2.0", optional = true }
bytesize = { version = "1.1.0" } bytesize = { version = "1.1.0" }
[dependencies.git2] [dependencies.git2]
version = "0.14" version = "0.15"
optional = true optional = true
default-features = false default-features = false
@@ -77,10 +77,10 @@ default-features = false
features = ["parsing"] features = ["parsing"]
[dependencies.clap] [dependencies.clap]
version = "2.34" version = "3.2.20"
optional = true optional = true
default-features = false default-features = false
features = ["suggestions", "color", "wrap_help"] features = ["std", "suggestions", "color", "wrap_help", "cargo"]
[dev-dependencies] [dev-dependencies]
assert_cmd = "2.0.4" assert_cmd = "2.0.4"
@@ -90,10 +90,10 @@ wait-timeout = "0.2.0"
tempfile = "3.3.0" tempfile = "3.3.0"
[target.'cfg(unix)'.dev-dependencies] [target.'cfg(unix)'.dev-dependencies]
nix = { version = "0.24.1", default-features = false, features = ["term"] } nix = { version = "0.24.2", default-features = false, features = ["term"] }
[build-dependencies] [build-dependencies]
clap = { version = "2.34", optional = true } clap = { version = "3.2.20", optional = true }
[profile.release] [profile.release]
lto = true lto = true
+5 -1
View File
@@ -418,7 +418,7 @@ binaries are also available: look for archives with `musl` in the file name.
### From source ### From source
If you want to build `bat` from source, you need Rust 1.51 or If you want to build `bat` from source, you need Rust 1.60.0 or
higher. You can then use `cargo` to build everything: higher. You can then use `cargo` to build everything:
```bash ```bash
@@ -639,6 +639,10 @@ A default configuration file can be created with the `--generate-config-file` op
bat --generate-config-file bat --generate-config-file
``` ```
There is also now a systemwide configuration file, which is located under `/etc/bat/config` on
Linux and Mac OS and `C:\ProgramData\bat\config` on windows. If the system wide configuration
file is present, the content of the user configuration will simply be appended to it.
### Format ### Format
The configuration file is a simple list of command line arguments. Use `bat --help` to see a full list of possible options and values. In addition, you can add comments by prepending a line with the `#` character. The configuration file is a simple list of command line arguments. Use `bat --help` to see a full list of possible options and values. In addition, you can add comments by prepending a line with the `#` character.
+184 -43
View File
@@ -1,78 +1,219 @@
# Fish Shell Completions # Fish Shell Completions
# Place or symlink to $XDG_CONFIG_HOME/fish/completions/{{PROJECT_EXECUTABLE}}.fish ($XDG_CONFIG_HOME is usually set to ~/.config) # Copy or symlink to $XDG_CONFIG_HOME/fish/completions/{{PROJECT_EXECUTABLE}}.fish
# ($XDG_CONFIG_HOME is usually set to ~/.config)
# Helper function: # `bat` is `batcat` on Debian and Ubuntu
function __{{PROJECT_EXECUTABLE}}_autocomplete_languages --description "A helper function used by "(status filename) set bat {{PROJECT_EXECUTABLE}}
{{PROJECT_EXECUTABLE}} --list-languages | awk -F':' '
{
lang=$1
split($2, exts, ",")
for (i in exts) { # Helper functions:
ext=exts[i]
if (ext !~ /[A-Z].*/ && ext !~ /^\..*rc$/) { function __bat_complete_files -a token
print ext"\t"lang # Cheat to complete files by calling `complete -C` on a fake command name,
} # like `__fish_complete_directories` does.
} set -l fake_command aaabccccdeeeeefffffffffgghhhhhhiiiii
} complete -C"$fake_command $token"
' | sort
end end
function __bat_complete_one_language -a comp
command $bat --list-languages | string split -f1 : | string match -e "$comp"
end
function __bat_complete_list_languages
for spec in (command $bat --list-languages)
set -l name (string split -f1 : $spec)
for ext in (string split -f2 : $spec | string split ,)
test -n "$ext"; or continue
string match -rq '[/*]' $ext; and continue
printf "%s\t%s\n" $ext $name
end
printf "%s\t\n" $name
end
end
function __bat_complete_map_syntax
set -l token (commandline -ct)
if string match -qr '(?<glob>.+):(?<syntax>.*)' -- $token
# If token ends with a colon, complete with the list of language names.
set -f comps $glob:(__bat_complete_one_language $syntax)
else if string match -qr '\*' -- $token
# If token contains a globbing character (`*`), complete only possible
# globs in the current directory
set -f comps (__bat_complete_files $token | string match -er '[*]'):
else
# Complete files (and globs).
set -f comps (__bat_complete_files $token | string match -erv '/$'):
end
if set -q comps[1]
printf "%s\t\n" $comps
end
end
function __bat_cache_subcommand
__fish_seen_subcommand_from cache
end
# Returns true if no exclusive arguments seen.
function __bat_no_excl_args
not __bat_cache_subcommand; and not __fish_seen_argument \
-s h -l help \
-s V -l version \
-l acknowledgements \
-l config-dir -l config-file \
-l diagnostic \
-l list-languages -l list-themes
end
# Returns true if the 'cache' subcommand is seen without any exclusive arguments.
function __bat_cache_no_excl
__bat_cache_subcommand; and not __fish_seen_argument \
-s h -l help \
-l acknowledgements -l build -l clear
end
function __bat_style_opts
set -l style_opts \
"default,recommended components" \
"auto,same as 'default' unless piped" \
"full,all components" \
"plain,no components" \
"changes,Git change markers" \
"header,alias for header-filename" \
"header-filename,filename above content" \
"header-filesize,filesize above content" \
"grid,lines b/w sidebar/header/content" \
"numbers,line numbers in sidebar" \
"rule,separate files" \
"snip,separate ranges"
string replace , \t $style_opts
end
# Use option argument descriptions to indicate which is the default, saving
# horizontal space and making sure the option description isn't truncated.
set -l color_opts '
auto\tdefault
never\t
always\t
'
set -l decorations_opts $color_opts
set -l paging_opts $color_opts
# Include some examples so we can indicate the default.
set -l pager_opts '
less\tdefault
less\ -FR\t
more\t
vimpager\t
'
set -l italic_text_opts '
always\t
never\tdefault
'
set -l wrap_opts '
auto\tdefault
never\t
character\t
'
# While --tabs theoretically takes any number, most people should be OK with these.
# Specifying a list lets us explain what 0 does.
set -l tabs_opts '
0\tpass\ tabs\ through\ directly
1\t
2\t
4\t
8\t
'
# Completions: # Completions:
complete -c {{PROJECT_EXECUTABLE}} -l color -xka "auto never always" -d "Specify when to use colored output (default: auto)" -n "not __fish_seen_subcommand_from cache" complete -c $bat -l acknowledgements -d "Print acknowledgements" -n __fish_is_first_arg
complete -c {{PROJECT_EXECUTABLE}} -l config-dir -d "Display location of '{{PROJECT_EXECUTABLE}}' configuration directory" -n "not __fish_seen_subcommand_from cache" complete -c $bat -l color -x -a "$color_opts" -d "When to use colored output" -n __bat_no_excl_args
complete -c {{PROJECT_EXECUTABLE}} -l config-file -d "Display location of '{{PROJECT_EXECUTABLE}}' configuration file" -n "not __fish_seen_subcommand_from cache" complete -c $bat -l config-dir -f -d "Display location of configuration directory" -n __fish_is_first_arg
complete -c {{PROJECT_EXECUTABLE}} -l decorations -xka "auto never always" -d "Specify when to use the decorations specified with '--style' (default: auto)" -n "not __fish_seen_subcommand_from cache" complete -c $bat -l config-file -f -d "Display location of configuration file" -n __fish_is_first_arg
complete -c {{PROJECT_EXECUTABLE}} -s h -l help -d "Print help message" -n "not __fish_seen_subcommand_from cache" complete -c $bat -l decorations -x -a "$decorations_opts" -d "When to use --style decorations" -n __bat_no_excl_args
complete -c {{PROJECT_EXECUTABLE}} -s H -l highlight-line -x -d "<N> Highlight the N-th line with a different background color" -n "not __fish_seen_subcommand_from cache" complete -c $bat -l diagnostic -d "Print diagnostic info for bug reports" -n __fish_is_first_arg
complete -c {{PROJECT_EXECUTABLE}} -l italic-text -xka "always never" -d "Specify when to use ANSI sequences for italic text (default: never)" -n "not __fish_seen_subcommand_from cache" complete -c $bat -s d -l diff -d "Only show lines with Git changes" -n __bat_no_excl_args
complete -c {{PROJECT_EXECUTABLE}} -s l -l language -d "Set the language for syntax highlighting" -n "not __fish_seen_subcommand_from cache" -xa "(__{{PROJECT_EXECUTABLE}}_autocomplete_languages)" complete -c $bat -l diff-context -x -d "Show N context lines around Git changes" -n "__fish_seen_argument -s d -l diff"
complete -c {{PROJECT_EXECUTABLE}} -s r -l line-range -x -d "<N:M> Only print the specified range of lines for each file" -n "not __fish_seen_subcommand_from cache" complete -c $bat -l file-name -x -d "Specify the display name" -n __bat_no_excl_args
complete -c {{PROJECT_EXECUTABLE}} -l list-languages -d "Display list of supported languages for syntax highlighting" -n "not __fish_seen_subcommand_from cache" complete -c $bat -s f -l force-colorization -d "Force color and decorations" -n __bat_no_excl_args
complete -c {{PROJECT_EXECUTABLE}} -l list-themes -d "Display a list of supported themes for syntax highlighting" -n "not __fish_seen_subcommand_from cache" complete -c $bat -s h -d "Print a concise overview" -n __fish_is_first_arg
complete -c {{PROJECT_EXECUTABLE}} -s m -l map-syntax -x -d "<from:to> Map a file extension or file name to an existing syntax" -n "not __fish_seen_subcommand_from cache" complete -c $bat -l help -f -d "Print all help information" -n __fish_is_first_arg
complete -c {{PROJECT_EXECUTABLE}} -s n -l number -d "Only show line numbers, no other decorations. Alias for '--style=numbers'" -n "not __fish_seen_subcommand_from cache" complete -c $bat -s H -l highlight-line -x -d "Highlight line(s) N[:M]" -n __bat_no_excl_args
complete -c {{PROJECT_EXECUTABLE}} -l pager -x -d "<command> Specify which pager program to use (default: less)" -n "not __fish_seen_subcommand_from cache" complete -c $bat -l ignored-suffix -x -d "Ignore extension" -n __bat_no_excl_args
complete -c {{PROJECT_EXECUTABLE}} -l paging -xka "auto never always" -d "Specify when to use the pager (default: auto)" -n "not __fish_seen_subcommand_from cache" complete -c $bat -l italic-text -x -a "$italic_text_opts" -d "When to use italic text in the output" -n __bat_no_excl_args
complete -c {{PROJECT_EXECUTABLE}} -s p -l plain -d "Only show plain style, no decorations. Alias for '--style=plain'" -n "not __fish_seen_subcommand_from cache" complete -c $bat -s l -l language -x -k -a "(__bat_complete_list_languages)" -d "Set the syntax highlighting language" -n __bat_no_excl_args
complete -c {{PROJECT_EXECUTABLE}} -s P -d "Disable paging. Alias for '--paging=never'" -n "not __fish_seen_subcommand_from cache" complete -c $bat -s r -l line-range -x -d "Only print lines [M]:[N] (either optional)" -n __bat_no_excl_args
complete -c {{PROJECT_EXECUTABLE}} -s A -l show-all -d "Show non-printable characters like space/tab/newline" -n "not __fish_seen_subcommand_from cache" complete -c $bat -l list-languages -f -d "List syntax highlighting languages" -n __fish_is_first_arg
complete -c {{PROJECT_EXECUTABLE}} -l style -xka "default auto full plain changes header header-filename header-filesize grid rule numbers snip" -d "Comma-separated list of style elements or presets to display with file contents" -n "not __fish_seen_subcommand_from cache" complete -c $bat -l list-themes -f -d "List syntax highlighting themes" -n __fish_is_first_arg
complete -c {{PROJECT_EXECUTABLE}} -l tabs -x -d "<T> Set the tab width to T spaces (width of 0 passes tabs through directly)" -n "not __fish_seen_subcommand_from cache" complete -c $bat -s m -l map-syntax -x -a "(__bat_complete_map_syntax)" -d "Map <glob pattern>:<language syntax>" -n __bat_no_excl_args
complete -c {{PROJECT_EXECUTABLE}} -l terminal-width -x -d "<width> Explicitly set terminal width; Prefix with '+' or '-' to offset (default width is auto determined)" -n "not __fish_seen_subcommand_from cache" complete -c $bat -s n -l number -d "Only show line numbers, no other decorations" -n __bat_no_excl_args
complete -c {{PROJECT_EXECUTABLE}} -l theme -xka "({{PROJECT_EXECUTABLE}} --list-themes | cat)" -d "Set the theme for syntax highlighting" -n "not __fish_seen_subcommand_from cache" complete -c $bat -l pager -x -a "$pager_opts" -d "Which pager to use" -n __bat_no_excl_args
complete -c {{PROJECT_EXECUTABLE}} -s u -l unbuffered -d "POSIX-compliant unbuffered output. Option is ignored" -n "not __fish_seen_subcommand_from cache" complete -c $bat -l paging -x -a "$paging_opts" -d "When to use the pager" -n __bat_no_excl_args
complete -c {{PROJECT_EXECUTABLE}} -s V -l version -d "Show version information" -n "not __fish_seen_subcommand_from cache" complete -c $bat -s p -l plain -d "Disable decorations" -n __bat_no_excl_args
complete -c {{PROJECT_EXECUTABLE}} -l wrap -xka "auto never character" -d "<mode> Specify the text-wrapping mode (default: auto)" -n "not __fish_seen_subcommand_from cache" complete -c $bat -o pp -d "Disable decorations and paging" -n __bat_no_excl_args
complete -c $bat -s P -d "Disable paging" -n __bat_no_excl_args
complete -c $bat -s A -l show-all -d "Show non-printable characters" -n __bat_no_excl_args
complete -c $bat -l style -x -k -a "(__fish_complete_list , __bat_style_opts)" -d "Specify which non-content elements to display" -n __bat_no_excl_args
complete -c $bat -l tabs -x -a "$tabs_opts" -d "Set tab width" -n __bat_no_excl_args
complete -c $bat -l terminal-width -x -d "Set terminal <width>, +<offset>, or -<offset>" -n __bat_no_excl_args
complete -c $bat -l theme -x -a "(command $bat --list-themes | command cat)" -d "Set the syntax highlighting theme" -n __bat_no_excl_args
complete -c $bat -s V -l version -f -d "Show version information" -n __fish_is_first_arg
complete -c $bat -l wrap -x -a "$wrap_opts" -d "Text-wrapping mode" -n __bat_no_excl_args
# Sub-command 'cache' completions # Sub-command 'cache' completions
complete -c {{PROJECT_EXECUTABLE}} -a "cache" -d "Modify the syntax/language definition cache" -n "not __fish_seen_subcommand_from cache" complete -c $bat -a cache -d "Modify the syntax/language definition cache" -n __fish_use_subcommand
complete -c {{PROJECT_EXECUTABLE}} -l build -f -d "Parse syntaxes/language definitions into cache" -n "__fish_seen_subcommand_from cache" complete -c $bat -l build -f -d "Parse new definitions into cache" -n __bat_cache_no_excl
complete -c {{PROJECT_EXECUTABLE}} -l clear -f -d "Reset syntaxes/language definitions to default settings" -n "__fish_seen_subcommand_from cache" complete -c $bat -l clear -f -d "Reset definitions to defaults" -n __bat_cache_no_excl
complete -c $bat -l blank -f -d "Create new data instead of appending" -n "__bat_cache_subcommand; and not __fish_seen_argument -l clear"
complete -c $bat -l source -x -a "(__fish_complete_directories)" -d "Load syntaxes and themes from DIR" -n "__bat_cache_subcommand; and not __fish_seen_argument -l clear"
complete -c $bat -l target -x -a "(__fish_complete_directories)" -d "Store cache in DIR" -n __bat_cache_subcommand
complete -c $bat -l acknowledgements -d "Build acknowledgements.bin" -n __bat_cache_no_excl
complete -c $bat -s h -d "Print a concise overview of $bat-cache help" -n __bat_cache_no_excl
complete -c $bat -l help -f -d "Print all $bat-cache help" -n __bat_cache_no_excl
# vim:ft=fish
+1 -1
View File
@@ -29,7 +29,7 @@ control the width of the tab\-placeholders.
.IP .IP
Only show plain style, no decorations. This is an alias for Only show plain style, no decorations. This is an alias for
\&'\-\-style=plain'. When '\-p' is used twice ('\-pp'), it also disables \&'\-\-style=plain'. When '\-p' is used twice ('\-pp'), it also disables
automatic paging (alias for '\-\-style=plain \fB\-\-pager\fR=\fI\,never\/\fR'). automatic paging (alias for '\-\-style=plain \fB\-\-paging\fR=\fI\,never\/\fR').
.HP .HP
\fB\-l\fR, \fB\-\-language\fR <language> \fB\-l\fR, \fB\-\-language\fR <language>
.IP .IP
BIN
View File
Binary file not shown.
+2 -2
View File
@@ -95,7 +95,7 @@ contexts:
fstab_dump: fstab_dump:
- include: comment - include: comment
- match: '\s*[01]\s*' - match: '\s*[012]\s*'
comment: dump field comment: dump field
scope: constant.numeric scope: constant.numeric
set: fstab_pass set: fstab_pass
@@ -107,7 +107,7 @@ contexts:
fstab_pass: fstab_pass:
- include: comment - include: comment
- match: '\s*[01]\s*' - match: '\s*[012]\s*'
comment: pass field comment: pass field
scope: constant.numeric scope: constant.numeric
set: expected_eol set: expected_eol
+2
View File
@@ -4,6 +4,8 @@
name: TypeScript name: TypeScript
file_extensions: file_extensions:
- ts - ts
- mts
- cts
scope: source.ts scope: source.ts
contexts: contexts:
main: main:
+60 -16
View File
@@ -7,8 +7,15 @@ scope: text.log
variables: variables:
ipv4_part: (?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?) ipv4_part: (?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)
hours_minutes_seconds: (?:[01]\d|2[0-3]):(?:[0-5]\d):(?:[0-5]\d) hours_minutes_seconds: (?:[01]\d|2[0-3]):(?:[0-5]\d):(?:[0-5]\d)
error: \b(?i:fail(?:ure|ed)?|error|exception|fatal|critical)\b
warning: \b(?i:warn(?:ing)?)\b
info: \b(?i:info)\b
debug: \b(?i:debug)\b
contexts: contexts:
main: main:
- include: log_level_lines
- include: main_without_log_level_line
main_without_log_level_line:
- match: (\w+)(=) - match: (\w+)(=)
captures: captures:
1: variable.parameter.log 1: variable.parameter.log
@@ -25,16 +32,58 @@ contexts:
- include: dates - include: dates
- include: ip_addresses - include: ip_addresses
- include: numbers - include: numbers
- match: \b(?i:fail(?:ure|ed)?|error|exception)\b - include: log_levels
scope: markup.error.log
- match: \b(?i:warn(?:ing)?)\b
scope: markup.warning.log
- match: \b(?i:debug)\b
scope: markup.info.log
#- include: scope:text.html.markdown#autolink-inet #- include: scope:text.html.markdown#autolink-inet
- match: \b\w+:/{2,3} - match: \b\w+:/{2,3}
scope: markup.underline.link.scheme.log scope: markup.underline.link.scheme.log
push: url-host push: url-host
log_level_lines:
- match: ^(?=.*{{error}})
push:
- error_line
- main_pop_at_eol
- match: ^(?=.*{{warning}})
push:
- warning_line
- main_pop_at_eol
- match: ^(?=.*{{info}})
push:
- info_line
- main_pop_at_eol
- match: ^(?=.*{{debug}})
push:
- debug_line
- main_pop_at_eol
log_levels:
- match: '{{error}}'
scope: markup.error.log
- match: '{{warning}}'
scope: markup.warning.log
- match: '{{info}}'
scope: markup.info.log
- match: '{{debug}}'
scope: markup.info.log
error_line:
- meta_scope: meta.annotation.error-line.log
- include: immediately_pop
warning_line:
- meta_scope: meta.annotation.warning-line.log
- include: immediately_pop
info_line:
- meta_scope: meta.annotation.info-line.log
- include: immediately_pop
debug_line:
- meta_scope: meta.annotation.debug-line.log
- include: immediately_pop
immediately_pop:
- match: ''
pop: true
pop_at_eol:
- match: $
pop: true
main_pop_at_eol:
- include: main_without_log_level_line
- include: pop_at_eol
dates: dates:
- match: \b\d{4}-\d{2}-\d{2}(?=\b|T) - match: \b\d{4}-\d{2}-\d{2}(?=\b|T)
scope: meta.date.log meta.number.integer.decimal.log constant.numeric.value.log scope: meta.date.log meta.number.integer.decimal.log constant.numeric.value.log
@@ -49,14 +98,12 @@ contexts:
scope: meta.time.log meta.number.integer.decimal.log constant.numeric.value.log scope: meta.time.log meta.number.integer.decimal.log constant.numeric.value.log
captures: captures:
1: punctuation.separator.decimal.log 1: punctuation.separator.decimal.log
- match: '' - include: immediately_pop
pop: true
maybe_date_time_separator: maybe_date_time_separator:
- match: T(?={{hours_minutes_seconds}}) - match: T(?={{hours_minutes_seconds}})
scope: meta.date.log meta.time.log keyword.other.log scope: meta.date.log meta.time.log keyword.other.log
set: time set: time
- match: '' - include: immediately_pop
pop: true
ip_addresses: ip_addresses:
- match: \b(?=(?:{{ipv4_part}}\.){3}{{ipv4_part}}\b) - match: \b(?=(?:{{ipv4_part}}\.){3}{{ipv4_part}}\b)
push: push:
@@ -65,8 +112,7 @@ contexts:
scope: constant.numeric.value.log scope: constant.numeric.value.log
- match: \. - match: \.
scope: punctuation.separator.sequence.log scope: punctuation.separator.sequence.log
- match: '' - include: immediately_pop
pop: true
- match: (?=(?:\h{0,4}:){2,6}\h{1,4}\b) - match: (?=(?:\h{0,4}:){2,6}\h{1,4}\b)
push: push:
- meta_scope: meta.ipaddress.v6.log meta.number.integer.hexadecimal.log - meta_scope: meta.ipaddress.v6.log meta.number.integer.hexadecimal.log
@@ -74,8 +120,7 @@ contexts:
scope: constant.numeric.value.log scope: constant.numeric.value.log
- match: ':' - match: ':'
scope: punctuation.separator.sequence.log scope: punctuation.separator.sequence.log
- match: '' - include: immediately_pop
pop: true
numbers: numbers:
- match: \b(0x)(\h+)(?:(\.)(\h+))?\b - match: \b(0x)(\h+)(?:(\.)(\h+))?\b
scope: meta.number.float.hexadecimal.log scope: meta.number.float.hexadecimal.log
@@ -127,8 +172,7 @@ contexts:
pop: true pop: true
- match: '[^?!.,:*_~\s<&()%]+|\S' - match: '[^?!.,:*_~\s<&()%]+|\S'
scope: markup.underline.link.path.log scope: markup.underline.link.path.log
- match: '' - include: immediately_pop
pop: true
double_quoted_string: double_quoted_string:
- meta_scope: string.quoted.double.log - meta_scope: string.quoted.double.log
- match: \\" - match: \\"
+1 -1
View File
@@ -366,7 +366,7 @@ ansible-galaxy install aeimer.install_bat
### From source ### From source
`bat` をソースからビルドしたいならば、Rust 1.51 以上の環境が必要です。 `bat` をソースからビルドしたいならば、Rust 1.60.0 以上の環境が必要です。
`cargo` を使用してビルドすることができます: `cargo` を使用してビルドすることができます:
```bash ```bash
+1 -1
View File
@@ -416,7 +416,7 @@ scoop install bat
### 소스에서 ### 소스에서
`bat`의 소스를 빌드하기 위해서는, Rust 1.51 이상이 필요합니다. `bat`의 소스를 빌드하기 위해서는, Rust 1.60.0 이상이 필요합니다.
`cargo`를 이용해 전부 빌드할 수 있습니다: `cargo`를 이용해 전부 빌드할 수 있습니다:
```bash ```bash
+1 -1
View File
@@ -344,7 +344,7 @@ ansible-galaxy install aeimer.install_bat
### Из исходников ### Из исходников
Если вы желаете установить `bat` из исходников, вам понадобится Rust 1.51 или выше. После этого используйте `cargo`, чтобы все скомпилировать: Если вы желаете установить `bat` из исходников, вам понадобится Rust 1.60.0 или выше. После этого используйте `cargo`, чтобы все скомпилировать:
```bash ```bash
cargo install --locked bat cargo install --locked bat
+2 -2
View File
@@ -372,7 +372,7 @@ scoop install bat
### 从源码编译 ### 从源码编译
如果你想要自己构建`bat`,那么你需要安装有高于1.51版本的 Rust。 如果你想要自己构建`bat`,那么你需要安装有高于1.58.0版本的 Rust。
使用以下命令编译。 使用以下命令编译。
@@ -550,7 +550,7 @@ bat --generate-config-file
# 在终端中以斜体输出文本(不是所有终端都支持) # 在终端中以斜体输出文本(不是所有终端都支持)
--italic-text=always --italic-text=always
# 使用 C++ 语法来给 Ardiuno 的 .ino 文件提供高亮 # 使用 C++ 语法来给 Arduino 的 .ino 文件提供高亮
--map-syntax "*.ino:C++" --map-syntax "*.ino:C++"
``` ```
+13 -11
View File
@@ -4,17 +4,17 @@ The following table tries to give an overview *from `bat`s perspective*, i.e. we
categories which are relevant for `bat`. Some of these projects have completely different goals and categories which are relevant for `bat`. Some of these projects have completely different goals and
if you are not looking for a program like `bat`, this comparison might not be for you. if you are not looking for a program like `bat`, this comparison might not be for you.
| | bat | [pygments](http://pygments.org/) | [highlight](http://www.andre-simon.de/doku/highlight/highlight.php) | [ccat](https://github.com/jingweno/ccat) | [source-highlight](https://www.gnu.org/software/src-highlite/) | [hicat](https://github.com/rstacruz/hicat) | [coderay](https://github.com/rubychan/coderay) | [rouge](https://github.com/jneen/rouge) | | | bat | [pygments](http://pygments.org/) | [highlight](http://www.andre-simon.de/doku/highlight/highlight.php) | [ccat](https://github.com/jingweno/ccat) | [source-highlight](https://www.gnu.org/software/src-highlite/) | [hicat](https://github.com/rstacruz/hicat) | [coderay](https://github.com/rubychan/coderay) | [rouge](https://github.com/jneen/rouge) | [clp](https://github.com/jpe90/clp) |
|----------------------------------------------|---------------------------------------------------------------------|----------------------------------|---------------------------------------------------------------------|------------------------------------------|----------------------------------------------------------------|-----------------------------------------------------|-----------------------------------------------------|-----------------------------------------------------| |----------------------------------------------|---------------------------------------------------------------------|----------------------------------|---------------------------------------------------------------------|------------------------------------------|----------------------------------------------------------------|-----------------------------------------------------|-----------------------------------------------------|-----------------------------------------------------|-----------------------------------------------------|
| Drop-in `cat` replacement | :heavy_check_mark: [*](https://github.com/sharkdp/bat/issues/134) | :x: | :x: | (:heavy_check_mark:) | :x: | :x: [*](https://github.com/rstacruz/hicat/issues/6) | :x: | :x: | | Drop-in `cat` replacement | :heavy_check_mark: [*](https://github.com/sharkdp/bat/issues/134) | :x: | :x: | (:heavy_check_mark:) | :x: | :x: [*](https://github.com/rstacruz/hicat/issues/6) | :x: | :x: | :x: |
| Git integration | :heavy_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | | Git integration | :heavy_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
| Automatic paging | :heavy_check_mark: | :x: | :x: | :x: | :x: | :heavy_check_mark: | :x: | :x: | | Automatic paging | :heavy_check_mark: | :x: | :x: | :x: | :x: | :heavy_check_mark: | :x: | :x: | :x: |
| Languages (circa) | 150 | 300 | 200 | 7 | 80 | 130 | 30 | 130 | | Languages (circa) | 150 | 300 | 200 | 7 | 80 | 130 | 30 | 130 | 150 |
| Extensible (languages, themes) | :heavy_check_mark: | (:heavy_check_mark:) | (:heavy_check_mark:) | :x: | (:heavy_check_mark:) | :x: | :x: | :x: | | Extensible (languages, themes) | :heavy_check_mark: | (:heavy_check_mark:) | (:heavy_check_mark:) | :x: | (:heavy_check_mark:) | :x: | :x: | :x: | :heavy_check_mark: |
| Advanced highlighting (e.g. nested syntaxes) | :heavy_check_mark: | :heavy_check_mark: | (:heavy_check_mark:) ? | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | Advanced highlighting (e.g. nested syntaxes) | :heavy_check_mark: | :heavy_check_mark: | (:heavy_check_mark:) ? | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| Execution time [ms] (`jquery-3.3.1.js`) | 624 | 789 | 400 | 80 | 300 | 316 | 157 | 695 | | Execution time [ms] (`jquery-3.3.1.js`) | 422 | 455 | 299 | 39 | 208 | 287 | 128 | 740 | 22 |
| Execution time [ms] (`miniz.c`) | 66 | 656 | 26 | 8 | 53 | 141 | 75 | 254 | | Execution time [ms] (`miniz.c`) | 27 | 169 | 19 | 4 | 36 | 131 | 58 | 231 | 4 |
| Execution time [ms] (370 kB XML file) | 238 | 487 | 129 | 111 | 110 | 339 | 147 | 359 | | Execution time [ms] (957 kB XML file) | 215 | 296 | 236 | 165 | 83 | 412 | 135 | 386 | 127 |
If you think that some entries in this table are outdated or wrong, please open a ticket or pull If you think that some entries in this table are outdated or wrong, please open a ticket or pull
request. request.
@@ -49,6 +49,7 @@ cmd_source_highlight="source-highlight --failsafe --infer-lang -f esc -i '$SRC'"
cmd_hicat="hicat '$SRC'" cmd_hicat="hicat '$SRC'"
cmd_coderay="coderay '$SRC'" cmd_coderay="coderay '$SRC'"
cmd_rouge="rougify '$SRC'" cmd_rouge="rougify '$SRC'"
cmd_clp="clp '$SRC'"
hyperfine --warmup 3 \ hyperfine --warmup 3 \
"$cmd_bat" \ "$cmd_bat" \
@@ -60,4 +61,5 @@ hyperfine --warmup 3 \
"$cmd_hicat" \ "$cmd_hicat" \
"$cmd_coderay" \ "$cmd_coderay" \
"$cmd_rouge" \ "$cmd_rouge" \
"$cmd_clp" \
``` ```
+1 -1
View File
@@ -1,4 +1,4 @@
/// A simple program that prints its own source code using the bat library /// A simple program that lists all supported syntaxes and themes.
use bat::PrettyPrinter; use bat::PrettyPrinter;
fn main() { fn main() {
+57
View File
@@ -69,10 +69,57 @@ impl HighlightingAssets {
} }
} }
/// The default theme.
///
/// ### Windows and Linux
///
/// Windows and most Linux distributions has a dark terminal theme by
/// default. On these platforms, this function always returns a theme that
/// looks good on a dark background.
///
/// ### macOS
///
/// On macOS the default terminal background is light, but it is common that
/// Dark Mode is active, which makes the terminal background dark. On this
/// platform, the default theme depends on
/// ```bash
/// defaults read -globalDomain AppleInterfaceStyle
/// ````
/// To avoid the overhead of the check on macOS, simply specify a theme
/// explicitly via `--theme`, `BAT_THEME`, or `~/.config/bat`.
///
/// See <https://github.com/sharkdp/bat/issues/1746> and
/// <https://github.com/sharkdp/bat/issues/1928> for more context.
pub fn default_theme() -> &'static str { pub fn default_theme() -> &'static str {
#[cfg(not(target_os = "macos"))]
{
Self::default_dark_theme()
}
#[cfg(target_os = "macos")]
{
if macos_dark_mode_active() {
Self::default_dark_theme()
} else {
Self::default_light_theme()
}
}
}
/**
* The default theme that looks good on a dark background.
*/
fn default_dark_theme() -> &'static str {
"Monokai Extended" "Monokai Extended"
} }
/**
* The default theme that looks good on a light background.
*/
#[cfg(target_os = "macos")]
fn default_light_theme() -> &'static str {
"Monokai Extended Light"
}
pub fn from_cache(cache_path: &Path) -> Result<Self> { pub fn from_cache(cache_path: &Path) -> Result<Self> {
Ok(HighlightingAssets::new( Ok(HighlightingAssets::new(
SerializedSyntaxSet::FromFile(cache_path.join("syntaxes.bin")), SerializedSyntaxSet::FromFile(cache_path.join("syntaxes.bin")),
@@ -352,6 +399,16 @@ fn asset_from_cache<T: serde::de::DeserializeOwned>(
.map_err(|_| format!("Could not parse cached {}", description).into()) .map_err(|_| format!("Could not parse cached {}", description).into())
} }
#[cfg(target_os = "macos")]
fn macos_dark_mode_active() -> bool {
let mut defaults_cmd = std::process::Command::new("defaults");
defaults_cmd.args(&["read", "-globalDomain", "AppleInterfaceStyle"]);
match defaults_cmd.output() {
Ok(output) => output.stdout == b"Dark\n",
Err(_) => true,
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
+1 -1
View File
@@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
use crate::error::*; use crate::error::*;
#[derive(Debug, PartialEq, Default, Serialize, Deserialize)] #[derive(Debug, PartialEq, Eq, Default, Serialize, Deserialize)]
pub struct AssetsMetadata { pub struct AssetsMetadata {
bat_version: Option<String>, bat_version: Option<String>,
creation_time: Option<SystemTime>, creation_time: Option<SystemTime>,
+2 -1
View File
@@ -1,3 +1,4 @@
use std::fmt::Write;
use std::fs::read_to_string; use std::fs::read_to_string;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@@ -124,7 +125,7 @@ fn append_to_acknowledgements(
relative_path: &str, relative_path: &str,
license_text: &str, license_text: &str,
) { ) {
acknowledgements.push_str(&format!("## {}\n\n{}", relative_path, license_text)); write!(acknowledgements, "## {}\n\n{}", relative_path, license_text).ok();
// Make sure the last char is a newline to not mess up formatting later // Make sure the last char is a newline to not mess up formatting later
if acknowledgements if acknowledgements
+86 -72
View File
@@ -1,6 +1,6 @@
use std::collections::HashSet; use std::collections::HashSet;
use std::env; use std::env;
use std::path::Path; use std::path::{Path, PathBuf};
use std::str::FromStr; use std::str::FromStr;
use atty::{self, Stream}; use atty::{self, Stream};
@@ -32,7 +32,7 @@ fn is_truecolor_terminal() -> bool {
} }
pub struct App { pub struct App {
pub matches: ArgMatches<'static>, pub matches: ArgMatches,
interactive_output: bool, interactive_output: bool,
} }
@@ -49,7 +49,7 @@ impl App {
}) })
} }
fn matches(interactive_output: bool) -> Result<ArgMatches<'static>> { fn matches(interactive_output: bool) -> Result<ArgMatches> {
let args = if wild::args_os().nth(1) == Some("cache".into()) let args = if wild::args_os().nth(1) == Some("cache".into())
|| wild::args_os().any(|arg| arg == "--no-config") || wild::args_os().any(|arg| arg == "--no-config")
{ {
@@ -79,13 +79,13 @@ impl App {
pub fn config(&self, inputs: &[Input]) -> Result<Config> { pub fn config(&self, inputs: &[Input]) -> Result<Config> {
let style_components = self.style_components()?; let style_components = self.style_components()?;
let paging_mode = match self.matches.value_of("paging") { let paging_mode = match self.matches.get_one::<String>("paging").map(|s| s.as_str()) {
Some("always") => PagingMode::Always, Some("always") => PagingMode::Always,
Some("never") => PagingMode::Never, Some("never") => PagingMode::Never,
Some("auto") | None => { Some("auto") | None => {
// If we have -pp as an option when in auto mode, the pager should be disabled. // If we have -pp as an option when in auto mode, the pager should be disabled.
let extra_plain = self.matches.occurrences_of("plain") > 1; let extra_plain = self.matches.get_count("plain") > 1;
if extra_plain || self.matches.is_present("no-paging") { if extra_plain || self.matches.get_flag("no-paging") {
PagingMode::Never PagingMode::Never
} else if inputs.iter().any(Input::is_stdin) { } else if inputs.iter().any(Input::is_stdin) {
// If we are reading from stdin, only enable paging if we write to an // If we are reading from stdin, only enable paging if we write to an
@@ -107,13 +107,13 @@ impl App {
let mut syntax_mapping = SyntaxMapping::builtin(); let mut syntax_mapping = SyntaxMapping::builtin();
if let Some(values) = self.matches.values_of("ignored-suffix") { if let Some(values) = self.matches.get_many::<String>("ignored-suffix") {
for suffix in values { for suffix in values {
syntax_mapping.insert_ignored_suffix(suffix); syntax_mapping.insert_ignored_suffix(suffix);
} }
} }
if let Some(values) = self.matches.values_of("map-syntax") { if let Some(values) = self.matches.get_many::<String>("map-syntax") {
for from_to in values { for from_to in values {
let parts: Vec<_> = from_to.split(':').collect(); let parts: Vec<_> = from_to.split(':').collect();
@@ -125,36 +125,43 @@ impl App {
} }
} }
let maybe_term_width = self.matches.value_of("terminal-width").and_then(|w| { let maybe_term_width = self
if w.starts_with('+') || w.starts_with('-') { .matches
// Treat argument as a delta to the current terminal width .get_one::<String>("terminal-width")
w.parse().ok().map(|delta: i16| { .and_then(|w| {
let old_width: u16 = Term::stdout().size().1; if w.starts_with('+') || w.starts_with('-') {
let new_width: i32 = i32::from(old_width) + i32::from(delta); // Treat argument as a delta to the current terminal width
w.parse().ok().map(|delta: i16| {
let old_width: u16 = Term::stdout().size().1;
let new_width: i32 = i32::from(old_width) + i32::from(delta);
if new_width <= 0 { if new_width <= 0 {
old_width as usize old_width as usize
} else { } else {
new_width as usize new_width as usize
} }
}) })
} else { } else {
w.parse().ok() w.parse().ok()
} }
}); });
Ok(Config { Ok(Config {
true_color: is_truecolor_terminal(), true_color: is_truecolor_terminal(),
language: self.matches.value_of("language").or_else(|| { language: self
if self.matches.is_present("show-all") { .matches
Some("show-nonprintable") .get_one::<String>("language")
} else { .map(|s| s.as_str())
None .or_else(|| {
} if self.matches.get_flag("show-all") {
}), Some("show-nonprintable")
show_nonprintable: self.matches.is_present("show-all"), } else {
None
}
}),
show_nonprintable: self.matches.get_flag("show-all"),
wrapping_mode: if self.interactive_output || maybe_term_width.is_some() { wrapping_mode: if self.interactive_output || maybe_term_width.is_some() {
match self.matches.value_of("wrap") { match self.matches.get_one::<String>("wrap").map(|s| s.as_str()) {
Some("character") => WrappingMode::Character, Some("character") => WrappingMode::Character,
Some("never") => WrappingMode::NoWrapping(true), Some("never") => WrappingMode::NoWrapping(true),
Some("auto") | None => { Some("auto") | None => {
@@ -171,8 +178,8 @@ impl App {
// There's no point in wrapping when this is the case. // There's no point in wrapping when this is the case.
WrappingMode::NoWrapping(false) WrappingMode::NoWrapping(false)
}, },
colored_output: self.matches.is_present("force-colorization") colored_output: self.matches.get_flag("force-colorization")
|| match self.matches.value_of("color") { || match self.matches.get_one::<String>("color").map(|s| s.as_str()) {
Some("always") => true, Some("always") => true,
Some("never") => false, Some("never") => false,
Some("auto") => env::var_os("NO_COLOR").is_none() && self.interactive_output, Some("auto") => env::var_os("NO_COLOR").is_none() && self.interactive_output,
@@ -181,12 +188,16 @@ impl App {
paging_mode, paging_mode,
term_width: maybe_term_width.unwrap_or(Term::stdout().size().1 as usize), term_width: maybe_term_width.unwrap_or(Term::stdout().size().1 as usize),
loop_through: !(self.interactive_output loop_through: !(self.interactive_output
|| self.matches.value_of("color") == Some("always") || self.matches.get_one::<String>("color").map(|s| s.as_str()) == Some("always")
|| self.matches.value_of("decorations") == Some("always") || self
|| self.matches.is_present("force-colorization")), .matches
.get_one::<String>("decorations")
.map(|s| s.as_str())
== Some("always")
|| self.matches.get_flag("force-colorization")),
tab_width: self tab_width: self
.matches .matches
.value_of("tabs") .get_one::<String>("tabs")
.map(String::from) .map(String::from)
.or_else(|| env::var("BAT_TABS").ok()) .or_else(|| env::var("BAT_TABS").ok())
.and_then(|t| t.parse().ok()) .and_then(|t| t.parse().ok())
@@ -199,7 +210,7 @@ impl App {
), ),
theme: self theme: self
.matches .matches
.value_of("theme") .get_one::<String>("theme")
.map(String::from) .map(String::from)
.or_else(|| env::var("BAT_THEME").ok()) .or_else(|| env::var("BAT_THEME").ok())
.map(|s| { .map(|s| {
@@ -210,19 +221,19 @@ impl App {
} }
}) })
.unwrap_or_else(|| String::from(HighlightingAssets::default_theme())), .unwrap_or_else(|| String::from(HighlightingAssets::default_theme())),
visible_lines: match self.matches.is_present("diff") { visible_lines: match self.matches.contains_id("diff") && self.matches.get_flag("diff") {
#[cfg(feature = "git")] #[cfg(feature = "git")]
true => VisibleLines::DiffContext( true => VisibleLines::DiffContext(
self.matches self.matches
.value_of("diff-context") .get_one::<String>("diff-context")
.and_then(|t| t.parse().ok()) .and_then(|t| t.parse().ok())
.unwrap_or(2), .unwrap_or(2),
), ),
_ => VisibleLines::Ranges( _ => VisibleLines::Ranges(
self.matches self.matches
.values_of("line-range") .get_many::<String>("line-range")
.map(|vs| vs.map(LineRange::from).collect()) .map(|vs| vs.map(|s| LineRange::from(s.as_str())).collect())
.transpose()? .transpose()?
.map(LineRanges::from) .map(LineRanges::from)
.unwrap_or_default(), .unwrap_or_default(),
@@ -230,45 +241,47 @@ impl App {
}, },
style_components, style_components,
syntax_mapping, syntax_mapping,
pager: self.matches.value_of("pager"), pager: self.matches.get_one::<String>("pager").map(|s| s.as_str()),
use_italic_text: self.matches.value_of("italic-text") == Some("always"), use_italic_text: self
.matches
.get_one::<String>("italic-text")
.map(|s| s.as_str())
== Some("always"),
highlighted_lines: self highlighted_lines: self
.matches .matches
.values_of("highlight-line") .get_many::<String>("highlight-line")
.map(|ws| ws.map(LineRange::from).collect()) .map(|ws| ws.map(|s| LineRange::from(s.as_str())).collect())
.transpose()? .transpose()?
.map(LineRanges::from) .map(LineRanges::from)
.map(HighlightedLineRanges) .map(HighlightedLineRanges)
.unwrap_or_default(), .unwrap_or_default(),
use_custom_assets: !self.matches.is_present("no-custom-assets"), use_custom_assets: !self.matches.get_flag("no-custom-assets"),
}) })
} }
pub fn inputs(&self) -> Result<Vec<Input>> { pub fn inputs(&self) -> Result<Vec<Input>> {
// verify equal length of file-names and input FILEs
match self.matches.values_of("file-name") {
Some(ref filenames)
if self.matches.values_of_os("FILE").is_some()
&& filenames.len() != self.matches.values_of_os("FILE").unwrap().len() =>
{
return Err("Must be one file name per input type.".into());
}
_ => {}
}
let filenames: Option<Vec<&Path>> = self let filenames: Option<Vec<&Path>> = self
.matches .matches
.values_of_os("file-name") .get_many::<PathBuf>("file-name")
.map(|values| values.map(Path::new).collect()); .map(|vs| vs.map(|p| p.as_path()).collect::<Vec<_>>());
let files: Option<Vec<&Path>> = self
.matches
.get_many::<PathBuf>("FILE")
.map(|vs| vs.map(|p| p.as_path()).collect::<Vec<_>>());
// verify equal length of file-names and input FILEs
if filenames.is_some()
&& files.is_some()
&& filenames.as_ref().map(|v| v.len()) != files.as_ref().map(|v| v.len())
{
return Err("Must be one file name per input type.".into());
}
let mut filenames_or_none: Box<dyn Iterator<Item = Option<&Path>>> = match filenames { let mut filenames_or_none: Box<dyn Iterator<Item = Option<&Path>>> = match filenames {
Some(filenames) => Box::new(filenames.into_iter().map(Some)), Some(filenames) => Box::new(filenames.into_iter().map(Some)),
None => Box::new(std::iter::repeat(None)), None => Box::new(std::iter::repeat(None)),
}; };
let files: Option<Vec<&Path>> = self
.matches
.values_of_os("FILE")
.map(|vs| vs.map(Path::new).collect());
if files.is_none() { if files.is_none() {
return Ok(vec![new_stdin_input( return Ok(vec![new_stdin_input(
filenames_or_none.next().unwrap_or(None), filenames_or_none.next().unwrap_or(None),
@@ -294,12 +307,12 @@ impl App {
fn style_components(&self) -> Result<StyleComponents> { fn style_components(&self) -> Result<StyleComponents> {
let matches = &self.matches; let matches = &self.matches;
let mut styled_components = let mut styled_components = StyleComponents(
StyleComponents(if matches.value_of("decorations") == Some("never") { if matches.get_one::<String>("decorations").map(|s| s.as_str()) == Some("never") {
HashSet::new() HashSet::new()
} else if matches.is_present("number") { } else if matches.get_flag("number") {
[StyleComponent::LineNumbers].iter().cloned().collect() [StyleComponent::LineNumbers].iter().cloned().collect()
} else if matches.is_present("plain") { } else if 0 < matches.get_count("plain") {
[StyleComponent::Plain].iter().cloned().collect() [StyleComponent::Plain].iter().cloned().collect()
} else { } else {
let env_style_components: Option<Vec<StyleComponent>> = env::var("BAT_STYLE") let env_style_components: Option<Vec<StyleComponent>> = env::var("BAT_STYLE")
@@ -313,7 +326,7 @@ impl App {
.transpose()?; .transpose()?;
matches matches
.value_of("style") .get_one::<String>("style")
.map(|styles| { .map(|styles| {
styles styles
.split(',') .split(',')
@@ -329,7 +342,8 @@ impl App {
acc.extend(components.iter().cloned()); acc.extend(components.iter().cloned());
acc acc
}) })
}); },
);
// If `grid` is set, remove `rule` as it is a subset of `grid`, and print a warning. // If `grid` is set, remove `rule` as it is a subset of `grid`, and print a warning.
if styled_components.grid() && styled_components.0.remove(&StyleComponent::Rule) { if styled_components.grid() && styled_components.0.remove(&StyleComponent::Rule) {
+142 -121
View File
@@ -1,7 +1,10 @@
use clap::{crate_name, crate_version, App as ClapApp, AppSettings, Arg, ArgGroup, SubCommand}; use clap::{
crate_name, crate_version, value_parser, AppSettings, Arg, ArgAction, ArgGroup, ColorChoice,
Command,
};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::env; use std::env;
use std::path::Path; use std::path::{Path, PathBuf};
static VERSION: Lazy<String> = Lazy::new(|| { static VERSION: Lazy<String> = Lazy::new(|| {
#[cfg(feature = "bugreport")] #[cfg(feature = "bugreport")]
@@ -16,23 +19,21 @@ static VERSION: Lazy<String> = Lazy::new(|| {
} }
}); });
pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> { pub fn build_app(interactive_output: bool) -> Command<'static> {
let clap_color_setting = if interactive_output && env::var_os("NO_COLOR").is_none() { let color_when = if interactive_output && env::var_os("NO_COLOR").is_none() {
AppSettings::ColoredHelp ColorChoice::Auto
} else { } else {
AppSettings::ColorNever ColorChoice::Never
}; };
let mut app = ClapApp::new(crate_name!()) let mut app = Command::new(crate_name!())
.version(VERSION.as_str()) .version(VERSION.as_str())
.global_setting(clap_color_setting) .color(color_when)
.global_setting(AppSettings::DeriveDisplayOrder) .global_setting(AppSettings::DeriveDisplayOrder)
.global_setting(AppSettings::UnifiedHelpMessage) .hide_possible_values(true)
.global_setting(AppSettings::HidePossibleValuesInHelp) .args_conflicts_with_subcommands(true)
.setting(AppSettings::ArgsNegateSubcommands) .allow_external_subcommands(true)
.setting(AppSettings::AllowExternalSubcommands) .disable_help_subcommand(true)
.setting(AppSettings::DisableHelpSubcommand)
.setting(AppSettings::VersionlessSubcommands)
.max_term_width(100) .max_term_width(100)
.about( .about(
"A cat(1) clone with wings.\n\n\ "A cat(1) clone with wings.\n\n\
@@ -44,20 +45,22 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
) )
.long_about("A cat(1) clone with syntax highlighting and Git integration.") .long_about("A cat(1) clone with syntax highlighting and Git integration.")
.arg( .arg(
Arg::with_name("FILE") Arg::new("FILE")
.help("File(s) to print / concatenate. Use '-' for standard input.") .help("File(s) to print / concatenate. Use '-' for standard input.")
.long_help( .long_help(
"File(s) to print / concatenate. Use a dash ('-') or no argument at all \ "File(s) to print / concatenate. Use a dash ('-') or no argument at all \
to read from standard input.", to read from standard input.",
) )
.multiple(true) .takes_value(true)
.empty_values(false), .multiple_values(true)
.value_parser(value_parser!(PathBuf)),
) )
.arg( .arg(
Arg::with_name("show-all") Arg::new("show-all")
.long("show-all") .long("show-all")
.alias("show-nonprintable") .alias("show-nonprintable")
.short("A") .short('A')
.action(ArgAction::SetTrue)
.conflicts_with("language") .conflicts_with("language")
.help("Show non-printable characters (space, tab, newline, ..).") .help("Show non-printable characters (space, tab, newline, ..).")
.long_help( .long_help(
@@ -67,22 +70,22 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
), ),
) )
.arg( .arg(
Arg::with_name("plain") Arg::new("plain")
.overrides_with("plain") .overrides_with("plain")
.overrides_with("number") .overrides_with("number")
.short("p") .short('p')
.long("plain") .long("plain")
.multiple(true) .action(ArgAction::Count)
.help("Show plain style (alias for '--style=plain').") .help("Show plain style (alias for '--style=plain').")
.long_help( .long_help(
"Only show plain style, no decorations. This is an alias for \ "Only show plain style, no decorations. This is an alias for \
'--style=plain'. When '-p' is used twice ('-pp'), it also disables \ '--style=plain'. When '-p' is used twice ('-pp'), it also disables \
automatic paging (alias for '--style=plain --pager=never').", automatic paging (alias for '--style=plain --paging=never').",
), ),
) )
.arg( .arg(
Arg::with_name("language") Arg::new("language")
.short("l") .short('l')
.long("language") .long("language")
.overrides_with("language") .overrides_with("language")
.help("Set the language for syntax highlighting.") .help("Set the language for syntax highlighting.")
@@ -95,12 +98,11 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
.takes_value(true), .takes_value(true),
) )
.arg( .arg(
Arg::with_name("highlight-line") Arg::new("highlight-line")
.long("highlight-line") .long("highlight-line")
.short("H") .short('H')
.takes_value(true) .takes_value(true)
.number_of_values(1) .action(ArgAction::Append)
.multiple(true)
.value_name("N:M") .value_name("N:M")
.help("Highlight lines N through M.") .help("Highlight lines N through M.")
.long_help( .long_help(
@@ -114,12 +116,12 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
), ),
) )
.arg( .arg(
Arg::with_name("file-name") Arg::new("file-name")
.long("file-name") .long("file-name")
.takes_value(true) .takes_value(true)
.number_of_values(1) .action(ArgAction::Append)
.multiple(true)
.value_name("name") .value_name("name")
.value_parser(value_parser!(PathBuf))
.help("Specify the name to display for a file.") .help("Specify the name to display for a file.")
.long_help( .long_help(
"Specify the name to display for a file. Useful when piping \ "Specify the name to display for a file. Useful when piping \
@@ -133,9 +135,11 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
{ {
app = app app = app
.arg( .arg(
Arg::with_name("diff") Arg::new("diff")
.long("diff") .long("diff")
.short("d") .short('d')
.action(ArgAction::SetTrue)
.conflicts_with("line-range")
.help("Only show lines that have been added/removed/modified.") .help("Only show lines that have been added/removed/modified.")
.long_help( .long_help(
"Only show lines that have been added/removed/modified with respect \ "Only show lines that have been added/removed/modified with respect \
@@ -143,20 +147,20 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
), ),
) )
.arg( .arg(
Arg::with_name("diff-context") Arg::new("diff-context")
.long("diff-context") .long("diff-context")
.overrides_with("diff-context") .overrides_with("diff-context")
.takes_value(true) .takes_value(true)
.value_name("N") .value_name("N")
.validator( .value_parser(
|n| { |n: &str| {
n.parse::<usize>() n.parse::<usize>()
.map_err(|_| "must be a number") .map_err(|_| "must be a number")
.map(|_| ()) // Convert to Result<(), &str> .map(|_| n.to_owned()) // Convert to Result<String, &str>
.map_err(|e| e.to_string()) .map_err(|e| e.to_string())
}, // Convert to Result<(), String> }, // Convert to Result<(), String>
) )
.hidden_short_help(true) .hide_short_help(true)
.long_help( .long_help(
"Include N lines of context around added/removed/modified lines when using '--diff'.", "Include N lines of context around added/removed/modified lines when using '--diff'.",
), ),
@@ -164,16 +168,16 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
} }
app = app.arg( app = app.arg(
Arg::with_name("tabs") Arg::new("tabs")
.long("tabs") .long("tabs")
.overrides_with("tabs") .overrides_with("tabs")
.takes_value(true) .takes_value(true)
.value_name("T") .value_name("T")
.validator( .value_parser(
|t| { |t: &str| {
t.parse::<u32>() t.parse::<u32>()
.map_err(|_t| "must be a number") .map_err(|_t| "must be a number")
.map(|_t| ()) // Convert to Result<(), &str> .map(|_t| t.to_owned()) // Convert to Result<String, &str>
.map_err(|e| e.to_string()) .map_err(|e| e.to_string())
}, // Convert to Result<(), String> }, // Convert to Result<(), String>
) )
@@ -184,12 +188,12 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
), ),
) )
.arg( .arg(
Arg::with_name("wrap") Arg::new("wrap")
.long("wrap") .long("wrap")
.overrides_with("wrap") .overrides_with("wrap")
.takes_value(true) .takes_value(true)
.value_name("mode") .value_name("mode")
.possible_values(&["auto", "never", "character"]) .value_parser(["auto", "never", "character"])
.default_value("auto") .default_value("auto")
.hide_default_value(true) .hide_default_value(true)
.help("Specify the text-wrapping mode (*auto*, never, character).") .help("Specify the text-wrapping mode (*auto*, never, character).")
@@ -198,21 +202,21 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
control the output width."), control the output width."),
) )
.arg( .arg(
Arg::with_name("terminal-width") Arg::new("terminal-width")
.long("terminal-width") .long("terminal-width")
.takes_value(true) .takes_value(true)
.value_name("width") .value_name("width")
.hidden_short_help(true) .hide_short_help(true)
.allow_hyphen_values(true) .allow_hyphen_values(true)
.validator( .value_parser(
|t| { |t: &str| {
let is_offset = t.starts_with('+') || t.starts_with('-'); let is_offset = t.starts_with('+') || t.starts_with('-');
t.parse::<i32>() t.parse::<i32>()
.map_err(|_e| "must be an offset or number") .map_err(|_e| "must be an offset or number")
.and_then(|v| if v == 0 && !is_offset { .and_then(|v| if v == 0 && !is_offset {
Err("terminal width cannot be zero") Err("terminal width cannot be zero")
} else { } else {
Ok(()) Ok(t.to_owned())
}) })
.map_err(|e| e.to_string()) .map_err(|e| e.to_string())
}) })
@@ -223,10 +227,11 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
), ),
) )
.arg( .arg(
Arg::with_name("number") Arg::new("number")
.long("number") .long("number")
.overrides_with("number") .overrides_with("number")
.short("n") .short('n')
.action(ArgAction::SetTrue)
.help("Show line numbers (alias for '--style=numbers').") .help("Show line numbers (alias for '--style=numbers').")
.long_help( .long_help(
"Only show line numbers, no other decorations. This is an alias for \ "Only show line numbers, no other decorations. This is an alias for \
@@ -234,12 +239,12 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
), ),
) )
.arg( .arg(
Arg::with_name("color") Arg::new("color")
.long("color") .long("color")
.overrides_with("color") .overrides_with("color")
.takes_value(true) .takes_value(true)
.value_name("when") .value_name("when")
.possible_values(&["auto", "never", "always"]) .value_parser(["auto", "never", "always"])
.hide_default_value(true) .hide_default_value(true)
.default_value("auto") .default_value("auto")
.help("When to use colors (*auto*, never, always).") .help("When to use colors (*auto*, never, always).")
@@ -251,23 +256,23 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
), ),
) )
.arg( .arg(
Arg::with_name("italic-text") Arg::new("italic-text")
.long("italic-text") .long("italic-text")
.takes_value(true) .takes_value(true)
.value_name("when") .value_name("when")
.possible_values(&["always", "never"]) .value_parser(["always", "never"])
.default_value("never") .default_value("never")
.hide_default_value(true) .hide_default_value(true)
.help("Use italics in output (always, *never*)") .help("Use italics in output (always, *never*)")
.long_help("Specify when to use ANSI sequences for italic text in the output. Possible values: always, *never*."), .long_help("Specify when to use ANSI sequences for italic text in the output. Possible values: always, *never*."),
) )
.arg( .arg(
Arg::with_name("decorations") Arg::new("decorations")
.long("decorations") .long("decorations")
.overrides_with("decorations") .overrides_with("decorations")
.takes_value(true) .takes_value(true)
.value_name("when") .value_name("when")
.possible_values(&["auto", "never", "always"]) .value_parser(["auto", "never", "always"])
.default_value("auto") .default_value("auto")
.hide_default_value(true) .hide_default_value(true)
.help("When to show the decorations (*auto*, never, always).") .help("When to show the decorations (*auto*, never, always).")
@@ -278,24 +283,26 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
), ),
) )
.arg( .arg(
Arg::with_name("force-colorization") Arg::new("force-colorization")
.long("force-colorization") .long("force-colorization")
.short("f") .short('f')
.action(ArgAction::SetTrue)
.conflicts_with("color") .conflicts_with("color")
.conflicts_with("decorations") .conflicts_with("decorations")
.overrides_with("force-colorization") .overrides_with("force-colorization")
.hidden_short_help(true) .hide_short_help(true)
.long_help("Alias for '--decorations=always --color=always'. This is useful \ .long_help("Alias for '--decorations=always --color=always'. This is useful \
if the output of bat is piped to another program, but you want \ if the output of bat is piped to another program, but you want \
to keep the colorization/decorations.") to keep the colorization/decorations.")
) )
.arg( .arg(
Arg::with_name("paging") Arg::new("paging")
.long("paging") .long("paging")
.overrides_with("paging") .overrides_with("paging")
.overrides_with("no-paging")
.takes_value(true) .takes_value(true)
.value_name("when") .value_name("when")
.possible_values(&["auto", "never", "always"]) .value_parser(["auto", "never", "always"])
.default_value("auto") .default_value("auto")
.hide_default_value(true) .hide_default_value(true)
.help("Specify when to use the pager, or use `-P` to disable (*auto*, never, always).") .help("Specify when to use the pager, or use `-P` to disable (*auto*, never, always).")
@@ -307,22 +314,23 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
), ),
) )
.arg( .arg(
Arg::with_name("no-paging") Arg::new("no-paging")
.short("P") .short('P')
.long("no-paging") .long("no-paging")
.alias("no-pager") .alias("no-pager")
.action(ArgAction::SetTrue)
.overrides_with("no-paging") .overrides_with("no-paging")
.hidden(true) .hide(true)
.hidden_short_help(true) .hide_short_help(true)
.help("Alias for '--paging=never'") .help("Alias for '--paging=never'")
) )
.arg( .arg(
Arg::with_name("pager") Arg::new("pager")
.long("pager") .long("pager")
.overrides_with("pager") .overrides_with("pager")
.takes_value(true) .takes_value(true)
.value_name("command") .value_name("command")
.hidden_short_help(true) .hide_short_help(true)
.help("Determine which pager to use.") .help("Determine which pager to use.")
.long_help( .long_help(
"Determine which pager is used. This option will override the \ "Determine which pager is used. This option will override the \
@@ -332,12 +340,11 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
), ),
) )
.arg( .arg(
Arg::with_name("map-syntax") Arg::new("map-syntax")
.short("m") .short('m')
.long("map-syntax") .long("map-syntax")
.multiple(true) .action(ArgAction::Append)
.takes_value(true) .takes_value(true)
.number_of_values(1)
.value_name("glob:syntax") .value_name("glob:syntax")
.help("Use the specified syntax for files matching the glob pattern ('*.cpp:C++').") .help("Use the specified syntax for files matching the glob pattern ('*.cpp:C++').")
.long_help( .long_help(
@@ -350,19 +357,18 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
.takes_value(true), .takes_value(true),
) )
.arg( .arg(
Arg::with_name("ignored-suffix") Arg::new("ignored-suffix")
.number_of_values(1) .action(ArgAction::Append)
.multiple(true)
.takes_value(true) .takes_value(true)
.long("ignored-suffix") .long("ignored-suffix")
.hidden_short_help(true) .hide_short_help(true)
.help( .help(
"Ignore extension. For example:\n \ "Ignore extension. For example:\n \
'bat --ignored-suffix \".dev\" my_file.json.dev' will use JSON syntax, and ignore '.dev'" 'bat --ignored-suffix \".dev\" my_file.json.dev' will use JSON syntax, and ignore '.dev'"
) )
) )
.arg( .arg(
Arg::with_name("theme") Arg::new("theme")
.long("theme") .long("theme")
.overrides_with("theme") .overrides_with("theme")
.takes_value(true) .takes_value(true)
@@ -376,24 +382,25 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
), ),
) )
.arg( .arg(
Arg::with_name("list-themes") Arg::new("list-themes")
.long("list-themes") .long("list-themes")
.action(ArgAction::SetTrue)
.help("Display all supported highlighting themes.") .help("Display all supported highlighting themes.")
.long_help("Display a list of supported themes for syntax highlighting."), .long_help("Display a list of supported themes for syntax highlighting."),
) )
.arg( .arg(
Arg::with_name("style") Arg::new("style")
.long("style") .long("style")
.value_name("components") .value_name("components")
// Need to turn this off for overrides_with to work as we want. See the bottom most // Need to turn this off for overrides_with to work as we want. See the bottom most
// example at https://docs.rs/clap/2.32.0/clap/struct.Arg.html#method.overrides_with // example at https://docs.rs/clap/2.32.0/clap/struct.Arg.html#method.overrides_with
.use_delimiter(false) .use_value_delimiter(false)
.takes_value(true) .takes_value(true)
.overrides_with("style") .overrides_with("style")
.overrides_with("plain") .overrides_with("plain")
.overrides_with("number") .overrides_with("number")
// Cannot use claps built in validation because we have to turn off clap's delimiters // Cannot use claps built in validation because we have to turn off clap's delimiters
.validator(|val| { .value_parser(|val: &str| {
let mut invalid_vals = val.split(',').filter(|style| { let mut invalid_vals = val.split(',').filter(|style| {
!&[ !&[
"auto", "auto",
@@ -415,7 +422,7 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
if let Some(invalid) = invalid_vals.next() { if let Some(invalid) = invalid_vals.next() {
Err(format!("Unknown style, '{}'", invalid)) Err(format!("Unknown style, '{}'", invalid))
} else { } else {
Ok(()) Ok(val.to_owned())
} }
}) })
.help( .help(
@@ -447,14 +454,12 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
), ),
) )
.arg( .arg(
Arg::with_name("line-range") Arg::new("line-range")
.long("line-range") .long("line-range")
.short("r") .short('r')
.multiple(true) .action(ArgAction::Append)
.takes_value(true) .takes_value(true)
.number_of_values(1)
.value_name("N:M") .value_name("N:M")
.conflicts_with("diff")
.help("Only print the lines from N to M.") .help("Only print the lines from N to M.")
.long_help( .long_help(
"Only print the specified range of lines for each file. \ "Only print the specified range of lines for each file. \
@@ -467,18 +472,19 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
), ),
) )
.arg( .arg(
Arg::with_name("list-languages") Arg::new("list-languages")
.long("list-languages") .long("list-languages")
.short("L") .short('L')
.action(ArgAction::SetTrue)
.conflicts_with("list-themes") .conflicts_with("list-themes")
.help("Display all supported languages.") .help("Display all supported languages.")
.long_help("Display a list of supported languages for syntax highlighting."), .long_help("Display a list of supported languages for syntax highlighting."),
) )
.arg( .arg(
Arg::with_name("unbuffered") Arg::new("unbuffered")
.short("u") .short('u')
.long("unbuffered") .long("unbuffered")
.hidden_short_help(true) .hide_short_help(true)
.long_help( .long_help(
"This option exists for POSIX-compliance reasons ('u' is for \ "This option exists for POSIX-compliance reasons ('u' is for \
'unbuffered'). The output is always unbuffered - this option \ 'unbuffered'). The output is always unbuffered - this option \
@@ -486,60 +492,66 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
), ),
) )
.arg( .arg(
Arg::with_name("no-config") Arg::new("no-config")
.long("no-config") .long("no-config")
.hidden(true) .hide(true)
.help("Do not use the configuration file"), .help("Do not use the configuration file"),
) )
.arg( .arg(
Arg::with_name("no-custom-assets") Arg::new("no-custom-assets")
.long("no-custom-assets") .long("no-custom-assets")
.hidden(true) .action(ArgAction::SetTrue)
.hide(true)
.help("Do not load custom assets"), .help("Do not load custom assets"),
) )
.arg( .arg(
Arg::with_name("config-file") Arg::new("config-file")
.long("config-file") .long("config-file")
.action(ArgAction::SetTrue)
.conflicts_with("list-languages") .conflicts_with("list-languages")
.conflicts_with("list-themes") .conflicts_with("list-themes")
.hidden(true) .hide(true)
.help("Show path to the configuration file."), .help("Show path to the configuration file."),
) )
.arg( .arg(
Arg::with_name("generate-config-file") Arg::new("generate-config-file")
.long("generate-config-file") .long("generate-config-file")
.action(ArgAction::SetTrue)
.conflicts_with("list-languages") .conflicts_with("list-languages")
.conflicts_with("list-themes") .conflicts_with("list-themes")
.hidden(true) .hide(true)
.help("Generates a default configuration file."), .help("Generates a default configuration file."),
) )
.arg( .arg(
Arg::with_name("config-dir") Arg::new("config-dir")
.long("config-dir") .long("config-dir")
.hidden(true) .action(ArgAction::SetTrue)
.hide(true)
.help("Show bat's configuration directory."), .help("Show bat's configuration directory."),
) )
.arg( .arg(
Arg::with_name("cache-dir") Arg::new("cache-dir")
.long("cache-dir") .long("cache-dir")
.hidden(true) .action(ArgAction::SetTrue)
.hide(true)
.help("Show bat's cache directory."), .help("Show bat's cache directory."),
) )
.arg( .arg(
Arg::with_name("diagnostic") Arg::new("diagnostic")
.long("diagnostic") .long("diagnostic")
.alias("diagnostics") .alias("diagnostics")
.hidden_short_help(true) .action(ArgAction::SetTrue)
.hide_short_help(true)
.help("Show diagnostic information for bug reports.") .help("Show diagnostic information for bug reports.")
) )
.arg( .arg(
Arg::with_name("acknowledgements") Arg::new("acknowledgements")
.long("acknowledgements") .long("acknowledgements")
.hidden_short_help(true) .action(ArgAction::SetTrue)
.hide_short_help(true)
.help("Show acknowledgements."), .help("Show acknowledgements."),
) )
.help_message("Print this help message.") .mut_arg("help", |arg| arg.help("Print this help message."));
.version_message("Show version information.");
// Check if the current directory contains a file name cache. Otherwise, // Check if the current directory contains a file name cache. Otherwise,
// enable the 'bat cache' subcommand. // enable the 'bat cache' subcommand.
@@ -547,12 +559,13 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
app app
} else { } else {
app.subcommand( app.subcommand(
SubCommand::with_name("cache") Command::new("cache")
.about("Modify the syntax-definition and theme cache") .about("Modify the syntax-definition and theme cache")
.arg( .arg(
Arg::with_name("build") Arg::new("build")
.long("build") .long("build")
.short("b") .short('b')
.action(ArgAction::SetTrue)
.help("Initialize (or update) the syntax/theme cache.") .help("Initialize (or update) the syntax/theme cache.")
.long_help( .long_help(
"Initialize (or update) the syntax/theme cache by loading from \ "Initialize (or update) the syntax/theme cache by loading from \
@@ -560,18 +573,19 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
), ),
) )
.arg( .arg(
Arg::with_name("clear") Arg::new("clear")
.long("clear") .long("clear")
.short("c") .short('c')
.action(ArgAction::SetTrue)
.help("Remove the cached syntax definitions and themes."), .help("Remove the cached syntax definitions and themes."),
) )
.group( .group(
ArgGroup::with_name("cache-actions") ArgGroup::new("cache-actions")
.args(&["build", "clear"]) .args(&["build", "clear"])
.required(true), .required(true),
) )
.arg( .arg(
Arg::with_name("source") Arg::new("source")
.long("source") .long("source")
.requires("build") .requires("build")
.takes_value(true) .takes_value(true)
@@ -579,7 +593,7 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
.help("Use a different directory to load syntaxes and themes from."), .help("Use a different directory to load syntaxes and themes from."),
) )
.arg( .arg(
Arg::with_name("target") Arg::new("target")
.long("target") .long("target")
.requires("build") .requires("build")
.takes_value(true) .takes_value(true)
@@ -589,8 +603,9 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
), ),
) )
.arg( .arg(
Arg::with_name("blank") Arg::new("blank")
.long("blank") .long("blank")
.action(ArgAction::SetTrue)
.requires("build") .requires("build")
.help( .help(
"Create completely new syntax and theme sets \ "Create completely new syntax and theme sets \
@@ -598,11 +613,17 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
), ),
) )
.arg( .arg(
Arg::with_name("acknowledgements") Arg::new("acknowledgements")
.long("acknowledgements") .long("acknowledgements")
.action(ArgAction::SetTrue)
.requires("build") .requires("build")
.help("Build acknowledgements.bin."), .help("Build acknowledgements.bin."),
), ),
) )
} }
} }
#[test]
fn verify_app() {
build_app(false).debug_assert();
}
+28 -5
View File
@@ -6,6 +6,22 @@ use std::path::PathBuf;
use crate::directories::PROJECT_DIRS; use crate::directories::PROJECT_DIRS;
#[cfg(not(target_os = "windows"))]
const DEFAULT_SYSTEM_CONFIG_PREFIX: &str = "/etc";
#[cfg(target_os = "windows")]
const DEFAULT_SYSTEM_CONFIG_PREFIX: &str = "C:\\ProgramData";
pub fn system_config_file() -> PathBuf {
let folder = option_env!("BAT_SYSTEM_CONFIG_PREFIX").unwrap_or(DEFAULT_SYSTEM_CONFIG_PREFIX);
let mut path = PathBuf::from(folder);
path.push("bat");
path.push("config");
path
}
pub fn config_file() -> PathBuf { pub fn config_file() -> PathBuf {
env::var("BAT_CONFIG_PATH") env::var("BAT_CONFIG_PATH")
.ok() .ok()
@@ -87,11 +103,18 @@ pub fn generate_config_file() -> bat::error::Result<()> {
} }
pub fn get_args_from_config_file() -> Result<Vec<OsString>, shell_words::ParseError> { pub fn get_args_from_config_file() -> Result<Vec<OsString>, shell_words::ParseError> {
Ok(fs::read_to_string(config_file()) let mut config = String::new();
.ok()
.map(|content| get_args_from_str(&content)) if let Ok(c) = fs::read_to_string(system_config_file()) {
.transpose()? config.push_str(&c);
.unwrap_or_default()) config.push('\n');
}
if let Ok(c) = fs::read_to_string(config_file()) {
config.push_str(&c);
}
get_args_from_str(&config)
} }
pub fn get_args_from_env_var() -> Option<Result<Vec<OsString>, shell_words::ParseError>> { pub fn get_args_from_env_var() -> Option<Result<Vec<OsString>, shell_words::ParseError>> {
+29 -22
View File
@@ -8,6 +8,7 @@ mod directories;
mod input; mod input;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::fmt::Write as _;
use std::io; use std::io;
use std::io::{BufReader, Write}; use std::io::{BufReader, Write};
use std::path::Path; use std::path::Path;
@@ -21,6 +22,9 @@ use crate::{
config::{config_file, generate_config_file}, config::{config_file, generate_config_file},
}; };
#[cfg(feature = "bugreport")]
use crate::config::system_config_file;
use assets::{assets_from_cache_or_binary, cache_dir, clear_assets, config_dir}; use assets::{assets_from_cache_or_binary, cache_dir, clear_assets, config_dir};
use directories::PROJECT_DIRS; use directories::PROJECT_DIRS;
use globset::GlobMatcher; use globset::GlobMatcher;
@@ -39,30 +43,30 @@ const THEME_PREVIEW_DATA: &[u8] = include_bytes!("../../../assets/theme_preview.
#[cfg(feature = "build-assets")] #[cfg(feature = "build-assets")]
fn build_assets(matches: &clap::ArgMatches) -> Result<()> { fn build_assets(matches: &clap::ArgMatches) -> Result<()> {
let source_dir = matches let source_dir = matches
.value_of("source") .get_one::<String>("source")
.map(Path::new) .map(Path::new)
.unwrap_or_else(|| PROJECT_DIRS.config_dir()); .unwrap_or_else(|| PROJECT_DIRS.config_dir());
let target_dir = matches let target_dir = matches
.value_of("target") .get_one::<String>("target")
.map(Path::new) .map(Path::new)
.unwrap_or_else(|| PROJECT_DIRS.cache_dir()); .unwrap_or_else(|| PROJECT_DIRS.cache_dir());
bat::assets::build( bat::assets::build(
source_dir, source_dir,
!matches.is_present("blank"), !matches.get_flag("blank"),
matches.is_present("acknowledgements"), matches.get_flag("acknowledgements"),
target_dir, target_dir,
clap::crate_version!(), clap::crate_version!(),
) )
} }
fn run_cache_subcommand(matches: &clap::ArgMatches) -> Result<()> { fn run_cache_subcommand(matches: &clap::ArgMatches) -> Result<()> {
if matches.is_present("build") { if matches.get_flag("build") {
#[cfg(feature = "build-assets")] #[cfg(feature = "build-assets")]
build_assets(matches)?; build_assets(matches)?;
#[cfg(not(feature = "build-assets"))] #[cfg(not(feature = "build-assets"))]
println!("bat has been built without the 'build-assets' feature. The 'cache --build' option is not available."); println!("bat has been built without the 'build-assets' feature. The 'cache --build' option is not available.");
} else if matches.is_present("clear") { } else if matches.get_flag("clear") {
clear_assets(); clear_assets();
} }
@@ -125,7 +129,7 @@ pub fn get_languages(config: &Config) -> Result<String> {
if config.loop_through { if config.loop_through {
for lang in languages { for lang in languages {
result += &format!("{}:{}\n", lang.name, lang.file_extensions.join(",")); writeln!(result, "{}:{}", lang.name, lang.file_extensions.join(",")).ok();
} }
} else { } else {
let longest = languages let longest = languages
@@ -146,7 +150,7 @@ pub fn get_languages(config: &Config) -> Result<String> {
}; };
for lang in languages { for lang in languages {
result += &format!("{:width$}{}", lang.name, separator, width = longest); write!(result, "{:width$}{}", lang.name, separator, width = longest).ok();
// Number of characters on this line so far, wrap before `desired_width` // Number of characters on this line so far, wrap before `desired_width`
let mut num_chars = 0; let mut num_chars = 0;
@@ -157,11 +161,11 @@ pub fn get_languages(config: &Config) -> Result<String> {
let new_chars = word.len() + comma_separator.len(); let new_chars = word.len() + comma_separator.len();
if num_chars + new_chars >= desired_width { if num_chars + new_chars >= desired_width {
num_chars = 0; num_chars = 0;
result += &format!("\n{:width$}{}", "", separator, width = longest); write!(result, "\n{:width$}{}", "", separator, width = longest).ok();
} }
num_chars += new_chars; num_chars += new_chars;
result += &format!("{}", style.paint(&word[..])); write!(result, "{}", style.paint(&word[..])).ok();
if extension.peek().is_some() { if extension.peek().is_some() {
result += comma_separator; result += comma_separator;
} }
@@ -227,8 +231,10 @@ fn run_controller(inputs: Vec<Input>, config: &Config) -> Result<bool> {
#[cfg(feature = "bugreport")] #[cfg(feature = "bugreport")]
fn invoke_bugreport(app: &App) { fn invoke_bugreport(app: &App) {
use bugreport::{bugreport, collector::*, format::Markdown}; use bugreport::{bugreport, collector::*, format::Markdown};
let pager = bat::config::get_pager_executable(app.matches.value_of("pager")) let pager = bat::config::get_pager_executable(
.unwrap_or_else(|| "less".to_owned()); // FIXME: Avoid non-canonical path to "less". app.matches.get_one::<String>("pager").map(|s| s.as_str()),
)
.unwrap_or_else(|| "less".to_owned()); // FIXME: Avoid non-canonical path to "less".
let mut custom_assets_metadata = PROJECT_DIRS.cache_dir().to_path_buf(); let mut custom_assets_metadata = PROJECT_DIRS.cache_dir().to_path_buf();
custom_assets_metadata.push("metadata.yaml"); custom_assets_metadata.push("metadata.yaml");
@@ -256,6 +262,7 @@ fn invoke_bugreport(app: &App) {
"NO_COLOR", "NO_COLOR",
"MANPAGER", "MANPAGER",
])) ]))
.info(FileContent::new("System Config file", system_config_file()))
.info(FileContent::new("Config file", config_file())) .info(FileContent::new("Config file", config_file()))
.info(FileContent::new( .info(FileContent::new(
"Custom assets metadata", "Custom assets metadata",
@@ -284,7 +291,7 @@ fn invoke_bugreport(app: &App) {
fn run() -> Result<bool> { fn run() -> Result<bool> {
let app = App::new()?; let app = App::new()?;
if app.matches.is_present("diagnostic") { if app.matches.get_flag("diagnostic") {
#[cfg(feature = "bugreport")] #[cfg(feature = "bugreport")]
invoke_bugreport(&app); invoke_bugreport(&app);
#[cfg(not(feature = "bugreport"))] #[cfg(not(feature = "bugreport"))]
@@ -293,11 +300,11 @@ fn run() -> Result<bool> {
} }
match app.matches.subcommand() { match app.matches.subcommand() {
("cache", Some(cache_matches)) => { Some(("cache", cache_matches)) => {
// If there is a file named 'cache' in the current working directory, // If there is a file named 'cache' in the current working directory,
// arguments for subcommand 'cache' are not mandatory. // arguments for subcommand 'cache' are not mandatory.
// If there are non-zero arguments, execute the subcommand cache, else, open the file cache. // If there are non-zero arguments, execute the subcommand cache, else, open the file cache.
if !cache_matches.args.is_empty() { if cache_matches.args_present() {
run_cache_subcommand(cache_matches)?; run_cache_subcommand(cache_matches)?;
Ok(true) Ok(true)
} else { } else {
@@ -311,7 +318,7 @@ fn run() -> Result<bool> {
let inputs = app.inputs()?; let inputs = app.inputs()?;
let config = app.config(&inputs)?; let config = app.config(&inputs)?;
if app.matches.is_present("list-languages") { if app.matches.get_flag("list-languages") {
let languages: String = get_languages(&config)?; let languages: String = get_languages(&config)?;
let inputs: Vec<Input> = vec![Input::from_reader(Box::new(languages.as_bytes()))]; let inputs: Vec<Input> = vec![Input::from_reader(Box::new(languages.as_bytes()))];
let plain_config = Config { let plain_config = Config {
@@ -320,22 +327,22 @@ fn run() -> Result<bool> {
..Default::default() ..Default::default()
}; };
run_controller(inputs, &plain_config) run_controller(inputs, &plain_config)
} else if app.matches.is_present("list-themes") { } else if app.matches.get_flag("list-themes") {
list_themes(&config)?; list_themes(&config)?;
Ok(true) Ok(true)
} else if app.matches.is_present("config-file") { } else if app.matches.get_flag("config-file") {
println!("{}", config_file().to_string_lossy()); println!("{}", config_file().to_string_lossy());
Ok(true) Ok(true)
} else if app.matches.is_present("generate-config-file") { } else if app.matches.get_flag("generate-config-file") {
generate_config_file()?; generate_config_file()?;
Ok(true) Ok(true)
} else if app.matches.is_present("config-dir") { } else if app.matches.get_flag("config-dir") {
writeln!(io::stdout(), "{}", config_dir())?; writeln!(io::stdout(), "{}", config_dir())?;
Ok(true) Ok(true)
} else if app.matches.is_present("cache-dir") { } else if app.matches.get_flag("cache-dir") {
writeln!(io::stdout(), "{}", cache_dir())?; writeln!(io::stdout(), "{}", cache_dir())?;
Ok(true) Ok(true)
} else if app.matches.is_present("acknowledgements") { } else if app.matches.get_flag("acknowledgements") {
writeln!(io::stdout(), "{}", bat::assets::get_acknowledgements())?; writeln!(io::stdout(), "{}", bat::assets::get_acknowledgements())?;
Ok(true) Ok(true)
} else { } else {
+1 -1
View File
@@ -3,7 +3,7 @@
use std::ffi::OsStr; use std::ffi::OsStr;
use std::process::Command; use std::process::Command;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Eq)]
pub enum LessVersion { pub enum LessVersion {
Less(usize), Less(usize),
BusyBox, BusyBox,
+1 -2
View File
@@ -46,10 +46,9 @@ pub(crate) mod printer;
pub mod style; pub mod style;
pub(crate) mod syntax_mapping; pub(crate) mod syntax_mapping;
mod terminal; mod terminal;
mod vscreen;
pub(crate) mod wrapping; pub(crate) mod wrapping;
pub use pretty_printer::{Input, PrettyPrinter}; pub use pretty_printer::{Input, PrettyPrinter, Syntax};
pub use syntax_mapping::{MappingTarget, SyntaxMapping}; pub use syntax_mapping::{MappingTarget, SyntaxMapping};
pub use wrapping::WrappingMode; pub use wrapping::WrappingMode;
+1 -1
View File
@@ -168,7 +168,7 @@ fn test_parse_minus_fail() {
assert!(range.is_err()); assert!(range.is_err());
} }
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum RangeCheckResult { pub enum RangeCheckResult {
// Within one of the given ranges // Within one of the given ranges
InRange, InRange,
+14 -6
View File
@@ -40,15 +40,23 @@ impl PagerKind {
fn from_bin(bin: &str) -> PagerKind { fn from_bin(bin: &str) -> PagerKind {
use std::path::Path; use std::path::Path;
match Path::new(bin) // Set to `less` by default on most Linux distros.
.file_stem() let pager_bin = Path::new(bin).file_stem();
.map(|s| s.to_string_lossy())
.as_deref() // The name of the current running binary. Normally `bat` but sometimes
{ // `batcat` for compatibility reasons.
Some("bat") => PagerKind::Bat, let current_bin = env::args_os().next();
// Check if the current running binary is set to be our pager.
let is_current_bin_pager = current_bin
.map(|s| Path::new(&s).file_stem() == pager_bin)
.unwrap_or(false);
match pager_bin.map(|s| s.to_string_lossy()).as_deref() {
Some("less") => PagerKind::Less, Some("less") => PagerKind::Less,
Some("more") => PagerKind::More, Some("more") => PagerKind::More,
Some("most") => PagerKind::Most, Some("most") => PagerKind::Most,
_ if is_current_bin_pager => PagerKind::Bat,
_ => PagerKind::Unknown, _ => PagerKind::Unknown,
} }
} }
+1 -1
View File
@@ -1,4 +1,4 @@
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PagingMode { pub enum PagingMode {
Always, Always,
QuitIfOneScreen, QuitIfOneScreen,
+20 -27
View File
@@ -1,35 +1,28 @@
use console::AnsiCodeIterator; use std::fmt::Write;
/// Expand tabs like an ANSI-enabled expand(1). /// Expand tabs like an ANSI-enabled expand(1).
pub fn expand_tabs(line: &str, width: usize, cursor: &mut usize) -> String { pub fn expand_tabs(mut text: &str, width: usize, cursor: &mut usize) -> String {
let mut buffer = String::with_capacity(line.len() * 2); let mut buffer = String::with_capacity(text.len() * 2);
for chunk in AnsiCodeIterator::new(line) { while let Some(index) = text.find('\t') {
match chunk { // Add previous text.
(text, true) => buffer.push_str(text), if index > 0 {
(mut text, false) => { *cursor += index;
while let Some(index) = text.find('\t') { buffer.push_str(&text[0..index]);
// Add previous text.
if index > 0 {
*cursor += index;
buffer.push_str(&text[0..index]);
}
// Add tab.
let spaces = width - (*cursor % width);
*cursor += spaces;
buffer.push_str(&*" ".repeat(spaces));
// Next.
text = &text[index + 1..text.len()];
}
*cursor += text.len();
buffer.push_str(text);
}
} }
// Add tab.
let spaces = width - (*cursor % width);
*cursor += spaces;
buffer.push_str(&*" ".repeat(spaces));
// Next.
text = &text[index + 1..text.len()];
} }
*cursor += text.len();
buffer.push_str(text);
buffer buffer
} }
@@ -101,7 +94,7 @@ pub fn replace_nonprintable(input: &[u8], tab_width: usize) -> String {
c => output.push_str(&c.escape_unicode().collect::<String>()), c => output.push_str(&c.escape_unicode().collect::<String>()),
} }
} else { } else {
output.push_str(&format!("\\x{:02X}", input[idx])); write!(output, "\\x{:02X}", input[idx]).ok();
idx += 1; idx += 1;
} }
} }
+18 -5
View File
@@ -2,7 +2,6 @@ use std::io::Read;
use std::path::Path; use std::path::Path;
use console::Term; use console::Term;
use syntect::parsing::SyntaxReference;
use crate::{ use crate::{
assets::HighlightingAssets, assets::HighlightingAssets,
@@ -28,6 +27,12 @@ struct ActiveStyleComponents {
snip: bool, snip: bool,
} }
#[non_exhaustive]
pub struct Syntax {
pub name: String,
pub file_extensions: Vec<String>,
}
pub struct PrettyPrinter<'a> { pub struct PrettyPrinter<'a> {
inputs: Vec<Input<'a>>, inputs: Vec<Input<'a>>,
config: Config<'a>, config: Config<'a>,
@@ -240,18 +245,26 @@ impl<'a> PrettyPrinter<'a> {
self.assets.themes() self.assets.themes()
} }
pub fn syntaxes(&self) -> impl Iterator<Item = &SyntaxReference> { pub fn syntaxes(&self) -> impl Iterator<Item = Syntax> + '_ {
// We always use assets from the binary, which are guaranteed to always // We always use assets from the binary, which are guaranteed to always
// be valid, so get_syntaxes() can never fail here // be valid, so get_syntaxes() can never fail here
self.assets.get_syntaxes().unwrap().iter() self.assets
.get_syntaxes()
.unwrap()
.iter()
.filter(|s| !s.hidden)
.map(|s| Syntax {
name: s.name.clone(),
file_extensions: s.file_extensions.clone(),
})
} }
/// Pretty-print all specified inputs. This method will "use" all stored inputs. /// Pretty-print all specified inputs. This method will "use" all stored inputs.
/// If you want to call 'print' multiple times, you have to call the appropriate /// If you want to call 'print' multiple times, you have to call the appropriate
/// input_* methods again. /// input_* methods again.
pub fn print(&mut self) -> Result<bool> { pub fn print(&mut self) -> Result<bool> {
self.config.highlighted_lines = let highlight_lines = std::mem::take(&mut self.highlighted_lines);
HighlightedLineRanges(LineRanges::from(self.highlighted_lines.clone())); self.config.highlighted_lines = HighlightedLineRanges(LineRanges::from(highlight_lines));
self.config.term_width = self self.config.term_width = self
.term_width .term_width
.unwrap_or_else(|| Term::stdout().size().1 as usize); .unwrap_or_else(|| Term::stdout().size().1 as usize);
+105 -132
View File
@@ -6,8 +6,6 @@ use ansi_term::Style;
use bytesize::ByteSize; use bytesize::ByteSize;
use console::AnsiCodeIterator;
use syntect::easy::HighlightLines; use syntect::easy::HighlightLines;
use syntect::highlighting::Color; use syntect::highlighting::Color;
use syntect::highlighting::Theme; use syntect::highlighting::Theme;
@@ -33,7 +31,6 @@ use crate::line_range::RangeCheckResult;
use crate::preprocessor::{expand_tabs, replace_nonprintable}; use crate::preprocessor::{expand_tabs, replace_nonprintable};
use crate::style::StyleComponent; use crate::style::StyleComponent;
use crate::terminal::{as_terminal_escaped, to_ansi_color}; use crate::terminal::{as_terminal_escaped, to_ansi_color};
use crate::vscreen::AnsiStyle;
use crate::wrapping::WrappingMode; use crate::wrapping::WrappingMode;
pub(crate) trait Printer { pub(crate) trait Printer {
@@ -122,7 +119,6 @@ pub(crate) struct InteractivePrinter<'a> {
config: &'a Config<'a>, config: &'a Config<'a>,
decorations: Vec<Box<dyn Decoration>>, decorations: Vec<Box<dyn Decoration>>,
panel_width: usize, panel_width: usize,
ansi_style: AnsiStyle,
content_type: Option<ContentType>, content_type: Option<ContentType>,
#[cfg(feature = "git")] #[cfg(feature = "git")]
pub line_changes: &'a Option<LineChanges>, pub line_changes: &'a Option<LineChanges>,
@@ -206,7 +202,6 @@ impl<'a> InteractivePrinter<'a> {
config, config,
decorations, decorations,
content_type: input.reader.content_type, content_type: input.reader.content_type,
ansi_style: AnsiStyle::new(),
#[cfg(feature = "git")] #[cfg(feature = "git")]
line_changes, line_changes,
highlighter_from_set, highlighter_from_set,
@@ -424,7 +419,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
let line = if self.config.show_nonprintable { let line = if self.config.show_nonprintable {
replace_nonprintable(line_buffer, self.config.tab_width) replace_nonprintable(line_buffer, self.config.tab_width)
} else { } else {
match self.content_type { let line = match self.content_type {
Some(ContentType::BINARY) | None => { Some(ContentType::BINARY) | None => {
return Ok(()); return Ok(());
} }
@@ -435,6 +430,15 @@ impl<'a> Printer for InteractivePrinter<'a> {
.decode(line_buffer, DecoderTrap::Replace) .decode(line_buffer, DecoderTrap::Replace)
.map_err(|_| "Invalid UTF-16BE")?, .map_err(|_| "Invalid UTF-16BE")?,
_ => String::from_utf8_lossy(line_buffer).to_string(), _ => String::from_utf8_lossy(line_buffer).to_string(),
};
// Remove byte order mark from the first line if it exists
if line_number == 1 {
match line.strip_prefix('\u{feff}') {
Some(stripped) => stripped.to_string(),
None => line,
}
} else {
line
} }
}; };
@@ -476,7 +480,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
self.config.highlighted_lines.0.check(line_number) == RangeCheckResult::InRange; self.config.highlighted_lines.0.check(line_number) == RangeCheckResult::InRange;
if highlight_this_line && self.config.theme == "ansi" { if highlight_this_line && self.config.theme == "ansi" {
self.ansi_style.update("^[4m"); write!(handle, "\x1B[4m")?;
} }
let background_color = self let background_color = self
@@ -503,51 +507,37 @@ impl<'a> Printer for InteractivePrinter<'a> {
let italics = self.config.use_italic_text; let italics = self.config.use_italic_text;
for &(style, region) in &regions { for &(style, region) in &regions {
let ansi_iterator = AnsiCodeIterator::new(region); let text = &*self.preprocess(region, &mut cursor_total);
for chunk in ansi_iterator { let text_trimmed = text.trim_end_matches(|c| c == '\r' || c == '\n');
match chunk {
// ANSI escape passthrough.
(ansi, true) => {
self.ansi_style.update(ansi);
write!(handle, "{}", ansi)?;
}
// Regular text. write!(
(text, false) => { handle,
let text = &*self.preprocess(text, &mut cursor_total); "{}",
let text_trimmed = text.trim_end_matches(|c| c == '\r' || c == '\n'); as_terminal_escaped(
style,
text_trimmed,
true_color,
colored_output,
italics,
background_color
)
)?;
write!( if text.len() != text_trimmed.len() {
handle, if let Some(background_color) = background_color {
"{}", let ansi_style = Style {
as_terminal_escaped( background: to_ansi_color(background_color, true_color),
style, ..Default::default()
&format!("{}{}", self.ansi_style, text_trimmed), };
true_color,
colored_output,
italics,
background_color
)
)?;
if text.len() != text_trimmed.len() { let width = if cursor_total <= cursor_max {
if let Some(background_color) = background_color { cursor_max - cursor_total + 1
let ansi_style = Style { } else {
background: to_ansi_color(background_color, true_color), 0
..Default::default() };
}; write!(handle, "{}", ansi_style.paint(" ".repeat(width)))?;
let width = if cursor_total <= cursor_max {
cursor_max - cursor_total + 1
} else {
0
};
write!(handle, "{}", ansi_style.paint(" ".repeat(width)))?;
}
write!(handle, "{}", &text[text_trimmed.len()..])?;
}
}
} }
write!(handle, "{}", &text[text_trimmed.len()..])?;
} }
} }
@@ -556,98 +546,82 @@ impl<'a> Printer for InteractivePrinter<'a> {
} }
} else { } else {
for &(style, region) in &regions { for &(style, region) in &regions {
let ansi_iterator = AnsiCodeIterator::new(region); let text = self.preprocess(
for chunk in ansi_iterator { region.trim_end_matches(|c| c == '\r' || c == '\n'),
match chunk { &mut cursor_total,
// ANSI escape passthrough. );
(ansi, true) => {
self.ansi_style.update(ansi);
write!(handle, "{}", ansi)?;
}
// Regular text. let mut max_width = cursor_max - cursor;
(text, false) => {
let text = self.preprocess(
text.trim_end_matches(|c| c == '\r' || c == '\n'),
&mut cursor_total,
);
let mut max_width = cursor_max - cursor; // line buffer (avoid calling write! for every character)
let mut line_buf = String::with_capacity(max_width * 4);
// line buffer (avoid calling write! for every character) // Displayed width of line_buf
let mut line_buf = String::with_capacity(max_width * 4); let mut current_width = 0;
// Displayed width of line_buf for c in text.chars() {
let mut current_width = 0; // calculate the displayed width for next character
let cw = c.width().unwrap_or(0);
current_width += cw;
for c in text.chars() { // if next character cannot be printed on this line,
// calculate the displayed width for next character // flush the buffer.
let cw = c.width().unwrap_or(0); if current_width > max_width {
current_width += cw; // Generate wrap padding if not already generated.
if panel_wrap.is_none() {
// if next character cannot be printed on this line, panel_wrap = if self.panel_width > 0 {
// flush the buffer. Some(format!(
if current_width > max_width { "{} ",
// Generate wrap padding if not already generated. self.decorations
if panel_wrap.is_none() { .iter()
panel_wrap = if self.panel_width > 0 { .map(|d| d.generate(line_number, true, self).text)
Some(format!( .collect::<Vec<String>>()
"{} ", .join(" ")
self.decorations ))
.iter() } else {
.map(|d| d Some("".to_string())
.generate(line_number, true, self)
.text)
.collect::<Vec<String>>()
.join(" ")
))
} else {
Some("".to_string())
}
}
// It wraps.
write!(
handle,
"{}\n{}",
as_terminal_escaped(
style,
&*format!("{}{}", self.ansi_style, line_buf),
self.config.true_color,
self.config.colored_output,
self.config.use_italic_text,
background_color
),
panel_wrap.clone().unwrap()
)?;
cursor = 0;
max_width = cursor_max;
line_buf.clear();
current_width = cw;
}
line_buf.push(c);
} }
// flush the buffer
cursor += current_width;
write!(
handle,
"{}",
as_terminal_escaped(
style,
&*format!("{}{}", self.ansi_style, line_buf),
self.config.true_color,
self.config.colored_output,
self.config.use_italic_text,
background_color
)
)?;
} }
// It wraps.
write!(
handle,
"{}\n{}",
as_terminal_escaped(
style,
&line_buf,
self.config.true_color,
self.config.colored_output,
self.config.use_italic_text,
background_color
),
panel_wrap.clone().unwrap()
)?;
cursor = 0;
max_width = cursor_max;
line_buf.clear();
current_width = cw;
} }
line_buf.push(c);
} }
// flush the buffer
cursor += current_width;
write!(
handle,
"{}",
as_terminal_escaped(
style,
&line_buf,
self.config.true_color,
self.config.colored_output,
self.config.use_italic_text,
background_color
)
)?;
} }
if let Some(background_color) = background_color { if let Some(background_color) = background_color {
@@ -666,7 +640,6 @@ impl<'a> Printer for InteractivePrinter<'a> {
} }
if highlight_this_line && self.config.theme == "ansi" { if highlight_this_line && self.config.theme == "ansi" {
self.ansi_style.update("^[24m");
write!(handle, "\x1B[24m")?; write!(handle, "\x1B[24m")?;
} }
+17 -2
View File
@@ -7,7 +7,7 @@ use globset::{Candidate, GlobBuilder, GlobMatcher};
pub mod ignored_suffixes; pub mod ignored_suffixes;
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive] #[non_exhaustive]
pub enum MappingTarget<'a> { pub enum MappingTarget<'a> {
/// For mapping a path to a specific syntax. /// For mapping a path to a specific syntax.
@@ -66,6 +66,14 @@ impl<'a> SyntaxMapping<'a> {
mapping mapping
.insert("*.pac", MappingTarget::MapTo("JavaScript (Babel)")) .insert("*.pac", MappingTarget::MapTo("JavaScript (Babel)"))
.unwrap(); .unwrap();
mapping
.insert("fish_history", MappingTarget::MapTo("YAML"))
.unwrap();
// See #2151, https://nmap.org/book/nse-language.html
mapping
.insert("*.nse", MappingTarget::MapTo("Lua"))
.unwrap();
// See #1008 // See #1008
mapping mapping
@@ -186,6 +194,7 @@ impl<'a> SyntaxMapping<'a> {
} }
pub(crate) fn get_syntax_for(&self, path: impl AsRef<Path>) -> Option<MappingTarget<'a>> { pub(crate) fn get_syntax_for(&self, path: impl AsRef<Path>) -> Option<MappingTarget<'a>> {
// Try matching on the file name as-is.
let candidate = Candidate::new(&path); let candidate = Candidate::new(&path);
let candidate_filename = path.as_ref().file_name().map(Candidate::new); let candidate_filename = path.as_ref().file_name().map(Candidate::new);
for (ref glob, ref syntax) in self.mappings.iter().rev() { for (ref glob, ref syntax) in self.mappings.iter().rev() {
@@ -197,7 +206,13 @@ impl<'a> SyntaxMapping<'a> {
return Some(*syntax); return Some(*syntax);
} }
} }
None // Try matching on the file name after removing an ignored suffix.
let file_name = path.as_ref().file_name()?;
self.ignored_suffixes
.try_with_stripped_suffix(file_name, |stripped_file_name| {
Ok(self.get_syntax_for(stripped_file_name))
})
.ok()?
} }
pub fn insert_ignored_suffix(&mut self, suffix: &'a str) { pub fn insert_ignored_suffix(&mut self, suffix: &'a str) {
-212
View File
@@ -1,212 +0,0 @@
use std::fmt::{Display, Formatter};
// Wrapper to avoid unnecessary branching when input doesn't have ANSI escape sequences.
pub struct AnsiStyle {
attributes: Option<Attributes>,
}
impl AnsiStyle {
pub fn new() -> Self {
AnsiStyle { attributes: None }
}
pub fn update(&mut self, sequence: &str) -> bool {
match &mut self.attributes {
Some(a) => a.update(sequence),
None => {
self.attributes = Some(Attributes::new());
self.attributes.as_mut().unwrap().update(sequence)
}
}
}
}
impl Display for AnsiStyle {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self.attributes {
Some(ref a) => a.fmt(f),
None => Ok(()),
}
}
}
struct Attributes {
foreground: String,
background: String,
underlined: String,
/// The character set to use.
/// REGEX: `\^[()][AB0-3]`
charset: String,
/// A buffer for unknown sequences.
unknown_buffer: String,
/// ON: ^[1m
/// OFF: ^[22m
bold: String,
/// ON: ^[2m
/// OFF: ^[22m
dim: String,
/// ON: ^[4m
/// OFF: ^[24m
underline: String,
/// ON: ^[3m
/// OFF: ^[23m
italic: String,
/// ON: ^[9m
/// OFF: ^[29m
strike: String,
}
impl Attributes {
pub fn new() -> Self {
Attributes {
foreground: "".to_owned(),
background: "".to_owned(),
underlined: "".to_owned(),
charset: "".to_owned(),
unknown_buffer: "".to_owned(),
bold: "".to_owned(),
dim: "".to_owned(),
underline: "".to_owned(),
italic: "".to_owned(),
strike: "".to_owned(),
}
}
/// Update the attributes with an escape sequence.
/// Returns `false` if the sequence is unsupported.
pub fn update(&mut self, sequence: &str) -> bool {
let mut chars = sequence.char_indices().skip(1);
if let Some((_, t)) = chars.next() {
match t {
'(' => self.update_with_charset('(', chars.map(|(_, c)| c)),
')' => self.update_with_charset(')', chars.map(|(_, c)| c)),
'[' => {
if let Some((i, last)) = chars.last() {
// SAFETY: Always starts with ^[ and ends with m.
self.update_with_csi(last, &sequence[2..i])
} else {
false
}
}
_ => self.update_with_unsupported(sequence),
}
} else {
false
}
}
fn sgr_reset(&mut self) {
self.foreground.clear();
self.background.clear();
self.underlined.clear();
self.bold.clear();
self.dim.clear();
self.underline.clear();
self.italic.clear();
self.strike.clear();
}
fn update_with_sgr(&mut self, parameters: &str) -> bool {
let mut iter = parameters
.split(';')
.map(|p| if p.is_empty() { "0" } else { p })
.map(|p| p.parse::<u16>())
.map(|p| p.unwrap_or(0)); // Treat errors as 0.
while let Some(p) = iter.next() {
match p {
0 => self.sgr_reset(),
1 => self.bold = format!("\x1B[{}m", parameters),
2 => self.dim = format!("\x1B[{}m", parameters),
3 => self.italic = format!("\x1B[{}m", parameters),
4 => self.underline = format!("\x1B[{}m", parameters),
23 => self.italic.clear(),
24 => self.underline.clear(),
22 => {
self.bold.clear();
self.dim.clear();
}
30..=39 => self.foreground = Self::parse_color(p, &mut iter),
40..=49 => self.background = Self::parse_color(p, &mut iter),
58..=59 => self.underlined = Self::parse_color(p, &mut iter),
90..=97 => self.foreground = Self::parse_color(p, &mut iter),
100..=107 => self.foreground = Self::parse_color(p, &mut iter),
_ => {
// Unsupported SGR sequence.
// Be compatible and pretend one just wasn't was provided.
}
}
}
true
}
fn update_with_csi(&mut self, finalizer: char, sequence: &str) -> bool {
if finalizer == 'm' {
self.update_with_sgr(sequence)
} else {
false
}
}
fn update_with_unsupported(&mut self, sequence: &str) -> bool {
self.unknown_buffer.push_str(sequence);
false
}
fn update_with_charset(&mut self, kind: char, set: impl Iterator<Item = char>) -> bool {
self.charset = format!("\x1B{}{}", kind, set.take(1).collect::<String>());
true
}
fn parse_color(color: u16, parameters: &mut dyn Iterator<Item = u16>) -> String {
match color % 10 {
8 => match parameters.next() {
Some(5) /* 256-color */ => format!("\x1B[{};5;{}m", color, join(";", 1, parameters)),
Some(2) /* 24-bit color */ => format!("\x1B[{};2;{}m", color, join(";", 3, parameters)),
Some(c) => format!("\x1B[{};{}m", color, c),
_ => "".to_owned(),
},
9 => "".to_owned(),
_ => format!("\x1B[{}m", color),
}
}
}
impl Display for Attributes {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}{}{}{}{}{}{}{}{}",
self.foreground,
self.background,
self.underlined,
self.charset,
self.bold,
self.dim,
self.underline,
self.italic,
self.strike,
)
}
}
fn join(
delimiter: &str,
limit: usize,
iterator: &mut dyn Iterator<Item = impl ToString>,
) -> String {
iterator
.take(limit)
.map(|i| i.to_string())
.collect::<Vec<String>>()
.join(delimiter)
}
+1 -1
View File
@@ -1,5 +1,5 @@
# Make sure that the pager gets executed # Make sure that the pager gets executed
--paging=always --paging=always
# Output a dummy message for the integration test. # Output a dummy message for the integration test and system wide config test.
--pager="echo dummy-pager-from-config" --pager="echo dummy-pager-from-config"
+5
View File
@@ -0,0 +1,5 @@
# Make sure that the pager gets executed
--paging=always
# Output a dummy message for the integration test.
--pager="echo dummy-pager-from-system-config"
+1
View File
@@ -0,0 +1 @@
{"test": "value"}
+1
View File
@@ -0,0 +1 @@
{"test": "value"}
+1
View File
@@ -0,0 +1 @@
hello world
+117 -54
View File
@@ -1,9 +1,7 @@
use assert_cmd::cargo::CommandCargoExt;
use predicates::boolean::PredicateBooleanExt; use predicates::boolean::PredicateBooleanExt;
use predicates::{prelude::predicate, str::PredicateStrExt}; use predicates::{prelude::predicate, str::PredicateStrExt};
use serial_test::serial; use serial_test::serial;
use std::path::Path; use std::path::Path;
use std::process::Command;
use std::str::from_utf8; use std::str::from_utf8;
use tempfile::tempdir; use tempfile::tempdir;
@@ -28,41 +26,14 @@ mod unix {
use unix::*; use unix::*;
mod utils; mod utils;
use utils::command::{bat, bat_with_config};
#[cfg(unix)]
use utils::command::bat_raw_command;
use utils::mocked_pagers; use utils::mocked_pagers;
const EXAMPLES_DIR: &str = "tests/examples"; const EXAMPLES_DIR: &str = "tests/examples";
fn bat_raw_command_with_config() -> Command {
let mut cmd = Command::cargo_bin("bat").unwrap();
cmd.current_dir("tests/examples");
cmd.env_remove("BAT_CACHE_PATH");
cmd.env_remove("BAT_CONFIG_DIR");
cmd.env_remove("BAT_CONFIG_PATH");
cmd.env_remove("BAT_OPTS");
cmd.env_remove("BAT_PAGER");
cmd.env_remove("BAT_STYLE");
cmd.env_remove("BAT_TABS");
cmd.env_remove("BAT_THEME");
cmd.env_remove("COLORTERM");
cmd.env_remove("NO_COLOR");
cmd.env_remove("PAGER");
cmd
}
fn bat_raw_command() -> Command {
let mut cmd = bat_raw_command_with_config();
cmd.arg("--no-config");
cmd
}
fn bat_with_config() -> assert_cmd::Command {
assert_cmd::Command::from_std(bat_raw_command_with_config())
}
fn bat() -> assert_cmd::Command {
assert_cmd::Command::from_std(bat_raw_command())
}
#[test] #[test]
fn basic() { fn basic() {
bat() bat()
@@ -695,6 +666,18 @@ fn alias_pager_disable_long_overrides_short() {
.stdout(predicate::eq("pager-output\n").normalize()); .stdout(predicate::eq("pager-output\n").normalize());
} }
#[test]
fn disable_pager_if_disable_paging_flag_comes_after_paging() {
bat()
.env("PAGER", "echo pager-output")
.arg("--paging=always")
.arg("-P")
.arg("test.txt")
.assert()
.success()
.stdout(predicate::eq("hello world\n").normalize());
}
#[test] #[test]
fn pager_failed_to_parse() { fn pager_failed_to_parse() {
bat() bat()
@@ -775,14 +758,66 @@ fn config_read_arguments_from_file() {
#[test] #[test]
fn utf16() { fn utf16() {
// The output will be converted to UTF-8 with a leading UTF-8 BOM // The output will be converted to UTF-8 with the leading UTF-16
// BOM removed. This behavior is wanted in interactive mode as
// some terminals seem to display the BOM character as a space,
// and it also breaks syntax highlighting.
bat() bat()
.arg("--plain") .arg("--plain")
.arg("--decorations=always") .arg("--decorations=always")
.arg("test_UTF-16LE.txt") .arg("test_UTF-16LE.txt")
.assert() .assert()
.success() .success()
.stdout(std::str::from_utf8(b"\xEF\xBB\xBFhello world\n").unwrap()); .stdout("hello world\n");
}
// Regression test for https://github.com/sharkdp/bat/issues/1922
#[test]
fn bom_not_stripped_in_loop_through_mode() {
bat()
.arg("--plain")
.arg("--decorations=never")
.arg("--color=never")
.arg("test_BOM.txt")
.assert()
.success()
.stdout("\u{feff}hello world\n");
}
// Regression test for https://github.com/sharkdp/bat/issues/1922
#[test]
fn bom_stripped_when_colored_output() {
bat()
.arg("--color=always")
.arg("--decorations=never")
.arg("test_BOM.txt")
.assert()
.success()
.stdout(
predicate::str::is_match("\u{1b}\\[38;5;[0-9]{3}mhello world\u{1b}\\[0m\n").unwrap(),
);
}
// Regression test for https://github.com/sharkdp/bat/issues/1922
#[test]
fn bom_stripped_when_no_color_and_not_loop_through() {
bat()
.arg("--color=never")
.arg("--decorations=always")
.arg("--style=numbers,grid,header")
.arg("--terminal-width=80")
.arg("test_BOM.txt")
.assert()
.success()
.stdout(
"\
File: test_BOM.txt
1 hello world
",
);
} }
#[test] #[test]
@@ -975,6 +1010,7 @@ fn header_full_binary() {
} }
#[test] #[test]
#[cfg(feature = "git")] // Expected output assumes git is enabled
fn header_default() { fn header_default() {
bat() bat()
.arg("--paging=never") .arg("--paging=never")
@@ -999,6 +1035,7 @@ fn header_default() {
} }
#[test] #[test]
#[cfg(feature = "git")] // Expected output assumes git is enabled
fn header_default_is_default() { fn header_default_is_default() {
bat() bat()
.arg("--paging=never") .arg("--paging=never")
@@ -1361,6 +1398,7 @@ fn plain_mode_does_not_add_nonexisting_newline() {
// Regression test for https://github.com/sharkdp/bat/issues/299 // Regression test for https://github.com/sharkdp/bat/issues/299
#[test] #[test]
#[cfg(feature = "git")] // Expected output assumes git is enabled
fn grid_for_file_without_newline() { fn grid_for_file_without_newline() {
bat() bat()
.arg("--paging=never") .arg("--paging=never")
@@ -1404,29 +1442,12 @@ fn ansi_highlight_underline() {
.stderr(""); .stderr("");
} }
// Ensure that ANSI passthrough is emitted properly for both wrapping and non-wrapping printer.
#[test]
fn ansi_passthrough_emit() {
for wrapping in &["never", "character"] {
bat()
.arg("--paging=never")
.arg("--color=never")
.arg("--terminal-width=80")
.arg(format!("--wrap={}", wrapping))
.arg("--decorations=always")
.arg("--style=plain")
.write_stdin("\x1B[33mColor\nColor \x1B[m\nPlain\n")
.assert()
.success()
.stdout("\x1B[33m\x1B[33mColor\n\x1B[33mColor \x1B[m\nPlain\n")
.stderr("");
}
}
#[test] #[test]
fn ignored_suffix_arg() { fn ignored_suffix_arg() {
bat() bat()
.arg("-f") .arg("-f")
.arg("--theme")
.arg("Monokai Extended")
.arg("-p") .arg("-p")
.arg("test.json~") .arg("test.json~")
.assert() .assert()
@@ -1436,6 +1457,8 @@ fn ignored_suffix_arg() {
bat() bat()
.arg("-f") .arg("-f")
.arg("--theme")
.arg("Monokai Extended")
.arg("-p") .arg("-p")
.arg("--ignored-suffix=.suffix") .arg("--ignored-suffix=.suffix")
.arg("test.json.suffix") .arg("test.json.suffix")
@@ -1446,6 +1469,8 @@ fn ignored_suffix_arg() {
bat() bat()
.arg("-f") .arg("-f")
.arg("--theme")
.arg("Monokai Extended")
.arg("-p") .arg("-p")
.arg("test.json.suffix") .arg("test.json.suffix")
.assert() .assert()
@@ -1463,6 +1488,8 @@ fn highlighting_is_skipped_on_long_lines() {
bat() bat()
.arg("-f") .arg("-f")
.arg("--theme")
.arg("Monokai Extended")
.arg("-p") .arg("-p")
.arg("longline.json") .arg("longline.json")
.assert() .assert()
@@ -1482,6 +1509,8 @@ fn all_global_git_config_locations_syntax_mapping_work() {
bat() bat()
.env("XDG_CONFIG_HOME", fake_home.join(".config").as_os_str()) .env("XDG_CONFIG_HOME", fake_home.join(".config").as_os_str())
.arg("-f") .arg("-f")
.arg("--theme")
.arg("Monokai Extended")
.arg("-p") .arg("-p")
.arg("git/.config/git/config") .arg("git/.config/git/config")
.assert() .assert()
@@ -1492,6 +1521,8 @@ fn all_global_git_config_locations_syntax_mapping_work() {
bat() bat()
.env("HOME", fake_home.as_os_str()) .env("HOME", fake_home.as_os_str())
.arg("-f") .arg("-f")
.arg("--theme")
.arg("Monokai Extended")
.arg("-p") .arg("-p")
.arg("git/.config/git/config") .arg("git/.config/git/config")
.assert() .assert()
@@ -1502,6 +1533,8 @@ fn all_global_git_config_locations_syntax_mapping_work() {
bat() bat()
.env("HOME", fake_home.as_os_str()) .env("HOME", fake_home.as_os_str())
.arg("-f") .arg("-f")
.arg("--theme")
.arg("Monokai Extended")
.arg("-p") .arg("-p")
.arg("git/.gitconfig") .arg("git/.gitconfig")
.assert() .assert()
@@ -1510,6 +1543,36 @@ fn all_global_git_config_locations_syntax_mapping_work() {
.stderr(""); .stderr("");
} }
#[test]
fn map_syntax_and_ignored_suffix_work_together() {
bat()
.arg("-f")
.arg("--theme")
.arg("Monokai Extended")
.arg("-p")
.arg("--ignored-suffix=.suffix")
.arg("--map-syntax=*.demo:JSON")
.arg("test.demo.suffix")
.assert()
.success()
.stdout("\u{1b}[38;5;231m{\u{1b}[0m\u{1b}[38;5;208m\"\u{1b}[0m\u{1b}[38;5;208mtest\u{1b}[0m\u{1b}[38;5;208m\"\u{1b}[0m\u{1b}[38;5;231m:\u{1b}[0m\u{1b}[38;5;231m \u{1b}[0m\u{1b}[38;5;186m\"\u{1b}[0m\u{1b}[38;5;186mvalue\u{1b}[0m\u{1b}[38;5;186m\"\u{1b}[0m\u{1b}[38;5;231m}\u{1b}[0m")
.stderr("");
bat()
.arg("-f")
.arg("--theme")
.arg("Monokai Extended")
.arg("-p")
.arg("--ignored-suffix=.suffix")
.arg("--ignored-suffix=.foo")
.arg("--map-syntax=*.demo:JSON")
.arg("test.demo.foo.suffix")
.assert()
.success()
.stdout("\u{1b}[38;5;231m{\u{1b}[0m\u{1b}[38;5;208m\"\u{1b}[0m\u{1b}[38;5;208mtest\u{1b}[0m\u{1b}[38;5;208m\"\u{1b}[0m\u{1b}[38;5;231m:\u{1b}[0m\u{1b}[38;5;231m \u{1b}[0m\u{1b}[38;5;186m\"\u{1b}[0m\u{1b}[38;5;186mvalue\u{1b}[0m\u{1b}[38;5;186m\"\u{1b}[0m\u{1b}[38;5;231m}\u{1b}[0m")
.stderr("");
}
#[test] #[test]
fn acknowledgements() { fn acknowledgements() {
bat() bat()
+1 -1
View File
@@ -18,7 +18,7 @@ gpl_occurances=$(git grep --recurse-submodules "${gpl_term}" -- "${gpl_excludes[
if [ -z "${gpl_occurances}" ]; then if [ -z "${gpl_occurances}" ]; then
echo "PASS: No files under GPL were found" echo "PASS: No files under GPL were found"
else else
echo "FAIL: GPL:ed code is not compatible with bat, but occurances of '${gpl_term}' were found:" echo "FAIL: GPL:ed code is not compatible with bat, but occurrences of '${gpl_term}' were found:"
echo "${gpl_occurances}" echo "${gpl_occurances}"
exit 1 exit 1
fi fi
+3 -3
View File
@@ -1,13 +1,13 @@
#[cfg(feature = "git")]
mod tester; mod tester;
use crate::tester::BatTester;
macro_rules! snapshot_tests { macro_rules! snapshot_tests {
($($test_name: ident: $style: expr,)*) => { ($($test_name: ident: $style: expr,)*) => {
$( $(
#[test] #[test]
#[cfg(feature = "git")]
fn $test_name() { fn $test_name() {
let bat_tester = BatTester::default(); let bat_tester = tester::BatTester::default();
bat_tester.test_snapshot(stringify!($test_name), $style); bat_tester.test_snapshot(stringify!($test_name), $style);
} }
)* )*
+3 -2
View File
@@ -3,5 +3,6 @@
# <file system> <dir> <type> <options> <dump> <pass> # <file system> <dir> <type> <options> <dump> <pass>
UUID=9e6faddf-31ab-3f3e-9b50-2ad4fbc2ea8b / ext4 rw,relatime,data=ordered 0 1 UUID=9e6faddf-31ab-3f3e-9b50-2ad4fbc2ea8b / ext4 rw,relatime,data=ordered 0 0
UUID=62F8-2047 /boot vfat rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro 0 2 UUID=9e6faddf-31ab-3f3e-9b50-2ad4fbc2ea8b / ext4 rw,relatime,data=ordered 1 1
UUID=62F8-2047 /boot vfat rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro 2 2
+34
View File
@@ -0,0 +1,34 @@
--- Finds factorial of a number.
-- @param value Number to find factorial.
-- @return Factorial of number.
local function factorial(value)
 if value <= 1 then
 return 1
 else
 return value * factorial(value - 1)
 end
end
--- Joins a table of strings into a new string.
-- @param table Table of strings.
-- @param separator Separator character.
-- @return Joined string.
local function join(table, separator)
 local data = ""
 
 for index, value in ipairs(table) do
 data = data .. value .. separator
 end
 
 data = data:sub(1, data:len() - 1)
 
 return data
end
local a = factorial(5)
print(a)
local b = join({ "l", "u", "a" }, ",")
print(b)
+1 -1
View File
@@ -1,4 +1,4 @@
# PowerShell script for testing syntax highlighting # PowerShell script for testing syntax highlighting
function Get-FutureTime { function Get-FutureTime {
 param (  param (
+1
View File
@@ -0,0 +1 @@
const dummy: string = "Regression test for https://github.com/sharkdp/bat/pull/2236";
@@ -0,0 +1,11 @@
- cmd: echo "hello world"
 when: 1656950812
- cmd: ls /tmp
 when: 1656950818
 paths:
 - /tmp
- cmd: cp .local/share/fish/fish_history .
 when: 1656950833
 paths:
 - .local/share/fish/fish_history
 - .
+3 -2
View File
@@ -3,5 +3,6 @@
# <file system> <dir> <type> <options> <dump> <pass> # <file system> <dir> <type> <options> <dump> <pass>
UUID=9e6faddf-31ab-3f3e-9b50-2ad4fbc2ea8b / ext4 rw,relatime,data=ordered 0 1 UUID=9e6faddf-31ab-3f3e-9b50-2ad4fbc2ea8b / ext4 rw,relatime,data=ordered 0 0
UUID=62F8-2047 /boot vfat rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro 0 2 UUID=9e6faddf-31ab-3f3e-9b50-2ad4fbc2ea8b / ext4 rw,relatime,data=ordered 1 1
UUID=62F8-2047 /boot vfat rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro 2 2
+34
View File
@@ -0,0 +1,34 @@
--- Finds factorial of a number.
-- @param value Number to find factorial.
-- @return Factorial of number.
local function factorial(value)
if value <= 1 then
return 1
else
return value * factorial(value - 1)
end
end
--- Joins a table of strings into a new string.
-- @param table Table of strings.
-- @param separator Separator character.
-- @return Joined string.
local function join(table, separator)
local data = ""
for index, value in ipairs(table) do
data = data .. value .. separator
end
data = data:sub(1, data:len() - 1)
return data
end
local a = factorial(5)
print(a)
local b = join({ "l", "u", "a" }, ",")
print(b)
+1
View File
@@ -0,0 +1 @@
const dummy: string = "Regression test for https://github.com/sharkdp/bat/pull/2236";
+11
View File
@@ -0,0 +1,11 @@
- cmd: echo "hello world"
when: 1656950812
- cmd: ls /tmp
when: 1656950818
paths:
- /tmp
- cmd: cp .local/share/fish/fish_history .
when: 1656950833
paths:
- .local/share/fish/fish_history
- .
+29
View File
@@ -0,0 +1,29 @@
use predicates::{prelude::predicate, str::PredicateStrExt};
mod utils;
use utils::command::bat_with_config;
// This test is ignored, as it needs a special system wide config put into place.
// In order to run this tests, use `cargo test --test system_wide_config -- --ignored`
#[test]
#[ignore]
fn use_systemwide_config() {
bat_with_config()
.arg("test.txt")
.assert()
.success()
.stdout(predicate::eq("dummy-pager-from-system-config\n").normalize());
}
// This test is ignored, as it needs a special system wide config put into place
// In order to run this tests, use `cargo test --test system_wide_config -- --ignored`
#[test]
#[ignore]
fn config_overrides_system_config() {
bat_with_config()
.env("BAT_CONFIG_PATH", "bat.conf")
.arg("test.txt")
.assert()
.success()
.stdout(predicate::eq("dummy-pager-from-config\n").normalize());
}
+16
View File
@@ -0,0 +1,16 @@
use bat::PrettyPrinter;
#[test]
fn syntaxes() {
let printer = PrettyPrinter::new();
let syntaxes: Vec<String> = printer.syntaxes().map(|s| s.name).collect();
// Just do some sanity checking
assert!(syntaxes.contains(&"Rust".to_string()));
assert!(syntaxes.contains(&"Java".to_string()));
assert!(!syntaxes.contains(&"this-language-does-not-exist".to_string()));
// This language exists but is hidden, so we should not see it; it shall
// have been filtered out before getting to us
assert!(!syntaxes.contains(&"Git Common".to_string()));
}
+38
View File
@@ -0,0 +1,38 @@
#![allow(unused)] // Because indirectly included by e.g.integration_tests.rs, but not everything inside is used
use assert_cmd::cargo::CommandCargoExt;
use std::process::Command;
pub fn bat_raw_command_with_config() -> Command {
let mut cmd = Command::cargo_bin("bat").unwrap();
cmd.current_dir("tests/examples");
cmd.env_remove("BAT_CACHE_PATH");
cmd.env_remove("BAT_CONFIG_DIR");
cmd.env_remove("BAT_CONFIG_PATH");
cmd.env_remove("BAT_OPTS");
cmd.env_remove("BAT_PAGER");
cmd.env_remove("BAT_STYLE");
cmd.env_remove("BAT_TABS");
cmd.env_remove("BAT_THEME");
cmd.env_remove("COLORTERM");
cmd.env_remove("NO_COLOR");
cmd.env_remove("PAGER");
cmd
}
#[cfg(test)]
pub fn bat_raw_command() -> Command {
let mut cmd = bat_raw_command_with_config();
cmd.arg("--no-config");
cmd
}
#[cfg(test)]
pub fn bat_with_config() -> assert_cmd::Command {
assert_cmd::Command::from_std(bat_raw_command_with_config())
}
#[cfg(test)]
pub fn bat() -> assert_cmd::Command {
assert_cmd::Command::from_std(bat_raw_command())
}
+2
View File
@@ -1,3 +1,5 @@
#![allow(unused)] // Because indirectly included by e.g. system_wide_config.rs, but not used
use assert_cmd::Command; use assert_cmd::Command;
use predicates::prelude::predicate; use predicates::prelude::predicate;
use std::env; use std::env;
+1
View File
@@ -1 +1,2 @@
pub mod command;
pub mod mocked_pagers; pub mod mocked_pagers;