mirror of
				https://github.com/sharkdp/bat.git
				synced 2025-10-31 15:12:12 +00:00 
			
		
		
		
	Compare commits
	
		
			84 Commits
		
	
	
		
			ci-experim
			...
			create_hig
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 271842d87c | ||
|  | ed3246c423 | ||
|  | 2339d78bf4 | ||
|  | 3a3cd0acba | ||
|  | ce4ddc0911 | ||
|  | aed4ea144f | ||
|  | eea061c1d9 | ||
|  | 10288e309e | ||
|  | ebdb00d4fc | ||
|  | 6fc7ebf37a | ||
|  | 8f6a0cd9e2 | ||
|  | 994c21a5e1 | ||
|  | 554374667e | ||
|  | 043f3381b0 | ||
|  | d04a83de7b | ||
|  | b622a4d890 | ||
|  | b551d28a2f | ||
|  | e6caa04209 | ||
|  | adadedeab1 | ||
|  | a6cf5235aa | ||
|  | 1477338106 | ||
|  | 418fce5683 | ||
|  | 7a15ba3796 | ||
|  | 0f002a5b06 | ||
|  | 5344a32d34 | ||
|  | c9645693a4 | ||
|  | f607263bdc | ||
|  | f309d2fbd2 | ||
|  | 47283f226a | ||
|  | aefc8fd824 | ||
|  | 405a80f3ee | ||
|  | ad98d35a48 | ||
|  | b69ab219d7 | ||
|  | dc8225f682 | ||
|  | 9d9b266f54 | ||
|  | b9d01c1a61 | ||
|  | 122cae7902 | ||
|  | 44a332c1c4 | ||
|  | 5143f3ad43 | ||
|  | a6dc25a216 | ||
|  | f04d2a9d6a | ||
|  | eb3b3b9f8d | ||
|  | 0994f3783f | ||
|  | 974dec38e3 | ||
|  | a0c363647f | ||
|  | d989224a8a | ||
|  | 82f439e715 | ||
|  | b034879eae | ||
|  | 9ed9a6fc3d | ||
|  | e84b702309 | ||
|  | 6226eba52a | ||
|  | 9e0ea06435 | ||
|  | 863d9cacd0 | ||
|  | 4baa346aae | ||
|  | 7956485e37 | ||
|  | 372e42f350 | ||
|  | 9124271eaf | ||
|  | 156dec2737 | ||
|  | 27f046ec03 | ||
|  | 74ae3dee91 | ||
|  | 87978e7755 | ||
|  | d935ea1cda | ||
|  | 9602195910 | ||
|  | 8ca852c728 | ||
|  | df067f7d1f | ||
|  | a8a81e99d2 | ||
|  | 65e7c531de | ||
|  | 7c41bd72da | ||
|  | 355a82db54 | ||
|  | b3e17bde82 | ||
|  | 4b38e7b1d7 | ||
|  | 43afae34be | ||
|  | 27fa55d274 | ||
|  | 19c3e82abf | ||
|  | f1c0fd7343 | ||
|  | 12dfbdc400 | ||
|  | c86a179412 | ||
|  | 0748783404 | ||
|  | b3247d9364 | ||
|  | ba8a694314 | ||
|  | b146958ecb | ||
|  | 15c701b196 | ||
|  | d8339808a1 | ||
|  | 3b263f0917 | 
							
								
								
									
										66
									
								
								.github/workflows/CICD.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										66
									
								
								.github/workflows/CICD.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,7 +1,7 @@ | ||||
