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

Compare commits

...

339 Commits

Author SHA1 Message Date
sharkdp 30b742e984 --map-syntax takes just one value 2018-10-17 23:27:44 +02:00
sharkdp 671deeef8c Update help text 2018-10-17 23:17:28 +02:00
sharkdp a892caeb33 Bump bat version to 0.8 2018-10-17 23:15:59 +02:00
sharkdp a770cbf25e Update assets 2018-10-17 23:14:07 +02:00
sharkdp 931c6e9414 Update man page 2018-10-17 23:13:50 +02:00
sharkdp 8dc7e2efa3 Add --config-file option 2018-10-17 23:08:37 +02:00
sharkdp 10965a6122 Implement syntax mapping
This adds a `-m`/`--map-syntax` option that allows users to (re)map
certain file extensions or file names to an existing syntax.

For example:
```
bat --map-syntax .config:json
```

The option can be use multiple times. Note that you can easily make
these mappings permanent by using `bat`s new configuration file.

closes #169
2018-10-17 23:08:19 +02:00
sharkdp e43d97dc15 Small cleanup 2018-10-17 21:12:23 +02:00
sharkdp 2c7087b8de Add integration tests for pager handling 2018-10-17 21:08:32 +02:00
sharkdp bb1f5aa841 Add proper handling of empty PAGER variables 2018-10-17 21:08:32 +02:00
sharkdp 2109a7830b Add error handling for parsing errors 2018-10-17 21:08:32 +02:00
sharkdp ec27c78a8a Remove duplicate 'extern crate' 2018-10-17 21:08:32 +02:00
Morten Linderud 67fe833bc8 Add arguments from PAGER/BAT_PAGER
Solves #352

Signed-off-by: Morten Linderud <morten@linderud.pw>
2018-10-17 21:08:32 +02:00
sharkdp e956225b4d Update syntect to 3.0.1
closes #314
2018-10-16 23:06:46 +02:00
sharkdp 314ec881ef Bump Rust version 2018-10-16 22:09:15 +02:00
sharkdp 25a6a55437 Revert "Fix for older version of Rust"
This reverts commit c530fadc44.
2018-10-16 22:09:15 +02:00
sharkdp 5bff4548be Add BAT_OPTS environment variable 2018-10-16 22:09:15 +02:00
sharkdp 866b9e16a8 Add error handling 2018-10-16 22:09:15 +02:00
sharkdp 5af176c94f Move transpose to util module 2018-10-16 22:09:15 +02:00
sharkdp 9e7da05459 Fix for older version of Rust 2018-10-16 22:09:15 +02:00
sharkdp 1ae02c65fb Fix include 2018-10-16 22:09:15 +02:00
sharkdp 495e7fd3b1 Add --no-config option 2018-10-16 22:09:15 +02:00
sharkdp b48f0fe389 Fix tests 2018-10-16 22:09:15 +02:00
sharkdp c19c704a43 Add more tests 2018-10-16 22:09:15 +02:00
sharkdp 693bd5929d Add possibility for spaces on a single line 2018-10-16 22:09:15 +02:00
sharkdp 8275b0436d Add simple configuration file
This allows users to create simple configuration file
(`~/.config/bat/config` on Linux) that has the following format:

    ```bash
    --flag1
    --flag2
    --option1=value1
    # lines beginning with '#' are ignored
    --option2=value2
    # empty lines and trailing whitespace are also ignored

    --option3=value3
    ```
