diff --git a/.envrc b/.envrc new file mode 100644 index 00000000..3550a30f --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml index 6274941a..f1bc3887 100644 --- a/.github/workflows/CICD.yml +++ b/.github/workflows/CICD.yml @@ -35,7 +35,7 @@ jobs: name: Extract crate metadata runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Extract crate information id: crate_metadata run: | @@ -58,7 +58,7 @@ jobs: - uses: dtolnay/rust-toolchain@stable with: components: rustfmt,clippy - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - run: cargo fmt -- --check - run: cargo clippy --locked --all-targets --all-features -- -D warnings @@ -68,7 +68,7 @@ jobs: needs: crate_metadata steps: - name: Checkout source code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Install rust toolchain (v${{ needs.crate_metadata.outputs.msrv }}) uses: dtolnay/rust-toolchain@master with: @@ -80,7 +80,7 @@ jobs: name: License checks runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: submodules: true # we especially want to perform license checks on submodules - run: tests/scripts/license-checks.sh @@ -90,7 +90,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: submodules: true # we need all syntax and theme submodules - name: Install Rust toolchain @@ -119,7 +119,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Prepare environment variables run: | echo "BAT_SYSTEM_CONFIG_PREFIX=$GITHUB_WORKSPACE/tests/examples/system_config" >> $GITHUB_ENV @@ -135,7 +135,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable - name: Check documentation @@ -150,7 +150,7 @@ jobs: runs-on: ubuntu-latest steps: - run: cargo install cargo-audit --locked - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - run: cargo audit build: @@ -178,7 +178,7 @@ jobs: BUILD_CMD: cargo steps: - name: Checkout source code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Install prerequisites shell: bash diff --git a/.github/workflows/require-changelog-for-PRs.yml b/.github/workflows/require-changelog-for-PRs.yml index a3905df6..3c8cca37 100644 --- a/.github/workflows/require-changelog-for-PRs.yml +++ b/.github/workflows/require-changelog-for-PRs.yml @@ -13,7 +13,7 @@ jobs: PR_NUMBER: ${{ github.event.number }} PR_BASE: ${{ github.base_ref }} steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Fetch PR base run: git fetch --no-tags --prune --depth=1 origin diff --git a/.gitignore b/.gitignore index fbfe6ac6..cd2047c3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,11 @@ +.direnv/ /target/ **/*.rs.bk +# Editors +.idea/ +.vscode/ + # Generated files /assets/completions/_bat.ps1 /assets/completions/bat.bash @@ -8,3 +13,5 @@ /assets/completions/bat.zsh /assets/manual/bat.1 /assets/metadata.yaml + + diff --git a/.gitmodules b/.gitmodules index 6c5ceb2d..ee84fe05 100644 --- a/.gitmodules +++ b/.gitmodules @@ -130,7 +130,7 @@ url = https://github.com/djuretic/SublimeStrace [submodule "assets/syntaxes/Jinja2"] path = assets/syntaxes/02_Extra/Jinja2 - url = https://github.com/Martin819/sublime-jinja2 + url = https://github.com/ltrzesniewski/sublime-jinja2.git [submodule "assets/syntaxes/SLS"] path = assets/syntaxes/02_Extra/SLS url = https://github.com/saltstack/sublime-text @@ -203,9 +203,6 @@ [submodule "assets/syntaxes/02_Extra/SystemVerilog"] path = assets/syntaxes/02_Extra/SystemVerilog url = https://github.com/TheClams/SystemVerilog.git -[submodule "assets/themes/visual-studio-dark-plus"] - path = assets/themes/visual-studio-dark-plus - url = https://github.com/vidann1/visual-studio-dark-plus.git [submodule "assets/syntaxes/02_Extra/SublimeEthereum"] path = assets/syntaxes/02_Extra/SublimeEthereum url = https://github.com/davidhq/SublimeEthereum.git diff --git a/CHANGELOG.md b/CHANGELOG.md index c01dd3ff..f96dbf1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,18 @@ # unreleased +- Fixed bug caused by using `--plain` and `--terminal-width=N` flags simultaneously, see #3529 (@H4k1l) + ## Features +- Added an initial `flake.nix` for a ready made development environment; see #3578 (@vorburger) +- Add `--quiet-empty` (`-E`) flag to suppress output when input is empty. Closes #1936, see #3563 (@NORMAL-EX) - Improve native man pages and command help syntax highlighting by stripping overstriking, see #3517 (@akirk) ## Bugfixes - Fix crash with BusyBox `less` on Windows, see #3527 (@Anchal-T) - `--help` now correctly honors `--pager=builtin`. See #3516 (@keith-hall) - `--help` now correctly honors custom themes. See #3524 (@keith-hall) +- Fixed test compatibility with future Cargo build directory changes, see #3550 (@nmacl) ## Other @@ -18,6 +23,8 @@ ## Themes +- Remove the Visual Studio Dark+ theme, see #3552 (@CosmicHorrorDev) + ## `bat` as a library # v0.26.1 diff --git a/Cargo.lock b/Cargo.lock index c3347f51..384b771b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -83,13 +83,12 @@ checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" [[package]] name = "assert_cmd" -version = "2.0.16" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1835b7f27878de8525dc71410b5a31cdcc5f230aed5ba5df968e09c201b23d" +checksum = "bcbb6924530aa9e0432442af08bbcafdad182db80d2e560da42a6d442535bf85" dependencies = [ "anstyle", "bstr", - "doc-comment", "libc", "predicates", "predicates-core", @@ -253,18 +252,18 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "clap" -version = "4.5.46" +version = "4.5.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c5e4fcf9c21d2e544ca1ee9d8552de13019a42aa7dbf32747fa7aaf1df76e57" +checksum = "a75ca66430e33a14957acc24c5077b503e7d374151b2b4b3a10c83b4ceb4be0e" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.46" +version = "4.5.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fecb53a0e6fcfb055f686001bc2e2592fa527efaf38dbe81a6a9563562e57d41" +checksum = "793207c7fa6300a0608d1080b858e5fdbe713cdc1c8db9fb17777d8a13e63df0" dependencies = [ "anstream", "anstyle", @@ -297,9 +296,9 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "console" -version = "0.16.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b430743a6eb14e9764d4260d4c0d8123087d504eeb9c48f2b2a5e810dd369df4" +checksum = "03e45a4a8926227e4197636ba97a9fc9b00477e9f4bd711395687c5f0734bec4" dependencies = [ "encode_unicode", "libc", @@ -471,12 +470,6 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59f8e79d1fbf76bdfbde321e902714bf6c49df88a7dda6fc682fc2979226962d" -[[package]] -name = "doc-comment" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" - [[package]] name = "either" version = "1.13.0" @@ -665,9 +658,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.20.2" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" +checksum = "3e2b37e2f62729cdada11f0e6b3b6fe383c69c29fc619e391223e12856af308c" dependencies = [ "bitflags", "libc", @@ -868,9 +861,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.12.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", "hashbrown 0.16.1", @@ -922,9 +915,9 @@ checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "libgit2-sys" -version = "0.18.2+1.9.1" +version = "0.18.3+1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c42fe03df2bd3c53a3a9c7317ad91d80c81cd1fb0caec8d7cc4cd2bfa10c222" +checksum = "c9b3acc4b91781bb0b3386669d325163746af5f6e4f73e6d2d630e09a35f3487" dependencies = [ "cc", "libc", @@ -956,6 +949,12 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + [[package]] name = "litemap" version = "0.7.4" @@ -1060,11 +1059,11 @@ dependencies = [ [[package]] name = "nu-ansi-term" -version = "0.50.1" +version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -1218,9 +1217,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -1319,10 +1318,23 @@ dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.15", "windows-sys 0.59.0", ] +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys 0.11.0", + "windows-sys 0.61.2", +] + [[package]] name = "ryu" version = "1.0.18" @@ -1403,9 +1415,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.15.1" +version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa66c845eee442168b2c8134fec70ac50dc20e760769c8ba0ad1319ca1959b04" +checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7" dependencies = [ "serde_core", "serde_with_macros", @@ -1413,9 +1425,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.15.1" +version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91a903660542fced4e99881aa481bdbaec1634568ee02e0b8bd57c64cb38955" +checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" dependencies = [ "darling", "proc-macro2", @@ -1467,9 +1479,9 @@ checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" [[package]] name = "shell-words" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" [[package]] name = "shlex" @@ -1591,16 +1603,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.16.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ - "cfg-if", "fastrand", "getrandom", "once_cell", - "rustix", - "windows-sys 0.59.0", + "rustix 1.1.2", + "windows-sys 0.61.2", ] [[package]] @@ -1644,7 +1655,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9" dependencies = [ - "rustix", + "rustix 0.38.43", "windows-sys 0.59.0", ] @@ -2034,15 +2045,6 @@ dependencies = [ "windows-targets 0.48.5", ] -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.59.0" diff --git a/Cargo.toml b/Cargo.toml index e26e86b9..c4bd2e2f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,16 +42,16 @@ regex-onig = ["syntect/regex-onig"] # Use the "oniguruma" regex engine regex-fancy = ["syntect/regex-fancy"] # Use the rust-only "fancy-regex" engine [dependencies] -nu-ansi-term = "0.50.0" +nu-ansi-term = "0.50.3" ansi_colours = "^1.2" bincode = "1.0" -console = "0.16.1" +console = "0.16.2" flate2 = "1.1" once_cell = "1.20" thiserror = "2.0" wild = { version = "2.2", optional = true } content_inspector = "0.2.4" -shell-words = { version = "1.1.0", optional = true } +shell-words = { version = "1.1.1", optional = true } minus = { version = "5.6", optional = true, features = [ "dynamic_output", "search", @@ -87,7 +87,7 @@ default-features = false features = ["parsing"] [dependencies.clap] -version = "4.5.46" +version = "4.5.56" optional = true features = ["wrap_help", "cargo"] @@ -95,12 +95,12 @@ features = ["wrap_help", "cargo"] plist = "1.7.0" [dev-dependencies] -assert_cmd = "2.0.12" +assert_cmd = "2.0.16" expect-test = "1.5.0" serial_test = { version = "2.0.0", default-features = false } predicates = "3.1.3" wait-timeout = "0.2.1" -tempfile = "3.16.0" +tempfile = "3.23.0" serde = { version = "1.0", features = ["derive"] } [target.'cfg(unix)'.dev-dependencies] @@ -108,22 +108,22 @@ nix = { version = "0.30", default-features = false, features = ["term"] } [build-dependencies] anyhow = "1.0.97" -indexmap = { version = "2.8.0", features = ["serde"] } +indexmap = { version = "2.13.0", features = ["serde"] } itertools = "0.14.0" once_cell = "1.20" prettyplease = "0.2.37" -proc-macro2 = "1.0.103" +proc-macro2 = "1.0.106" quote = "1.0.40" regex = "1.12.2" serde = "1.0" serde_derive = "1.0" -serde_with = { version = "3.15.1", default-features = false, features = ["macros"] } +serde_with = { version = "3.16.1", default-features = false, features = ["macros"] } syn = { version = "2.0.104", features = ["full"] } toml = { version = "0.9.8", features = ["preserve_order"] } walkdir = "2.5" [build-dependencies.clap] -version = "4.5.46" +version = "4.5.56" optional = true features = ["wrap_help", "cargo"] diff --git a/assets/completions/_bat.ps1.in b/assets/completions/_bat.ps1.in index a9b3bcd5..db10302a 100644 --- a/assets/completions/_bat.ps1.in +++ b/assets/completions/_bat.ps1.in @@ -186,6 +186,7 @@ Register-ArgumentCompleter -Native -CommandName '{{PROJECT_EXECUTABLE}}' -Script [CompletionResult]::new('--acknowledgements' , 'acknowledgements' , [CompletionResultType]::ParameterName, 'Show acknowledgements.') [CompletionResult]::new('--set-terminal-title' , 'set-terminal-title' , [CompletionResultType]::ParameterName, 'Sets terminal title to filenames when using a pager.') [CompletionResult]::new('--diagnostic' , 'diagnostic' , [CompletionResultType]::ParameterName, 'Show diagnostic information for bug reports.') + [CompletionResult]::new('--quiet-empty' , 'quiet-empty' , [CompletionResultType]::ParameterName, 'Do not produce any output when the input is empty.') # [CompletionResult]::new('-h' , 'h' , [CompletionResultType]::ParameterName, 'Print this help message.') [CompletionResult]::new('--help' , 'help' , [CompletionResultType]::ParameterName, 'Print this help message.') # [CompletionResult]::new('-V' , 'V' , [CompletionResultType]::ParameterName, 'Show version information.') diff --git a/assets/completions/bat.bash.in b/assets/completions/bat.bash.in index 66be3985..7593df8f 100644 --- a/assets/completions/bat.bash.in +++ b/assets/completions/bat.bash.in @@ -100,6 +100,7 @@ _bat() { --lessopen | \ --no-paging | \ --diagnostic | \ + --quiet-empty | \ --acknowledgements | \ -h | --help | \ -V | --version | \ @@ -227,6 +228,7 @@ _bat() { --lessopen --completion --diagnostic + --quiet-empty --acknowledgements --set-terminal-title --help diff --git a/assets/completions/bat.fish.in b/assets/completions/bat.fish.in index 09f6407b..21c07adf 100644 --- a/assets/completions/bat.fish.in +++ b/assets/completions/bat.fish.in @@ -61,7 +61,7 @@ function __bat_no_excl_args -s V -l version \ -l acknowledgements \ -l config-dir -l config-file \ - -l diagnostic \ + -l diagnostic -l quiet-empty \ -l list-languages -l list-themes end @@ -159,6 +159,7 @@ complete -c $bat -l config-file -f -d "Display location of configuration file" - complete -c $bat -l decorations -x -a "$decorations_opts" -d "When to use --style decorations" -n __bat_no_excl_args complete -c $bat -l diagnostic -d "Print diagnostic info for bug reports" -n __fish_is_first_arg +complete -c $bat -l quiet-empty -d "Do not produce any output when the input is empty" -n __fish_is_first_arg complete -c $bat -s d -l diff -d "Only show lines with Git changes" -n __bat_no_excl_args diff --git a/assets/completions/bat.zsh.in b/assets/completions/bat.zsh.in index 910ec9d0..da9a66e6 100644 --- a/assets/completions/bat.zsh.in +++ b/assets/completions/bat.zsh.in @@ -62,6 +62,7 @@ _{{PROJECT_EXECUTABLE}}_main() { --completion='[show shell completion for a certain shell]:shell:(bash fish zsh ps1)' --set-terminal-title'[sets terminal title to filenames when using a pager]' --diagnostic'[show diagnostic information for bug reports]' + --quiet-empty'[do not produce any output when the input is empty]' -P'[disable paging]' "--no-config[don't use the configuration file]" "--no-custom-assets[don't load custom assets]" diff --git a/assets/manual/bat.1.in b/assets/manual/bat.1.in index 0be4bb63..ff4cb76f 100644 --- a/assets/manual/bat.1.in +++ b/assets/manual/bat.1.in @@ -282,6 +282,10 @@ Show bat's cache directory. .IP Show diagnostic information for bug reports. .HP +\fB\-\-quiet\-empty\fR +.IP +Do not produce any output when the input is empty (e.g. an empty file or empty stdin). This is useful in scripts where silent behavior is preferred for empty input. +.HP \fB\-\-acknowledgements\fR .IP Show acknowledgements. diff --git a/assets/syntaxes/02_Extra/Jinja2 b/assets/syntaxes/02_Extra/Jinja2 index 45355633..e572427f 160000 --- a/assets/syntaxes/02_Extra/Jinja2 +++ b/assets/syntaxes/02_Extra/Jinja2 @@ -1 +1 @@ -Subproject commit 45355633d17ee562481ca1d2ad0e3502c238f58a +Subproject commit e572427f6ac5f71fa2b9cf93e976a99bff4a3e94 diff --git a/assets/themes/visual-studio-dark-plus b/assets/themes/visual-studio-dark-plus deleted file mode 160000 index 01ee1e8e..00000000 --- a/assets/themes/visual-studio-dark-plus +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 01ee1e8e0dc578f3b4e8c0dbb6aa0279b4a26a40 diff --git a/doc/long-help.txt b/doc/long-help.txt index 8cb60812..994a3810 100644 --- a/doc/long-help.txt +++ b/doc/long-help.txt @@ -212,6 +212,10 @@ Options: --diagnostic Show diagnostic information for bug reports. + -E, --quiet-empty + When this flag is set, bat will produce no output at all when the input is empty. This is + useful when piping commands that may produce empty output, like 'git diff'. + --acknowledgements Show acknowledgements. diff --git a/doc/short-help.txt b/doc/short-help.txt index d67a51d0..41a0fdee 100644 --- a/doc/short-help.txt +++ b/doc/short-help.txt @@ -60,6 +60,8 @@ Options: Display all supported languages. --completion Show shell completion for a certain shell. [possible values: bash, fish, zsh, ps1] + -E, --quiet-empty + Produce no output when the input is empty. -h, --help Print help (see more with '--help') -V, --version diff --git a/flake.lock b/flake.lock new file mode 100644 index 00000000..b8b992e7 --- /dev/null +++ b/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1769789167, + "narHash": "sha256-kKB3bqYJU5nzYeIROI82Ef9VtTbu4uA3YydSk/Bioa8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "62c8382960464ceb98ea593cb8321a2cf8f9e3e5", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000..35c8cec1 --- /dev/null +++ b/flake.nix @@ -0,0 +1,40 @@ +{ + description = "bat"; + + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + outputs = + { self, ... }@inputs: + let + supportedSystems = [ + "x86_64-linux" # 64-bit Intel/AMD Linux + "aarch64-linux" # 64-bit ARM Linux + "aarch64-darwin" # 64-bit ARM macOS + "x86_64-darwin" # 64-bit Intel macOS + ]; + + forEachSupportedSystem = + f: + inputs.nixpkgs.lib.genAttrs supportedSystems ( + system: + f { + inherit system; + pkgs = import inputs.nixpkgs { + inherit system; + }; + } + ); + in + { + devShells = forEachSupportedSystem ( + { pkgs, system }: + { + default = pkgs.mkShellNoCC { + packages = with pkgs; [ + cargo + ]; + }; + } + ); + }; +} diff --git a/src/bin/bat/app.rs b/src/bin/bat/app.rs index 2df38f27..f5f59ec7 100644 --- a/src/bin/bat/app.rs +++ b/src/bin/bat/app.rs @@ -405,7 +405,7 @@ impl App { Some("character") => WrappingMode::Character, Some("never") => WrappingMode::NoWrapping(true), Some("auto") | None => { - if style_components.plain() { + if style_components.plain() && maybe_term_width.is_none() { WrappingMode::NoWrapping(false) } else { WrappingMode::Character @@ -461,6 +461,7 @@ impl App { Some("auto") => StripAnsiMode::Auto, _ => unreachable!("other values for --strip-ansi are not allowed"), }, + quiet_empty: self.matches.get_flag("quiet-empty"), theme: theme(self.theme_options()).to_string(), visible_lines: match self.matches.try_contains_id("diff").unwrap_or_default() && self.matches.get_flag("diff") diff --git a/src/bin/bat/clap_app.rs b/src/bin/bat/clap_app.rs index acb505ee..10bf7a8b 100644 --- a/src/bin/bat/clap_app.rs +++ b/src/bin/bat/clap_app.rs @@ -643,6 +643,18 @@ pub fn build_app(interactive_output: bool) -> Command { .hide_short_help(true) .help("Show diagnostic information for bug reports."), ) + .arg( + Arg::new("quiet-empty") + .long("quiet-empty") + .short('E') + .action(ArgAction::SetTrue) + .help("Produce no output when the input is empty.") + .long_help( + "When this flag is set, bat will produce no output at all when \ + the input is empty. This is useful when piping commands that may \ + produce empty output, like 'git diff'.", + ), + ) .arg( Arg::new("acknowledgements") .long("acknowledgements") diff --git a/src/config.rs b/src/config.rs index a4dd626f..7209c2fd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -99,14 +99,17 @@ pub struct Config<'a> { #[cfg(feature = "lessopen")] pub use_lessopen: bool, - // Weather or not to set terminal title when using a pager + // Whether or not to set terminal title when using a pager pub set_terminal_title: bool, /// The maximum number of consecutive empty lines to display pub squeeze_lines: Option, - // Weather or not to set terminal title when using a pager + // Whether or not to strip ANSI escape codes from the input pub strip_ansi: StripAnsiMode, + + /// Whether or not to produce no output when input is empty + pub quiet_empty: bool, } #[cfg(all(feature = "minimal-application", feature = "paging"))] diff --git a/src/printer.rs b/src/printer.rs index 1ddd5e66..3c3facf5 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -454,6 +454,11 @@ impl Printer for InteractivePrinter<'_> { input: &OpenedInput, add_header_padding: bool, ) -> Result<()> { + // If input is empty and quiet_empty is enabled, skip all output + if self.content_type.is_none() && self.config.quiet_empty { + return Ok(()); + } + if add_header_padding && self.config.style_components.rule() { self.print_horizontal_line_term(handle, self.colors.rule)?; } @@ -556,6 +561,11 @@ impl Printer for InteractivePrinter<'_> { } fn print_footer(&mut self, handle: &mut OutputHandle, _input: &OpenedInput) -> Result<()> { + // If input is empty and quiet_empty is enabled, skip footer + if self.content_type.is_none() && self.config.quiet_empty { + return Ok(()); + } + if self.config.style_components.grid() && (self.content_type.is_some_and(|c| c.is_text()) || self.config.show_nonprintable diff --git a/tests/assets.rs b/tests/assets.rs index 358e07ea..99ccb599 100644 --- a/tests/assets.rs +++ b/tests/assets.rs @@ -34,7 +34,6 @@ fn all_themes_are_present() { "Solarized (light)", "Sublime Snazzy", "TwoDark", - "Visual Studio Dark+", "ansi", "base16", "base16-256", diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 8896d9fa..7b4e2df4 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -1357,27 +1357,33 @@ fn disable_pager_if_pp_flag_comes_after_paging() { } #[test] +#[serial] fn enable_pager_if_disable_paging_flag_comes_before_paging() { - bat() - .env("PAGER", "echo pager-output") - .arg("-P") - .arg("--paging=always") - .arg("test.txt") - .assert() - .success() - .stdout(predicate::eq("pager-output\n").normalize()); + mocked_pagers::with_mocked_versions_of_more_and_most_in_path(|| { + bat() + .env("PAGER", mocked_pagers::from("echo pager-output")) + .arg("-P") + .arg("--paging=always") + .arg("test.txt") + .assert() + .success() + .stdout(predicate::str::contains("pager-output\n").normalize()); + }); } #[test] +#[serial] fn enable_pager_if_pp_flag_comes_before_paging() { - bat() - .env("PAGER", "echo pager-output") - .arg("-pp") - .arg("--paging=always") - .arg("test.txt") - .assert() - .success() - .stdout(predicate::eq("pager-output\n").normalize()); + mocked_pagers::with_mocked_versions_of_more_and_most_in_path(|| { + bat() + .env("PAGER", mocked_pagers::from("echo pager-output")) + .arg("-pp") + .arg("--paging=always") + .arg("test.txt") + .assert() + .success() + .stdout(predicate::str::contains("pager-output\n").normalize()); + }); } #[test] @@ -1394,15 +1400,18 @@ fn paging_does_not_override_simple_plain() { } #[test] +#[serial] fn simple_plain_does_not_override_paging() { - bat() - .env("PAGER", "echo pager-output") - .arg("--paging=always") - .arg("--plain") - .arg("test.txt") - .assert() - .success() - .stdout(predicate::eq("pager-output\n")); + mocked_pagers::with_mocked_versions_of_more_and_most_in_path(|| { + bat() + .env("PAGER", mocked_pagers::from("echo pager-output")) + .arg("--paging=always") + .arg("--plain") + .arg("test.txt") + .assert() + .success() + .stdout(predicate::str::contains("pager-output\n").normalize()); + }); } #[test] @@ -3631,3 +3640,47 @@ fn style_components_will_merge_with_env_var() { .stdout(" STDIN\n 1 test\n") .stderr(""); } + +// Test for https://github.com/sharkdp/bat/issues/3526 +#[test] +fn plain_with_sized_terminal_width() { + bat() + .arg("--plain") + .arg("--terminal-width=6") + .arg("--decorations=always") + .arg("test.txt") + .assert() + .success() + .stdout("hello \nworld\n") + .stderr(""); +} + +#[test] +fn quiet_empty_suppresses_output_on_empty_stdin() { + bat() + .arg("--quiet-empty") + .write_stdin("") + .assert() + .success() + .stdout(""); +} + +#[test] +fn quiet_empty_does_not_affect_non_empty_input() { + bat() + .arg("--quiet-empty") + .write_stdin("hello\n") + .assert() + .success() + .stdout("hello\n"); +} + +#[test] +fn quiet_empty_suppresses_output_on_empty_file() { + bat() + .arg("--quiet-empty") + .arg("empty.txt") + .assert() + .success() + .stdout(""); +} diff --git a/tests/tester/mod.rs b/tests/tester/mod.rs index 6c7e4226..b25a634c 100644 --- a/tests/tester/mod.rs +++ b/tests/tester/mod.rs @@ -53,16 +53,7 @@ impl Default for BatTester { fn default() -> Self { let temp_dir = create_sample_directory().expect("sample directory"); - let root = env::current_exe() - .expect("tests executable") - .parent() - .expect("tests executable directory") - .parent() - .expect("bat executable directory") - .to_path_buf(); - - let exe_name = if cfg!(windows) { "bat.exe" } else { "bat" }; - let exe = root.join(exe_name); + let exe = assert_cmd::cargo::cargo_bin!("bat").to_path_buf(); BatTester { temp_dir, exe } } diff --git a/tests/utils/command.rs b/tests/utils/command.rs index 40b01960..3a077d66 100644 --- a/tests/utils/command.rs +++ b/tests/utils/command.rs @@ -4,7 +4,7 @@ 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(); + let mut cmd = Command::new(assert_cmd::cargo::cargo_bin!("bat")); cmd.current_dir("tests/examples"); cmd.env_remove("BAT_CACHE_PATH"); cmd.env_remove("BAT_CONFIG_DIR");