| name: CICD | ||||
|  | ||||
| env: | ||||
|   MIN_SUPPORTED_RUST_VERSION: "1.45.0" | ||||
|   MIN_SUPPORTED_RUST_VERSION: "1.46.0" | ||||
|   CICD_INTERMEDIATES_DIR: "_cicd-intermediates" | ||||
|  | ||||
| on: | ||||
| @@ -14,6 +14,19 @@ on: | ||||
|       - '*' | ||||
|  | ||||
| jobs: | ||||
|   ensure_cargo_fmt: | ||||
|     name: Ensure 'cargo fmt' has been run | ||||
|     runs-on: ubuntu-20.04 | ||||
|     steps: | ||||
|     - uses: actions-rs/toolchain@v1 | ||||
|       with: | ||||
|         toolchain: stable | ||||
|         default: true | ||||
|         profile: minimal | ||||
|         components: rustfmt | ||||
|     - uses: actions/checkout@v2 | ||||
|     - run: cargo fmt -- --check | ||||
|  | ||||
|   min_version: | ||||
|     name: Minimum supported rust version | ||||
|     runs-on: ubuntu-20.04 | ||||
| @@ -27,17 +40,12 @@ jobs: | ||||
|         toolchain: ${{ env.MIN_SUPPORTED_RUST_VERSION }} | ||||
|         default: true | ||||
|         profile: minimal # minimal component installation (ie, no documentation) | ||||
|         components: clippy, rustfmt | ||||
|     - name: Ensure `cargo fmt` has been run | ||||
|       uses: actions-rs/cargo@v1 | ||||
|       with: | ||||
|         command: fmt | ||||
|         args: -- --check | ||||
|         components: clippy | ||||
|     - name: Run clippy (on minimum supported rust version to prevent warnings we can't fix) | ||||
|       uses: actions-rs/cargo@v1 | ||||
|       with: | ||||
|         command: clippy | ||||
|         args: --locked --all-targets --all-features | ||||
|         args: --locked --all-targets --all-features -- --allow clippy::unknown_clippy_lints | ||||
|     - name: Run tests | ||||
|       uses: actions-rs/cargo@v1 | ||||
|       with: | ||||
| @@ -86,6 +94,21 @@ jobs: | ||||
|       run: bat --list-languages | ||||
|     - name: List of themes | ||||
|       run: bat --list-themes | ||||
|     - name: Test custom assets | ||||
|       run: tests/syntax-tests/test_custom_assets.sh | ||||
|  | ||||
|   documentation: | ||||
|     name: Documentation | ||||
|     runs-on: ubuntu-20.04 | ||||
|     steps: | ||||
|     - name: Git checkout | ||||
|       uses: actions/checkout@v2 | ||||
|     - name: Install Rust toolchain | ||||
|       uses: actions-rs/toolchain@v1 | ||||
|       with: | ||||
|         toolchain: stable | ||||
|         default: true | ||||
|         profile: minimal | ||||
|     - name: Check documentation | ||||
|       env: | ||||
|         RUSTDOCFLAGS: -D warnings | ||||
| @@ -95,24 +118,23 @@ jobs: | ||||
|         args: --locked --no-deps --document-private-items --all-features | ||||
|  | ||||
|   build: | ||||
|     name: ${{ matrix.job.os }} (${{ matrix.job.target }}) | ||||
|     name: ${{ matrix.job.target }} (${{ matrix.job.os }}) | ||||
|     runs-on: ${{ matrix.job.os }} | ||||
|     strategy: | ||||
|       fail-fast: false | ||||
|       matrix: | ||||
|         job: | ||||
|           - { os: ubuntu-20.04, target: arm-unknown-linux-gnueabihf , use-cross: true } | ||||
|           - { os: ubuntu-20.04, target: arm-unknown-linux-musleabihf, use-cross: true } | ||||
|           - { os: ubuntu-20.04, target: aarch64-unknown-linux-gnu   , use-cross: true } | ||||
|           - { os: ubuntu-20.04, target: i686-unknown-linux-gnu      , use-cross: true } | ||||
|           - { os: ubuntu-20.04, target: i686-unknown-linux-musl     , use-cross: true } | ||||
|           - { os: ubuntu-20.04, target: x86_64-unknown-linux-gnu    } | ||||
|           - { os: ubuntu-20.04, target: x86_64-unknown-linux-musl   , use-cross: true } | ||||
|           - { os: macos-10.15 , target: x86_64-apple-darwin         } | ||||
|           # - { os: windows-2019, target: i686-pc-windows-gnu         }  ## disabled; error: linker `i686-w64-mingw32-gcc` not found | ||||
|           - { os: windows-2019, target: i686-pc-windows-msvc        } | ||||
|           - { os: windows-2019, target: x86_64-pc-windows-gnu       } | ||||
|           - { os: windows-2019, target: x86_64-pc-windows-msvc      } | ||||
|           - { target: aarch64-unknown-linux-gnu   , os: ubuntu-20.04, use-cross: true } | ||||
|           - { target: arm-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true } | ||||
|           - { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, use-cross: true } | ||||
|           - { target: i686-pc-windows-msvc        , os: windows-2019                  } | ||||
|           - { target: i686-unknown-linux-gnu      , os: ubuntu-20.04, use-cross: true } | ||||
|           - { target: i686-unknown-linux-musl     , os: ubuntu-20.04, use-cross: true } | ||||
|           - { target: x86_64-apple-darwin         , os: macos-10.15                   } | ||||
|           - { target: x86_64-pc-windows-gnu       , os: windows-2019                  } | ||||
|           - { target: x86_64-pc-windows-msvc      , os: windows-2019                  } | ||||
|           - { target: x86_64-unknown-linux-gnu    , os: ubuntu-20.04                  } | ||||
|           - { target: x86_64-unknown-linux-musl   , os: ubuntu-20.04, use-cross: true } | ||||
|     steps: | ||||
|     - name: Checkout source code | ||||
|       uses: actions/checkout@v2 | ||||
| @@ -285,6 +307,7 @@ jobs: | ||||
|         # Autocompletion files | ||||
|         cp 'target/${{ matrix.job.target }}/release/build/${{ env.PROJECT_NAME }}'-*/out/assets/completions/bat.bash "$ARCHIVE_DIR/autocomplete/${{ env.PROJECT_NAME }}.bash" | ||||
|         cp 'target/${{ matrix.job.target }}/release/build/${{ env.PROJECT_NAME }}'-*/out/assets/completions/bat.fish "$ARCHIVE_DIR/autocomplete/${{ env.PROJECT_NAME }}.fish" | ||||
|         cp 'target/${{ matrix.job.target }}/release/build/${{ env.PROJECT_NAME }}'-*/out/assets/completions/_bat.ps1 "$ARCHIVE_DIR/autocomplete/_${{ env.PROJECT_NAME }}.ps1" | ||||
|         cp 'target/${{ matrix.job.target }}/release/build/${{ env.PROJECT_NAME }}'-*/out/assets/completions/bat.zsh "$ARCHIVE_DIR/autocomplete/${{ env.PROJECT_NAME }}.zsh" | ||||
|  | ||||
|         # base compressed package | ||||
| @@ -333,6 +356,7 @@ jobs: | ||||
|         gzip -n --best "${DPKG_DIR}/usr/share/man/man1/${{ env.PROJECT_NAME }}.1" | ||||
|  | ||||
|         # Autocompletion files | ||||
|         install -Dm644 'target/${{ matrix.job.target }}/release/build/${{ env.PROJECT_NAME }}'-*/out/assets/completions/bat.bash "${DPKG_DIR}/usr/share/bash-completion/completions/${{ env.PROJECT_NAME }}" | ||||
|         install -Dm644 'target/${{ matrix.job.target }}/release/build/${{ env.PROJECT_NAME }}'-*/out/assets/completions/bat.fish "${DPKG_DIR}/usr/share/fish/vendor_completions.d/${{ env.PROJECT_NAME }}.fish" | ||||
|         install -Dm644 'target/${{ matrix.job.target }}/release/build/${{ env.PROJECT_NAME }}'-*/out/assets/completions/bat.zsh "${DPKG_DIR}/usr/share/zsh/vendor-completions/_${{ env.PROJECT_NAME }}" | ||||
|  | ||||
|   | ||||
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @@ -230,3 +230,6 @@ | ||||
| [submodule "assets/syntaxes/02_Extra/Slim"] | ||||
| 	path = assets/syntaxes/02_Extra/Slim | ||||
| 	url = https://github.com/slim-template/ruby-slim.tmbundle.git | ||||
| [submodule "assets/syntaxes/02_Extra/Racket"] | ||||
| 	path = assets/syntaxes/02_Extra/Racket | ||||
| 	url = https://github.com/follesoe/sublime-racket.git | ||||
|   | ||||
							
								
								
									
										21
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -3,16 +3,23 @@ | ||||
| ## Features | ||||
|  | ||||
| - `$BAT_CONFIG_DIR` is now a recognized environment variable. It has precedence over `$XDG_CONFIG_HOME`, see #1727 (@billrisher) | ||||
| - Support for `x:+delta` syntax in line ranges (e.g. `20:+10`). See  #1810 (@bojan88) | ||||
|  | ||||
| ## Bugfixes | ||||
|  | ||||
| - Python syntax highlighting no longer suffers from abysmal performance in specific scenarios. See #1688 (@keith-hall) | ||||
| - First line not shown in diff context. See #1891 (@divagant-martian) | ||||
|  | ||||
| ## Other | ||||
| ## Performance | ||||
|  | ||||
| - Load cached assets as fast as integrated assets, see #1753 (@Enselic) | ||||
| - Greatly reduce startup time in loop-through mode, e.g. when redirecting output. Instead of *50 ms* - *100 ms*, startup takes *5 ms* - *10 ms*. See #1747 (@Enselic) | ||||
| - Reduce startup time by approximately 80% for 91 out of 168 syntaxes when using `--language`. See #1787 (@Enselic) | ||||
|  | ||||
| ## Other | ||||
|  | ||||
| - Add PowerShell completion, see #1826 (@rashil2000) | ||||
| - Minimum supported Rust version (MSRV) bumped to 1.46 | ||||
|  | ||||
| ## Syntaxes | ||||
|  | ||||
| @@ -22,16 +29,26 @@ | ||||
| - Highlight for `vimrc` and `gvimrc` files, see #1763 (@SuperSandro2000) | ||||
| - Syslog highlighting improvements, see #1793 (@scop) | ||||
| - Added support for `slim` syntax, see #1693 (@mfinelli) | ||||
| - Racket, see #1884 (@jubnzv) | ||||
|  | ||||
| ## New themes | ||||
|  | ||||
|  | ||||
| ## `bat` as a library | ||||
|  | ||||
| - Deprecate `HighlightingAssets::syntaxes()` and `HighlightingAssets::syntax_for_file_name()`. Use `HighlightingAssets::get_syntaxes()` and `HighlightingAssets::get_syntax_for_file_name()` instead. They return a `Result` which is needed for upcoming lazy-loading work to improve startup performance. They also return what `SyntaxSet` the returned `SyntaxReference` belongs to. See #1747, #1755 and #1776 (@Enselic) | ||||
| - Deprecate `HighlightingAssets::syntaxes()` and `HighlightingAssets::syntax_for_file_name()`. Use `HighlightingAssets::get_syntaxes()` and `HighlightingAssets::get_syntax_for_path()` instead. They return a `Result` which is needed for upcoming lazy-loading work to improve startup performance. They also return which `SyntaxSet` the returned `SyntaxReference` belongs to. See #1747, #1755, #1776, #1862 (@Enselic) | ||||
| - Remove `HighlightingAssets::from_files` and `HighlightingAssets::save_to_cache`. Instead of calling the former and then the latter you now make a single call to `bat::assets::build`. See #1802 (@Enselic) | ||||
| - Replace  the `error::Error(error::ErrorKind, _)` struct and enum with an `error::Error` enum. `Error(ErrorKind::UnknownSyntax, _)` becomes `Error::UnknownSyntax`, etc. Also remove the `error::ResultExt` trait. These changes stem from replacing `error-chain` with `thiserror`. See #1820 (@Enselic) | ||||
|  | ||||
|  | ||||
|  | ||||
| # v0.18.3 | ||||
|  | ||||
| ## Bugfixes | ||||
|  | ||||
| - Bump `git2` dependency to fix build with Rust 1.54, see #1761 | ||||
|  | ||||
|  | ||||
| # v0.18.2 | ||||
|  | ||||
| ## Features | ||||
|   | ||||
							
								
								
									
										83
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										83
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @@ -46,9 +46,9 @@ dependencies = [ | ||||
|  | ||||
| [[package]] | ||||
| name = "assert_cmd" | ||||
| version = "1.0.8" | ||||
| version = "2.0.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "c98233c6673d8601ab23e77eb38f999c51100d46c5703b17288c57fddf3a1ffe" | ||||
| checksum = "b800c4403e8105d959595e1f88119e78bc12bc874c4336973658b648a746ba93" | ||||
| dependencies = [ | ||||
|  "bstr", | ||||
|  "doc-comment", | ||||
| @@ -83,12 +83,13 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" | ||||
|  | ||||
| [[package]] | ||||
| name = "bat" | ||||
| version = "0.18.2" | ||||
| version = "0.18.3" | ||||
| dependencies = [ | ||||
|  "ansi_colours", | ||||
|  "ansi_term 0.12.1", | ||||
|  "assert_cmd", | ||||
|  "atty", | ||||
|  "bincode", | ||||
|  "bugreport", | ||||
|  "clap", | ||||
|  "clircle", | ||||
| @@ -96,7 +97,7 @@ dependencies = [ | ||||
|  "content_inspector", | ||||
|  "dirs-next", | ||||
|  "encoding", | ||||
|  "error-chain", | ||||
|  "flate2", | ||||
|  "git2", | ||||
|  "globset", | ||||
|  "grep-cli", | ||||
| @@ -112,6 +113,7 @@ dependencies = [ | ||||
|  "shell-words", | ||||
|  "syntect", | ||||
|  "tempfile", | ||||
|  "thiserror", | ||||
|  "unicode-width", | ||||
|  "wait-timeout", | ||||
|  "wild", | ||||
| @@ -143,9 +145,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" | ||||
|  | ||||
| [[package]] | ||||
| name = "bitflags" | ||||
| version = "1.2.1" | ||||
| version = "1.3.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" | ||||
| checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" | ||||
|  | ||||
| [[package]] | ||||
| name = "bstr" | ||||
| @@ -376,15 +378,6 @@ version = "0.1.4" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" | ||||
|  | ||||
| [[package]] | ||||
| name = "error-chain" | ||||
| version = "0.12.4" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" | ||||
| dependencies = [ | ||||
|  "version_check", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "fancy-regex" | ||||
| version = "0.7.1" | ||||
| @@ -397,9 +390,9 @@ dependencies = [ | ||||
|  | ||||
| [[package]] | ||||
| name = "flate2" | ||||
| version = "1.0.20" | ||||
| version = "1.0.22" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0" | ||||
| checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" | ||||
| dependencies = [ | ||||
|  "cfg-if", | ||||
|  "crc32fast", | ||||
| @@ -597,9 +590,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" | ||||
|  | ||||
| [[package]] | ||||
| name = "libc" | ||||
| version = "0.2.98" | ||||
| version = "0.2.103" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" | ||||
| checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" | ||||
|  | ||||
| [[package]] | ||||
| name = "libgit2-sys" | ||||
| @@ -691,9 +684,9 @@ dependencies = [ | ||||
|  | ||||
| [[package]] | ||||
| name = "nix" | ||||
| version = "0.22.0" | ||||
| version = "0.23.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "cf1e25ee6b412c2a1e3fcb6a4499a5c1bfe7f43e014bdce9a6b6666e5aa2d187" | ||||
| checksum = "f305c2c2e4c39a82f7bf0bf65fb557f9070ce06781d4f2454295cc34b1c43188" | ||||
| dependencies = [ | ||||
|  "bitflags", | ||||
|  "cc", | ||||
| @@ -817,9 +810,9 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" | ||||
|  | ||||
| [[package]] | ||||
| name = "predicates" | ||||
| version = "2.0.1" | ||||
| version = "2.0.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "bc3d91237f5de3bcd9d927e24d03b495adb6135097b001cea7403e2d573d00a9" | ||||
| checksum = "c143348f141cc87aab5b950021bac6145d0e5ae754b0591de23244cee42c9308" | ||||
| dependencies = [ | ||||
|  "difflib", | ||||
|  "float-cmp", | ||||
| @@ -998,18 +991,18 @@ checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" | ||||
|  | ||||
| [[package]] | ||||
| name = "serde" | ||||
| version = "1.0.127" | ||||
| version = "1.0.130" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" | ||||
| checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" | ||||
| dependencies = [ | ||||
|  "serde_derive", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "serde_derive" | ||||
| version = "1.0.127" | ||||
| version = "1.0.130" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc" | ||||
| checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" | ||||
| dependencies = [ | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
| @@ -1029,12 +1022,12 @@ dependencies = [ | ||||
|  | ||||
| [[package]] | ||||
| name = "serde_yaml" | ||||
| version = "0.8.17" | ||||
| version = "0.8.21" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23" | ||||
| checksum = "d8c608a35705a5d3cdc9fbe403147647ff34b921f8e833e49306df898f9b20af" | ||||
| dependencies = [ | ||||
|  "dtoa", | ||||
|  "linked-hash-map", | ||||
|  "indexmap", | ||||
|  "serde", | ||||
|  "yaml-rust", | ||||
| ] | ||||
| @@ -1188,6 +1181,26 @@ dependencies = [ | ||||
|  "unicode-width", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "thiserror" | ||||
| version = "1.0.29" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88" | ||||
| dependencies = [ | ||||
|  "thiserror-impl", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "thiserror-impl" | ||||
| version = "1.0.29" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c" | ||||
| dependencies = [ | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "syn", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "tinyvec" | ||||
| version = "1.2.0" | ||||
| @@ -1229,9 +1242,9 @@ dependencies = [ | ||||
|  | ||||
| [[package]] | ||||
| name = "unicode-width" | ||||
| version = "0.1.8" | ||||
| version = "0.1.9" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" | ||||
| checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" | ||||
|  | ||||
| [[package]] | ||||
| name = "unicode-xid" | ||||
| @@ -1263,12 +1276,6 @@ version = "0.8.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" | ||||
|  | ||||
| [[package]] | ||||
| name = "version_check" | ||||
| version = "0.9.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" | ||||
|  | ||||
| [[package]] | ||||
| name = "wait-timeout" | ||||
| version = "0.2.0" | ||||
|   | ||||
							
								
								
									
										23
									
								
								Cargo.toml
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								Cargo.toml
									
									
									
									
									
								
							| @@ -6,7 +6,7 @@ homepage = "https://github.com/sharkdp/bat" | ||||
| license = "MIT/Apache-2.0" | ||||
| name = "bat" | ||||
| repository = "https://github.com/sharkdp/bat" | ||||
| version = "0.18.2" | ||||
| version = "0.18.3" | ||||
| exclude = ["assets/syntaxes/*", "assets/themes/*"] | ||||
| build = "build.rs" | ||||
| edition = '2018' | ||||
| @@ -33,7 +33,7 @@ minimal-application = [ | ||||
|     "wild", | ||||
| ] | ||||
| git = ["git2"] # Support indicating git modifications | ||||
| paging = ["shell-words"] # Support applying a pager on the output | ||||
| paging = ["shell-words", "grep-cli"] # Support applying a pager on the output | ||||
| # Add "syntect/plist-load" when https://github.com/trishume/syntect/pull/345 reaches us | ||||
| build-assets = ["syntect/yaml-load", "syntect/dump-create"] | ||||
|  | ||||
| @@ -45,14 +45,17 @@ regex-fancy = ["syntect/regex-fancy"] # Use the rust-only "fancy-regex" engine | ||||
| atty = { version = "0.2.14", optional = true } | ||||
| ansi_term = "^0.12.1" | ||||
| ansi_colours = "^1.0" | ||||
| bincode = "1.0" | ||||
| console = "0.14.1" | ||||
| flate2 = "1.0" | ||||
| lazy_static = { version = "1.4", optional = true } | ||||
| lazycell = "1.0" | ||||
| thiserror = "1.0" | ||||
| wild = { version = "2.0", optional = true } | ||||
| content_inspector = "0.2.4" | ||||
| encoding = "0.2" | ||||
| shell-words = { version = "1.0.0", optional = true } | ||||
| unicode-width = "0.1.8" | ||||
| unicode-width = "0.1.9" | ||||
| globset = "0.4" | ||||
| serde = { version = "1.0", features = ["derive"] } | ||||
| serde_yaml = "0.8" | ||||
| @@ -61,7 +64,7 @@ path_abs = { version = "0.5", default-features = false } | ||||
| clircle = "0.3" | ||||
| bugreport = { version = "0.4", optional = true } | ||||
| dirs-next = { version = "2.0.0", optional = true } | ||||
| grep-cli = "0.1.6" | ||||
| grep-cli = { version = "0.1.6", optional = true } | ||||
|  | ||||
| [dependencies.git2] | ||||
| version = "0.13" | ||||
| @@ -71,7 +74,7 @@ default-features = false | ||||
| [dependencies.syntect] | ||||
| version = "4.6.0" | ||||
| default-features = false | ||||
| features = ["parsing", "dump-load"] | ||||
| features = ["parsing"] | ||||
|  | ||||
| [dependencies.clap] | ||||
| version = "2.33" | ||||
| @@ -79,19 +82,15 @@ optional = true | ||||
| default-features = false | ||||
| features = ["suggestions", "color", "wrap_help"] | ||||
|  | ||||
| [dependencies.error-chain] | ||||
| version = "0.12" | ||||
| default-features = false | ||||
|  | ||||
| [dev-dependencies] | ||||
| assert_cmd = "1.0.8" | ||||
| assert_cmd = "2.0.1" | ||||
| serial_test = "0.5.1" | ||||
| predicates = "2.0.1" | ||||
| predicates = "2.0.2" | ||||
| wait-timeout = "0.2.0" | ||||
| tempfile = "3.2.0" | ||||
|  | ||||
| [target.'cfg(unix)'.dev-dependencies] | ||||
| nix = "0.22.0" | ||||
| nix = "0.23.0" | ||||
|  | ||||
| [build-dependencies] | ||||
| clap = { version = "2.33", optional = true } | ||||
|   | ||||
							
								
								
									
										33
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								README.md
									
									
									
									
									
								
							| @@ -12,7 +12,11 @@ | ||||
|   <a href="#installation">Installation</a> • | ||||
|   <a href="#customization">Customization</a> • | ||||
|   <a href="#project-goals-and-alternatives">Project goals, alternatives</a><br> | ||||
|   [<a href="https://github.com/chinanf-boy/bat-zh">中文</a>] [<a href="doc/README-ja.md">日本語</a>] [<a href="doc/README-ko.md">한국어</a>] [<a href="doc/README-ru.md">Русский</a>] | ||||
|   [English] | ||||
|   [<a href="https://github.com/chinanf-boy/bat-zh">中文</a>] | ||||
|   [<a href="doc/README-ja.md">日本語</a>] | ||||
|   [<a href="doc/README-ko.md">한국어</a>] | ||||
|   [<a href="doc/README-ru.md">Русский</a>] | ||||
| </p> | ||||
|  | ||||
| ### Syntax highlighting | ||||
| @@ -196,10 +200,7 @@ The [`prettybat`](https://github.com/eth-p/bat-extras/blob/master/doc/prettybat. | ||||
| ### On Ubuntu (using `apt`) | ||||
| *... and other Debian-based Linux distributions.* | ||||
|  | ||||
| `bat` is making its way through the [Ubuntu](https://packages.ubuntu.com/eoan/bat) and | ||||
| [Debian](https://packages.debian.org/testing/bat) package release process, and is available | ||||
| for Ubuntu as of Eoan 19.10. On Debian `bat` is currently available on the unstable | ||||
| "Sid" branch and on the testing branch. | ||||
| `bat` is available on [Ubuntu since 20.04 ("Focal")](https://packages.ubuntu.com/search?keywords=bat&exact=1) and [Debian since August 2021 (Debian 11 - "Bullseye")](https://packages.debian.org/bullseye/bat). | ||||
|  | ||||
| If your Ubuntu/Debian installation is new enough you can simply run: | ||||
|  | ||||
| @@ -222,7 +223,7 @@ the most recent release of `bat`, download the latest `.deb` package from the | ||||
| [release page](https://github.com/sharkdp/bat/releases) and install it via: | ||||
|  | ||||
| ```bash | ||||
| sudo dpkg -i bat_0.18.2_amd64.deb  # adapt version number and architecture | ||||
| sudo dpkg -i bat_0.18.3_amd64.deb  # adapt version number and architecture | ||||
| ``` | ||||
|  | ||||
| ### On Alpine Linux | ||||
| @@ -251,6 +252,14 @@ You can install [the `bat` package](https://koji.fedoraproject.org/koji/packagei | ||||
| dnf install bat | ||||
| ``` | ||||
|  | ||||
| ### On Funtoo Linux | ||||
|  | ||||
| You can install [the `bat` package](https://github.com/funtoo/dev-kit/tree/1.4-release/sys-apps/bat) from dev-kit. | ||||
|  | ||||
| ```bash | ||||
| emerge sys-apps/bat | ||||
| ``` | ||||
|  | ||||
| ### On Gentoo Linux | ||||
|  | ||||
| You can install [the `bat` package](https://packages.gentoo.org/packages/sys-apps/bat) | ||||
| @@ -289,6 +298,14 @@ cd /usr/ports/textproc/bat | ||||
| make install | ||||
| ``` | ||||
|  | ||||
| ### On OpenBSD | ||||
|  | ||||
| You can install `bat` package using [`pkg_add(1)`](https://man.openbsd.org/pkg_add.1): | ||||
|  | ||||
| ```bash | ||||
| pkg_add bat | ||||
| ``` | ||||
|  | ||||
| ### Via nix | ||||
|  | ||||
| You can install `bat` using the [nix package manager](https://nixos.org/nix): | ||||
| @@ -363,7 +380,7 @@ binaries are also available: look for archives with `musl` in the file name. | ||||
|  | ||||
| ### From source | ||||
|  | ||||
| If you want to build `bat` from source, you need Rust 1.45 or | ||||
| If you want to build `bat` from source, you need Rust 1.46 or | ||||
| higher. You can then use `cargo` to build everything: | ||||
|  | ||||
| ```bash | ||||
| @@ -598,7 +615,7 @@ Example configuration file: | ||||
| # Use italic text on the terminal (not supported on all terminals) | ||||
| --italic-text=always | ||||
|  | ||||
| # Use C++ syntax for .ino files | ||||
| # Use C++ syntax for Arduino .ino files | ||||
| --map-syntax "*.ino:C++" | ||||
| ``` | ||||
|  | ||||
|   | ||||
							
								
								
									
										92
									
								
								assets/completions/_bat.ps1.in
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								assets/completions/_bat.ps1.in
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | ||||
|  | ||||
| using namespace System.Management.Automation | ||||
| using namespace System.Management.Automation.Language | ||||
|  | ||||
| Register-ArgumentCompleter -Native -CommandName '{{PROJECT_EXECUTABLE}}' -ScriptBlock { | ||||
|     param($wordToComplete, $commandAst, $cursorPosition) | ||||
|  | ||||
|     $commandElements = $commandAst.CommandElements | ||||
|     $command = @( | ||||
|         '{{PROJECT_EXECUTABLE}}' | ||||
|         for ($i = 1; $i -lt $commandElements.Count; $i++) { | ||||
|             $element = $commandElements[$i] | ||||
|             if ($element -isnot [StringConstantExpressionAst] -or | ||||
|                 $element.StringConstantType -ne [StringConstantType]::BareWord -or | ||||
|                 $element.Value.StartsWith('-')) { | ||||
|                 break | ||||
|         } | ||||
|         $element.Value | ||||
|     }) -join ';' | ||||
|  | ||||
|     $completions = @(switch ($command) { | ||||
|         '{{PROJECT_EXECUTABLE}}' { | ||||
|             [CompletionResult]::new('-l', 'l', [CompletionResultType]::ParameterName, 'Set the language for syntax highlighting.') | ||||
|             [CompletionResult]::new('--language', 'language', [CompletionResultType]::ParameterName, 'Set the language for syntax highlighting.') | ||||
|             [CompletionResult]::new('-H', 'H', [CompletionResultType]::ParameterName, 'Highlight lines N through M.') | ||||
|             [CompletionResult]::new('--highlight-line', 'highlight-line', [CompletionResultType]::ParameterName, 'Highlight lines N through M.') | ||||
|             [CompletionResult]::new('--file-name', 'file-name', [CompletionResultType]::ParameterName, 'Specify the name to display for a file.') | ||||
|             [CompletionResult]::new('--diff-context', 'diff-context', [CompletionResultType]::ParameterName, 'diff-context') | ||||
|             [CompletionResult]::new('--tabs', 'tabs', [CompletionResultType]::ParameterName, 'Set the tab width to T spaces.') | ||||
|             [CompletionResult]::new('--wrap', 'wrap', [CompletionResultType]::ParameterName, 'Specify the text-wrapping mode (*auto*, never, character).') | ||||
|             [CompletionResult]::new('--terminal-width', 'terminal-width', [CompletionResultType]::ParameterName, 'Explicitly set the width of the terminal instead of determining it automatically. If prefixed with ''+'' or ''-'', the value will be treated as an offset to the actual terminal width. See also: ''--wrap''.') | ||||
|             [CompletionResult]::new('--color', 'color', [CompletionResultType]::ParameterName, 'When to use colors (*auto*, never, always).') | ||||
|             [CompletionResult]::new('--italic-text', 'italic-text', [CompletionResultType]::ParameterName, 'Use italics in output (always, *never*)') | ||||
|             [CompletionResult]::new('--decorations', 'decorations', [CompletionResultType]::ParameterName, 'When to show the decorations (*auto*, never, always).') | ||||
|             [CompletionResult]::new('--paging', 'paging', [CompletionResultType]::ParameterName, 'Specify when to use the pager, or use `-P` to disable (*auto*, never, always).') | ||||
|             [CompletionResult]::new('--pager', 'pager', [CompletionResultType]::ParameterName, 'Determine which pager to use.') | ||||
|             [CompletionResult]::new('-m', 'm', [CompletionResultType]::ParameterName, 'Use the specified syntax for files matching the glob pattern (''*.cpp:C++'').') | ||||
|             [CompletionResult]::new('--map-syntax', 'map-syntax', [CompletionResultType]::ParameterName, 'Use the specified syntax for files matching the glob pattern (''*.cpp:C++'').') | ||||
|             [CompletionResult]::new('--theme', 'theme', [CompletionResultType]::ParameterName, 'Set the color theme for syntax highlighting.') | ||||
|             [CompletionResult]::new('--style', 'style', [CompletionResultType]::ParameterName, 'Comma-separated list of style elements to display (*auto*, full, plain, changes, header, grid, rule, numbers, snip).') | ||||
|             [CompletionResult]::new('-r', 'r', [CompletionResultType]::ParameterName, 'Only print the lines from N to M.') | ||||
|             [CompletionResult]::new('--line-range', 'line-range', [CompletionResultType]::ParameterName, 'Only print the lines from N to M.') | ||||
|             [CompletionResult]::new('-A', 'A', [CompletionResultType]::ParameterName, 'Show non-printable characters (space, tab, newline, ..).') | ||||
|             [CompletionResult]::new('--show-all', 'show-all', [CompletionResultType]::ParameterName, 'Show non-printable characters (space, tab, newline, ..).') | ||||
|             [CompletionResult]::new('-p', 'p', [CompletionResultType]::ParameterName, 'Show plain style (alias for ''--style=plain'').') | ||||
|             [CompletionResult]::new('--plain', 'plain', [CompletionResultType]::ParameterName, 'Show plain style (alias for ''--style=plain'').') | ||||
|             [CompletionResult]::new('-d', 'd', [CompletionResultType]::ParameterName, 'Only show lines that have been added/removed/modified.') | ||||
|             [CompletionResult]::new('--diff', 'diff', [CompletionResultType]::ParameterName, 'Only show lines that have been added/removed/modified.') | ||||
|             [CompletionResult]::new('-n', 'n', [CompletionResultType]::ParameterName, 'Show line numbers (alias for ''--style=numbers'').') | ||||
|             [CompletionResult]::new('--number', 'number', [CompletionResultType]::ParameterName, 'Show line numbers (alias for ''--style=numbers'').') | ||||
|             [CompletionResult]::new('-f', 'f', [CompletionResultType]::ParameterName, 'f') | ||||
|             [CompletionResult]::new('--force-colorization', 'force-colorization', [CompletionResultType]::ParameterName, 'force-colorization') | ||||
|             [CompletionResult]::new('-P', 'P', [CompletionResultType]::ParameterName, 'Alias for ''--paging=never''') | ||||
|             [CompletionResult]::new('--no-paging', 'no-paging', [CompletionResultType]::ParameterName, 'Alias for ''--paging=never''') | ||||
|             [CompletionResult]::new('--list-themes', 'list-themes', [CompletionResultType]::ParameterName, 'Display all supported highlighting themes.') | ||||
|             [CompletionResult]::new('-L', 'L', [CompletionResultType]::ParameterName, 'Display all supported languages.') | ||||
|             [CompletionResult]::new('--list-languages', 'list-languages', [CompletionResultType]::ParameterName, 'Display all supported languages.') | ||||
|             [CompletionResult]::new('-u', 'u', [CompletionResultType]::ParameterName, 'u') | ||||
|             [CompletionResult]::new('--unbuffered', 'unbuffered', [CompletionResultType]::ParameterName, 'unbuffered') | ||||
|             [CompletionResult]::new('--no-config', 'no-config', [CompletionResultType]::ParameterName, 'Do not use the configuration file') | ||||
|             [CompletionResult]::new('--no-custom-assets', 'no-custom-assets', [CompletionResultType]::ParameterName, 'Do not load custom assets') | ||||
|             [CompletionResult]::new('--config-file', 'config-file', [CompletionResultType]::ParameterName, 'Show path to the configuration file.') | ||||
|             [CompletionResult]::new('--generate-config-file', 'generate-config-file', [CompletionResultType]::ParameterName, 'Generates a default configuration file.') | ||||
|             [CompletionResult]::new('--config-dir', 'config-dir', [CompletionResultType]::ParameterName, 'Show bat''s configuration directory.') | ||||
|             [CompletionResult]::new('--cache-dir', 'cache-dir', [CompletionResultType]::ParameterName, 'Show bat''s cache directory.') | ||||
|             [CompletionResult]::new('--diagnostic', 'diagnostic', [CompletionResultType]::ParameterName, 'Show diagnostic information for bug reports.') | ||||
|             [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.') | ||||
|             [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Show version information.') | ||||
|             [CompletionResult]::new('cache', 'cache', [CompletionResultType]::ParameterValue, 'Modify the syntax-definition and theme cache') | ||||
|             break | ||||
|         } | ||||
|         '{{PROJECT_EXECUTABLE}};cache' { | ||||
|             [CompletionResult]::new('--source', 'source', [CompletionResultType]::ParameterName, 'Use a different directory to load syntaxes and themes from.') | ||||
|             [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'Use a different directory to store the cached syntax and theme set.') | ||||
|             [CompletionResult]::new('-b', 'b', [CompletionResultType]::ParameterName, 'Initialize (or update) the syntax/theme cache.') | ||||
|             [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'Initialize (or update) the syntax/theme cache.') | ||||
|             [CompletionResult]::new('-c', 'c', [CompletionResultType]::ParameterName, 'Remove the cached syntax definitions and themes.') | ||||
|             [CompletionResult]::new('--clear', 'clear', [CompletionResultType]::ParameterName, 'Remove the cached syntax definitions and themes.') | ||||
|             [CompletionResult]::new('--blank', 'blank', [CompletionResultType]::ParameterName, 'Create completely new syntax and theme sets (instead of appending to the default sets).') | ||||
|             [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information') | ||||
|             [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information') | ||||
|             [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information') | ||||
|             [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information') | ||||
|             break | ||||
|         } | ||||
|     }) | ||||
|  | ||||
|     $completions.Where{ $_.CompletionText -like "$wordToComplete*" } | | ||||
|         Sort-Object -Property ListItemText | ||||
| } | ||||
							
								
								
									
										2
									
								
								assets/completions/bat.fish.in
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								assets/completions/bat.fish.in
									
									
									
									
										vendored
									
									
								
							| @@ -56,7 +56,7 @@ complete -c {{PROJECT_EXECUTABLE}} -s P -d "Disable paging. Alias for '--paging= | ||||
|  | ||||
| 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 {{PROJECT_EXECUTABLE}} -l style -xka "auto full plain changes header grid numbers" -d "Comma-separated list of style elements or presets to display with file contents" -n "not __fish_seen_subcommand_from cache" | ||||
| complete -c {{PROJECT_EXECUTABLE}} -l style -xka "auto full plain changes header 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 {{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" | ||||
|  | ||||
|   | ||||
							
								
								
									
										2
									
								
								assets/completions/bat.zsh.in
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								assets/completions/bat.zsh.in
									
									
									
									
										vendored
									
									
								
							| @@ -75,7 +75,7 @@ _{{PROJECT_EXECUTABLE}}_main() { | ||||
|         ;; | ||||
|  | ||||
|         style) | ||||
|             _values -s , 'style' auto full plain changes header grid numbers snip | ||||
|             _values -s , 'style' auto full plain changes header grid rule numbers snip | ||||
|         ;; | ||||
|     esac | ||||
| } | ||||
|   | ||||
							
								
								
									
										4
									
								
								assets/manual/bat.1.in
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								assets/manual/bat.1.in
									
									
									
									
										vendored
									
									
								
							| @@ -50,6 +50,8 @@ highlights lines 30 to 40 | ||||
| highlights lines 1 to 40 | ||||
| .IP "\-\-highlight\-line 40:" | ||||
| highlights lines 40 to the end of the file | ||||
| .IP "\-\-highlight\-line 30:+10" | ||||
| highlights lines 30 to 40 | ||||
| .RE | ||||
| .HP | ||||
| \fB\-\-file\-name\fR <name>... | ||||
| @@ -154,6 +156,8 @@ prints lines 30 to 40 | ||||
| prints lines 1 to 40 | ||||
| .IP "\-\-line\-range 40:" | ||||
| prints lines 40 to the end of the file | ||||
| .IP "\-\-line\-range 30:+10" | ||||
| prints lines 30 to 40 | ||||
| .RE | ||||
| .HP | ||||
| \fB\-L\fR, \fB\-\-list\-languages\fR | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								assets/minimal_syntaxes.bin
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/minimal_syntaxes.bin
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										2
									
								
								assets/syntaxes/02_Extra/Julia
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								assets/syntaxes/02_Extra/Julia
									
									
									
									
										vendored
									
									
								
							 Submodule assets/syntaxes/02_Extra/Julia updated: 48639e1dbf...1e55f3211b
									
								
							
							
								
								
									
										1
									
								
								assets/syntaxes/02_Extra/Racket
									
									
									
									
										vendored
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								assets/syntaxes/02_Extra/Racket
									
									
									
									
										vendored
									
									
										Submodule
									
								
							 Submodule assets/syntaxes/02_Extra/Racket added at 7df4479c07
									
								
							
							
								
								
									
										52
									
								
								assets/syntaxes/02_Extra/Racket.sublime-syntax
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								assets/syntaxes/02_Extra/Racket.sublime-syntax
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| %YAML 1.2 | ||||
| --- | ||||
| # http://www.sublimetext.com/docs/3/syntax.html | ||||
| name: Racket | ||||
| file_extensions: | ||||
|   - rkt | ||||
| scope: source.racket | ||||
| contexts: | ||||
|   main: | ||||
|     - match: '[^\\](\"[^\"]*\")' | ||||
|       captures: | ||||
|         1: string.quoted.double.source.racket | ||||
|     - match: '\((define)\s+([a-zA-Z0-9_\-?\+^]+)\s*' | ||||
|       scope: meta.variable.source.racket | ||||
|       captures: | ||||
|         1: keyword.source.racket | ||||
|         2: entity.name.variable.source.racket | ||||
|     - match: '\((define)\s+\(([a-zA-Z0-9_\-?\+^]+)\s*' | ||||
|       scope: meta.function.source.racket | ||||
|       captures: | ||||
|         1: keyword.source.racket | ||||
|         2: entity.name.function | ||||
|     - match: '\((struct)\s+([a-zA-Z0-9_\-?\+^]+)\s+' | ||||
|       scope: meta.struct.source.racket | ||||
|       captures: | ||||
|         1: keyword.source.racket | ||||
|         2: entity.name.type | ||||
|     - match: '[\s\(](if|lambda|cond|define|type-case|let|letrec|let!|\#lang|require|test|else|first|rest|define-type|define-type-alias|define-struct|not|local|error|lang)[\s\)]' | ||||
|       scope: meta.keywords.source.racket | ||||
|       captures: | ||||
|         1: keyword.source.racket | ||||
|     - match: '[\s\(](true|false|empty|null)[\s\)]' | ||||
|       captures: | ||||
|         1: constant.language.source.racket | ||||
|     - match: '[\s\(\[\{](#t|#true|#f|#false)[\s\)\]\}]' | ||||
|       captures: | ||||
|         1: constant.language.source.racket | ||||
|     - match: '(#\\[a-zA-Z0-9_\-?\+\.\!\"]+)' | ||||
|       captures: | ||||
|         1: constant.language.source.racket | ||||
|     - match: '\b(0|([1-9][0-9_]*))\b' | ||||
|       scope: constant.numeric.integer.source.racket | ||||
|     - match: ; | ||||
|       push: | ||||
|         - meta_scope: comment.line.documentation.source.racket | ||||
|         - match: $\n | ||||
|           pop: true | ||||
|     - match: '#\|' | ||||
|       push: | ||||
|         - meta_scope: comment.block.source.racket | ||||
|         - match: '\|#' | ||||
|           pop: true | ||||
							
								
								
									
										5
									
								
								build.rs
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								build.rs
									
									
									
									
									
								
							| @@ -64,6 +64,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
|         "assets/completions/bat.fish.in", | ||||
|         out_dir.join("assets/completions/bat.fish"), | ||||
|     )?; | ||||
|     template( | ||||
|         &variables, | ||||
|         "assets/completions/_bat.ps1.in", | ||||
|         out_dir.join("assets/completions/_bat.ps1"), | ||||
|     )?; | ||||
|     template( | ||||
|         &variables, | ||||
|         "assets/completions/bat.zsh.in", | ||||
|   | ||||
| @@ -1,7 +1,6 @@ | ||||
| <p align="center"> | ||||
|   <img src="logo-header.svg" alt="bat - a cat clone with wings"><br> | ||||
|   <a href="https://travis-ci.org/sharkdp/bat"><img src="https://travis-ci.org/sharkdp/bat.svg?branch=master" alt="Build Status"></a> | ||||
|   <a href="https://ci.appveyor.com/project/sharkdp/bat"><img src="https://ci.appveyor.com/api/projects/status/cptsmtbiwbnr2vhf?svg=true"></a> | ||||
|   <a href="https://github.com/sharkdp/bat/actions?query=workflow%3ACICD"><img src="https://github.com/sharkdp/bat/workflows/CICD/badge.svg" alt="Build Status"></a> | ||||
|   <img src="https://img.shields.io/crates/l/bat.svg" alt="license"> | ||||
|   <a href="https://crates.io/crates/bat"><img src="https://img.shields.io/crates/v/bat.svg?colorB=319e8c" alt="Version info"></a><br> | ||||
|   シンタックスハイライトとGitとの連携機能付きの <i>cat(1)</i> クローン。 | ||||
| @@ -12,8 +11,12 @@ | ||||
|   <a href="#使い方">使い方</a> • | ||||
|   <a href="#インストール">インストール</a> • | ||||
|   <a href="#カスタマイズ">カスタマイズ</a> • | ||||
|   <a href="#プロジェクトの目標と既存の類似したOSS">プロジェクトの目標と既存の類似したOSS</a> • | ||||
|   翻訳 [<a href="https://github.com/chinanf-boy/bat-zh">中文</a>][<a href="README-ja.md">日本語</a>][<a href="README-ko.md">한국어</a>] | ||||
|   <a href="#プロジェクトの目標と既存の類似したOSS">プロジェクトの目標と既存の類似したOSS</a><br> | ||||
|   [<a href="../README.md">English</a>] | ||||
|   [<a href="https://github.com/chinanf-boy/bat-zh">中文</a>] | ||||
|   [日本語] | ||||
|   [<a href="README-ko.md">한국어</a>] | ||||
|   [<a href="README-ru.md">Русский</a>] | ||||
| </p> | ||||
|  | ||||
| ### シンタックスハイライト | ||||
| @@ -202,7 +205,7 @@ ln -s /usr/bin/batcat ~/.local/bin/bat | ||||
| batの最新リリースを実行する場合、または Ubuntu/Debian の古いバージョンを使用している場合は、[release page](https://github.com/sharkdp/bat/releases) から最新の `.deb` パッケージをダウンロードし、 | ||||
| 次の方法でインストールします: | ||||
| ```bash | ||||
| sudo dpkg -i bat_0.18.2_amd64.deb  # adapt version number and architecture | ||||
| sudo dpkg -i bat_0.18.3_amd64.deb  # adapt version number and architecture | ||||
| ``` | ||||
|  | ||||
| ### On Alpine Linux | ||||
| @@ -522,7 +525,7 @@ export BAT_CONFIG_PATH="/path/to/bat.conf" | ||||
| # Use italic text on the terminal (not supported on all terminals) | ||||
| --italic-text=always | ||||
|  | ||||
| # Use C++ syntax for .ino files | ||||
| # Use C++ syntax for Arduino .ino files | ||||
| --map-syntax "*.ino:C++" | ||||
|  | ||||
| # Use ".gitignore"-style highlighting for ".ignore" files | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| <p align="center"> | ||||
|   <img src="../doc/logo-header.svg" alt="bat - a cat clone with wings"><br> | ||||
|   <img src="logo-header.svg" alt="bat - a cat clone with wings"><br> | ||||
|   <a href="https://github.com/sharkdp/bat/actions?query=workflow%3ACICD"><img src="https://github.com/sharkdp/bat/workflows/CICD/badge.svg" alt="Build Status"></a> | ||||
|   <img src="https://img.shields.io/crates/l/bat.svg" alt="license"> | ||||
|   <a href="https://crates.io/crates/bat"><img src="https://img.shields.io/crates/v/bat.svg?colorB=319e8c" alt="Version info"></a><br> | ||||
| @@ -11,8 +11,12 @@ | ||||
|   <a href="#사용법">사용법</a> • | ||||
|   <a href="#설치">설치</a> • | ||||
|   <a href="#사용자화">사용자화</a> • | ||||
|   <a href="#프로젝트-목표와-대안들">프로젝트 목표와 대안들</a> • | ||||
|   [<a href="https://github.com/chinanf-boy/bat-zh">中文</a>] [<a href="../doc/README-ja.md">日本語</a>] [<a href="../doc/README-ko.md">한국어</a>] [<a href="../doc/README-ru.md">Русский</a>] | ||||
|   <a href="#프로젝트-목표와-대안들">프로젝트 목표와 대안들</a><br> | ||||
|   [<a href="../README.md">English</a>] | ||||
|   [<a href="https://github.com/chinanf-boy/bat-zh">中文</a>] | ||||
|   [<a href="README-ja.md">日本語</a>] | ||||
|   [한국어] | ||||
|   [<a href="README-ru.md">Русский</a>] | ||||
| </p> | ||||
|  | ||||
| ### 문법 강조 | ||||
| @@ -244,7 +248,7 @@ ln -s /usr/bin/batcat ~/.local/bin/bat | ||||
| 다음과 같이 `.deb` 패키지를 받아 설치하세요: | ||||
|  | ||||
| ```bash | ||||
| sudo dpkg -i bat_0.18.2_amd64.deb  # adapt version number and architecture | ||||
| sudo dpkg -i bat_0.18.3_amd64.deb  # adapt version number and architecture | ||||
| ``` | ||||
|  | ||||
| ### Alpine Linux에서 | ||||
| @@ -279,6 +283,14 @@ pacman -S bat | ||||
| dnf install bat | ||||
| ``` | ||||
|  | ||||
| ### Funtoo Linux에서 | ||||
|  | ||||
| dev-kit을 통해 [`bat` 패키지](https://github.com/funtoo/dev-kit/tree/1.4-release/sys-apps/bat)를 설치할 수 있습니다:  | ||||
|  | ||||
| ```bash | ||||
| emerge sys-apps/bat | ||||
| ``` | ||||
|  | ||||
| ### Gentoo Linux에서 | ||||
|  | ||||
| 공식 소스를 통해 | ||||
| @@ -404,7 +416,7 @@ scoop install bat | ||||
|  | ||||
| ### 소스에서 | ||||
|  | ||||
| `bat`의 소스를 빌드하기 위해서는, Rust 1.45 이상이 필요합니다. | ||||
| `bat`의 소스를 빌드하기 위해서는, Rust 1.46 이상이 필요합니다. | ||||
| `cargo`를 이용해 전부 빌드할 수 있습니다: | ||||
|  | ||||
| ```bash | ||||
| @@ -663,7 +675,7 @@ bat --generate-config-file | ||||
| # 터미널에서 이탤릭체 쓰기 (일부 터미널에서 미지원) | ||||
| --italic-text=always | ||||
|  | ||||
| # .ino 파일에 C++ 문법 쓰기 | ||||
| # Arduino .ino 파일에 C++ 문법 쓰기 | ||||
| --map-syntax "*.ino:C++" | ||||
| ``` | ||||
|  | ||||
| @@ -797,6 +809,10 @@ cargo install --locked --force | ||||
| - [keith-hall](https://github.com/keith-hall) | ||||
| - [Enselic](https://github.com/Enselic) | ||||
|  | ||||
| ## 보안 취약점 | ||||
|  | ||||
| 만약 `bat`의 취약점을 발견하였다면, [David Peter](https://david-peter.de/)에게 메일로 연락주시기 바랍니다.  | ||||
|  | ||||
| ## 프로젝트 목표와 대안들 | ||||
|  | ||||
| `bat`은 다음과 같은 목표를 달성하려고 합니다: | ||||
|   | ||||
| @@ -1,7 +1,6 @@ | ||||
| <p align="center"> | ||||
|   <img src="doc/logo-header.svg" alt="bat - a cat clone with wings"><br> | ||||
|   <a href="https://travis-ci.org/sharkdp/bat"><img src="https://travis-ci.org/sharkdp/bat.svg?branch=master" alt="Build Status"></a> | ||||
|   <a href="https://ci.appveyor.com/project/sharkdp/bat"><img src="https://ci.appveyor.com/api/projects/status/cptsmtbiwbnr2vhf/branch/master?svg=true"></a> | ||||
|   <img src="logo-header.svg" alt="bat - a cat clone with wings"><br> | ||||
|   <a href="https://github.com/sharkdp/bat/actions?query=workflow%3ACICD"><img src="https://github.com/sharkdp/bat/workflows/CICD/badge.svg" alt="Build Status"></a> | ||||
|   <img src="https://img.shields.io/crates/l/bat.svg" alt="license"> | ||||
|   <a href="https://crates.io/crates/bat"><img src="https://img.shields.io/crates/v/bat.svg?colorB=319e8c" alt="Version info"></a><br> | ||||
|   Клон утилиты <i>cat(1)</i> с поддержкой выделения синтаксиса и Git | ||||
| @@ -12,8 +11,12 @@ | ||||
|   <a href="#как-использовать">Использование</a> • | ||||
|   <a href="#установка">Установка</a> • | ||||
|   <a href="#кастомизация">Кастомизация</a> • | ||||
|   <a href="#цели-и-альтернативы">Цели и альтернативы </a> • | ||||
|   Перевод [<a href="https://github.com/chinanf-boy/bat-zh">中文</a>][<a href="doc/README-ja.md">日本語</a>][<a href="doc/README-ko.md">한국어</a>][<a href="doc/README-ru.md">Русский</a>] | ||||
|   <a href="#цели-и-альтернативы">Цели и альтернативы </a><br> | ||||
|   [<a href="../README.md">English] | ||||
|   [<a href="https://github.com/chinanf-boy/bat-zh">中文</a>] | ||||
|   [<a href="README-ja.md">日本語</a>] | ||||
|   [<a href="README-ko.md">한국어</a>] | ||||
|   [Русский] | ||||
| </p> | ||||
|  | ||||
| ### Выделение синтаксиса | ||||
| @@ -185,7 +188,7 @@ ln -s /usr/bin/batcat ~/.local/bin/bat | ||||
| [release page](https://github.com/sharkdp/bat/releases) и установить так: | ||||
|  | ||||
| ```bash | ||||
| sudo dpkg -i bat_0.18.2_amd64.deb  # измените архитектуру и версию | ||||
| sudo dpkg -i bat_0.18.3_amd64.deb  # измените архитектуру и версию | ||||
| ``` | ||||
|  | ||||
| ### Alpine Linux | ||||
| @@ -341,7 +344,7 @@ ansible-galaxy install aeimer.install_bat | ||||
|  | ||||
| ### Из исходников | ||||
|  | ||||
| Если вы желаете установить `bat` из исходников, вам понадобится Rust 1.45 или выше. После этого используйте `cargo`, чтобы все скомпилировать: | ||||
| Если вы желаете установить `bat` из исходников, вам понадобится Rust 1.46 или выше. После этого используйте `cargo`, чтобы все скомпилировать: | ||||
|  | ||||
| ```bash | ||||
| cargo install --locked bat | ||||
| @@ -481,7 +484,7 @@ bat --generate-config-file | ||||
| # Использовать курсив (поддерживается не всеми терминалами) | ||||
| --italic-text=always | ||||
|  | ||||
| # Использовать синтаксис C++ для всех .ino файлов | ||||
| # Использовать синтаксис C++ для всех Arduino .ino файлов | ||||
| --map-syntax "*.ino:C++" | ||||
|  | ||||
| # Использовать синтаксик Git Ignore для всех файлов .ignore | ||||
|   | ||||
| @@ -45,7 +45,7 @@ See this page for a good overview: https://deps.rs/repo/github/sharkdp/bat | ||||
|  | ||||
| ## Release | ||||
|  | ||||
| - [ ] Create a tag and push it to the remote `git tag vX.Y.Z; git push --tags`. | ||||
| - [ ] Create a tag and push it: `git tag vX.Y.Z; git push origin tag vX.Y.Z`. | ||||
|       This will trigger the deployment via GitHub Actions. | ||||
| - [ ] Go to https://github.com/sharkdp/bat/releases/new to create the new | ||||
|       release. Select the new tag and also use it as the release title. For the | ||||
|   | ||||
							
								
								
									
										469
									
								
								src/assets.rs
									
									
									
									
									
								
							
							
						
						
									
										469
									
								
								src/assets.rs
									
									
									
									
									
								
							| @@ -1,10 +1,9 @@ | ||||
| use std::ffi::OsStr; | ||||
| use std::fs; | ||||
| use std::path::{Path, PathBuf}; | ||||
| use std::path::Path; | ||||
|  | ||||
| use lazycell::LazyCell; | ||||
|  | ||||
| use syntect::dumps::{from_binary, from_reader}; | ||||
| use syntect::highlighting::{Theme, ThemeSet}; | ||||
| use syntect::parsing::{SyntaxReference, SyntaxSet}; | ||||
|  | ||||
| @@ -12,13 +11,30 @@ use path_abs::PathAbs; | ||||
|  | ||||
| use crate::bat_warning; | ||||
| use crate::error::*; | ||||
| use crate::input::{InputReader, OpenedInput, OpenedInputKind}; | ||||
| use crate::input::{InputReader, OpenedInput}; | ||||
| use crate::syntax_mapping::{MappingTarget, SyntaxMapping}; | ||||
|  | ||||
| use ignored_suffixes::*; | ||||
| use minimal_assets::*; | ||||
| use serialized_syntax_set::*; | ||||
|  | ||||
| #[cfg(feature = "build-assets")] | ||||
| pub use crate::assets::build_assets::*; | ||||
|  | ||||
| pub(crate) mod assets_metadata; | ||||
| #[cfg(feature = "build-assets")] | ||||
| mod build_assets; | ||||
| mod ignored_suffixes; | ||||
| mod minimal_assets; | ||||
| mod serialized_syntax_set; | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub struct HighlightingAssets { | ||||
|     syntax_set_cell: LazyCell<SyntaxSet>, | ||||
|     serialized_syntax_set: Option<SerializedSyntaxSet>, | ||||
|     serialized_syntax_set: SerializedSyntaxSet, | ||||
|  | ||||
|     minimal_assets: MinimalAssets, | ||||
|  | ||||
|     theme_set: ThemeSet, | ||||
|     fallback_theme: Option<&'static str>, | ||||
| } | ||||
| @@ -29,39 +45,33 @@ pub struct SyntaxReferenceInSet<'a> { | ||||
|     pub syntax_set: &'a SyntaxSet, | ||||
| } | ||||
|  | ||||
| const IGNORED_SUFFIXES: [&str; 10] = [ | ||||
|     // Editor etc backups | ||||
|     "~", | ||||
|     ".bak", | ||||
|     ".old", | ||||
|     ".orig", | ||||
|     // Debian and derivatives apt/dpkg backups | ||||
|     ".dpkg-dist", | ||||
|     ".dpkg-old", | ||||
|     // Red Hat and derivatives rpm backups | ||||
|     ".rpmnew", | ||||
|     ".rpmorig", | ||||
|     ".rpmsave", | ||||
|     // Build system input/template files | ||||
|     ".in", | ||||
| ]; | ||||
| /// Compress for size of ~700 kB instead of ~4600 kB at the cost of ~30% longer deserialization time | ||||
| pub(crate) const COMPRESS_SYNTAXES: bool = true; | ||||
|  | ||||
| /// Compress for size of ~20 kB instead of ~200 kB at the cost of ~30% longer deserialization time | ||||
| pub(crate) const COMPRESS_THEMES: bool = true; | ||||
|  | ||||
| /// Compress for size of ~400 kB instead of ~2100 kB at the cost of ~30% longer deserialization time | ||||
| pub(crate) const COMPRESS_SERIALIZED_MINIMAL_SYNTAXES: bool = true; | ||||
|  | ||||
| /// Whether or not to compress the serialized form of [MinimalSyntaxes]. Shall | ||||
| /// always be `false`, because the data in | ||||
| /// [MinimalSyntaxes.serialized_syntax_sets] has already been compressed | ||||
| /// (assuming [COMPRESS_SERIALIZED_MINIMAL_SYNTAXES] is `true`). The "outer" data | ||||
| /// structures like `by_name` are tiny. If we compress, deserialization can't do | ||||
| /// efficient byte-by-byte copy of `serialized_syntax_sets`. | ||||
| pub(crate) const COMPRESS_MINIMAL_SYNTAXES: bool = false; | ||||
|  | ||||
| impl HighlightingAssets { | ||||
|     fn new( | ||||
|         syntax_set: Option<SyntaxSet>, | ||||
|         serialized_syntax_set: Option<SerializedSyntaxSet>, | ||||
|         serialized_syntax_set: SerializedSyntaxSet, | ||||
|         minimal_syntaxes: MinimalSyntaxes, | ||||
|         theme_set: ThemeSet, | ||||
|     ) -> Self { | ||||
|         assert!(syntax_set.is_some() || serialized_syntax_set.is_some()); | ||||
|  | ||||
|         let syntax_set_cell = LazyCell::new(); | ||||
|         if let Some(syntax_set) = syntax_set { | ||||
|             syntax_set_cell.fill(syntax_set).expect("can never fail"); | ||||
|         } | ||||
|  | ||||
|         HighlightingAssets { | ||||
|             syntax_set_cell, | ||||
|             syntax_set_cell: LazyCell::new(), | ||||
|             serialized_syntax_set, | ||||
|             minimal_assets: MinimalAssets::new(minimal_syntaxes), | ||||
|             theme_set, | ||||
|             fallback_theme: None, | ||||
|         } | ||||
| @@ -71,127 +81,33 @@ impl HighlightingAssets { | ||||
|         "Monokai Extended" | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "build-assets")] | ||||
|     pub fn from_files(source_dir: &Path, include_integrated_assets: bool) -> Result<Self> { | ||||
|         let mut theme_set = if include_integrated_assets { | ||||
|             get_integrated_themeset() | ||||
|         } else { | ||||
|             ThemeSet::new() | ||||
|         }; | ||||
|  | ||||
|         let theme_dir = source_dir.join("themes"); | ||||
|         if theme_dir.exists() { | ||||
|             let res = theme_set.add_from_folder(&theme_dir); | ||||
|             if let Err(err) = res { | ||||
|                 println!( | ||||
|                     "Failed to load one or more themes from '{}' (reason: '{}')", | ||||
|                     theme_dir.to_string_lossy(), | ||||
|                     err, | ||||
|                 ); | ||||
|             } | ||||
|         } else { | ||||
|             println!( | ||||
|                 "No themes were found in '{}', using the default set", | ||||
|                 theme_dir.to_string_lossy() | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         let mut syntax_set_builder = if !include_integrated_assets { | ||||
|             let mut builder = syntect::parsing::SyntaxSetBuilder::new(); | ||||
|             builder.add_plain_text_syntax(); | ||||
|             builder | ||||
|         } else { | ||||
|             from_binary::<SyntaxSet>(get_serialized_integrated_syntaxset()).into_builder() | ||||
|         }; | ||||
|  | ||||
|         let syntax_dir = source_dir.join("syntaxes"); | ||||
|         if syntax_dir.exists() { | ||||
|             syntax_set_builder.add_from_folder(syntax_dir, true)?; | ||||
|         } else { | ||||
|             println!( | ||||
|                 "No syntaxes were found in '{}', using the default set.", | ||||
|                 syntax_dir.to_string_lossy() | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         if std::env::var("BAT_PRINT_SYNTAX_DEPENDENCIES").is_ok() { | ||||
|             // To trigger this code, run: | ||||
|             // BAT_PRINT_SYNTAX_DEPENDENCIES=1 cargo run -- cache --build --source assets --blank --target /tmp | ||||
|             crate::syntax_dependencies::print_syntax_dependencies(&syntax_set_builder); | ||||
|         } | ||||
|  | ||||
|         let syntax_set = syntax_set_builder.build(); | ||||
|         let missing_contexts = syntax_set.find_unlinked_contexts(); | ||||
|         if !missing_contexts.is_empty() { | ||||
|             println!("Some referenced contexts could not be found!"); | ||||
|             for context in missing_contexts { | ||||
|                 println!("- {}", context); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         Ok(HighlightingAssets::new(Some(syntax_set), None, theme_set)) | ||||
|     } | ||||
|  | ||||
|     pub fn from_cache(cache_path: &Path) -> Result<Self> { | ||||
|         Ok(HighlightingAssets::new( | ||||
|             None, | ||||
|             Some(SerializedSyntaxSet::FromFile( | ||||
|                 cache_path.join("syntaxes.bin"), | ||||
|             )), | ||||
|             asset_from_cache(&cache_path.join("themes.bin"), "theme set")?, | ||||
|             SerializedSyntaxSet::FromFile(cache_path.join("syntaxes.bin")), | ||||
|             asset_from_cache( | ||||
|                 &cache_path.join("minimal_syntaxes.bin"), | ||||
|                 "minimal syntax sets", | ||||
|                 COMPRESS_MINIMAL_SYNTAXES, | ||||
|             )?, | ||||
|             asset_from_cache(&cache_path.join("themes.bin"), "theme set", COMPRESS_THEMES)?, | ||||
|         )) | ||||
|     } | ||||
|  | ||||
|     pub fn from_binary() -> Self { | ||||
|         HighlightingAssets::new( | ||||
|             None, | ||||
|             Some(SerializedSyntaxSet::FromBinary( | ||||
|                 get_serialized_integrated_syntaxset(), | ||||
|             )), | ||||
|             SerializedSyntaxSet::FromBinary(get_serialized_integrated_syntaxset()), | ||||
|             get_integrated_minimal_syntaxes(), | ||||
|             get_integrated_themeset(), | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "build-assets")] | ||||
|     pub fn save_to_cache(&self, target_dir: &Path, current_version: &str) -> Result<()> { | ||||
|         let _ = fs::create_dir_all(target_dir); | ||||
|         asset_to_cache( | ||||
|             self.get_theme_set(), | ||||
|             &target_dir.join("themes.bin"), | ||||
|             "theme set", | ||||
|         )?; | ||||
|         asset_to_cache( | ||||
|             self.get_syntax_set()?, | ||||
|             &target_dir.join("syntaxes.bin"), | ||||
|             "syntax set", | ||||
|         )?; | ||||
|  | ||||
|         print!( | ||||
|             "Writing metadata to folder {} ... ", | ||||
|             target_dir.to_string_lossy() | ||||
|         ); | ||||
|         crate::assets_metadata::AssetsMetadata::new(current_version).save_to_folder(target_dir)?; | ||||
|         println!("okay"); | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     pub fn set_fallback_theme(&mut self, theme: &'static str) { | ||||
|         self.fallback_theme = Some(theme); | ||||
|     } | ||||
|  | ||||
|     pub(crate) fn get_syntax_set(&self) -> Result<&SyntaxSet> { | ||||
|         if !self.syntax_set_cell.filled() { | ||||
|             self.syntax_set_cell.fill( | ||||
|                 self.serialized_syntax_set | ||||
|                 .as_ref() | ||||
|                 .expect("a dev forgot to setup serialized_syntax_set, please report to https://github.com/sharkdp/bat/issues") | ||||
|                 .deserialize()? | ||||
|              ).unwrap(); | ||||
|         } | ||||
|  | ||||
|         // It is safe to .unwrap() because we just made sure it was .filled() | ||||
|         Ok(self.syntax_set_cell.borrow().unwrap()) | ||||
|         self.syntax_set_cell | ||||
|             .try_borrow_with(|| self.serialized_syntax_set.deserialize()) | ||||
|     } | ||||
|  | ||||
|     /// Use [Self::get_syntaxes] instead | ||||
| @@ -214,36 +130,68 @@ impl HighlightingAssets { | ||||
|         self.get_theme_set().themes.keys().map(|s| s.as_ref()) | ||||
|     } | ||||
|  | ||||
|     /// Use [Self::get_syntax_for_file_name] instead | ||||
|     /// Finds a [SyntaxSet] that contains a [SyntaxReference] by its name. First | ||||
|     /// tries to find a minimal [SyntaxSet]. If none is found, returns the | ||||
|     /// [SyntaxSet] that contains all syntaxes. | ||||
|     fn get_syntax_set_by_name(&self, name: &str) -> Result<&SyntaxSet> { | ||||
|         match self.minimal_assets.get_syntax_set_by_name(name) { | ||||
|             Some(syntax_set) => Ok(syntax_set), | ||||
|             None => self.get_syntax_set(), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Use [Self::get_syntax_for_path] instead | ||||
|     #[deprecated] | ||||
|     pub fn syntax_for_file_name( | ||||
|         &self, | ||||
|         file_name: impl AsRef<Path>, | ||||
|         mapping: &SyntaxMapping, | ||||
|     ) -> Option<&SyntaxReference> { | ||||
|         self.get_syntax_for_file_name(file_name, mapping) | ||||
|             .expect( | ||||
|                 ".syntax_for_file_name() is deprecated, use .get_syntax_for_file_name() instead", | ||||
|             ) | ||||
|         self.get_syntax_for_path(file_name, mapping) | ||||
|             .ok() | ||||
|             .map(|syntax_in_set| syntax_in_set.syntax) | ||||
|     } | ||||
|  | ||||
|     pub fn get_syntax_for_file_name( | ||||
|     /// Detect the syntax based on, in order: | ||||
|     ///  1. Syntax mappings (e.g. `/etc/profile` -> `Bourne Again Shell (bash)`) | ||||
|     ///  2. The file name (e.g. `Dockerfile`) | ||||
|     ///  3. The file name extension (e.g. `.rs`) | ||||
|     /// | ||||
|     /// When detecting syntax based on syntax mappings, the full path is taken | ||||
|     /// into account. When detecting syntax based on file name, no regard is | ||||
|     /// taken to the path of the file. Only the file name itself matters. When | ||||
|     /// detecting syntax based on file name extension, only the file name | ||||
|     /// extension itself matters. | ||||
|     /// | ||||
|     /// Returns [Error::UndetectedSyntax] if it was not possible detect syntax | ||||
|     /// based on path/file name/extension (or if the path was mapped to | ||||
|     /// [MappingTarget::MapToUnknown]). In this case it is appropriate to fall | ||||
|     /// back to other methods to detect syntax. Such as using the contents of | ||||
|     /// the first line of the file. | ||||
|     /// | ||||
|     /// Returns [Error::UnknownSyntax] if a syntax mapping exist, but the mapped | ||||
|     /// syntax does not exist. | ||||
|     pub fn get_syntax_for_path( | ||||
|         &self, | ||||
|         file_name: impl AsRef<Path>, | ||||
|         path: impl AsRef<Path>, | ||||
|         mapping: &SyntaxMapping, | ||||
|     ) -> Result<Option<SyntaxReferenceInSet>> { | ||||
|         let file_name = file_name.as_ref(); | ||||
|         Ok(match mapping.get_syntax_for(file_name) { | ||||
|             Some(MappingTarget::MapToUnknown) => None, | ||||
|             Some(MappingTarget::MapTo(syntax_name)) => { | ||||
|                 let syntax_set = self.get_syntax_set()?; | ||||
|                 syntax_set | ||||
|                     .find_syntax_by_name(syntax_name) | ||||
|                     .map(|syntax| SyntaxReferenceInSet { syntax, syntax_set }) | ||||
|     ) -> Result<SyntaxReferenceInSet> { | ||||
|         let path = path.as_ref(); | ||||
|         match mapping.get_syntax_for(path) { | ||||
|             Some(MappingTarget::MapToUnknown) => { | ||||
|                 Err(Error::UndetectedSyntax(path.to_string_lossy().into())) | ||||
|             } | ||||
|             None => self.get_extension_syntax(file_name.as_os_str())?, | ||||
|         }) | ||||
|  | ||||
|             Some(MappingTarget::MapTo(syntax_name)) => self | ||||
|                 .find_syntax_by_name(syntax_name)? | ||||
|                 .ok_or_else(|| Error::UnknownSyntax(syntax_name.to_owned())), | ||||
|  | ||||
|             None => { | ||||
|                 let file_name = path.file_name().unwrap_or_default(); | ||||
|                 self.get_extension_syntax(file_name)? | ||||
|                     .ok_or_else(|| Error::UndetectedSyntax(path.to_string_lossy().into())) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub(crate) fn get_theme(&self, theme: &str) -> &Theme { | ||||
| @@ -270,113 +218,60 @@ impl HighlightingAssets { | ||||
|         mapping: &SyntaxMapping, | ||||
|     ) -> Result<SyntaxReferenceInSet> { | ||||
|         if let Some(language) = language { | ||||
|             let syntax_set = self.get_syntax_set()?; | ||||
|             syntax_set | ||||
|             let syntax_set = self.get_syntax_set_by_name(language)?; | ||||
|             return syntax_set | ||||
|                 .find_syntax_by_token(language) | ||||
|                 .map(|syntax| SyntaxReferenceInSet { syntax, syntax_set }) | ||||
|                 .ok_or_else(|| ErrorKind::UnknownSyntax(language.to_owned()).into()) | ||||
|         } else { | ||||
|             let line_syntax = self.get_first_line_syntax(&mut input.reader)?; | ||||
|  | ||||
|             // Get the path of the file: | ||||
|             // If this was set by the metadata, that will take priority. | ||||
|             // If it wasn't, it will use the real file path (if available). | ||||
|             let path_str = | ||||
|                 input | ||||
|                     .metadata | ||||
|                     .user_provided_name | ||||
|                     .as_ref() | ||||
|                     .or_else(|| match input.kind { | ||||
|                         OpenedInputKind::OrdinaryFile(ref path) => Some(path), | ||||
|                         _ => None, | ||||
|                     }); | ||||
|  | ||||
|             if let Some(path_str) = path_str { | ||||
|                 // If a path was provided, we try and detect the syntax based on extension mappings. | ||||
|                 let path = Path::new(path_str); | ||||
|                 let absolute_path = PathAbs::new(path) | ||||
|                     .ok() | ||||
|                     .map(|p| p.as_path().to_path_buf()) | ||||
|                     .unwrap_or_else(|| path.to_owned()); | ||||
|  | ||||
|                 match mapping.get_syntax_for(absolute_path) { | ||||
|                     Some(MappingTarget::MapToUnknown) => line_syntax.ok_or_else(|| { | ||||
|                         ErrorKind::UndetectedSyntax(path.to_string_lossy().into()).into() | ||||
|                     }), | ||||
|  | ||||
|                     Some(MappingTarget::MapTo(syntax_name)) => { | ||||
|                         let syntax_set = self.get_syntax_set()?; | ||||
|                         syntax_set | ||||
|                             .find_syntax_by_name(syntax_name) | ||||
|                             .map(|syntax| SyntaxReferenceInSet { syntax, syntax_set }) | ||||
|                             .ok_or_else(|| ErrorKind::UnknownSyntax(syntax_name.to_owned()).into()) | ||||
|                     } | ||||
|  | ||||
|                     None => { | ||||
|                         let file_name = path.file_name().unwrap_or_default(); | ||||
|                         self.get_extension_syntax(file_name)? | ||||
|                             .or(line_syntax) | ||||
|                             .ok_or_else(|| { | ||||
|                                 ErrorKind::UndetectedSyntax(path.to_string_lossy().into()).into() | ||||
|                             }) | ||||
|                     } | ||||
|                 } | ||||
|             } else { | ||||
|                 // If a path wasn't provided, we fall back to the detect first-line syntax. | ||||
|                 line_syntax.ok_or_else(|| ErrorKind::UndetectedSyntax("[unknown]".into()).into()) | ||||
|             } | ||||
|                 .ok_or_else(|| Error::UnknownSyntax(language.to_owned())); | ||||
|         } | ||||
|  | ||||
|         let path = input.path(); | ||||
|         let path_syntax = if let Some(path) = path { | ||||
|             self.get_syntax_for_path( | ||||
|                 PathAbs::new(path).map_or_else(|_| path.to_owned(), |p| p.as_path().to_path_buf()), | ||||
|                 mapping, | ||||
|             ) | ||||
|         } else { | ||||
|             Err(Error::UndetectedSyntax("[unknown]".into())) | ||||
|         }; | ||||
|  | ||||
|         match path_syntax { | ||||
|             // If a path wasn't provided, or if path based syntax detection | ||||
|             // above failed, we fall back to first-line syntax detection. | ||||
|             Err(Error::UndetectedSyntax(path)) => self | ||||
|                 .get_first_line_syntax(&mut input.reader)? | ||||
|                 .ok_or(Error::UndetectedSyntax(path)), | ||||
|             _ => path_syntax, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub(crate) fn find_syntax_by_name( | ||||
|         &self, | ||||
|         syntax_name: &str, | ||||
|     ) -> Result<Option<SyntaxReferenceInSet>> { | ||||
|         let syntax_set = self.get_syntax_set()?; | ||||
|         Ok(syntax_set | ||||
|             .find_syntax_by_name(syntax_name) | ||||
|             .map(|syntax| SyntaxReferenceInSet { syntax, syntax_set })) | ||||
|     } | ||||
|  | ||||
|     fn find_syntax_by_extension(&self, e: Option<&OsStr>) -> Result<Option<SyntaxReferenceInSet>> { | ||||
|         let syntax_set = self.get_syntax_set()?; | ||||
|         let extension = e.and_then(|x| x.to_str()).unwrap_or_default(); | ||||
|         Ok(syntax_set | ||||
|             .find_syntax_by_extension(extension) | ||||
|             .map(|syntax| SyntaxReferenceInSet { syntax, syntax_set })) | ||||
|     } | ||||
|  | ||||
|     fn get_extension_syntax(&self, file_name: &OsStr) -> Result<Option<SyntaxReferenceInSet>> { | ||||
|         let mut syntax = self.find_syntax_by_file_name(file_name)?; | ||||
|         let mut syntax = self.find_syntax_by_extension(Some(file_name))?; | ||||
|         if syntax.is_none() { | ||||
|             syntax = self.find_syntax_by_file_name_extension(file_name)?; | ||||
|             syntax = self.find_syntax_by_extension(Path::new(file_name).extension())?; | ||||
|         } | ||||
|         if syntax.is_none() { | ||||
|             syntax = self.get_extension_syntax_with_stripped_suffix(file_name)?; | ||||
|         } | ||||
|         Ok(syntax) | ||||
|     } | ||||
|  | ||||
|     fn find_syntax_by_file_name(&self, file_name: &OsStr) -> Result<Option<SyntaxReferenceInSet>> { | ||||
|         let syntax_set = self.get_syntax_set()?; | ||||
|         Ok(syntax_set | ||||
|             .find_syntax_by_extension(file_name.to_str().unwrap_or_default()) | ||||
|             .map(|syntax| SyntaxReferenceInSet { syntax, syntax_set })) | ||||
|     } | ||||
|  | ||||
|     fn find_syntax_by_file_name_extension( | ||||
|         &self, | ||||
|         file_name: &OsStr, | ||||
|     ) -> Result<Option<SyntaxReferenceInSet>> { | ||||
|         let file_path = Path::new(file_name); | ||||
|         let syntax_set = self.get_syntax_set()?; | ||||
|         Ok(syntax_set | ||||
|             .find_syntax_by_extension( | ||||
|                 file_path | ||||
|                     .extension() | ||||
|                     .and_then(|x| x.to_str()) | ||||
|                     .unwrap_or_default(), | ||||
|             ) | ||||
|             .map(|syntax| SyntaxReferenceInSet { syntax, syntax_set })) | ||||
|     } | ||||
|  | ||||
|     /// If we find an ignored suffix on the file name, e.g. '~', we strip it and | ||||
|     /// then try again to find a syntax without it. Note that we do this recursively. | ||||
|     fn get_extension_syntax_with_stripped_suffix( | ||||
|         &self, | ||||
|         file_name: &OsStr, | ||||
|     ) -> Result<Option<SyntaxReferenceInSet>> { | ||||
|         let file_path = Path::new(file_name); | ||||
|         let mut syntax = None; | ||||
|         if let Some(file_str) = file_path.to_str() { | ||||
|             for suffix in IGNORED_SUFFIXES.iter() { | ||||
|                 if let Some(stripped_filename) = file_str.strip_suffix(suffix) { | ||||
|                     syntax = self.get_extension_syntax(OsStr::new(stripped_filename))?; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|             syntax = try_with_stripped_suffix(file_name, |stripped_file_name| { | ||||
|                 self.get_extension_syntax(stripped_file_name) // Note: recursion | ||||
|             })?; | ||||
|         } | ||||
|         Ok(syntax) | ||||
|     } | ||||
| @@ -393,57 +288,53 @@ impl HighlightingAssets { | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// A SyntaxSet in serialized form, i.e. bincoded and flate2 compressed. | ||||
| /// We keep it in this format since we want to load it lazily. | ||||
| #[derive(Debug)] | ||||
| enum SerializedSyntaxSet { | ||||
|     /// The data comes from a user-generated cache file. | ||||
|     FromFile(PathBuf), | ||||
|  | ||||
|     /// The data to use is embedded into the bat binary. | ||||
|     FromBinary(&'static [u8]), | ||||
| } | ||||
|  | ||||
| impl SerializedSyntaxSet { | ||||
|     fn deserialize(&self) -> Result<SyntaxSet> { | ||||
|         match self { | ||||
|             SerializedSyntaxSet::FromBinary(data) => Ok(from_binary(data)), | ||||
|             SerializedSyntaxSet::FromFile(ref path) => asset_from_cache(path, "syntax set"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn get_serialized_integrated_syntaxset() -> &'static [u8] { | ||||
| pub(crate) fn get_serialized_integrated_syntaxset() -> &'static [u8] { | ||||
|     include_bytes!("../assets/syntaxes.bin") | ||||
| } | ||||
|  | ||||
| fn get_integrated_themeset() -> ThemeSet { | ||||
|     from_binary(include_bytes!("../assets/themes.bin")) | ||||
| pub(crate) fn get_integrated_themeset() -> ThemeSet { | ||||
|     from_binary(include_bytes!("../assets/themes.bin"), COMPRESS_THEMES) | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "build-assets")] | ||||
| fn asset_to_cache<T: serde::Serialize>(asset: &T, path: &Path, description: &str) -> Result<()> { | ||||
|     print!("Writing {} to {} ... ", description, path.to_string_lossy()); | ||||
|     syntect::dumps::dump_to_file(asset, &path).chain_err(|| { | ||||
|         format!( | ||||
|             "Could not save {} to {}", | ||||
|             description, | ||||
|             path.to_string_lossy() | ||||
|         ) | ||||
|     })?; | ||||
|     println!("okay"); | ||||
|     Ok(()) | ||||
| fn get_integrated_minimal_syntaxes() -> MinimalSyntaxes { | ||||
|     from_binary( | ||||
|         include_bytes!("../assets/minimal_syntaxes.bin"), | ||||
|         COMPRESS_MINIMAL_SYNTAXES, | ||||
|     ) | ||||
| } | ||||
|  | ||||
| fn asset_from_cache<T: serde::de::DeserializeOwned>(path: &Path, description: &str) -> Result<T> { | ||||
|     let contents = fs::read(path).chain_err(|| { | ||||
| pub(crate) fn from_binary<T: serde::de::DeserializeOwned>(v: &[u8], compressed: bool) -> T { | ||||
|     asset_from_contents(v, "n/a", compressed) | ||||
|         .expect("data integrated in binary is never faulty, but make sure `compressed` is in sync!") | ||||
| } | ||||
|  | ||||
| fn asset_from_contents<T: serde::de::DeserializeOwned>( | ||||
|     contents: &[u8], | ||||
|     description: &str, | ||||
|     compressed: bool, | ||||
| ) -> Result<T> { | ||||
|     if compressed { | ||||
|         bincode::deserialize_from(flate2::read::ZlibDecoder::new(contents)) | ||||
|     } else { | ||||
|         bincode::deserialize_from(contents) | ||||
|     } | ||||
|     .map_err(|_| format!("Could not parse {}", description).into()) | ||||
| } | ||||
|  | ||||
| fn asset_from_cache<T: serde::de::DeserializeOwned>( | ||||
|     path: &Path, | ||||
|     description: &str, | ||||
|     compressed: bool, | ||||
| ) -> Result<T> { | ||||
|     let contents = fs::read(path).map_err(|_| { | ||||
|         format!( | ||||
|             "Could not load cached {} '{}'", | ||||
|             description, | ||||
|             path.to_string_lossy() | ||||
|         ) | ||||
|     })?; | ||||
|     from_reader(&contents[..]).chain_err(|| format!("Could not parse cached {}", description)) | ||||
|     asset_from_contents(&contents[..], description, compressed) | ||||
|         .map_err(|_| format!("Could not parse cached {}", description).into()) | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
|   | ||||
| @@ -52,16 +52,15 @@ impl AssetsMetadata { | ||||
|     pub fn load_from_folder(path: &Path) -> Result<Option<Self>> { | ||||
|         match Self::try_load_from_folder(path) { | ||||
|             Ok(metadata) => Ok(Some(metadata)), | ||||
|             Err(e) => match e.kind() { | ||||
|                 ErrorKind::SerdeYamlError(_) => Err(e), | ||||
|                 _ => { | ||||
|                     if path.join("syntaxes.bin").exists() || path.join("themes.bin").exists() { | ||||
|                         Ok(Some(Self::default())) | ||||
|                     } else { | ||||
|                         Ok(None) | ||||
|                     } | ||||
|             Err(e) => { | ||||
|                 if let Error::SerdeYamlError(_) = e { | ||||
|                     Err(e) | ||||
|                 } else if path.join("syntaxes.bin").exists() || path.join("themes.bin").exists() { | ||||
|                     Ok(Some(Self::default())) | ||||
|                 } else { | ||||
|                     Ok(None) | ||||
|                 } | ||||
|             }, | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
							
								
								
									
										500
									
								
								src/assets/build_assets.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										500
									
								
								src/assets/build_assets.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,500 @@ | ||||
| use std::collections::HashMap; | ||||
| use std::path::Path; | ||||
| use syntect::highlighting::ThemeSet; | ||||
| use syntect::parsing::syntax_definition::{ | ||||
|     ContextReference, MatchOperation, MatchPattern, Pattern, SyntaxDefinition, | ||||
| }; | ||||
| use syntect::parsing::{Scope, SyntaxSet, SyntaxSetBuilder}; | ||||
|  | ||||
| use crate::assets::*; | ||||
|  | ||||
| mod graphviz_utils; | ||||
|  | ||||
| type SyntaxName = String; | ||||
|  | ||||
| /// Used to look up which [SyntaxDefinition] corresponds to a given [OtherSyntax] | ||||
| type OtherSyntaxLookup<'a> = HashMap<OtherSyntax, &'a SyntaxDefinition>; | ||||
|  | ||||
| /// Used to look up what dependencies a given [SyntaxDefinition] has | ||||
| type SyntaxToDependencies = HashMap<SyntaxName, Vec<OtherSyntax>>; | ||||
|  | ||||
| /// Used to look up what other [SyntaxDefinition]s depend on a given [SyntaxDefinition] | ||||
| type SyntaxToDependents<'a> = HashMap<SyntaxName, Vec<OtherSyntax>>; | ||||
|  | ||||
| /// Represents some other `*.sublime-syntax` file, i.e. another [SyntaxDefinition]. | ||||
| #[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Clone, Hash)] | ||||
| pub(crate) enum OtherSyntax { | ||||
|     /// By name. Example YAML: `include: C.sublime-syntax` (name is `"C"`) | ||||
|     ByName(String), | ||||
|  | ||||
|     /// By scope. Example YAML: `embed: scope:source.c` (scope is `"source.c"`) | ||||
|     ByScope(Scope), | ||||
| } | ||||
|  | ||||
| pub fn build( | ||||
|     source_dir: &Path, | ||||
|     include_integrated_assets: bool, | ||||
|     target_dir: &Path, | ||||
|     current_version: &str, | ||||
| ) -> Result<()> { | ||||
|     let theme_set = build_theme_set(source_dir, include_integrated_assets); | ||||
|  | ||||
|     let syntax_set_builder = build_syntax_set_builder(source_dir, include_integrated_assets)?; | ||||
|  | ||||
|     let minimal_syntaxes = build_minimal_syntaxes(&syntax_set_builder, include_integrated_assets)?; | ||||
|  | ||||
|     let syntax_set = syntax_set_builder.build(); | ||||
|  | ||||
|     print_unlinked_contexts(&syntax_set); | ||||
|  | ||||
|     write_assets( | ||||
|         &theme_set, | ||||
|         &syntax_set, | ||||
|         &minimal_syntaxes, | ||||
|         target_dir, | ||||
|         current_version, | ||||
|     ) | ||||
| } | ||||
|  | ||||
| fn build_theme_set(source_dir: &Path, include_integrated_assets: bool) -> ThemeSet { | ||||
|     let mut theme_set = if include_integrated_assets { | ||||
|         crate::assets::get_integrated_themeset() | ||||
|     } else { | ||||
|         ThemeSet::new() | ||||
|     }; | ||||
|  | ||||
|     let theme_dir = source_dir.join("themes"); | ||||
|     if theme_dir.exists() { | ||||
|         let res = theme_set.add_from_folder(&theme_dir); | ||||
|         if let Err(err) = res { | ||||
|             println!( | ||||
|                 "Failed to load one or more themes from '{}' (reason: '{}')", | ||||
|                 theme_dir.to_string_lossy(), | ||||
|                 err, | ||||
|             ); | ||||
|         } | ||||
|     } else { | ||||
|         println!( | ||||
|             "No themes were found in '{}', using the default set", | ||||
|             theme_dir.to_string_lossy() | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     theme_set | ||||
| } | ||||
|  | ||||
| fn build_syntax_set_builder( | ||||
|     source_dir: &Path, | ||||
|     include_integrated_assets: bool, | ||||
| ) -> Result<SyntaxSetBuilder> { | ||||
|     let mut syntax_set_builder = if !include_integrated_assets { | ||||
|         let mut builder = syntect::parsing::SyntaxSetBuilder::new(); | ||||
|         builder.add_plain_text_syntax(); | ||||
|         builder | ||||
|     } else { | ||||
|         from_binary::<SyntaxSet>(get_serialized_integrated_syntaxset(), COMPRESS_SYNTAXES) | ||||
|             .into_builder() | ||||
|     }; | ||||
|  | ||||
|     let syntax_dir = source_dir.join("syntaxes"); | ||||
|     if syntax_dir.exists() { | ||||
|         syntax_set_builder.add_from_folder(syntax_dir, true)?; | ||||
|     } else { | ||||
|         println!( | ||||
|             "No syntaxes were found in '{}', using the default set.", | ||||
|             syntax_dir.to_string_lossy() | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     Ok(syntax_set_builder) | ||||
| } | ||||
|  | ||||
| fn print_unlinked_contexts(syntax_set: &SyntaxSet) { | ||||
|     let missing_contexts = syntax_set.find_unlinked_contexts(); | ||||
|     if !missing_contexts.is_empty() { | ||||
|         println!("Some referenced contexts could not be found!"); | ||||
|         for context in missing_contexts { | ||||
|             println!("- {}", context); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn write_assets( | ||||
|     theme_set: &ThemeSet, | ||||
|     syntax_set: &SyntaxSet, | ||||
|     minimal_syntaxes: &MinimalSyntaxes, | ||||
|     target_dir: &Path, | ||||
|     current_version: &str, | ||||
| ) -> Result<()> { | ||||
|     let _ = std::fs::create_dir_all(target_dir); | ||||
|     asset_to_cache( | ||||
|         theme_set, | ||||
|         &target_dir.join("themes.bin"), | ||||
|         "theme set", | ||||
|         COMPRESS_THEMES, | ||||
|     )?; | ||||
|     asset_to_cache( | ||||
|         syntax_set, | ||||
|         &target_dir.join("syntaxes.bin"), | ||||
|         "syntax set", | ||||
|         COMPRESS_SYNTAXES, | ||||
|     )?; | ||||
|     asset_to_cache( | ||||
|         minimal_syntaxes, | ||||
|         &target_dir.join("minimal_syntaxes.bin"), | ||||
|         "minimal syntax sets", | ||||
|         COMPRESS_MINIMAL_SYNTAXES, | ||||
|     )?; | ||||
|  | ||||
|     print!( | ||||
|         "Writing metadata to folder {} ... ", | ||||
|         target_dir.to_string_lossy() | ||||
|     ); | ||||
|     crate::assets_metadata::AssetsMetadata::new(current_version).save_to_folder(target_dir)?; | ||||
|     println!("okay"); | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| fn print_syntax_set_names(syntax_set: &SyntaxSet) { | ||||
|     let names = syntax_set | ||||
|         .syntaxes() | ||||
|         .iter() | ||||
|         .map(|syntax| &syntax.name) | ||||
|         .collect::<Vec<_>>(); | ||||
|     println!("{:?}", names); | ||||
| } | ||||
|  | ||||
| fn build_minimal_syntaxes( | ||||
|     syntax_set_builder: &'_ SyntaxSetBuilder, | ||||
|     include_integrated_assets: bool, | ||||
| ) -> Result<MinimalSyntaxes> { | ||||
|     let mut minimal_syntaxes = MinimalSyntaxes { | ||||
|         by_name: HashMap::new(), | ||||
|         serialized_syntax_sets: vec![], | ||||
|     }; | ||||
|  | ||||
|     if include_integrated_assets { | ||||
|         // Dependency info is not present in integrated assets, so we can't | ||||
|         // calculate minimal syntax sets. Return early without any data filled | ||||
|         // in. This means that no minimal syntax sets will be available to use, and | ||||
|         // the full, slow-to-deserialize, fallback syntax set will be used instead. | ||||
|         return Ok(minimal_syntaxes); | ||||
|     } | ||||
|  | ||||
|     let minimal_syntax_sets_to_serialize = build_minimal_syntax_sets(syntax_set_builder) | ||||
|         // For now, only store syntax sets with one syntax, otherwise | ||||
|         // the binary grows by several megs | ||||
|         .filter(|syntax_set| syntax_set.syntaxes().len() == 1); | ||||
|  | ||||
|     for minimal_syntax_set in minimal_syntax_sets_to_serialize { | ||||
|         // Remember what index it is found at | ||||
|         let current_index = minimal_syntaxes.serialized_syntax_sets.len(); | ||||
|  | ||||
|         for syntax in minimal_syntax_set.syntaxes() { | ||||
|             minimal_syntaxes | ||||
|                 .by_name | ||||
|                 .insert(syntax.name.to_ascii_lowercase().clone(), current_index); | ||||
|         } | ||||
|  | ||||
|         let serialized_syntax_set = asset_to_contents( | ||||
|             &minimal_syntax_set, | ||||
|             &format!("failed to serialize minimal syntax set {}", current_index), | ||||
|             COMPRESS_SERIALIZED_MINIMAL_SYNTAXES, | ||||
|         )?; | ||||
|  | ||||
|         // Add last so that it ends up at `current_index` | ||||
|         minimal_syntaxes | ||||
|             .serialized_syntax_sets | ||||
|             .push(serialized_syntax_set); | ||||
|     } | ||||
|  | ||||
|     Ok(minimal_syntaxes) | ||||
| } | ||||
|  | ||||
| /// Analyzes dependencies between syntaxes in a [SyntaxSetBuilder]. | ||||
| /// From that, it builds minimal [SyntaxSet]s. | ||||
| fn build_minimal_syntax_sets( | ||||
|     syntax_set_builder: &'_ SyntaxSetBuilder, | ||||
| ) -> impl Iterator<Item = SyntaxSet> + '_ { | ||||
|     let syntaxes = syntax_set_builder.syntaxes(); | ||||
|  | ||||
|     // Build the data structures we need for dependency resolution | ||||
|     let (other_syntax_lookup, syntax_to_dependencies, syntax_to_dependents) = | ||||
|         generate_maps(syntaxes); | ||||
|  | ||||
|     maybe_write_syntax_dependencies_to_graphviz_dot_file( | ||||
|         &other_syntax_lookup, | ||||
|         &syntax_to_dependencies, | ||||
|     ); | ||||
|  | ||||
|     // Create one minimal SyntaxSet from each (non-hidden) SyntaxDefinition | ||||
|     syntaxes.iter().filter_map(move |syntax| { | ||||
|         if syntax.hidden { | ||||
|             return None; | ||||
|         } | ||||
|  | ||||
|         let mut builder = SyntaxSetDependencyBuilder::new(); | ||||
|         builder.add_with_dependencies( | ||||
|             syntax, | ||||
|             &other_syntax_lookup, | ||||
|             &syntax_to_dependencies, | ||||
|             &syntax_to_dependents, | ||||
|         ); | ||||
|         let syntax_set = builder.build(); | ||||
|  | ||||
|         if std::env::var("BAT_PRINT_SYNTAX_DEPENDENCIES").is_ok() { | ||||
|             // To trigger this code, run: | ||||
|             // BAT_PRINT_SYNTAX_DEPENDENCIES=1 cargo run -- cache --build --source assets --blank --target /tmp | ||||
|             print_syntax_set_names(&syntax_set); | ||||
|         } | ||||
|  | ||||
|         Some(syntax_set) | ||||
|     }) | ||||
| } | ||||
|  | ||||
| /// In order to analyze dependencies, we need three key pieces of data. | ||||
| /// | ||||
| ///  * When we have a [OtherSyntax], we need to know what [SyntaxDefinition] | ||||
| ///    that corresponds to | ||||
| ///  * When we have a [SyntaxDefinition], we need to know what dependencies it | ||||
| ///    has | ||||
| ///  * When we have a [SyntaxDefinition], we need to know what other syntaxes | ||||
| ///    depend on it | ||||
| /// | ||||
| /// This functions generates that data for each syntax. | ||||
| fn generate_maps( | ||||
|     syntaxes: &[SyntaxDefinition], | ||||
| ) -> (OtherSyntaxLookup, SyntaxToDependencies, SyntaxToDependents) { | ||||
|     let mut other_syntax_lookup = HashMap::new(); | ||||
|     let mut syntax_to_dependencies = HashMap::new(); | ||||
|     let mut syntax_to_dependents = HashMap::new(); | ||||
|  | ||||
|     for syntax in syntaxes { | ||||
|         other_syntax_lookup.insert(OtherSyntax::ByName(syntax.name.clone()), syntax); | ||||
|         other_syntax_lookup.insert(OtherSyntax::ByScope(syntax.scope), syntax); | ||||
|     } | ||||
|  | ||||
|     for syntax in syntaxes { | ||||
|         let dependencies = dependencies_for_syntax(syntax); | ||||
|  | ||||
|         for dependency in &dependencies { | ||||
|             if let Some(dependency) = other_syntax_lookup.get(dependency) { | ||||
|                 syntax_to_dependents | ||||
|                     .entry(dependency.name.clone()) | ||||
|                     .or_insert_with(Vec::new) | ||||
|                     .push(OtherSyntax::ByName(syntax.name.clone())); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         syntax_to_dependencies.insert(syntax.name.clone(), dependencies); | ||||
|     } | ||||
|  | ||||
|     ( | ||||
|         other_syntax_lookup, | ||||
|         syntax_to_dependencies, | ||||
|         syntax_to_dependents, | ||||
|     ) | ||||
| } | ||||
|  | ||||
| /// Gets what external dependencies a given [SyntaxDefinition] has. | ||||
| /// An external dependency is another `.sublime-syntax` file. | ||||
| /// It does that by looking for variants of the following YAML patterns: | ||||
| /// - `include: C.sublime-syntax` | ||||
| /// - `embed: scope:source.c` | ||||
| fn dependencies_for_syntax(syntax: &SyntaxDefinition) -> Vec<OtherSyntax> { | ||||
|     let mut dependencies: Vec<OtherSyntax> = syntax | ||||
|         .contexts | ||||
|         .values() | ||||
|         .flat_map(|context| &context.patterns) | ||||
|         .flat_map(dependencies_from_pattern) | ||||
|         .collect(); | ||||
|  | ||||
|     // No need to track a dependency more than once | ||||
|     dependencies.sort(); | ||||
|     dependencies.dedup(); | ||||
|  | ||||
|     dependencies | ||||
| } | ||||
|  | ||||
| fn dependencies_from_pattern(pattern: &Pattern) -> Vec<OtherSyntax> { | ||||
|     match *pattern { | ||||
|         Pattern::Match(MatchPattern { | ||||
|             operation: MatchOperation::Push(ref context_references), | ||||
|             .. | ||||
|         }) => context_references | ||||
|             .iter() | ||||
|             .map(dependency_from_context_reference) | ||||
|             .collect(), | ||||
|         Pattern::Include(ref context_reference) => { | ||||
|             vec![dependency_from_context_reference(context_reference)] | ||||
|         } | ||||
|         _ => vec![], | ||||
|     } | ||||
|     .into_iter() | ||||
|     .flatten() | ||||
|     .collect() | ||||
| } | ||||
|  | ||||
| /// To generate a Graphviz dot file of syntax dependencies, do this: | ||||
| /// ```bash | ||||
| /// sudo apt install graphviz | ||||
| /// BAT_SYNTAX_DEPENDENCIES_TO_GRAPHVIZ_DOT_FILE=/tmp/bat-syntax-dependencies.dot cargo run -- cache  --build --source assets --blank --target /tmp | ||||
| /// dot /tmp/bat-syntax-dependencies.dot -Tpng -o /tmp/bat-syntax-dependencies.png | ||||
| /// open /tmp/bat-syntax-dependencies.png | ||||
| /// ``` | ||||
| fn maybe_write_syntax_dependencies_to_graphviz_dot_file( | ||||
|     other_syntax_lookup: &OtherSyntaxLookup, | ||||
|     syntax_to_dependencies: &SyntaxToDependencies, | ||||
| ) { | ||||
|     if let Ok(dot_file_path) = std::env::var("BAT_SYNTAX_DEPENDENCIES_TO_GRAPHVIZ_DOT_FILE") { | ||||
|         graphviz_utils::try_syntax_dependencies_to_graphviz_dot_file( | ||||
|             other_syntax_lookup, | ||||
|             syntax_to_dependencies, | ||||
|             &dot_file_path, | ||||
|         ); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Removes any context name from the syntax reference. | ||||
| /// | ||||
| /// When we track dependencies between syntaxes, we are not interested in | ||||
| /// dependencies on specific contexts inside other syntaxes. We only care about | ||||
| /// the dependency on the syntax itself. | ||||
| /// | ||||
| /// For example, if a syntax includes another syntax like this: | ||||
| /// ```yaml | ||||
| ///   - include: scope:source.c++#unique-variables | ||||
| /// ``` | ||||
| /// we only want to track the dependency on `source.c++`. | ||||
| fn remove_explicit_context(scope: Scope) -> Scope { | ||||
|     if let Some(without_context) = scope.build_string().split('#').next() { | ||||
|         Scope::new(without_context).expect("removing context reference must never fail") | ||||
|     } else { | ||||
|         scope | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn dependency_from_context_reference(context_reference: &ContextReference) -> Option<OtherSyntax> { | ||||
|     match &context_reference { | ||||
|         ContextReference::File { ref name, .. } => Some(OtherSyntax::ByName(name.clone())), | ||||
|         ContextReference::ByScope { ref scope, .. } => { | ||||
|             Some(OtherSyntax::ByScope(remove_explicit_context(*scope))) | ||||
|         } | ||||
|         _ => None, | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Helper to construct a [SyntaxSetBuilder] that contains only [SyntaxDefinition]s | ||||
| /// that have dependencies among them. | ||||
| struct SyntaxSetDependencyBuilder { | ||||
|     syntax_set_builder: SyntaxSetBuilder, | ||||
| } | ||||
|  | ||||
| impl SyntaxSetDependencyBuilder { | ||||
|     fn new() -> Self { | ||||
|         SyntaxSetDependencyBuilder { | ||||
|             syntax_set_builder: SyntaxSetBuilder::new(), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Add a [SyntaxDefinition] to the underlying [SyntaxSetBuilder]. | ||||
|     /// Also resolve any dependencies it has and add those [SyntaxDefinition]s too. | ||||
|     /// This is a recursive process. | ||||
|     fn add_with_dependencies( | ||||
|         &mut self, | ||||
|         syntax: &SyntaxDefinition, | ||||
|         other_syntax_lookup: &OtherSyntaxLookup, | ||||
|         syntax_to_dependencies: &SyntaxToDependencies, | ||||
|         syntax_to_dependents: &SyntaxToDependents, | ||||
|     ) { | ||||
|         let name = &syntax.name; | ||||
|         if self.is_syntax_already_added(name) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         self.syntax_set_builder.add(syntax.clone()); | ||||
|  | ||||
|         let mut syntaxes_to_add = vec![]; | ||||
|         if let Some(dependencies) = syntax_to_dependencies.get(name) { | ||||
|             syntaxes_to_add.extend(dependencies); | ||||
|         } | ||||
|         if let Some(dependents) = syntax_to_dependents.get(name) { | ||||
|             // This will later be enabled intelligently | ||||
|             if std::env::var("BAT_INCLUDE_SYNTAX_DEPENDENTS").is_ok() { | ||||
|                 syntaxes_to_add.extend(dependents); | ||||
|             } | ||||
|         } | ||||
|         for syntax_to_add in syntaxes_to_add { | ||||
|             if let Some(syntax_to_add) = other_syntax_lookup.get(syntax_to_add) { | ||||
|                 self.add_with_dependencies( | ||||
|                     syntax_to_add, | ||||
|                     other_syntax_lookup, | ||||
|                     syntax_to_dependencies, | ||||
|                     syntax_to_dependents, | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn is_syntax_already_added(&self, name: &str) -> bool { | ||||
|         self.syntax_set_builder | ||||
|             .syntaxes() | ||||
|             .iter() | ||||
|             .any(|syntax| syntax.name == name) | ||||
|     } | ||||
|  | ||||
|     fn build(self) -> SyntaxSet { | ||||
|         self.syntax_set_builder.build() | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn asset_to_contents<T: serde::Serialize>( | ||||
|     asset: &T, | ||||
|     description: &str, | ||||
|     compressed: bool, | ||||
| ) -> Result<Vec<u8>> { | ||||
|     let mut contents = vec![]; | ||||
|     if compressed { | ||||
|         bincode::serialize_into( | ||||
|             flate2::write::ZlibEncoder::new(&mut contents, flate2::Compression::best()), | ||||
|             asset, | ||||
|         ) | ||||
|     } else { | ||||
|         bincode::serialize_into(&mut contents, asset) | ||||
|     } | ||||
|     .map_err(|_| format!("Could not serialize {}", description))?; | ||||
|     Ok(contents) | ||||
| } | ||||
|  | ||||
| fn asset_to_cache<T: serde::Serialize>( | ||||
|     asset: &T, | ||||
|     path: &Path, | ||||
|     description: &str, | ||||
|     compressed: bool, | ||||
| ) -> Result<()> { | ||||
|     print!("Writing {} to {} ... ", description, path.to_string_lossy()); | ||||
|     let contents = asset_to_contents(asset, description, compressed)?; | ||||
|     std::fs::write(path, &contents[..]).map_err(|_| { | ||||
|         format!( | ||||
|             "Could not save {} to {}", | ||||
|             description, | ||||
|             path.to_string_lossy() | ||||
|         ) | ||||
|     })?; | ||||
|     println!("okay"); | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
|  | ||||
|     #[test] | ||||
|     fn remove_explicit_context_sanity() { | ||||
|         // Example from Objective-C++.sublime-syntax | ||||
|         let scope = Scope::new("source.c++#unique-variables").unwrap(); | ||||
|         let expected = Scope::new("source.c++").unwrap(); | ||||
|         assert_eq!(remove_explicit_context(scope), expected); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										41
									
								
								src/assets/build_assets/graphviz_utils.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/assets/build_assets/graphviz_utils.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| use super::*; | ||||
|  | ||||
| pub(crate) fn try_syntax_dependencies_to_graphviz_dot_file( | ||||
|     other_syntax_lookup: &OtherSyntaxLookup, | ||||
|     syntax_to_dependencies: &SyntaxToDependencies, | ||||
|     dot_file_path: &str, | ||||
| ) { | ||||
|     match syntax_dependencies_to_graphviz_dot_file( | ||||
|         other_syntax_lookup, | ||||
|         syntax_to_dependencies, | ||||
|         dot_file_path, | ||||
|     ) { | ||||
|         Ok(_) => println!("Wrote graphviz dot file to {}", dot_file_path), | ||||
|         Err(e) => eprintln!( | ||||
|             "Failed to write graphviz dot file to {}: {}", | ||||
|             dot_file_path, e | ||||
|         ), | ||||
|     }; | ||||
| } | ||||
|  | ||||
| fn syntax_dependencies_to_graphviz_dot_file( | ||||
|     other_syntax_lookup: &OtherSyntaxLookup, | ||||
|     syntax_to_dependencies: &SyntaxToDependencies, | ||||
|     dot_file_path: &str, | ||||
| ) -> Result<()> { | ||||
|     use std::io::Write; | ||||
|  | ||||
|     let mut dot_file = std::fs::File::create(dot_file_path)?; | ||||
|  | ||||
|     writeln!(dot_file, "digraph BatSyntaxDependencies {{")?; | ||||
|     for (key, dependencies) in syntax_to_dependencies { | ||||
|         for dependency in dependencies { | ||||
|             if let Some(dep) = other_syntax_lookup.get(dependency) { | ||||
|                 writeln!(dot_file, "    \"{}\" -> \"{}\"", key, dep.name)?; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     writeln!(dot_file, "}}")?; | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
							
								
								
									
										42
									
								
								src/assets/ignored_suffixes.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/assets/ignored_suffixes.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| use std::ffi::OsStr; | ||||
| use std::path::Path; | ||||
|  | ||||
| use crate::error::*; | ||||
|  | ||||
| const IGNORED_SUFFIXES: [&str; 13] = [ | ||||
|     // Editor etc backups | ||||
|     "~", | ||||
|     ".bak", | ||||
|     ".old", | ||||
|     ".orig", | ||||
|     // Debian and derivatives apt/dpkg/ucf backups | ||||
|     ".dpkg-dist", | ||||
|     ".dpkg-old", | ||||
|     ".ucf-dist", | ||||
|     ".ucf-new", | ||||
|     ".ucf-old", | ||||
|     // Red Hat and derivatives rpm backups | ||||
|     ".rpmnew", | ||||
|     ".rpmorig", | ||||
|     ".rpmsave", | ||||
|     // Build system input/template files | ||||
|     ".in", | ||||
| ]; | ||||
|  | ||||
| /// If we find an ignored suffix on the file name, e.g. '~', we strip it and | ||||
| /// then try again without it. | ||||
| pub fn try_with_stripped_suffix<T, F>(file_name: &OsStr, func: F) -> Result<Option<T>> | ||||
| where | ||||
|     F: Fn(&OsStr) -> Result<Option<T>>, | ||||
| { | ||||
|     let mut from_stripped = None; | ||||
|     if let Some(file_str) = Path::new(file_name).to_str() { | ||||
|         for suffix in &IGNORED_SUFFIXES { | ||||
|             if let Some(stripped_filename) = file_str.strip_suffix(suffix) { | ||||
|                 from_stripped = func(OsStr::new(stripped_filename))?; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     Ok(from_stripped) | ||||
| } | ||||
							
								
								
									
										72
									
								
								src/assets/minimal_assets.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/assets/minimal_assets.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| use std::collections::HashMap; | ||||
|  | ||||
| use lazycell::LazyCell; | ||||
|  | ||||
| use syntect::parsing::SyntaxSet; | ||||
|  | ||||
| use super::*; | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub(crate) struct MinimalAssets { | ||||
|     minimal_syntaxes: MinimalSyntaxes, | ||||
|  | ||||
|     /// Lazily load serialized [SyntaxSet]s from [Self.minimal_syntaxes]. The | ||||
|     /// index in this vec matches the index in | ||||
|     /// [Self.minimal_syntaxes.serialized_syntax_sets] | ||||
|     deserialized_minimal_syntaxes: Vec<LazyCell<SyntaxSet>>, | ||||
| } | ||||
|  | ||||
| /// Stores and allows lookup of minimal [SyntaxSet]s. The [SyntaxSet]s are | ||||
| /// stored in serialized form, and are deserialized on-demand. This gives good | ||||
| /// startup performance since only the necessary [SyntaxReference]s needs to be | ||||
| /// deserialized. | ||||
| #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] | ||||
| pub(crate) struct MinimalSyntaxes { | ||||
|     /// Lookup the index into `serialized_syntax_sets` of a [SyntaxSet] by the | ||||
|     /// name of any [SyntaxReference] inside the [SyntaxSet] | ||||
|     /// (We will later add `by_extension`, `by_first_line`, etc.) | ||||
|     pub(crate) by_name: HashMap<String, usize>, | ||||
|  | ||||
|     /// Serialized [SyntaxSet]s. Whether or not this data is compressed is | ||||
|     /// decided by [COMPRESS_SERIALIZED_MINIMAL_SYNTAXES] | ||||
|     pub(crate) serialized_syntax_sets: Vec<Vec<u8>>, | ||||
| } | ||||
|  | ||||
| impl MinimalAssets { | ||||
|     pub(crate) fn new(minimal_syntaxes: MinimalSyntaxes) -> Self { | ||||
|         // Prepare so we can lazily load minimal syntaxes without a mut reference | ||||
|         let deserialized_minimal_syntaxes = | ||||
|             vec![LazyCell::new(); minimal_syntaxes.serialized_syntax_sets.len()]; | ||||
|  | ||||
|         Self { | ||||
|             minimal_syntaxes, | ||||
|             deserialized_minimal_syntaxes, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn get_syntax_set_by_name(&self, name: &str) -> Option<&SyntaxSet> { | ||||
|         self.minimal_syntaxes | ||||
|             .by_name | ||||
|             .get(&name.to_ascii_lowercase()) | ||||
|             .and_then(|index| self.get_minimal_syntax_set_with_index(*index)) | ||||
|     } | ||||
|  | ||||
|     fn load_minimal_syntax_set_with_index(&self, index: usize) -> Result<SyntaxSet> { | ||||
|         let serialized_syntax_set = &self.minimal_syntaxes.serialized_syntax_sets[index]; | ||||
|         asset_from_contents( | ||||
|             &serialized_syntax_set[..], | ||||
|             &format!("minimal syntax set {}", index), | ||||
|             COMPRESS_SERIALIZED_MINIMAL_SYNTAXES, | ||||
|         ) | ||||
|         .map_err(|_| format!("Could not parse minimal syntax set {}", index).into()) | ||||
|     } | ||||
|  | ||||
|     fn get_minimal_syntax_set_with_index(&self, index: usize) -> Option<&SyntaxSet> { | ||||
|         self.deserialized_minimal_syntaxes | ||||
|             .get(index) | ||||
|             .and_then(|cell| { | ||||
|                 cell.try_borrow_with(|| self.load_minimal_syntax_set_with_index(index)) | ||||
|                     .ok() | ||||
|             }) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										27
									
								
								src/assets/serialized_syntax_set.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/assets/serialized_syntax_set.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| use std::path::PathBuf; | ||||
|  | ||||
| use syntect::parsing::SyntaxSet; | ||||
|  | ||||
| use super::*; | ||||
|  | ||||
| /// A SyntaxSet in serialized form, i.e. bincoded and flate2 compressed. | ||||
| /// We keep it in this format since we want to load it lazily. | ||||
| #[derive(Debug)] | ||||
| pub enum SerializedSyntaxSet { | ||||
|     /// The data comes from a user-generated cache file. | ||||
|     FromFile(PathBuf), | ||||
|  | ||||
|     /// The data to use is embedded into the bat binary. | ||||
|     FromBinary(&'static [u8]), | ||||
| } | ||||
|  | ||||
| impl SerializedSyntaxSet { | ||||
|     pub fn deserialize(&self) -> Result<SyntaxSet> { | ||||
|         match self { | ||||
|             SerializedSyntaxSet::FromBinary(data) => Ok(from_binary(data, COMPRESS_SYNTAXES)), | ||||
|             SerializedSyntaxSet::FromFile(ref path) => { | ||||
|                 asset_from_cache(path, "syntax set", COMPRESS_SYNTAXES) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -62,7 +62,7 @@ impl App { | ||||
|             // Read arguments from bats config file | ||||
|             let mut args = get_args_from_env_var() | ||||
|                 .unwrap_or_else(get_args_from_config_file) | ||||
|                 .chain_err(|| "Could not parse configuration file")?; | ||||
|                 .map_err(|_| "Could not parse configuration file")?; | ||||
|  | ||||
|             // Put the zero-th CLI argument (program name) first | ||||
|             args.insert(0, cli_args.next().unwrap()); | ||||
|   | ||||
| @@ -20,6 +20,7 @@ pub fn cache_dir() -> Cow<'static, str> { | ||||
| pub fn clear_assets() { | ||||
|     clear_asset("themes.bin", "theme set cache"); | ||||
|     clear_asset("syntaxes.bin", "syntax set cache"); | ||||
|     clear_asset("minimal_syntaxes.bin", "minimal syntax sets cache"); | ||||
|     clear_asset("metadata.yaml", "metadata file"); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -95,7 +95,8 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> { | ||||
|                      '--highlight-line 40' highlights line 40\n  \ | ||||
|                      '--highlight-line 30:40' highlights lines 30 to 40\n  \ | ||||
|                      '--highlight-line :40' highlights lines 1 to 40\n  \ | ||||
|                      '--highlight-line 40:' highlights lines 40 to the end of the file", | ||||
|                      '--highlight-line 40:' highlights lines 40 to the end of the file\n  \ | ||||
|                      '--highlight-line 30:+10' highlights lines 30 to 40", | ||||
|                 ), | ||||
|         ) | ||||
|         .arg( | ||||
| @@ -423,7 +424,8 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> { | ||||
|                      '--line-range 30:40' prints lines 30 to 40\n  \ | ||||
|                      '--line-range :40' prints lines 1 to 40\n  \ | ||||
|                      '--line-range 40:' prints lines 40 to the end of the file\n  \ | ||||
|                      '--line-range 40' only prints line 40", | ||||
|                      '--line-range 40' only prints line 40\n  \ | ||||
|                      '--line-range 30:+10' prints lines 30 to 40", | ||||
|                 ), | ||||
|         ) | ||||
|         .arg( | ||||
|   | ||||
| @@ -64,7 +64,7 @@ pub fn generate_config_file() -> bat::error::Result<()> { | ||||
| #--pager="less --RAW-CONTROL-CHARS --quit-if-one-screen --mouse" | ||||
|  | ||||
| # Syntax mappings: map a certain filename pattern to a language. | ||||
| #   Example 1: use the C++ syntax for .ino files | ||||
| #   Example 1: use the C++ syntax for Arduino .ino files | ||||
| #   Example 2: Use ".gitignore"-style highlighting for ".ignore" files | ||||
| #--map-syntax "*.ino:C++" | ||||
| #--map-syntax ".ignore:Git Ignore" | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| // `error_chain!` can recurse deeply | ||||
| #![recursion_limit = "1024"] | ||||
| #![deny(unsafe_code)] | ||||
|  | ||||
| mod app; | ||||
| mod assets; | ||||
| @@ -50,8 +49,7 @@ fn build_assets(matches: &clap::ArgMatches) -> Result<()> { | ||||
|  | ||||
|     let blank = matches.is_present("blank"); | ||||
|  | ||||
|     let assets = bat::assets::HighlightingAssets::from_files(source_dir, !blank)?; | ||||
|     assets.save_to_cache(target_dir, clap::crate_version!()) | ||||
|     bat::assets::build(source_dir, !blank, target_dir, clap::crate_version!()) | ||||
| } | ||||
|  | ||||
| fn run_cache_subcommand(matches: &clap::ArgMatches) -> Result<()> { | ||||
| @@ -95,7 +93,7 @@ pub fn get_languages(config: &Config) -> Result<String> { | ||||
|         .collect::<Vec<_>>(); | ||||
|  | ||||
|     // Handling of file-extension conflicts, see issue #1076 | ||||
|     for lang in languages.iter_mut() { | ||||
|     for lang in &mut languages { | ||||
|         let lang_name = lang.name.clone(); | ||||
|         lang.file_extensions.retain(|extension| { | ||||
|             // The 'extension' variable is not certainly a real extension. | ||||
| @@ -104,17 +102,12 @@ pub fn get_languages(config: &Config) -> Result<String> { | ||||
|             // Also skip if the 'extension' contains another real extension, likely | ||||
|             // that is a full match file name like 'CMakeLists.txt' and 'Cargo.lock' | ||||
|             if extension.starts_with('.') || Path::new(extension).extension().is_some() { | ||||
|                 true | ||||
|             } else { | ||||
|                 let test_file = Path::new("test").with_extension(extension); | ||||
|                 let syntax_in_set = assets | ||||
|                     .get_syntax_for_file_name(test_file, &config.syntax_mapping) | ||||
|                     .unwrap(); // safe since .get_syntaxes() above worked | ||||
|                 match syntax_in_set { | ||||
|                     Some(syntax_in_set) => syntax_in_set.syntax.name == lang_name, | ||||
|                     None => false, | ||||
|                 } | ||||
|                 return true; | ||||
|             } | ||||
|  | ||||
|             let test_file = Path::new("test").with_extension(extension); | ||||
|             let syntax_in_set = assets.get_syntax_for_path(test_file, &config.syntax_mapping); | ||||
|             matches!(syntax_in_set, Ok(syntax_in_set) if syntax_in_set.syntax.name == lang_name) | ||||
|         }); | ||||
|     } | ||||
|  | ||||
| @@ -122,7 +115,7 @@ pub fn get_languages(config: &Config) -> Result<String> { | ||||
|  | ||||
|     let configured_languages = get_syntax_mapping_to_paths(config.syntax_mapping.mappings()); | ||||
|  | ||||
|     for lang in languages.iter_mut() { | ||||
|     for lang in &mut languages { | ||||
|         if let Some(additional_paths) = configured_languages.get(lang.name.as_str()) { | ||||
|             lang.file_extensions | ||||
|                 .extend(additional_paths.iter().cloned()); | ||||
| @@ -236,7 +229,7 @@ fn invoke_bugreport(app: &App) { | ||||
|     let pager = bat::config::get_pager_executable(app.matches.value_of("pager")) | ||||
|         .unwrap_or_else(|| "less".to_owned()); // FIXME: Avoid non-canonical path to "less". | ||||
|  | ||||
|     let report = bugreport!() | ||||
|     let mut report = bugreport!() | ||||
|         .info(SoftwareVersion::default()) | ||||
|         .info(OperatingSystem::default()) | ||||
|         .info(CommandLine::default()) | ||||
| @@ -244,6 +237,8 @@ fn invoke_bugreport(app: &App) { | ||||
|             "SHELL", | ||||
|             "PAGER", | ||||
|             "LESS", | ||||
|             "LANG", | ||||
|             "LC_ALL", | ||||
|             "BAT_PAGER", | ||||
|             "BAT_CACHE_PATH", | ||||
|             "BAT_CONFIG_PATH", | ||||
| @@ -260,14 +255,13 @@ fn invoke_bugreport(app: &App) { | ||||
|         .info(FileContent::new("Config file", config_file())) | ||||
|         .info(CompileTimeInformation::default()); | ||||
|  | ||||
|     let mut report = if let Ok(resolved_path) = grep_cli::resolve_binary(pager) { | ||||
|         report.info(CommandOutput::new( | ||||
|     #[cfg(feature = "paging")] | ||||
|     if let Ok(resolved_path) = grep_cli::resolve_binary(pager) { | ||||
|         report = report.info(CommandOutput::new( | ||||
|             "Less version", | ||||
|             resolved_path, | ||||
|             &["--version"], | ||||
|         )) | ||||
|     } else { | ||||
|         report | ||||
|     }; | ||||
|  | ||||
|     report.print::<Markdown>(); | ||||
|   | ||||
| @@ -90,11 +90,10 @@ pub struct Config<'a> { | ||||
|  | ||||
| #[cfg(all(feature = "minimal-application", feature = "paging"))] | ||||
| pub fn get_pager_executable(config_pager: Option<&str>) -> Option<String> { | ||||
|     if let Ok(Some(pager)) = crate::pager::get_pager(config_pager) { | ||||
|         Some(pager.bin) | ||||
|     } else { | ||||
|         None | ||||
|     } | ||||
|     crate::pager::get_pager(config_pager) | ||||
|         .ok() | ||||
|         .flatten() | ||||
|         .map(|pager| pager.bin) | ||||
| } | ||||
|  | ||||
| #[test] | ||||
|   | ||||
| @@ -175,9 +175,10 @@ impl<'b> Controller<'b> { | ||||
|                     let mut line_ranges: Vec<LineRange> = vec![]; | ||||
|  | ||||
|                     if let Some(line_changes) = line_changes { | ||||
|                         for line in line_changes.keys() { | ||||
|                             let line = *line as usize; | ||||
|                             line_ranges.push(LineRange::new(line - context, line + context)); | ||||
|                         for &line in line_changes.keys() { | ||||
|                             let line = line as usize; | ||||
|                             line_ranges | ||||
|                                 .push(LineRange::new(line.saturating_sub(context), line + context)); | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|   | ||||
							
								
								
									
										64
									
								
								src/error.rs
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								src/error.rs
									
									
									
									
									
								
							| @@ -1,42 +1,52 @@ | ||||
| use error_chain::error_chain; | ||||
| use std::io::Write; | ||||
| use thiserror::Error; | ||||
|  | ||||
| error_chain! { | ||||
|     foreign_links { | ||||
|         Clap(::clap::Error) #[cfg(feature = "minimal-application")]; | ||||
|         Io(::std::io::Error); | ||||
|         SyntectError(::syntect::LoadingError); | ||||
|         ParseIntError(::std::num::ParseIntError); | ||||
|         GlobParsingError(::globset::Error); | ||||
|         SerdeYamlError(::serde_yaml::Error); | ||||
|     } | ||||
| #[derive(Error, Debug)] | ||||
| pub enum Error { | ||||
|     #[error(transparent)] | ||||
|     Io(#[from] ::std::io::Error), | ||||
|     #[error(transparent)] | ||||
|     SyntectError(#[from] ::syntect::LoadingError), | ||||
|     #[error(transparent)] | ||||
|     ParseIntError(#[from] ::std::num::ParseIntError), | ||||
|     #[error(transparent)] | ||||
|     GlobParsingError(#[from] ::globset::Error), | ||||
|     #[error(transparent)] | ||||
|     SerdeYamlError(#[from] ::serde_yaml::Error), | ||||
|     #[error("unable to detect syntax for {0}")] | ||||
|     UndetectedSyntax(String), | ||||
|     #[error("unknown syntax: '{0}'")] | ||||
|     UnknownSyntax(String), | ||||
|     #[error("Unknown style '{0}'")] | ||||
|     UnknownStyle(String), | ||||
|     #[error("Use of bat as a pager is disallowed in order to avoid infinite recursion problems")] | ||||
|     InvalidPagerValueBat, | ||||
|     #[error("{0}")] | ||||
|     Msg(String), | ||||
| } | ||||
|  | ||||
|     errors { | ||||
|         UndetectedSyntax(input: String) { | ||||
|             description("unable to detect syntax"), | ||||
|             display("unable to detect syntax for {}", input) | ||||
|         } | ||||
|         UnknownSyntax(name: String) { | ||||
|             description("unknown syntax"), | ||||
|             display("unknown syntax: '{}'", name) | ||||
|         } | ||||
|         InvalidPagerValueBat { | ||||
|             description("invalid value `bat` for pager property"), | ||||
|             display("Use of bat as a pager is disallowed in order to avoid infinite recursion problems") | ||||
|         } | ||||
| impl From<&'static str> for Error { | ||||
|     fn from(s: &'static str) -> Self { | ||||
|         Error::Msg(s.to_owned()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<String> for Error { | ||||
|     fn from(s: String) -> Self { | ||||
|         Error::Msg(s) | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub type Result<T> = std::result::Result<T, Error>; | ||||
|  | ||||
| pub fn default_error_handler(error: &Error, output: &mut dyn Write) { | ||||
|     use ansi_term::Colour::Red; | ||||
|  | ||||
|     match error { | ||||
|         Error(ErrorKind::Io(ref io_error), _) | ||||
|             if io_error.kind() == ::std::io::ErrorKind::BrokenPipe => | ||||
|         { | ||||
|         Error::Io(ref io_error) if io_error.kind() == ::std::io::ErrorKind::BrokenPipe => { | ||||
|             ::std::process::exit(0); | ||||
|         } | ||||
|         Error(ErrorKind::SerdeYamlError(_), _) => { | ||||
|         Error::SerdeYamlError(_) => { | ||||
|             writeln!( | ||||
|                 output, | ||||
|                 "{}: Error while parsing metadata.yaml file: {}", | ||||
|   | ||||
							
								
								
									
										37
									
								
								src/input.rs
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								src/input.rs
									
									
									
									
									
								
							| @@ -50,7 +50,7 @@ impl InputDescription { | ||||
|     } | ||||
|  | ||||
|     pub fn title(&self) -> &String { | ||||
|         match self.title.as_ref() { | ||||
|         match &self.title { | ||||
|             Some(title) => title, | ||||
|             None => &self.name, | ||||
|         } | ||||
| @@ -108,6 +108,21 @@ pub(crate) struct OpenedInput<'a> { | ||||
|     pub(crate) description: InputDescription, | ||||
| } | ||||
|  | ||||
| impl OpenedInput<'_> { | ||||
|     /// Get the path of the file: | ||||
|     /// If this was set by the metadata, that will take priority. | ||||
|     /// If it wasn't, it will use the real file path (if available). | ||||
|     pub(crate) fn path(&self) -> Option<&PathBuf> { | ||||
|         self.metadata | ||||
|             .user_provided_name | ||||
|             .as_ref() | ||||
|             .or_else(|| match self.kind { | ||||
|                 OpenedInputKind::OrdinaryFile(ref path) => Some(path), | ||||
|                 _ => None, | ||||
|             }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a> Input<'a> { | ||||
|     pub fn ordinary_file(path: impl AsRef<Path>) -> Self { | ||||
|         Self::_ordinary_file(path.as_ref()) | ||||
| @@ -256,18 +271,18 @@ impl<'a> InputReader<'a> { | ||||
|     } | ||||
|  | ||||
|     pub(crate) fn read_line(&mut self, buf: &mut Vec<u8>) -> io::Result<bool> { | ||||
|         if self.first_line.is_empty() { | ||||
|             let res = self.inner.read_until(b'\n', buf).map(|size| size > 0)?; | ||||
|  | ||||
|             if self.content_type == Some(ContentType::UTF_16LE) { | ||||
|                 self.inner.read_until(0x00, buf).ok(); | ||||
|             } | ||||
|  | ||||
|             Ok(res) | ||||
|         } else { | ||||
|         if !self.first_line.is_empty() { | ||||
|             buf.append(&mut self.first_line); | ||||
|             Ok(true) | ||||
|             return Ok(true); | ||||
|         } | ||||
|  | ||||
|         let res = self.inner.read_until(b'\n', buf).map(|size| size > 0)?; | ||||
|  | ||||
|         if self.content_type == Some(ContentType::UTF_16LE) { | ||||
|             let _ = self.inner.read_until(0x00, buf); | ||||
|         } | ||||
|  | ||||
|         Ok(res) | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										12
									
								
								src/less.rs
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								src/less.rs
									
									
									
									
									
								
							| @@ -11,13 +11,13 @@ pub fn retrieve_less_version(less_path: &dyn AsRef<OsStr>) -> Option<usize> { | ||||
| } | ||||
|  | ||||
| fn parse_less_version(output: &[u8]) -> Option<usize> { | ||||
|     if output.starts_with(b"less ") { | ||||
|         let version = std::str::from_utf8(&output[5..]).ok()?; | ||||
|         let end = version.find(|c: char| !c.is_ascii_digit())?; | ||||
|         version[..end].parse::<usize>().ok() | ||||
|     } else { | ||||
|         None | ||||
|     if !output.starts_with(b"less ") { | ||||
|         return None; | ||||
|     } | ||||
|  | ||||
|     let version = std::str::from_utf8(&output[5..]).ok()?; | ||||
|     let end = version.find(|c: char| !c.is_ascii_digit())?; | ||||
|     version[..end].parse::<usize>().ok() | ||||
| } | ||||
|  | ||||
| #[test] | ||||
|   | ||||
| @@ -19,10 +19,14 @@ | ||||
| //!     .unwrap(); | ||||
| //! ``` | ||||
|  | ||||
| #![deny(unsafe_code)] | ||||
|  | ||||
| mod macros; | ||||
|  | ||||
| pub mod assets; | ||||
| pub mod assets_metadata; | ||||
| pub mod assets_metadata { | ||||
|     pub use super::assets::assets_metadata::*; | ||||
| } | ||||
| pub mod config; | ||||
| pub mod controller; | ||||
| mod decorations; | ||||
| @@ -40,8 +44,6 @@ mod preprocessor; | ||||
| mod pretty_printer; | ||||
| pub(crate) mod printer; | ||||
| pub mod style; | ||||
| #[cfg(feature = "build-assets")] | ||||
| mod syntax_dependencies; | ||||
| pub(crate) mod syntax_mapping; | ||||
| mod terminal; | ||||
| pub(crate) mod wrapping; | ||||
|   | ||||
| @@ -47,7 +47,16 @@ impl LineRange { | ||||
|             } | ||||
|             2 => { | ||||
|                 new_range.lower = line_numbers[0].parse()?; | ||||
|                 new_range.upper = line_numbers[1].parse()?; | ||||
|  | ||||
|                 new_range.upper = if line_numbers[1].bytes().next() == Some(b'+') { | ||||
|                     let more_lines = &line_numbers[1][1..] | ||||
|                         .parse() | ||||
|                         .map_err(|_| "Invalid character after +")?; | ||||
|                     new_range.lower + more_lines | ||||
|                 } else { | ||||
|                     line_numbers[1].parse()? | ||||
|                 }; | ||||
|  | ||||
|                 Ok(new_range) | ||||
|             } | ||||
|             _ => Err( | ||||
| @@ -100,6 +109,23 @@ fn test_parse_fail() { | ||||
|     assert!(range.is_err()); | ||||
| } | ||||
|  | ||||
| #[test] | ||||
| fn test_parse_plus() { | ||||
|     let range = LineRange::from("40:+10").expect("Shouldn't fail on test!"); | ||||
|     assert_eq!(40, range.lower); | ||||
|     assert_eq!(50, range.upper); | ||||
| } | ||||
|  | ||||
| #[test] | ||||
| fn test_parse_plus_fail() { | ||||
|     let range = LineRange::from("40:+z"); | ||||
|     assert!(range.is_err()); | ||||
|     let range = LineRange::from("40:+-10"); | ||||
|     assert!(range.is_err()); | ||||
|     let range = LineRange::from("40:+"); | ||||
|     assert!(range.is_err()); | ||||
| } | ||||
|  | ||||
| #[derive(Copy, Clone, Debug, PartialEq)] | ||||
| pub enum RangeCheckResult { | ||||
|     // Within one of the given ranges | ||||
|   | ||||
| @@ -52,7 +52,7 @@ impl OutputType { | ||||
|         use std::process::{Command, Stdio}; | ||||
|  | ||||
|         let pager_opt = | ||||
|             pager::get_pager(pager_from_config).chain_err(|| "Could not parse pager command.")?; | ||||
|             pager::get_pager(pager_from_config).map_err(|_| "Could not parse pager command.")?; | ||||
|  | ||||
|         let pager = match pager_opt { | ||||
|             Some(pager) => pager, | ||||
| @@ -60,7 +60,7 @@ impl OutputType { | ||||
|         }; | ||||
|  | ||||
|         if pager.kind == PagerKind::Bat { | ||||
|             return Err(ErrorKind::InvalidPagerValueBat.into()); | ||||
|             return Err(Error::InvalidPagerValueBat); | ||||
|         } | ||||
|  | ||||
|         let resolved_path = match grep_cli::resolve_binary(&pager.bin) { | ||||
| @@ -142,7 +142,7 @@ impl OutputType { | ||||
|             OutputType::Pager(ref mut command) => command | ||||
|                 .stdin | ||||
|                 .as_mut() | ||||
|                 .chain_err(|| "Could not open stdin for pager")?, | ||||
|                 .ok_or("Could not open stdin for pager")?, | ||||
|             OutputType::Stdout(ref mut handle) => handle, | ||||
|         }) | ||||
|     } | ||||
|   | ||||
| @@ -99,6 +99,20 @@ impl<'a> Printer for SimplePrinter<'a> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| struct HighlighterFromSet<'a> { | ||||
|     highlighter: HighlightLines<'a>, | ||||
|     syntax_set: &'a SyntaxSet, | ||||
| } | ||||
|  | ||||
| impl<'a> HighlighterFromSet<'a> { | ||||
|     fn new(syntax_in_set: SyntaxReferenceInSet<'a>, theme: &'a Theme) -> Self { | ||||
|         Self { | ||||
|             highlighter: HighlightLines::new(syntax_in_set.syntax, theme), | ||||
|             syntax_set: syntax_in_set.syntax_set, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub(crate) struct InteractivePrinter<'a> { | ||||
|     colors: Colors, | ||||
|     config: &'a Config<'a>, | ||||
| @@ -108,8 +122,7 @@ pub(crate) struct InteractivePrinter<'a> { | ||||
|     content_type: Option<ContentType>, | ||||
|     #[cfg(feature = "git")] | ||||
|     pub line_changes: &'a Option<LineChanges>, | ||||
|     highlighter: Option<HighlightLines<'a>>, | ||||
|     syntax_set: &'a SyntaxSet, | ||||
|     highlighter_from_set: Option<HighlighterFromSet<'a>>, | ||||
|     background_color_highlight: Option<Color>, | ||||
| } | ||||
|  | ||||
| @@ -163,29 +176,24 @@ impl<'a> InteractivePrinter<'a> { | ||||
|             panel_width = 0; | ||||
|         } | ||||
|  | ||||
|         let (highlighter, syntax_set) = if input | ||||
|         let highlighter_from_set = if input | ||||
|             .reader | ||||
|             .content_type | ||||
|             .map_or(false, |c| c.is_binary() && !config.show_nonprintable) | ||||
|         { | ||||
|             (None, assets.get_syntax_set()?) | ||||
|             None | ||||
|         } else { | ||||
|             // Determine the type of syntax for highlighting | ||||
|             let syntax_in_set = | ||||
|                 match assets.get_syntax(config.language, input, &config.syntax_mapping) { | ||||
|                     Ok(syntax_in_set) => syntax_in_set, | ||||
|                     Err(Error(ErrorKind::UndetectedSyntax(_), _)) => { | ||||
|                         let syntax_set = assets.get_syntax_set()?; | ||||
|                         let syntax = syntax_set.find_syntax_plain_text(); | ||||
|                         SyntaxReferenceInSet { syntax, syntax_set } | ||||
|                     } | ||||
|                     Err(Error::UndetectedSyntax(_)) => assets | ||||
|                         .find_syntax_by_name("Plain Text")? | ||||
|                         .expect("A plain text syntax is available"), | ||||
|                     Err(e) => return Err(e), | ||||
|                 }; | ||||
|  | ||||
|             ( | ||||
|                 Some(HighlightLines::new(syntax_in_set.syntax, theme)), | ||||
|                 syntax_in_set.syntax_set, | ||||
|             ) | ||||
|             Some(HighlighterFromSet::new(syntax_in_set, theme)) | ||||
|         }; | ||||
|  | ||||
|         Ok(InteractivePrinter { | ||||
| @@ -197,8 +205,7 @@ impl<'a> InteractivePrinter<'a> { | ||||
|             ansi_prefix_sgr: String::new(), | ||||
|             #[cfg(feature = "git")] | ||||
|             line_changes, | ||||
|             highlighter, | ||||
|             syntax_set, | ||||
|             highlighter_from_set, | ||||
|             background_color_highlight, | ||||
|         }) | ||||
|     } | ||||
| @@ -226,29 +233,29 @@ impl<'a> InteractivePrinter<'a> { | ||||
|  | ||||
|     fn create_fake_panel(&self, text: &str) -> String { | ||||
|         if self.panel_width == 0 { | ||||
|             "".to_string() | ||||
|             return "".to_string(); | ||||
|         } | ||||
|  | ||||
|         let text_truncated: String = text.chars().take(self.panel_width - 1).collect(); | ||||
|         let text_filled: String = format!( | ||||
|             "{}{}", | ||||
|             text_truncated, | ||||
|             " ".repeat(self.panel_width - 1 - text_truncated.len()) | ||||
|         ); | ||||
|         if self.config.style_components.grid() { | ||||
|             format!("{} │ ", text_filled) | ||||
|         } else { | ||||
|             let text_truncated: String = text.chars().take(self.panel_width - 1).collect(); | ||||
|             let text_filled: String = format!( | ||||
|                 "{}{}", | ||||
|                 text_truncated, | ||||
|                 " ".repeat(self.panel_width - 1 - text_truncated.len()) | ||||
|             ); | ||||
|             if self.config.style_components.grid() { | ||||
|                 format!("{} │ ", text_filled) | ||||
|             } else { | ||||
|                 text_filled | ||||
|             } | ||||
|             text_filled | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn preprocess(&self, text: &str, cursor: &mut usize) -> String { | ||||
|         if self.config.tab_width > 0 { | ||||
|             expand_tabs(text, self.config.tab_width, cursor) | ||||
|         } else { | ||||
|             *cursor += text.len(); | ||||
|             text.to_string() | ||||
|             return expand_tabs(text, self.config.tab_width, cursor); | ||||
|         } | ||||
|  | ||||
|         *cursor += text.len(); | ||||
|         text.to_string() | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -389,13 +396,15 @@ impl<'a> Printer for InteractivePrinter<'a> { | ||||
|         }; | ||||
|  | ||||
|         let regions = { | ||||
|             let highlighter = match self.highlighter { | ||||
|                 Some(ref mut highlighter) => highlighter, | ||||
|             let highlighter_from_set = match self.highlighter_from_set { | ||||
|                 Some(ref mut highlighter_from_set) => highlighter_from_set, | ||||
|                 _ => { | ||||
|                     return Ok(()); | ||||
|                 } | ||||
|             }; | ||||
|             highlighter.highlight(line.as_ref(), self.syntax_set) | ||||
|             highlighter_from_set | ||||
|                 .highlighter | ||||
|                 .highlight(&line, highlighter_from_set.syntax_set) | ||||
|         }; | ||||
|  | ||||
|         if out_of_range { | ||||
| @@ -420,8 +429,7 @@ impl<'a> Printer for InteractivePrinter<'a> { | ||||
|             let decorations = self | ||||
|                 .decorations | ||||
|                 .iter() | ||||
|                 .map(|d| d.generate(line_number, false, self)) | ||||
|                 .collect::<Vec<_>>(); | ||||
|                 .map(|d| d.generate(line_number, false, self)); | ||||
|  | ||||
|             for deco in decorations { | ||||
|                 write!(handle, "{} ", deco.text)?; | ||||
| @@ -435,7 +443,7 @@ impl<'a> Printer for InteractivePrinter<'a> { | ||||
|             let colored_output = self.config.colored_output; | ||||
|             let italics = self.config.use_italic_text; | ||||
|  | ||||
|             for &(style, region) in regions.iter() { | ||||
|             for &(style, region) in ®ions { | ||||
|                 let text = &*self.preprocess(region, &mut cursor_total); | ||||
|                 let text_trimmed = text.trim_end_matches(|c| c == '\r' || c == '\n'); | ||||
|                 write!( | ||||
| @@ -472,7 +480,7 @@ impl<'a> Printer for InteractivePrinter<'a> { | ||||
|                 writeln!(handle)?; | ||||
|             } | ||||
|         } else { | ||||
|             for &(style, region) in regions.iter() { | ||||
|             for &(style, region) in ®ions { | ||||
|                 let ansi_iterator = AnsiCodeIterator::new(region); | ||||
|                 let mut ansi_prefix: String = String::new(); | ||||
|                 for chunk in ansi_iterator { | ||||
|   | ||||
| @@ -1,184 +0,0 @@ | ||||
| use std::collections::HashMap; | ||||
| use syntect::parsing::syntax_definition::{ | ||||
|     ContextReference, MatchOperation, MatchPattern, Pattern, SyntaxDefinition, | ||||
| }; | ||||
| use syntect::parsing::{Scope, SyntaxSet, SyntaxSetBuilder}; | ||||
|  | ||||
| type SyntaxName = String; | ||||
|  | ||||
| /// Used to look up what dependencies a given [SyntaxDefinition] has | ||||
| type SyntaxToDependencies = HashMap<SyntaxName, Vec<Dependency>>; | ||||
|  | ||||
| /// Used to look up which [SyntaxDefinition] corresponds to a given [Dependency] | ||||
| type DependencyToSyntax<'a> = HashMap<Dependency, &'a SyntaxDefinition>; | ||||
|  | ||||
| /// Represents a dependency on an external `.sublime-syntax` file. | ||||
| #[derive(Debug, Eq, PartialEq, Clone, Hash)] | ||||
| enum Dependency { | ||||
|     /// By name. Example YAML: `include: C.sublime-syntax` | ||||
|     ByName(String), | ||||
|  | ||||
|     /// By scope. Example YAML: `embed: scope:source.c` | ||||
|     ByScope(Scope), | ||||
| } | ||||
|  | ||||
| /// Generates independent [SyntaxSet]s after analyzing dependencies between syntaxes | ||||
| /// in a [SyntaxSetBuilder], and then prints the reults. | ||||
| pub(crate) fn print_syntax_dependencies(syntax_set_builder: &SyntaxSetBuilder) { | ||||
|     println!("Constructing independent SyntaxSets..."); | ||||
|     let independent_syntax_sets = build_independent_syntax_sets(syntax_set_builder); | ||||
|  | ||||
|     println!("Independent SyntaxSets:"); | ||||
|     for syntax_set in independent_syntax_sets { | ||||
|         let names = syntax_set | ||||
|             .syntaxes() | ||||
|             .iter() | ||||
|             .map(|syntax| &syntax.name) | ||||
|             .collect::<Vec<_>>(); | ||||
|         println!("{:?}", names); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Analyzes dependencies between syntaxes in a [SyntaxSetBuilder]. | ||||
| /// From that, it builds independent [SyntaxSet]s. | ||||
| fn build_independent_syntax_sets( | ||||
|     syntax_set_builder: &'_ SyntaxSetBuilder, | ||||
| ) -> impl Iterator<Item = SyntaxSet> + '_ { | ||||
|     let syntaxes = syntax_set_builder.syntaxes(); | ||||
|  | ||||
|     // Build the data structures we need for dependency resolution | ||||
|     let (syntax_to_dependencies, dependency_to_syntax) = generate_maps(syntaxes); | ||||
|  | ||||
|     // Create one independent SyntaxSet from each (non-hidden) SyntaxDefinition | ||||
|     syntaxes.iter().filter_map(move |syntax| { | ||||
|         if syntax.hidden { | ||||
|             return None; | ||||
|         } | ||||
|  | ||||
|         let mut builder = SyntaxSetDependencyBuilder::new(); | ||||
|         builder.add_with_dependencies(syntax, &syntax_to_dependencies, &dependency_to_syntax); | ||||
|         Some(builder.build()) | ||||
|     }) | ||||
| } | ||||
|  | ||||
| /// In order to analyze dependencies, we need two key pieces of data. | ||||
| /// First, when we have a [Dependency], we need to know what [SyntaxDefinition] that | ||||
| /// corresponds to. Second, when we have a [SyntaxDefinition], we need to know | ||||
| /// what dependencies it has. This functions generates that data for each syntax. | ||||
| fn generate_maps(syntaxes: &[SyntaxDefinition]) -> (SyntaxToDependencies, DependencyToSyntax) { | ||||
|     let mut syntax_to_dependencies = HashMap::new(); | ||||
|     let mut dependency_to_syntax = HashMap::new(); | ||||
|  | ||||
|     for syntax in syntaxes { | ||||
|         syntax_to_dependencies.insert(syntax.name.clone(), dependencies_for_syntax(syntax)); | ||||
|  | ||||
|         dependency_to_syntax.insert(Dependency::ByName(syntax.name.clone()), syntax); | ||||
|         dependency_to_syntax.insert(Dependency::ByScope(syntax.scope), syntax); | ||||
|     } | ||||
|  | ||||
|     (syntax_to_dependencies, dependency_to_syntax) | ||||
| } | ||||
|  | ||||
| /// Gets what external dependencies a given [SyntaxDefinition] has. | ||||
| /// An external dependency is another `.sublime-syntax` file. | ||||
| /// It does that by looking for variants of the following YAML patterns: | ||||
| /// - `include: C.sublime-syntax` | ||||
| /// - `embed: scope:source.c` | ||||
| fn dependencies_for_syntax(syntax: &SyntaxDefinition) -> Vec<Dependency> { | ||||
|     let mut dependencies: Vec<Dependency> = syntax | ||||
|         .contexts | ||||
|         .values() | ||||
|         .flat_map(|context| &context.patterns) | ||||
|         .flat_map(dependencies_from_pattern) | ||||
|         .collect(); | ||||
|  | ||||
|     // No need to track a dependency more than once | ||||
|     dependencies.dedup(); | ||||
|  | ||||
|     dependencies | ||||
| } | ||||
|  | ||||
| fn dependencies_from_pattern(pattern: &Pattern) -> Vec<Dependency> { | ||||
|     match *pattern { | ||||
|         Pattern::Match(MatchPattern { | ||||
|             operation: MatchOperation::Push(ref context_references), | ||||
|             .. | ||||
|         }) => context_references | ||||
|             .iter() | ||||
|             .map(dependency_from_context_reference) | ||||
|             .collect(), | ||||
|         Pattern::Include(ref context_reference) => { | ||||
|             vec![dependency_from_context_reference(context_reference)] | ||||
|         } | ||||
|         _ => vec![], | ||||
|     } | ||||
|     .into_iter() | ||||
|     .flatten() | ||||
|     .collect() | ||||
| } | ||||
|  | ||||
| fn dependency_from_context_reference(context_reference: &ContextReference) -> Option<Dependency> { | ||||
|     match &context_reference { | ||||
|         ContextReference::File { ref name, .. } => Some(Dependency::ByName(name.clone())), | ||||
|         ContextReference::ByScope { ref scope, .. } => Some(Dependency::ByScope(*scope)), | ||||
|         _ => None, | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Helper to construct a [SyntaxSetBuilder] that contains only [SyntaxDefinition]s | ||||
| /// that have dependencies among them. | ||||
| struct SyntaxSetDependencyBuilder { | ||||
|     syntax_set_builder: SyntaxSetBuilder, | ||||
| } | ||||
|  | ||||
| impl SyntaxSetDependencyBuilder { | ||||
|     fn new() -> Self { | ||||
|         SyntaxSetDependencyBuilder { | ||||
|             syntax_set_builder: SyntaxSetBuilder::new(), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Add a [SyntaxDefinition] to the underlying [SyntaxSetBuilder]. | ||||
|     /// Also resolve any dependencies it has and add those [SyntaxDefinition]s too. | ||||
|     /// This is a recursive process. | ||||
|     fn add_with_dependencies( | ||||
|         &mut self, | ||||
|         syntax: &SyntaxDefinition, | ||||
|         syntax_to_dependencies: &SyntaxToDependencies, | ||||
|         dependency_to_syntax: &DependencyToSyntax, | ||||
|     ) { | ||||
|         let name = &syntax.name; | ||||
|         if self.is_syntax_already_added(name) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         self.syntax_set_builder.add(syntax.clone()); | ||||
|  | ||||
|         let dependencies = syntax_to_dependencies.get(name); | ||||
|         if dependencies.is_none() { | ||||
|             eprintln!("ERROR: Unknown dependencies for {}", name); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         for dependency in dependencies.unwrap() { | ||||
|             if let Some(syntax_definition_dependency) = dependency_to_syntax.get(dependency) { | ||||
|                 self.add_with_dependencies( | ||||
|                     syntax_definition_dependency, | ||||
|                     syntax_to_dependencies, | ||||
|                     dependency_to_syntax, | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn is_syntax_already_added(&self, name: &str) -> bool { | ||||
|         self.syntax_set_builder | ||||
|             .syntaxes() | ||||
|             .iter() | ||||
|             .any(|syntax| syntax.name == name) | ||||
|     } | ||||
|  | ||||
|     fn build(self) -> SyntaxSet { | ||||
|         self.syntax_set_builder.build() | ||||
|     } | ||||
| } | ||||
| @@ -81,7 +81,7 @@ impl<'a> SyntaxMapping<'a> { | ||||
|                 .unwrap(); | ||||
|         } | ||||
|  | ||||
|         for glob in [ | ||||
|         for glob in &[ | ||||
|             "**/systemd/**/*.conf", | ||||
|             "**/systemd/**/*.example", | ||||
|             "*.automount", | ||||
| @@ -100,9 +100,7 @@ impl<'a> SyntaxMapping<'a> { | ||||
|             "*.swap", | ||||
|             "*.target", | ||||
|             "*.timer", | ||||
|         ] | ||||
|         .iter() | ||||
|         { | ||||
|         ] { | ||||
|             mapping.insert(glob, MappingTarget::MapTo("INI")).unwrap(); | ||||
|         } | ||||
|  | ||||
| @@ -153,7 +151,7 @@ impl<'a> SyntaxMapping<'a> { | ||||
|     } | ||||
|  | ||||
|     pub(crate) fn get_syntax_for(&self, path: impl AsRef<Path>) -> Option<MappingTarget<'a>> { | ||||
|         let candidate = Candidate::new(path.as_ref()); | ||||
|         let candidate = Candidate::new(&path); | ||||
|         let candidate_filename = path.as_ref().file_name().map(Candidate::new); | ||||
|         for (ref glob, ref syntax) in self.mappings.iter().rev() { | ||||
|             if glob.is_match_candidate(&candidate) | ||||
|   | ||||
							
								
								
									
										2
									
								
								tests/examples/regression_tests/first_line_fallback.invalid-syntax
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/examples/regression_tests/first_line_fallback.invalid-syntax
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| #!/usr/bin/env bash | ||||
| echo "Hello" | ||||
| @@ -34,13 +34,17 @@ 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("PAGER"); | ||||
|     cmd.env_remove("BAT_PAGER"); | ||||
|     cmd.env_remove("BAT_CONFIG_PATH"); | ||||
|     cmd.env_remove("BAT_STYLE"); | ||||
|     cmd.env_remove("BAT_THEME"); | ||||
|     cmd.env_remove("BAT_TABS"); | ||||
|     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 | ||||
| } | ||||
|  | ||||
| @@ -1123,6 +1127,21 @@ fn do_not_detect_different_syntax_for_stdin_and_files() { | ||||
|     ); | ||||
| } | ||||
|  | ||||
| #[test] | ||||
| fn no_first_line_fallback_when_mapping_to_invalid_syntax() { | ||||
|     let file = "regression_tests/first_line_fallback.invalid-syntax"; | ||||
|  | ||||
|     bat() | ||||
|         .arg("--color=always") | ||||
|         .arg("--map-syntax=*.invalid-syntax:InvalidSyntax") | ||||
|         .arg(&format!("--file-name={}", file)) | ||||
|         .arg("--style=plain") | ||||
|         .arg(file) | ||||
|         .assert() | ||||
|         .failure() | ||||
|         .stderr(predicate::str::contains("unknown syntax: 'InvalidSyntax'")); | ||||
| } | ||||
|  | ||||
| #[test] | ||||
| fn show_all_mode() { | ||||
|     bat() | ||||
|   | ||||
							
								
								
									
										1
									
								
								tests/snapshots/output/changes.snapshot.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								tests/snapshots/output/changes.snapshot.txt
									
									
									
									
										vendored
									
									
								
							| @@ -1,3 +1,4 @@ | ||||
| + /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|   struct Rectangle { | ||||
|       width: u32, | ||||
|       height: u32, | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| ──┬───────────────────────────────────────────────────────────────────────────── | ||||
| + │ /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|   │ struct Rectangle { | ||||
|   │     width: u32, | ||||
|   │     height: u32, | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| ──┬───────────────────────────────────────────────────────────────────────────── | ||||
|   │ File: sample.rs | ||||
| ──┼───────────────────────────────────────────────────────────────────────────── | ||||
| + │ /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|   │ struct Rectangle { | ||||
|   │     width: u32, | ||||
|   │     height: u32, | ||||
|   | ||||
| @@ -1,26 +1,27 @@ | ||||
| ───────┬──────────────────────────────────────────────────────────────────────── | ||||
|        │ File: sample.rs | ||||
| ───────┼──────────────────────────────────────────────────────────────────────── | ||||
|    1   │ struct Rectangle { | ||||
|    2   │     width: u32, | ||||
|    3   │     height: u32, | ||||
|    4   │ } | ||||
|    5   │  | ||||
|    6 _ │ fn main() { | ||||
|    7   │     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    8   │  | ||||
|    9   │     println!( | ||||
|   10 ~ │         "The perimeter of the rectangle is {} pixels.", | ||||
|   11 ~ │         perimeter(&rect1) | ||||
|   12   │     ); | ||||
|   13 + │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   14   │ } | ||||
|   15   │  | ||||
|   16   │ fn area(rectangle: &Rectangle) -> u32 { | ||||
|   17   │     rectangle.width * rectangle.height | ||||
|   18   │ } | ||||
|   19 + │  | ||||
|   20 + │ fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   21 + │     (rectangle.width + rectangle.height) * 2 | ||||
|   22 + │ } | ||||
|    1 + │ /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|    2   │ struct Rectangle { | ||||
|    3   │     width: u32, | ||||
|    4   │     height: u32, | ||||
|    5   │ } | ||||
|    6   │  | ||||
|    7 _ │ fn main() { | ||||
|    8   │     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    9   │  | ||||
|   10   │     println!( | ||||
|   11 ~ │         "The perimeter of the rectangle is {} pixels.", | ||||
|   12 ~ │         perimeter(&rect1) | ||||
|   13   │     ); | ||||
|   14 + │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   15   │ } | ||||
|   16   │  | ||||
|   17   │ fn area(rectangle: &Rectangle) -> u32 { | ||||
|   18   │     rectangle.width * rectangle.height | ||||
|   19   │ } | ||||
|   20 + │  | ||||
|   21 + │ fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   22 + │     (rectangle.width + rectangle.height) * 2 | ||||
|   23 + │ } | ||||
| ───────┴──────────────────────────────────────────────────────────────────────── | ||||
|   | ||||
| @@ -1,26 +1,27 @@ | ||||
| ───────┬──────────────────────────────────────────────────────────────────────── | ||||
|        │ File: sample.rs | ||||
| ───────┼──────────────────────────────────────────────────────────────────────── | ||||
|    1   │ struct Rectangle { | ||||
|    2   │     width: u32, | ||||
|    3   │     height: u32, | ||||
|    4   │ } | ||||
|    5   │  | ||||
|    6 _ │ fn main() { | ||||
|    7   │     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    8   │  | ||||
|    9   │     println!( | ||||
|   10 ~ │         "The perimeter of the rectangle is {} pixels.", | ||||
|   11 ~ │         perimeter(&rect1) | ||||
|   12   │     ); | ||||
|   13 + │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   14   │ } | ||||
|   15   │  | ||||
|   16   │ fn area(rectangle: &Rectangle) -> u32 { | ||||
|   17   │     rectangle.width * rectangle.height | ||||
|   18   │ } | ||||
|   19 + │  | ||||
|   20 + │ fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   21 + │     (rectangle.width + rectangle.height) * 2 | ||||
|   22 + │ } | ||||
|    1 + │ /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|    2   │ struct Rectangle { | ||||
|    3   │     width: u32, | ||||
|    4   │     height: u32, | ||||
|    5   │ } | ||||
|    6   │  | ||||
|    7 _ │ fn main() { | ||||
|    8   │     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    9   │  | ||||
|   10   │     println!( | ||||
|   11 ~ │         "The perimeter of the rectangle is {} pixels.", | ||||
|   12 ~ │         perimeter(&rect1) | ||||
|   13   │     ); | ||||
|   14 + │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   15   │ } | ||||
|   16   │  | ||||
|   17   │ fn area(rectangle: &Rectangle) -> u32 { | ||||
|   18   │     rectangle.width * rectangle.height | ||||
|   19   │ } | ||||
|   20 + │  | ||||
|   21 + │ fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   22 + │     (rectangle.width + rectangle.height) * 2 | ||||
|   23 + │ } | ||||
| ───────┴──────────────────────────────────────────────────────────────────────── | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| ──┬───────────────────────────────────────────────────────────────────────────── | ||||
|   │ File: sample.rs | ||||
| ──┼───────────────────────────────────────────────────────────────────────────── | ||||
| + │ /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|   │ struct Rectangle { | ||||
|   │     width: u32, | ||||
|   │     height: u32, | ||||
|   | ||||
| @@ -1,24 +1,25 @@ | ||||
| ───────┬──────────────────────────────────────────────────────────────────────── | ||||
|    1   │ struct Rectangle { | ||||
|    2   │     width: u32, | ||||
|    3   │     height: u32, | ||||
|    4   │ } | ||||
|    5   │  | ||||
|    6 _ │ fn main() { | ||||
|    7   │     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    8   │  | ||||
|    9   │     println!( | ||||
|   10 ~ │         "The perimeter of the rectangle is {} pixels.", | ||||
|   11 ~ │         perimeter(&rect1) | ||||
|   12   │     ); | ||||
|   13 + │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   14   │ } | ||||
|   15   │  | ||||
|   16   │ fn area(rectangle: &Rectangle) -> u32 { | ||||
|   17   │     rectangle.width * rectangle.height | ||||
|   18   │ } | ||||
|   19 + │  | ||||
|   20 + │ fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   21 + │     (rectangle.width + rectangle.height) * 2 | ||||
|   22 + │ } | ||||
|    1 + │ /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|    2   │ struct Rectangle { | ||||
|    3   │     width: u32, | ||||
|    4   │     height: u32, | ||||
|    5   │ } | ||||
|    6   │  | ||||
|    7 _ │ fn main() { | ||||
|    8   │     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    9   │  | ||||
|   10   │     println!( | ||||
|   11 ~ │         "The perimeter of the rectangle is {} pixels.", | ||||
|   12 ~ │         perimeter(&rect1) | ||||
|   13   │     ); | ||||
|   14 + │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   15   │ } | ||||
|   16   │  | ||||
|   17   │ fn area(rectangle: &Rectangle) -> u32 { | ||||
|   18   │     rectangle.width * rectangle.height | ||||
|   19   │ } | ||||
|   20 + │  | ||||
|   21 + │ fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   22 + │     (rectangle.width + rectangle.height) * 2 | ||||
|   23 + │ } | ||||
| ───────┴──────────────────────────────────────────────────────────────────────── | ||||
|   | ||||
| @@ -1,24 +1,25 @@ | ||||
| ───────┬──────────────────────────────────────────────────────────────────────── | ||||
|    1   │ struct Rectangle { | ||||
|    2   │     width: u32, | ||||
|    3   │     height: u32, | ||||
|    4   │ } | ||||
|    5   │  | ||||
|    6 _ │ fn main() { | ||||
|    7   │     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    8   │  | ||||
|    9   │     println!( | ||||
|   10 ~ │         "The perimeter of the rectangle is {} pixels.", | ||||
|   11 ~ │         perimeter(&rect1) | ||||
|   12   │     ); | ||||
|   13 + │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   14   │ } | ||||
|   15   │  | ||||
|   16   │ fn area(rectangle: &Rectangle) -> u32 { | ||||
|   17   │     rectangle.width * rectangle.height | ||||
|   18   │ } | ||||
|   19 + │  | ||||
|   20 + │ fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   21 + │     (rectangle.width + rectangle.height) * 2 | ||||
|   22 + │ } | ||||
|    1 + │ /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|    2   │ struct Rectangle { | ||||
|    3   │     width: u32, | ||||
|    4   │     height: u32, | ||||
|    5   │ } | ||||
|    6   │  | ||||
|    7 _ │ fn main() { | ||||
|    8   │     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    9   │  | ||||
|   10   │     println!( | ||||
|   11 ~ │         "The perimeter of the rectangle is {} pixels.", | ||||
|   12 ~ │         perimeter(&rect1) | ||||
|   13   │     ); | ||||
|   14 + │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   15   │ } | ||||
|   16   │  | ||||
|   17   │ fn area(rectangle: &Rectangle) -> u32 { | ||||
|   18   │     rectangle.width * rectangle.height | ||||
|   19   │ } | ||||
|   20 + │  | ||||
|   21 + │ fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   22 + │     (rectangle.width + rectangle.height) * 2 | ||||
|   23 + │ } | ||||
| ───────┴──────────────────────────────────────────────────────────────────────── | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| ──┬───────────────────────────────────────────────────────────────────────────── | ||||
| + │ /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|   │ struct Rectangle { | ||||
|   │     width: u32, | ||||
|   │     height: u32, | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
|   File: sample.rs | ||||
| + /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|   struct Rectangle { | ||||
|       width: u32, | ||||
|       height: u32, | ||||
|   | ||||
| @@ -1,23 +1,24 @@ | ||||
|        File: sample.rs | ||||
|    1   struct Rectangle { | ||||
|    2       width: u32, | ||||
|    3       height: u32, | ||||
|    4   } | ||||
|    5    | ||||
|    6 _ fn main() { | ||||
|    7       let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    8    | ||||
|    9       println!( | ||||
|   10 ~         "The perimeter of the rectangle is {} pixels.", | ||||
|   11 ~         perimeter(&rect1) | ||||
|   12       ); | ||||
|   13 +     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   14   } | ||||
|   15    | ||||
|   16   fn area(rectangle: &Rectangle) -> u32 { | ||||
|   17       rectangle.width * rectangle.height | ||||
|   18   } | ||||
|   19 +  | ||||
|   20 + fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   21 +     (rectangle.width + rectangle.height) * 2 | ||||
|   22 + } | ||||
|    1 + /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|    2   struct Rectangle { | ||||
|    3       width: u32, | ||||
|    4       height: u32, | ||||
|    5   } | ||||
|    6    | ||||
|    7 _ fn main() { | ||||
|    8       let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    9    | ||||
|   10       println!( | ||||
|   11 ~         "The perimeter of the rectangle is {} pixels.", | ||||
|   12 ~         perimeter(&rect1) | ||||
|   13       ); | ||||
|   14 +     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   15   } | ||||
|   16    | ||||
|   17   fn area(rectangle: &Rectangle) -> u32 { | ||||
|   18       rectangle.width * rectangle.height | ||||
|   19   } | ||||
|   20 +  | ||||
|   21 + fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   22 +     (rectangle.width + rectangle.height) * 2 | ||||
|   23 + } | ||||
|   | ||||
| @@ -1,23 +1,24 @@ | ||||
|        File: sample.rs | ||||
|    1   struct Rectangle { | ||||
|    2       width: u32, | ||||
|    3       height: u32, | ||||
|    4   } | ||||
|    5    | ||||
|    6 _ fn main() { | ||||
|    7       let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    8    | ||||
|    9       println!( | ||||
|   10 ~         "The perimeter of the rectangle is {} pixels.", | ||||
|   11 ~         perimeter(&rect1) | ||||
|   12       ); | ||||
|   13 +     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   14   } | ||||
|   15    | ||||
|   16   fn area(rectangle: &Rectangle) -> u32 { | ||||
|   17       rectangle.width * rectangle.height | ||||
|   18   } | ||||
|   19 +  | ||||
|   20 + fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   21 +     (rectangle.width + rectangle.height) * 2 | ||||
|   22 + } | ||||
|    1 + /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|    2   struct Rectangle { | ||||
|    3       width: u32, | ||||
|    4       height: u32, | ||||
|    5   } | ||||
|    6    | ||||
|    7 _ fn main() { | ||||
|    8       let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    9    | ||||
|   10       println!( | ||||
|   11 ~         "The perimeter of the rectangle is {} pixels.", | ||||
|   12 ~         perimeter(&rect1) | ||||
|   13       ); | ||||
|   14 +     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   15   } | ||||
|   16    | ||||
|   17   fn area(rectangle: &Rectangle) -> u32 { | ||||
|   18       rectangle.width * rectangle.height | ||||
|   19   } | ||||
|   20 +  | ||||
|   21 + fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   22 +     (rectangle.width + rectangle.height) * 2 | ||||
|   23 + } | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
|   File: sample.rs | ||||
| + /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|   struct Rectangle { | ||||
|       width: u32, | ||||
|       height: u32, | ||||
|   | ||||
| @@ -1,22 +1,23 @@ | ||||
|    1   struct Rectangle { | ||||
|    2       width: u32, | ||||
|    3       height: u32, | ||||
|    4   } | ||||
|    5    | ||||
|    6 _ fn main() { | ||||
|    7       let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    8    | ||||
|    9       println!( | ||||
|   10 ~         "The perimeter of the rectangle is {} pixels.", | ||||
|   11 ~         perimeter(&rect1) | ||||
|   12       ); | ||||
|   13 +     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   14   } | ||||
|   15    | ||||
|   16   fn area(rectangle: &Rectangle) -> u32 { | ||||
|   17       rectangle.width * rectangle.height | ||||
|   18   } | ||||
|   19 +  | ||||
|   20 + fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   21 +     (rectangle.width + rectangle.height) * 2 | ||||
|   22 + } | ||||
|    1 + /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|    2   struct Rectangle { | ||||
|    3       width: u32, | ||||
|    4       height: u32, | ||||
|    5   } | ||||
|    6    | ||||
|    7 _ fn main() { | ||||
|    8       let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    9    | ||||
|   10       println!( | ||||
|   11 ~         "The perimeter of the rectangle is {} pixels.", | ||||
|   12 ~         perimeter(&rect1) | ||||
|   13       ); | ||||
|   14 +     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   15   } | ||||
|   16    | ||||
|   17   fn area(rectangle: &Rectangle) -> u32 { | ||||
|   18       rectangle.width * rectangle.height | ||||
|   19   } | ||||
|   20 +  | ||||
|   21 + fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   22 +     (rectangle.width + rectangle.height) * 2 | ||||
|   23 + } | ||||
|   | ||||
| @@ -1,22 +1,23 @@ | ||||
|    1   struct Rectangle { | ||||
|    2       width: u32, | ||||
|    3       height: u32, | ||||
|    4   } | ||||
|    5    | ||||
|    6 _ fn main() { | ||||
|    7       let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    8    | ||||
|    9       println!( | ||||
|   10 ~         "The perimeter of the rectangle is {} pixels.", | ||||
|   11 ~         perimeter(&rect1) | ||||
|   12       ); | ||||
|   13 +     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   14   } | ||||
|   15    | ||||
|   16   fn area(rectangle: &Rectangle) -> u32 { | ||||
|   17       rectangle.width * rectangle.height | ||||
|   18   } | ||||
|   19 +  | ||||
|   20 + fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   21 +     (rectangle.width + rectangle.height) * 2 | ||||
|   22 + } | ||||
|    1 + /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|    2   struct Rectangle { | ||||
|    3       width: u32, | ||||
|    4       height: u32, | ||||
|    5   } | ||||
|    6    | ||||
|    7 _ fn main() { | ||||
|    8       let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    9    | ||||
|   10       println!( | ||||
|   11 ~         "The perimeter of the rectangle is {} pixels.", | ||||
|   12 ~         perimeter(&rect1) | ||||
|   13       ); | ||||
|   14 +     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   15   } | ||||
|   16    | ||||
|   17   fn area(rectangle: &Rectangle) -> u32 { | ||||
|   18       rectangle.width * rectangle.height | ||||
|   19   } | ||||
|   20 +  | ||||
|   21 + fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   22 +     (rectangle.width + rectangle.height) * 2 | ||||
|   23 + } | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| + /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|   struct Rectangle { | ||||
|       width: u32, | ||||
|       height: u32, | ||||
|   | ||||
							
								
								
									
										45
									
								
								tests/snapshots/output/full.snapshot.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										45
									
								
								tests/snapshots/output/full.snapshot.txt
									
									
									
									
										vendored
									
									
								
							| @@ -1,26 +1,27 @@ | ||||
| ───────┬──────────────────────────────────────────────────────────────────────── | ||||
|        │ File: sample.rs | ||||
| ───────┼──────────────────────────────────────────────────────────────────────── | ||||
|    1   │ struct Rectangle { | ||||
|    2   │     width: u32, | ||||
|    3   │     height: u32, | ||||
|    4   │ } | ||||
|    5   │  | ||||
|    6 _ │ fn main() { | ||||
|    7   │     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    8   │  | ||||
|    9   │     println!( | ||||
|   10 ~ │         "The perimeter of the rectangle is {} pixels.", | ||||
|   11 ~ │         perimeter(&rect1) | ||||
|   12   │     ); | ||||
|   13 + │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   14   │ } | ||||
|   15   │  | ||||
|   16   │ fn area(rectangle: &Rectangle) -> u32 { | ||||
|   17   │     rectangle.width * rectangle.height | ||||
|   18   │ } | ||||
|   19 + │  | ||||
|   20 + │ fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   21 + │     (rectangle.width + rectangle.height) * 2 | ||||
|   22 + │ } | ||||
|    1 + │ /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|    2   │ struct Rectangle { | ||||
|    3   │     width: u32, | ||||
|    4   │     height: u32, | ||||
|    5   │ } | ||||
|    6   │  | ||||
|    7 _ │ fn main() { | ||||
|    8   │     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    9   │  | ||||
|   10   │     println!( | ||||
|   11 ~ │         "The perimeter of the rectangle is {} pixels.", | ||||
|   12 ~ │         perimeter(&rect1) | ||||
|   13   │     ); | ||||
|   14 + │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   15   │ } | ||||
|   16   │  | ||||
|   17   │ fn area(rectangle: &Rectangle) -> u32 { | ||||
|   18   │     rectangle.width * rectangle.height | ||||
|   19   │ } | ||||
|   20 + │  | ||||
|   21 + │ fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   22 + │     (rectangle.width + rectangle.height) * 2 | ||||
|   23 + │ } | ||||
| ───────┴──────────────────────────────────────────────────────────────────────── | ||||
|   | ||||
							
								
								
									
										1
									
								
								tests/snapshots/output/grid.snapshot.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								tests/snapshots/output/grid.snapshot.txt
									
									
									
									
										vendored
									
									
								
							| @@ -1,4 +1,5 @@ | ||||
| ──────────────────────────────────────────────────────────────────────────────── | ||||
| /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
| struct Rectangle { | ||||
|     width: u32, | ||||
|     height: u32, | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| ──────────────────────────────────────────────────────────────────────────────── | ||||
| File: sample.rs | ||||
| ──────────────────────────────────────────────────────────────────────────────── | ||||
| /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
| struct Rectangle { | ||||
|     width: u32, | ||||
|     height: u32, | ||||
|   | ||||
| @@ -1,26 +1,27 @@ | ||||
| ─────┬────────────────────────────────────────────────────────────────────────── | ||||
|      │ File: sample.rs | ||||
| ─────┼────────────────────────────────────────────────────────────────────────── | ||||
|    1 │ struct Rectangle { | ||||
|    2 │     width: u32, | ||||
|    3 │     height: u32, | ||||
|    4 │ } | ||||
|    5 │  | ||||
|    6 │ fn main() { | ||||
|    7 │     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    8 │  | ||||
|    9 │     println!( | ||||
|   10 │         "The perimeter of the rectangle is {} pixels.", | ||||
|   11 │         perimeter(&rect1) | ||||
|   12 │     ); | ||||
|   13 │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   14 │ } | ||||
|   15 │  | ||||
|   16 │ fn area(rectangle: &Rectangle) -> u32 { | ||||
|   17 │     rectangle.width * rectangle.height | ||||
|   18 │ } | ||||
|   19 │  | ||||
|   20 │ fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   21 │     (rectangle.width + rectangle.height) * 2 | ||||
|   22 │ } | ||||
|    1 │ /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|    2 │ struct Rectangle { | ||||
|    3 │     width: u32, | ||||
|    4 │     height: u32, | ||||
|    5 │ } | ||||
|    6 │  | ||||
|    7 │ fn main() { | ||||
|    8 │     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    9 │  | ||||
|   10 │     println!( | ||||
|   11 │         "The perimeter of the rectangle is {} pixels.", | ||||
|   12 │         perimeter(&rect1) | ||||
|   13 │     ); | ||||
|   14 │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   15 │ } | ||||
|   16 │  | ||||
|   17 │ fn area(rectangle: &Rectangle) -> u32 { | ||||
|   18 │     rectangle.width * rectangle.height | ||||
|   19 │ } | ||||
|   20 │  | ||||
|   21 │ fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   22 │     (rectangle.width + rectangle.height) * 2 | ||||
|   23 │ } | ||||
| ─────┴────────────────────────────────────────────────────────────────────────── | ||||
|   | ||||
| @@ -1,26 +1,27 @@ | ||||
| ─────┬────────────────────────────────────────────────────────────────────────── | ||||
|      │ File: sample.rs | ||||
| ─────┼────────────────────────────────────────────────────────────────────────── | ||||
|    1 │ struct Rectangle { | ||||
|    2 │     width: u32, | ||||
|    3 │     height: u32, | ||||
|    4 │ } | ||||
|    5 │  | ||||
|    6 │ fn main() { | ||||
|    7 │     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    8 │  | ||||
|    9 │     println!( | ||||
|   10 │         "The perimeter of the rectangle is {} pixels.", | ||||
|   11 │         perimeter(&rect1) | ||||
|   12 │     ); | ||||
|   13 │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   14 │ } | ||||
|   15 │  | ||||
|   16 │ fn area(rectangle: &Rectangle) -> u32 { | ||||
|   17 │     rectangle.width * rectangle.height | ||||
|   18 │ } | ||||
|   19 │  | ||||
|   20 │ fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   21 │     (rectangle.width + rectangle.height) * 2 | ||||
|   22 │ } | ||||
|    1 │ /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|    2 │ struct Rectangle { | ||||
|    3 │     width: u32, | ||||
|    4 │     height: u32, | ||||
|    5 │ } | ||||
|    6 │  | ||||
|    7 │ fn main() { | ||||
|    8 │     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    9 │  | ||||
|   10 │     println!( | ||||
|   11 │         "The perimeter of the rectangle is {} pixels.", | ||||
|   12 │         perimeter(&rect1) | ||||
|   13 │     ); | ||||
|   14 │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   15 │ } | ||||
|   16 │  | ||||
|   17 │ fn area(rectangle: &Rectangle) -> u32 { | ||||
|   18 │     rectangle.width * rectangle.height | ||||
|   19 │ } | ||||
|   20 │  | ||||
|   21 │ fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   22 │     (rectangle.width + rectangle.height) * 2 | ||||
|   23 │ } | ||||
| ─────┴────────────────────────────────────────────────────────────────────────── | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| ──────────────────────────────────────────────────────────────────────────────── | ||||
| File: sample.rs | ||||
| ──────────────────────────────────────────────────────────────────────────────── | ||||
| /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
| struct Rectangle { | ||||
|     width: u32, | ||||
|     height: u32, | ||||
|   | ||||
							
								
								
									
										45
									
								
								tests/snapshots/output/grid_numbers.snapshot.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										45
									
								
								tests/snapshots/output/grid_numbers.snapshot.txt
									
									
									
									
										vendored
									
									
								
							| @@ -1,24 +1,25 @@ | ||||
| ─────┬────────────────────────────────────────────────────────────────────────── | ||||
|    1 │ struct Rectangle { | ||||
|    2 │     width: u32, | ||||
|    3 │     height: u32, | ||||
|    4 │ } | ||||
|    5 │  | ||||
|    6 │ fn main() { | ||||
|    7 │     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    8 │  | ||||
|    9 │     println!( | ||||
|   10 │         "The perimeter of the rectangle is {} pixels.", | ||||
|   11 │         perimeter(&rect1) | ||||
|   12 │     ); | ||||
|   13 │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   14 │ } | ||||
|   15 │  | ||||
|   16 │ fn area(rectangle: &Rectangle) -> u32 { | ||||
|   17 │     rectangle.width * rectangle.height | ||||
|   18 │ } | ||||
|   19 │  | ||||
|   20 │ fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   21 │     (rectangle.width + rectangle.height) * 2 | ||||
|   22 │ } | ||||
|    1 │ /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|    2 │ struct Rectangle { | ||||
|    3 │     width: u32, | ||||
|    4 │     height: u32, | ||||
|    5 │ } | ||||
|    6 │  | ||||
|    7 │ fn main() { | ||||
|    8 │     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    9 │  | ||||
|   10 │     println!( | ||||
|   11 │         "The perimeter of the rectangle is {} pixels.", | ||||
|   12 │         perimeter(&rect1) | ||||
|   13 │     ); | ||||
|   14 │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   15 │ } | ||||
|   16 │  | ||||
|   17 │ fn area(rectangle: &Rectangle) -> u32 { | ||||
|   18 │     rectangle.width * rectangle.height | ||||
|   19 │ } | ||||
|   20 │  | ||||
|   21 │ fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   22 │     (rectangle.width + rectangle.height) * 2 | ||||
|   23 │ } | ||||
| ─────┴────────────────────────────────────────────────────────────────────────── | ||||
|   | ||||
| @@ -1,24 +1,25 @@ | ||||
| ─────┬────────────────────────────────────────────────────────────────────────── | ||||
|    1 │ struct Rectangle { | ||||
|    2 │     width: u32, | ||||
|    3 │     height: u32, | ||||
|    4 │ } | ||||
|    5 │  | ||||
|    6 │ fn main() { | ||||
|    7 │     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    8 │  | ||||
|    9 │     println!( | ||||
|   10 │         "The perimeter of the rectangle is {} pixels.", | ||||
|   11 │         perimeter(&rect1) | ||||
|   12 │     ); | ||||
|   13 │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   14 │ } | ||||
|   15 │  | ||||
|   16 │ fn area(rectangle: &Rectangle) -> u32 { | ||||
|   17 │     rectangle.width * rectangle.height | ||||
|   18 │ } | ||||
|   19 │  | ||||
|   20 │ fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   21 │     (rectangle.width + rectangle.height) * 2 | ||||
|   22 │ } | ||||
|    1 │ /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|    2 │ struct Rectangle { | ||||
|    3 │     width: u32, | ||||
|    4 │     height: u32, | ||||
|    5 │ } | ||||
|    6 │  | ||||
|    7 │ fn main() { | ||||
|    8 │     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    9 │  | ||||
|   10 │     println!( | ||||
|   11 │         "The perimeter of the rectangle is {} pixels.", | ||||
|   12 │         perimeter(&rect1) | ||||
|   13 │     ); | ||||
|   14 │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   15 │ } | ||||
|   16 │  | ||||
|   17 │ fn area(rectangle: &Rectangle) -> u32 { | ||||
|   18 │     rectangle.width * rectangle.height | ||||
|   19 │ } | ||||
|   20 │  | ||||
|   21 │ fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   22 │     (rectangle.width + rectangle.height) * 2 | ||||
|   23 │ } | ||||
| ─────┴────────────────────────────────────────────────────────────────────────── | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| ──────────────────────────────────────────────────────────────────────────────── | ||||
| /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
| struct Rectangle { | ||||
|     width: u32, | ||||
|     height: u32, | ||||
|   | ||||
							
								
								
									
										1
									
								
								tests/snapshots/output/header.snapshot.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								tests/snapshots/output/header.snapshot.txt
									
									
									
									
										vendored
									
									
								
							| @@ -1,4 +1,5 @@ | ||||
| File: sample.rs | ||||
| /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
| struct Rectangle { | ||||
|     width: u32, | ||||
|     height: u32, | ||||
|   | ||||
| @@ -1,23 +1,24 @@ | ||||
|      File: sample.rs | ||||
|    1 struct Rectangle { | ||||
|    2     width: u32, | ||||
|    3     height: u32, | ||||
|    4 } | ||||
|    5  | ||||
|    6 fn main() { | ||||
|    7     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    8  | ||||
|    9     println!( | ||||
|   10         "The perimeter of the rectangle is {} pixels.", | ||||
|   11         perimeter(&rect1) | ||||
|   12     ); | ||||
|   13     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   14 } | ||||
|   15  | ||||
|   16 fn area(rectangle: &Rectangle) -> u32 { | ||||
|   17     rectangle.width * rectangle.height | ||||
|   18 } | ||||
|   19  | ||||
|   20 fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   21     (rectangle.width + rectangle.height) * 2 | ||||
|   22 } | ||||
|    1 /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|    2 struct Rectangle { | ||||
|    3     width: u32, | ||||
|    4     height: u32, | ||||
|    5 } | ||||
|    6  | ||||
|    7 fn main() { | ||||
|    8     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    9  | ||||
|   10     println!( | ||||
|   11         "The perimeter of the rectangle is {} pixels.", | ||||
|   12         perimeter(&rect1) | ||||
|   13     ); | ||||
|   14     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   15 } | ||||
|   16  | ||||
|   17 fn area(rectangle: &Rectangle) -> u32 { | ||||
|   18     rectangle.width * rectangle.height | ||||
|   19 } | ||||
|   20  | ||||
|   21 fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   22     (rectangle.width + rectangle.height) * 2 | ||||
|   23 } | ||||
|   | ||||
| @@ -1,23 +1,24 @@ | ||||
|      File: sample.rs | ||||
|    1 struct Rectangle { | ||||
|    2     width: u32, | ||||
|    3     height: u32, | ||||
|    4 } | ||||
|    5  | ||||
|    6 fn main() { | ||||
|    7     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    8  | ||||
|    9     println!( | ||||
|   10         "The perimeter of the rectangle is {} pixels.", | ||||
|   11         perimeter(&rect1) | ||||
|   12     ); | ||||
|   13     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   14 } | ||||
|   15  | ||||
|   16 fn area(rectangle: &Rectangle) -> u32 { | ||||
|   17     rectangle.width * rectangle.height | ||||
|   18 } | ||||
|   19  | ||||
|   20 fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   21     (rectangle.width + rectangle.height) * 2 | ||||
|   22 } | ||||
|    1 /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|    2 struct Rectangle { | ||||
|    3     width: u32, | ||||
|    4     height: u32, | ||||
|    5 } | ||||
|    6  | ||||
|    7 fn main() { | ||||
|    8     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    9  | ||||
|   10     println!( | ||||
|   11         "The perimeter of the rectangle is {} pixels.", | ||||
|   12         perimeter(&rect1) | ||||
|   13     ); | ||||
|   14     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   15 } | ||||
|   16  | ||||
|   17 fn area(rectangle: &Rectangle) -> u32 { | ||||
|   18     rectangle.width * rectangle.height | ||||
|   19 } | ||||
|   20  | ||||
|   21 fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   22     (rectangle.width + rectangle.height) * 2 | ||||
|   23 } | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| File: sample.rs | ||||
| /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
| struct Rectangle { | ||||
|     width: u32, | ||||
|     height: u32, | ||||
|   | ||||
							
								
								
									
										45
									
								
								tests/snapshots/output/numbers.snapshot.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										45
									
								
								tests/snapshots/output/numbers.snapshot.txt
									
									
									
									
										vendored
									
									
								
							| @@ -1,22 +1,23 @@ | ||||
|    1 struct Rectangle { | ||||
|    2     width: u32, | ||||
|    3     height: u32, | ||||
|    4 } | ||||
|    5  | ||||
|    6 fn main() { | ||||
|    7     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    8  | ||||
|    9     println!( | ||||
|   10         "The perimeter of the rectangle is {} pixels.", | ||||
|   11         perimeter(&rect1) | ||||
|   12     ); | ||||
|   13     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   14 } | ||||
|   15  | ||||
|   16 fn area(rectangle: &Rectangle) -> u32 { | ||||
|   17     rectangle.width * rectangle.height | ||||
|   18 } | ||||
|   19  | ||||
|   20 fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   21     (rectangle.width + rectangle.height) * 2 | ||||
|   22 } | ||||
|    1 /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|    2 struct Rectangle { | ||||
|    3     width: u32, | ||||
|    4     height: u32, | ||||
|    5 } | ||||
|    6  | ||||
|    7 fn main() { | ||||
|    8     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    9  | ||||
|   10     println!( | ||||
|   11         "The perimeter of the rectangle is {} pixels.", | ||||
|   12         perimeter(&rect1) | ||||
|   13     ); | ||||
|   14     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   15 } | ||||
|   16  | ||||
|   17 fn area(rectangle: &Rectangle) -> u32 { | ||||
|   18     rectangle.width * rectangle.height | ||||
|   19 } | ||||
|   20  | ||||
|   21 fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   22     (rectangle.width + rectangle.height) * 2 | ||||
|   23 } | ||||
|   | ||||
							
								
								
									
										45
									
								
								tests/snapshots/output/numbers_rule.snapshot.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										45
									
								
								tests/snapshots/output/numbers_rule.snapshot.txt
									
									
									
									
										vendored
									
									
								
							| @@ -1,22 +1,23 @@ | ||||
|    1 struct Rectangle { | ||||
|    2     width: u32, | ||||
|    3     height: u32, | ||||
|    4 } | ||||
|    5  | ||||
|    6 fn main() { | ||||
|    7     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    8  | ||||
|    9     println!( | ||||
|   10         "The perimeter of the rectangle is {} pixels.", | ||||
|   11         perimeter(&rect1) | ||||
|   12     ); | ||||
|   13     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   14 } | ||||
|   15  | ||||
|   16 fn area(rectangle: &Rectangle) -> u32 { | ||||
|   17     rectangle.width * rectangle.height | ||||
|   18 } | ||||
|   19  | ||||
|   20 fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   21     (rectangle.width + rectangle.height) * 2 | ||||
|   22 } | ||||
|    1 /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
|    2 struct Rectangle { | ||||
|    3     width: u32, | ||||
|    4     height: u32, | ||||
|    5 } | ||||
|    6  | ||||
|    7 fn main() { | ||||
|    8     let rect1 = Rectangle { width: 30, height: 50 }; | ||||
|    9  | ||||
|   10     println!( | ||||
|   11         "The perimeter of the rectangle is {} pixels.", | ||||
|   12         perimeter(&rect1) | ||||
|   13     ); | ||||
|   14     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#; | ||||
|   15 } | ||||
|   16  | ||||
|   17 fn area(rectangle: &Rectangle) -> u32 { | ||||
|   18     rectangle.width * rectangle.height | ||||
|   19 } | ||||
|   20  | ||||
|   21 fn perimeter(rectangle: &Rectangle) -> u32 { | ||||
|   22     (rectangle.width + rectangle.height) * 2 | ||||
|   23 } | ||||
|   | ||||
							
								
								
									
										1
									
								
								tests/snapshots/output/plain.snapshot.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								tests/snapshots/output/plain.snapshot.txt
									
									
									
									
										vendored
									
									
								
							| @@ -1,3 +1,4 @@ | ||||
| /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
| struct Rectangle { | ||||
|     width: u32, | ||||
|     height: u32, | ||||
|   | ||||
							
								
								
									
										1
									
								
								tests/snapshots/output/rule.snapshot.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								tests/snapshots/output/rule.snapshot.txt
									
									
									
									
										vendored
									
									
								
							| @@ -1,3 +1,4 @@ | ||||
| /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
| struct Rectangle { | ||||
|     width: u32, | ||||
|     height: u32, | ||||
|   | ||||
							
								
								
									
										1
									
								
								tests/snapshots/sample.modified.rs
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								tests/snapshots/sample.modified.rs
									
									
									
									
										vendored
									
									
								
							| @@ -1,3 +1,4 @@ | ||||
| /// A rectangle. First line is changed to prevent a regression of #1869 | ||||
| struct Rectangle { | ||||
|     width: u32, | ||||
|     height: u32, | ||||
|   | ||||
							
								
								
									
										21
									
								
								tests/syntax-tests/BatTestCustomAssets.sublime-syntax
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								tests/syntax-tests/BatTestCustomAssets.sublime-syntax
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| %YAML 1.2 | ||||
| --- | ||||
| # http://www.sublimetext.com/docs/3/syntax.html | ||||
| name: BatTestCustomAssets | ||||
| file_extensions: | ||||
|   - battestcustomassets | ||||
| scope: source.battestcustomassets | ||||
|  | ||||
| # This syntax is used to test if custom assets work with bat. | ||||
| # The way it works is that this syntax is only allowed to be included with | ||||
| # custom assets. That way it is easy to test if custom assets are used (and works) | ||||
| # or not. | ||||
| # | ||||
| # This syntax is based on CpuInfo.sublime-syntax. | ||||
|  | ||||
| contexts: | ||||
|   main: | ||||
|     - match: '^([^:]+)\w*:\w*(.*)$' | ||||
|       captures: | ||||
|         1: keyword.other.battestcustomassets-key | ||||
|         2: string.other.battestcustomassets-value | ||||
| @@ -6,7 +6,7 @@ import sys | ||||
| import os.path as path | ||||
| import os | ||||
| import argparse | ||||
|  | ||||
| from multiprocessing import Pool | ||||
|  | ||||
| BAT_OPTIONS = [ | ||||
|     "--no-config", | ||||
| @@ -38,64 +38,79 @@ def get_options(source): | ||||
|     return options | ||||
|  | ||||
|  | ||||
| def create_highlighted_version(args): | ||||
|     output_basepath, source = args | ||||
|     env = os.environ.copy() | ||||
|     env.pop("BAT_CACHE_PATH", None) | ||||
|     env.pop("BAT_CONFIG_DIR", None) | ||||
|     env.pop("BAT_CONFIG_PATH", None) | ||||
|     env.pop("BAT_OPTS", None) | ||||
|     env.pop("BAT_PAGER", None) | ||||
|     env.pop("BAT_STYLE", None) | ||||
|     env.pop("BAT_TABS", None) | ||||
|     env.pop("BAT_THEME", None) | ||||
|     env.pop("NO_COLOR", None) | ||||
|     env.pop("PAGER", None) | ||||
|     env["COLORTERM"] = "truecolor"  # make sure to output 24bit colors | ||||
|  | ||||
|     source_dirname = path.basename(path.dirname(source)) | ||||
|     source_filename = path.basename(source) | ||||
|  | ||||
|     if source_filename in SKIP_FILENAMES: | ||||
|         return | ||||
|  | ||||
|     bat_output = subprocess.check_output( | ||||
|         ["bat"] + get_options(source) + [source], | ||||
|         stderr=subprocess.PIPE, | ||||
|         env=env, | ||||
|     ) | ||||
|  | ||||
|     output_dir = path.join(output_basepath, source_dirname) | ||||
|     output_path = path.join(output_dir, source_filename) | ||||
|  | ||||
|     os.makedirs(output_dir, exist_ok=True) | ||||
|  | ||||
|     with open(output_path, "wb") as output_file: | ||||
|         output_file.write(bat_output) | ||||
|  | ||||
|     print("Created '{}'".format(output_path)) | ||||
|  | ||||
|  | ||||
| def create_highlighted_versions(output_basepath): | ||||
|     root = os.path.dirname(os.path.abspath(__file__)) | ||||
|     sources = path.join(root, "source", "*") | ||||
|     source_paths = path.join(root, "source", "*") | ||||
|  | ||||
|     for source in glob.glob(path.join(sources, "*")) + glob.glob( | ||||
|         path.join(sources, ".*") | ||||
|     sources = [] | ||||
|     for source in glob.glob(path.join(source_paths, "*")) + glob.glob( | ||||
|         path.join(source_paths, ".*") | ||||
|     ): | ||||
|         try: | ||||
|             env = os.environ.copy() | ||||
|             env.pop("PAGER", None) | ||||
|             env.pop("BAT_PAGER", None) | ||||
|             env.pop("BAT_CONFIG_PATH", None) | ||||
|             env.pop("BAT_STYLE", None) | ||||
|             env.pop("BAT_THEME", None) | ||||
|             env.pop("BAT_TABS", None) | ||||
|             env["COLORTERM"] = "truecolor"  # make sure to output 24bit colors | ||||
|         sources.append((output_basepath, source)) | ||||
|  | ||||
|             source_dirname = path.basename(path.dirname(source)) | ||||
|             source_filename = path.basename(source) | ||||
|     try: | ||||
|         with Pool() as p: | ||||
|             p.map(create_highlighted_version, sources) | ||||
|     except subprocess.CalledProcessError as err: | ||||
|         print( | ||||
|             "=== Error: Could not highlight source file '{}".format(source), | ||||
|             file=sys.stderr, | ||||
|         ) | ||||
|         print( | ||||
|             "=== bat stdout:\n{}".format(err.stdout.decode("utf-8")), | ||||
|             file=sys.stderr, | ||||
|         ) | ||||
|         print( | ||||
|             "=== bat stderr:\n{}".format(err.stderr.decode("utf-8")), | ||||
|             file=sys.stderr, | ||||
|         ) | ||||
|         return False | ||||
|     except FileNotFoundError: | ||||
|         print( | ||||
|             "Error: Could not execute 'bat'. Please make sure that the executable " | ||||
|             "is available on the PATH." | ||||
|         ) | ||||
|         return False | ||||
|  | ||||
|             if source_filename in SKIP_FILENAMES: | ||||
|                 continue | ||||
|  | ||||
|             bat_output = subprocess.check_output( | ||||
|                 ["bat"] + get_options(source) + [source], | ||||
|                 stderr=subprocess.PIPE, | ||||
|                 env=env, | ||||
|             ) | ||||
|  | ||||
|             output_dir = path.join(output_basepath, source_dirname) | ||||
|             output_path = path.join(output_dir, source_filename) | ||||
|  | ||||
|             os.makedirs(output_dir, exist_ok=True) | ||||
|  | ||||
|             with open(output_path, "wb") as output_file: | ||||
|                 output_file.write(bat_output) | ||||
|  | ||||
|             print("Created '{}'".format(output_path)) | ||||
|         except subprocess.CalledProcessError as err: | ||||
|             print( | ||||
|                 "=== Error: Could not highlight source file '{}".format(source), | ||||
|                 file=sys.stderr, | ||||
|             ) | ||||
|             print( | ||||
|                 "=== bat stdout:\n{}".format(err.stdout.decode("utf-8")), | ||||
|                 file=sys.stderr, | ||||
|             ) | ||||
|             print( | ||||
|                 "=== bat stderr:\n{}".format(err.stderr.decode("utf-8")), | ||||
|                 file=sys.stderr, | ||||
|             ) | ||||
|             sys.exit(1) | ||||
|         except FileNotFoundError: | ||||
|             print( | ||||
|                 "Error: Could not execute 'bat'. Please make sure that the executable " | ||||
|                 "is available on the PATH." | ||||
|             ) | ||||
|             sys.exit(1) | ||||
|     return True | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
| @@ -114,4 +129,5 @@ if __name__ == "__main__": | ||||
|  | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     create_highlighted_versions(output_basepath=args.output) | ||||
|     if not create_highlighted_versions(output_basepath=args.output): | ||||
|         sys.exit(1) | ||||
|   | ||||
| @@ -0,0 +1,2 @@ | ||||
| [38;2;248;248;242mcustom assets : 0[0m | ||||
| [38;2;248;248;242mare           : the best[0m | ||||
| @@ -1,45 +0,0 @@ | ||||
| [38;2;248;248;242mprocessor    : 0[0m | ||||
| [38;2;248;248;242mmodel name    : ARMv7 Processor rev 3 (v7l)[0m | ||||
| [38;2;248;248;242mBogoMIPS    : 270.00[0m | ||||
| [38;2;248;248;242mFeatures    : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32[0m | ||||
| [38;2;248;248;242mCPU implementer    : 0x41[0m | ||||
| [38;2;248;248;242mCPU architecture: 7[0m | ||||
| [38;2;248;248;242mCPU variant    : 0x0[0m | ||||
| [38;2;248;248;242mCPU part    : 0xd08[0m | ||||
| [38;2;248;248;242mCPU revision    : 3[0m | ||||
|  | ||||
| [38;2;248;248;242mprocessor    : 1[0m | ||||
| [38;2;248;248;242mmodel name    : ARMv7 Processor rev 3 (v7l)[0m | ||||
| [38;2;248;248;242mBogoMIPS    : 270.00[0m | ||||
| [38;2;248;248;242mFeatures    : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32[0m | ||||
| [38;2;248;248;242mCPU implementer    : 0x41[0m | ||||
| [38;2;248;248;242mCPU architecture: 7[0m | ||||
| [38;2;248;248;242mCPU variant    : 0x0[0m | ||||
| [38;2;248;248;242mCPU part    : 0xd08[0m | ||||
| [38;2;248;248;242mCPU revision    : 3[0m | ||||
|  | ||||
| [38;2;248;248;242mprocessor    : 2[0m | ||||
| [38;2;248;248;242mmodel name    : ARMv7 Processor rev 3 (v7l)[0m | ||||
| [38;2;248;248;242mBogoMIPS    : 270.00[0m | ||||
| [38;2;248;248;242mFeatures    : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32[0m | ||||
| [38;2;248;248;242mCPU implementer    : 0x41[0m | ||||
| [38;2;248;248;242mCPU architecture: 7[0m | ||||
| [38;2;248;248;242mCPU variant    : 0x0[0m | ||||
| [38;2;248;248;242mCPU part    : 0xd08[0m | ||||
| [38;2;248;248;242mCPU revision    : 3[0m | ||||
|  | ||||
| [38;2;248;248;242mprocessor    : 3[0m | ||||
| [38;2;248;248;242mmodel name    : ARMv7 Processor rev 3 (v7l)[0m | ||||
| [38;2;248;248;242mBogoMIPS    : 270.00[0m | ||||
| [38;2;248;248;242mFeatures    : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32[0m | ||||
| [38;2;248;248;242mCPU implementer    : 0x41[0m | ||||
| [38;2;248;248;242mCPU architecture: 7[0m | ||||
| [38;2;248;248;242mCPU variant    : 0x0[0m | ||||
| [38;2;248;248;242mCPU part    : 0xd08[0m | ||||
| [38;2;248;248;242mCPU revision    : 3[0m | ||||
|  | ||||
| [38;2;248;248;242mHardware    : BCM2711[0m | ||||
| [38;2;248;248;242mRevision    : b03111[0m | ||||
| [38;2;248;248;242mSerial        : 1000000095fd9fc5[0m | ||||
| [38;2;248;248;242mModel        : Raspberry Pi 4 Model B Rev 1.1[0m | ||||
|  | ||||
							
								
								
									
										45
									
								
								tests/syntax-tests/highlighted/CpuInfo/test.cpuinfo
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								tests/syntax-tests/highlighted/CpuInfo/test.cpuinfo
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| [38;2;249;38;114mprocessor    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 0[0m | ||||
| [38;2;249;38;114mmodel name    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m ARMv7 Processor rev 3 (v7l)[0m | ||||
| [38;2;249;38;114mBogoMIPS    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 270.00[0m | ||||
| [38;2;249;38;114mFeatures    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32[0m | ||||
| [38;2;249;38;114mCPU implementer    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 0x41[0m | ||||
| [38;2;249;38;114mCPU architecture[0m[38;2;248;248;242m:[0m[38;2;230;219;116m 7[0m | ||||
| [38;2;249;38;114mCPU variant    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 0x0[0m | ||||
| [38;2;249;38;114mCPU part    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 0xd08[0m | ||||
| [38;2;249;38;114mCPU revision    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 3[0m | ||||
|  | ||||
| [38;2;249;38;114mprocessor    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 1[0m | ||||
| [38;2;249;38;114mmodel name    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m ARMv7 Processor rev 3 (v7l)[0m | ||||
| [38;2;249;38;114mBogoMIPS    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 270.00[0m | ||||
| [38;2;249;38;114mFeatures    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32[0m | ||||
| [38;2;249;38;114mCPU implementer    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 0x41[0m | ||||
| [38;2;249;38;114mCPU architecture[0m[38;2;248;248;242m:[0m[38;2;230;219;116m 7[0m | ||||
| [38;2;249;38;114mCPU variant    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 0x0[0m | ||||
| [38;2;249;38;114mCPU part    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 0xd08[0m | ||||
| [38;2;249;38;114mCPU revision    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 3[0m | ||||
|  | ||||
| [38;2;249;38;114mprocessor    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 2[0m | ||||
| [38;2;249;38;114mmodel name    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m ARMv7 Processor rev 3 (v7l)[0m | ||||
| [38;2;249;38;114mBogoMIPS    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 270.00[0m | ||||
| [38;2;249;38;114mFeatures    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32[0m | ||||
| [38;2;249;38;114mCPU implementer    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 0x41[0m | ||||
| [38;2;249;38;114mCPU architecture[0m[38;2;248;248;242m:[0m[38;2;230;219;116m 7[0m | ||||
| [38;2;249;38;114mCPU variant    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 0x0[0m | ||||
| [38;2;249;38;114mCPU part    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 0xd08[0m | ||||
| [38;2;249;38;114mCPU revision    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 3[0m | ||||
|  | ||||
| [38;2;249;38;114mprocessor    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 3[0m | ||||
| [38;2;249;38;114mmodel name    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m ARMv7 Processor rev 3 (v7l)[0m | ||||
| [38;2;249;38;114mBogoMIPS    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 270.00[0m | ||||
| [38;2;249;38;114mFeatures    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32[0m | ||||
| [38;2;249;38;114mCPU implementer    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 0x41[0m | ||||
| [38;2;249;38;114mCPU architecture[0m[38;2;248;248;242m:[0m[38;2;230;219;116m 7[0m | ||||
| [38;2;249;38;114mCPU variant    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 0x0[0m | ||||
| [38;2;249;38;114mCPU part    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 0xd08[0m | ||||
| [38;2;249;38;114mCPU revision    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 3[0m | ||||
|  | ||||
| [38;2;249;38;114mHardware    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m BCM2711[0m | ||||
| [38;2;249;38;114mRevision    [0m[38;2;248;248;242m:[0m[38;2;230;219;116m b03111[0m | ||||
| [38;2;249;38;114mSerial        [0m[38;2;248;248;242m:[0m[38;2;230;219;116m 1000000095fd9fc5[0m | ||||
| [38;2;249;38;114mModel        [0m[38;2;248;248;242m:[0m[38;2;230;219;116m Raspberry Pi 4 Model B Rev 1.1[0m | ||||
|  | ||||
							
								
								
									
										1
									
								
								tests/syntax-tests/highlighted/Ignored suffixes/test.rs.ucf-dist
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/syntax-tests/highlighted/Ignored suffixes/test.rs.ucf-dist
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| [38;2;117;113;94m//[0m[38;2;117;113;94m foo.ucf-dist (Debian ucf backup) should highlight same as foo[0m | ||||
							
								
								
									
										1
									
								
								tests/syntax-tests/highlighted/Ignored suffixes/test.rs.ucf-new
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/syntax-tests/highlighted/Ignored suffixes/test.rs.ucf-new
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| [38;2;117;113;94m//[0m[38;2;117;113;94m foo.ucf-new (Debian ucf backup) should highlight same as foo[0m | ||||
							
								
								
									
										1
									
								
								tests/syntax-tests/highlighted/Ignored suffixes/test.rs.ucf-old
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/syntax-tests/highlighted/Ignored suffixes/test.rs.ucf-old
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| [38;2;117;113;94m//[0m[38;2;117;113;94m foo.ucf-old (Debian ucf backup) should highlight same as foo[0m | ||||
| @@ -1,53 +0,0 @@ | ||||
| [38;2;248;248;242mMemTotal:        1004892 kB[0m | ||||
| [38;2;248;248;242mMemFree:          109424 kB[0m | ||||
| [38;2;248;248;242mMemAvailable:     498032 kB[0m | ||||
| [38;2;248;248;242mBuffers:           66360 kB[0m | ||||
| [38;2;248;248;242mCached:           448344 kB[0m | ||||
| [38;2;248;248;242mSwapCached:            0 kB[0m | ||||
| [38;2;248;248;242mActive:           547076 kB[0m | ||||
| [38;2;248;248;242mInactive:         196864 kB[0m | ||||
| [38;2;248;248;242mActive(anon):     249956 kB[0m | ||||
| [38;2;248;248;242mInactive(anon):     7328 kB[0m | ||||
| [38;2;248;248;242mActive(file):     297120 kB[0m | ||||
| [38;2;248;248;242mInactive(file):   189536 kB[0m | ||||
| [38;2;248;248;242mUnevictable:       18516 kB[0m | ||||
| [38;2;248;248;242mMlocked:           18516 kB[0m | ||||
| [38;2;248;248;242mSwapTotal:             0 kB[0m | ||||
| [38;2;248;248;242mSwapFree:              0 kB[0m | ||||
| [38;2;248;248;242mDirty:               276 kB[0m | ||||
| [38;2;248;248;242mWriteback:             0 kB[0m | ||||
| [38;2;248;248;242mAnonPages:        247780 kB[0m | ||||
| [38;2;248;248;242mMapped:           168472 kB[0m | ||||
| [38;2;248;248;242mShmem:             19860 kB[0m | ||||
| [38;2;248;248;242mKReclaimable:      59128 kB[0m | ||||
| [38;2;248;248;242mSlab:             108616 kB[0m | ||||
| [38;2;248;248;242mSReclaimable:      59128 kB[0m | ||||
| [38;2;248;248;242mSUnreclaim:        49488 kB[0m | ||||
| [38;2;248;248;242mKernelStack:        2060 kB[0m | ||||
| [38;2;248;248;242mPageTables:         4232 kB[0m | ||||
| [38;2;248;248;242mNFS_Unstable:          0 kB[0m | ||||
| [38;2;248;248;242mBounce:                0 kB[0m | ||||
| [38;2;248;248;242mWritebackTmp:          0 kB[0m | ||||
| [38;2;248;248;242mCommitLimit:      502444 kB[0m | ||||
| [38;2;248;248;242mCommitted_AS:     678300 kB[0m | ||||
| [38;2;248;248;242mVmallocTotal:   34359738367 kB[0m | ||||
| [38;2;248;248;242mVmallocUsed:       10756 kB[0m | ||||
| [38;2;248;248;242mVmallocChunk:          0 kB[0m | ||||
| [38;2;248;248;242mPercpu:              784 kB[0m | ||||
| [38;2;248;248;242mHardwareCorrupted:     0 kB[0m | ||||
| [38;2;248;248;242mAnonHugePages:         0 kB[0m | ||||
| [38;2;248;248;242mShmemHugePages:        0 kB[0m | ||||
| [38;2;248;248;242mShmemPmdMapped:        0 kB[0m | ||||
| [38;2;248;248;242mFileHugePages:         0 kB[0m | ||||
| [38;2;248;248;242mFilePmdMapped:         0 kB[0m | ||||
| [38;2;248;248;242mCmaTotal:              0 kB[0m | ||||
| [38;2;248;248;242mCmaFree:               0 kB[0m | ||||
| [38;2;248;248;242mHugePages_Total:       0[0m | ||||
| [38;2;248;248;242mHugePages_Free:        0[0m | ||||
| [38;2;248;248;242mHugePages_Rsvd:        0[0m | ||||
| [38;2;248;248;242mHugePages_Surp:        0[0m | ||||
| [38;2;248;248;242mHugepagesize:       2048 kB[0m | ||||
| [38;2;248;248;242mHugetlb:               0 kB[0m | ||||
| [38;2;248;248;242mDirectMap4k:      118764 kB[0m | ||||
| [38;2;248;248;242mDirectMap2M:      929792 kB[0m | ||||
| [38;2;248;248;242mDirectMap1G:           0 kB[0m | ||||
							
								
								
									
										53
									
								
								tests/syntax-tests/highlighted/MemInfo/test.meminfo
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								tests/syntax-tests/highlighted/MemInfo/test.meminfo
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| [38;2;249;38;114mMemTotal[0m[38;2;248;248;242m:[0m[38;2;230;219;116m        1004892 kB[0m | ||||
| [38;2;249;38;114mMemFree[0m[38;2;248;248;242m:[0m[38;2;230;219;116m          109424 kB[0m | ||||
| [38;2;249;38;114mMemAvailable[0m[38;2;248;248;242m:[0m[38;2;230;219;116m     498032 kB[0m | ||||
| [38;2;249;38;114mBuffers[0m[38;2;248;248;242m:[0m[38;2;230;219;116m           66360 kB[0m | ||||
| [38;2;249;38;114mCached[0m[38;2;248;248;242m:[0m[38;2;230;219;116m           448344 kB[0m | ||||
| [38;2;249;38;114mSwapCached[0m[38;2;248;248;242m:[0m[38;2;230;219;116m            0 kB[0m | ||||
| [38;2;249;38;114mActive[0m[38;2;248;248;242m:[0m[38;2;230;219;116m           547076 kB[0m | ||||
| [38;2;249;38;114mInactive[0m[38;2;248;248;242m:[0m[38;2;230;219;116m         196864 kB[0m | ||||
| [38;2;249;38;114mActive(anon)[0m[38;2;248;248;242m:[0m[38;2;230;219;116m     249956 kB[0m | ||||
| [38;2;249;38;114mInactive(anon)[0m[38;2;248;248;242m:[0m[38;2;230;219;116m     7328 kB[0m | ||||
| [38;2;249;38;114mActive(file)[0m[38;2;248;248;242m:[0m[38;2;230;219;116m     297120 kB[0m | ||||
| [38;2;249;38;114mInactive(file)[0m[38;2;248;248;242m:[0m[38;2;230;219;116m   189536 kB[0m | ||||
| [38;2;249;38;114mUnevictable[0m[38;2;248;248;242m:[0m[38;2;230;219;116m       18516 kB[0m | ||||
| [38;2;249;38;114mMlocked[0m[38;2;248;248;242m:[0m[38;2;230;219;116m           18516 kB[0m | ||||
| [38;2;249;38;114mSwapTotal[0m[38;2;248;248;242m:[0m[38;2;230;219;116m             0 kB[0m | ||||
| [38;2;249;38;114mSwapFree[0m[38;2;248;248;242m:[0m[38;2;230;219;116m              0 kB[0m | ||||
| [38;2;249;38;114mDirty[0m[38;2;248;248;242m:[0m[38;2;230;219;116m               276 kB[0m | ||||
| [38;2;249;38;114mWriteback[0m[38;2;248;248;242m:[0m[38;2;230;219;116m             0 kB[0m | ||||
| [38;2;249;38;114mAnonPages[0m[38;2;248;248;242m:[0m[38;2;230;219;116m        247780 kB[0m | ||||
| [38;2;249;38;114mMapped[0m[38;2;248;248;242m:[0m[38;2;230;219;116m           168472 kB[0m | ||||
| [38;2;249;38;114mShmem[0m[38;2;248;248;242m:[0m[38;2;230;219;116m             19860 kB[0m | ||||
| [38;2;249;38;114mKReclaimable[0m[38;2;248;248;242m:[0m[38;2;230;219;116m      59128 kB[0m | ||||
| [38;2;249;38;114mSlab[0m[38;2;248;248;242m:[0m[38;2;230;219;116m             108616 kB[0m | ||||
| [38;2;249;38;114mSReclaimable[0m[38;2;248;248;242m:[0m[38;2;230;219;116m      59128 kB[0m | ||||
| [38;2;249;38;114mSUnreclaim[0m[38;2;248;248;242m:[0m[38;2;230;219;116m        49488 kB[0m | ||||
| [38;2;249;38;114mKernelStack[0m[38;2;248;248;242m:[0m[38;2;230;219;116m        2060 kB[0m | ||||
| [38;2;249;38;114mPageTables[0m[38;2;248;248;242m:[0m[38;2;230;219;116m         4232 kB[0m | ||||
| [38;2;249;38;114mNFS_Unstable[0m[38;2;248;248;242m:[0m[38;2;230;219;116m          0 kB[0m | ||||
| [38;2;249;38;114mBounce[0m[38;2;248;248;242m:[0m[38;2;230;219;116m                0 kB[0m | ||||
| [38;2;249;38;114mWritebackTmp[0m[38;2;248;248;242m:[0m[38;2;230;219;116m          0 kB[0m | ||||
| [38;2;249;38;114mCommitLimit[0m[38;2;248;248;242m:[0m[38;2;230;219;116m      502444 kB[0m | ||||
| [38;2;249;38;114mCommitted_AS[0m[38;2;248;248;242m:[0m[38;2;230;219;116m     678300 kB[0m | ||||
| [38;2;249;38;114mVmallocTotal[0m[38;2;248;248;242m:[0m[38;2;230;219;116m   34359738367 kB[0m | ||||
| [38;2;249;38;114mVmallocUsed[0m[38;2;248;248;242m:[0m[38;2;230;219;116m       10756 kB[0m | ||||
| [38;2;249;38;114mVmallocChunk[0m[38;2;248;248;242m:[0m[38;2;230;219;116m          0 kB[0m | ||||
| [38;2;249;38;114mPercpu[0m[38;2;248;248;242m:[0m[38;2;230;219;116m              784 kB[0m | ||||
| [38;2;249;38;114mHardwareCorrupted[0m[38;2;248;248;242m:[0m[38;2;230;219;116m     0 kB[0m | ||||
| [38;2;249;38;114mAnonHugePages[0m[38;2;248;248;242m:[0m[38;2;230;219;116m         0 kB[0m | ||||
| [38;2;249;38;114mShmemHugePages[0m[38;2;248;248;242m:[0m[38;2;230;219;116m        0 kB[0m | ||||
| [38;2;249;38;114mShmemPmdMapped[0m[38;2;248;248;242m:[0m[38;2;230;219;116m        0 kB[0m | ||||
| [38;2;249;38;114mFileHugePages[0m[38;2;248;248;242m:[0m[38;2;230;219;116m         0 kB[0m | ||||
| [38;2;249;38;114mFilePmdMapped[0m[38;2;248;248;242m:[0m[38;2;230;219;116m         0 kB[0m | ||||
| [38;2;249;38;114mCmaTotal[0m[38;2;248;248;242m:[0m[38;2;230;219;116m              0 kB[0m | ||||
| [38;2;249;38;114mCmaFree[0m[38;2;248;248;242m:[0m[38;2;230;219;116m               0 kB[0m | ||||
| [38;2;249;38;114mHugePages_Total[0m[38;2;248;248;242m:[0m[38;2;230;219;116m       0[0m | ||||
| [38;2;249;38;114mHugePages_Free[0m[38;2;248;248;242m:[0m[38;2;230;219;116m        0[0m | ||||
| [38;2;249;38;114mHugePages_Rsvd[0m[38;2;248;248;242m:[0m[38;2;230;219;116m        0[0m | ||||
| [38;2;249;38;114mHugePages_Surp[0m[38;2;248;248;242m:[0m[38;2;230;219;116m        0[0m | ||||
| [38;2;249;38;114mHugepagesize[0m[38;2;248;248;242m:[0m[38;2;230;219;116m       2048 kB[0m | ||||
| [38;2;249;38;114mHugetlb[0m[38;2;248;248;242m:[0m[38;2;230;219;116m               0 kB[0m | ||||
| [38;2;249;38;114mDirectMap4k[0m[38;2;248;248;242m:[0m[38;2;230;219;116m      118764 kB[0m | ||||
| [38;2;249;38;114mDirectMap2M[0m[38;2;248;248;242m:[0m[38;2;230;219;116m      929792 kB[0m | ||||
| [38;2;249;38;114mDirectMap1G[0m[38;2;248;248;242m:[0m[38;2;230;219;116m           0 kB[0m | ||||
							
								
								
									
										56
									
								
								tests/syntax-tests/highlighted/Racket/test.rkt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								tests/syntax-tests/highlighted/Racket/test.rkt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| [38;2;248;248;242m#lang racket[0m | ||||
|  | ||||
| [38;2;248;248;242m([0m[38;2;249;38;114mrequire[0m[38;2;248;248;242m [0m[38;2;248;248;242m"main.rkt" rackunit)[0m | ||||
|  | ||||
| [38;2;117;113;94m;; Helper for test cases with multiple outputs[0m | ||||
| [38;2;117;113;94m;; See: https://stackoverflow.com/questions/41081395/unit-testing-in-racket-with-multiple-outputs[0m | ||||
| [38;2;248;248;242m(define-syntax check-values-equal?[0m | ||||
| [38;2;248;248;242m  (syntax-rules ()[0m | ||||
| [38;2;248;248;242m    [(_ a b) (check-equal? (call-with-values (thunk a) list) b)]))[0m | ||||
|  | ||||
|  | ||||
| [38;2;117;113;94m;; Named POSIX semaphores[0m | ||||
| [38;2;248;248;242m(test-begin[0m | ||||
| [38;2;248;248;242m  [0m[38;2;248;248;242m([0m[38;2;249;38;114mdefine[0m[38;2;248;248;242m [0m[38;2;166;226;46mtest-sem-name[0m[38;2;248;248;242m [0m[38;2;248;248;242m"/test-nix-[0m[38;2;190;132;255m1[0m[38;2;248;248;242m")[0m | ||||
|  | ||||
| [38;2;248;248;242m  [0m[38;2;117;113;94m;; Unlink if already exists[0m | ||||
| [38;2;248;248;242m  (sem-unlink test-sem-name)[0m | ||||
|  | ||||
| [38;2;248;248;242m  [0m[38;2;117;113;94m;; Open and unlink[0m | ||||
| [38;2;248;248;242m  [0m[38;2;248;248;242m([0m[38;2;249;38;114mdefine[0m[38;2;248;248;242m [0m[38;2;166;226;46mtest-sem-p[0m[38;2;248;248;242m [0m[38;2;248;248;242m(sem-open test-sem-name (+ O_CREAT O_EXCL)))[0m | ||||
| [38;2;248;248;242m  (check-not-false test-sem-p)[0m | ||||
| [38;2;248;248;242m  (check-not-equal? test-sem-p (void))[0m | ||||
| [38;2;248;248;242m  (check-exn exn:fail?[0m | ||||
| [38;2;248;248;242m             [0m[38;2;248;248;242m([0m[38;2;249;38;114mlambda[0m[38;2;248;248;242m [0m[38;2;248;248;242m() (sem-open test-sem-name (+ O_CREAT O_EXCL)))[0m | ||||
| [38;2;248;248;242m             [0m[38;2;230;219;116m"Permission denied"[0m[38;2;248;248;242m)[0m | ||||
| [38;2;248;248;242m  (check-exn exn:fail?[0m | ||||
| [38;2;248;248;242m             [0m[38;2;248;248;242m([0m[38;2;249;38;114mlambda[0m[38;2;248;248;242m [0m[38;2;248;248;242m() (sem-open test-sem-name (+ O_CREAT O_EXCL))))[0m | ||||
|  | ||||
| [38;2;248;248;242m  [0m[38;2;117;113;94m;; Change values[0m | ||||
| [38;2;248;248;242m  (check-equal? (sem-getvalue test-sem-p) [0m[38;2;190;132;255m0[0m[38;2;248;248;242m)[0m | ||||
| [38;2;248;248;242m  (sem-post test-sem-p)[0m | ||||
| [38;2;248;248;242m  (check-equal? (sem-getvalue test-sem-p) [0m[38;2;190;132;255m1[0m[38;2;248;248;242m)[0m | ||||
| [38;2;248;248;242m  (sem-wait test-sem-p)[0m | ||||
| [38;2;248;248;242m  (check-equal? (sem-getvalue test-sem-p) [0m[38;2;190;132;255m0[0m[38;2;248;248;242m)[0m | ||||
| [38;2;248;248;242m  (sem-post test-sem-p)[0m | ||||
| [38;2;248;248;242m  (check-equal? (sem-getvalue test-sem-p) [0m[38;2;190;132;255m1[0m[38;2;248;248;242m)[0m | ||||
| [38;2;248;248;242m  (sem-post test-sem-p)[0m | ||||
| [38;2;248;248;242m  (check-equal? (sem-getvalue test-sem-p) [0m[38;2;190;132;255m2[0m[38;2;248;248;242m)[0m | ||||
| [38;2;248;248;242m  (sem-trywait test-sem-p)[0m | ||||
| [38;2;248;248;242m  (check-equal? (sem-getvalue test-sem-p) [0m[38;2;190;132;255m2[0m[38;2;248;248;242m)[0m | ||||
|  | ||||
| [38;2;248;248;242m  [0m[38;2;117;113;94m;; Can't unlink twice[0m | ||||
| [38;2;248;248;242m  (check-not-false (sem-unlink test-sem-name))[0m | ||||
| [38;2;248;248;242m  (check-false (sem-unlink test-sem-name)))[0m | ||||
|  | ||||
|  | ||||
| [38;2;117;113;94m;; Named POSIX shared memory[0m | ||||
| [38;2;248;248;242m(test-begin[0m | ||||
| [38;2;248;248;242m  [0m[38;2;248;248;242m([0m[38;2;249;38;114mdefine[0m[38;2;248;248;242m [0m[38;2;166;226;46mtest-shm-name[0m[38;2;248;248;242m [0m[38;2;248;248;242m"test-nix-mem-[0m[38;2;190;132;255m1[0m[38;2;248;248;242m")[0m | ||||
|  | ||||
| [38;2;248;248;242m  [0m[38;2;117;113;94m;; Open and unlink[0m | ||||
| [38;2;248;248;242m  (shm-unlink test-shm-name)[0m | ||||
| [38;2;248;248;242m  [0m[38;2;248;248;242m([0m[38;2;249;38;114mdefine[0m[38;2;248;248;242m [0m[38;2;166;226;46mtest-shm-fd[0m[38;2;248;248;242m [0m[38;2;248;248;242m(shm-open test-shm-name (+ O_EXCL O_CREAT O_RDWR) #o644))[0m | ||||
| [38;2;248;248;242m  (check > test-shm-fd [0m[38;2;190;132;255m0[0m[38;2;248;248;242m)[0m | ||||
| [38;2;248;248;242m  (check-not-false (shm-unlink test-shm-name))[0m | ||||
| [38;2;248;248;242m  (check-false (shm-unlink test-shm-name)))[0m | ||||
| @@ -0,0 +1,2 @@ | ||||
| custom assets : 0 | ||||
| are           : the best | ||||
							
								
								
									
										1
									
								
								tests/syntax-tests/source/Ignored suffixes/test.rs.ucf-dist
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/syntax-tests/source/Ignored suffixes/test.rs.ucf-dist
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| // foo.ucf-dist (Debian ucf backup) should highlight same as foo | ||||
							
								
								
									
										1
									
								
								tests/syntax-tests/source/Ignored suffixes/test.rs.ucf-new
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/syntax-tests/source/Ignored suffixes/test.rs.ucf-new
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| // foo.ucf-new (Debian ucf backup) should highlight same as foo | ||||
							
								
								
									
										1
									
								
								tests/syntax-tests/source/Ignored suffixes/test.rs.ucf-old
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/syntax-tests/source/Ignored suffixes/test.rs.ucf-old
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| // foo.ucf-old (Debian ucf backup) should highlight same as foo | ||||
							
								
								
									
										56
									
								
								tests/syntax-tests/source/Racket/test.rkt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								tests/syntax-tests/source/Racket/test.rkt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| #lang racket | ||||
|  | ||||
| (require "main.rkt" rackunit) | ||||
|  | ||||
| ;; Helper for test cases with multiple outputs | ||||
| ;; See: https://stackoverflow.com/questions/41081395/unit-testing-in-racket-with-multiple-outputs | ||||
| (define-syntax check-values-equal? | ||||
|   (syntax-rules () | ||||
|     [(_ a b) (check-equal? (call-with-values (thunk a) list) b)])) | ||||
|  | ||||
|  | ||||
| ;; Named POSIX semaphores | ||||
| (test-begin | ||||
|   (define test-sem-name "/test-nix-1") | ||||
|  | ||||
|   ;; Unlink if already exists | ||||
|   (sem-unlink test-sem-name) | ||||
|  | ||||
|   ;; Open and unlink | ||||
|   (define test-sem-p (sem-open test-sem-name (+ O_CREAT O_EXCL))) | ||||
|   (check-not-false test-sem-p) | ||||
|   (check-not-equal? test-sem-p (void)) | ||||
|   (check-exn exn:fail? | ||||
|              (lambda () (sem-open test-sem-name (+ O_CREAT O_EXCL))) | ||||
|              "Permission denied") | ||||
|   (check-exn exn:fail? | ||||
|              (lambda () (sem-open test-sem-name (+ O_CREAT O_EXCL)))) | ||||
|  | ||||
|   ;; Change values | ||||
|   (check-equal? (sem-getvalue test-sem-p) 0) | ||||
|   (sem-post test-sem-p) | ||||
|   (check-equal? (sem-getvalue test-sem-p) 1) | ||||
|   (sem-wait test-sem-p) | ||||
|   (check-equal? (sem-getvalue test-sem-p) 0) | ||||
|   (sem-post test-sem-p) | ||||
|   (check-equal? (sem-getvalue test-sem-p) 1) | ||||
|   (sem-post test-sem-p) | ||||
|   (check-equal? (sem-getvalue test-sem-p) 2) | ||||
|   (sem-trywait test-sem-p) | ||||
|   (check-equal? (sem-getvalue test-sem-p) 2) | ||||
|  | ||||
|   ;; Can't unlink twice | ||||
|   (check-not-false (sem-unlink test-sem-name)) | ||||
|   (check-false (sem-unlink test-sem-name))) | ||||
|  | ||||
|  | ||||
| ;; Named POSIX shared memory | ||||
| (test-begin | ||||
|   (define test-shm-name "test-nix-mem-1") | ||||
|  | ||||
|   ;; Open and unlink | ||||
|   (shm-unlink test-shm-name) | ||||
|   (define test-shm-fd (shm-open test-shm-name (+ O_EXCL O_CREAT O_RDWR) #o644)) | ||||
|   (check > test-shm-fd 0) | ||||
|   (check-not-false (shm-unlink test-shm-name)) | ||||
|   (check-false (shm-unlink test-shm-name))) | ||||
							
								
								
									
										4
									
								
								tests/syntax-tests/source/Svelte/App.svelte
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								tests/syntax-tests/source/Svelte/App.svelte
									
									
									
									
										vendored
									
									
								
							| @@ -26,6 +26,10 @@ | ||||
| 	onMount(hashchange); | ||||
| </script> | ||||
|  | ||||
| <script type="text/livescript"> | ||||
|     // This block is a regression test for a bat panic when a LiveScript syntax definition is missing | ||||
| </script> | ||||
|  | ||||
| <style> | ||||
| 	main { | ||||
| 		position: relative; | ||||
|   | ||||
							
								
								
									
										74
									
								
								tests/syntax-tests/test_custom_assets.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										74
									
								
								tests/syntax-tests/test_custom_assets.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| #!/usr/bin/env bash | ||||
| set -o errexit -o nounset -o pipefail | ||||
|  | ||||
| ### ENVIRONMENT | ||||
|  | ||||
| BAT_CONFIG_DIR=$(mktemp -d) | ||||
| export BAT_CONFIG_DIR | ||||
|  | ||||
| BAT_CACHE_PATH=$(mktemp -d) | ||||
| export BAT_CACHE_PATH | ||||
|  | ||||
| echo " | ||||
| BAT_CONFIG_DIR = ${BAT_CONFIG_DIR} | ||||
| BAT_CACHE_PATH = ${BAT_CACHE_PATH} | ||||
| " | ||||
|  | ||||
| ### HELPER VARS | ||||
|  | ||||
| custom_syntax_args=( | ||||
|     "--language=BatTestCustomAssets" | ||||
|     "tests/syntax-tests/source/BatTestCustomAssets/NoColorsUnlessCustomAssetsAreUsed.battestcustomassets" | ||||
| ) | ||||
|  | ||||
| integrated_syntax_args=( | ||||
|     "--language=Rust" | ||||
|     "examples/simple.rs" | ||||
| ) | ||||
|  | ||||
| ### HELPER FUNCTIONS | ||||
|  | ||||
| echo_step() { | ||||
|     echo -e "\n== $1 ==" | ||||
| } | ||||
|  | ||||
| fail_test() { | ||||
|     echo -e "FAIL: $1" | ||||
|     exit 1 | ||||
| } | ||||
|  | ||||
| ### TEST STEPS | ||||
|  | ||||
| echo_step "TEST: Make sure 'BatTestCustomAssets' is not part of integrated syntaxes" | ||||
| bat -f "${custom_syntax_args[@]}" && | ||||
|     fail_test "EXPECTED: 'unknown syntax' error ACTUAL: no error occured" | ||||
|  | ||||
| echo_step "PREPARE: Install custom syntax 'BatTestCustomAssets'" | ||||
| custom_syntaxes_dir="$(bat --config-dir)/syntaxes" | ||||
| mkdir -p "${custom_syntaxes_dir}" | ||||
| cp -v "tests/syntax-tests/BatTestCustomAssets.sublime-syntax" \ | ||||
|     "${custom_syntaxes_dir}/BatTestCustomAssets.sublime-syntax" | ||||
|  | ||||
| echo_step "PREPARE: Build custom assets to enable 'BatTestCustomAssets' syntax" | ||||
| bat cache --build | ||||
|  | ||||
| echo_step "TEST: 'BatTestCustomAssets' is a known syntax" | ||||
| bat -f "${custom_syntax_args[@]}" || | ||||
|     fail_test "EXPECTED: syntax highlighting to work ACTUAL: there was an error" | ||||
|  | ||||
| echo_step "TEST: The 'Rust' syntax is still available" | ||||
| bat -f "${integrated_syntax_args[@]}" || | ||||
|     fail_test "EXPECTED: syntax highlighting still works with integrated assets ACTUAL: there was an error" | ||||
|  | ||||
| echo_step "TEST: 'BatTestCustomAssets' is an unknown syntax with --no-custom-assets" | ||||
| bat -f --no-custom-assets "${custom_syntax_args[@]}" && | ||||
|     fail_test "EXPECTED: 'unknown syntax' error because of --no-custom-assets ACTUAL: no error occured" | ||||
|  | ||||
| echo_step "TEST: 'bat cache --clear' removes all files" | ||||
| bat cache --clear | ||||
| remaining_files=$(ls -A "${BAT_CACHE_PATH}") | ||||
| [ -z "${remaining_files}" ] || | ||||
|     fail_test "EXPECTED: no files remain ACTUAL: some files remain:\n${remaining_files}" | ||||
|  | ||||
| echo_step "CLEAN" | ||||
| rm -rv "${BAT_CONFIG_DIR}" "${BAT_CACHE_PATH}" | ||||
		Reference in New Issue
	
	Block a user