2018-10-16 22:09:15 +02:00
sharkdp 278bde5cee Continue with output after "is directory"-error 2018-10-11 21:54:19 +02:00
Russ Taylor eee7e5a575 Removes duplicate explanation. 2018-10-11 20:58:44 +02:00
Russ Taylor ad7b634ee6 Fixes #328 - adds info for light backgrounds. 2018-10-11 20:58:44 +02:00
David Peter 1310f83c8d Update Docker alias for bat 2018-10-11 20:57:46 +02:00
David Peter 897b9e7030 Add Docker instructions, closes #331 2018-10-11 20:05:17 +02:00
sharkdp 1891e194b5 Add simple integration tests 2018-10-11 07:06:13 +02:00
sharkdp d2d01b9fe8 Always remove the local cache when creating new assets 2018-10-10 21:49:03 +02:00
sharkdp 5842d58c01 Updates for syntect 3.0 2018-10-09 22:04:51 +02:00
Tim Sampson e3c71adba7 syntax: Add robot framework support 2018-10-09 20:27:01 +02:00
Merlin Göttlinger 504f28b3a1 Documented nix availability 2018-10-09 20:07:27 +02:00
Fredrik Fornwall d977ba9194 Update dependencies 2018-10-08 22:33:09 +02:00
Tim Sampson 9c09799e1f misc: add exec bit for create.sh 2018-10-08 20:20:05 +02:00
David Peter d83c93c805 Update README.md 2018-10-07 18:39:52 +02:00
sharkdp fc8fd1e63f cargo fmt 2018-10-07 17:49:38 +02:00
sharkdp 404d6a4a81 Update content_inspector version 2018-10-07 17:49:38 +02:00
sharkdp 25d96da4a2 Add support for UTF-16LE and UTF-16BE 2018-10-07 17:49:38 +02:00
sharkdp e97095b724 Use first-line detection for STDIN 2018-10-07 15:34:37 +02:00
sharkdp ce96df00b6 Do not display binary files in interactive mode
closes #248
2018-10-07 15:34:37 +02:00
sharkdp f98fc5f06a Simplify access to first line 2018-10-07 15:34:37 +02:00
sharkdp 1dbb4ef683 Update minimum Rust version to 1.27 2018-10-07 15:34:37 +02:00
sharkdp 0502a3bd4a Add first-line detection for all input types
closes #205
2018-10-07 15:34:37 +02:00
sharkdp 869cf6368c Add possibility to get first line 2018-10-07 15:34:37 +02:00
sharkdp 078228deac Add unit test for InputFileReader 2018-10-07 15:34:37 +02:00
sharkdp e09d7dabb8 Move snapshot tests into separate module 2018-10-07 15:34:37 +02:00
sharkdp 6d1cc8c2c8 Move read_line functionality to inputfile module 2018-10-07 15:34:37 +02:00
sharkdp 87f021078e Use dyn Trait for trait objects 2018-10-07 15:34:37 +02:00
sharkdp d5b0502419 Move get_reader into inputfile module 2018-10-07 15:34:37 +02:00
sharkdp 860f3e9006 Move InputFile to separate module 2018-10-07 15:34:37 +02:00
sharkdp 1be346a038 Add 'plain' version of bat to the benchmarks 2018-10-07 10:57:08 +02:00
sharkdp f9fd5e4851 Simplify -h help text 2018-10-07 10:43:39 +02:00
sharkdp da09f3877b Remove unnecessary scope 2018-10-07 10:09:10 +02:00
sharkdp e30e1bab2e Move theme-preview section into own paragraph 2018-10-06 21:12:12 +02:00
Russ Taylor f140f6da46 Fixes #273 - describes 'musl' builds. 2018-10-06 21:07:01 +02:00
Grégoire Paris 3446fdf5f2 Document how to rapidly preview theme on a file 2018-10-06 21:06:31 +02:00
sharkdp e1345cdc2a Update VimL syntax 2018-10-05 18:44:51 +02:00
sharkdp a2676ccc55 Workaround for #81 2018-10-04 11:09:41 +02:00
Richard Hozák b39e28d2c8 Add support for wildcards in Windows CMD (#329)
Windows does not support wildcard expansion in cmd, this adds 'wild' crate (as discussed in #309) that handles everything transparently, so wildcards work everywhere.

Fixes #309
2018-10-03 22:59:11 +02:00
davideGiovannini 0d71968615 Generate shell completions with clap during build (#327)
* Generate shell completions with clap during build

* Updated ci release script, added SHELL_COMPLETIONS_DIR override to build.rs and fixed dependency version
2018-10-03 09:39:30 +02:00
sharkdp 80da0dc619 run cargo fmt 2018-09-26 19:16:03 +02:00
sharkdp 64903bb858 Typo 2018-09-26 19:13:32 +02:00
sharkdp 3456ce1187 Add a small tutorial 2018-09-26 18:08:24 +02:00
sharkdp 886a5b3d24 Document the situation with less and scrolling
closes #312
closes #246
2018-09-26 18:03:46 +02:00
sharkdp 238482e5f3 Update syntax-set, fixes #314 2018-09-23 10:30:19 +02:00
Michal Nazarewicz 79b960e17e Use ansi_colours package for better true-colour approximation 2018-09-23 10:19:19 +02:00
sharkdp 6aa626f1c4 Document INI syntax modifications 2018-09-22 11:23:29 +02:00
Tuk Bredsdorff 1b30539493 Added Mercurial's hgrc-files to the list of INI-extensions 2018-09-22 11:23:29 +02:00
Katrin Leinweber 96b24d8a7e Fix typos 2018-09-20 19:16:51 +02:00
sharkdp 20b02e72b3 Disable wrapping when --style is plain
closes #289
2018-09-18 21:31:56 +02:00
eth-p 254efac9c2 Added section to README on using Cygwin. 2018-09-14 18:30:43 +02:00
Jeroen Hoek dcec322117 Update README (libz-dev may be required)
On Ubuntu 18.04 I had to install `cmake` as well as `libz-dev` to get
bat to compile.
2018-09-14 14:12:44 +02:00
Alexander Eimer d781156327 Adds ansible install instructions for ansible to readme 2018-09-12 23:06:33 +02:00
sharkdp 732750c274 Bump version 2018-09-12 22:03:48 +02:00
sharkdp 6b6baa3118 Update dependencies 2018-09-12 22:01:27 +02:00
sharkdp 54c434934e Bump version, update assets 2018-09-12 22:01:01 +02:00
sharkdp ad6e0a2581 Update man page 2018-09-12 22:00:28 +02:00
sharkdp bd619db3ca Mention BAT_STYLE in README.md 2018-09-12 21:57:54 +02:00
sharkdp e098eb43a2 Do not show file header for directories
This also adds a better error message.

closes #292
2018-09-12 21:53:41 +02:00
David Peter ea369ee17f Merge pull request #298 from ms2300/bat_style
#208 Added BAT_STYLE env variable functionality
2018-09-12 21:48:34 +02:00
sharkdp 63d32bc818 Merge remote-tracking branch 'upstream/master' into bat_style 2018-09-12 21:40:41 +02:00
sharkdp dccf8d8221 Use a more streamlined version of style-component collection 2018-09-12 21:35:23 +02:00
sharkdp 97129ab9d8 Add PowerShell syntax, closes #306 2018-09-12 20:53:49 +02:00
David Peter 52d0d6ca30 Merge pull request #302 from eth-p/feature-tabs
Tab expansion support.

closes #166 
closes #184
2018-09-12 20:50:05 +02:00
sharkdp a05494e9d9 Make tests more robust 2018-09-12 20:32:49 +02:00
sharkdp 84ac92efbb Fix test for --style=plain 2018-09-12 20:32:33 +02:00
sharkdp b4c6e412dc Make generate_snapshots script more robust 2018-09-12 20:28:42 +02:00
sharkdp 3e21d69a92 Re-generate files again 2018-09-12 20:28:30 +02:00
sharkdp b7690d4bb1 Undo change in sample.modified.rs 2018-09-12 20:28:21 +02:00
eth-p d404139ff7 Added validation for --tabs.
Also added a comment to explain what 0 represents.
2018-09-12 10:08:58 -07:00
eth-p 9ef1e9f792 Update snapshots. 2018-09-11 15:04:44 -07:00
eth-p 503fe0b641 Fix sample.modified.rs 2018-09-11 15:03:13 -07:00
eth-p 1807f9653c Merge remote-tracking branch 'upstream/master' into feature-tabs
# Conflicts:
#	src/printer.rs
2018-09-11 14:03:47 -07:00
eth-p 1e74f0e2a9 Ran cargo fmt. 2018-09-11 13:47:35 -07:00
eth-p c1e1f753cf Added three new snapshot tests for --tabs and --wrap. 2018-09-11 13:47:01 -07:00
eth-p d90797f8e9 Fixed tab expansion not working in --wrap=never mode. 2018-09-11 13:45:49 -07:00
eth-p b4096e5627 Moved tab expansion to happen after syntax highlighting. 2018-09-11 13:02:22 -07:00
shik Chen 4e3ab4d399 Query git diff only when needed
In large git repo like chromium, it takes too long time to query git
diff.
2018-09-11 21:09:38 +02:00
rachitchokshi f0d936763c provide armhf deb packages (#301)
* Enabled deb packaging for armhf architecture

closes #280.
2018-09-11 21:03:53 +02:00
ms2300 7897260bf0 BAT_STYLE accounts for multiple styles (ie numbers,header) 2018-09-10 21:58:19 -06:00
eth-p eb6e43b9a9 Disabled tab expansion when decorations and pager are not used. 2018-09-10 20:12:13 -07:00
eth-p 7cdcdbb31d Updated snapshots. 2018-09-10 19:20:09 -07:00
eth-p 9159341714 Modified snapshot tests to support tab expansion.
This changes how the files are named (to allow for snapshots that aren't
directly related to the --style argument) and fixes the
generate_snapshots.py script to work with the latest version of bat.

Three new tests are also introduced:
- tabs_4 - Tab expansion with a width of 4.
- tabs_8 - Tab expansion with a width of 8.
- tabs_passthrough - No tab expansion.
2018-09-10 19:19:43 -07:00
eth-p b23ff24ebc Added tab expansion preprocessing step. 2018-09-10 18:11:59 -07:00
Rogach e1ecc17f69 print additional newline if last line in input file was not terminated with a newline (fixes #299) 2018-09-10 22:18:16 +02:00
rachitchokshi 0fe3badf19 adding deb packaging for arm64 (#1) 2018-09-10 21:24:15 +02:00
rachitchokshi 89d4cb951a Updated before_deploy.bash to call version of strip specific to aarch64 target 2018-09-10 21:24:15 +02:00
rachitchokshi e9681bf22d Testing build by removing dependency 'libz-sys = "1.0.20"' 2018-09-10 21:24:15 +02:00
rachitchokshi 1b6df8a480 Enabled build target aarch64-unknown-linux-gnu for arm64 architecture 2018-09-10 21:24:15 +02:00
ms2300 cf24986edb Run formatting for bat_style changes 2018-09-10 00:07:46 -06:00
ms2300 b9c556a0b6 Updated long help to reflect BAT_STYLE changes 2018-09-09 18:35:40 -06:00
ms2300 9d6bde48fa Added BAT_STYLE env variable functionality 2018-09-09 18:28:04 -06:00
Aankhen d6c8fee044 README.md: Add Using bat on Windows 2018-09-09 12:22:05 +02:00
sharkdp 8b4abb03db Run 'cargo fmt' 2018-09-08 09:52:21 +02:00
eth-p 375cf76e15 Formatted for newest rustfmt. 2018-09-08 09:52:21 +02:00
eth-p 1a4acc435e Typo 2018-09-08 09:52:21 +02:00
eth-p d8030626f8 Automatically disable wrapping when style is plain. 2018-09-08 09:52:21 +02:00
eth-p fb61aa4f60 Wrapping disabled when --plain is used. (#289) 2018-09-08 09:52:21 +02:00
Aankhen 76df41fa97 src/output.rs: Handle less in a portable way. 2018-09-07 21:47:31 +02:00
Miguel Madrid Mencía 97efd75cee Add Crystal syntax 2018-09-05 23:45:09 +02:00
Shreyansh Chouhan 53d0c1deca Can read files named "cache" now, cache subcommand working too (#275)
Now if a cache file exists in the current directory, and the user passes
no arguments to the cache command, the cache file would be displayed.
If however the user uses cache command with arguments, the cache command
would be executed as normal regardless of whether the file cache exists
in the current directory or not.

Though now there won't be an error message displayed if the user uses the cache sub command without arguments in any directory that contains a file named cache.
2018-09-05 23:22:12 +02:00
David Peter 155179a07a Update alternatives.md 2018-09-05 22:01:42 +02:00
sharkdp ba00caf9c3 Add Swift syntax 2018-09-05 21:56:49 +02:00
sharkdp ac418ba21c Add PureScript syntax 2018-09-05 21:50:16 +02:00
sharkdp acde83af31 Add note about 'lesspipe', closes #242 2018-09-05 21:44:53 +02:00
sharkdp 021a68eb21 Add F# syntax, closes #284 2018-09-05 21:38:35 +02:00
David Peter 566aab3b05 Merge pull request #279 from tobenna/add-jsx-syntax
Add support for JSX in javascript and typescript
2018-09-05 21:33:50 +02:00
sharkdp f88eba6476 Add section concerning missing zlib-devel
closes #229
2018-09-05 21:13:43 +02:00
sharkdp 1d9e7ac4c2 Support "(/usr)/bin/less" as PAGER too
closes #271
2018-09-05 21:10:11 +02:00
David Peter 80ae2ecbf8 Merge branch 'master' into add-jsx-syntax 2018-09-05 20:51:03 +02:00
David Peter 96d4492d27 Merge pull request #282 from tobenna/support-cabal-syntax
Syntax highlighting for .cabal
2018-09-05 20:44:25 +02:00
David Peter c90f0b8e21 Merge branch 'master' into support-cabal-syntax 2018-09-05 20:43:50 +02:00
David Peter 4b866ab6af Merge branch 'master' into add-jsx-syntax 2018-09-05 20:36:31 +02:00
Tobenna 2dbd91e543 Add Dart syntax 2018-09-05 20:33:16 +02:00
Tobenna Ndu 785da3d9df Add support for cabal syntax 2018-09-05 14:42:27 +01:00
Tobenna d455cb7c32 Add support for JSX in javascript and typescript 2018-09-05 08:49:33 +01:00
sharkdp d2b4766f92 Small README update 2018-09-04 08:25:24 +02:00
Roald 5cf92b4f94 Windows download with scoop 2018-09-04 08:23:38 +02:00
sharkdp 7b803a50af Ignore enable_ansi_support errors
- Call `enable_ansi_support` only once.
- Ignore errors that appear when trying to enable ANSI support. This
  will hopefully fix #252 and #264
2018-09-03 22:15:38 +02:00
sharkdp 67ec5fe2b7 Add OneHalf themes, closes #256 2018-09-03 22:12:41 +02:00
sharkdp 3447ed4def Add CSV syntax, closes #254 2018-09-03 21:49:26 +02:00
David Peter 532fb921a6 Update README.md 2018-09-01 00:59:30 +02:00
sharkdp ba4d5a2e7d Bump version number 2018-09-01 00:30:43 +02:00
sharkdp 026273a05c Enable ANSI support on Windows 2018-09-01 00:23:15 +02:00
sharkdp 8903b64830 Fix for Rust 1.26 2018-08-31 23:57:27 +02:00
sharkdp 194155f062 Fix relative-path computation for Windows 2018-08-31 23:57:27 +02:00
sharkdp a6ff3b900d Fix terminal width to 80 characters in tests 2018-08-31 23:57:27 +02:00
sharkdp 8a52bcf92d Add hidden --terminal-width option 2018-08-31 23:57:27 +02:00
sharkdp 0b1535f63b Split snapshot tests into individual tests 2018-08-31 23:57:27 +02:00
sharkdp 0a5b3eaf3e Re-enable tests on windows 2018-08-31 23:57:27 +02:00
sharkdp 11294249f8 Add new key for AppVeyor 2018-08-31 23:57:27 +02:00
anykao 35a1236ad0 Update tests.rs 2018-08-31 23:57:27 +02:00
anykao af8da50c2c Update appveyor.yml 2018-08-31 23:57:27 +02:00
anykao 649d1e3df2 Update appveyor.yml 2018-08-31 23:57:27 +02:00
anykao 199cfd4519 Update appveyor.yml 2018-08-31 23:57:27 +02:00
David Peter c7cce0752b Add AppVeyor badge 2018-08-31 23:57:27 +02:00
anykao 3a89486189 Create before_deploy.ps1 2018-08-31 23:57:27 +02:00
anykao 720a2fb7a5 Create appveyor.yml 2018-08-31 23:57:27 +02:00
sharkdp e3c990f11e Respect color settings for list-themes and list-languages 2018-08-31 21:57:18 +02:00
sharkdp 90c7d0c365 Use stdout locks 2018-08-31 21:48:26 +02:00
mchlrhw 56002267d2 Fix panic when running bat --list-languages | head
Fixes: https://github.com/sharkdp/bat/issues/232
2018-08-31 21:43:49 +02:00
David Peter 84734eac9d Update alternatives.md 2018-08-31 00:39:26 +02:00
sharkdp acdea97e71 Add --plain 2018-08-28 23:37:49 +02:00
sharkdp 839e4ee611 Bump version 2018-08-28 23:21:35 +02:00
sharkdp c7afcdebf8 Move theme_preview file to constant 2018-08-28 22:16:42 +02:00
sharkdp 08e6db1581 Add Troubleshooting section
see #220
2018-08-28 22:08:34 +02:00
sharkdp 4d08ecd828 Fix headline levels 2018-08-28 21:04:41 +02:00
sharkdp 28e1d0e613 Add development section to README 2018-08-28 21:03:03 +02:00
sharkdp d11839ad03 Update install instructions 2018-08-28 20:55:15 +02:00
sharkdp 8cacd9b432 Include theme_preview file in binary 2018-08-28 20:24:13 +02:00
sharkdp 6f67444c99 Run cargo fmt 2018-08-28 20:24:13 +02:00
sharkdp fd2b376ea0 Small style changes to --list-themes 2018-08-28 20:24:13 +02:00
sharkdp cda54e4f61 Fix build for Rust 1.26 2018-08-28 20:24:13 +02:00
ms2300 3b90ada735 Mutation done correctly 2018-08-28 20:24:13 +02:00
ms2300 1837d364fe Added bold to theme titles 2018-08-28 20:24:13 +02:00
ms2300 4ea3e6bbb7 Changed preview code 2018-08-28 20:24:13 +02:00
ms2300 38544ed735 Changed to plain style 2018-08-28 20:24:13 +02:00
ms2300 5444b0dfed Fixes mut issue 2018-08-28 20:24:13 +02:00
ms2300 f3dde0185d Modifying changing config for efficiency 2018-08-28 20:24:13 +02:00
ms2300 2e3784aa30 #213 : output hello world for each theme when --list-theme is flagged 2018-08-28 20:24:13 +02:00
sharkdp 1088455702 Add syntaxes for Elm, Kotlin, Puppet, TypeScript
closes #215
closes #216
closes #217
closes #218
2018-08-28 19:36:31 +02:00
Colin Dean 4f812c32ab Adds zenburn theme submodule
Work towards #224 but @sharkdp is going to rebuild themes.bin
2018-08-28 07:37:27 +02:00
sharkdp b6c59a5bd4 Add man page to releases 2018-08-27 23:10:14 +02:00
sharkdp b682679776 Add initial version of man page, see #52 2018-08-27 22:57:47 +02:00
ms2300 81771432fb #212 : added -p as an alias for --style=plain 2018-08-27 17:56:50 +02:00
sharkdp 627181bcb6 Always call the syntax highlighter 2018-08-23 23:35:57 +02:00
sharkdp 226d9a573a Add simple loop-through mode
Use a loop-through mode that simply copies input to output if a
non-interactive terminal is detected.

see #150
2018-08-23 23:13:24 +02:00
sharkdp 246cf79dbd Split into Controller and Printer 2018-08-23 22:37:27 +02:00
sharkdp ea955c734d Refactoring, introduce Printer trait 2018-08-23 19:44:14 +02:00
sharkdp 6223ad6d52 Document Config struct 2018-08-22 22:36:59 +02:00
sharkdp 31a9335bd5 Document Config struct 2018-08-22 22:36:37 +02:00
sharkdp 9316f2a758 Major refactoring and cleanup 2018-08-22 22:29:12 +02:00
sharkdp c884c3cc12 Re-order options in help texts 2018-08-22 19:34:30 +02:00
sharkdp 08850f0474 Update the --help text 2018-08-22 19:27:11 +02:00
Tim Sampson 8e6c5bc562 doc: mention BAT_THEME in help output 2018-08-22 18:14:01 +02:00
sharkdp 052425b12f Load customized themes in addition to defaults
- New themes in `$BAT_CONFIG_DIR/themes` are now loaded *in addition* to
  the default themes (they may also override).
- The `Default.tmTheme` symlink is not necessary anymore.

This relates to #172
2018-08-20 21:39:21 +02:00
sharkdp 2df3305b94 Add new '--blank' option for 'bat cache --init'
closes #206
2018-08-20 21:34:08 +02:00
sharkdp 6882fc1512 Clean up help messages 2018-08-20 21:34:08 +02:00
sharkdp 2508323264 Extract grid and line-number color from theme
This changes the output color of the grid and the line numbers to use
the "gutter" foreground color defined in the Sublime `.tmTheme` files.

Sublime Text does the same.

Note: we could go one step further and also extract the "GitGutter"
colors from the themes. These could be used instead of red/green/yellow
to signify Git modifications. The problem is that they are quite a bit
harder to extract from the syntect `Theme` object.

closes #178
2018-08-19 12:32:35 +02:00
sharkdp 297afad337 Bump version 2018-08-19 12:31:35 +02:00
sharkdp 1dddce3aa1 Separate syntax set and theme set
This commit separates the handling of syntax sets and theme sets. It
also changes the way how new syntax definitions are loaded from `bat`'s
configuration folder. New syntax definitions are now loaded *in
addition* to the ones that are stored in the `bat` binary by default.

This fixes #172
2018-08-19 11:08:23 +02:00
sharkdp 76be0d3933 Add arm as a compile target 2018-08-19 09:50:24 +02:00
sharkdp e5b8c4471a Bump minimum required rust version 2018-08-18 21:30:12 +02:00
sharkdp b191691767 Revert "replace trait object BufRead by generic"
This reverts commit 037861e588.
2018-08-18 21:25:58 +02:00
Michal Nazarewicz 5c95b8803b Avoid floating point arithmetic in RGB→8-bit ANSI approximation 2018-08-18 20:58:03 +02:00
sharkdp 5b421b455d Update dependencies 2018-08-18 20:44:25 +02:00
sharkdp a6d6c28723 Add documentation on new pager-customization 2018-08-18 20:22:11 +02:00
sharkdp 2966939e38 Update submodules 2018-08-18 19:30:35 +02:00
sharkdp d179693d1d Use BAT_PAGER and PAGER environment variables, closes #158 2018-08-18 18:48:22 +02:00
sharkdp 268577c6f9 Run 'cargo fmt' 2018-08-18 17:54:26 +02:00
TA Thanh Dinh 037861e588 replace trait object BufRead by generic 2018-08-18 17:54:26 +02:00
sharkdp 94ccc646e8 Update README 2018-07-23 21:58:06 +02:00
sharkdp 0cc5d1dab6 Update error-chain to fix compiler warnings 2018-07-23 21:54:30 +02:00
sharkdp 28397b8f78 Always show a warning when theme is unknown 2018-07-23 21:51:49 +02:00
sharkdp c899849101 Use map instead of and_then(..Some(..)) 2018-07-23 21:51:49 +02:00
sharkdp bf53b64125 Small style fix 2018-07-23 21:51:49 +02:00
Armando Perez c68aa0f424 Allow specifying the theme via the BAT_THEME environment variable
The `--theme` command line option stills takes precedence and this
change preserves how errors are handled when it's used: If a theme name
that doesn't exist is specified using the argument, this error is fatal.
However, if a theme that doesn't exist is specified using the environment
variable, the error is logged to `stderr` and the "Default" theme is
loaded as a fallback.
2018-07-23 21:51:49 +02:00
sharkdp 6b57f4eebc Style changes 2018-07-18 00:06:24 +02:00
eth-p 0ddd388a29 Improve logic for SGR sequence passthrough 2018-07-18 00:06:24 +02:00
eth-p 34811b8161 Fix #182 2018-07-18 00:06:24 +02:00
David Peter 8b92aae23f Fix Travis link 2018-07-17 23:37:03 +02:00
sharkdp 3a0941cabe Update syntaxes.bin 2018-07-17 23:28:44 +02:00
sharkdp 52877c6d67 Add Nix syntax, closes #180 2018-07-17 23:28:31 +02:00
sharkdp 455de98a89 Update sublimehq/Packages, closes #183 2018-07-17 23:27:19 +02:00
Stéphane Campinas 8c6a74a6c5 typo 2018-07-06 19:09:53 +02:00
Gert Hulselmans 3f8b340ed8 Add AWK syntax. 2018-06-15 16:41:51 +02:00
sharkdp 65e6970907 Change help text for --line-range 2018-06-12 08:18:44 +02:00
sharkdp 90cc019482 Run 'cargo fmt' 2018-06-12 08:18:44 +02:00
Taylor eaf0b99d25 update 2018-06-12 08:18:44 +02:00
Taylor Skinner 3b1dcca5d0 use map() 2018-06-12 08:18:44 +02:00
Taylor Skinner 26dbdf4fa0 update line-ranges 2018-06-12 08:18:44 +02:00
Taylor Skinner 6691786d82 add line-range 2018-06-12 08:18:44 +02:00
Conrad Kleinespel 50209bfe21 updates archlinux install instructions 2018-06-08 16:15:27 +02:00
sharkdp c91511cca1 Always run snapshot test 2018-06-02 19:03:38 +02:00
sharkdp c9f7a0c126 Use separate Git repository for snapshot testing
closes #161
2018-06-02 19:00:05 +02:00
Ezinwa Okpoechi 69c798eafd Fix command typo 2018-06-01 17:01:28 +02:00
sharkdp 195d5e0e16 Update Cargo.lock 2018-06-01 00:35:20 +02:00
sharkdp 86c1777205 Skip snapshot test if Git is not available
closes #161
2018-06-01 00:33:39 +02:00
sharkdp 16874ab016 Exclude assets from upload 2018-05-31 23:49:02 +02:00
sharkdp bf5883f06f Updates for 0.4 2018-05-31 22:57:18 +02:00
sharkdp e27bdfc7d6 Fix clippy warnings 2018-05-31 15:27:55 +02:00
David Peter a7f4f202cb Update README.md 2018-05-30 21:32:40 +02:00
David Peter 397223374a Add TOC 2018-05-30 21:23:24 +02:00
David Peter 0c2da90fa4 Change color of crates.io badge 2018-05-30 21:10:14 +02:00
David Peter fe29da6e76 Add license badge 2018-05-30 21:02:40 +02:00
sharkdp 0eccfb50d9 Update header 2018-05-30 20:54:46 +02:00
sharkdp f74263e71d Update syntect 2018-05-30 20:50:50 +02:00
sharkdp 54f4896ced Update syntaxes, fix CMake syntax problem 2018-05-30 20:43:50 +02:00
sharkdp 9d92350cbb Use default Markdown syntax, closes #157 2018-05-30 20:40:02 +02:00
sharkdp 26d409db65 Add 'rouge' to list of alternatives 2018-05-30 19:24:30 +02:00
sharkdp 06cd4b2ce8 Add 'coderay' to list of alternatives 2018-05-30 19:16:08 +02:00
sharkdp a348a9f68e Handle syntax-set loading errors 2018-05-25 22:42:06 +02:00
sharkdp 39e2971e96 Add .ignore files to avoid searching asset folders 2018-05-25 17:44:50 +02:00
TA Thanh Dinh a13eb60df3 Using slice notation instead of as_ref 2018-05-25 17:38:54 +02:00
sharkdp 9342d0bb24 Explicitly specify which args override themselves 2018-05-24 22:53:23 +02:00
sharkdp 36d7250af2 Allow arguments to override themselves 2018-05-24 22:53:23 +02:00
Ezinwa Okpoechi 2ce8655167 Build bat before generating snapshots 2018-05-24 19:10:24 +02:00
Ezinwa Okpoechi a452467e06 Remove unnecessary space if there are no decorations 2018-05-24 19:10:24 +02:00
Ezinwa Okpoechi 2ea3758c4b Justify header when there are decorations but no grid 2018-05-24 19:10:24 +02:00
Gert Hulselmans 65bb4c7ee6 Print themes directory in error message if no themes could be loaded from it.
Before this patch:
    $ bat cache --init
    [bat error]: Could not load themes from '{}'

After:
    $ bat cache --init
    [bat error]: Could not load themes from '/home/user/.config/bat/themes'
2018-05-24 09:09:23 +02:00
sharkdp 556149ad3a Add comparison benchmark 2018-05-22 23:32:46 +02:00
Gert Hulselmans 33bbf25468 Fix launching of pager so text is interpreted as UTF-8 by default.
This fixes issue https://github.com/sharkdp/bat/issues/98
2018-05-22 22:41:58 +02:00
sharkdp 5ee8913538 Add logo header to README 2018-05-22 22:39:20 +02:00
David Peter 9b1c1c0271 Add more benchmark results 2018-05-22 22:27:25 +02:00
Ezinwa Okpoechi 2712d63a4b Move asset clearing to assets module 2018-05-21 23:20:45 +02:00
Ezinwa Okpoechi b21fb6bca8 Extract features to separate module 2018-05-21 23:20:45 +02:00
Ezinwa Okpoechi ee43377a9c Move colors to printer module 2018-05-21 19:24:02 +02:00
Ezinwa Okpoechi 120b33a9db Move output to separate module 2018-05-21 19:24:02 +02:00
sharkdp 17b37fedcb Add project goals and list of alternatives 2018-05-21 00:28:30 +02:00
sharkdp 1013cdd80a Bump version 2018-05-19 17:55:07 +02:00
sharkdp be0a2d6048 Extended help texts for '--help' 2018-05-19 17:54:05 +02:00
sharkdp d1a1943998 Add -u and -n options, see #134 2018-05-19 16:58:45 +02:00
sharkdp 2a9f5a24ed Permissive error handling, closes #17 2018-05-19 12:50:41 +02:00
sharkdp a0ae089c4a Reset line number to 0 for new files 2018-05-19 12:25:07 +02:00
sharkdp 96cc391f2d Skip '--quit-if-one-screen' for --paging=always
closes #97
2018-05-19 10:54:54 +02:00
sharkdp a1e1170319 Add a few popular Sublime Text themes 2018-05-18 20:41:40 +02:00
sharkdp 54a331d162 Add syntax docu, add VimL, CMake, INI, LESS syntax
closes #99
closes #106
2018-05-18 19:57:58 +02:00
sharkdp 5e3b17e6f7 Fix code formatting 2018-05-18 17:44:43 +02:00
eth-p 486e6a19cd Fixed #124 2018-05-18 17:44:43 +02:00
Ezinwa Okpoechi 247dfbee83 Extract syntax finding to assets module 2018-05-18 16:45:59 +02:00
Ezinwa Okpoechi 882931a77b Update snapshots 2018-05-18 16:44:34 +02:00
Ezinwa Okpoechi 12cb438aa4 Handle line with invalid UTF-8 2018-05-18 16:44:34 +02:00
Ezinwa Okpoechi d0782ef954 Add line with invalid UTF-8 2018-05-18 16:44:34 +02:00
sharkdp c826c2a438 Better error handling 2018-05-16 22:55:37 +02:00
sharkdp 9aa97b6c22 Update to latest syntect, closes #100 2018-05-16 22:55:37 +02:00
sharkdp f7890870ea Add syntax for Dockerfiles
closes #101
2018-05-16 22:04:12 +02:00
sharkdp 145b99f01c Include syntaxes and themes in repository
This changes a few things:

- All syntaxes and themes are now stored (as submodules) under
  assets/syntaxes and assets/themes

- The default directories for syntaxes and themes are "syntaxes"
  and "themes" (used to be "syntax" and "themes")

- The "bat cache" command can now take a `--source <dir>` and
  `--target <dir>` option.

- The cached files have been renamed to "themes.bin" and "syntaxes.bin"
2018-05-16 22:04:12 +02:00
Mateusz Piotrowski 9af1d2b891 Add FreeBSD installation instructions
Closes #41.
2018-05-16 20:25:14 +02:00
David Peter 2eee68599d Merge pull request #102 from eth-p/master
Added text wrapping. (Fixes #54)
2018-05-16 08:41:49 +02:00
eth-p d569693dab Formatted with newer cargo fmt.
It should pass all the checks now.
2018-05-16 08:29:41 +02:00
eth-p 900f61032d Fix #117 2018-05-15 14:09:51 -07:00
eth-p d0ca566979 Replace for_line and for_wrap with generate 2018-05-15 13:55:38 -07:00
eth-p a5a7dc14e4 Fix \r character being printed with wrapping enabled. 2018-05-14 14:36:08 -07:00
sharkdp 54b33c8c21 Add simple benchmark scripts 2018-05-14 22:20:26 +02:00
rleungx a5de77af4d address comment 2018-05-14 20:30:16 +02:00
rleungx 870ff7b538 sort the language listing 2018-05-14 20:30:16 +02:00
sharkdp 15b9acd12f Updates for new rustfmt 2018-05-14 19:04:13 +02:00
eth-p b327127f37 Split decorations into a separate file and optimized them a bit. 2018-05-13 18:44:07 -07:00
eth-p 9214a4a4f0 PR #102 Followed @sharkdp's suggestions 2018-05-13 12:45:16 -07:00
sharkdp fcecd97224 Add ansi_term import for Windows, see #107 2018-05-13 21:19:26 +02:00
eth-p 870b3c0daf PR #102 Followed @BrainMaestro's suggestions
Also ran cargo fmt.
2018-05-13 03:26:23 -07:00
sharkdp b9c780c8c8 Ignore errors when clearing cache, closes #91 2018-05-13 10:34:35 +02:00
sharkdp ca865f9d26 Enable ANSI support on Windows 10 2018-05-13 09:58:16 +02:00
sharkdp 3ee0e56315 Update create.sh script 2018-05-13 09:53:30 +02:00
Eric Davies 091b0b6437 Add Julia highlighting support 2018-05-13 09:53:00 +02:00
eth-p 9f005d115d Update snapshot test files. 2018-05-12 14:04:54 -07:00
eth-p b4cfc9633c Fix double spaces when outputting without wrapping. 2018-05-12 14:02:47 -07:00
eth-p f7e055b6b7 Merge branch 'master' of https://github.com/sharkdp/bat 2018-05-12 14:00:25 -07:00
eth-p d4b438b9d3 Fix padding, add --wrap argument, disable wrap for non-tty. (Fixed)
I'm not quite sure what was up with git on that last commit, but it's
all properly committed now.
2018-05-12 13:44:10 -07:00
eth-p cd26d403a3 Fix padding, add --wrap argument, disable wrap for non-tty.
Now bat(1) can be used like cat(1) again!
2018-05-12 13:23:33 -07:00
eth-p f95a23f948 Fix off-by-one error with text wrapping and --style grid 2018-05-12 12:07:41 -07:00
Ezinwa Okpoechi 0886a24685 Add snapshot testing 2018-05-12 18:07:30 +02:00
Ezinwa Okpoechi 53eb9c57d6 Add generated snapshots 2018-05-12 18:07:30 +02:00
Ezinwa Okpoechi 026a9ebae3 Add sample files and snapshot generator 2018-05-12 18:07:30 +02:00
Ethan P bdd10b8bec Merge branch 'master' into master 2018-05-12 06:40:47 -07:00
eth-p fc160b0dcd PR #102 Review Changes
- Reformatted code.
- Removed leftover code.
- Removed leftover comments.
- Fixed compiling on Rust 1.24.0
2018-05-12 06:32:23 -07:00
sharkdp cb7b158172 Add bold, italic and underline font styles 2018-05-12 13:23:39 +02:00
eth-p fcc36b1f79 Forgot to add styling to the horizontal line. 2018-05-11 22:49:26 -07:00
eth-p 4e4110bf50 Added line wrapping. 2018-05-11 21:59:26 -07:00
Ryan Leung 22c8978fca add theme option (#95)
closes #89
2018-05-11 13:53:17 +02:00
Ezinwa Okpoechi f711fb5006 Split style to separate module 2018-05-11 10:15:26 +02:00
Ezinwa Okpoechi 64a9341b73 Split app to separate module 2018-05-11 10:15:26 +02:00
sharkdp ccf88fd5d8 Add and use --style=auto by default 2018-05-10 16:22:24 +02:00
David Peter 6343535eb2 Add 32bit support (#87)
* Add 32bit support, closes #84
* Remove error-chain backtrace support
2018-05-10 14:36:05 +02:00
sharkdp e2ac6de783 Fix clippy warnings 2018-05-10 13:15:59 +02:00
Ezinwa Okpoechi 25cee002f9 Split modules (#86)
* Split diffing to separate module
* Split assets to separate module
2018-05-10 12:36:09 +02:00
sharkdp 13a53d230b Add MacOS install instructions, closes #33 2018-05-10 12:35:07 +02:00
sharkdp ea27053a63 Remove unused lifetimes 2018-05-10 12:20:38 +02:00
Pit Kleyersburg b2b932f3ed Fix header-line if grid is not requested 2018-05-10 12:20:38 +02:00
Pit Kleyersburg 747d074be1 Replace Cow by String 2018-05-10 12:20:38 +02:00
Pit Kleyersburg 61109ece15 Create OutputComponents struct, use HashSet 2018-05-10 12:20:38 +02:00
Pit Kleyersburg 389edd7239 Combine OutputComponents and PredefinedStyles
This commit tries to simply the change. Instead of separating an
`OutputComponent` and a `PredefinedStyle`, I have combined the two into
just `OutputComponent`.

To still have the styles work, I added an impl to `OutputComponent` with
a function `components` which returns the components related to the
specified component.

For a simple output component this is trivial, but for the predefined
styles this is a list of other components.

The evaluating of the command-line parameter simplified significantly,
making use of Claps `values_t!` macro to parse the supplied parameters
into a `Vec<OutputComponent>`. After that it is simply a task of
combining all supplied output components into one vector.

Important: this means that the styles are now additive, rather than one
of the predefined styles overruling other parameters supplied.
2018-05-10 12:20:38 +02:00
Pit Kleyersburg 23813cc08b Make --style parameter more flexible
The `--style` parameter now accepts a comma-separated list of strings,
where every element defines either a single output component (`changes`,
`grid`, `header`, `numbers`) or a predefined style (`full`,
`line-numbers`, `plain`).

If available, bat picks the first predefined style in the user-supplied
style-list and ignores everything else. If no predefined style was
requested, the other parameters that are simple output components will
be used.

Examples:

    --style changes,full,numbers

  Will internally be reduced to only the predefined style `full`.

    --style plain,full

  Will internally be reduced to only the predefined style `plain`.

    --style changes,numbers

  Will not be reduced, because the list does not contain any predefined
  styles.

(Note: if `grid` is requested but no other parameters, bat still creates
the left-most column with a width of `PANEL_WIDTH`. I didn't want to
introduce further logic in this PR that drops or adapts the width of the
left column.)
2018-05-10 12:20:38 +02:00
David Peter fdeb98e859 Add usage examples 2018-05-09 00:33:49 +02:00
David Peter 6a417886aa Add comment about paging & concatenation 2018-05-09 00:12:25 +02:00
127 changed files with 27756 additions and 1245 deletions
+96
View File
@@ -0,0 +1,96 @@
[submodule "assets/syntaxes/Elixir"]
path = assets/syntaxes/Elixir
url = https://github.com/princemaple/elixir-sublime-syntax/
[submodule "assets/syntaxes/Packages"]
path = assets/syntaxes/Packages
url = https://github.com/sublimehq/Packages/
[submodule "assets/syntaxes/TOML"]
path = assets/syntaxes/TOML
url = https://github.com/sharkdp/sublime_toml_highlighting
[submodule "assets/syntaxes/Julia"]
path = assets/syntaxes/Julia
url = https://github.com/JuliaEditorSupport/Julia-sublime
[submodule "assets/themes/sublime-monokai-extended"]
path = assets/themes/sublime-monokai-extended
url = https://github.com/jonschlinkert/sublime-monokai-extended
[submodule "assets/syntaxes/Docker"]
path = assets/syntaxes/Docker
url = https://github.com/asbjornenge/Docker.tmbundle
[submodule "assets/syntaxes/VimL"]
path = assets/syntaxes/VimL
url = https://github.com/SalGnt/Sublime-VimL
[submodule "assets/syntaxes/INI"]
path = assets/syntaxes/INI
url = https://github.com/clintberry/sublime-text-2-ini
[submodule "assets/syntaxes/CMake"]
path = assets/syntaxes/CMake
url = https://github.com/zyxar/Sublime-CMakeLists
[submodule "assets/syntaxes/LESS"]
path = assets/syntaxes/LESS
url = https://github.com/danro/LESS-sublime
[submodule "assets/themes/DarkNeon"]
path = assets/themes/DarkNeon
url = https://github.com/RainyDayMedia/DarkNeon
[submodule "assets/themes/github-sublime-theme"]
path = assets/themes/github-sublime-theme
url = https://github.com/AlexanderEkdahl/github-sublime-theme
[submodule "assets/themes/1337-Scheme"]
path = assets/themes/1337-Scheme
url = https://github.com/MarkMichos/1337-Scheme
[submodule "assets/themes/TwoDark"]
path = assets/themes/TwoDark
url = https://github.com/erremauro/TwoDark
[submodule "assets/syntaxes/AWK"]
path = assets/syntaxes/AWK
url = https://github.com/JohnNilsson/awk-sublime
[submodule "assets/syntaxes/Nix"]
path = assets/syntaxes/Nix
url = https://github.com/wmertens/sublime-nix
[submodule "assets/themes/zenburn"]
path = assets/themes/zenburn
url = https://github.com/colinta/zenburn.git
[submodule "assets/syntaxes/Kotlin"]
path = assets/syntaxes/Kotlin
url = https://github.com/vkostyukov/kotlin-sublime-package
[submodule "assets/syntaxes/Elm"]
path = assets/syntaxes/Elm
url = https://github.com/elm-community/SublimeElmLanguageSupport
[submodule "assets/syntaxes/TypeScript"]
path = assets/syntaxes/TypeScript
url = https://github.com/Microsoft/TypeScript-Sublime-Plugin
[submodule "assets/syntaxes/Puppet"]
path = assets/syntaxes/Puppet
url = https://github.com/russCloak/SublimePuppet
[submodule "assets/syntaxes/CSV"]
path = assets/syntaxes/CSV
url = https://github.com/wadetb/Sublime-Text-Advanced-CSV
[submodule "assets/themes/onehalf"]
path = assets/themes/onehalf
url = https://github.com/sonph/onehalf
[submodule "assets/syntaxes/JavaScript (Babel)"]
path = assets/syntaxes/JavaScript (Babel)
url = https://github.com/babel/babel-sublime
[submodule "assets/syntaxes/Cabal"]
path = assets/syntaxes/Cabal
url = https://github.com/SublimeHaskell/SublimeHaskell
[submodule "assets/syntaxes/Dart"]
path = assets/syntaxes/Dart
url = https://github.com/guillermooo/dart-sublime-bundle
[submodule "assets/syntaxes/FSharp"]
path = assets/syntaxes/FSharp
url = https://github.com/hoest/sublimetext-fsharp
[submodule "assets/syntaxes/PureScript"]
path = assets/syntaxes/PureScript
url = https://github.com/tellnobody1/sublime-purescript-syntax
[submodule "assets/syntaxes/Swift"]
path = assets/syntaxes/Swift
url = https://github.com/quiqueg/Swift-Sublime-Package
[submodule "assets/syntaxes/Crystal"]
path = assets/syntaxes/Crystal
url = https://github.com/crystal-lang-tools/sublime-crystal.git
[submodule "assets/syntaxes/PowerShell"]
path = assets/syntaxes/PowerShell
url = https://github.com/PowerShell/EditorSyntax
[submodule "assets/syntaxes/Robot"]
path = assets/syntaxes/Robot
url = https://github.com/andriyko/sublime-robot-framework-assistant.git
+24 -20
View File
@@ -11,21 +11,36 @@ matrix:
env: env:
- TARGET=x86_64-unknown-linux-musl - TARGET=x86_64-unknown-linux-musl
- CC_x86_64_unknown_linux_musl=/usr/bin/musl-gcc - CC_x86_64_unknown_linux_musl=/usr/bin/musl-gcc
- os: linux
rust: stable
env: TARGET=i686-unknown-linux-gnu
- os: osx - os: osx
rust: stable rust: stable
env: TARGET=x86_64-apple-darwin env: TARGET=x86_64-apple-darwin
- os: linux
rust: stable
env:
- TARGET=arm-unknown-linux-gnueabihf
- CC_arm_unknown_linux_gnueabihf=/usr/bin/arm-linux-gnueabihf-gcc-4.8
- CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc-4.8
- os: linux
rust: stable
env:
- TARGET=aarch64-unknown-linux-gnu
- CC_aarch64-unknown-linux-gnu=/usr/bin/aarch64-linux-gnu-gcc-4.8
- CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc-4.8
# Minimum Rust supported channel. # Minimum Rust supported channel.
- os: linux - os: linux
rust: 1.24.0 rust: 1.29.0
env: TARGET=x86_64-unknown-linux-gnu env: TARGET=x86_64-unknown-linux-gnu
- os: linux - os: linux
rust: 1.24.0 rust: 1.29.0
env: env:
- TARGET=x86_64-unknown-linux-musl - TARGET=x86_64-unknown-linux-musl
- CC_x86_64_unknown_linux_musl=/usr/bin/musl-gcc - CC_x86_64_unknown_linux_musl=/usr/bin/musl-gcc
- os: osx - os: osx
rust: 1.24.0 rust: 1.29.0
env: TARGET=x86_64-apple-darwin env: TARGET=x86_64-apple-darwin
# Code formatting check # Code formatting check
@@ -34,17 +49,12 @@ matrix:
# skip the global install step # skip the global install step
install: install:
- cargo install --debug --force rustfmt-nightly - cargo install --debug --force rustfmt-nightly
script: cargo fmt -- --write-mode=diff script: cargo fmt -- --check
addons: sudo: required
apt:
packages: before_install:
# needed for i686-unknown-linux-gnu target - ci/before_install.bash
- gcc-multilib
# needed for musl targets
- musl-tools
# needed to build deb packages
- fakeroot
env: env:
global: global:
@@ -59,13 +69,7 @@ install:
- if [[ $TRAVIS_OS_NAME = linux && $HOST != $TARGET ]]; then rustup target add $TARGET; fi - if [[ $TRAVIS_OS_NAME = linux && $HOST != $TARGET ]]; then rustup target add $TARGET; fi
script: script:
# Incorporate TARGET env var to the build and test process - ci/script.bash
- cargo build --target $TARGET --verbose
- cargo test --target $TARGET --verbose
# Run 'bat' on its own source code and the README
# Piping to 'cat' forces the tty check to fail so that a pager is not used
- cargo run --target $TARGET -- src/main.rs | cat
- cargo run --target $TARGET -- README.md | cat
before_deploy: before_deploy:
- bash ci/before_deploy.bash - bash ci/before_deploy.bash
Generated
+527 -374
View File
File diff suppressed because it is too large Load Diff
+27 -6
View File
@@ -7,15 +7,24 @@ license = "MIT/Apache-2.0"
name = "bat" name = "bat"
readme = "README.md" readme = "README.md"
repository = "https://github.com/sharkdp/bat" repository = "https://github.com/sharkdp/bat"
version = "0.3.0" version = "0.8.0"
exclude = [
"assets/syntaxes/*",
"assets/themes/*",
]
build = "build.rs"
[dependencies] [dependencies]
atty = "0.2.2" atty = "0.2.2"
ansi_term = "0.10" ansi_term = "0.11"
ansi_colours = "^1.0"
console = "0.6" console = "0.6"
error-chain = "0.11" directories = "1.0"
directories = "0.10"
lazy_static = "1.0" lazy_static = "1.0"
wild = "2.0"
content_inspector = "0.2.3"
encoding = "0.2"
shell-words = "0.1.0"
[dependencies.git2] [dependencies.git2]
version = "0.7" version = "0.7"
@@ -23,11 +32,23 @@ default-features = false
features = [] features = []
[dependencies.syntect] [dependencies.syntect]
version = "2" version = "3.0.1"
default-features = false default-features = false
features = ["parsing", "yaml-load", "dump-load", "dump-create"] features = ["parsing", "yaml-load", "dump-load", "dump-create"]
[dependencies.clap] [dependencies.clap]
version = "2" version = "2.32"
default-features = false default-features = false
features = ["suggestions", "color", "wrap_help"] features = ["suggestions", "color", "wrap_help"]
[dependencies.error-chain]
version = "0.12"
default-features = false
features = []
[dev-dependencies]
tempdir = "0.3"
assert_cmd = "0.10.1"
[build-dependencies]
clap = "2.32"
+361 -53
View File
@@ -1,11 +1,19 @@
# bat <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?svg=true"></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>
A <i>cat(1)</i> clone with syntax highlighting and Git integration.
</p>
[![Build Status](https://travis-ci.org/sharkdp/bat.svg?branch=master)](https://travis-ci.org/sharkdp/bat) <p align="center">
[![Version info](https://img.shields.io/crates/v/bat.svg)](https://crates.io/crates/bat) <a href="#syntax-highlighting">Key Features</a> •
<a href="#how-to-use">How To Use</a> •
A *cat(1)* clone with syntax highlighting and Git integration. <a href="#installation">Installation</a> •
<a href="#customization">Customization</a> •
## Features <a href="#project-goals-and-alternatives">Project goals, alternatives</a>
</p>
### Syntax highlighting ### Syntax highlighting
@@ -21,82 +29,382 @@ languages:
![Git integration example](https://i.imgur.com/2lSW4RE.png) ![Git integration example](https://i.imgur.com/2lSW4RE.png)
### Automatic paging
`bat` can pipe its own output to `less` if the output is too large for one screen.
### File concatenation
Oh.. you can also use it to concatenate files :wink:. Whenever
`bat` detects a non-interactive terminal, it will fall back to printing
the plain file contents.
## How to use
Display a single file on the terminal
```bash
> bat README.md
```
Display multiple files at once
```bash
> bat src/*.rs
```
Read from stdin, determine the syntax automatically
```bash
> curl -s https://sh.rustup.rs | bat
```
Read from stdin, specify the language explicitly
```bash
> yaml2json .travis.yml | json_pp | bat -l json
```
As a replacement for `cat`:
```bash
bat > note.md # quickly create a new file
bat header.md content.md footer.md > document.md
bat -n main.rs # show line numbers (only)
bat f - g # output 'f', then stdin, then 'g'.
```
## Installation ## Installation
### On Ubuntu
*... and other Debian-based Linux distributions.*
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.8.0_amd64.deb # adapt version number and architecture
```
### On Arch Linux
You can install [the `bat` package](https://www.archlinux.org/packages/community/x86_64/bat/)
from the official sources:
```bash
pacman -S bat
```
### On Void Linux
You can install `bat` via xbps-install:
```
xbps-install -S bat
```
### On FreeBSD
You can install a precompiled [`bat` package](https://www.freshports.org/textproc/bat) with pkg:
```bash
pkg install bat
```
or build it on your own from the FreeBSD ports:
```bash
cd /usr/ports/textproc/bat
make install
```
### Via nix
You can install `bat` using the [nix package manager](https://nixos.org/nix):
```bash
nix-env -i bat
```
### On macOS
You can install `bat` with [Homebrew](http://braumeister.org/formula/bat):
```bash
brew install bat
```
### On Windows
You can download prebuilt binaries from the [Release page](https://github.com/sharkdp/bat/releases),
or install it with [scoop](https://scoop.sh/):
```bash
scoop install bat
```
[See below](#using-bat-on-windows) for notes.
### Via Docker
There is a [Docker image](https://hub.docker.com/r/danlynn/bat/) that you can use to run `bat` in a container:
```bash
docker pull danlynn/bat
alias bat='docker run -it --rm -e BAT_THEME -e BAT_STYLE -e BAT_TABS -v "$(pwd):/myapp" danlynn/bat'
```
### Via Ansible
You can install `bat` with [Ansible](https://www.ansible.com/):
```bash
# Install role on local machine
ansible-galaxy install aeimer.install_bat
```
```yaml
---
# Playbook to install bat
- host: all
roles:
- aeimer.install_bat
```
- [Ansible Galaxy](https://galaxy.ansible.com/aeimer/install_bat)
- [GitHub](https://github.com/aeimer/ansible-install-bat)
This should work with the following distributions:
- Debian/Ubuntu
- ARM (eg. Raspberry PI)
- Arch Linux
- Void Linux
- FreeBSD
- MacOS
### From binaries ### From binaries
Check out the [Release page](https://github.com/sharkdp/bat/releases) for Check out the [Release page](https://github.com/sharkdp/bat/releases) for
binary builds and Debian packages. prebuilt versions of `bat` for many different architectures. Statically-linked
binaries are available, just look for releases with `musl` in the name on the
#### Arch Linux releases page.
On Arch Linux, you can install
[the AUR package](https://aur.archlinux.org/packages/bat/) via yaourt, or
manually:
```bash
git clone https://aur.archlinux.org/bat.git
cd bat
makepkg -si
```
### From source ### From source
If you want to build to compile `bat` from source, you need Rust 1.24 or If you want to build `bat` from source, you need Rust 1.29 or
higher. You can then use `cargo` to build everything: higher. You can then use `cargo` to build everything:
``` bash ```bash
cargo install bat cargo install bat
``` ```
On macOS, you might have to install `cmake` (`brew install cmake`) in order for You may have to install `cmake` and the `libz` development package
some dependencies to be built. (`libz-dev` or `libz-devel`) in order for the build to succeed.
## Customization ## Customization
### Highlighting theme
Use `bat --list-themes` to get a list of all available themes for syntax
highlighting. To select the `TwoDark` theme, call `bat` with the
`--theme=TwoDark` option or set the `BAT_THEME` environment variable to
`TwoDark`. Use `export BAT_THEME="TwoDark"` in your shell's startup file to
make the change permanent.
If you want to preview the different themes on a custom file, you can use
the following command (you need [`fzf`](https://github.com/junegunn/fzf) for this):
``` bash
bat --list-themes | fzf --preview="bat --theme={} --color=always /path/to/file"
```
`bat` looks good on a dark background by default. However, if your terminal uses a
light background, some themes will work better for you. For example, the `GitHub`
theme is made for light backgrounds. You can also make your own theme by following the
['Adding new themes' section below](https://github.com/sharkdp/bat#adding-new-themes).
### Output style
You can use the `--style` option to control the appearance of `bat`s output.
You can use `--style=numbers,changes`, for example, to show only Git changes
and line numbers but no grid and no file header. Use the `BAT_STYLE` environment
variable to make these changes permanent.
### Adding new syntaxes / language definitions
`bat` uses the excellent [`syntect`](https://github.com/trishume/syntect/) `bat` uses the excellent [`syntect`](https://github.com/trishume/syntect/)
library for syntax highlighting. `syntect` can read any library for syntax highlighting. `syntect` can read any
[Sublime Text `.sublime-syntax` file](https://www.sublimetext.com/docs/3/syntax.html) [Sublime Text `.sublime-syntax` file](https://www.sublimetext.com/docs/3/syntax.html)
and theme. and theme. To add new syntax definitions, do the following.
To build your own language-set and theme, follow these steps: Create a folder with syntax definition files:
Create a folder with a syntax highlighting theme: ```bash
BAT_CONFIG_DIR="$(bat cache --config-dir)"
``` bash mkdir -p "$BAT_CONFIG_DIR/syntaxes"
cd "$BAT_CONFIG_DIR/syntaxes"
# Put new '.sublime-syntax' language definition files
# in this folder (or its subdirectories), for example:
git clone https://github.com/tellnobody1/sublime-purescript-syntax
```
Now use the following command to parse these files into a binary cache:
```bash
bat cache --init
```
Finally, use `bat --list-languages` to check if the new languages are available.
If you ever want to go back to the default settings, call:
```bash
bat cache --clear
```
### Adding new themes
This works very similar to how we add new syntax definitions.
First, create a folder with the new syntax highlighting themes:
```bash
BAT_CONFIG_DIR="$(bat cache --config-dir)" BAT_CONFIG_DIR="$(bat cache --config-dir)"
mkdir -p "$BAT_CONFIG_DIR/themes" mkdir -p "$BAT_CONFIG_DIR/themes"
cd "$BAT_CONFIG_DIR/themes" cd "$BAT_CONFIG_DIR/themes"
# Download a theme, for example: # Download a theme in '.tmTheme' format, for example:
git clone https://github.com/jonschlinkert/sublime-monokai-extended git clone https://github.com/greggb/sublime-snazzy
# Create a 'Default.tmTheme' link # Update the binary cache
ln -s "sublime-monokai-extended/Monokai Extended.tmTheme" Default.tmTheme
```
Create a folder with language definition files:
``` bash
mkdir -p "$BAT_CONFIG_DIR/syntax"
cd "$BAT_CONFIG_DIR/syntax"
# Download some language definition files, for example:
git clone https://github.com/sublimehq/Packages/
rm -rf Packages/Markdown
git clone https://github.com/jonschlinkert/sublime-markdown-extended
```
Finally, use the following command to parse all these files into a binary
cache:
``` bash
bat cache --init bat cache --init
``` ```
If you ever want to go back to the default settings, call: Finally, use `bat --list-themes` to check if the new themes are available.
``` bash ### Using a different pager
bat cache --clear
`bat` uses the pager that is specified in the `PAGER` environment variable. If this variable is not
set, `less` is used by default. If you want to use a different pager, you can either modify the
`PAGER` variable or set the `BAT_PAGER` environment variable to override what is specified in
`PAGER`.
If you want to pass command-line arguments to the pager, you need to create a small shell
script as a wrapper, for example
```bash
#!/bin/bash
less --tabs 4 -R "$@"
``` ```
(put this in a file `~/.bat-pager.sh`, make it executable `chmod +x ~/.bat-pager.sh` and use
`export BAT_PAGER="$HOME/.bat-pager.sh"` in your shells `rc` file)
**Note**: By default, if the pager is set to `less`, `bat` will pass the following command line
options to the pager: `-R`/`--RAW-CONTROL-CHARS`, `-F`/`--quit-if-one-screen` and `-X`/`--no-init`.
The first (`-R`) is needed to interpret ANSI colors correctly. The second option (`-F`) instructs
less to exit immediately if the output size is smaller than the vertical size of the terminal.
This is convenient for small files because you do not have to press `q` to quit the pager. The
third option (`-X`) is needed to fix a bug with the `--quit-if-one-screen` feature in old versions
of `less`. Unfortunately, it also breaks mouse-wheel support in `less`. If you want to enable
mouse-wheel scrolling, you can either pass just `-R` (as in the example above, this will disable
the quit-if-one-screen feature), or you can use a recent version of `less` and pass `-RF` which
will hopefully enable both quit-if-one-screen and mouse-wheel scrolling.
If scrolling still doesn't work for you, you can try to pass the `-S` option in addition.
## Using `bat` on Windows
`bat` mostly works out-of-the-box on Windows, but a few features may need extra configuration.
### Paging
Windows only includes a very limited pager in the form of `more`. You can download a Windows binary
for `less` [from its homepage](http://www.greenwoodsoftware.com/less/download.html) or [through
Chocolatey](https://chocolatey.org/packages/Less). To use it, place the binary in a directory in
your `PATH` or [define an environment variable](#using-a-different-pager).
### Colours
Windows 10 natively supports colours in both `conhost.exe` (Command Prompt) and PowerShell since
[v1511](https://en.wikipedia.org/wiki/Windows_10_version_history#Version_1511_(November_Update)), as
well as in newer versions of bash. On earlier versions of Windows, you can use
[Cmder](http://cmder.net/), which includes [ConEmu](https://conemu.github.io/).
**Note:** The Git and MSYS versions of `less` do not correctly interpret colours on Windows. If you
dont have any other pagers installed, you can disable paging entirely by passing `--paging=never`
or by setting `BAT_PAGER` to an empty string.
### Cygwin
`bat` on Windows does not natively support Cygwin's unix-style paths (`/cygdrive/*`). When passed an absolute cygwin path as an argument, `bat` will encounter the following error: `The system cannot find the path specified. (os error 3)`
This can be solved by creating a wrapper or adding the following function to your `.bash_profile` file:
```shell
bat() {
local index
local args=("$@")
for index in $(seq 0 ${#args[@]}) ; do
case "${args[index]}" in
-*) continue;;
*) [ -e "${args[index]}" ] && args[index]="$(cygpath --windows "${args[index]}")";;
esac
done
command bat "${args[@]}"
}
```
## Troubleshooting
### Terminals & colors
`bat` handles terminals *with* and *without* truecolor support. However, the colors in the syntax
highlighting themes are not optimized for 8-bit colors and it is therefore strongly recommended
that you use a terminal with 24-bit truecolor support (`terminator`, `konsole`, `iTerm2`, ...).
See [this article](https://gist.github.com/XVilka/8346728) for more details and a full list of
terminals with truecolor support.
Make sure that your truecolor terminal sets the `COLORTERM` variable to either `truecolor` or
`24bit`. Otherwise, `bat` will not be able to determine whether or not 24-bit escape sequences
are supported (and fall back to 8-bit colors).
### Line numbers and grid are hardly visible
Please try a different theme (see `bat --list-themes` for a list). The `OneHalfDark` and
`OneHalfLight` themes provide grid and line colors that are brighter.
## Development
```bash
# Recursive clone to retrieve all submodules
git clone --recursive https://github.com/sharkdp/bat
# Build (debug version)
cd bat
cargo build
# Run unit tests and integration tests
cargo test
# Install (release version)
cargo install
# Build a bat binary with modified syntaxes and themes
bash assets/create.sh
cargo install -f
```
## Project goals and alternatives
`bat` tries to achieve the following goals:
- Provide beautiful, advanced syntax highlighting
- Integrate with Git to show file modifications
- Be a drop-in replacement for (POSIX) `cat`
- Offer a user-friendly command-line interface
There are a lot of alternatives, if you are looking for similar programs. See
[this document](doc/alternatives.md) for a comparison.
+49
View File
@@ -0,0 +1,49 @@
environment:
global:
TARGET: x86_64-pc-windows-msvc
RUST_VERSION: stable
CRATE_NAME: bat
CARGO_HOME: "c:\\cargo"
RUSTUP_HOME: "c:\\rustup"
install:
- appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
- rustup-init.exe -y --default-host %TARGET%
- set PATH=%PATH%;C:\cargo\bin
- rustc -Vv
- cargo -V
build: false
test_script:
- cargo test --target %TARGET% --verbose
- cargo run --target %TARGET% -- src/main.rs README.md --paging=never
before_deploy:
# Generate artifacts for release
- cargo build --release --verbose
- ps: ci\before_deploy.ps1
deploy:
description: 'Automatically deployed release'
artifact: /.*\.zip/
# Here's how:
# - Go to 'https://github.com/settings/tokens/new' and generate a Token with only the
# `public_repo` scope enabled
# - Then go to 'https://ci.appveyor.com/tools/encrypt' and enter the newly generated token.
# - Enter the "encrypted value" below
auth_token:
secure: oO4/J+hcFXgXcEqEc8gzlQNqLG0IxU78s4EyH+uczGdsyWajb3yipxPR6nXUvmoj
provider: GitHub
on:
RUST_VERSION: stable
appveyor_repo_tag: true
cache:
- C:\Users\appveyor\.cargo\registry
- target
notifications:
- provider: Email
on_build_success: false
on_build_failure: false
on_build_status_changed: false
+2
View File
@@ -0,0 +1,2 @@
syntaxes/*
themes/*
+13
View File
@@ -0,0 +1,13 @@
diff --git syntaxes/Packages/Java/JavaDoc.sublime-syntax syntaxes/Packages/Java/JavaDoc.sublime-syntax
index 422a6a9..40a741e 100644
--- syntaxes/Packages/Java/JavaDoc.sublime-syntax
+++ syntaxes/Packages/Java/JavaDoc.sublime-syntax
@@ -13,7 +13,7 @@ variables:
contexts:
prototype:
# https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#leadingasterisks
- - match: ^\s*(\*)\s*(?!\s*@)
+ - match: ^\s*(\*)(?!/)\s*(?!\s*@)
captures:
1: punctuation.definition.comment.javadoc
+32
View File
@@ -0,0 +1,32 @@
## Syntax Highlighting in bat
`bat` uses the [syntect](https://github.com/trishume/syntect) library to highlight source
code. As a basis, syntect uses [Sublime Text](https://www.sublimetext.com/) syntax definitions
in the `.sublime-syntax` format.
In order to add new syntaxes to `bat`, follow these steps:
1. Find a Sublime Text syntax for the given language, preferably in a separate Git repository
which can be included as a submodule (under `assets/syntaxes`).
2. If the Sublime Text syntax is only available as a `.tmLanguage` file, open the file in
Sublime Text and convert it to a `.sublime-syntax` file via *Tools* -> *Developer* ->
*New Syntax from XXX.tmLanguage...*. Save the new file in the `assets/syntaxes` folder.
3. Run the `create.sh` script. It calls `bat cache --init` to parse all available
`.sublime-syntax` files and serialize them to a `syntaxes.bin` file (in this folder).
4. Re-compile `bat`. At compilation time, the `syntaxes.bin` file will be stored inside the
`bat` binary.
### Troubleshooting
Make sure that the local cache does not interfere with the internally stored syntaxes and
themes (`bat cache --clear`).
### Manual modifications
The following files have been manually modified after converting from a `.tmLanguage` file:
* `Dart.sublime-syntax` => removed `#regex.dart` include.
* `INI.sublime-syntax` => added `.hgrc` and `hgrc` file types.
Regular → Executable
+11 -31
View File
@@ -1,36 +1,16 @@
set -e #!/bin/bash
THEME_FOLDER="$HOME/.config/bat/themes" ASSET_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
SYNTAX_FOLDER="$HOME/.config/bat/syntax"
if [ ! -e "$THEME_FOLDER" ]; then # Always remove the local cache to avoid any confusion
mkdir -p "$THEME_FOLDER" bat cache --clear
(
cd "$THEME_FOLDER"
git clone https://github.com/jonschlinkert/sublime-monokai-extended
ln -s "sublime-monokai-extended/Monokai Extended.tmTheme" Default.tmTheme
)
fi
if [ ! -e "$SYNTAX_FOLDER" ]; then # TODO: Remove this (and the reverse part below) when
mkdir -p "$SYNTAX_FOLDER" # https://github.com/trishume/syntect/issues/160 has been fixed
( JAVADOC_FILE="${ASSET_DIR}/syntaxes/Packages/Java/JavaDoc.sublime-syntax"
cd "$SYNTAX_FOLDER" JAVADOC_PATCH="${ASSET_DIR}/JavaDoc.sublime-syntax.patch"
git clone https://github.com/sublimehq/Packages/ patch "$JAVADOC_FILE" "$JAVADOC_PATCH"
# Patch JavaScript syntax bat cache --init --blank --source="$ASSET_DIR" --target="$ASSET_DIR"
sed -i -e 's/{{identifier_break}}+/{{identifier_break}}/' Packages/JavaScript/JavaScript.sublime-syntax
# Use extended Markdown syntax patch -R "$JAVADOC_FILE" "$JAVADOC_PATCH"
rm -rf Packages/Markdown
git clone https://github.com/jonschlinkert/sublime-markdown-extended
# Add additional sxntax definitions
git clone https://github.com/princemaple/elixir-sublime-syntax/
git clone https://github.com/sharkdp/sublime_toml_highlighting
)
fi
bat init-cache
cp "$HOME/.cache/bat"/* .
BIN
View File
Binary file not shown.
Binary file not shown.
Submodule assets/syntaxes/AWK added at 1ce5f90d44
Submodule assets/syntaxes/CSV added at 4786d037a7
+46
View File
@@ -0,0 +1,46 @@
%YAML 1.2
---
# http://www.sublimetext.com/docs/3/syntax.html
name: Advanced CSV
file_extensions:
- csv
- tsv
scope: text.advanced_csv
contexts:
main:
- match: (\")
captures:
1: string.quoted.double.advanced_csv
push:
- meta_scope: meta.quoted.advanced_csv
- match: (\")
captures:
1: string.quoted.double.advanced_csv
pop: true
- include: main
- match: '(\[([+-]?\d*)(\:)?([+-]?\d*)(\,)?([+-]?\d*)(\:)?([+-]?\d*)\])?\s*([<>v^])?\s*(=)'
captures:
1: keyword.operator.advanced_csv
2: constant.numeric.formula.advanced_csv
4: constant.numeric.formula.advanced_csv
6: constant.numeric.formula.advanced_csv
8: constant.numeric.formula.advanced_csv
9: keyword.operator.advanced_csv
10: keyword.operator.advanced_csv
push:
- meta_scope: meta.range.advanced_csv
- match: (?=(\")|$)
pop: true
- include: scope:source.python
- match: '(?<=^|,|\s|\")([0-9.eE+-]+)(?=$|,|\s|\")'
scope: meta.number.advanced_csv
captures:
1: constant.numeric.advanced_csv
- match: '(?<=^|,|\s|\")([^, \t\"]+)(?=$|,|\s|\")'
scope: meta.nonnumber.advanced_csv
captures:
1: storage.type.advanced_csv
- match: (\,)
scope: meta.delimiter.advanced_csv
captures:
1: keyword.operator.advanced_csv
+47
View File
@@ -0,0 +1,47 @@
%YAML 1.2
---
# http://www.sublimetext.com/docs/3/syntax.html
name: Cabal
file_extensions:
- cabal
scope: source.cabal
contexts:
main:
- match: ^(\s*)(exposed-modules):$
captures:
2: constant.other.cabal
push:
- meta_scope: exposed.modules.cabal
- match: ^(?!\1\s)
pop: true
- include: module_name
- match: ^(\s*)(build-depends):$
captures:
2: constant.other.cabal
push:
- meta_scope: exposed.modules.cabal
- match: ^(?!\1\s)
pop: true
- match: "([<>=]+)|([&|]+)"
scope: keyword.operator.haskell
- match: ((\d+|\*)\.)*(\d+|\*)
scope: constant.numeric.haskell
- match: '([\w\-]+)'
scope: support.function.haskell
- match: '^\s*([a-zA-Z_-]+)(:)\s+'
scope: entity.cabal
captures:
1: constant.other.cabal
2: punctuation.entity.cabal
- match: '^(?i)(executable|library|test-suite|benchmark|flag|source-repository)\s+([^\s,]+)\s*$'
scope: entity.cabal
captures:
1: keyword.entity.cabal
2: string.cabal
- match: ^(?i)library\s*$
scope: keyword.entity.cabal
- match: "--.*$"
scope: comment.cabal
module_name:
- match: '([A-Z][A-Za-z_''0-9]*)(\.[A-Z][A-Za-z_''0-9]*)*'
scope: storage.module.haskell
File diff suppressed because it is too large Load Diff
+369
View File
@@ -0,0 +1,369 @@
%YAML 1.2
---
# http://www.sublimetext.com/docs/3/syntax.html
name: Dart
file_extensions:
- dart
scope: source.dart
contexts:
main:
- match: ^(#!.*)$
scope: meta.preprocessor.script.dart
- match: ^\s*\b(library|import|export|part of|part)\b
captures:
0: keyword.other.import.dart
push:
- meta_scope: meta.declaration.dart
- match: ;
captures:
0: punctuation.terminator.dart
pop: true
- include: strings
- match: \b(as|show|hide|deferred)\b
scope: keyword.other.import.dart
- include: comments
- include: constants-and-special-vars
- include: annotations
- include: decl-typedef
- include: decl-class
- include: decl-enum
- include: decl-function
- include: keywords
- include: strings
annotations:
- match: '^(?:\s*)((@)([a-zA-Z0-9_]+))'
captures:
1: annotation.dart
2: entity.name.function.annotation.dart
3: support.type.dart
comments:
- match: /\*\*/
scope: comment.block.empty.dart
captures:
0: punctuation.definition.comment.dart
- include: comments-inline
comments-inline:
- match: /\*
push:
- meta_scope: comment.block.dart
- match: \*/
pop: true
- include: scope:text.dart-doccomments
- match: (///)
captures:
1: marker.dart
push:
- meta_scope: comment.line.triple-slash.dart
- match: $
pop: true
- include: scope:text.dart-doccomments
- match: (//)
captures:
1: marker.dart
push:
- meta_scope: comment.line.double-slash.dart
- match: $
pop: true
- include: scope:text.dart-doccomments
constants-and-special-vars:
- match: \b(true|false|null)\b
scope: constant.language.dart
- match: \b(this|super)\b
scope: variable.language.dart
- match: '\b((0(x|X)[0-9a-fA-F]*)|(([0-9]+\.?[0-9]*)|(\.[0-9]+))((e|E)(\+|-)?[0-9]+)?)\b'
scope: constant.numeric.dart
decl-class:
- match: \bclass\b
captures:
0: keyword.control.new.dart
push:
- meta_scope: meta.declaration.class.dart
- match: "(?={)"
pop: true
- include: keywords
- match: "[A-Za-z_][A-Za-z0-9_]*"
scope: class.name.dart
decl-enum:
- match: \benum\b
captures:
0: keyword.declaration.dart
push:
- meta_scope: meta.declaration.enum.dart
- match: "(?={)"
pop: true
- include: keywords
- match: "[A-Za-z_][A-Za-z0-9_]*"
scope: enum.name.dart
decl-function:
- match: ^\s*(?:\b(void|bool|num|int|double|dynamic|var|String|List|Map)\b)\s+(get)\s+(\w+)\s+(?==>)
comment: A getter with a primitive return type.
scope: meta.declaration.function.dart
captures:
1: storage.type.primitive.dart
2: keyword.declaration.dart
3: function.name.dart
- match: ^\s*(?:\b(\w+)\b\s+)?(get)\s+(\w+)\s+(?==>)
comment: A getter with a user-defined return type or no return type.
scope: meta.declaration.function.dart
captures:
1: type.user-defined.dart
2: keyword.declaration.dart
3: function.name.dart
- match: ^\s*(set)\s+(\w+)(?=\()
comment: A setter.
captures:
1: keyword.declaration.dart
2: function.name.dart
push:
- meta_scope: meta.declaration.function.dart
- match: \)
pop: true
- include: comments-inline
- include: decl-function-parameter
- include: strings
- include: keywords
- match: ^\s*(?:\b(void|bool|num|int|double|dynamic|var|String|List|Map)\b)\s+(\w+)(?=\()
comment: A function with a primitive return type.
captures:
1: storage.type.primitive.dart
2: function.name.dart
push:
- meta_scope: meta.declaration.function.dart
- match: \)
pop: true
- include: comments-inline
- include: decl-function-parameter
- include: strings
- include: keywords
- match: ^\s*(?:\b(return)\b)\s+(\w+)(?=\()
comment: A function invocation after 'return'
captures:
1: keyword.control.dart
2: function.name.dart
push:
- meta_scope: meta.invocation.function.dart
- match: \)
pop: true
- include: comments-inline
- include: decl-function-parameter
- include: strings
- include: keywords
- match: ^\s*\b(new)\b\s+(\w+)(?=\()
comment: A class instantiation after 'new'
captures:
1: keyword.declaration.dart
2: function.name.dart
push:
- meta_scope: meta.invocation.function.dart
- match: \)
pop: true
- include: comments-inline
- include: decl-function-parameter
- include: strings
- include: keywords
decl-function-parameter:
- include: constants-and-special-vars
- match: (?:\b(void|bool|num|int|double|dynamic|var|String|List|Map)\b)\s+(\w+)(?=\()
comment: A function with a primitive return type.
captures:
1: storage.type.primitive.dart
2: function.name.dart
push:
- meta_scope: meta.parameter.function.dart
- match: \)
pop: true
- include: decl-function-parameter
- include: strings
- include: keywords
- match: \b(new)\b\s+(\w+)(?=\()
comment: A class instantiation after 'new'
captures:
1: keyword.declaration.dart
2: function.name.dart
push:
- meta_scope: meta.invocation.function.dart
- match: \)
pop: true
- include: decl-function-parameter
- include: strings
- include: keywords
- match: (?:\b(\w+)\b)\s+(\w+)(?=\()
comment: A function with a user-defined return type.
captures:
1: type.user-defined.dart
2: function.name.dart
push:
- meta_scope: meta.parameter.function.dart
- match: \)
pop: true
- include: decl-function-parameter
- include: strings
- include: keywords
- match: (\w+)(?=\()
comment: A function with no return type.
captures:
1: function.name.dart
push:
- meta_scope: meta.parameter.function.dart
- match: \)
pop: true
- include: decl-function-parameter
- include: strings
- include: keywords
decl-typedef:
- match: typedef
captures:
0: keyword.control.new.dart
push:
- meta_scope: meta.declaration.typedef.dart
- match: ;
captures:
0: punctuation.terminator.dart
pop: true
- match: '(?:\b(void|bool|num|int|double|dynamic|var|String|List|Map)\b|([a-zA-Z_][a-zA-Z0-9_]*))\s+([a-zA-Z_][a-zA-Z0-9_]+)'
captures:
1: storage.type.primitive.dart
2: typedef.return.dart
3: typedef.name.dart
- match: \(
push:
- meta_scope: typedef.params.dart
- match: \)
pop: true
- include: keywords
keywords:
- match: \bassert\b
scope: keyword.control.assert.dart
- match: \bas\b
scope: keyword.cast.dart
- match: \b(try|catch|finally|throw|on|rethrow)\b
scope: keyword.control.catch-exception.dart
- match: \s+\?\s+|\s+:\s+
scope: keyword.control.ternary.dart
- match: \b(break|case|continue|default|do|else|for|if|in|return|switch|while)\b
scope: keyword.control.dart
- match: \b(async\*|async|await\*|await|yield)\b
scope: keyword.control.async.dart
- match: \b(new)\b
scope: keyword.control.new.dart
- match: \b(abstract|extends|external|factory|implements|with|interface|get|native|operator|set|typedef)\b
scope: keyword.declaration.dart
- match: \b(is\!?)\b
scope: keyword.operator.dart
- match: (<<|>>>?|~|\^|\||&)
scope: keyword.operator.bitwise.dart
- match: ((&|\^|\||<<|>>>?)=)
scope: keyword.operator.assignment.bitwise.dart
- match: (===?|!==?|<=?|>=?)
scope: keyword.operator.comparison.dart
- match: '(([+*/%-]|\~)=)'
scope: keyword.operator.assignment.arithmetic.dart
- match: (=)
scope: keyword.operator.assignment.dart
- match: (\-\-|\+\+)
scope: keyword.operator.increment-decrement.dart
- match: (\-|\+|\*|\/|\~\/|%)
scope: keyword.operator.arithmetic.dart
- match: (!|&&|\|\|)
scope: keyword.operator.logical.dart
- match: ;
scope: punctuation.terminator.dart
- match: \b(static|final|const)\b
scope: storage.modifier.dart
- match: \b(?:void|bool|num|int|double|dynamic|var|String|List|Map)\b
scope: storage.type.primitive.dart
regexp:
- match: '\\[^''"]'
scope: constant.character.escaped.regex.dart
- match: \(
push:
- meta_content_scope: meta.capture.regex.dart
- match: \)
pop: true
- match: \?(:|=|!)
scope: ignore.capture.regex.dart
- match: \*|\+|\?|\.|\|
scope: keyword.other.regex.dart
- match: \^|\$
scope: keyword.other.regex.dart
- match: \.
scope: constant.other.regex.dart
- match: '\[(\^)?'
captures:
1: keyword.other.negation.regex.dart
push:
- meta_scope: constant.character.range.regex.dart
- match: '\]'
pop: true
- match: '\\[^"'']'
scope: constant.character.escaped.regex.dart
- match: '\{(?:\d+)?,(?:\d+)?\}'
scope: keyword.other.regex.dart
string-interp:
- match: '(\$)(\{)'
captures:
1: keyword.other.dart
2: keyword.other.dart
push:
- meta_scope: interpolation.dart
- meta_content_scope: source.dart
- match: '(\})'
captures:
1: keyword.other.dart
pop: true
- include: main
- match: (\$)(\w+)
captures:
1: keyword.other.dart
2: variable.parameter.dart
- match: \\.
scope: constant.character.escape.dart
strings:
- match: (?<!r)"""
push:
- meta_scope: string.interpolated.triple.double.dart
- match: '"""(?!")'
pop: true
- include: string-interp
- match: (?<!r)'''
push:
- meta_scope: string.interpolated.triple.single.dart
- match: "'''(?!')"
pop: true
- include: string-interp
- match: r"""
push:
- meta_scope: string.quoted.triple.double.dart
- match: '"""(?!")'
pop: true
- match: r'''
push:
- meta_scope: string.quoted.triple.single.dart
- match: "'''(?!')"
pop: true
- match: (?<!\\|r)"
push:
- meta_scope: string.interpolated.double.dart
- match: '"'
pop: true
- match: \n
scope: invalid.string.newline
- include: string-interp
- match: r"
push:
- meta_scope: string.quoted.double.dart
- match: '"'
pop: true
- include: regexp
- match: (?<!\|r)'
push:
- meta_scope: string.interpolated.single.dart
- match: "'"
pop: true
- include: string-interp
- match: r'
push:
- meta_scope: string.quoted.single.dart
- match: "'"
pop: true
- include: regexp
Submodule assets/syntaxes/Elm added at dfbb8bdc9a
+234
View File
@@ -0,0 +1,234 @@
%YAML 1.2
---
# http://www.sublimetext.com/docs/3/syntax.html
name: "F#"
file_extensions:
- fs
- fsi
- fsx
scope: source.fsharp
contexts:
main:
- include: comments
- include: constants
- include: structure
- include: attributes
- include: strings
- include: definition
- include: method_calls
- include: modules
- include: anonymous_functions
- include: keywords
anonymous_functions:
- match: \b(fun)\b
captures:
1: keyword.other.function-definition.fsharp
push:
- meta_scope: meta.function.anonymous
- match: (->)
captures:
1: keyword.other.fsharp
pop: true
- include: variables
attributes:
- match: '\[\<'
push:
- meta_scope: support.function.attribute.fsharp
- match: '\>\]'
pop: true
- include: main
characters:
- match: (')
captures:
1: punctuation.definition.string.begin.fsharp
push:
- meta_scope: string.quoted.single.fsharp
- match: (')
captures:
1: punctuation.definition.string.end.fsharp
pop: true
- match: '\\$[ \t]*'
scope: punctuation.separator.string.ignore-eol.fsharp
- match: '\\([\\""ntbr]|u[a-fA-F0-9]{4}|u[a-fA-F0-9]{8})'
scope: constant.character.string.escape.fsharp
- match: '\\(?![\\''ntbr]|u[a-fA-F0-9]{4}|u[a-fA-F0-9]{8}).'
scope: invalid.illeagal.character.string.fsharp
comments:
- match: \(\*\*?(\*)\)
scope: comment.block.fsharp
captures:
1: comment.block.empty.fsharp
- match: '\(\*[^\)]'
push:
- meta_scope: comment.block.fsharp
- match: \*\)
pop: true
- include: comments
- match: //.*$
scope: comment.line.double-slash.fsharp
constants:
- match: \(\)
scope: constant.language.unit.fsharp
- match: '\b-?[0-9][0-9_]*((\.([0-9][0-9_]*([eE][+-]??[0-9][0-9_]*)?)?)|([eE][+-]??[0-9][0-9_]*))'
scope: constant.numeric.floating-point.fsharp
- match: '\b(-?((0(x|X)[0-9a-fA-F][0-9a-fA-F_]*)|(0(o|O)[0-7][0-7_]*)|(0(b|B)[01][01_]*)|([0-9][0-9_]*)))'
scope: constant.numeric.integer.nativeint.fsharp
definition:
- match: '\b(val|val|let|and|member|override|use)\s?(rec|inline|mutable)?(\s+\(?([a-zA-Z.\|_][a-zA-Z0-9.|_]*)\)?\w*)\b'
captures:
1: keyword.other.binding.fsharp
2: keyword.other.function-recursive.fsharp
3: variable.other.binding.fsharp
push:
- meta_scope: meta.binding.fsharp
- match: "=|$"
captures:
1: punctuation.separator.function.type-constraint.fsharp
pop: true
- include: variables
- match: \b(let)\s+((\(\))|(_))\s+=
scope: meta.expression.fsharp
captures:
1: keyword.other.binding.fsharp
2: keyword.other.function-recursive.fsharp
4: constant.language.unit.fsharp
5: constant.language.ignored.fsharp
keywords:
- match: ^\s*#\s*(light|if|else|endif|r|I|load|time|help|quit)\b
push:
- meta_scope: meta.preprocessor.fsharp
- match: (\s|$)
pop: true
- match: \b(new|in|as|if|then|else|elif|for|begin|end|match|with|type|inherit|true|false|null|do)\b
scope: keyword.other.fsharp
- match: '(\|>|\|?>|\->|\<\-|:>|:|\[|\]|\;|\||_)'
scope: entity.name
method_calls:
- match: '(?<!\w)([a-z]\w*)(\.)'
push:
- meta_scope: meta.method-call.fsharp
- match: '[A-Z]\w*(\.)'
scope: meta.method.fsharp
captures:
1: punctuation.separator.method-call.fsharp
- match: (?=.)
pop: true
modules:
- match: '\b(namespace|module)\s+([a-zA-Z][a-zA-Z0-9''_.]*)'
captures:
1: keyword.other.fsharp
2: entity.name.section.fsharp
push:
- meta_scope: meta.module.namespace.fsharp
- match: (\s|$)
pop: true
- match: '(\.)([A-Z][a-zA-Z0-9''_]*)'
scope: support.other.module.fsharp
captures:
1: punctuation.separator.module-reference.fsharp
2: support.other.module.fsharp
- match: '\b(open)\s+([A-Z][a-zA-Z0-9''_]*)(?=(\.[A-Z][a-zA-Z0-9_]*)*)'
captures:
1: keyword.other.fsharp
2: support.other.module.fsharp
push:
- meta_scope: meta.module.open.fsharp
- match: (\s|$)
pop: true
- match: '(\.)([A-Z][a-zA-Z0-9''_]*)'
scope: support.other.module.fsharp
captures:
1: punctuation.separator.module-reference.fsharp
2: support.other.module.fsharp
- match: '^\s*(module)\s+([A-Z][a-zA-Z0-9''_]*)\s*(=)\s*([A-Z][a-zA-Z0-9''_]*)'
captures:
1: keyword.other.module-definition.fsharp
2: entity.name.type.module.fsharp
3: punctuation.separator.module-definition.fsharp
4: support.other.module.fsharp
push:
- meta_scope: meta.module.alias.fsharp
- match: (\s|$)
pop: true
- match: '(\.)([A-Z][a-zA-Z0-9''_]*)'
scope: support.other.module.fsharp
captures:
1: punctuation.separator.module-reference.fsharp
2: support.other.module.fsharp
- match: '(?<!\w)([A-Z][a-zA-Z0-9_]*)(\.)'
captures:
1: support.other.module.fsharp
2: punctuation.separator.module-reference.fsharp
push:
- meta_scope: meta.module.reference.fsharp
- match: '[A-Z][a-zA-Z0-9_]+(\.)'
scope: support.other.module.fsharp
captures:
1: punctuation.separator.module-reference.fsharp
- match: (?=.)
pop: true
strings:
- match: '(?=[^\\])(""")'
captures:
1: punctuation.definition.string.begin.fsharp
push:
- meta_scope: string.quoted.double.fsharp
- match: (""")
captures:
1: punctuation.definition.string.end.fsharp
pop: true
- match: '\\$[ \t]*'
scope: punctuation.separator.string.ignore-eol.fsharp
- match: '(?=[^\\])(@")'
captures:
1: punctuation.definition.string.begin.fsharp
push:
- meta_scope: string.quoted.double.fsharp
- match: (")
captures:
1: punctuation.definition.string.end.fsharp
pop: true
- match: '\\$[ \t]*'
scope: punctuation.separator.string.ignore-eol.fsharp
- match: '(?=[^\\])(")'
captures:
1: punctuation.definition.string.begin.fsharp
push:
- meta_scope: string.quoted.double.fsharp
- match: (")
captures:
1: punctuation.definition.string.end.fsharp
pop: true
- match: '\\$[ \t]*'
scope: punctuation.separator.string.ignore-eol.fsharp
- match: '\\([\\''ntbr]|u[a-fA-F0-9]{4}|u[a-fA-F0-9]{8})'
scope: constant.character.string.escape.fsharp
- match: '\\(?![\\''ntbr]|u[a-fA-F0-9]{4}|u[a-fA-F0-9]{8}).'
scope: invalid.illeagal.character.string.fsharp
- match: '(?=[^\\])('')'
captures:
1: punctuation.definition.string.begin.fsharp
push:
- meta_scope: string.quoted.double.fsharp
- match: (')
captures:
1: punctuation.definition.string.end.fsharp
pop: true
- match: '\\$[ \t]*'
scope: punctuation.separator.string.ignore-eol.fsharp
- match: '\\([\\"ntbr]|u[a-fA-F0-9]{4}|u[a-fA-F0-9]{8})'
scope: constant.character.string.escape.fsharp
- match: '\\(?![\\"ntbr]|u[a-fA-F0-9]{4}|u[a-fA-F0-9]{8}).'
scope: invalid.illeagal.character.string.fsharp
structure:
- match: \(
push:
- meta_scope: meta.paren-group.fsharp
- match: \)
pop: true
- include: main
variables:
- match: \(\)
scope: variable.parameter.unit.fsharp
- match: '[a-zA-Z]\w*'
scope: variable.parameter.fsharp
Submodule assets/syntaxes/INI added at 8dd3e316ad
+45
View File
@@ -0,0 +1,45 @@
%YAML 1.2
---
# http://www.sublimetext.com/docs/3/syntax.html
name: INI
file_extensions:
- ini
- INI
- inf
- INF
- reg
- REG
- lng
- cfg
- CFG
- url
- URL
- .editorconfig
- .hgrc
- hgrc
scope: source.ini
contexts:
main:
- match: ^\s*(;|#).*$\n?
scope: comment.line.semicolon.ini
captures:
1: punctuation.definition.comment.ini
- match: '^\s*(\[)(.*?)(\])'
scope: meta.tag.section.ini
captures:
1: punctuation.definition.section.ini
2: entity.section.ini
3: punctuation.definition.section.ini
- match: '^(\s*(["'']?)(.+?)(\2)\s*(=))?\s*((["'']?)(.*?)(\7))\s*(;.*)?$\n?'
scope: meta.declaration.ini
captures:
1: meta.property.ini
2: punctuation.definition.quote.ini
3: keyword.name.ini
4: punctuation.definition.quote.ini
5: punctuation.definition.equals.ini
6: meta.value.ini
7: punctuation.definition.quote.ini
8: string.name.value.ini
9: punctuation.definition.quote.ini
10: comment.declarationline.semicolon.ini
File diff suppressed because it is too large Load Diff
+398
View File
@@ -0,0 +1,398 @@
%YAML 1.2
---
# http://www.sublimetext.com/docs/3/syntax.html
name: Kotlin
file_extensions:
- kt
- kts
scope: source.Kotlin
contexts:
main:
- include: comments
- match: '^\s*(package)\b(?:\s*([^ ;$]+)\s*)?'
captures:
1: keyword.other.kotlin
2: entity.name.package.kotlin
- include: imports
- include: statements
classes:
- match: (?<!::)(?=\b(?:companion|class|object|interface)\b)
push:
- match: '(?=$|\})'
pop: true
- include: comments
- match: \b(companion\s*)?(class|object|interface)\b
captures:
1: storage.modifier.kotlin
2: storage.modifier.kotlin
push:
- match: '(?=<|\{|\(|:|$)'
pop: true
- include: comments
- match: \w+
scope: entity.name.type.class.kotlin
- match: <
push:
- match: ">"
pop: true
- include: generics
- match: \(
push:
- match: \)
pop: true
- include: parameters
- match: (:)
captures:
1: keyword.operator.declaration.kotlin
push:
- match: "(?={|$)"
pop: true
- match: \w+
scope: entity.other.inherited-class.kotlin
- match: \(
push:
- match: \)
pop: true
- include: expressions
- match: '\{'
push:
- match: '\}'
pop: true
- include: statements
comments:
- match: /\*
captures:
0: punctuation.definition.comment.kotlin
push:
- meta_scope: comment.block.kotlin
- match: \*/
captures:
0: punctuation.definition.comment.kotlin
pop: true
- match: \s*((//).*$\n?)
captures:
1: comment.line.double-slash.kotlin
2: punctuation.definition.comment.kotlin
constants:
- match: \b(true|false|null|this|super)\b
scope: constant.language.kotlin
- match: '\b((0(x|X)[0-9a-fA-F]*)|(([0-9]+\.?[0-9]*)|(\.[0-9]+))((e|E)(\+|-)?[0-9]+)?)([LlFf])?\b'
scope: constant.numeric.kotlin
- match: '\b([A-Z][A-Z0-9_]+)\b'
scope: constant.other.kotlin
expressions:
- match: \(
push:
- match: \)
pop: true
- include: expressions
- include: types
- include: strings
- include: constants
- include: comments
- include: keywords
functions:
- match: (?=\s*\b(?:fun)\b)
push:
- match: '(?=$|\})'
pop: true
- match: \b(fun)\b
captures:
1: keyword.other.kotlin
push:
- match: (?=\()
pop: true
- match: <
push:
- match: ">"
pop: true
- include: generics
- match: '([\.<\?>\w]+\.)?(\w+)'
captures:
2: entity.name.function.kotlin
- match: \(
push:
- match: \)
pop: true
- include: parameters
- match: (:)
captures:
1: keyword.operator.declaration.kotlin
push:
- match: "(?={|=|$)"
pop: true
- include: types
- match: '\{'
push:
- match: '(?=\})'
pop: true
- include: statements
- match: (=)
captures:
1: keyword.operator.assignment.kotlin
push:
- match: (?=$)
pop: true
- include: expressions
generics:
- match: (:)
captures:
1: keyword.operator.declaration.kotlin
push:
- match: (?=,|>)
pop: true
- include: types
- include: keywords
- match: \w+
scope: storage.type.generic.kotlin
getters-and-setters:
- match: \b(get)\b\s*\(\s*\)
captures:
1: entity.name.function.kotlin
push:
- match: '\}|(?=\bset\b)|$'
pop: true
- match: (=)
captures:
1: keyword.operator.assignment.kotlin
push:
- match: (?=$|\bset\b)
pop: true
- include: expressions
- match: '\{'
push:
- match: '\}'
pop: true
- include: expressions
- match: \b(set)\b\s*(?=\()
captures:
1: entity.name.function.kotlin
push:
- match: '\}|(?=\bget\b)|$'
pop: true
- match: \(
push:
- match: \)
pop: true
- include: parameters
- match: (=)
captures:
1: keyword.operator.assignment.kotlin
push:
- match: (?=$|\bset\b)
pop: true
- include: expressions
- match: '\{'
push:
- match: '\}'
pop: true
- include: expressions
imports:
- match: '^\s*(import)\s+[^ $]+\s+(as)?'
captures:
1: keyword.other.kotlin
2: keyword.other.kotlin
keywords:
- match: \b(var|val|public|private|protected|abstract|final|sealed|enum|open|attribute|annotation|override|inline|vararg|in|out|internal|data|tailrec|operator|infix|const|yield|typealias|typeof|reified|suspend)\b
scope: storage.modifier.kotlin
- match: \b(try|catch|finally|throw)\b
scope: keyword.control.catch-exception.kotlin
- match: \b(if|else|while|for|do|return|when|where|break|continue)\b
scope: keyword.control.kotlin
- match: \b(in|is|!in|!is|as|as\?|assert)\b
scope: keyword.operator.kotlin
- match: (==|!=|===|!==|<=|>=|<|>)
scope: keyword.operator.comparison.kotlin
- match: (=)
scope: keyword.operator.assignment.kotlin
- match: (::)
scope: keyword.operator.kotlin
- match: (:)
scope: keyword.operator.declaration.kotlin
- match: \b(by)\b
scope: keyword.other.by.kotlin
- match: (\?\.)
scope: keyword.operator.safenav.kotlin
- match: (\.)
scope: keyword.operator.dot.kotlin
- match: (\?:)
scope: keyword.operator.elvis.kotlin
- match: (\-\-|\+\+)
scope: keyword.operator.increment-decrement.kotlin
- match: (\+=|\-=|\*=|\/=)
scope: keyword.operator.arithmetic.assign.kotlin
- match: (\.\.)
scope: keyword.operator.range.kotlin
- match: (\-|\+|\*|\/|%)
scope: keyword.operator.arithmetic.kotlin
- match: (!|&&|\|\|)
scope: keyword.operator.logical.kotlin
- match: (;)
scope: punctuation.terminator.kotlin
namespaces:
- match: \b(namespace)\b
scope: keyword.other.kotlin
- match: '\{'
push:
- match: '\}'
pop: true
- include: statements
parameters:
- match: (:)
captures:
1: keyword.operator.declaration.kotlin
push:
- match: (?=,|\)|=)
pop: true
- include: types
- match: (=)
captures:
1: keyword.operator.declaration.kotlin
push:
- match: (?=,|\))
pop: true
- include: expressions
- include: keywords
- match: \w+
scope: variable.parameter.function.kotlin
statements:
- include: namespaces
- include: typedefs
- include: classes
- include: functions
- include: variables
- include: getters-and-setters
- include: expressions
strings:
- match: '"""'
captures:
0: punctuation.definition.string.begin.kotlin
push:
- meta_scope: string.quoted.third.kotlin
- match: '"""'
captures:
0: punctuation.definition.string.end.kotlin
pop: true
- match: '(\$\w+|\$\{[^\}]+\})'
scope: variable.parameter.template.kotlin
- match: \\.
scope: constant.character.escape.kotlin
- match: '"'
captures:
0: punctuation.definition.string.begin.kotlin
push:
- meta_scope: string.quoted.double.kotlin
- match: '"'
captures:
0: punctuation.definition.string.end.kotlin
pop: true
- match: '(\$\w+|\$\{[^\}]+\})'
scope: variable.parameter.template.kotlin
- match: \\.
scope: constant.character.escape.kotlin
- match: "'"
captures:
0: punctuation.definition.string.begin.kotlin
push:
- meta_scope: string.quoted.single.kotlin
- match: "'"
captures:
0: punctuation.definition.string.end.kotlin
pop: true
- match: \\.
scope: constant.character.escape.kotlin
- match: "`"
captures:
0: punctuation.definition.string.begin.kotlin
push:
- meta_scope: string.quoted.single.kotlin
- match: "`"
captures:
0: punctuation.definition.string.end.kotlin
pop: true
typedefs:
- match: (?=\s*(?:type))
push:
- match: (?=$)
pop: true
- match: \b(type)\b
scope: keyword.other.kotlin
- match: <
push:
- match: ">"
pop: true
- include: generics
- include: expressions
types:
- match: \b(Nothing|Any|Unit|String|CharSequence|Int|Boolean|Char|Long|Double|Float|Short|Byte|dynamic)\b
scope: storage.type.buildin.kotlin
- match: \b(IntArray|BooleanArray|CharArray|LongArray|DoubleArray|FloatArray|ShortArray|ByteArray)\b
scope: storage.type.buildin.array.kotlin
- match: \b(Array|Collection|List|Map|Set|MutableList|MutableMap|MutableSet|Sequence)<\b
captures:
1: storage.type.buildin.collection.kotlin
push:
- match: ">"
pop: true
- include: types
- include: keywords
- match: \w+<
push:
- match: ">"
pop: true
- include: types
- include: keywords
- match: '\{'
push:
- match: '\}'
pop: true
- include: statements
- match: \(
push:
- match: \)
pop: true
- include: types
- match: (->)
scope: keyword.operator.declaration.kotlin
variables:
- match: (?=\s*\b(?:var|val)\b)
push:
- match: (?=:|=|(\b(by)\b)|$)
pop: true
- match: \b(var|val)\b
captures:
1: keyword.other.kotlin
push:
- match: (?=:|=|(\b(by)\b)|$)
pop: true
- match: <
push:
- match: ">"
pop: true
- include: generics
- match: '([\.<\?>\w]+\.)?(\w+)'
captures:
2: entity.name.variable.kotlin
- match: (:)
captures:
1: keyword.operator.declaration.kotlin
push:
- match: (?==|$)
pop: true
- include: types
- include: getters-and-setters
- match: \b(by)\b
captures:
1: keyword.other.kotlin
push:
- match: (?=$)
pop: true
- include: expressions
- match: (=)
captures:
1: keyword.operator.assignment.kotlin
push:
- match: (?=$)
pop: true
- include: expressions
- include: getters-and-setters
Submodule assets/syntaxes/Nix added at ebf06571f3
+609
View File
@@ -0,0 +1,609 @@
%YAML 1.2
---
# http://www.sublimetext.com/docs/3/syntax.html
name: Nix
file_extensions:
- nix
scope: source.nix
contexts:
main:
- include: expression
comment:
- match: '/\*([^*]|\*[^\/])*'
push:
- meta_scope: comment.block.nix
- match: \*\/
pop: true
- include: comment-remark
- match: '\#'
push:
- meta_scope: comment.line.number-sign.nix
- match: $
pop: true
- include: comment-remark
attribute-bind:
- include: attribute-name
- include: attribute-bind-from-equals
attribute-bind-from-equals:
- match: \=
captures:
0: keyword.operator.bind.nix
push:
- match: \;
captures:
0: punctuation.terminator.bind.nix
pop: true
- include: expression
attribute-inherit:
- match: \binherit\b
captures:
0: keyword.other.inherit.nix
push:
- match: \;
captures:
0: punctuation.terminator.inherit.nix
pop: true
- match: \(
captures:
0: punctuation.section.function.arguments.nix
push:
- match: (?=\;)
pop: true
- match: \)
captures:
0: punctuation.section.function.arguments.nix
push:
- match: (?=\;)
pop: true
- include: bad-reserved
- include: attribute-name-single
- include: others
- include: expression
- match: '(?=[a-zA-Z\_])'
push:
- match: (?=\;)
pop: true
- include: bad-reserved
- include: attribute-name-single
- include: others
- include: others
attribute-name:
- match: '\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*'
scope: entity.other.attribute-name.multipart.nix
- match: \.
- include: string-quoted
- include: interpolation
attribute-name-single:
- match: '\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*'
scope: entity.other.attribute-name.single.nix
attrset-contents:
- include: attribute-inherit
- include: bad-reserved
- include: attribute-bind
- include: others
attrset-definition:
- match: '(?=\{)'
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- match: '(\{)'
captures:
0: punctuation.definition.attrset.nix
push:
- match: '(\})'
captures:
0: punctuation.definition.attrset.nix
pop: true
- include: attrset-contents
- match: '(?<=\})'
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: expression-cont
attrset-definition-brace-opened:
- match: '(?<=\})'
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: expression-cont
- match: (?=.?)
push:
- match: '\}'
captures:
0: punctuation.definition.attrset.nix
pop: true
- include: attrset-contents
attrset-for-sure:
- match: (?=\brec\b)
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- match: \brec\b
captures:
0: keyword.other.nix
push:
- match: '(?=\{)'
pop: true
- include: others
- include: attrset-definition
- include: others
- match: '(?=\{\s*(\}|[^,?]*(=|;)))'
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: attrset-definition
- include: others
attrset-or-function:
- match: '\{'
captures:
0: punctuation.definition.attrset-or-function.nix
push:
- match: '(?=([\])};]|\b(else|then)\b))'
pop: true
- match: '(?=(\s*\}|\"|\binherit\b|\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*(\s*\.|\s*=[^=])))'
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: attrset-definition-brace-opened
- match: '(?=(\.\.\.|\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*\s*[,?]))'
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: function-definition-brace-opened
- include: bad-reserved
- match: '\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*'
captures:
0: variable.parameter.function.maybe.nix
push:
- match: '(?=([\])};]|\b(else|then)\b))'
pop: true
- match: (?=\.)
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: attrset-definition-brace-opened
- match: \s*(\,)
captures:
1: keyword.operator.nix
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: function-definition-brace-opened
- match: (?=\=)
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: attribute-bind-from-equals
- include: attrset-definition-brace-opened
- match: (?=\?)
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: function-parameter-default
- match: \,
captures:
0: keyword.operator.nix
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: function-definition-brace-opened
- include: others
- include: others
bad-reserved:
- match: '(?<![\w''-])(if|then|else|assert|with|let|in|rec|inherit)(?![\w''-])'
scope: invalid.illegal.reserved.nix
comment-remark:
- match: (TODO|FIXME|BUG|\!\!\!):?
captures:
1: markup.bold.comment.nix
constants:
- match: \b(builtins|true|false|null)\b
captures:
0: constant.language.nix
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: expression-cont
- match: \b(scopedImport|import|isNull|abort|throw|baseNameOf|dirOf|removeAttrs|map|toString|derivationStrict|derivation)\b
captures:
0: support.function.nix
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: expression-cont
- match: '\b[0-9]+\b'
captures:
0: constant.numeric.nix
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: expression-cont
expression:
- include: parens-and-cont
- include: list-and-cont
- include: string
- include: interpolation
- include: with-assert
- include: function-for-sure
- include: attrset-for-sure
- include: attrset-or-function
- include: let
- include: if
- include: operator-unary
- include: constants
- include: bad-reserved
- include: parameter-name-and-cont
- include: others
expression-cont:
- match: (?=.?)
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: parens
- include: list
- include: string
- include: interpolation
- include: function-for-sure
- include: attrset-for-sure
- include: attrset-or-function
- match: '(\bor\b|\.|==|!=|!|\<\=|\<|\>\=|\>|&&|\|\||-\>|//|\?|\+\+|-|\*|/(?=([^*]|$))|\+)'
scope: keyword.operator.nix
- include: constants
- include: bad-reserved
- include: parameter-name
- include: others
function-body:
- match: '(@\s*([a-zA-Z\_][a-zA-Z0-9\_\''\-]*)\s*)?(\:)'
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: expression
function-body-from-colon:
- match: (\:)
captures:
0: punctuation.definition.function.nix
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: expression
function-contents:
- include: bad-reserved
- include: function-parameter
- include: others
function-definition:
- match: (?=.?)
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: function-body-from-colon
- match: (?=.?)
push:
- match: (?=\:)
pop: true
- match: '(\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*)'
captures:
0: variable.parameter.function.4.nix
push:
- match: (?=\:)
pop: true
- match: \@
push:
- match: (?=\:)
pop: true
- include: function-header-until-colon-no-arg
- include: others
- include: others
- match: '(?=\{)'
push:
- match: (?=\:)
pop: true
- include: function-header-until-colon-with-arg
- include: others
function-definition-brace-opened:
- match: (?=.?)
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: function-body-from-colon
- match: (?=.?)
push:
- match: (?=\:)
pop: true
- include: function-header-close-brace-with-arg
- match: (?=.?)
push:
- match: '(?=\})'
pop: true
- include: function-contents
- include: others
function-for-sure:
- match: '(?=(\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*\s*[:@]|\{[^}]*\}\s*:|\{[^#}"''/=]*[,\?]))'
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: function-definition
function-header-close-brace-no-arg:
- match: '\}'
captures:
0: punctuation.definition.entity.function.nix
push:
- match: (?=\:)
pop: true
- include: others
function-header-close-brace-with-arg:
- match: '\}'
captures:
0: punctuation.definition.entity.function.nix
push:
- match: (?=\:)
pop: true
- include: function-header-terminal-arg
- include: others
function-header-open-brace:
- match: '\{'
captures:
0: punctuation.definition.entity.function.2.nix
push:
- match: '(?=\})'
pop: true
- include: function-contents
function-header-terminal-arg:
- match: (?=@)
push:
- match: (?=\:)
pop: true
- match: \@
push:
- match: (?=\:)
pop: true
- match: '(\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*)'
push:
- meta_scope: variable.parameter.function.3.nix
- match: (?=\:)
pop: true
- include: others
- include: others
function-header-until-colon-no-arg:
- match: '(?=\{)'
push:
- match: (?=\:)
pop: true
- include: function-header-open-brace
- include: function-header-close-brace-no-arg
function-header-until-colon-with-arg:
- match: '(?=\{)'
push:
- match: (?=\:)
pop: true
- include: function-header-open-brace
- include: function-header-close-brace-with-arg
function-parameter:
- match: (\.\.\.)
push:
- meta_scope: keyword.operator.nix
- match: '(,|(?=\}))'
pop: true
- include: others
- match: '\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*'
captures:
0: variable.parameter.function.1.nix
push:
- match: '(,|(?=\}))'
captures:
0: keyword.operator.nix
pop: true
- include: whitespace
- include: comment
- include: function-parameter-default
- include: expression
- include: others
function-parameter-default:
- match: \?
captures:
0: keyword.operator.nix
push:
- match: "(?=[,}])"
pop: true
- include: expression
if:
- match: (?=\bif\b)
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- match: \bif\b
captures:
0: keyword.other.nix
push:
- match: \bth(?=en\b)
captures:
0: keyword.other.nix
pop: true
- include: expression
- match: (?<=th)en\b
captures:
0: keyword.other.nix
push:
- match: \bel(?=se\b)
captures:
0: keyword.other.nix
pop: true
- include: expression
- match: (?<=el)se\b
captures:
0: keyword.other.nix
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
captures:
0: keyword.other.nix
pop: true
- include: expression
illegal:
- match: .
scope: invalid.illegal
interpolation:
- match: '\$\{'
captures:
0: punctuation.section.embedded.begin.nix
push:
- meta_scope: markup.italic
- match: '\}'
captures:
0: punctuation.section.embedded.end.nix
pop: true
- include: expression
let:
- match: (?=\blet\b)
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- match: \blet\b
captures:
0: keyword.other.nix
push:
- match: '(?=([\])};,]|\b(in|else|then)\b))'
pop: true
- match: '(?=\{)'
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- match: '\{'
push:
- match: '\}'
pop: true
- include: attrset-contents
- match: '(^|(?<=\}))'
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: expression-cont
- include: others
- include: attrset-contents
- include: others
- match: \bin\b
captures:
0: keyword.other.nix
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: expression
list:
- match: '\['
captures:
0: punctuation.definition.list.nix
push:
- match: '\]'
captures:
0: punctuation.definition.list.nix
pop: true
- include: expression
list-and-cont:
- match: '(?=\[)'
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: list
- include: expression-cont
operator-unary:
- match: (!|-)
scope: keyword.operator.unary.nix
others:
- include: whitespace
- include: comment
- include: illegal
parameter-name:
- match: '\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*'
captures:
0: variable.parameter.name.nix
parameter-name-and-cont:
- match: '\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*'
captures:
0: variable.parameter.name.nix
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: expression-cont
parens:
- match: \(
captures:
0: punctuation.definition.expression.nix
push:
- match: \)
captures:
0: punctuation.definition.expression.nix
pop: true
- include: expression
parens-and-cont:
- match: (?=\()
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: parens
- include: expression-cont
string:
- match: (?=\'\')
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- match: \'\'
captures:
0: punctuation.definition.string.other.start.nix
push:
- meta_scope: string.quoted.other.nix
- match: \'\'(?!\$|\'|\\.)
captures:
0: punctuation.definition.string.other.end.nix
pop: true
- match: \'\'(\$|\'|\\.)
scope: constant.character.escape.nix
- include: interpolation
- include: expression-cont
- match: (?=\")
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: string-quoted
- include: expression-cont
- match: '([a-zA-Z0-9\.\_\-\+]*(\/[a-zA-Z0-9\.\_\-\+]+)+)'
captures:
0: string.unquoted.path.nix
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: expression-cont
- match: '(\<[a-zA-Z0-9\.\_\-\+]+(\/[a-zA-Z0-9\.\_\-\+]+)*\>)'
captures:
0: string.unquoted.spath.nix
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: expression-cont
- match: '([a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\'']+)'
captures:
0: string.unquoted.url.nix
push:
- match: '(?=([\])};,]|\b(else|then)\b))'
pop: true
- include: expression-cont
string-quoted:
- match: \"
captures:
0: punctuation.definition.string.double.start.nix
push:
- meta_scope: string.quoted.double.nix
- match: \"
captures:
0: punctuation.definition.string.double.end.nix
pop: true
- match: \\.
scope: constant.character.escape.nix
- include: interpolation
whitespace:
- match: \s+
with-assert:
- match: '(?<![\w''-])(with|assert)(?![\w''-])'
captures:
0: keyword.other.nix
push:
- match: \;
pop: true
- include: expression
+466
View File
@@ -0,0 +1,466 @@
%YAML 1.2
---
# http://www.sublimetext.com/docs/3/syntax.html
name: PowerShell
file_extensions:
- ps1
- psm1
- psd1
scope: source.powershell
contexts:
main:
- match: "<#"
captures:
0: punctuation.definition.comment.block.begin.powershell
push:
- meta_scope: comment.block.powershell
- match: "#>"
captures:
0: punctuation.definition.comment.block.end.powershell
pop: true
- include: commentEmbeddedDocs
- match: '[2-6]>&1|>>|>|<<|<|>|>\||[1-6]>|[1-6]>>'
scope: keyword.operator.redirection.powershell
- include: commands
- include: commentLine
- include: variable
- include: interpolatedStringContent
- include: function
- include: attribute
- include: UsingDirective
- include: type
- include: hashtable
- include: doubleQuotedString
- include: scriptblock
- include: doubleQuotedStringEscapes
- match: (?<!')'
captures:
0: punctuation.definition.string.begin.powershell
push:
- meta_scope: string.quoted.single.powershell
- match: "'(?!')"
captures:
0: punctuation.definition.string.end.powershell
pop: true
- match: "''"
scope: constant.character.escape.powershell
- match: \@"(?=$)
push:
- meta_scope: string.quoted.double.heredoc.powershell
- match: ^"@
pop: true
- include: variableNoProperty
- include: doubleQuotedStringEscapes
- include: interpolation
- match: \@'(?=$)
push:
- meta_scope: string.quoted.single.heredoc.powershell
- match: ^'@
pop: true
- match: "''"
scope: constant.character.escape.powershell
- include: numericConstant
- match: (@)(\()
captures:
1: keyword.other.array.begin.powershell
2: punctuation.section.group.begin.powershell
push:
- meta_scope: meta.group.array-expression.powershell
- match: \)
captures:
0: punctuation.section.group.end.powershell
pop: true
- include: main
- match: (\$)(\()
comment: "TODO: move to repo; make recursive."
captures:
1: punctuation.definition.variable.powershell
2: punctuation.section.group.begin.powershell
push:
- meta_scope: meta.group.complex.subexpression.powershell
- match: \)
captures:
0: punctuation.section.group.end.powershell
pop: true
- include: main
- match: '(\b(([A-Za-z0-9\-_\.]+)\.(?i:exe|com|cmd|bat))\b)'
scope: support.function.powershell
- match: (?<!\w|-|\.)((?i:begin|break|catch|continue|data|default|define|do|dynamicparam|else|elseif|end|exit|finally|for|from|if|in|inlinescript|parallel|param|process|return|sequence|switch|throw|trap|try|until|var|while)|%|\?)(?!\w)
scope: keyword.control.powershell
- match: '(?<!\w|-|[^\)]\.)((?i:(foreach|where)(?!-object))|%|\?)(?!\w)'
scope: keyword.control.powershell
- match: (?<!\w)(--%)(?!\w)
comment: This should be moved to the repository at some point.
captures:
1: keyword.control.powershell
push:
- match: $
pop: true
- match: .+
scope: string.unquoted.powershell
- match: (?<!\w)((?i:hidden|static))(?!\w)
comment: This should only be relevant inside a class but will require a rework of how classes are matched. This is a temp fix.
scope: storage.modifier.powershell
- match: '(?<!\w|-)((?i:class)|%|\?)(?:\s)+((?:\p{L}|\d|_|-|)+)\b'
comment: capture should be entity.name.type, but it doesn't provide a good color in the default schema.
captures:
1: storage.type.powershell
2: entity.name.function
- match: (?<!\w)-(?i:is(?:not)?|as)\b
scope: keyword.operator.comparison.powershell
- match: '(?<!\w)-(?i:[ic]?(?:eq|ne|[gl][te]|(?:not)?(?:like|match|contains|in)|replace))(?!\p{L})'
scope: keyword.operator.comparison.powershell
- match: '(?<!\w)-(?i:join|split)(?!\p{L})|!'
scope: keyword.operator.unary.powershell
- match: '(?<!\w)-(?i:and|or|not|xor)(?!\p{L})|!'
scope: keyword.operator.logical.powershell
- match: '(?<!\w)-(?i:band|bor|bnot|bxor|shl|shr)(?!\p{L})'
scope: keyword.operator.bitwise.powershell
- match: '(?<!\w)-(?i:f)(?!\p{L})'
scope: keyword.operator.string-format.powershell
- match: "[+%*/-]?=|[+/*%-]"
scope: keyword.operator.assignment.powershell
- match: '\|{2}|&{2}|;'
scope: punctuation.terminator.statement.powershell
- match: '&|(?<!\w)\.(?= )|`|,|\|'
scope: keyword.operator.other.powershell
- match: (?<!\s|^)\.\.(?=\-?\d|\(|\$)
comment: This is very imprecise, is there a syntax for 'must come after...'
scope: keyword.operator.range.powershell
RequiresDirective:
- match: (?<=#)(?i:(requires))\s
captures:
0: keyword.control.requires.powershell
push:
- meta_scope: meta.requires.powershell
- match: $
pop: true
- match: \-(?i:Modules|PSSnapin|RunAsAdministrator|ShellId|Version)
scope: keyword.other.powershell
- match: '(?<!-)\b\p{L}+|\d+(?:\.\d+)*'
scope: variable.parameter.powershell
- include: hashtable
UsingDirective:
- match: (?<!\w)(?i:(using))\s+(?i:(namespace|module))\s+(?i:((?:\w+(?:\.)?)+))
captures:
1: keyword.control.using.powershell
2: keyword.other.powershell
3: variable.parameter.powershell
attribute:
- match: '(\[)\s*\b(?i)(cmdletbinding|alias|outputtype|parameter|validatenotnull|validatenotnullorempty|validatecount|validateset|allownull|allowemptycollection|allowemptystring|validatescript|validaterange|validatepattern|validatelength)\b'
captures:
1: punctuation.section.bracket.begin.powershell
2: support.function.attribute.powershell
push:
- meta_scope: meta.attribute.powershell
- match: '(\])'
captures:
1: punctuation.section.bracket.end.powershell
pop: true
- match: \(
captures:
0: punctuation.section.group.begin.powershell
push:
- match: \)
captures:
0: punctuation.section.group.end.powershell
pop: true
- include: variable
- include: variableNoProperty
- include: hashtable
- include: scriptblock
- include: doubleQuotedStringEscapes
- include: doubleQuotedString
- include: type
- include: numericConstant
- include: doubleQuotedString
- include: main
- match: (?i)\b(mandatory|valuefrompipeline|valuefrompipelinebypropertyname|valuefromremainingarguments|position|parametersetname|defaultparametersetname|supportsshouldprocess|supportspaging|positionalbinding|helpuri|confirmimpact|helpmessage)\b(?:\s+)?(=)?
captures:
1: variable.parameter.attribute.powershell
2: keyword.operator.assignment.powershell
- match: (?<!')'
captures:
0: punctuation.definition.string.begin.powershell
push:
- meta_scope: string.quoted.single.powershell
- match: "'(?!')"
captures:
0: punctuation.definition.string.end.powershell
pop: true
- match: "''"
scope: constant.character.escape.powershell
commands:
- match: '(?:(\p{L}|\d|_|-|\\|\:)*\\)?\b(?i:Add|Approve|Assert|Backup|Block|Build|Checkpoint|Clear|Close|Compare|Complete|Compress|Confirm|Connect|Convert|ConvertFrom|ConvertTo|Copy|Debug|Deny|Deploy|Disable|Disconnect|Dismount|Edit|Enable|Enter|Exit|Expand|Export|Find|Format|Get|Grant|Group|Hide|Import|Initialize|Install|Invoke|Join|Limit|Lock|Measure|Merge|Mount|Move|New|Open|Optimize|Out|Ping|Pop|Protect|Publish|Push|Read|Receive|Redo|Register|Remove|Rename|Repair|Request|Reset|Resize|Resolve|Restart|Restore|Resume|Revoke|Save|Search|Select|Send|Set|Show|Skip|Split|Start|Step|Stop|Submit|Suspend|Switch|Sync|Test|Trace|Unblock|Undo|Uninstall|Unlock|Unprotect|Unpublish|Unregister|Update|Use|Wait|Watch|Write)\-.+?(?:\.(?i:exe|cmd|bat|ps1))?\b'
comment: "Verb-Noun pattern:"
scope: support.function.powershell
- match: (?<!\w)(?i:foreach-object)(?!\w)
comment: Builtin cmdlets with reserved verbs
scope: support.function.powershell
- match: (?<!\w)(?i:where-object)(?!\w)
comment: Builtin cmdlets with reserved verbs
scope: support.function.powershell
- match: (?<!\w)(?i:sort-object)(?!\w)
comment: Builtin cmdlets with reserved verbs
scope: support.function.powershell
- match: (?<!\w)(?i:tee-object)(?!\w)
comment: Builtin cmdlets with reserved verbs
scope: support.function.powershell
commentEmbeddedDocs:
- match: ^(?i:(?:\s?|#)+(\.)(COMPONENT|DESCRIPTION|EXAMPLE|EXTERNALHELP|FORWARDHELPCATEGORY|FORWARDHELPTARGETNAME|FUNCTIONALITY|INPUTS|LINK|NOTES|OUTPUTS|REMOTEHELPRUNSPACE|ROLE|SYNOPSIS))
scope: comment.documentation.embedded.powershell
captures:
1: constant.string.documentation.powershell
2: keyword.operator.documentation.powershell
- match: '(?i:\s?(\.)(PARAMETER|FORWARDHELPTARGETNAME|FORWARDHELPCATEGORY|REMOTEHELPRUNSPACE|EXTERNALHELP)\s+([a-z0-9-_]+))'
scope: comment.documentation.embedded.powershell
captures:
1: constant.string.documentation.powershell
2: keyword.operator.documentation.powershell
3: keyword.operator.documentation.powershell
commentLine:
- match: '(?<![`\\-])#'
captures:
0: punctuation.definition.comment.powershell
push:
- meta_scope: comment.line.powershell
- match: $\n?
captures:
0: punctuation.definition.comment.powershell
pop: true
- include: commentEmbeddedDocs
- include: RequiresDirective
doubleQuotedString:
- match: (?<!(?<!`)")"
captures:
0: punctuation.definition.string.begin.powershell
push:
- meta_scope: string.quoted.double.powershell
- match: '"(?!")'
captures:
0: punctuation.definition.string.end.powershell
pop: true
- match: '(?i)\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,64}\b'
- include: variableNoProperty
- include: variable
- include: doubleQuotedStringEscapes
- include: interpolation
- match: '`\s*$'
scope: keyword.other.powershell
doubleQuotedStringEscapes:
- match: '`[0abnfrvt"''$`]'
scope: constant.character.escape.powershell
- match: '""'
scope: constant.character.escape.powershell
function:
- match: '^(?:\s*+)(?i)(function|filter|configuration|workflow)\s+(?:(global|local|script|private):)?((?:\p{L}|\d|_|-|\.)+)'
captures:
0: meta.function.powershell
1: storage.type.powershell
2: storage.modifier.scope.powershell
3: entity.name.function.powershell
push:
- match: '(?=\{|\()'
pop: true
- include: commentLine
hashtable:
- match: '(@)(\{)'
captures:
1: keyword.other.hashtable.begin.powershell
2: punctuation.section.braces.begin.powershell
push:
- meta_scope: meta.hashtable.powershell
- match: '(\})'
captures:
1: punctuation.section.braces.end.powershell
pop: true
- match: \b((?:\'|\")?)(\w+)((?:\'|\")?)(?:\s+)?(=)(?:\s+)?
scope: meta.hashtable.assignment.powershell
captures:
1: punctuation.definition.string.begin.powershell
2: variable.other.readwrite.powershell
3: punctuation.definition.string.end.powershell
4: keyword.operator.assignment.powershell
- include: scriptblock
- include: main
interpolatedStringContent:
- match: \(
captures:
0: punctuation.section.group.begin.powershell
push:
- meta_content_scope: interpolated.simple.source.powershell
- match: \)
captures:
0: punctuation.section.group.end.powershell
pop: true
- include: main
- include: interpolation
- include: interpolatedStringContent
interpolation:
- match: (\$)(\()
captures:
1: punctuation.definition.variable.powershell
2: punctuation.section.group.begin.powershell
push:
- meta_content_scope: interpolated.complex.source.powershell
- match: \)
captures:
0: punctuation.section.group.end.powershell
pop: true
- include: main
- include: interpolation
- include: interpolatedStringContent
numericConstant:
- match: '(?<!\w)([-+]?0(?:x|X)[0-9a-fA-F_]+(?:U|u|L|l|UL|Ul|uL|ul|LU|Lu|lU|lu)?)((?i:[kmgtp]b)?)\b'
captures:
1: constant.numeric.hex.powershell
2: keyword.other.powershell
- match: '(?<!\w)([-+]?(?:[0-9_]+)?\.[0-9_]+(?:(?:e|E)[0-9]+)?(?:F|f|D|d|M|m)?)((?i:[kmgtp]b)?)\b'
captures:
1: constant.numeric.integer.powershell
2: keyword.other.powershell
- match: '(?<!\w)([-+]?0(?:b|B)[01_]+(?:U|u|L|l|UL|Ul|uL|ul|LU|Lu|lU|lu)?)((?i:[kmgtp]b)?)\b'
captures:
1: constant.numeric.octal.powershell
2: keyword.other.powershell
- match: '(?<!\w)([-+]?[0-9_]+(?:e|E)(?:[0-9_])?+(?:F|f|D|d|M|m)?)((?i:[kmgtp]b)?)\b'
captures:
1: constant.numeric.integer.powershell
2: keyword.other.powershell
- match: '(?<!\w)([-+]?[0-9_]+\.(?:e|E)(?:[0-9_])?+(?:F|f|D|d|M|m)?)((?i:[kmgtp]b)?)\b'
captures:
1: constant.numeric.integer.powershell
2: keyword.other.powershell
- match: '(?<!\w)([-+]?[0-9_]+[\.]?(?:F|f|D|d|M|m))((?i:[kmgtp]b)?)\b'
captures:
1: constant.numeric.integer.powershell
2: keyword.other.powershell
- match: '(?<!\w)([-+]?[0-9_]+[\.]?(?:U|u|L|l|UL|Ul|uL|ul|LU|Lu|lU|lu)?)((?i:[kmgtp]b)?)\b'
captures:
1: constant.numeric.integer.powershell
2: keyword.other.powershell
scriptblock:
- match: '\{'
captures:
0: punctuation.section.braces.begin.powershell
push:
- meta_scope: meta.scriptblock.powershell
- match: '\}'
captures:
0: punctuation.section.braces.end.powershell
pop: true
- include: main
type:
- match: '\['
captures:
0: punctuation.section.bracket.begin.powershell
push:
- match: '\]'
captures:
0: punctuation.section.bracket.end.powershell
pop: true
- match: '(?!\d+|\.)(?:\p{L}|\p{N}|\.)+'
scope: storage.type.powershell
- include: main
variable:
- match: (\$)(?i:(False|Null|True))\b
comment: These are special constants.
captures:
0: constant.language.powershell
1: punctuation.definition.variable.powershell
- match: '(\$)(?i:(Error|ExecutionContext|Host|Home|PID|PsHome|PsVersionTable|ShellID))((?:\.(?:\p{L}|\d|_)+)*\b)?\b'
comment: These are the other built-in constants.
captures:
0: support.constant.variable.powershell
1: punctuation.definition.variable.powershell
3: variable.other.member.powershell
- match: '(\$)(?i:(\$|\^|\?|_|Args|ConsoleFileName|Event|EventArgs|EventSubscriber|ForEach|Input|LastExitCode|Matches|MyInvocation|NestedPromptLevel|Profile|PSBoundParameters|PsCmdlet|PsCulture|PSDebugContext|PSItem|PSCommandPath|PSScriptRoot|PsUICulture|Pwd|Sender|SourceArgs|SourceEventArgs|StackTrace|Switch|This))((?:\.(?:\p{L}|\d|_)+)*\b)?\b'
comment: Automatic variables are not constants, but they are read-only. In monokai (default) color schema support.variable doesn't have color, so we use constant.
captures:
0: support.constant.automatic.powershell
1: punctuation.definition.variable.powershell
3: variable.other.member.powershell
- match: '(\$)(?i:(ConfirmPreference|DebugPreference|ErrorActionPreference|ErrorView|FormatEnumerationLimit|MaximumAliasCount|MaximumDriveCount|MaximumErrorCount|MaximumFunctionCount|MaximumHistoryCount|MaximumVariableCount|OFS|OutputEncoding|ProgressPreference|PsCulture|PSDebugContext|PSDefaultParameterValues|PSEmailServer|PSItem|PSModuleAutoloadingPreference|PSSenderInfo|PSSessionApplicationName|PSSessionConfigurationName|PSSessionOption|VerbosePreference|WarningPreference|WhatIfPreference))((?:\.(?:\p{L}|\d|_)+)*\b)?\b'
comment: Style preference variables as language variables so that they stand out.
captures:
0: variable.language.powershell
1: punctuation.definition.variable.powershell
3: variable.other.member.powershell
- match: '(?i:(\$|@)(global|local|private|script|using|workflow):((?:\p{L}|\d|_)+))((?:\.(?:\p{L}|\d|_)+)*\b)?'
captures:
0: variable.other.readwrite.powershell
1: punctuation.definition.variable.powershell
2: storage.modifier.scope.powershell
4: variable.other.member.powershell
- match: '(?i:(\$)(\{)(global|local|private|script|using|workflow):([^}]*[^}`])(\}))((?:\.(?:\p{L}|\d|_)+)*\b)?'
captures:
0: variable.other.readwrite.powershell
1: punctuation.definition.variable.powershell
2: punctuation.section.braces.begin.powershell
3: storage.modifier.scope.powershell
5: punctuation.section.braces.end.powershell
6: variable.other.member.powershell
- match: '(?i:(\$|@)((?:\p{L}|\d|_)+:)?((?:\p{L}|\d|_)+))((?:\.(?:\p{L}|\d|_)+)*\b)?'
captures:
0: variable.other.readwrite.powershell
1: punctuation.definition.variable.powershell
2: support.variable.drive.powershell
4: variable.other.member.powershell
- match: '(?i:(\$)(\{)((?:\p{L}|\d|_)+:)?([^}]*[^}`])(\}))((?:\.(?:\p{L}|\d|_)+)*\b)?'
captures:
0: variable.other.readwrite.powershell
1: punctuation.definition.variable.powershell
2: punctuation.section.braces.begin.powershell
3: support.variable.drive.powershell
5: punctuation.section.braces.end.powershell
6: variable.other.member.powershell
variableNoProperty:
- match: (\$)(?i:(False|Null|True))\b
comment: These are special constants.
captures:
0: constant.language.powershell
1: punctuation.definition.variable.powershell
- match: (\$)(?i:(Error|ExecutionContext|Host|Home|PID|PsHome|PsVersionTable|ShellID))\b
comment: These are the other built-in constants.
captures:
0: support.constant.variable.powershell
1: punctuation.definition.variable.powershell
3: variable.other.member.powershell
- match: (\$)(?i:(\$|\^|\?|_|Args|ConsoleFileName|Event|EventArgs|EventSubscriber|ForEach|Input|LastExitCode|Matches|MyInvocation|NestedPromptLevel|Profile|PSBoundParameters|PsCmdlet|PsCulture|PSDebugContext|PSItem|PSCommandPath|PSScriptRoot|PsUICulture|Pwd|Sender|SourceArgs|SourceEventArgs|StackTrace|Switch|This))\b
comment: Automatic variables are not constants, but they are read-only...
captures:
0: support.variable.automatic.powershell
1: punctuation.definition.variable.powershell
3: variable.other.member.powershell
- match: (\$)(?i:(ConfirmPreference|DebugPreference|ErrorActionPreference|ErrorView|FormatEnumerationLimit|MaximumAliasCount|MaximumDriveCount|MaximumErrorCount|MaximumFunctionCount|MaximumHistoryCount|MaximumVariableCount|OFS|OutputEncoding|ProgressPreference|PsCulture|PSDebugContext|PSDefaultParameterValues|PSEmailServer|PSItem|PSModuleAutoloadingPreference|PSSenderInfo|PSSessionApplicationName|PSSessionConfigurationName|PSSessionOption|VerbosePreference|WarningPreference|WhatIfPreference))\b
comment: Style preference variables as language variables so that they stand out.
captures:
0: variable.language.powershell
1: punctuation.definition.variable.powershell
3: variable.other.member.powershell
- match: '(?i:(\$|@)(global|local|private|script|using|workflow):((?:\p{L}|\d|_)+))'
captures:
0: variable.other.readwrite.powershell
1: punctuation.definition.variable.powershell
2: storage.modifier.scope.powershell
4: variable.other.member.powershell
- match: '(?i:(\$)(\{)(global|local|private|script|using|workflow):([^}]*[^}`])(\}))'
captures:
0: variable.other.readwrite.powershell
1: punctuation.definition.variable.powershell
2: storage.modifier.scope.powershell
4: keyword.other.powershell
5: variable.other.member.powershell
- match: '(?i:(\$)((?:\p{L}|\d|_)+:)?((?:\p{L}|\d|_)+))'
captures:
0: variable.other.readwrite.powershell
1: punctuation.definition.variable.powershell
2: support.variable.drive.powershell
4: variable.other.member.powershell
- match: '(?i:(\$)(\{)((?:\p{L}|\d|_)+:)?([^}]*[^}`])(\}))'
captures:
0: variable.other.readwrite.powershell
1: punctuation.definition.variable.powershell
2: punctuation.section.braces.begin
3: support.variable.drive.powershell
5: punctuation.section.braces.end
+54
View File
@@ -0,0 +1,54 @@
%YAML 1.2
---
# http://www.sublimetext.com/docs/3/syntax.html
name: Robot Framework syntax highlighting.
file_extensions:
- robot
scope: source.robot
contexts:
main:
- match: '\$\{(\d+|\d+\.\d*|0[bB][01]+|0[oO][0-7]+|0[xX][0-9a-fA-F]+)\}'
comment: "Robot Framework numbers, like ${1} or ${12.3}"
scope: constant.numeric.robot
- match: '(?i)(%\{[\w|\s]+\})'
comment: "Robot Framework environment variable, like %{USER}"
scope: variable.parameter.robot
- match: '((?<!\\)|(?<=\\\\))[$&]{'
comment: Robot Framework scalar and dictionary variables
push:
- meta_scope: entity.name.class
- match: '\}'
pop: true
- match: '((?<!\\)(@{)|(?<=\\\\)(@{))'
comment: Robot Framework list variables
push:
- meta_scope: entity.name.class
- match: '(}\[.+])|(})'
pop: true
- match: '(?i)^(\|\s*)?(\*{1,3} ?)(settings?|variables?|keywords?|test cases?)( ?\*{1,3})?(\s*\|)?'
comment: Robot Framework data tables
scope: string.robot.header
- match: '(?i)(^\|\s*)?\[?Documentation\]?\s+'
comment: Test case, keyword and settings table documentation
push:
- meta_scope: comment
- match: ^(?!\s*+\.\.\.)
pop: true
- match: '(^| {2,}|\t|\\| {1,})(?<!\\\\)#'
comment: Comment character
push:
- meta_scope: comment
- match: $
pop: true
- match: '(?i)\s+\[(Tags|Setup|Teardown|Template|Timeout|Arguments|Return)\]'
comment: Tests case and keyword settings
scope: storage.type
- match: (?i)^(\|\s*)?(Library|Resource|Test Timeout|Test Template|Test Teardown|Test Setup|Default Tags|Force Tags|Metadata|Variables|Suite Setup|Suite Teardown)(?:( )|( \| ))
comment: Settings table settings, like Library
scope: constant.language
- match: '^(\|\s+)?(?!^\.{3})(?![\|$&])\S+'
comment: Keywords and test cases
push:
- meta_scope: keyword.control.robot
- match: '($|\||\s{2,})'
pop: true
+371
View File
@@ -0,0 +1,371 @@
%YAML 1.2
---
# http://www.sublimetext.com/docs/3/syntax.html
name: Swift
file_extensions:
- swift
first_line_match: ^#!/.*\bswift
scope: source.swift
contexts:
main:
- include: shebang-line
- include: comment
- include: attribute
- include: literal
- include: operator
- include: declaration
- include: storage-type
- include: keyword
- include: type
- include: boolean
comment:
- include: documentation-comment
- include: block-comment
- include: in-line-comment
access-level-modifier:
- match: \b(open|public|internal|fileprivate|private)\b(?:\(set\))?
comment: access-level-modifier
scope: keyword.other.access-level-modifier.swift
arithmetic-operator:
- match: '(?<![/=\-+!*%<>&|\^~.])(\+|\-|\*|\/)(?![/=\-+!*%<>&|\^~.])'
scope: keyword.operator.arithmetic.swift
array-type:
- match: \b(Array)(<)
captures:
1: support.type.array.swift
2: punctuation.array.begin.swift
push:
- meta_scope: meta.array.swift
- match: (>)
captures:
1: punctuation.array.end.swift
pop: true
- include: main
assignment-operator:
- match: '(?<![/=\-+!*%<>&|\^~.])(\+|\-|\*|\/|%|<<|>>|&|\^|\||&&|\|\|)?=(?![/=\-+!*%<>&|\^~.])'
scope: keyword.operator.assignment.swift
attribute:
- match: '((@)(\B\$[0-9]+|\b[\w^\d][\w\d]*\b|\B`[\w^\d][\w\d]*`\B))(\()'
captures:
1: storage.modifier.attribute.swift
2: punctuation.definition.attribute.swift
3: punctuation.definition.attribute-arguments.begin.swift
push:
- meta_content_scope: meta.attribute.arguments.swift
- match: \)
captures:
0: punctuation.definition.attribute-arguments.end.swift
pop: true
- include: main
- match: '((@)(\B\$[0-9]+|\b[\w^\d][\w\d]*\b|\B`[\w^\d][\w\d]*`\B))'
captures:
1: storage.modifier.attribute.swift
2: punctuation.definition.attribute.swift
bitwise-operator:
- match: '(?<![/=\-+!*%<>&|\^~.])(&|\||\^|<<|>>)(?![/=\-+!*%<>&|\^~.])'
scope: keyword.operator.bitwise.swift
block-comment:
- match: /\*
comment: Block comment
captures:
0: punctuation.definition.comment.block.begin.swift
push:
- meta_scope: comment.block.swift
- match: \*/
captures:
0: punctuation.definition.comment.block.end.swift
pop: true
boolean:
- match: \b(true|false)\b
scope: keyword.constant.boolean.swift
branch-statement-keyword:
- include: if-statement-keyword
- include: switch-statement-keyword
catch-statement-keyword:
- match: \b(catch|do)\b
comment: catch-statement
scope: kewyord.control.catch.swift
code-block:
- match: '(\{)'
comment: code-block
captures:
1: punctuation.definition.code-block.begin.swift
push:
- match: '(\})'
captures:
1: punctuation.definition.code-block.end.swift
pop: true
- include: main
collection-type:
- include: array-type
- include: dictionary-type
- match: \b(Array|Dictionary)\b
scope: support.type.swift
comparative-operator:
- match: '(?<![/=\-+!*%<>&|\^~.])((=|!)==?|(<|>)=?|~=)(?![/=\-+!*%<>&|\^~.])'
scope: keyword.operator.comparative.swift
control-transfer-statement-keyword:
- match: \b(continue|break|fallthrough|return)\b
comment: control-transfer-statement
scope: keyword.control.transfer.swift
custom-operator:
- match: '(?<=[\s(\[{,;:])([/=\-+!*%<>&|\^~.]++)(?![\s)\]},;:])'
scope: keyword.operator.custom.prefix.unary.swift
- match: '(?<![\s(\[{,;:])([/=\-+!*%<>&|\^~.]++)(?![\s)\]},;:\.])'
scope: keyword.operator.custom.postfix.unary.swift
- match: '(?<=[\s(\[{,;:])([/=\-+!*%<>&|\^~.]++)(?=[\s)\]},;:])'
scope: keyword.operator.custom.binary.swift
declaration:
- include: import-declaration
- include: function-declaration
declaration-modifier:
- match: \b(class|convenience|dynamic|final|lazy|(non)?mutating|optional|override|required|static|unowned((un)?safe)?|weak)\b
comment: declaration-modifier
scope: keyword.other.declaration-modifier.swift
dictionary-type:
- match: \b(Dictionary)(<)
captures:
1: support.type.dictionary.swift
2: punctuation.dictionary.begin.swift
push:
- meta_scope: meta.dictionary.swift
- match: (>)
captures:
1: punctuation.dictionary.end.swift
pop: true
- include: main
documentation-comment:
- match: /\*\*
comment: Documentation comment
captures:
0: punctuation.definition.comment.block.documentation.begin.swift
push:
- meta_scope: comment.block.documentation.swift
- match: \*/
captures:
0: punctuation.definition.comment.block.documentation.end.swift
pop: true
floating-point-literal:
- match: '\b([0-9][0-9_]*)(\.([0-9][0-9_]*))?([eE][+\-]?([0-9][0-9_]*))?\b'
comment: floating-point-literal -> (decimal-literal)(decimal-fraction)?(decimal-exponent)?
- match: '\b(0x\h[\h_]*)(\.(0x\h[\h_]*))?([pP][+\-]?(0x\h[\h_]*))\b'
comment: floating-point-literal -> (hexadecimal-literal)(hexadecimal-fraction)?(hexadecimal-exponent)
function-body:
- include: code-block
function-declaration:
- match: '\b(func)\s+(\B\$[0-9]+|\b[\w^\d][\w\d]*\b|\B`[\w^\d][\w\d]*`\B|[/=\-+!*%<>&|\^~.]+)\s*(?=\(|<)'
comment: function-declaration
captures:
1: storage.type.function.swift
2: entity.type.function.swift
push:
- meta_scope: meta.function-declaration.swift
- match: '(?<=\})'
pop: true
- include: generic-parameter-clause
- include: parameter-clause
- include: function-result
- include: function-body
function-result:
- match: '(?<![/=\-+!*%<>&|\^~.])(\->)(?![/=\-+!*%<>&|\^~.])\s*'
comment: function-result
captures:
1: keyword.operator.function-result.swift
push:
- meta_scope: meta.function-result.swift
- match: '\s*(?=\{)'
pop: true
- include: type
generic-parameter-clause:
- match: (<)
comment: generic-parameter-clause
captures:
1: punctuation.definition.generic-parameter-clause.begin.swift
push:
- meta_scope: meta.generic-parameter-clause.swift
- match: (>)
captures:
1: punctuation.definition.generic-parameter-clause.end.swift
pop: true
- include: main
identifier:
- match: '(\B\$[0-9]+|\b[\w^\d][\w\d]*\b|\B`[\w^\d][\w\d]*`\B)'
comment: identifier
scope: meta.identifier.swift
if-statement-keyword:
- match: \b(if|else)\b
comment: if-statement
scope: keyword.control.if.swift
import-declaration:
- match: '\b(import)\s+(?:(typealias|struct|class|enum|protocol|var|func)\s+)?((?:\B\$[0-9]+|\b[\w^\d][\w\d]*\b|\B`[\w^\d][\w\d]*`\B|[/=\-+!*%<>&|\^~.]+)(?:\.(?:\B\$[0-9]+|\b[\w^\d][\w\d]*\b|\B`[\w^\d][\w\d]*`\B|[/=\-+!*%<>&|\^~.]+))*)'
comment: import-declaration
scope: meta.import.swift
captures:
1: keyword.other.import.swift
2: storage.modifier.swift
3: support.type.module.import.swift
in-line-comment:
- match: (//).*
comment: In-line comment
scope: comment.line.double-slash.swift
captures:
1: punctuation.definition.comment.line.double-slash.swift
increment-decrement-operator:
- match: '(?<![/=\-+!*%<>&|\^~.])(\+\+|\-\-)(?![/=\-+!*%<>&|\^~.])'
scope: keyword.operator.increment-or-decrement.swift
integer-literal:
- match: '(\B\-|\b)(0b[01][01_]*)\b'
comment: binary-literal
scope: constant.numeric.integer.binary.swift
- match: '(\B\-|\b)(0o[0-7][0-7_]*)\b'
comment: octal-literal
scope: constant.numeric.integer.octal.swift
- match: '(\B\-|\b)([0-9][0-9_]*)\b'
comment: decimal-literal
scope: constant.numeric.integer.decimal.swift
- match: '(\B\-|\b)(0x\h[\h_]*)\b'
comment: hexadecimal-literal
scope: constant.numeric.integer.hexadecimal.swift
integer-type:
- match: \bU?Int(8|16|32|64)?\b
comment: Int types
scope: support.type.swift
keyword:
- include: branch-statement-keyword
- include: control-transfer-statement-keyword
- include: loop-statement-keyword
- include: catch-statement-keyword
- include: operator-declaration-modifier
- include: declaration-modifier
- include: access-level-modifier
- match: \b(class|deinit|enum|extension|func|import|init|let|protocol|static|struct|subscript|typealias|var|throws|rethrows)\b
comment: declaration keyword
scope: keyword.declaration.swift
- match: \b(break|case|continue|default|do|else|fallthrough|if|in|for|return|switch|where|while|repeat|catch|guard|defer|try|throw)\b
comment: statement keyword
scope: keyword.statement.swift
- match: \b(as|dynamicType|is|new|super|self|Self|Type)\b
comment: expression and type keyword
scope: keyword.other.statement.swift
- match: \b(associativity|didSet|get|infix|inout|left|mutating|none|nonmutating|operator|override|postfix|precedence|prefix|right|set|unowned((un)?safe)?|weak|willSet)\b
comment: other keyword
scope: keyword.other.swift
literal:
- include: integer-literal
- include: floating-point-literal
- include: nil-literal
- include: string-literal
- include: special-literal
logical-operator:
- match: '(?<![/=\-+!*%<>&|\^~.])(!|&&|\|\|)(?![/=\-+!*%<>&|\^~.])'
scope: keyword.operator.logical.swift
loop-statement-keyword:
- match: \b(while|repeat|for|in)\b
comment: loop-statement
scope: keyword.control.loop.swift
nil-literal:
- match: \bnil\b
comment: nil-literal
scope: constant.nil.swift
operator:
- include: comparative-operator
- include: assignment-operator
- include: logical-operator
- include: remainder-operator
- include: increment-decrement-operator
- include: overflow-operator
- include: range-operator
- include: bitwise-operator
- include: arithmetic-operator
- include: ternary-operator
- include: type-casting-operator
- include: custom-operator
operator-declaration-modifier:
- match: \b(operator|prefix|infix|postfix)\b
comment: operator-declaration
scope: keyword.other.operator.swift
optional-type:
- match: \b(Optional)(<)
scope: meta.optional.swift
overflow-operator:
- match: '(?<![/=\-+!*%<>&|\^~.])\&(\+|\-|\*|\/|%)(?![/=\-+!*%<>&|\^~.])'
scope: keyword.operator.overflow.swift
parameter-clause:
- match: (\()
comment: parameter-clause
captures:
1: punctuation.definition.function-arguments.begin.swift
push:
- meta_scope: meta.parameter-clause.swift
- match: (\))
captures:
1: punctuation.definition.function-arguments.end.swift
pop: true
- include: main
primitive-type:
- match: \b(Int|Float|Double|String|Bool|Character|Void)\b
comment: Primitive types
scope: support.type.swift
protocol-composition-type:
- match: \b(protocol)(<)
scope: meta.protocol.swift
range-operator:
- match: '(?<![/=\-+!*%<>&|\^~.])\.\.(?:\.)?(?![/=\-+!*%<>&|\^~.])'
scope: keyword.operator.range.swift
remainder-operator:
- match: '(?<![/=\-+!*%<>&|\^~.])\%(?![/=\-+!*%<>&|\^~.])'
scope: keyword.operator.remainder.swift
shebang-line:
- match: ^(#!).*$
comment: Shebang line
scope: comment.line.shebang.swift
captures:
1: punctuation.definition.comment.line.shebang.swift
special-literal:
- match: \b__(FILE|LINE|COLUMN|FUNCTION)__\b
scope: keyword.other.literal.swift
storage-type:
- match: \b(var|func|let|class|enum|struct|protocol|extension|typealias)\b
scope: storage.type.swift
string-literal:
- match: \"
captures:
0: string.quoted.double.swift
push:
- meta_scope: meta.literal.string.swift
- match: \"
captures:
0: string.quoted.double.swift
pop: true
- match: '\\([0tnr\"\''\\]|x\h{2}|u\h{4}|U\h{8})'
scope: constant.character.escape.swift
- match: (\\\()
captures:
1: support.punctuation.expression.begin.swift
push:
- meta_content_scope: meta.expression.swift
- match: (\))
captures:
1: support.punctuation.expression.end.swift
pop: true
- include: scope:source.swift
- match: (\"|\\)
scope: invalid.illegal.swift
- match: (.)
scope: string.quoted.double.swift
switch-statement-keyword:
- match: \b(switch|case|default|where)\b
comment: switch-statement
scope: keyword.control.switch.swift
ternary-operator:
- match: '(?<=[\s(\[{,;:])(\?|:)(?=[\s)\]},;:])'
scope: keyword.operator.ternary.swift
type:
- include: primitive-type
- include: integer-type
- include: collection-type
- include: optional-type
- include: protocol-composition-type
type-casting-operator:
- match: \b(is\b|as(\?\B|\b))
scope: keyword.operator.type-casting.swift
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+91
View File
@@ -0,0 +1,91 @@
%YAML 1.2
---
# http://www.sublimetext.com/docs/3/syntax.html
name: VimL
file_extensions:
- vim
- .vimrc
scope: source.viml
contexts:
main:
- include: comment
- include: string_quoted_double
- include: string_quoted_single
- include: string_regex
- include: inline_comment
- include: number_int
- include: number_hex
- include: keyword
- include: support_function
- include: support_variable
- include: support_type
- include: function_params
- include: function_definition
- include: function_call
- include: function
- include: variable
- include: expr
comment:
- match: ^\s*".*$
scope: comment.line.quotes.viml
captures:
1: punctuation.definition.comment.vim
expr:
- match: (\|\||&&|==(\?|#)?|(!|>|<)=(#|\?)?|(=|!)~(#|\?)?|(>|<)(#|\?)is|isnot|\.|\*|\\|%)
scope: storage.function.viml
function:
- match: \b(fu(n|nction)?|end(f|fu|fun|function)?)\b
scope: storage.function.viml
function_call:
- match: '(([sgbwtl]|)?:?[0-9a-zA-Z_#]+)(?=\()'
scope: support.function.any-method
function_definition:
- match: '^\s*(function)\s*!?\s+(?=(s:)?[0-9a-zA-Z_#]+\s*\()'
captures:
1: storage.function.viml
push:
- meta_scope: meta.function.viml
- match: (\()
captures:
1: punctuation.definition.parameters.begin.viml
pop: true
- match: "(s:)?[0-9a-zA-Z_#]+"
scope: entity.name.function.viml
function_params:
- match: '-\w+='
scope: support.type.viml
inline_comment:
- match: '(?!\$)(")(?!\{).*$\n?'
scope: comment.line.quotes.viml
captures:
1: punctuation.definition.comment.vim
keyword:
- match: \b(if|while|for|try|return|throw|end(if|for|while|try)?|au(g|group)|else(if|)?|do|in|catch|finally|:)\b
scope: keyword.control.viml
number_hex:
- match: "0x[0-9a-f]+"
scope: constant.numeric.hex
number_int:
- match: '-?\d+'
scope: constant.numeric.integer
string_quoted_double:
- match: '"(\\\\|\\"|\n[^\S\n]*\\|[^\n"])*"'
scope: string.quoted.double.viml
string_quoted_single:
- match: '''(''''|\n[^\S\n]*\\|[^\n''])*'''
scope: string.quoted.single.viml
string_regex:
- match: '/(\\\\|\\/|\n[^\S\n]*\\|[^\n/])*/'
scope: string.regexp.viml
support_function:
- match: \b(set(local|global)?|let|command|filetype|colorscheme|\w*map|\w*a(b|brev)?|syn|exe(c|cute)?|ec(ho|)?|au(tocmd|)?)\b
scope: support.function.viml
support_type:
- match: <.*?>
scope: support.type.viml
support_variable:
- match: '\b(am(enu|)?|(hl|inc)?search|[Bb]uf([Nn]ew[Ff]ile|[Rr]ead)?|[Ff]ile[Tt]ype)\b'
scope: support.variable.viml
variable:
- match: '([sSgGbBwWlLaAvV]:|@|$|&(?!&))\w*'
scope: variable.other.viml
+5
View File
@@ -0,0 +1,5 @@
// Output the square of a number.
fn print_square(num: f64) {
let result = f64::powf(num, 2.0);
println!("The square of {:.2} is {:.2}.", num, result);
}
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+26
View File
@@ -0,0 +1,26 @@
#[macro_use]
extern crate clap;
use clap::Shell;
use std::fs;
include!("src/clap_app.rs");
const BIN_NAME: &str = "bat";
fn main() {
let outdir = std::env::var_os("SHELL_COMPLETIONS_DIR").or(std::env::var_os("OUT_DIR"));
let outdir = match outdir {
None => return,
Some(outdir) => outdir,
};
fs::create_dir_all(&outdir).unwrap();
let mut app = build_app(true);
app.gen_completions(BIN_NAME, Shell::Bash, &outdir);
app.gen_completions(BIN_NAME, Shell::Fish, &outdir);
app.gen_completions(BIN_NAME, Shell::Zsh, &outdir);
app.gen_completions(BIN_NAME, Shell::PowerShell, &outdir);
}
+37 -5
View File
@@ -11,23 +11,39 @@ pack() {
local tempdir local tempdir
local out_dir local out_dir
local package_name local package_name
local gcc_prefix
tempdir=$(mktemp -d 2>/dev/null || mktemp -d -t tmp) tempdir=$(mktemp -d 2>/dev/null || mktemp -d -t tmp)
out_dir=$(pwd) out_dir=$(pwd)
package_name="$PROJECT_NAME-$TRAVIS_TAG-$TARGET" package_name="$PROJECT_NAME-$TRAVIS_TAG-$TARGET"
if [[ $TARGET == "arm-unknown-linux-gnueabihf" ]]; then
gcc_prefix="arm-linux-gnueabihf-"
elif [[ $TARGET == "aarch64-unknown-linux-gnu" ]]; then
gcc_prefix="aarch64-linux-gnu-"
else
gcc_prefix=""
fi
# create a "staging" directory # create a "staging" directory
mkdir "$tempdir/$package_name" mkdir "$tempdir/$package_name"
mkdir "$tempdir/$package_name/autocomplete"
# copying the main binary # copying the main binary
cp "target/$TARGET/release/$PROJECT_NAME" "$tempdir/$package_name/" cp "target/$TARGET/release/$PROJECT_NAME" "$tempdir/$package_name/"
strip "$tempdir/$package_name/$PROJECT_NAME" "${gcc_prefix}"strip "$tempdir/$package_name/$PROJECT_NAME"
# readme and license # manpage, readme and license
cp "doc/$PROJECT_NAME.1" "$tempdir/$package_name"
cp README.md "$tempdir/$package_name" cp README.md "$tempdir/$package_name"
cp LICENSE-MIT "$tempdir/$package_name" cp LICENSE-MIT "$tempdir/$package_name"
cp LICENSE-APACHE "$tempdir/$package_name" cp LICENSE-APACHE "$tempdir/$package_name"
# various autocomplete
cp target/"$TARGET"/release/build/"$PROJECT_NAME"-*/out/"$PROJECT_NAME".bash "$tempdir/$package_name/autocomplete/${PROJECT_NAME}.bash-completion"
cp target/"$TARGET"/release/build/"$PROJECT_NAME"-*/out/"$PROJECT_NAME".fish "$tempdir/$package_name/autocomplete"
cp target/"$TARGET"/release/build/"$PROJECT_NAME"-*/out/_"$PROJECT_NAME" "$tempdir/$package_name/autocomplete"
# archiving # archiving
pushd "$tempdir" pushd "$tempdir"
tar czf "$out_dir/$package_name.tar.gz" "$package_name"/* tar czf "$out_dir/$package_name.tar.gz" "$package_name"/*
@@ -41,17 +57,28 @@ make_deb() {
local version local version
local dpkgname local dpkgname
local conflictname local conflictname
local gcc_prefix
case $TARGET in case $TARGET in
x86_64*) x86_64*)
architecture=amd64 architecture=amd64
gcc_prefix=""
;; ;;
i686*) i686*)
architecture=i386 architecture=i386
gcc_prefix=""
;;
aarch64*)
architecture=arm64
gcc_prefix="aarch64-linux-gnu-"
;;
arm*hf)
architecture=armhf
gcc_prefix="arm-linux-gnueabihf-"
;; ;;
*) *)
echo "ERROR: unknown target" >&2 echo "make_deb: skipping target '${TARGET}'" >&2
return 1 return 0
;; ;;
esac esac
version=${TRAVIS_TAG#v} version=${TRAVIS_TAG#v}
@@ -67,7 +94,11 @@ make_deb() {
# copy the main binary # copy the main binary
install -Dm755 "target/$TARGET/release/$PROJECT_NAME" "$tempdir/usr/bin/$PROJECT_NAME" install -Dm755 "target/$TARGET/release/$PROJECT_NAME" "$tempdir/usr/bin/$PROJECT_NAME"
strip "$tempdir/usr/bin/$PROJECT_NAME" "${gcc_prefix}"strip "$tempdir/usr/bin/$PROJECT_NAME"
# manpage
install -Dm644 "doc/$PROJECT_NAME.1" "$tempdir/usr/share/man/man1/$PROJECT_NAME.1"
gzip --best "$tempdir/usr/share/man/man1/$PROJECT_NAME.1"
# readme and license # readme and license
install -Dm644 README.md "$tempdir/usr/share/doc/$PROJECT_NAME/README.md" install -Dm644 README.md "$tempdir/usr/share/doc/$PROJECT_NAME/README.md"
@@ -86,6 +117,7 @@ Architecture: $architecture
Provides: $PROJECT_NAME Provides: $PROJECT_NAME
Conflicts: $conflictname Conflicts: $conflictname
Description: A cat(1) clone with wings. Description: A cat(1) clone with wings.
A cat(1) clone with syntax highlighting and Git integration.
EOF EOF
fakeroot dpkg-deb --build "$tempdir" "${dpkgname}_${version}_${architecture}.deb" fakeroot dpkg-deb --build "$tempdir" "${dpkgname}_${version}_${architecture}.deb"
+27
View File
@@ -0,0 +1,27 @@
# This script takes care of packaging the build artifacts that will go in the
# release zipfile
$SRC_DIR = $PWD.Path
$STAGE = [System.Guid]::NewGuid().ToString()
Set-Location $ENV:Temp
New-Item -Type Directory -Name $STAGE
Set-Location $STAGE
$ZIP = "$SRC_DIR\$($Env:CRATE_NAME)-$($Env:APPVEYOR_REPO_TAG_NAME)-$($Env:TARGET).zip"
Copy-Item "$SRC_DIR\target\release\bat.exe" '.\'
Copy-Item $SRC_DIR\target\release\build\bat-*\out\_bat.ps1 '.\'
# readme and license
Copy-Item $SRC_DIR\README.md '.\'
Copy-Item $SRC_DIR\LICENSE-MIT '.\'
Copy-Item $SRC_DIR\LICENSE-APACHE '.\'
7z a "$ZIP" *
Push-AppveyorArtifact "$ZIP"
Set-Location ..
Remove-Item $STAGE -Force -Recurse
Set-Location $SRC_DIR
+37
View File
@@ -0,0 +1,37 @@
#!/usr/bin/env bash
set -ex
if [ "$TRAVIS_OS_NAME" != linux ]; then
exit 0
fi
sudo apt-get update
# needed for musl targets
sudo apt-get install -y musl-tools
# needed to build deb packages
sudo apt-get install -y fakeroot
# needed for i686 linux gnu target
if [[ $TARGET == i686-unknown-linux-gnu ]]; then
sudo apt-get install -y gcc-multilib
fi
# needed for cross-compiling for arm
if [[ $TARGET == arm-unknown-linux-gnueabihf ]]; then
sudo apt-get install -y \
gcc-4.8-arm-linux-gnueabihf \
binutils-arm-linux-gnueabihf \
libc6-armhf-cross \
libc6-dev-armhf-cross
fi
# needed for cross-compiling for arm64
if [[ $TARGET == aarch64-unknown-linux-gnu ]]; then
sudo apt-get install -y \
gcc-4.8-aarch64-linux-gnu \
binutils-aarch64-linux-gnu \
gcc-aarch64-linux-gnu
fi
Executable
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -ex
# Incorporate TARGET env var to the build and test process
cargo build --target "$TARGET" --verbose
# We cannot run arm executables on linux
if [[ $TARGET != arm-unknown-linux-gnueabihf ]] && [[ $TARGET != aarch64-unknown-linux-gnu ]]; then
cargo test --target "$TARGET" --verbose
# Run 'bat' on its own source code and the README
cargo run --target "$TARGET" -- src/main.rs README.md --paging=never
fi
+23
View File
@@ -0,0 +1,23 @@
# Alternatives
The following table tries to give an overview *from `bat`s perspective*, i.e. we only compare
categories which are relevant for `bat`. Some of these projects have completely different goals and
if you are not looking for a program like `bat`, this comparison might not be for you.
| | bat | [pygments](http://pygments.org/) | [highlight](http://www.andre-simon.de/doku/highlight/highlight.php) | [ccat](https://github.com/jingweno/ccat) | [source-highlight](https://www.gnu.org/software/src-highlite/) | [hicat](https://github.com/rstacruz/hicat) | [coderay](https://github.com/rubychan/coderay) | [rouge](https://github.com/jneen/rouge) |
|----------------------------------------------|---------------------------------------------------------------------|----------------------------------|---------------------------------------------------------------------|------------------------------------------|----------------------------------------------------------------|-----------------------------------------------------|-----------------------------------------------------|-----------------------------------------------------|
| Drop-in `cat` replacement | :heavy_check_mark: [*](https://github.com/sharkdp/bat/issues/134) | :x: | :x: | (:heavy_check_mark:) | :x: | :x: [*](https://github.com/rstacruz/hicat/issues/6) | :x: | :x: |
| Git integration | :heavy_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
| Automatic paging | :heavy_check_mark: | :x: | :x: | :x: | :x: | :heavy_check_mark: | :x: | :x: |
| Languages (circa) | 100 | 300 | 200 | 7 | 80 | 130 | 30 | 130 |
| Extensible (languages, themes) | :heavy_check_mark: | (:heavy_check_mark:) | (:heavy_check_mark:) | :x: | (:heavy_check_mark:) | :x: | :x: | :x: |
| Advanced highlighting (e.g. nested syntaxes) | :heavy_check_mark: | :heavy_check_mark: | (:heavy_check_mark:) ? | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| Execution time [ms] (`jquery-3.3.1.js`) | 624 | 789 | 400 | 80 | 300 | 316 | 157 | 695 |
| Execution time [ms] (`miniz.c`) | 66 | 656 | 26 | 8 | 53 | 141 | 75 | 254 |
| Execution time [ms] (370 kB XML file) | 238 | 487 | 129 | 111 | 110 | 339 | 147 | 359 |
If you think that some entries in this table are outdated or wrong, please open a ticket or pull
request.
Some other alternatives that are also related, but not yet included in the table:
- [lesspipe](https://github.com/wofr06/lesspipe)
+119
View File
@@ -0,0 +1,119 @@
.TH BAT "1"
.SH NAME
bat \- manual page for bat
.SH DESCRIPTION
bat - a cat(1) clone with syntax highlighting and Git integration.
.SH "USAGE"
.IP
bat [OPTIONS] [FILE]...
.IP
bat <SUBCOMMAND>
.SH "OPTIONS"
.HP
\fB\-l\fR, \fB\-\-language\fR <language>
.IP
Explicitly set the language for syntax highlighting. The language can be
specified as a name (like 'C++' or 'LaTeX') or possible file extension (like
\&'cpp', 'hpp' or 'md'). Use '\-\-list\-languages' to show all supported language
names and file extensions.
.HP
\fB\-\-list\-languages\fR
.IP
Display a list of supported languages for syntax highlighting.
.HP
\fB\-m\fR, \fB\-\-map\-syntax\fR <from:to>...
.IP
Map a file extension or file name to an existing syntax. For example, to highlight
*.conf files with the INI syntax, use '\-m conf:ini'. To highlight files named
\&'.myignore' with the Git Ignore syntax, use '\-m .myignore:gitignore'.
.HP
\fB\-\-theme\fR <theme>
.IP
Set the theme for syntax highlighting. Use '\-\-list\-themes' to see all
available themes. To set a default theme, export the BAT_THEME environment
variable (e.g.: export BAT_THEME="TwoDark").
.HP
\fB\-\-list\-themes\fR
.IP
Display a list of supported themes for syntax highlighting.
.HP
\fB\-\-style\fR <style\-components>
.IP
Configure which elements (line numbers, file headers, grid borders, Git
modifications, ..) to display in addition to the file contents. The argument
is a comma\-separated list of components to display (e.g.
\&'numbers,changes,grid') or a pre\-defined style ('full'). To set a default
theme, export the BAT_STYLE environment variable (e.g.: export
BAT_STYLE="numbers"). [possible values: auto, full, plain, changes, header,
grid, numbers]
.HP
\fB\-p\fR, \fB\-\-plain\fR
.IP
Only show plain style, no decorations. This is an alias for '\-\-style=plain'
.HP
\fB\-n\fR, \fB\-\-number\fR
.IP
Only show line numbers, no other decorations. This is an alias for
\&'\-\-style=numbers'
.HP
\fB\-\-line\-range\fR <N:M>
.IP
Only print the specified range of lines for each file. For example:
.RS
.IP "\-\-line\-range 30:40"
prints lines 30 to 40
.IP "\-\-line\-range :40"
prints lines 1 to 40
.IP "\-\-line\-range 40:"
prints lines 40 to the end of the file
.RE
.HP
\fB\-\-color\fR <when>
.IP
Specify when to use colored output. The automatic mode only enables colors if an
interactive terminal is detected. Possible values: *auto*, never, always.
.HP
\fB\-\-decorations\fR <when>
.IP
Specify when to use the decorations that have been specified via '\-\-style'. The
automatic mode only enables decorations if an interactive terminal is detected. Possible
values: *auto*, never, always.
.HP
\fB\-\-paging\fR <when>
.IP
Specify when to use the pager. To control which pager is used, set the PAGER or
BAT_PAGER environment variables (the latter takes precedence). The default pager is
\&'less'. To disable the pager permanently, set BAT_PAGER to an empty string. Possible
values: *auto*, never, always.
.HP
\fB\-\-wrap\fR <mode>
.IP
Specify the text\-wrapping mode (*auto*, never, character).
.HP
\fB\-\-tabs\fR <T>
.IP
Set the tab width to T spaces. Use a width of 0 to pass tabs through directly
.HP
\fB\-u\fR, \fB\-\-unbuffered\fR
.IP
This option exists for POSIX\-compliance reasons ('u' is for 'unbuffered'). The output is
always unbuffered \- this option is simply ignored.
.HP
\fB\-h\fR, \fB\-\-help\fR
.IP
Print this help message.
.HP
\fB\-V\fR, \fB\-\-version\fR
.IP
Show version information.
.SH "ARGS"
.IP
<FILE>...
.IP
File(s) to print / concatenate. Use a dash ('\-') or no argument at all to read
from standard input.
.SH "SUBCOMMANDS"
.IP
cache
.IP
Modify the syntax\-definition and theme cache. See "bat cache --help" for more information
+326
View File
@@ -0,0 +1,326 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1000"
height="286.64285"
viewBox="0 0 1000 286.64285"
version="1.1"
xml:space="preserve"
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41420996"
id="svg1285"
sodipodi:docname="logo-header.svg"
inkscape:version="0.92.2 2405546, 2018-03-11"><metadata
id="metadata1289"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1175"
id="namedview1287"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="0.82573726"
inkscape:cx="438.92362"
inkscape:cy="320.87266"
inkscape:window-x="1920"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg1285"
showguides="true"
inkscape:guide-bbox="true" />
<rect
style="opacity:1;fill:#f2f2f2;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.14294769px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
id="rect1929"
width="1000"
height="286.64285"
x="0"
y="0" /><g
id="g929"
transform="translate(0,13.321425)"><g
transform="matrix(5.1207879,0,0,4.741146,45.483811,-7057.152)"
id="g1168">
<path
d="m 77.792,1533.05 c 0,0.32 -0.064,0.61 -0.192,0.88 -0.128,0.27 -0.3,0.5 -0.516,0.7 -0.216,0.19 -0.468,0.34 -0.756,0.45 -0.288,0.11 -0.596,0.16 -0.924,0.16 h -4.02 v -8.52 h 4.104 c 0.296,0 0.564,0.07 0.804,0.19 0.24,0.13 0.444,0.3 0.612,0.5 0.168,0.21 0.298,0.44 0.39,0.7 0.092,0.26 0.138,0.52 0.138,0.78 0,0.44 -0.108,0.83 -0.324,1.19 -0.216,0.35 -0.516,0.62 -0.9,0.8 0.488,0.14 0.874,0.41 1.158,0.8 0.284,0.39 0.426,0.85 0.426,1.37 z m -0.84,-0.15 c 0,-0.21 -0.036,-0.41 -0.108,-0.6 -0.072,-0.2 -0.174,-0.37 -0.306,-0.52 -0.132,-0.15 -0.288,-0.27 -0.468,-0.36 -0.18,-0.09 -0.374,-0.14 -0.582,-0.14 h -3.264 v 3.23 h 3.18 c 0.216,0 0.418,-0.04 0.606,-0.13 0.188,-0.09 0.352,-0.21 0.492,-0.35 0.14,-0.15 0.25,-0.33 0.33,-0.52 0.08,-0.2 0.12,-0.4 0.12,-0.61 z m -4.728,-5.45 v 3.15 h 2.928 c 0.208,0 0.402,-0.04 0.582,-0.13 0.18,-0.09 0.334,-0.21 0.462,-0.35 0.128,-0.14 0.228,-0.31 0.3,-0.5 0.072,-0.19 0.108,-0.38 0.108,-0.59 0,-0.22 -0.034,-0.42 -0.102,-0.62 -0.068,-0.19 -0.164,-0.35 -0.288,-0.49 -0.124,-0.14 -0.27,-0.26 -0.438,-0.34 -0.168,-0.08 -0.352,-0.13 -0.552,-0.13 z"
style="fill:#1d2167;fill-rule:nonzero"
id="path1162"
inkscape:connector-curvature="0" />
<path
d="m 88.436,1526.72 h 0.708 l 3.54,8.52 h -0.888 l -1.104,-2.66 h -3.828 l -1.092,2.66 h -0.9 z m 2.064,5.2 -1.716,-4.21 -1.74,4.21 z"
style="fill:#1d2167;fill-rule:nonzero"
id="path1164"
inkscape:connector-curvature="0" />
<path
d="m 105.716,1527.47 h -3.036 v 7.77 h -0.84 v -7.77 h -3.036 v -0.75 h 6.912 z"
style="fill:#1d2167;fill-rule:nonzero"
id="path1166"
inkscape:connector-curvature="0" />
</g><g
transform="translate(1.9578e-5)"
id="g6103"><g
id="g1172"
transform="matrix(0.31374232,0,0,0.31374232,-949.56013,-170.6326)">
<path
inkscape:connector-curvature="0"
id="path1170"
style="fill:url(#_Linear1)"
d="m 4399.57,773.907 c 0,0 35.33,20.718 42.25,24.779 13.1,7.683 47.96,27.832 64.24,37.232 1.77,1.027 2.87,2.923 2.87,4.975 0.01,2.053 -1.08,3.952 -2.85,4.986 -27.1,15.803 -110.2,64.254 -128.26,74.788 -2.16,1.254 -4.82,1.237 -6.95,-0.046 -13.57,-8.147 -62.93,-37.791 -75.02,-44.875 -16.93,-9.911 -37.27,-21.84 -37.27,-21.84 z" />
</g><g
id="g1176"
transform="matrix(0.31374232,0,0,0.31374232,-949.56013,-170.6326)">
<path
inkscape:connector-curvature="0"
id="path1174"
style="fill:#31369e"
d="m 4269.48,860.305 c -54.5,-31.918 -88.34,-51.732 -117.18,-68.621 -3.98,-2.335 -6.43,-6.608 -6.44,-11.228 0,-4.619 2.45,-8.893 6.44,-11.229 l 319.41,-187.171 c 2.02,-1.186 4.52,-1.198 6.56,-0.032 2.03,1.166 3.29,3.333 3.29,5.678 0,29.472 0,107.932 0,138.732 0,7.842 -4.16,15.094 -10.94,19.049 -13.32,7.783 -54.43,31.465 -67.73,39.233 0,0 -133.3,75.654 -133.41,75.589 z" />
</g><g
id="g1180"
transform="matrix(0.31374232,0,0,0.31374232,-949.56013,-170.6326)">
<path
inkscape:connector-curvature="0"
id="path1178"
style="fill:#1d2167"
d="m 4604.42,705.593 85.54,34.367 v -63.802 c 0,-2.628 -1.37,-5.066 -3.62,-6.431 -2.24,-1.365 -5.04,-1.459 -7.37,-0.247 -5.93,3.078 -74.55,36.113 -74.55,36.113 z" />
</g><g
id="g1184"
transform="matrix(0.31374232,0,0,0.31374232,-949.56013,-170.6326)">
<path
inkscape:connector-curvature="0"
id="path1182"
style="fill:url(#_Linear2)"
d="m 4976.91,704.019 c 0,0 -8.53,-4.983 -8.56,-5 -79.92,-46.83 -170.16,-99.71 -199.6,-116.963 -2.02,-1.186 -4.52,-1.198 -6.56,-0.032 -2.04,1.166 -3.29,3.333 -3.29,5.678 0,29.472 0,107.932 0,138.732 0,7.842 4.16,15.094 10.93,19.049 13.33,7.783 68.33,39.913 68.33,39.913 z" />
</g><g
id="g1188"
transform="matrix(0.31374232,0,0,0.31374232,-949.56013,-170.6326)">
<path
inkscape:connector-curvature="0"
id="path1186"
style="fill:url(#_Linear3)"
d="m 4968.44,699.073 c 0,0 -235.66,138.235 -263.83,154.762 -3.01,1.764 -6.73,1.783 -9.76,0.05 -3.02,-1.733 -4.89,-4.953 -4.89,-8.44 V 731.796 c 0,0 -111.16,-50.383 -128.47,-59.371 -2.33,-1.212 -4.9781,-0.84921 -7.37,0.247 -1.9592,0.89788 -3.62,3.803 -3.62,6.431 v 166.342 c 0,3.487 0.43,15.045 -12.02,22.226 -2.41,1.392 -130.21,75.278 -130.21,75.278 l 211.99,122.751 c 0,0 377.71,-221.201 467.9,-274.016 3.98,-2.335 6.43,-6.608 6.43,-11.228 0,-4.619 -2.45,-8.893 -6.43,-11.229 -24.64,-14.438 -119.72,-70.154 -119.72,-70.154"
sodipodi:nodetypes="cccsccsssccccscc" />
</g></g><g
transform="matrix(0.18627124,0,0,0.22786575,340.43532,-286.36087)"
id="g1262">
<g
transform="matrix(1.28,0,0,1,-97.8353,0)"
id="g1192">
<path
d="m 374.487,2270.67 h 4.788 l 23.94,57.61 h -6.006 l -7.465,-18.01 h -25.887 l -7.385,18.01 h -6.086 z m 13.958,35.14 -11.604,-28.49 -11.767,28.49 z"
style="fill:#1d2167;fill-rule:nonzero"
id="path1190"
inkscape:connector-curvature="0" />
</g>
<g
transform="matrix(1.28,0,0,1,-97.8353,0)"
id="g1196">
<path
d="m 421.293,2307.02 c 0,-2.97 0.514,-5.78 1.542,-8.44 1.028,-2.65 2.475,-4.96 4.342,-6.94 1.866,-1.97 4.098,-3.52 6.695,-4.66 2.596,-1.14 5.464,-1.7 8.602,-1.7 4.003,0 7.492,0.9 10.468,2.71 2.975,1.82 5.221,4.26 6.735,7.35 l -5.356,1.7 c -1.19,-2.16 -2.853,-3.85 -4.99,-5.07 -2.137,-1.22 -4.504,-1.83 -7.101,-1.83 -2.164,0 -4.179,0.44 -6.046,1.3 -1.866,0.87 -3.489,2.05 -4.869,3.53 -1.379,1.49 -2.461,3.26 -3.246,5.32 -0.784,2.05 -1.176,4.3 -1.176,6.73 0,2.38 0.405,4.63 1.217,6.74 0.811,2.11 1.92,3.94 3.327,5.48 1.407,1.54 3.043,2.76 4.91,3.65 1.866,0.89 3.854,1.34 5.964,1.34 1.353,0 2.692,-0.19 4.017,-0.57 1.326,-0.38 2.556,-0.91 3.692,-1.58 1.137,-0.68 2.11,-1.45 2.922,-2.32 0.811,-0.86 1.379,-1.78 1.704,-2.75 l 5.437,1.62 c -0.595,1.51 -1.461,2.91 -2.597,4.18 -1.136,1.27 -2.475,2.38 -4.017,3.32 -1.541,0.95 -3.246,1.68 -5.112,2.2 -1.867,0.51 -3.801,0.77 -5.802,0.77 -3.084,0 -5.924,-0.59 -8.521,-1.75 -2.597,-1.16 -4.842,-2.76 -6.736,-4.79 -1.893,-2.03 -3.367,-4.36 -4.422,-7.02 -1.055,-2.65 -1.583,-5.49 -1.583,-8.52 z"
style="fill:#1d2167;fill-rule:nonzero"
id="path1194"
inkscape:connector-curvature="0" />
</g>
<g
transform="matrix(1.28,0,0,1,-97.8353,0)"
id="g1200">
<path
d="m 476.962,2329.1 c -2.001,0 -3.854,-0.34 -5.558,-1.02 -1.705,-0.67 -3.192,-1.61 -4.464,-2.8 -1.271,-1.19 -2.258,-2.58 -2.962,-4.18 -0.703,-1.59 -1.055,-3.31 -1.055,-5.15 0,-1.84 0.433,-3.54 1.299,-5.11 0.865,-1.57 2.083,-2.92 3.652,-4.06 1.568,-1.14 3.435,-2.02 5.599,-2.64 2.164,-0.62 4.544,-0.93 7.141,-0.93 2.164,0 4.355,0.19 6.573,0.57 2.218,0.38 4.193,0.92 5.924,1.62 v -3.81 c 0,-3.74 -1.055,-6.7 -3.165,-8.89 -2.11,-2.19 -5.031,-3.29 -8.764,-3.29 -2.164,0 -4.382,0.44 -6.654,1.3 -2.272,0.87 -4.572,2.11 -6.898,3.74 l -1.948,-3.66 c 5.465,-3.67 10.766,-5.51 15.906,-5.51 5.302,0 9.467,1.48 12.497,4.46 3.03,2.97 4.544,7.09 4.544,12.33 v 19.07 c 0,1.52 0.677,2.28 2.029,2.28 v 4.86 c -0.919,0.17 -1.623,0.25 -2.11,0.25 -1.406,0 -2.502,-0.35 -3.286,-1.06 -0.785,-0.7 -1.204,-1.67 -1.258,-2.92 l -0.162,-3.33 c -1.948,2.55 -4.396,4.5 -7.345,5.85 -2.948,1.35 -6.126,2.03 -9.535,2.03 z m 1.299,-4.22 c 2.867,0 5.504,-0.54 7.912,-1.63 2.407,-1.08 4.233,-2.51 5.478,-4.3 0.486,-0.48 0.852,-1.01 1.095,-1.58 0.244,-0.57 0.365,-1.09 0.365,-1.58 v -6.9 c -1.839,-0.7 -3.746,-1.24 -5.721,-1.62 -1.975,-0.38 -3.99,-0.57 -6.046,-0.57 -3.895,0 -7.06,0.81 -9.494,2.43 -2.435,1.63 -3.652,3.76 -3.652,6.41 0,1.3 0.257,2.52 0.771,3.66 0.514,1.13 1.217,2.12 2.11,2.96 0.893,0.84 1.961,1.5 3.205,1.99 1.245,0.48 2.57,0.73 3.977,0.73 z"
style="fill:#1d2167;fill-rule:nonzero"
id="path1198"
inkscape:connector-curvature="0" />
</g>
<g
transform="matrix(1.28,0,0,1,-97.8353,0)"
id="g1204">
<path
d="m 528.158,2326.26 c -0.325,0.16 -0.798,0.38 -1.42,0.65 -0.622,0.27 -1.339,0.54 -2.151,0.81 -0.811,0.27 -1.731,0.51 -2.759,0.73 -1.028,0.21 -2.11,0.32 -3.246,0.32 -1.19,0 -2.326,-0.16 -3.408,-0.49 -1.082,-0.32 -2.029,-0.82 -2.84,-1.5 -0.812,-0.67 -1.461,-1.52 -1.948,-2.55 -0.487,-1.03 -0.73,-2.22 -0.73,-3.57 v -30.27 h -5.843 v -4.38 h 5.843 v -14.29 h 5.518 v 14.29 h 9.738 v 4.38 h -9.738 v 28.73 c 0.108,1.56 0.663,2.71 1.664,3.44 1,0.73 2.15,1.1 3.448,1.1 1.569,0 2.949,-0.26 4.139,-0.77 1.19,-0.52 1.948,-0.88 2.272,-1.1 z"
style="fill:#1d2167;fill-rule:nonzero"
id="path1202"
inkscape:connector-curvature="0" />
</g>
<g
transform="matrix(1.28,0,0,1,-97.8353,0)"
id="g1208">
<path
d="m 547.959,2307.02 c 0,-2.97 0.514,-5.78 1.542,-8.44 1.027,-2.65 2.475,-4.96 4.341,-6.94 1.866,-1.97 4.098,-3.52 6.695,-4.66 2.597,-1.14 5.464,-1.7 8.602,-1.7 4.003,0 7.493,0.9 10.468,2.71 2.976,1.82 5.221,4.26 6.736,7.35 l -5.356,1.7 c -1.19,-2.16 -2.854,-3.85 -4.991,-5.07 -2.137,-1.22 -4.504,-1.83 -7.101,-1.83 -2.164,0 -4.179,0.44 -6.045,1.3 -1.867,0.87 -3.49,2.05 -4.869,3.53 -1.38,1.49 -2.462,3.26 -3.246,5.32 -0.785,2.05 -1.177,4.3 -1.177,6.73 0,2.38 0.406,4.63 1.217,6.74 0.812,2.11 1.921,3.94 3.327,5.48 1.407,1.54 3.044,2.76 4.91,3.65 1.866,0.89 3.855,1.34 5.965,1.34 1.352,0 2.691,-0.19 4.016,-0.57 1.326,-0.38 2.557,-0.91 3.693,-1.58 1.136,-0.68 2.11,-1.45 2.921,-2.32 0.812,-0.86 1.38,-1.78 1.704,-2.75 l 5.437,1.62 c -0.595,1.51 -1.46,2.91 -2.596,4.18 -1.136,1.27 -2.475,2.38 -4.017,3.32 -1.542,0.95 -3.246,1.68 -5.113,2.2 -1.866,0.51 -3.8,0.77 -5.802,0.77 -3.084,0 -5.924,-0.59 -8.521,-1.75 -2.597,-1.16 -4.842,-2.76 -6.735,-4.79 -1.894,-2.03 -3.368,-4.36 -4.423,-7.02 -1.055,-2.65 -1.582,-5.49 -1.582,-8.52 z"
style="fill:#1d2167;fill-rule:nonzero"
id="path1206"
inkscape:connector-curvature="0" />
</g>
<g
transform="matrix(1.28,0,0,1,-97.8353,0)"
id="g1212">
<path
d="m 593.24,2269.05 h 5.519 v 49.66 c 0,1.57 0.432,2.8 1.298,3.69 0.866,0.89 2.083,1.34 3.652,1.34 0.595,0 1.298,-0.08 2.11,-0.24 0.811,-0.16 1.569,-0.38 2.272,-0.65 l 0.974,4.46 c -1.028,0.43 -2.286,0.79 -3.774,1.06 -1.487,0.27 -2.772,0.4 -3.854,0.4 -2.543,0 -4.545,-0.72 -6.005,-2.15 -1.461,-1.43 -2.192,-3.45 -2.192,-6.04 z"
style="fill:#1d2167;fill-rule:nonzero"
id="path1210"
inkscape:connector-curvature="0" />
</g>
<g
transform="matrix(1.28,0,0,1,-97.8353,0)"
id="g1216">
<path
d="m 630.651,2329.1 c -3.084,0 -5.897,-0.59 -8.44,-1.75 -2.543,-1.16 -4.747,-2.74 -6.614,-4.75 -1.866,-2 -3.313,-4.32 -4.341,-6.97 -1.028,-2.66 -1.542,-5.44 -1.542,-8.36 0,-2.98 0.527,-5.79 1.582,-8.44 1.055,-2.65 2.516,-4.98 4.383,-6.98 1.866,-2 4.071,-3.6 6.613,-4.79 2.543,-1.19 5.329,-1.78 8.359,-1.78 3.029,0 5.829,0.59 8.399,1.78 2.57,1.19 4.788,2.79 6.654,4.79 1.867,2 3.327,4.33 4.382,6.98 1.055,2.65 1.583,5.46 1.583,8.44 0,2.92 -0.514,5.7 -1.542,8.36 -1.028,2.65 -2.475,4.97 -4.342,6.97 -1.866,2.01 -4.084,3.59 -6.654,4.75 -2.57,1.16 -5.397,1.75 -8.48,1.75 z m -15.338,-21.75 c 0,2.38 0.406,4.58 1.218,6.61 0.811,2.03 1.907,3.82 3.286,5.36 1.38,1.54 3.003,2.74 4.869,3.61 1.867,0.86 3.855,1.3 5.965,1.3 2.11,0 4.098,-0.45 5.964,-1.34 1.867,-0.89 3.503,-2.11 4.91,-3.65 1.406,-1.54 2.516,-3.34 3.327,-5.4 0.812,-2.06 1.217,-4.27 1.217,-6.65 0,-2.33 -0.405,-4.53 -1.217,-6.62 -0.811,-2.08 -1.921,-3.89 -3.327,-5.43 -1.407,-1.55 -3.043,-2.76 -4.91,-3.66 -1.866,-0.89 -3.854,-1.34 -5.964,-1.34 -2.11,0 -4.085,0.45 -5.924,1.34 -1.84,0.9 -3.463,2.13 -4.869,3.7 -1.407,1.56 -2.516,3.39 -3.327,5.47 -0.812,2.09 -1.218,4.32 -1.218,6.7 z"
style="fill:#1d2167;fill-rule:nonzero"
id="path1214"
inkscape:connector-curvature="0" />
</g>
<g
transform="matrix(1.28,0,0,1,-97.8353,0)"
id="g1220">
<path
d="m 694.029,2328.28 h -5.518 v -23.61 c 0,-5.03 -0.744,-8.68 -2.232,-10.95 -1.488,-2.28 -3.773,-3.41 -6.857,-3.41 -1.623,0 -3.246,0.29 -4.869,0.89 -1.623,0.59 -3.124,1.43 -4.504,2.52 -1.379,1.08 -2.61,2.36 -3.692,3.85 -1.082,1.49 -1.867,3.1 -2.354,4.83 v 25.88 h -5.518 v -42.27 h 5.032 v 9.57 c 1.731,-3.08 4.206,-5.57 7.425,-7.46 3.219,-1.9 6.722,-2.84 10.509,-2.84 2.326,0 4.301,0.43 5.924,1.29 1.623,0.87 2.921,2.09 3.895,3.65 0.974,1.57 1.677,3.5 2.11,5.77 0.433,2.27 0.649,4.79 0.649,7.54 z"
style="fill:#1d2167;fill-rule:nonzero"
id="path1218"
inkscape:connector-curvature="0" />
</g>
<g
transform="matrix(1.28,0,0,1,-97.8353,0)"
id="g1224">
<path
d="m 721.62,2329.1 c -3.084,0 -5.91,-0.59 -8.48,-1.75 -2.57,-1.16 -4.801,-2.76 -6.695,-4.79 -1.893,-2.03 -3.368,-4.36 -4.423,-7.02 -1.055,-2.65 -1.582,-5.49 -1.582,-8.52 0,-2.97 0.527,-5.77 1.582,-8.4 1.055,-2.62 2.516,-4.92 4.382,-6.89 1.867,-1.98 4.099,-3.55 6.695,-4.71 2.597,-1.16 5.41,-1.74 8.44,-1.74 3.084,0 5.91,0.58 8.48,1.74 2.57,1.16 4.775,2.74 6.614,4.75 1.839,2 3.273,4.3 4.301,6.89 1.028,2.6 1.542,5.36 1.542,8.28 0,0.44 0,0.87 0,1.3 0,0.43 -0.027,0.73 -0.081,0.89 h -36.193 c 0.162,2.28 0.689,4.37 1.582,6.29 0.893,1.92 2.042,3.59 3.449,4.99 1.407,1.41 3.016,2.5 4.828,3.29 1.813,0.78 3.747,1.18 5.803,1.18 1.352,0 2.705,-0.19 4.057,-0.57 1.353,-0.38 2.597,-0.89 3.733,-1.54 1.136,-0.65 2.164,-1.45 3.084,-2.4 0.919,-0.94 1.623,-1.99 2.11,-3.12 l 4.787,1.3 c -0.649,1.57 -1.568,2.99 -2.759,4.26 -1.19,1.27 -2.569,2.38 -4.138,3.32 -1.569,0.95 -3.3,1.68 -5.194,2.2 -1.893,0.51 -3.868,0.77 -5.924,0.77 z m 15.581,-24.19 c -0.162,-2.27 -0.69,-4.34 -1.582,-6.21 -0.893,-1.86 -2.029,-3.47 -3.409,-4.82 -1.379,-1.35 -2.975,-2.41 -4.788,-3.17 -1.812,-0.76 -3.746,-1.13 -5.802,-1.13 -2.056,0 -4.003,0.37 -5.843,1.13 -1.839,0.76 -3.449,1.82 -4.828,3.17 -1.38,1.35 -2.489,2.97 -3.327,4.87 -0.839,1.89 -1.339,3.95 -1.502,6.16 z"
style="fill:#1d2167;fill-rule:nonzero"
id="path1222"
inkscape:connector-curvature="0" />
</g>
<g
transform="matrix(1.28,0,0,1,-97.8353,0)"
id="g1228">
<path
d="m 818.344,2286.01 h 5.437 l -18.178,42.27 h -4.544 l -9.089,-21.58 -9.008,21.58 h -4.544 l -18.178,-42.27 h 5.356 l 15.418,36.59 8.034,-19.31 -7.222,-17.2 h 4.626 l 5.518,13.79 5.518,-13.79 h 4.707 l -7.223,17.2 8.034,19.31 z"
style="fill:#1d2167;fill-rule:nonzero"
id="path1226"
inkscape:connector-curvature="0" />
</g>
<g
transform="matrix(1.28,0,0,1,-97.8353,0)"
id="g1232">
<path
d="m 828.65,2328.28 v -42.27 h 5.518 v 42.27 z m 0,-51.12 v -8.11 h 5.518 v 8.11 z"
style="fill:#1d2167;fill-rule:nonzero"
id="path1230"
inkscape:connector-curvature="0" />
</g>
<g
transform="matrix(1.28,0,0,1,-97.8353,0)"
id="g1236">
<path
d="m 864.193,2326.26 c -0.324,0.16 -0.798,0.38 -1.42,0.65 -0.622,0.27 -1.339,0.54 -2.15,0.81 -0.812,0.27 -1.731,0.51 -2.759,0.73 -1.028,0.21 -2.11,0.32 -3.246,0.32 -1.19,0 -2.327,-0.16 -3.409,-0.49 -1.082,-0.32 -2.028,-0.82 -2.84,-1.5 -0.811,-0.67 -1.461,-1.52 -1.947,-2.55 -0.487,-1.03 -0.731,-2.22 -0.731,-3.57 v -30.27 h -5.843 v -4.38 h 5.843 v -14.29 h 5.518 v 14.29 h 9.738 v 4.38 h -9.738 v 28.73 c 0.109,1.56 0.663,2.71 1.664,3.44 1.001,0.73 2.15,1.1 3.449,1.1 1.569,0 2.948,-0.26 4.139,-0.77 1.19,-0.52 1.947,-0.88 2.272,-1.1 z"
style="fill:#1d2167;fill-rule:nonzero"
id="path1234"
inkscape:connector-curvature="0" />
</g>
<g
transform="matrix(1.28,0,0,1,-97.8353,0)"
id="g1240">
<path
d="m 904.201,2328.28 h -5.519 v -23.61 c 0,-4.81 -0.825,-8.41 -2.475,-10.79 -1.65,-2.38 -4.071,-3.57 -7.263,-3.57 -1.569,0 -3.124,0.31 -4.666,0.93 -1.542,0.62 -2.989,1.47 -4.341,2.56 -1.353,1.08 -2.53,2.35 -3.53,3.81 -1.001,1.46 -1.745,3.06 -2.232,4.79 v 25.88 h -5.518 v -59.23 h 5.518 v 26.53 c 1.677,-3.19 4.003,-5.71 6.979,-7.55 2.975,-1.83 6.194,-2.75 9.657,-2.75 2.434,0 4.49,0.44 6.167,1.33 1.677,0.9 3.057,2.14 4.139,3.74 1.082,1.59 1.866,3.51 2.353,5.76 0.487,2.24 0.731,4.72 0.731,7.42 z"
style="fill:#1d2167;fill-rule:nonzero"
id="path1238"
inkscape:connector-curvature="0" />
</g>
<g
transform="matrix(1.28,0,0,1,-97.8353,0)"
id="g1244">
<path
d="m 983.314,2286.01 h 5.437 l -18.177,42.27 h -4.545 l -9.088,-21.58 -9.008,21.58 h -4.545 l -18.177,-42.27 h 5.356 l 15.418,36.59 8.034,-19.31 -7.222,-17.2 h 4.625 l 5.519,13.79 5.518,-13.79 h 4.707 l -7.223,17.2 8.034,19.31 z"
style="fill:#1d2167;fill-rule:nonzero"
id="path1242"
inkscape:connector-curvature="0" />
</g>
<g
transform="matrix(1.28,0,0,1,-97.8353,0)"
id="g1248">
<path
d="m 993.62,2328.28 v -42.27 h 5.519 v 42.27 z m 0,-51.12 v -8.11 h 5.519 v 8.11 z"
style="fill:#1d2167;fill-rule:nonzero"
id="path1246"
inkscape:connector-curvature="0" />
</g>
<g
transform="matrix(1.28,0,0,1,-97.8353,0)"
id="g1252">
<path
d="m 1044.42,2328.28 h -5.52 v -23.61 c 0,-5.03 -0.74,-8.68 -2.23,-10.95 -1.49,-2.28 -3.77,-3.41 -6.86,-3.41 -1.62,0 -3.24,0.29 -4.87,0.89 -1.62,0.59 -3.12,1.43 -4.5,2.52 -1.38,1.08 -2.61,2.36 -3.69,3.85 -1.08,1.49 -1.87,3.1 -2.36,4.83 v 25.88 h -5.51 v -42.27 h 5.03 v 9.57 c 1.73,-3.08 4.2,-5.57 7.42,-7.46 3.22,-1.9 6.73,-2.84 10.51,-2.84 2.33,0 4.3,0.43 5.93,1.29 1.62,0.87 2.92,2.09 3.89,3.65 0.97,1.57 1.68,3.5 2.11,5.77 0.43,2.27 0.65,4.79 0.65,7.54 z"
style="fill:#1d2167;fill-rule:nonzero"
id="path1250"
inkscape:connector-curvature="0" />
</g>
<g
transform="matrix(1.28,0,0,1,-97.8353,0)"
id="g1256">
<path
d="m 1070.71,2328.85 c -2.92,0 -5.58,-0.61 -7.99,-1.82 -2.41,-1.22 -4.49,-2.83 -6.25,-4.83 -1.76,-2 -3.12,-4.3 -4.1,-6.9 -0.97,-2.6 -1.46,-5.27 -1.46,-8.03 0,-2.92 0.48,-5.72 1.42,-8.4 0.95,-2.68 2.29,-5.02 4.02,-7.02 1.73,-2 3.8,-3.6 6.21,-4.79 2.4,-1.19 5.07,-1.78 7.99,-1.78 3.63,0 6.76,0.9 9.41,2.71 2.66,1.82 4.93,4.1 6.82,6.86 v -8.84 h 4.95 v 42.44 c 0,2.92 -0.55,5.5 -1.66,7.75 -1.11,2.24 -2.6,4.12 -4.47,5.64 -1.86,1.51 -4.05,2.65 -6.57,3.4 -2.51,0.76 -5.18,1.14 -7.99,1.14 -4.87,0 -8.79,-0.86 -11.77,-2.6 -2.97,-1.73 -5.38,-4.05 -7.22,-6.97 l 3.41,-2.68 c 1.67,2.7 3.89,4.69 6.65,5.96 2.76,1.27 5.74,1.91 8.93,1.91 2.05,0 4,-0.28 5.84,-0.85 1.84,-0.57 3.45,-1.41 4.83,-2.52 1.38,-1.11 2.47,-2.51 3.29,-4.22 0.81,-1.7 1.21,-3.69 1.21,-5.96 v -8.36 c -1.62,2.7 -3.84,4.84 -6.65,6.41 -2.81,1.57 -5.76,2.35 -8.85,2.35 z m 1.55,-4.62 c 1.62,0 3.21,-0.3 4.78,-0.89 1.57,-0.6 2.99,-1.4 4.26,-2.4 1.28,-1 2.34,-2.12 3.21,-3.37 0.86,-1.24 1.43,-2.51 1.7,-3.81 v -13.07 c -0.59,-1.51 -1.4,-2.92 -2.43,-4.22 -1.03,-1.29 -2.19,-2.4 -3.49,-3.32 -1.3,-0.92 -2.69,-1.65 -4.18,-2.19 -1.49,-0.55 -2.99,-0.82 -4.5,-0.82 -2.39,0 -4.51,0.5 -6.37,1.5 -1.87,1.01 -3.45,2.32 -4.75,3.94 -1.3,1.62 -2.29,3.46 -2.96,5.52 -0.68,2.06 -1.02,4.14 -1.02,6.25 0,2.27 0.41,4.43 1.22,6.49 0.81,2.06 1.93,3.86 3.37,5.4 1.43,1.54 3.09,2.76 4.99,3.65 1.89,0.89 3.95,1.34 6.17,1.34 z"
style="fill:#1d2167;fill-rule:nonzero"
id="path1254"
inkscape:connector-curvature="0" />
</g>
<g
transform="matrix(1.28,0,0,1,-97.8353,0)"
id="g1260">
<path
d="m 1115.51,2329.1 c -3.3,0 -6.52,-0.55 -9.66,-1.63 -3.14,-1.08 -5.84,-2.65 -8.11,-4.7 l 2.51,-3.74 c 2.38,1.95 4.8,3.41 7.27,4.39 2.46,0.97 5.09,1.46 7.91,1.46 3.41,0 6.12,-0.69 8.15,-2.07 2.03,-1.38 3.05,-3.34 3.05,-5.89 0,-1.19 -0.27,-2.17 -0.82,-2.96 -0.54,-0.78 -1.33,-1.47 -2.39,-2.07 -1.05,-0.59 -2.38,-1.12 -3.98,-1.58 -1.59,-0.46 -3.44,-0.93 -5.56,-1.42 -2.43,-0.59 -4.54,-1.19 -6.32,-1.78 -1.79,-0.6 -3.26,-1.28 -4.43,-2.03 -1.16,-0.76 -2.03,-1.69 -2.59,-2.8 -0.57,-1.11 -0.86,-2.51 -0.86,-4.18 0,-2.11 0.42,-3.98 1.26,-5.6 0.84,-1.63 1.98,-2.96 3.41,-4.02 1.43,-1.05 3.11,-1.85 5.03,-2.39 1.92,-0.54 3.96,-0.81 6.13,-0.81 3.24,0 6.19,0.52 8.84,1.58 2.65,1.05 4.79,2.45 6.41,4.18 l -2.67,3.24 c -1.57,-1.62 -3.48,-2.84 -5.72,-3.65 -2.25,-0.81 -4.59,-1.22 -7.02,-1.22 -1.47,0 -2.82,0.15 -4.06,0.45 -1.25,0.3 -2.34,0.77 -3.29,1.42 -0.94,0.65 -1.69,1.47 -2.23,2.48 -0.54,1 -0.81,2.17 -0.81,3.52 0,1.14 0.19,2.06 0.57,2.76 0.37,0.71 1,1.32 1.86,1.83 0.87,0.51 1.96,0.97 3.29,1.38 1.33,0.41 2.94,0.83 4.83,1.26 2.7,0.65 5.08,1.3 7.14,1.94 2.05,0.66 3.77,1.41 5.15,2.28 1.38,0.86 2.42,1.92 3.13,3.16 0.7,1.25 1.05,2.76 1.05,4.55 0,3.89 -1.49,6.98 -4.46,9.25 -2.98,2.27 -6.98,3.41 -12.01,3.41 z"
style="fill:#1d2167;fill-rule:nonzero"
id="path1258"
inkscape:connector-curvature="0" />
</g>
</g></g>
<defs
id="defs1283"><linearGradient
id="_Linear1"
x1="0"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-158.501,-265.604,265.604,-158.501,4436.06,964.047)"><stop
offset="0"
style="stop-color:rgb(49,54,158);stop-opacity:1"
id="stop1266" /><stop
offset="0.52"
style="stop-color:rgb(38,42,122);stop-opacity:1"
id="stop1268" /><stop
offset="1"
style="stop-color:black;stop-opacity:1"
id="stop1270" /></linearGradient><linearGradient
id="_Linear2"
x1="0"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(160.563,96.0376,-96.0376,160.563,4771.78,656.669)"><stop
offset="0"
style="stop-color:rgb(49,54,158);stop-opacity:1"
id="stop1273" /><stop
offset="1"
style="stop-color:rgb(29,33,103);stop-opacity:1"
id="stop1275" /></linearGradient><linearGradient
id="_Linear3"
x1="0"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(76.53,136.554,-136.554,76.53,4737.26,847.244)"><stop
offset="0"
style="stop-color:rgb(49,54,158);stop-opacity:1"
id="stop1278" /><stop
offset="1"
style="stop-color:rgb(29,33,103);stop-opacity:1"
id="stop1280" /></linearGradient></defs>
</svg>

After

Width:  |  Height:  |  Size: 23 KiB

+275
View File
@@ -0,0 +1,275 @@
use std::collections::HashSet;
use std::env;
use std::str::FromStr;
use atty::{self, Stream};
use clap::ArgMatches;
use clap_app;
use wild;
use console::Term;
#[cfg(windows)]
use ansi_term;
use assets::BAT_THEME_DEFAULT;
use config::{get_args_from_config_file, get_args_from_env_var};
use errors::*;
use inputfile::InputFile;
use line_range::LineRange;
use style::{OutputComponent, OutputComponents, OutputWrap};
use syntax_mapping::SyntaxMapping;
use util::transpose;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PagingMode {
Always,
QuitIfOneScreen,
Never,
}
#[derive(Clone)]
pub struct Config<'a> {
/// List of files to print
pub files: Vec<InputFile<'a>>,
/// The explicitly configured language, if any
pub language: Option<&'a str>,
/// The character width of the terminal
pub term_width: usize,
/// The width of tab characters.
/// Currently, a value of 0 will cause tabs to be passed through without expanding them.
pub tab_width: usize,
/// Whether or not to simply loop through all input (`cat` mode)
pub loop_through: bool,
/// Whether or not the output should be colorized
pub colored_output: bool,
/// Whether or not the output terminal supports true color
pub true_color: bool,
/// Style elements (grid, line numbers, ...)
pub output_components: OutputComponents,
/// Text wrapping mode
pub output_wrap: OutputWrap,
/// Pager or STDOUT
pub paging_mode: PagingMode,
/// The range lines that should be printed, if specified
pub line_range: Option<LineRange>,
/// The syntax highlighting theme
pub theme: String,
/// File extension/name mappings
pub syntax_mapping: SyntaxMapping,
}
fn is_truecolor_terminal() -> bool {
env::var("COLORTERM")
.map(|colorterm| colorterm == "truecolor" || colorterm == "24bit")
.unwrap_or(false)
}
pub struct App {
pub matches: ArgMatches<'static>,
interactive_output: bool,
}
impl App {
pub fn new() -> Result<Self> {
#[cfg(windows)]
let _ = ansi_term::enable_ansi_support();
let interactive_output = atty::is(Stream::Stdout);
Ok(App {
matches: Self::matches(interactive_output)?,
interactive_output,
})
}
fn matches(interactive_output: bool) -> Result<ArgMatches<'static>> {
let args = if wild::args_os().nth(1) == Some("cache".into())
|| wild::args_os().any(|arg| arg == "--no-config")
{
// Skip the arguments in bats config file
wild::args_os().collect::<Vec<_>>()
} else {
let mut cli_args = wild::args_os();
// 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")?;
// Put the zero-th CLI argument (program name) first
args.insert(0, cli_args.next().unwrap());
// .. and the rest at the end
cli_args.for_each(|a| args.push(a));
args
};
Ok(clap_app::build_app(interactive_output).get_matches_from(args))
}
pub fn config(&self) -> Result<Config> {
let files = self.files();
let output_components = self.output_components()?;
let paging_mode = match self.matches.value_of("paging") {
Some("always") => PagingMode::Always,
Some("never") => PagingMode::Never,
Some("auto") | _ => {
if files.contains(&InputFile::StdIn) {
// If we are reading from stdin, only enable paging if we write to an
// interactive terminal and if we do not *read* from an interactive
// terminal.
if self.interactive_output && !atty::is(Stream::Stdin) {
PagingMode::QuitIfOneScreen
} else {
PagingMode::Never
}
} else {
if self.interactive_output {
PagingMode::QuitIfOneScreen
} else {
PagingMode::Never
}
}
}
};
let mut syntax_mapping = SyntaxMapping::new();
if let Some(values) = self.matches.values_of("map-syntax") {
for from_to in values {
let parts: Vec<_> = from_to.split(":").collect();
if parts.len() != 2 {
return Err("Invalid syntax mapping. The format of the -m/--map-syntax option is 'from:to'.".into());
}
syntax_mapping.insert(parts[0].into(), parts[1].into());
}
}
Ok(Config {
true_color: is_truecolor_terminal(),
language: self.matches.value_of("language"),
output_wrap: if !self.interactive_output {
// We don't have the tty width when piping to another program.
// There's no point in wrapping when this is the case.
OutputWrap::None
} else {
match self.matches.value_of("wrap") {
Some("character") => OutputWrap::Character,
Some("never") => OutputWrap::None,
Some("auto") | _ => {
if output_components.plain() {
OutputWrap::None
} else {
OutputWrap::Character
}
}
}
},
colored_output: match self.matches.value_of("color") {
Some("always") => true,
Some("never") => false,
Some("auto") | _ => self.interactive_output,
},
paging_mode,
term_width: self
.matches
.value_of("terminal-width")
.and_then(|w| w.parse().ok())
.unwrap_or(Term::stdout().size().1 as usize),
loop_through: !(self.interactive_output
|| self.matches.value_of("color") == Some("always")
|| self.matches.value_of("decorations") == Some("always")),
files,
tab_width: self
.matches
.value_of("tabs")
.map(String::from)
.or_else(|| env::var("BAT_TABS").ok())
.and_then(|t| t.parse().ok())
.unwrap_or(
if output_components.plain() && paging_mode == PagingMode::Never {
0
} else {
8
},
),
theme: self
.matches
.value_of("theme")
.map(String::from)
.or_else(|| env::var("BAT_THEME").ok())
.unwrap_or(String::from(BAT_THEME_DEFAULT)),
line_range: transpose(self.matches.value_of("line-range").map(LineRange::from))?,
output_components,
syntax_mapping,
})
}
fn files(&self) -> Vec<InputFile> {
self.matches
.values_of("FILE")
.map(|values| {
values
.map(|filename| {
if filename == "-" {
InputFile::StdIn
} else {
InputFile::Ordinary(filename)
}
})
.collect()
})
.unwrap_or_else(|| vec![InputFile::StdIn])
}
fn output_components(&self) -> Result<OutputComponents> {
let matches = &self.matches;
Ok(OutputComponents(
if matches.value_of("decorations") == Some("never") {
HashSet::new()
} else if matches.is_present("number") {
[OutputComponent::Numbers].iter().cloned().collect()
} else if matches.is_present("plain") {
[OutputComponent::Plain].iter().cloned().collect()
} else {
let env_style_components: Option<Vec<OutputComponent>> =
transpose(env::var("BAT_STYLE").ok().map(|style_str| {
style_str
.split(",")
.map(|x| OutputComponent::from_str(&x))
.collect::<Result<Vec<OutputComponent>>>()
}))?;
values_t!(matches.values_of("style"), OutputComponent)
.ok()
.or(env_style_components)
.unwrap_or(vec![OutputComponent::Full])
.into_iter()
.map(|style| style.components(self.interactive_output))
.fold(HashSet::new(), |mut acc, components| {
acc.extend(components.iter().cloned());
acc
})
},
))
}
}
+227
View File
@@ -0,0 +1,227 @@
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::fs::{self, File};
use std::io::BufReader;
use std::path::{Path, PathBuf};
use syntect::dumps::{dump_to_file, from_binary, from_reader};
use syntect::highlighting::{Theme, ThemeSet};
use syntect::parsing::{SyntaxReference, SyntaxSet, SyntaxSetBuilder};
use dirs::PROJECT_DIRS;
use errors::*;
use inputfile::{InputFile, InputFileReader};
use syntax_mapping::SyntaxMapping;
pub const BAT_THEME_DEFAULT: &str = "Monokai Extended";
pub struct HighlightingAssets {
pub syntax_set: SyntaxSet,
pub theme_set: ThemeSet,
}
impl HighlightingAssets {
pub fn new() -> Self {
Self::from_cache().unwrap_or_else(|_| Self::from_binary())
}
pub fn from_files(dir: Option<&Path>, start_empty: bool) -> Result<Self> {
let source_dir = dir.unwrap_or_else(|| PROJECT_DIRS.config_dir());
let mut theme_set = if start_empty {
ThemeSet {
themes: BTreeMap::new(),
}
} else {
Self::get_integrated_themeset()
};
let theme_dir = source_dir.join("themes");
let res = theme_set.add_from_folder(&theme_dir);
if !res.is_ok() {
println!(
"No themes were found in '{}', using the default set",
theme_dir.to_string_lossy()
);
}
let mut syntax_set_builder = if start_empty {
let mut builder = SyntaxSetBuilder::new();
builder.add_plain_text_syntax();
builder
} else {
Self::get_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()
);
}
Ok(HighlightingAssets {
syntax_set: syntax_set_builder.build(),
theme_set,
})
}
fn from_cache() -> Result<Self> {
let theme_set_path = theme_set_path();
let syntax_set_file = File::open(&syntax_set_path()).chain_err(|| {
format!(
"Could not load cached syntax set '{}'",
syntax_set_path().to_string_lossy()
)
})?;
let syntax_set: SyntaxSet = from_reader(BufReader::new(syntax_set_file))
.chain_err(|| "Could not parse cached syntax set")?;
let theme_set_file = File::open(&theme_set_path).chain_err(|| {
format!(
"Could not load cached theme set '{}'",
theme_set_path.to_string_lossy()
)
})?;
let theme_set: ThemeSet = from_reader(BufReader::new(theme_set_file))
.chain_err(|| "Could not parse cached theme set")?;
Ok(HighlightingAssets {
syntax_set,
theme_set,
})
}
fn get_integrated_syntaxset() -> SyntaxSet {
from_binary(include_bytes!("../assets/syntaxes.bin"))
}
fn get_integrated_themeset() -> ThemeSet {
from_binary(include_bytes!("../assets/themes.bin"))
}
fn from_binary() -> Self {
let syntax_set = Self::get_integrated_syntaxset();
let theme_set = Self::get_integrated_themeset();
HighlightingAssets {
syntax_set,
theme_set,
}
}
pub fn save(&self, dir: Option<&Path>) -> Result<()> {
let target_dir = dir.unwrap_or_else(|| PROJECT_DIRS.cache_dir());
let _ = fs::create_dir(target_dir);
let theme_set_path = target_dir.join("themes.bin");
let syntax_set_path = target_dir.join("syntaxes.bin");
print!(
"Writing theme set to {} ... ",
theme_set_path.to_string_lossy()
);
dump_to_file(&self.theme_set, &theme_set_path).chain_err(|| {
format!(
"Could not save theme set to {}",
theme_set_path.to_string_lossy()
)
})?;
println!("okay");
print!(
"Writing syntax set to {} ... ",
syntax_set_path.to_string_lossy()
);
dump_to_file(&self.syntax_set, &syntax_set_path).chain_err(|| {
format!(
"Could not save syntax set to {}",
syntax_set_path.to_string_lossy()
)
})?;
println!("okay");
Ok(())
}
pub fn get_theme(&self, theme: &str) -> &Theme {
match self.theme_set.themes.get(theme) {
Some(theme) => theme,
None => {
use ansi_term::Colour::Yellow;
eprintln!(
"{}: Unknown theme '{}', using default.",
Yellow.paint("[bat warning]"),
theme
);
&self.theme_set.themes[BAT_THEME_DEFAULT]
}
}
}
pub fn get_syntax(
&self,
language: Option<&str>,
filename: InputFile,
reader: &mut InputFileReader,
mapping: &SyntaxMapping,
) -> &SyntaxReference {
let syntax = match (language, filename) {
(Some(language), _) => self.syntax_set.find_syntax_by_token(language),
(None, InputFile::Ordinary(filename)) => {
let path = Path::new(filename);
let file_name = path.file_name().and_then(|n| n.to_str()).unwrap_or("");
let extension = path.extension().and_then(|x| x.to_str()).unwrap_or("");
let file_name = mapping.replace(file_name);
let extension = mapping.replace(extension);
let ext_syntax = self
.syntax_set
.find_syntax_by_extension(&file_name)
.or_else(|| self.syntax_set.find_syntax_by_extension(&extension));
let line_syntax = if ext_syntax.is_none() {
String::from_utf8(reader.first_line.clone())
.ok()
.and_then(|l| self.syntax_set.find_syntax_by_first_line(&l))
} else {
None
};
let syntax = ext_syntax.or(line_syntax);
syntax
}
(None, InputFile::StdIn) => String::from_utf8(reader.first_line.clone())
.ok()
.and_then(|l| self.syntax_set.find_syntax_by_first_line(&l)),
(_, InputFile::ThemePreviewFile) => self.syntax_set.find_syntax_by_name("Rust"),
};
syntax.unwrap_or_else(|| self.syntax_set.find_syntax_plain_text())
}
}
fn theme_set_path() -> PathBuf {
PROJECT_DIRS.cache_dir().join("themes.bin")
}
fn syntax_set_path() -> PathBuf {
PROJECT_DIRS.cache_dir().join("syntaxes.bin")
}
pub fn config_dir() -> Cow<'static, str> {
PROJECT_DIRS.config_dir().to_string_lossy()
}
pub fn clear_assets() {
print!("Clearing theme set cache ... ");
fs::remove_file(theme_set_path()).ok();
println!("okay");
print!("Clearing syntax set cache ... ");
fs::remove_file(syntax_set_path()).ok();
println!("okay");
}
+332
View File
@@ -0,0 +1,332 @@
use clap::{App as ClapApp, AppSettings, Arg, ArgGroup, SubCommand};
use std::path::Path;
pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
let clap_color_setting = if interactive_output {
AppSettings::ColoredHelp
} else {
AppSettings::ColorNever
};
// Check if the current directory contains a file name cache, if it does
// do not make the arguements for subcommand 'cache' required.
let arg_group_required = !Path::new("cache").exists();
ClapApp::new(crate_name!())
.version(crate_version!())
.global_setting(clap_color_setting)
.global_setting(AppSettings::DeriveDisplayOrder)
.global_setting(AppSettings::UnifiedHelpMessage)
.global_setting(AppSettings::HidePossibleValuesInHelp)
.setting(AppSettings::InferSubcommands)
.setting(AppSettings::ArgsNegateSubcommands)
.setting(AppSettings::DisableHelpSubcommand)
.setting(AppSettings::VersionlessSubcommands)
.max_term_width(100)
.about(
"A cat(1) clone with wings.\n\n\
Use '--help' instead of '-h' to see a more detailed version of the help text.",
)
.long_about("A cat(1) clone with syntax highlighting and Git integration.")
.arg(
Arg::with_name("FILE")
.help("File(s) to print / concatenate. Use '-' for standard input.")
.long_help(
"File(s) to print / concatenate. Use a dash ('-') or no argument at all \
to read from standard input.",
)
.multiple(true)
.empty_values(false),
)
.arg(
Arg::with_name("language")
.short("l")
.long("language")
.overrides_with("language")
.help("Set the language for syntax highlighting.")
.long_help(
"Explicitly set the language for syntax highlighting. The language can be \
specified as a name (like 'C++' or 'LaTeX') or possible file extension \
(like 'cpp', 'hpp' or 'md'). Use '--list-languages' to show all supported \
language names and file extensions.",
)
.takes_value(true),
)
.arg(
Arg::with_name("list-languages")
.long("list-languages")
.conflicts_with("list-themes")
.help("Display all supported languages.")
.long_help("Display a list of supported languages for syntax highlighting."),
)
.arg(
Arg::with_name("map-syntax")
.short("m")
.long("map-syntax")
.multiple(true)
.takes_value(true)
.number_of_values(1)
.value_name("from:to")
.help("Map a file extension or name to an existing syntax.")
.long_help(
"Map a file extension or file name to an existing syntax. For example, \
to highlight *.conf files with the INI syntax, use '-m conf:ini'. \
To highlight files named '.myignore' with the Git Ignore syntax, use \
'-m .myignore:gitignore'.",
)
.takes_value(true),
)
.arg(
Arg::with_name("theme")
.long("theme")
.overrides_with("theme")
.takes_value(true)
.help("Set the color theme for syntax highlighting.")
.long_help(
"Set the theme for syntax highlighting. Use '--list-themes' to \
see all available themes. To set a default theme, export the \
BAT_THEME environment variable (e.g.: export \
BAT_THEME=\"TwoDark\").",
),
)
.arg(
Arg::with_name("list-themes")
.long("list-themes")
.help("Display all supported highlighting themes.")
.long_help("Display a list of supported themes for syntax highlighting."),
)
.arg(
Arg::with_name("style")
.long("style")
.value_name("style-components")
.use_delimiter(true)
.takes_value(true)
.possible_values(&[
"auto", "full", "plain", "changes", "header", "grid", "numbers",
])
.help(
"Comma-separated list of style elements to display \
(*auto*, full, plain, changes, header, grid, numbers).",
)
.long_help(
"Configure which elements (line numbers, file headers, grid \
borders, Git modifications, ..) to display in addition to the \
file contents. The argument is a comma-separated list of \
components to display (e.g. 'numbers,changes,grid') or a \
pre-defined style ('full'). To set a default theme, export the \
BAT_STYLE environment variable (e.g.: export BAT_STYLE=\"numbers\"). \
Possible values: *auto*, full, plain, changes, header, grid, numbers.",
),
)
.arg(
Arg::with_name("plain")
.overrides_with("plain")
.short("p")
.long("plain")
.conflicts_with("style")
.conflicts_with("number")
.help("Show plain style (alias for '--style=plain').")
.long_help(
"Only show plain style, no decorations. This is an alias for \
'--style=plain'",
),
)
.arg(
Arg::with_name("number")
.long("number")
.overrides_with("number")
.short("n")
.conflicts_with("style")
.help("Show line numbers (alias for '--style=numbers').")
.long_help(
"Only show line numbers, no other decorations. This is an alias for \
'--style=numbers'",
),
)
.arg(
Arg::with_name("line-range")
.long("line-range")
.overrides_with("line-range")
.takes_value(true)
.value_name("N:M")
.help("Only print the lines from N to M.")
.long_help(
"Only print the specified range of lines for each file. \
For example:\n \
'--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",
),
)
.arg(
Arg::with_name("color")
.long("color")
.overrides_with("color")
.takes_value(true)
.value_name("when")
.possible_values(&["auto", "never", "always"])
.hide_default_value(true)
.default_value("auto")
.help("When to use colors (*auto*, never, always).")
.long_help(
"Specify when to use colored output. The automatic mode \
only enables colors if an interactive terminal is detected. \
Possible values: *auto*, never, always.",
),
)
.arg(
Arg::with_name("decorations")
.long("decorations")
.overrides_with("decorations")
.takes_value(true)
.value_name("when")
.possible_values(&["auto", "never", "always"])
.default_value("auto")
.hide_default_value(true)
.help("When to show the decorations (*auto*, never, always).")
.long_help(
"Specify when to use the decorations that have been specified \
via '--style'. The automatic mode only enables decorations if \
an interactive terminal is detected. Possible values: *auto*, never, always.",
),
)
.arg(
Arg::with_name("paging")
.long("paging")
.overrides_with("paging")
.takes_value(true)
.value_name("when")
.possible_values(&["auto", "never", "always"])
.default_value("auto")
.hide_default_value(true)
.help("Specify when to use the pager (*auto*, never, always).")
.long_help(
"Specify when to use the pager. To control which pager \
is used, set the PAGER or BAT_PAGER environment \
variables (the latter takes precedence). The default \
pager is 'less'. To disable the pager permanently, set \
BAT_PAGER to an empty string. \
Possible values: *auto*, never, always.",
),
)
.arg(
Arg::with_name("wrap")
.long("wrap")
.overrides_with("wrap")
.takes_value(true)
.value_name("mode")
.possible_values(&["auto", "never", "character"])
.default_value("auto")
.hide_default_value(true)
.help("Specify the text-wrapping mode (*auto*, never, character).")
.long_help("Specify the text-wrapping mode (*auto*, never, character)."),
)
.arg(
Arg::with_name("tabs")
.long("tabs")
.overrides_with("tabs")
.takes_value(true)
.value_name("T")
.validator(
|t| {
t.parse::<u32>()
.map_err(|_t| "must be a number")
.map(|_t| ()) // Convert to Result<(), &str>
.map_err(|e| e.to_string())
}, // Convert to Result<(), String>
)
.help("Set the tab width to T spaces.")
.long_help(
"Set the tab width to T spaces. Use a width of 0 to pass tabs through \
directly",
),
)
.arg(
Arg::with_name("unbuffered")
.short("u")
.long("unbuffered")
.hidden_short_help(true)
.long_help(
"This option exists for POSIX-compliance reasons ('u' is for \
'unbuffered'). The output is always unbuffered - this option \
is simply ignored.",
),
)
.arg(
Arg::with_name("terminal-width")
.long("terminal-width")
.takes_value(true)
.value_name("width")
.hidden(true)
.help("Set the width of the terminal"),
)
.arg(
Arg::with_name("no-config")
.long("no-config")
.hidden(true)
.help("Do not use the configuration file"),
)
.arg(
Arg::with_name("config-file")
.long("config-file")
.conflicts_with("list-languages")
.conflicts_with("list-themes")
.hidden(true)
.help("Show path to the configuration file."),
)
.subcommand(
SubCommand::with_name("cache")
.about("Modify the syntax-definition and theme cache")
.arg(
Arg::with_name("init")
.long("init")
.short("i")
.help("Initialize the syntax/theme cache.")
.long_help(
"Initialize the syntax/theme cache by loading from the \
source directory (default: the configuration directory).",
),
)
.arg(
Arg::with_name("clear")
.long("clear")
.short("c")
.help("Remove the cached syntax definitions and themes."),
)
.arg(
Arg::with_name("config-dir")
.long("config-dir")
.short("d")
.help("Show bat's configuration directory."),
)
.group(
ArgGroup::with_name("cache-actions")
.args(&["init", "clear", "config-dir"])
.required(arg_group_required),
)
.arg(
Arg::with_name("source")
.long("source")
.requires("init")
.takes_value(true)
.value_name("dir")
.help("Use a different directory to load syntaxes and themes from."),
)
.arg(
Arg::with_name("target")
.long("target")
.requires("init")
.takes_value(true)
.value_name("dir")
.help(
"Use a different directory to store the cached syntax and theme set.",
),
)
.arg(Arg::with_name("blank").long("blank").requires("init").help(
"Create completely new syntax and theme sets \
(instead of appending to the default sets).",
)),
)
.help_message("Print this help message.")
.version_message("Show version information.")
}
+101
View File
@@ -0,0 +1,101 @@
use std::env;
use std::ffi::OsString;
use std::fs;
use std::path::PathBuf;
use shell_words;
use dirs::PROJECT_DIRS;
use util::transpose;
pub fn config_file() -> PathBuf {
PROJECT_DIRS.config_dir().join("config")
}
pub fn get_args_from_config_file() -> Result<Vec<OsString>, shell_words::ParseError> {
Ok(transpose(
fs::read_to_string(config_file())
.ok()
.map(|content| get_args_from_str(&content)),
)?
.unwrap_or(vec![]))
}
pub fn get_args_from_env_var() -> Option<Result<Vec<OsString>, shell_words::ParseError>> {
env::var("BAT_OPTS").ok().map(|s| get_args_from_str(&s))
}
fn get_args_from_str<'a>(content: &'a str) -> Result<Vec<OsString>, shell_words::ParseError> {
let args_per_line = content
.split('\n')
.map(|line| line.trim())
.filter(|line| !line.is_empty())
.filter(|line| !line.starts_with("#"))
.map(|line| shell_words::split(line))
.collect::<Result<Vec<_>, _>>()?;
Ok(args_per_line
.iter()
.flatten()
.map(|line| line.into())
.collect())
}
#[test]
fn empty() {
let args = get_args_from_str("").unwrap();
assert!(args.is_empty());
}
#[test]
fn single() {
assert_eq!(vec!["--plain"], get_args_from_str("--plain").unwrap());
}
#[test]
fn multiple() {
assert_eq!(
vec!["--plain", "--language=cpp"],
get_args_from_str("--plain --language=cpp").unwrap()
);
}
#[test]
fn quotes() {
assert_eq!(
vec!["--theme", "Sublime Snazzy"],
get_args_from_str("--theme \"Sublime Snazzy\"").unwrap()
);
}
#[test]
fn multi_line() {
let config = "
-p
--style numbers,changes
--color=always
";
assert_eq!(
vec!["-p", "--style", "numbers,changes", "--color=always"],
get_args_from_str(config).unwrap()
);
}
#[test]
fn comments() {
let config = "
# plain style
-p
# show line numbers and Git modifications
--style numbers,changes
# Always show ANSI colors
--color=always
";
assert_eq!(
vec!["-p", "--style", "numbers,changes", "--color=always"],
get_args_from_str(config).unwrap()
);
}
+108
View File
@@ -0,0 +1,108 @@
use std::io::{self, Write};
use app::Config;
use assets::HighlightingAssets;
use errors::*;
use inputfile::{InputFile, InputFileReader};
use line_range::LineRange;
use output::OutputType;
use printer::{InteractivePrinter, Printer, SimplePrinter};
pub struct Controller<'a> {
config: &'a Config<'a>,
assets: &'a HighlightingAssets,
}
impl<'b> Controller<'b> {
pub fn new<'a>(config: &'a Config, assets: &'a HighlightingAssets) -> Controller<'a> {
Controller { config, assets }
}
pub fn run(&self) -> Result<bool> {
let mut output_type = OutputType::from_mode(self.config.paging_mode)?;
let writer = output_type.handle()?;
let mut no_errors: bool = true;
let stdin = io::stdin();
for input_file in &self.config.files {
match input_file.get_reader(&stdin) {
Err(error) => {
handle_error(&error);
no_errors = false;
}
Ok(mut reader) => {
let result = if self.config.loop_through {
let mut printer = SimplePrinter::new();
self.print_file(reader, &mut printer, writer, *input_file)
} else {
let mut printer = InteractivePrinter::new(
&self.config,
&self.assets,
*input_file,
&mut reader,
);
self.print_file(reader, &mut printer, writer, *input_file)
};
if let Err(error) = result {
handle_error(&error);
no_errors = false;
}
}
}
}
Ok(no_errors)
}
fn print_file<'a, P: Printer>(
&self,
reader: InputFileReader,
printer: &mut P,
writer: &mut Write,
input_file: InputFile<'a>,
) -> Result<()> {
printer.print_header(writer, input_file)?;
self.print_file_ranges(printer, writer, reader, &self.config.line_range)?;
printer.print_footer(writer)?;
Ok(())
}
fn print_file_ranges<'a, P: Printer>(
&self,
printer: &mut P,
writer: &mut Write,
mut reader: InputFileReader,
line_ranges: &Option<LineRange>,
) -> Result<()> {
let mut line_buffer = Vec::new();
let mut line_number: usize = 1;
while reader.read_line(&mut line_buffer)? {
match line_ranges {
&Some(ref range) => {
if line_number < range.lower {
// Call the printer in case we need to call the syntax highlighter
// for this line. However, set `out_of_range` to `true`.
printer.print_line(true, writer, line_number, &line_buffer)?;
} else if line_number > range.upper {
// no more lines in range, exit early
break;
} else {
printer.print_line(false, writer, line_number, &line_buffer)?;
}
}
&None => {
printer.print_line(false, writer, line_number, &line_buffer)?;
}
}
line_number += 1;
line_buffer.clear();
}
Ok(())
}
}
+154
View File
@@ -0,0 +1,154 @@
use ansi_term::Style;
use diff::LineChange;
use printer::{Colors, InteractivePrinter};
#[derive(Clone)]
pub struct DecorationText {
pub width: usize,
pub text: String,
}
pub trait Decoration {
fn generate(
&self,
line_number: usize,
continuation: bool,
printer: &InteractivePrinter,
) -> DecorationText;
fn width(&self) -> usize;
}
pub struct LineNumberDecoration {
color: Style,
cached_wrap: DecorationText,
cached_wrap_invalid_at: usize,
}
impl LineNumberDecoration {
pub fn new(colors: &Colors) -> Self {
LineNumberDecoration {
color: colors.line_number,
cached_wrap_invalid_at: 10000,
cached_wrap: DecorationText {
text: colors.line_number.paint(" ".repeat(4)).to_string(),
width: 4,
},
}
}
}
impl Decoration for LineNumberDecoration {
fn generate(
&self,
line_number: usize,
continuation: bool,
_printer: &InteractivePrinter,
) -> DecorationText {
if continuation {
if line_number > self.cached_wrap_invalid_at {
let new_width = self.cached_wrap.width + 1;
return DecorationText {
text: self.color.paint(" ".repeat(new_width)).to_string(),
width: new_width,
};
}
self.cached_wrap.clone()
} else {
let plain: String = format!("{:4}", line_number);
DecorationText {
width: plain.len(),
text: self.color.paint(plain).to_string(),
}
}
}
fn width(&self) -> usize {
4
}
}
pub struct LineChangesDecoration {
cached_none: DecorationText,
cached_added: DecorationText,
cached_removed_above: DecorationText,
cached_removed_below: DecorationText,
cached_modified: DecorationText,
}
impl LineChangesDecoration {
#[inline]
fn generate_cached(style: Style, text: &str) -> DecorationText {
DecorationText {
text: style.paint(text).to_string(),
width: text.chars().count(),
}
}
pub fn new(colors: &Colors) -> Self {
LineChangesDecoration {
cached_none: Self::generate_cached(Style::default(), " "),
cached_added: Self::generate_cached(colors.git_added, "+"),
cached_removed_above: Self::generate_cached(colors.git_removed, ""),
cached_removed_below: Self::generate_cached(colors.git_removed, "_"),
cached_modified: Self::generate_cached(colors.git_modified, "~"),
}
}
}
impl Decoration for LineChangesDecoration {
fn generate(
&self,
line_number: usize,
continuation: bool,
printer: &InteractivePrinter,
) -> DecorationText {
if !continuation {
if let Some(ref changes) = printer.line_changes {
return match changes.get(&(line_number as u32)) {
Some(&LineChange::Added) => self.cached_added.clone(),
Some(&LineChange::RemovedAbove) => self.cached_removed_above.clone(),
Some(&LineChange::RemovedBelow) => self.cached_removed_below.clone(),
Some(&LineChange::Modified) => self.cached_modified.clone(),
_ => self.cached_none.clone(),
};
}
}
self.cached_none.clone()
}
fn width(&self) -> usize {
self.cached_none.width
}
}
pub struct GridBorderDecoration {
cached: DecorationText,
}
impl GridBorderDecoration {
pub fn new(colors: &Colors) -> Self {
GridBorderDecoration {
cached: DecorationText {
text: colors.grid.paint("").to_string(),
width: 1,
},
}
}
}
impl Decoration for GridBorderDecoration {
fn generate(
&self,
_line_number: usize,
_continuation: bool,
_printer: &InteractivePrinter,
) -> DecorationText {
self.cached.clone()
}
fn width(&self) -> usize {
self.cached.width
}
}
+80
View File
@@ -0,0 +1,80 @@
use git2::{DiffOptions, IntoCString, Repository};
use std::collections::HashMap;
use std::fs;
use std::path::Path;
#[derive(Copy, Clone, Debug)]
pub enum LineChange {
Added,
RemovedAbove,
RemovedBelow,
Modified,
}
pub type LineChanges = HashMap<u32, LineChange>;
pub fn get_git_diff(filename: &str) -> Option<LineChanges> {
let repo = Repository::discover(&filename).ok()?;
let repo_path_absolute = fs::canonicalize(repo.workdir()?).ok()?;
let filepath_absolute = fs::canonicalize(&filename).ok()?;
let filepath_relative_to_repo = filepath_absolute.strip_prefix(&repo_path_absolute).ok()?;
let mut diff_options = DiffOptions::new();
let pathspec = filepath_relative_to_repo.into_c_string().ok()?;
diff_options.pathspec(pathspec);
diff_options.context_lines(0);
let diff = repo
.diff_index_to_workdir(None, Some(&mut diff_options))
.ok()?;
let mut line_changes: LineChanges = HashMap::new();
let mark_section =
|line_changes: &mut LineChanges, start: u32, end: i32, change: LineChange| {
for line in start..(end + 1) as u32 {
line_changes.insert(line, change);
}
};
let _ = diff.foreach(
&mut |_, _| true,
None,
Some(&mut |delta, hunk| {
let path = delta.new_file().path().unwrap_or_else(|| Path::new(""));
if filepath_relative_to_repo != path {
return false;
}
let old_lines = hunk.old_lines();
let new_start = hunk.new_start();
let new_lines = hunk.new_lines();
let new_end = (new_start + new_lines) as i32 - 1;
if old_lines == 0 && new_lines > 0 {
mark_section(&mut line_changes, new_start, new_end, LineChange::Added);
} else if new_lines == 0 && old_lines > 0 {
if new_start == 0 {
mark_section(&mut line_changes, 1, 1, LineChange::RemovedAbove);
} else {
mark_section(
&mut line_changes,
new_start,
new_start as i32,
LineChange::RemovedBelow,
);
}
} else {
mark_section(&mut line_changes, new_start, new_end, LineChange::Modified);
}
true
}),
None,
);
Some(line_changes)
}
+6
View File
@@ -0,0 +1,6 @@
use directories::ProjectDirs;
lazy_static! {
pub static ref PROJECT_DIRS: ProjectDirs =
ProjectDirs::from("", "", crate_name!()).expect("Could not get home directory");
}
+131
View File
@@ -0,0 +1,131 @@
use std::fs::File;
use std::io::{self, BufRead, BufReader};
use content_inspector::{self, ContentType};
use errors::*;
const THEME_PREVIEW_FILE: &[u8] = include_bytes!("../assets/theme_preview.rs");
pub struct InputFileReader<'a> {
inner: Box<dyn BufRead + 'a>,
pub first_line: Vec<u8>,
pub content_type: ContentType,
}
impl<'a> InputFileReader<'a> {
fn new<R: BufRead + 'a>(mut reader: R) -> InputFileReader<'a> {
let mut first_line = vec![];
reader.read_until(b'\n', &mut first_line).ok();
let content_type = content_inspector::inspect(&first_line[..]);
if content_type == ContentType::UTF_16LE {
reader.read_until(0x00, &mut first_line).ok();
}
InputFileReader {
inner: Box::new(reader),
first_line,
content_type,
}
}
pub 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 == ContentType::UTF_16LE {
self.inner.read_until(0x00, buf).ok();
}
Ok(res)
} else {
buf.append(&mut self.first_line);
Ok(true)
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum InputFile<'a> {
StdIn,
Ordinary(&'a str),
ThemePreviewFile,
}
impl<'a> InputFile<'a> {
pub fn get_reader(&self, stdin: &'a io::Stdin) -> Result<InputFileReader> {
match self {
InputFile::StdIn => Ok(InputFileReader::new(stdin.lock())),
InputFile::Ordinary(filename) => {
let file = File::open(filename)?;
if file.metadata()?.is_dir() {
return Err(format!("'{}' is a directory.", filename).into());
}
Ok(InputFileReader::new(BufReader::new(file)))
}
InputFile::ThemePreviewFile => Ok(InputFileReader::new(THEME_PREVIEW_FILE)),
}
}
}
#[test]
fn basic() {
let content = b"#!/bin/bash\necho hello";
let mut reader = InputFileReader::new(&content[..]);
assert_eq!(b"#!/bin/bash\n", &reader.first_line[..]);
let mut buffer = vec![];
let res = reader.read_line(&mut buffer);
assert!(res.is_ok());
assert_eq!(true, res.unwrap());
assert_eq!(b"#!/bin/bash\n", &buffer[..]);
buffer.clear();
let res = reader.read_line(&mut buffer);
assert!(res.is_ok());
assert_eq!(true, res.unwrap());
assert_eq!(b"echo hello", &buffer[..]);
buffer.clear();
let res = reader.read_line(&mut buffer);
assert!(res.is_ok());
assert_eq!(false, res.unwrap());
assert!(buffer.is_empty());
}
#[test]
fn utf16le() {
let content = b"\xFF\xFE\x73\x00\x0A\x00\x64\x00";
let mut reader = InputFileReader::new(&content[..]);
assert_eq!(b"\xFF\xFE\x73\x00\x0A\x00", &reader.first_line[..]);
let mut buffer = vec![];
let res = reader.read_line(&mut buffer);
assert!(res.is_ok());
assert_eq!(true, res.unwrap());
assert_eq!(b"\xFF\xFE\x73\x00\x0A\x00", &buffer[..]);
buffer.clear();
let res = reader.read_line(&mut buffer);
assert!(res.is_ok());
assert_eq!(true, res.unwrap());
assert_eq!(b"\x64\x00", &buffer[..]);
buffer.clear();
let res = reader.read_line(&mut buffer);
assert!(res.is_ok());
assert_eq!(false, res.unwrap());
assert!(buffer.is_empty());
}
+74
View File
@@ -0,0 +1,74 @@
use errors::*;
#[derive(Clone)]
pub struct LineRange {
pub lower: usize,
pub upper: usize,
}
impl LineRange {
pub fn from(range_raw: &str) -> Result<LineRange> {
LineRange::parse_range(range_raw)
}
pub fn new() -> LineRange {
LineRange {
lower: usize::min_value(),
upper: usize::max_value(),
}
}
pub fn parse_range(range_raw: &str) -> Result<LineRange> {
let mut new_range = LineRange::new();
if range_raw.bytes().nth(0).ok_or("Empty line range")? == b':' {
new_range.upper = range_raw[1..].parse()?;
return Ok(new_range);
} else if range_raw.bytes().last().ok_or("Empty line range")? == b':' {
new_range.lower = range_raw[..range_raw.len() - 1].parse()?;
return Ok(new_range);
}
let line_numbers: Vec<&str> = range_raw.split(':').collect();
if line_numbers.len() == 2 {
new_range.lower = line_numbers[0].parse()?;
new_range.upper = line_numbers[1].parse()?;
return Ok(new_range);
}
Err("expected single ':' character".into())
}
}
#[test]
fn test_parse_full() {
let range = LineRange::from("40:50").expect("Shouldn't fail on test!");
assert_eq!(40, range.lower);
assert_eq!(50, range.upper);
}
#[test]
fn test_parse_partial_min() {
let range = LineRange::from(":50").expect("Shouldn't fail on test!");
assert_eq!(usize::min_value(), range.lower);
assert_eq!(50, range.upper);
}
#[test]
fn test_parse_partial_max() {
let range = LineRange::from("40:").expect("Shouldn't fail on test!");
assert_eq!(40, range.lower);
assert_eq!(usize::max_value(), range.upper);
}
#[test]
fn test_parse_fail() {
let range = LineRange::from("40:50:80");
assert!(range.is_err());
let range = LineRange::from("40::80");
assert!(range.is_err());
let range = LineRange::from(":40:");
assert!(range.is_err());
let range = LineRange::from("40");
assert!(range.is_err());
}
+185 -594
View File
@@ -13,652 +13,243 @@ extern crate lazy_static;
extern crate ansi_term; extern crate ansi_term;
extern crate atty; extern crate atty;
extern crate console; extern crate console;
extern crate content_inspector;
extern crate directories; extern crate directories;
extern crate encoding;
extern crate git2; extern crate git2;
extern crate shell_words;
extern crate syntect; extern crate syntect;
extern crate wild;
mod app;
mod assets;
mod clap_app;
mod config;
mod controller;
mod decorations;
mod diff;
mod dirs;
mod inputfile;
mod line_range;
mod output;
mod preprocessor;
mod printer; mod printer;
mod style;
mod syntax_mapping;
mod terminal; mod terminal;
mod util;
use std::collections::HashMap; use std::collections::HashSet;
use std::env; use std::io;
use std::fs::{self, File}; use std::io::Write;
use std::io::{self, BufRead, BufReader, Write}; use std::path::Path;
use std::path::{Path, PathBuf}; use std::process;
use std::process::{self, Child, Command, Stdio};
#[cfg(unix)] use ansi_term::Colour::Green;
use std::os::unix::fs::FileTypeExt;
use ansi_term::Colour::{Fixed, Green, Red, White, Yellow};
use ansi_term::Style; use ansi_term::Style;
use atty::Stream;
use clap::{App, AppSettings, Arg, ArgGroup, SubCommand};
use directories::ProjectDirs;
use git2::{DiffOptions, IntoCString, Repository};
use syntect::dumps::{dump_to_file, from_binary, from_reader}; use app::{App, Config};
use syntect::easy::HighlightLines; use assets::{clear_assets, config_dir, HighlightingAssets};
use syntect::highlighting::{Theme, ThemeSet}; use config::config_file;
use syntect::parsing::SyntaxSet; use controller::Controller;
use inputfile::InputFile;
use printer::Printer; use style::{OutputComponent, OutputComponents};
lazy_static! {
static ref PROJECT_DIRS: ProjectDirs = ProjectDirs::from("", "", crate_name!());
}
mod errors { mod errors {
error_chain! { error_chain! {
foreign_links { foreign_links {
Clap(::clap::Error);
Io(::std::io::Error); Io(::std::io::Error);
SyntectError(::syntect::LoadingError);
ParseIntError(::std::num::ParseIntError);
} }
} }
pub fn handle_error(error: &Error) {
match error {
&Error(ErrorKind::Io(ref io_error), _)
if io_error.kind() == super::io::ErrorKind::BrokenPipe =>
{
super::process::exit(0);
}
_ => {
use ansi_term::Colour::Red;
eprintln!("{}: {}", Red.paint("[bat error]"), error);
}
};
}
} }
use errors::*; use errors::*;
pub enum OptionsStyle { fn run_cache_subcommand(matches: &clap::ArgMatches) -> Result<()> {
Plain, if matches.is_present("init") {
LineNumbers, let source_dir = matches.value_of("source").map(Path::new);
Full, let target_dir = matches.value_of("target").map(Path::new);
}
pub struct Options<'a> { let blank = matches.is_present("blank");
pub true_color: bool,
pub style: OptionsStyle,
pub language: Option<&'a str>,
pub colored_output: bool,
pub paging: bool,
pub term_width: usize,
}
enum OutputType { let assets = HighlightingAssets::from_files(source_dir, blank)?;
Pager(Child), assets.save(target_dir)?;
Stdout(io::Stdout), } else if matches.is_present("clear") {
} clear_assets();
} else if matches.is_present("config-dir") {
impl OutputType { writeln!(io::stdout(), "{}", config_dir())?;
fn pager() -> Result<Self> {
Ok(OutputType::Pager(Command::new("less")
.args(&["--quit-if-one-screen", "--RAW-CONTROL-CHARS", "--no-init"])
.stdin(Stdio::piped())
.spawn()
.chain_err(|| "Could not spawn pager")?))
} }
fn stdout() -> Self {
OutputType::Stdout(io::stdout())
}
fn handle(&mut self) -> Result<&mut Write> {
Ok(match *self {
OutputType::Pager(ref mut command) => command
.stdin
.as_mut()
.chain_err(|| "Could not open stdin for pager")?,
OutputType::Stdout(ref mut handle) => handle,
})
}
}
impl Drop for OutputType {
fn drop(&mut self) {
if let OutputType::Pager(ref mut command) = *self {
let _ = command.wait();
}
}
}
#[derive(Copy, Clone, Debug)]
pub enum LineChange {
Added,
RemovedAbove,
RemovedBelow,
Modified,
}
pub type LineChanges = HashMap<u32, LineChange>;
const GRID_COLOR: u8 = 238;
const LINE_NUMBER_COLOR: u8 = 244;
#[derive(Default)]
pub struct Colors {
pub grid: Style,
pub filename: Style,
pub git_added: Style,
pub git_removed: Style,
pub git_modified: Style,
pub line_number: Style,
}
impl Colors {
fn plain() -> Self {
Colors::default()
}
fn colored() -> Self {
Colors {
grid: Fixed(GRID_COLOR).normal(),
filename: White.bold(),
git_added: Green.normal(),
git_removed: Red.normal(),
git_modified: Yellow.normal(),
line_number: Fixed(LINE_NUMBER_COLOR).normal(),
}
}
}
fn print_file(
options: &Options,
theme: &Theme,
syntax_set: &SyntaxSet,
printer: &mut Printer,
filename: Option<&str>,
) -> Result<()> {
let stdin = io::stdin(); // TODO: this is not always needed
let mut reader: Box<BufRead> = match filename {
None => Box::new(stdin.lock()),
Some(filename) => Box::new(BufReader::new(File::open(filename)?)),
};
let syntax = match (options.language, filename) {
(Some(language), _) => syntax_set.find_syntax_by_token(language),
(None, Some(filename)) => {
#[cfg(not(unix))]
let may_read_from_file = true;
// Do not peek at the file (to determine the syntax) if it is a FIFO because they can
// only be read once.
#[cfg(unix)]
let may_read_from_file = !fs::metadata(filename)?.file_type().is_fifo();
if may_read_from_file {
syntax_set.find_syntax_for_file(filename)?
} else {
None
}
}
(None, None) => None,
};
let syntax = syntax.unwrap_or_else(|| syntax_set.find_syntax_plain_text());
let mut highlighter = HighlightLines::new(syntax, theme);
printer.print_header(filename)?;
let mut line_nr = 1;
let mut line_buffer = String::new();
loop {
line_buffer.clear();
let num_bytes = reader.read_line(&mut line_buffer);
let line = match num_bytes {
Ok(0) => {
break;
}
Ok(_) => {
if !line_buffer.ends_with("\n") {
line_buffer.push('\n');
}
&line_buffer
}
Err(_) => "<bat: INVALID UTF-8>\n",
};
let regions = highlighter.highlight(line);
printer.print_line(line_nr, &regions)?;
line_nr += 1;
}
printer.print_footer()?;
Ok(()) Ok(())
} }
fn get_git_diff(filename: &str) -> Option<LineChanges> { pub fn list_languages(config: &Config) -> Result<()> {
let repo = Repository::discover(&filename).ok()?; let assets = HighlightingAssets::new();
let path_absolute = fs::canonicalize(&filename).ok()?; let mut languages = assets
let path_relative_to_repo = path_absolute.strip_prefix(repo.workdir()?).ok()?; .syntax_set
.syntaxes()
.iter()
.filter(|syntax| !syntax.hidden && !syntax.file_extensions.is_empty())
.collect::<Vec<_>>();
languages.sort_by_key(|lang| lang.name.to_uppercase());
let mut diff_options = DiffOptions::new(); let longest = languages
let pathspec = path_relative_to_repo.into_c_string().ok()?; .iter()
diff_options.pathspec(pathspec); .map(|syntax| syntax.name.len())
diff_options.context_lines(0); .max()
.unwrap_or(32); // Fallback width if they have no language definitions.
let diff = repo.diff_index_to_workdir(None, Some(&mut diff_options)) let comma_separator = ", ";
.ok()?; let separator = " ";
// Line-wrapping for the possible file extension overflow.
let desired_width = config.term_width - longest - separator.len();
let mut line_changes: LineChanges = HashMap::new(); let stdout = io::stdout();
let mut stdout = stdout.lock();
let mark_section = let style = if config.colored_output {
|line_changes: &mut LineChanges, start: u32, end: i32, change: LineChange| { Green.normal()
for line in start..(end + 1) as u32 {
line_changes.insert(line, change);
}
};
let _ = diff.foreach(
&mut |_, _| true,
None,
Some(&mut |delta, hunk| {
let path = delta.new_file().path().unwrap_or_else(|| Path::new(""));
if path_relative_to_repo != path {
return false;
}
let old_lines = hunk.old_lines();
let new_start = hunk.new_start();
let new_lines = hunk.new_lines();
let new_end = (new_start + new_lines) as i32 - 1;
if old_lines == 0 && new_lines > 0 {
mark_section(&mut line_changes, new_start, new_end, LineChange::Added);
} else if new_lines == 0 && old_lines > 0 {
if new_start == 0 {
mark_section(&mut line_changes, 1, 1, LineChange::RemovedAbove);
} else {
mark_section(
&mut line_changes,
new_start,
new_start as i32,
LineChange::RemovedBelow,
);
}
} else {
mark_section(&mut line_changes, new_start, new_end, LineChange::Modified);
}
true
}),
None,
);
Some(line_changes)
}
fn get_output_type(paging: bool) -> OutputType {
if paging {
OutputType::pager().unwrap_or_else(|_| OutputType::stdout())
} else { } else {
OutputType::stdout() Style::default()
}
}
fn is_truecolor_terminal() -> bool {
env::var("COLORTERM")
.map(|colorterm| colorterm == "truecolor" || colorterm == "24bit")
.unwrap_or(false)
}
struct HighlightingAssets {
pub syntax_set: SyntaxSet,
pub theme_set: ThemeSet,
}
impl HighlightingAssets {
fn theme_set_path() -> PathBuf {
PROJECT_DIRS.cache_dir().join("theme_set")
}
fn syntax_set_path() -> PathBuf {
PROJECT_DIRS.cache_dir().join("syntax_set")
}
fn from_files() -> Result<Self> {
let config_dir = PROJECT_DIRS.config_dir();
let theme_dir = config_dir.join("themes");
let theme_set = ThemeSet::load_from_folder(&theme_dir).map_err(|_| {
io::Error::new(
io::ErrorKind::Other,
format!(
"Could not load themes from '{}'",
theme_dir.to_string_lossy()
),
)
})?;
let mut syntax_set = SyntaxSet::new();
let syntax_dir = config_dir.join("syntax");
let _ = syntax_set.load_syntaxes(syntax_dir, true);
syntax_set.load_plain_text_syntax();
Ok(HighlightingAssets {
syntax_set,
theme_set,
})
}
fn save(&self) -> Result<()> {
let cache_dir = PROJECT_DIRS.cache_dir();
let _ = fs::create_dir(cache_dir);
print!(
"Writing theme set to {} ... ",
Self::theme_set_path().to_string_lossy()
);
dump_to_file(&self.theme_set, &Self::theme_set_path()).map_err(|_| {
io::Error::new(
io::ErrorKind::Other,
format!(
"Could not save theme set to {}",
Self::theme_set_path().to_string_lossy()
),
)
})?;
println!("okay");
print!(
"Writing syntax set to {} ... ",
Self::syntax_set_path().to_string_lossy()
);
dump_to_file(&self.syntax_set, &Self::syntax_set_path()).map_err(|_| {
io::Error::new(
io::ErrorKind::Other,
format!(
"Could not save syntax set to {}",
Self::syntax_set_path().to_string_lossy()
),
)
})?;
println!("okay");
Ok(())
}
fn from_cache() -> Result<Self> {
let syntax_set_file = File::open(&Self::syntax_set_path()).chain_err(|| {
format!(
"Could not load cached syntax set '{}'",
Self::syntax_set_path().to_string_lossy()
)
})?;
let mut syntax_set: SyntaxSet = from_reader(syntax_set_file).map_err(|_| {
io::Error::new(
io::ErrorKind::Other,
format!("Could not parse cached syntax set"),
)
})?;
syntax_set.link_syntaxes();
let theme_set_file = File::open(&Self::theme_set_path()).chain_err(|| {
format!(
"Could not load cached theme set '{}'",
Self::theme_set_path().to_string_lossy()
)
})?;
let theme_set: ThemeSet = from_reader(theme_set_file).map_err(|_| {
io::Error::new(
io::ErrorKind::Other,
format!("Could not parse cached theme set"),
)
})?;
Ok(HighlightingAssets {
syntax_set,
theme_set,
})
}
fn from_binary() -> Self {
let mut syntax_set: SyntaxSet = from_binary(include_bytes!("../assets/syntax_set"));
syntax_set.link_syntaxes();
let theme_set: ThemeSet = from_binary(include_bytes!("../assets/theme_set"));
HighlightingAssets {
syntax_set,
theme_set,
}
}
}
fn run() -> Result<()> {
let interactive_terminal = atty::is(Stream::Stdout);
let clap_color_setting = if interactive_terminal {
AppSettings::ColoredHelp
} else {
AppSettings::ColorNever
}; };
let app_matches = App::new(crate_name!()) for lang in languages {
.version(crate_version!()) write!(stdout, "{:width$}{}", lang.name, separator, width = longest)?;
.global_setting(clap_color_setting)
.global_setting(AppSettings::DeriveDisplayOrder)
.global_setting(AppSettings::UnifiedHelpMessage)
.global_setting(AppSettings::NextLineHelp)
.setting(AppSettings::InferSubcommands)
.setting(AppSettings::ArgsNegateSubcommands)
.setting(AppSettings::DisableHelpSubcommand)
.setting(AppSettings::VersionlessSubcommands)
.max_term_width(90)
.about(crate_description!())
.arg(
Arg::with_name("language")
.short("l")
.long("language")
.help("Set the language for highlighting")
.takes_value(true),
)
.arg(
Arg::with_name("FILE")
.help("File(s) to print")
.multiple(true)
.empty_values(false),
)
.arg(
Arg::with_name("style")
.long("style")
.possible_values(&["auto", "plain", "line-numbers", "full"])
.default_value("auto")
.help("Additional info to display along with content"),
)
.arg(
Arg::with_name("color")
.long("color")
.takes_value(true)
.possible_values(&["auto", "never", "always"])
.default_value("auto")
.help("When to use colors"),
)
.arg(
Arg::with_name("paging")
.long("paging")
.takes_value(true)
.possible_values(&["auto", "never", "always"])
.default_value("auto")
.help("When to use the pager"),
)
.arg(
Arg::with_name("list-languages")
.long("list-languages")
.help("Displays supported languages"),
)
.subcommand(
SubCommand::with_name("cache")
.about("Modify the syntax-definition and theme cache")
.arg(
Arg::with_name("init")
.long("init")
.short("i")
.help("Initialize the cache by loading from the config dir"),
)
.arg(
Arg::with_name("clear")
.long("clear")
.short("c")
.help("Reset the cache"),
)
.arg(
Arg::with_name("config-dir")
.long("config-dir")
.short("d")
.help("Show the configuration directory"),
)
.group(
ArgGroup::with_name("cache-actions")
.args(&["init", "clear", "config-dir"])
.required(true),
),
)
.help_message("Print this help message.")
.version_message("Show version information.")
.get_matches();
match app_matches.subcommand() { // Number of characters on this line so far, wrap before `desired_width`
let mut num_chars = 0;
let mut extension = lang.file_extensions.iter().peekable();
while let Some(word) = extension.next() {
// If we can't fit this word in, then create a line break and align it in.
let new_chars = word.len() + comma_separator.len();
if num_chars + new_chars >= desired_width {
num_chars = 0;
write!(stdout, "\n{:width$}{}", "", separator, width = longest)?;
}
num_chars += new_chars;
write!(stdout, "{}", style.paint(&word[..]))?;
if extension.peek().is_some() {
write!(stdout, "{}", comma_separator)?;
}
}
writeln!(stdout)?;
}
Ok(())
}
pub fn list_themes(cfg: &Config) -> Result<()> {
let assets = HighlightingAssets::new();
let themes = &assets.theme_set.themes;
let mut config = cfg.clone();
let mut style = HashSet::new();
style.insert(OutputComponent::Plain);
config.files = vec![InputFile::ThemePreviewFile];
config.output_components = OutputComponents(style);
let stdout = io::stdout();
let mut stdout = stdout.lock();
if config.colored_output {
for (theme, _) in themes.iter() {
writeln!(
stdout,
"Theme: {}\n",
Style::new().bold().paint(theme.to_string())
)?;
config.theme = theme.to_string();
let _controller = Controller::new(&config, &assets).run();
writeln!(stdout)?;
}
} else {
for (theme, _) in themes.iter() {
writeln!(stdout, "{}", theme)?;
}
}
Ok(())
}
fn run_controller(config: &Config) -> Result<bool> {
let assets = HighlightingAssets::new();
let controller = Controller::new(&config, &assets);
controller.run()
}
/// Returns `Err(..)` upon fatal errors. Otherwise, returns `Some(true)` on full success and
/// `Some(false)` if any intermediate errors occurred (were printed).
fn run() -> Result<bool> {
let app = App::new()?;
match app.matches.subcommand() {
("cache", Some(cache_matches)) => { ("cache", Some(cache_matches)) => {
if cache_matches.is_present("init") { // If there is a file named 'cache' in the current working directory,
let assets = HighlightingAssets::from_files()?; // arguments for subcommand 'cache' are not mandatory.
assets.save()?; // If there are non-zero arguments, execute the subcommand cache, else, open the file cache.
} else if cache_matches.is_present("clear") { if !cache_matches.args.is_empty() {
print!("Clearing theme set cache ... "); run_cache_subcommand(cache_matches)?;
fs::remove_file(HighlightingAssets::theme_set_path())?; Ok(true)
println!("okay"); } else {
let mut config = app.config()?;
config.files = vec![InputFile::Ordinary(&"cache")];
print!("Clearing syntax set cache ... "); run_controller(&config)
fs::remove_file(HighlightingAssets::syntax_set_path())?;
println!("okay");
} else if cache_matches.is_present("config-dir") {
println!("{}", PROJECT_DIRS.config_dir().to_string_lossy());
} }
} }
_ => { _ => {
let files: Vec<Option<&str>> = app_matches let config = app.config()?;
.values_of("FILE")
.map(|values| {
values
.map(|filename| {
if filename == "-" {
None
} else {
Some(filename)
}
})
.collect()
})
.unwrap_or_else(|| vec![None]); // read from stdin (None) if no args are given
let options = Options { if app.matches.is_present("list-languages") {
true_color: is_truecolor_terminal(), list_languages(&config)?;
style: match app_matches.value_of("style") {
Some("plain") => OptionsStyle::Plain,
Some("line-numbers") => OptionsStyle::LineNumbers,
Some("full") => OptionsStyle::Full,
Some("auto") | _ => if interactive_terminal {
OptionsStyle::Full
} else {
OptionsStyle::Plain
},
},
language: app_matches.value_of("language"),
colored_output: match app_matches.value_of("color") {
Some("always") => true,
Some("never") => false,
_ => interactive_terminal,
},
paging: match app_matches.value_of("paging") {
Some("always") => true,
Some("never") => false,
Some("auto") | _ => if files.contains(&None) {
// If we are reading from stdin, only enable paging if we write to an
// interactive terminal and if we do not *read* from an interactive
// terminal.
interactive_terminal && !atty::is(Stream::Stdin)
} else {
interactive_terminal
},
},
term_width: console::Term::stdout().size().1 as usize,
};
let assets = Ok(true)
HighlightingAssets::from_cache().unwrap_or(HighlightingAssets::from_binary()); } else if app.matches.is_present("list-themes") {
list_themes(&config)?;
let theme = assets.theme_set.themes.get("Default").ok_or_else(|| { Ok(true)
io::Error::new( } else if app.matches.is_present("config-file") {
io::ErrorKind::Other, println!("{}", config_file().to_string_lossy());
format!("Could not find 'Default' theme"),
)
})?;
if app_matches.is_present("list-languages") { Ok(true)
let languages = assets.syntax_set.syntaxes(); } else {
run_controller(&config)
let longest = languages
.iter()
.filter(|s| !s.hidden && s.file_extensions.len() > 0)
.map(|s| s.name.len())
.max()
.unwrap_or(32); // Fallback width if they have no language definitions.
let separator = " ";
for lang in languages {
if lang.hidden || lang.file_extensions.len() == 0 {
continue;
}
print!("{:width$}{}", lang.name, separator, width = longest);
// Line-wrapping for the possible file extension overflow.
let desired_width = options.term_width - longest - separator.len();
// Number of characters on this line so far, wrap before `desired_width`
let mut num_chars = 0;
let comma_separator = ", ";
let mut extension = lang.file_extensions.iter().peekable();
while let Some(word) = extension.next() {
// If we can't fit this word in, then create a line break and align it in.
let new_chars = word.len() + comma_separator.len();
if num_chars + new_chars >= desired_width {
num_chars = 0;
print!("\n{:width$}{}", "", separator, width = longest);
}
num_chars += new_chars;
print!("{}", Green.paint(word as &str));
if extension.peek().is_some() {
print!("{}", comma_separator);
}
}
println!();
}
return Ok(());
}
let mut output_type = get_output_type(options.paging);
let handle = output_type.handle()?;
let mut printer = Printer::new(handle, &options);
for file in files {
printer.line_changes = file.and_then(|filename| get_git_diff(filename));
print_file(&options, theme, &assets.syntax_set, &mut printer, file)?;
} }
} }
} }
Ok(())
} }
fn main() { fn main() {
let result = run(); let result = run();
if let Err(error) = result { match result {
match error { Err(error) => {
Error(ErrorKind::Io(ref io_error), _) handle_error(&error);
if io_error.kind() == io::ErrorKind::BrokenPipe => {} process::exit(1);
_ => { }
eprintln!("{}: {}", Red.paint("[bat error]"), error); Ok(false) => {
process::exit(1);
process::exit(1); }
} Ok(true) => {
}; process::exit(0);
}
} }
} }
+87
View File
@@ -0,0 +1,87 @@
use std::env;
use std::ffi::OsString;
use std::io::{self, Write};
use std::path::PathBuf;
use std::process::{Child, Command, Stdio};
use shell_words;
use app::PagingMode;
use errors::*;
pub enum OutputType {
Pager(Child),
Stdout(io::Stdout),
}
impl OutputType {
pub fn from_mode(mode: PagingMode) -> Result<Self> {
use self::PagingMode::*;
Ok(match mode {
Always => OutputType::try_pager(false)?,
QuitIfOneScreen => OutputType::try_pager(true)?,
_ => OutputType::stdout(),
})
}
/// Try to launch the pager. Fall back to stdout in case of errors.
fn try_pager(quit_if_one_screen: bool) -> Result<Self> {
let pager = env::var("BAT_PAGER")
.or_else(|_| env::var("PAGER"))
.unwrap_or(String::from("less"));
let pagerflags = shell_words::split(&pager)
.chain_err(|| "Could not parse (BAT_)PAGER environment variable.")?;
match pagerflags.split_first() {
Some((pager_name, args)) => {
let pager_path = PathBuf::from(pager_name);
let is_less = pager_path.file_stem() == Some(&OsString::from("less"));
let mut process = if is_less {
let mut p = Command::new(&pager_path);
if args.is_empty() {
p.args(vec!["--RAW-CONTROL-CHARS", "--no-init"]);
if quit_if_one_screen {
p.arg("--quit-if-one-screen");
}
}
p.env("LESSCHARSET", "UTF-8");
p
} else {
Command::new(&pager_path)
};
Ok(process
.args(args)
.stdin(Stdio::piped())
.spawn()
.map(OutputType::Pager)
.unwrap_or_else(|_| OutputType::stdout()))
}
None => Ok(OutputType::stdout()),
}
}
fn stdout() -> Self {
OutputType::Stdout(io::stdout())
}
pub fn handle(&mut self) -> Result<&mut Write> {
Ok(match *self {
OutputType::Pager(ref mut command) => command
.stdin
.as_mut()
.chain_err(|| "Could not open stdin for pager")?,
OutputType::Stdout(ref mut handle) => handle,
})
}
}
impl Drop for OutputType {
fn drop(&mut self) {
if let OutputType::Pager(ref mut command) = *self {
let _ = command.wait();
}
}
}
+34
View File
@@ -0,0 +1,34 @@
use console::AnsiCodeIterator;
/// Expand tabs like an ANSI-enabled expand(1).
pub fn expand(line: &str, width: usize, cursor: &mut usize) -> String {
let mut buffer = String::with_capacity(line.len() * 2);
for chunk in AnsiCodeIterator::new(line) {
match chunk {
(text, true) => buffer.push_str(text),
(mut text, false) => {
while let Some(index) = text.find('\t') {
// Add previous text.
if index > 0 {
*cursor += index;
buffer.push_str(&text[0..index]);
}
// Add tab.
let spaces = width - (*cursor % width);
*cursor += spaces;
buffer.push_str(&*" ".repeat(spaces));
// Next.
text = &text[index + 1..text.len()];
}
*cursor += text.len();
buffer.push_str(text);
}
}
}
buffer
}
+415 -104
View File
@@ -1,145 +1,456 @@
use ansi_term::Style;
use errors::*;
use std::io::Write; use std::io::Write;
use syntect::highlighting; use std::vec::Vec;
use terminal::as_terminal_escaped;
use {Colors, LineChange, LineChanges, Options, OptionsStyle};
const PANEL_WIDTH: usize = 7; use ansi_term::Colour::{Fixed, Green, Red, Yellow};
use ansi_term::Style;
pub struct Printer<'a> { use console::AnsiCodeIterator;
handle: &'a mut Write,
colors: Colors, use syntect::easy::HighlightLines;
options: &'a Options<'a>, use syntect::highlighting::Theme;
pub line_changes: Option<LineChanges>, use syntect::parsing::SyntaxSet;
use content_inspector::ContentType;
use encoding::all::{UTF_16BE, UTF_16LE};
use encoding::{DecoderTrap, Encoding};
use app::Config;
use assets::HighlightingAssets;
use decorations::{Decoration, GridBorderDecoration, LineChangesDecoration, LineNumberDecoration};
use diff::get_git_diff;
use diff::LineChanges;
use errors::*;
use inputfile::{InputFile, InputFileReader};
use preprocessor::expand;
use style::OutputWrap;
use terminal::{as_terminal_escaped, to_ansi_color};
pub trait Printer {
fn print_header(&mut self, handle: &mut Write, file: InputFile) -> Result<()>;
fn print_footer(&mut self, handle: &mut Write) -> Result<()>;
fn print_line(
&mut self,
out_of_range: bool,
handle: &mut Write,
line_number: usize,
line_buffer: &[u8],
) -> Result<()>;
} }
impl<'a> Printer<'a> { pub struct SimplePrinter;
pub fn new(handle: &'a mut Write, options: &'a Options) -> Self {
let colors = if options.colored_output { impl SimplePrinter {
Colors::colored() pub fn new() -> Self {
SimplePrinter {}
}
}
impl Printer for SimplePrinter {
fn print_header(&mut self, _handle: &mut Write, _file: InputFile) -> Result<()> {
Ok(())
}
fn print_footer(&mut self, _handle: &mut Write) -> Result<()> {
Ok(())
}
fn print_line(
&mut self,
out_of_range: bool,
handle: &mut Write,
_line_number: usize,
line_buffer: &[u8],
) -> Result<()> {
if !out_of_range {
handle.write(line_buffer)?;
}
Ok(())
}
}
pub struct InteractivePrinter<'a> {
colors: Colors,
config: &'a Config<'a>,
decorations: Vec<Box<dyn Decoration>>,
panel_width: usize,
ansi_prefix_sgr: String,
content_type: ContentType,
pub line_changes: Option<LineChanges>,
highlighter: Option<HighlightLines<'a>>,
syntax_set: &'a SyntaxSet,
}
impl<'a> InteractivePrinter<'a> {
pub fn new(
config: &'a Config,
assets: &'a HighlightingAssets,
file: InputFile,
reader: &mut InputFileReader,
) -> Self {
let theme = assets.get_theme(&config.theme);
let colors = if config.colored_output {
Colors::colored(theme, config.true_color)
} else { } else {
Colors::plain() Colors::plain()
}; };
Printer { // Create decorations.
handle, let mut decorations: Vec<Box<dyn Decoration>> = Vec::new();
if config.output_components.numbers() {
decorations.push(Box::new(LineNumberDecoration::new(&colors)));
}
if config.output_components.changes() {
decorations.push(Box::new(LineChangesDecoration::new(&colors)));
}
let mut panel_width: usize =
decorations.len() + decorations.iter().fold(0, |a, x| a + x.width());
// The grid border decoration isn't added until after the panel_width calculation, since the
// print_horizontal_line, print_header, and print_footer functions all assume the panel
// width is without the grid border.
if config.output_components.grid() && !decorations.is_empty() {
decorations.push(Box::new(GridBorderDecoration::new(&colors)));
}
// Disable the panel if the terminal is too small (i.e. can't fit 5 characters with the
// panel showing).
if config.term_width
< (decorations.len() + decorations.iter().fold(0, |a, x| a + x.width())) + 5
{
decorations.clear();
panel_width = 0;
}
let mut line_changes = None;
let highlighter = if reader.content_type.is_binary() {
None
} else {
// Get the Git modifications
line_changes = if config.output_components.changes() {
match file {
InputFile::Ordinary(filename) => get_git_diff(filename),
_ => None,
}
} else {
None
};
// Determine the type of syntax for highlighting
let syntax = assets.get_syntax(config.language, file, reader, &config.syntax_mapping);
Some(HighlightLines::new(syntax, theme))
};
InteractivePrinter {
panel_width,
colors, colors,
options, config,
line_changes: None, decorations,
content_type: reader.content_type,
ansi_prefix_sgr: String::new(),
line_changes,
highlighter,
syntax_set: &assets.syntax_set,
} }
} }
pub fn print_header(&mut self, filename: Option<&str>) -> Result<()> { fn print_horizontal_line(&mut self, handle: &mut Write, grid_char: char) -> Result<()> {
match self.options.style { if self.panel_width == 0 {
OptionsStyle::Full => {} writeln!(
_ => return Ok(()), handle,
"{}",
self.colors.grid.paint("".repeat(self.config.term_width))
)?;
} else {
let hline = "".repeat(self.config.term_width - (self.panel_width + 1));
let hline = format!("{}{}{}", "".repeat(self.panel_width), grid_char, hline);
writeln!(handle, "{}", self.colors.grid.paint(hline))?;
} }
self.print_horizontal_line('┬')?; Ok(())
}
write!( fn preprocess(&self, text: &str, cursor: &mut usize) -> String {
self.handle, if self.config.tab_width > 0 {
"{}{} ", expand(text, self.config.tab_width, cursor)
" ".repeat(PANEL_WIDTH), } else {
self.colors.grid.paint(""), text.to_string()
)?; }
}
}
impl<'a> Printer for InteractivePrinter<'a> {
fn print_header(&mut self, handle: &mut Write, file: InputFile) -> Result<()> {
if !self.config.output_components.header() {
return Ok(());
}
if self.config.output_components.grid() {
self.print_horizontal_line(handle, '┬')?;
write!(
handle,
"{}{}",
" ".repeat(self.panel_width),
self.colors
.grid
.paint(if self.panel_width > 0 { "" } else { "" }),
)?;
} else {
write!(handle, "{}", " ".repeat(self.panel_width))?;
}
let (prefix, name) = match file {
InputFile::Ordinary(filename) => ("File: ", filename),
_ => ("", "STDIN"),
};
let mode = match self.content_type {
ContentType::BINARY => " <BINARY>",
ContentType::UTF_16LE => " <UTF-16LE>",
ContentType::UTF_16BE => " <UTF-16BE>",
_ => "",
};
writeln!( writeln!(
self.handle, handle,
"{}{}", "{}{}{}",
filename.map_or("", |_| "File: "), prefix,
self.colors.filename.paint(filename.unwrap_or("STDIN")) self.colors.filename.paint(name),
mode
)?; )?;
self.print_horizontal_line('┼') if self.config.output_components.grid() {
if self.content_type.is_text() {
self.print_horizontal_line(handle, '┼')?;
} else {
self.print_horizontal_line(handle, '┴')?;
}
}
Ok(())
} }
pub fn print_footer(&mut self) -> Result<()> { fn print_footer(&mut self, handle: &mut Write) -> Result<()> {
if let OptionsStyle::Full = self.options.style { if self.config.output_components.grid() && self.content_type.is_text() {
self.print_horizontal_line('┴') self.print_horizontal_line(handle, '┴')
} else { } else {
Ok(()) Ok(())
} }
} }
pub fn print_line( fn print_line(
&mut self, &mut self,
out_of_range: bool,
handle: &mut Write,
line_number: usize, line_number: usize,
regions: &[(highlighting::Style, &str)], line_buffer: &[u8],
) -> Result<()> { ) -> Result<()> {
let decorations = vec![ let line = match self.content_type {
self.print_line_number(line_number), ContentType::BINARY => {
self.print_git_marker(line_number), return Ok(());
self.print_line_border(),
Some(as_terminal_escaped(
&regions,
self.options.true_color,
self.options.colored_output,
)),
];
write!(
self.handle,
"{}",
decorations
.into_iter()
.filter_map(|dec| dec)
.collect::<Vec<_>>()
.join(" ")
)?;
Ok(())
}
fn print_line_number(&self, line_number: usize) -> Option<String> {
if let OptionsStyle::Plain = self.options.style {
return None;
}
Some(
self.colors
.line_number
.paint(format!("{:4}", line_number))
.to_string(),
)
}
fn print_git_marker(&self, line_number: usize) -> Option<String> {
match self.options.style {
OptionsStyle::Full => {}
_ => return None,
}
let marker = if let Some(ref changes) = self.line_changes {
match changes.get(&(line_number as u32)) {
Some(&LineChange::Added) => self.colors.git_added.paint("+"),
Some(&LineChange::RemovedAbove) => self.colors.git_removed.paint(""),
Some(&LineChange::RemovedBelow) => self.colors.git_removed.paint("_"),
Some(&LineChange::Modified) => self.colors.git_modified.paint("~"),
_ => Style::default().paint(" "),
} }
} else { ContentType::UTF_16LE => UTF_16LE
Style::default().paint(" ") .decode(&line_buffer, DecoderTrap::Strict)
.unwrap_or("Invalid UTF-16LE".into()),
ContentType::UTF_16BE => UTF_16BE
.decode(&line_buffer, DecoderTrap::Strict)
.unwrap_or("Invalid UTF-16BE".into()),
_ => String::from_utf8_lossy(&line_buffer).to_string(),
};
let regions = {
let highlighter = match self.highlighter {
Some(ref mut highlighter) => highlighter,
_ => {
return Ok(());
}
};
highlighter.highlight(line.as_ref(), self.syntax_set)
}; };
Some(marker.to_string()) if out_of_range {
} return Ok(());
fn print_line_border(&self) -> Option<String> {
if let OptionsStyle::Plain = self.options.style {
return None;
} }
Some(self.colors.grid.paint("").to_string()) let mut cursor: usize = 0;
} let mut cursor_max: usize = self.config.term_width;
let mut cursor_total: usize = 0;
let mut panel_wrap: Option<String> = None;
fn print_horizontal_line(&mut self, grid_char: char) -> Result<()> { // Line decorations.
let hline = "".repeat(self.options.term_width - (PANEL_WIDTH + 1)); if self.panel_width > 0 {
let hline = format!("{}{}{}", "".repeat(PANEL_WIDTH), grid_char, hline); let decorations = self
.decorations
.iter()
.map(|ref d| d.generate(line_number, false, self))
.collect::<Vec<_>>();
writeln!(self.handle, "{}", self.colors.grid.paint(hline))?; for deco in decorations {
write!(handle, "{} ", deco.text)?;
cursor_max -= deco.width + 1;
}
}
// Line contents.
if self.config.output_wrap == OutputWrap::None {
let true_color = self.config.true_color;
let colored_output = self.config.colored_output;
for &(style, region) in regions.iter() {
let text = &*self.preprocess(region, &mut cursor_total);
write!(
handle,
"{}",
as_terminal_escaped(style, &*text, true_color, colored_output,)
)?;
}
if line.bytes().next_back() != Some(b'\n') {
write!(handle, "\n")?;
}
} else {
for &(style, region) in regions.iter() {
let mut ansi_iterator = AnsiCodeIterator::new(region);
let mut ansi_prefix: String = String::new();
for chunk in ansi_iterator {
match chunk {
// ANSI escape passthrough.
(text, true) => {
if text.chars().last().map_or(false, |c| c == 'm') {
ansi_prefix.push_str(text);
if text == "\x1B[0m" {
self.ansi_prefix_sgr = "\x1B[0m".to_owned();
} else {
self.ansi_prefix_sgr.push_str(text);
}
} else {
ansi_prefix.push_str(text);
}
}
// Regular text.
(text, false) => {
let text = self.preprocess(
text.trim_right_matches(|c| c == '\r' || c == '\n'),
&mut cursor_total,
);
let mut chars = text.chars();
let mut remaining = text.chars().count();
while remaining > 0 {
let available = cursor_max - cursor;
// It fits.
if remaining <= available {
let text = chars.by_ref().take(remaining).collect::<String>();
cursor += remaining;
write!(
handle,
"{}",
as_terminal_escaped(
style,
&*format!(
"{}{}{}",
self.ansi_prefix_sgr, ansi_prefix, text
),
self.config.true_color,
self.config.colored_output,
)
)?;
break;
}
// Generate wrap padding if not already generated.
if panel_wrap.is_none() {
panel_wrap = if self.panel_width > 0 {
Some(format!(
"{} ",
self.decorations
.iter()
.map(|ref d| d
.generate(line_number, true, self)
.text)
.collect::<Vec<String>>()
.join(" ")
))
} else {
Some("".to_string())
}
}
// It wraps.
let text = chars.by_ref().take(available).collect::<String>();
cursor = 0;
remaining -= available;
write!(
handle,
"{}\n{}",
as_terminal_escaped(
style,
&*format!(
"{}{}{}",
self.ansi_prefix_sgr, ansi_prefix, text
),
self.config.true_color,
self.config.colored_output,
),
panel_wrap.clone().unwrap()
)?;
}
// Clear the ANSI prefix buffer.
ansi_prefix.clear();
}
}
}
}
write!(handle, "\n")?;
}
Ok(()) Ok(())
} }
} }
const DEFAULT_GUTTER_COLOR: u8 = 238;
#[derive(Default)]
pub struct Colors {
pub grid: Style,
pub filename: Style,
pub git_added: Style,
pub git_removed: Style,
pub git_modified: Style,
pub line_number: Style,
}
impl Colors {
fn plain() -> Self {
Colors::default()
}
fn colored(theme: &Theme, true_color: bool) -> Self {
let gutter_color = theme
.settings
.gutter_foreground
.map(|c| to_ansi_color(c, true_color))
.unwrap_or(Fixed(DEFAULT_GUTTER_COLOR));
Colors {
grid: gutter_color.normal(),
filename: Style::new().bold(),
git_added: Green.normal(),
git_removed: Red.normal(),
git_modified: Yellow.normal(),
line_number: gutter_color.normal(),
}
}
}
+88
View File
@@ -0,0 +1,88 @@
use std::collections::HashSet;
use std::str::FromStr;
use errors::*;
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
pub enum OutputComponent {
Auto,
Changes,
Grid,
Header,
Numbers,
Full,
Plain,
}
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
pub enum OutputWrap {
Character,
None,
}
impl OutputComponent {
pub fn components(&self, interactive_terminal: bool) -> &'static [OutputComponent] {
match *self {
OutputComponent::Auto => {
if interactive_terminal {
OutputComponent::Full.components(interactive_terminal)
} else {
OutputComponent::Plain.components(interactive_terminal)
}
}
OutputComponent::Changes => &[OutputComponent::Changes],
OutputComponent::Grid => &[OutputComponent::Grid],
OutputComponent::Header => &[OutputComponent::Header],
OutputComponent::Numbers => &[OutputComponent::Numbers],
OutputComponent::Full => &[
OutputComponent::Changes,
OutputComponent::Grid,
OutputComponent::Header,
OutputComponent::Numbers,
],
OutputComponent::Plain => &[],
}
}
}
impl FromStr for OutputComponent {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
match s {
"auto" => Ok(OutputComponent::Auto),
"changes" => Ok(OutputComponent::Changes),
"grid" => Ok(OutputComponent::Grid),
"header" => Ok(OutputComponent::Header),
"numbers" => Ok(OutputComponent::Numbers),
"full" => Ok(OutputComponent::Full),
"plain" => Ok(OutputComponent::Plain),
_ => Err(format!("Unknown style '{}'", s).into()),
}
}
}
#[derive(Clone)]
pub struct OutputComponents(pub HashSet<OutputComponent>);
impl OutputComponents {
pub fn changes(&self) -> bool {
self.0.contains(&OutputComponent::Changes)
}
pub fn grid(&self) -> bool {
self.0.contains(&OutputComponent::Grid)
}
pub fn header(&self) -> bool {
self.0.contains(&OutputComponent::Header)
}
pub fn numbers(&self) -> bool {
self.0.contains(&OutputComponent::Numbers)
}
pub fn plain(&self) -> bool {
self.0.iter().all(|c| c == &OutputComponent::Plain)
}
}
+35
View File
@@ -0,0 +1,35 @@
use std::borrow::Cow;
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct SyntaxMapping(HashMap<String, String>);
impl SyntaxMapping {
pub fn new() -> SyntaxMapping {
SyntaxMapping(HashMap::new())
}
pub fn insert(&mut self, from: String, to: String) -> Option<String> {
self.0.insert(from, to)
}
pub fn replace<'a>(&self, input: &'a str) -> Cow<'a, str> {
let mut out = Cow::from(input);
if let Some(value) = self.0.get(input) {
out = Cow::from(value.clone())
}
out
}
}
#[test]
fn basic() {
let mut map = SyntaxMapping::new();
map.insert("Cargo.lock".into(), "toml".into());
map.insert(".ignore".into(), ".gitignore".into());
assert_eq!("toml", map.replace("Cargo.lock"));
assert_eq!("other.lock", map.replace("other.lock"));
assert_eq!(".gitignore", map.replace(".ignore"));
}
+24 -58
View File
@@ -1,73 +1,39 @@
use std::fmt::Write; extern crate ansi_colours;
use ansi_term::Colour::{Fixed, RGB}; use ansi_term::Colour::{Fixed, RGB};
use ansi_term::Style; use ansi_term::{self, Style};
use syntect::highlighting;
/// Approximate a 24 bit color value by a 8 bit ANSI code use syntect::highlighting::{self, FontStyle};
fn rgb2ansi(r: u8, g: u8, b: u8) -> u8 {
const BLACK: u8 = 16;
const WHITE: u8 = 231;
if r == g && g == b { pub fn to_ansi_color(color: highlighting::Color, true_color: bool) -> ansi_term::Colour {
if r < 8 { if true_color {
BLACK RGB(color.r, color.g, color.b)
} else if r > 248 {
WHITE
} else {
let fr = f32::from(r);
(((fr - 8.) / 247.) * 24.) as u8 + 232
}
} else { } else {
let fr = f32::from(r); Fixed(ansi_colours::ansi256_from_rgb((color.r, color.g, color.b)))
let fg = f32::from(g);
let fb = f32::from(b);
16 + (36 * (fr / 255. * 5.) as u8) + (6 * (fg / 255. * 5.) as u8) + (fb / 255. * 5.) as u8
} }
} }
pub fn as_terminal_escaped( pub fn as_terminal_escaped(
v: &[(highlighting::Style, &str)], style: highlighting::Style,
text: &str,
true_color: bool, true_color: bool,
colored: bool, colored: bool,
) -> String { ) -> String {
let mut s: String = String::new(); let style = if !colored {
for &(ref style, text) in v.iter() { Style::default()
let style = if !colored { } else {
Style::default() let color = to_ansi_color(style.foreground, true_color);
} else if true_color {
RGB(style.foreground.r, style.foreground.g, style.foreground.b).normal() if style.font_style.contains(FontStyle::BOLD) {
color.bold()
} else if style.font_style.contains(FontStyle::UNDERLINE) {
color.underline()
} else if style.font_style.contains(FontStyle::ITALIC) {
color.italic()
} else { } else {
let ansi = rgb2ansi(style.foreground.r, style.foreground.g, style.foreground.b); color.normal()
Fixed(ansi).normal() }
}; };
write!(s, "{}", style.paint(text)).unwrap(); style.paint(text).to_string()
}
s
}
#[test]
fn test_rgb2ansi_black_white() {
assert_eq!(16, rgb2ansi(0x00, 0x00, 0x00));
assert_eq!(231, rgb2ansi(0xff, 0xff, 0xff));
}
#[test]
fn test_rgb2ansi_gray() {
assert_eq!(241, rgb2ansi(0x6c, 0x6c, 0x6c));
assert_eq!(233, rgb2ansi(0x1c, 0x1c, 0x1c));
}
#[test]
fn test_rgb2ansi_color() {
assert_eq!(96, rgb2ansi(0x87, 0x5f, 0x87));
assert_eq!(141, rgb2ansi(0xaf, 0x87, 0xff));
assert_eq!(193, rgb2ansi(0xd7, 0xff, 0xaf));
}
#[test]
fn test_rgb2ansi_approx() {
assert_eq!(231, rgb2ansi(0xfe, 0xfe, 0xfe));
} }
+27
View File
@@ -0,0 +1,27 @@
/// Helper function that might appear in Rust stable at some point
/// (https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.transpose)
pub fn transpose<T, E>(opt: Option<Result<T, E>>) -> Result<Option<T>, E> {
opt.map_or(Ok(None), |res| res.map(Some))
}
#[cfg(test)]
mod tests {
use super::transpose;
#[derive(Debug, PartialEq)]
struct TestError;
type TestResult<T> = Result<T, TestError>;
#[test]
fn basic() {
let a: Option<TestResult<i32>> = Some(Ok(2));
assert_eq!(Ok(Some(2)), transpose(a));
let b: Option<TestResult<i32>> = Some(Err(TestError));
assert_eq!(Err(TestError), transpose(b));
let c: Option<TestResult<i32>> = None;
assert_eq!(Ok(None), transpose(c));
}
}
+1
View File
@@ -0,0 +1 @@
test-src/* linguist-vendored
+1
View File
@@ -0,0 +1 @@
test-src/*
+31
View File
@@ -0,0 +1,31 @@
#!/bin/bash
if ! which hyperfine > /dev/null 2>&1; then
echo "'hyperfine' does not seem to be installed."
echo "You can get it here: https://github.com/sharkdp/hyperfine"
exit 1
fi
SRC="test-src/jquery-3.3.1.js"
cmd_bat="bat --style=full --color=always --paging=never '$SRC'"
cmd_bat_simple="bat --plain --wrap=never --tabs=0 --color=always --paging=never '$SRC'"
cmd_pygmentize="pygmentize -g '$SRC'"
cmd_highlight="highlight -O truecolor '$SRC'"
cmd_ccat="ccat --color=always '$SRC'"
cmd_source_highlight="source-highlight --failsafe --infer-lang -f esc -i '$SRC'"
cmd_hicat="hicat '$SRC'"
cmd_coderay="coderay '$SRC'"
cmd_rouge="rougify '$SRC'"
hyperfine --warmup 3 \
"$cmd_bat" \
"$cmd_bat_simple" \
"$cmd_pygmentize" \
"$cmd_highlight" \
"$cmd_ccat" \
"$cmd_source_highlight" \
"$cmd_hicat" \
"$cmd_coderay" \
"$cmd_rouge" \
+26
View File
@@ -0,0 +1,26 @@
#!/bin/bash
if ! which hyperfine > /dev/null 2>&1; then
echo "'hyperfine' does not seem to be installed."
echo "You can get it here: https://github.com/sharkdp/hyperfine"
exit 1
fi
echo "### Startup time"
echo
hyperfine --warmup 3 bat
echo
echo "### Plain text"
echo
hyperfine --warmup 3 "bat --language txt --paging=never 'test-src/jquery-3.3.1.js'"
echo
echo "### Time to syntax-highlight large files"
echo
for SRC in test-src/*; do
hyperfine --warmup 3 "bat --style=full --color=always --paging=never '$SRC'"
done
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+602
View File
@@ -0,0 +1,602 @@
/**************************************************************************
*
* Copyright 2013-2014 RAD Game Tools and Valve Software
* Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
**************************************************************************/
#include "miniz.h"
typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1];
typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1];
typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1];
#ifdef __cplusplus
extern "C" {
#endif
/* ------------------- zlib-style API's */
mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len)
{
mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16);
size_t block_len = buf_len % 5552;
if (!ptr)
return MZ_ADLER32_INIT;
while (buf_len)
{
for (i = 0; i + 7 < block_len; i += 8, ptr += 8)
{
s1 += ptr[0], s2 += s1;
s1 += ptr[1], s2 += s1;
s1 += ptr[2], s2 += s1;
s1 += ptr[3], s2 += s1;
s1 += ptr[4], s2 += s1;
s1 += ptr[5], s2 += s1;
s1 += ptr[6], s2 += s1;
s1 += ptr[7], s2 += s1;
}
for (; i < block_len; ++i)
s1 += *ptr++, s2 += s1;
s1 %= 65521U, s2 %= 65521U;
buf_len -= block_len;
block_len = 5552;
}
return (s2 << 16) + s1;
}
/* Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ */
#if 0
mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len)
{
static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c };
mz_uint32 crcu32 = (mz_uint32)crc;
if (!ptr)
return MZ_CRC32_INIT;
crcu32 = ~crcu32;
while (buf_len--)
{
mz_uint8 b = *ptr++;
crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)];
crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)];
}
return ~crcu32;
}
#else
/* Faster, but larger CPU cache footprint.
*/
mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len)
{
static const mz_uint32 s_crc_table[256] =
{
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB,
0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA,
0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE,
0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,
0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409,
0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739,
0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268,
0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0,
0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8,
0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF,
0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703,
0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7,
0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE,
0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6,
0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D,
0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5,
0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,
0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};
mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF;
const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr;
while (buf_len >= 4)
{
crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF];
crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF];
crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF];
crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF];
pByte_buf += 4;
buf_len -= 4;
}
while (buf_len)
{
crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF];
++pByte_buf;
--buf_len;
}
return ~crc32;
}
#endif
void mz_free(void *p)
{
MZ_FREE(p);
}
void *miniz_def_alloc_func(void *opaque, size_t items, size_t size)
{
(void)opaque, (void)items, (void)size;
return MZ_MALLOC(items * size);
}
void miniz_def_free_func(void *opaque, void *address)
{
(void)opaque, (void)address;
MZ_FREE(address);
}
void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size)
{
(void)opaque, (void)address, (void)items, (void)size;
return MZ_REALLOC(address, items * size);
}
const char *mz_version(void)
{
return MZ_VERSION;
}
#ifndef MINIZ_NO_ZLIB_APIS
int mz_deflateInit(mz_streamp pStream, int level)
{
return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY);
}
int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy)
{
tdefl_compressor *pComp;
mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy);
if (!pStream)
return MZ_STREAM_ERROR;
if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)))
return MZ_PARAM_ERROR;
pStream->data_type = 0;
pStream->adler = MZ_ADLER32_INIT;
pStream->msg = NULL;
pStream->reserved = 0;
pStream->total_in = 0;
pStream->total_out = 0;
if (!pStream->zalloc)
pStream->zalloc = miniz_def_alloc_func;
if (!pStream->zfree)
pStream->zfree = miniz_def_free_func;
pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor));
if (!pComp)
return MZ_MEM_ERROR;
pStream->state = (struct mz_internal_state *)pComp;
if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY)
{
mz_deflateEnd(pStream);
return MZ_PARAM_ERROR;
}
return MZ_OK;
}
int mz_deflateReset(mz_streamp pStream)
{
if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree))
return MZ_STREAM_ERROR;
pStream->total_in = pStream->total_out = 0;
tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags);
return MZ_OK;
}
int mz_deflate(mz_streamp pStream, int flush)
{
size_t in_bytes, out_bytes;
mz_ulong orig_total_in, orig_total_out;
int mz_status = MZ_OK;
if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out))
return MZ_STREAM_ERROR;
if (!pStream->avail_out)
return MZ_BUF_ERROR;
if (flush == MZ_PARTIAL_FLUSH)
flush = MZ_SYNC_FLUSH;
if (((tdefl_compressor *)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE)
return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR;
orig_total_in = pStream->total_in;
orig_total_out = pStream->total_out;
for (;;)
{
tdefl_status defl_status;
in_bytes = pStream->avail_in;
out_bytes = pStream->avail_out;
defl_status = tdefl_compress((tdefl_compressor *)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush);
pStream->next_in += (mz_uint)in_bytes;
pStream->avail_in -= (mz_uint)in_bytes;
pStream->total_in += (mz_uint)in_bytes;
pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state);
pStream->next_out += (mz_uint)out_bytes;
pStream->avail_out -= (mz_uint)out_bytes;
pStream->total_out += (mz_uint)out_bytes;
if (defl_status < 0)
{
mz_status = MZ_STREAM_ERROR;
break;
}
else if (defl_status == TDEFL_STATUS_DONE)
{
mz_status = MZ_STREAM_END;
break;
}
else if (!pStream->avail_out)
break;
else if ((!pStream->avail_in) && (flush != MZ_FINISH))
{
if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out))
break;
return MZ_BUF_ERROR; /* Can't make forward progress without some input.
*/
}
}
return mz_status;
}
int mz_deflateEnd(mz_streamp pStream)
{
if (!pStream)
return MZ_STREAM_ERROR;
if (pStream->state)
{
pStream->zfree(pStream->opaque, pStream->state);
pStream->state = NULL;
}
return MZ_OK;
}
mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len)
{
(void)pStream;
/* This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) */
return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5);
}
int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level)
{
int status;
mz_stream stream;
memset(&stream, 0, sizeof(stream));
/* In case mz_ulong is 64-bits (argh I hate longs). */
if ((source_len | *pDest_len) > 0xFFFFFFFFU)
return MZ_PARAM_ERROR;
stream.next_in = pSource;
stream.avail_in = (mz_uint32)source_len;
stream.next_out = pDest;
stream.avail_out = (mz_uint32)*pDest_len;
status = mz_deflateInit(&stream, level);
if (status != MZ_OK)
return status;
status = mz_deflate(&stream, MZ_FINISH);
if (status != MZ_STREAM_END)
{
mz_deflateEnd(&stream);
return (status == MZ_OK) ? MZ_BUF_ERROR : status;
}
*pDest_len = stream.total_out;
return mz_deflateEnd(&stream);
}
int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len)
{
return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION);
}
mz_ulong mz_compressBound(mz_ulong source_len)
{
return mz_deflateBound(NULL, source_len);
}
typedef struct
{
tinfl_decompressor m_decomp;
mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed;
int m_window_bits;
mz_uint8 m_dict[TINFL_LZ_DICT_SIZE];
tinfl_status m_last_status;
} inflate_state;
int mz_inflateInit2(mz_streamp pStream, int window_bits)
{
inflate_state *pDecomp;
if (!pStream)
return MZ_STREAM_ERROR;
if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))
return MZ_PARAM_ERROR;
pStream->data_type = 0;
pStream->adler = 0;
pStream->msg = NULL;
pStream->total_in = 0;
pStream->total_out = 0;
pStream->reserved = 0;
if (!pStream->zalloc)
pStream->zalloc = miniz_def_alloc_func;
if (!pStream->zfree)
pStream->zfree = miniz_def_free_func;
pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state));
if (!pDecomp)
return MZ_MEM_ERROR;
pStream->state = (struct mz_internal_state *)pDecomp;
tinfl_init(&pDecomp->m_decomp);
pDecomp->m_dict_ofs = 0;
pDecomp->m_dict_avail = 0;
pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT;
pDecomp->m_first_call = 1;
pDecomp->m_has_flushed = 0;
pDecomp->m_window_bits = window_bits;
return MZ_OK;
}
int mz_inflateInit(mz_streamp pStream)
{
return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS);
}
int mz_inflate(mz_streamp pStream, int flush)
{
inflate_state *pState;
mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32;
size_t in_bytes, out_bytes, orig_avail_in;
tinfl_status status;
if ((!pStream) || (!pStream->state))
return MZ_STREAM_ERROR;
if (flush == MZ_PARTIAL_FLUSH)
flush = MZ_SYNC_FLUSH;
if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH))
return MZ_STREAM_ERROR;
pState = (inflate_state *)pStream->state;
if (pState->m_window_bits > 0)
decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER;
orig_avail_in = pStream->avail_in;
first_call = pState->m_first_call;
pState->m_first_call = 0;
if (pState->m_last_status < 0)
return MZ_DATA_ERROR;
if (pState->m_has_flushed && (flush != MZ_FINISH))
return MZ_STREAM_ERROR;
pState->m_has_flushed |= (flush == MZ_FINISH);
if ((flush == MZ_FINISH) && (first_call))
{
/* MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. */
decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
in_bytes = pStream->avail_in;
out_bytes = pStream->avail_out;
status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags);
pState->m_last_status = status;
pStream->next_in += (mz_uint)in_bytes;
pStream->avail_in -= (mz_uint)in_bytes;
pStream->total_in += (mz_uint)in_bytes;
pStream->adler = tinfl_get_adler32(&pState->m_decomp);
pStream->next_out += (mz_uint)out_bytes;
pStream->avail_out -= (mz_uint)out_bytes;
pStream->total_out += (mz_uint)out_bytes;
if (status < 0)
return MZ_DATA_ERROR;
else if (status != TINFL_STATUS_DONE)
{
pState->m_last_status = TINFL_STATUS_FAILED;
return MZ_BUF_ERROR;
}
return MZ_STREAM_END;
}
/* flush != MZ_FINISH then we must assume there's more input. */
if (flush != MZ_FINISH)
decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT;
if (pState->m_dict_avail)
{
n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
pStream->next_out += n;
pStream->avail_out -= n;
pStream->total_out += n;
pState->m_dict_avail -= n;
pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;
}
for (;;)
{
in_bytes = pStream->avail_in;
out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs;
status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags);
pState->m_last_status = status;
pStream->next_in += (mz_uint)in_bytes;
pStream->avail_in -= (mz_uint)in_bytes;
pStream->total_in += (mz_uint)in_bytes;
pStream->adler = tinfl_get_adler32(&pState->m_decomp);
pState->m_dict_avail = (mz_uint)out_bytes;
n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
pStream->next_out += n;
pStream->avail_out -= n;
pStream->total_out += n;
pState->m_dict_avail -= n;
pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
if (status < 0)
return MZ_DATA_ERROR; /* Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). */
else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in))
return MZ_BUF_ERROR; /* Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. */
else if (flush == MZ_FINISH)
{
/* The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. */
if (status == TINFL_STATUS_DONE)
return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END;
/* status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. */
else if (!pStream->avail_out)
return MZ_BUF_ERROR;
}
else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail))
break;
}
return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;
}
int mz_inflateEnd(mz_streamp pStream)
{
if (!pStream)
return MZ_STREAM_ERROR;
if (pStream->state)
{
pStream->zfree(pStream->opaque, pStream->state);
pStream->state = NULL;
}
return MZ_OK;
}
int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len)
{
mz_stream stream;
int status;
memset(&stream, 0, sizeof(stream));
/* In case mz_ulong is 64-bits (argh I hate longs). */
if ((source_len | *pDest_len) > 0xFFFFFFFFU)
return MZ_PARAM_ERROR;
stream.next_in = pSource;
stream.avail_in = (mz_uint32)source_len;
stream.next_out = pDest;
stream.avail_out = (mz_uint32)*pDest_len;
status = mz_inflateInit(&stream);
if (status != MZ_OK)
return status;
status = mz_inflate(&stream, MZ_FINISH);
if (status != MZ_STREAM_END)
{
mz_inflateEnd(&stream);
return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status;
}
*pDest_len = stream.total_out;
return mz_inflateEnd(&stream);
}
const char *mz_error(int err)
{
static struct
{
int m_err;
const char *m_pDesc;
} s_error_descs[] =
{
{ MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" }
};
mz_uint i;
for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i)
if (s_error_descs[i].m_err == err)
return s_error_descs[i].m_pDesc;
return NULL;
}
#endif /*MINIZ_NO_ZLIB_APIS */
#ifdef __cplusplus
}
#endif
/*
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
*/
+4
View File
@@ -0,0 +1,4 @@
line 1
line 2
line 3
line 4
+1
View File
@@ -0,0 +1 @@
hello world
+152
View File
@@ -0,0 +1,152 @@
extern crate assert_cmd;
use assert_cmd::prelude::*;
use std::process::Command;
fn bat() -> Command {
let mut cmd = Command::main_binary().unwrap();
cmd.current_dir("tests/examples");
cmd.arg("--no-config");
cmd.env_remove("PAGER");
cmd.env_remove("BAT_PAGER");
cmd
}
#[test]
fn basic() {
bat()
.arg("test.txt")
.assert()
.success()
.stdout("hello world\n")
.stderr("");
}
#[test]
fn stdin() {
bat()
.with_stdin()
.buffer("foo\nbar\n")
.assert()
.success()
.stdout("foo\nbar\n");
}
#[test]
fn concatenate() {
bat()
.arg("test.txt")
.arg("test.txt")
.assert()
.success()
.stdout("hello world\nhello world\n");
}
#[test]
fn concatenate_stdin() {
bat()
.arg("test.txt")
.arg("-")
.arg("test.txt")
.with_stdin()
.buffer("stdin\n")
.assert()
.success()
.stdout("hello world\nstdin\nhello world\n");
}
#[test]
fn line_numbers() {
bat()
.arg("multiline.txt")
.arg("--style=numbers")
.arg("--decorations=always")
.assert()
.success()
.stdout(" 1 line 1\n 2 line 2\n 3 line 3\n 4 line 4\n");
}
#[test]
fn line_range_2_3() {
bat()
.arg("multiline.txt")
.arg("--line-range=2:3")
.assert()
.success()
.stdout("line 2\nline 3\n");
}
#[test]
fn line_range_first_two() {
bat()
.arg("multiline.txt")
.arg("--line-range=:2")
.assert()
.success()
.stdout("line 1\nline 2\n");
}
#[test]
fn line_range_last_3() {
bat()
.arg("multiline.txt")
.arg("--line-range=2:")
.assert()
.success()
.stdout("line 2\nline 3\nline 4\n");
}
#[test]
fn fail_non_existing() {
bat().arg("non-existing-file").assert().failure();
}
#[test]
fn fail_directory() {
bat().arg("sub_directory").assert().failure();
}
#[test]
fn do_not_exit_directory() {
bat()
.arg("sub_directory")
.arg("test.txt")
.assert()
.stdout("hello world\n")
.failure();
}
#[test]
fn pager_basic() {
bat()
.env("PAGER", "echo pager-output")
.arg("--paging=always")
.arg("test.txt")
.assert()
.success()
.stdout("pager-output\n");
}
#[test]
fn pager_overwrite() {
bat()
.env("PAGER", "echo other-pager")
.env("BAT_PAGER", "echo pager-output")
.arg("--paging=always")
.arg("test.txt")
.assert()
.success()
.stdout("pager-output\n");
}
#[test]
fn pager_disable() {
bat()
.env("PAGER", "echo other-pager")
.env("BAT_PAGER", "")
.arg("--paging=always")
.arg("test.txt")
.assert()
.success()
.stdout("hello world\n");
}
+41
View File
@@ -0,0 +1,41 @@
mod tester;
use tester::BatTester;
macro_rules! snapshot_tests {
($($test_name: ident: $style: expr => [wrap: $wrap:expr, tabs: $tabs:expr],)*) => {
$(
#[test]
fn $test_name() {
let bat_tester = BatTester::new();
bat_tester.test_snapshot(stringify!($test_name), $style, $tabs, $wrap);
}
)*
};
}
snapshot_tests! {
changes: "changes" => [wrap: false, tabs: 8],
grid: "grid" => [wrap: false, tabs: 8],
header: "header" => [wrap: false, tabs: 8],
numbers: "numbers" => [wrap: false, tabs: 8],
changes_grid: "changes,grid" => [wrap: false, tabs: 8],
changes_header: "changes,header" => [wrap: false, tabs: 8],
changes_numbers: "changes,numbers" => [wrap: false, tabs: 8],
grid_header: "grid,header" => [wrap: false, tabs: 8],
grid_numbers: "grid,numbers" => [wrap: false, tabs: 8],
header_numbers: "header,numbers" => [wrap: false, tabs: 8],
changes_grid_header: "changes,grid,header" => [wrap: false, tabs: 8],
changes_grid_numbers: "changes,grid,numbers" => [wrap: false, tabs: 8],
changes_header_numbers: "changes,header,numbers" => [wrap: false, tabs: 8],
grid_header_numbers: "grid,header,numbers" => [wrap: false, tabs: 8],
changes_grid_header_numbers: "changes,grid,header,numbers" => [wrap: false, tabs: 8],
full: "full" => [wrap: false, tabs: 8],
plain: "plain" => [wrap: false, tabs: 0],
tabs_passthrough_wrapped: "full" => [wrap: true, tabs: 0],
tabs_4_wrapped: "full" => [wrap: true, tabs: 4],
tabs_8_wrapped: "full" => [wrap: true, tabs: 8],
tabs_passthrough: "full" => [wrap: false, tabs: 0],
tabs_4: "full" => [wrap: false, tabs: 4],
tabs_8: "full" => [wrap: false, tabs: 8],
}

Some files were not shown because too many files have changed in this diff Show More