mirror of
https://github.com/sharkdp/bat
synced 2026-08-04 19:01:44 +00:00
Compare commits
175 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 238482e5f3 | |||
| 79b960e17e | |||
| 6aa626f1c4 | |||
| 1b30539493 | |||
| 96b24d8a7e | |||
| 20b02e72b3 | |||
| 254efac9c2 | |||
| dcec322117 | |||
| d781156327 | |||
| 732750c274 | |||
| 6b6baa3118 | |||
| 54c434934e | |||
| ad6e0a2581 | |||
| bd619db3ca | |||
| e098eb43a2 | |||
| ea369ee17f | |||
| 63d32bc818 | |||
| dccf8d8221 | |||
| 97129ab9d8 | |||
| 52d0d6ca30 | |||
| a05494e9d9 | |||
| 84ac92efbb | |||
| b4c6e412dc | |||
| 3e21d69a92 | |||
| b7690d4bb1 | |||
| d404139ff7 | |||
| 9ef1e9f792 | |||
| 503fe0b641 | |||
| 1807f9653c | |||
| 1e74f0e2a9 | |||
| c1e1f753cf | |||
| d90797f8e9 | |||
| b4096e5627 | |||
| 4e3ab4d399 | |||
| f0d936763c | |||
| 7897260bf0 | |||
| eb6e43b9a9 | |||
| 7cdcdbb31d | |||
| 9159341714 | |||
| b23ff24ebc | |||
| e1ecc17f69 | |||
| 0fe3badf19 | |||
| 89d4cb951a | |||
| e9681bf22d | |||
| 1b6df8a480 | |||
| cf24986edb | |||
| b9c556a0b6 | |||
| 9d6bde48fa | |||
| d6c8fee044 | |||
| 8b4abb03db | |||
| 375cf76e15 | |||
| 1a4acc435e | |||
| d8030626f8 | |||
| fb61aa4f60 | |||
| 76df41fa97 | |||
| 97efd75cee | |||
| 53d0c1deca | |||
| 155179a07a | |||
| ba00caf9c3 | |||
| ac418ba21c | |||
| acde83af31 | |||
| 021a68eb21 | |||
| 566aab3b05 | |||
| f88eba6476 | |||
| 1d9e7ac4c2 | |||
| 80ae2ecbf8 | |||
| 96d4492d27 | |||
| c90f0b8e21 | |||
| 4b866ab6af | |||
| 2dbd91e543 | |||
| 785da3d9df | |||
| d455cb7c32 | |||
| d2b4766f92 | |||
| 5cf92b4f94 | |||
| 7b803a50af | |||
| 67ec5fe2b7 | |||
| 3447ed4def | |||
| 532fb921a6 | |||
| ba4d5a2e7d | |||
| 026273a05c | |||
| 8903b64830 | |||
| 194155f062 | |||
| a6ff3b900d | |||
| 8a52bcf92d | |||
| 0b1535f63b | |||
| 0a5b3eaf3e | |||
| 11294249f8 | |||
| 35a1236ad0 | |||
| af8da50c2c | |||
| 649d1e3df2 | |||
| 199cfd4519 | |||
| c7cce0752b | |||
| 3a89486189 | |||
| 720a2fb7a5 | |||
| e3c990f11e | |||
| 90c7d0c365 | |||
| 56002267d2 | |||
| 84734eac9d | |||
| acdea97e71 | |||
| 839e4ee611 | |||
| c7afcdebf8 | |||
| 08e6db1581 | |||
| 4d08ecd828 | |||
| 28e1d0e613 | |||
| d11839ad03 | |||
| 8cacd9b432 | |||
| 6f67444c99 | |||
| fd2b376ea0 | |||
| cda54e4f61 | |||
| 3b90ada735 | |||
| 1837d364fe | |||
| 4ea3e6bbb7 | |||
| 38544ed735 | |||
| 5444b0dfed | |||
| f3dde0185d | |||
| 2e3784aa30 | |||
| 1088455702 | |||
| 4f812c32ab | |||
| b6c59a5bd4 | |||
| b682679776 | |||
| 81771432fb | |||
| 627181bcb6 | |||
| 226d9a573a | |||
| 246cf79dbd | |||
| ea955c734d | |||
| 6223ad6d52 | |||
| 31a9335bd5 | |||
| 9316f2a758 | |||
| c884c3cc12 | |||
| 08850f0474 | |||
| 8e6c5bc562 | |||
| 052425b12f | |||
| 2df3305b94 | |||
| 6882fc1512 | |||
| 2508323264 | |||
| 297afad337 | |||
| 1dddce3aa1 | |||
| 76be0d3933 | |||
| e5b8c4471a | |||
| b191691767 | |||
| 5c95b8803b | |||
| 5b421b455d | |||
| a6d6c28723 | |||
| 2966939e38 | |||
| d179693d1d | |||
| 268577c6f9 | |||
| 037861e588 | |||
| 94ccc646e8 | |||
| 0cc5d1dab6 | |||
| 28397b8f78 | |||
| c899849101 | |||
| bf53b64125 | |||
| c68aa0f424 | |||
| 6b57f4eebc | |||
| 0ddd388a29 | |||
| 34811b8161 | |||
| 8b92aae23f | |||
| 3a0941cabe | |||
| 52877c6d67 | |||
| 455de98a89 | |||
| 8c6a74a6c5 | |||
| 3f8b340ed8 | |||
| 65e6970907 | |||
| 90cc019482 | |||
| eaf0b99d25 | |||
| 3b1dcca5d0 | |||
| 26dbdf4fa0 | |||
| 6691786d82 | |||
| 50209bfe21 | |||
| c91511cca1 | |||
| c9f7a0c126 | |||
| 69c798eafd | |||
| 195d5e0e16 | |||
| 86c1777205 | |||
| 16874ab016 |
+52
-1
@@ -24,7 +24,7 @@
|
||||
url = https://github.com/clintberry/sublime-text-2-ini
|
||||
[submodule "assets/syntaxes/CMake"]
|
||||
path = assets/syntaxes/CMake
|
||||
url = https://github.com/sharkdp/Sublime-CMakeLists
|
||||
url = https://github.com/zyxar/Sublime-CMakeLists
|
||||
[submodule "assets/syntaxes/LESS"]
|
||||
path = assets/syntaxes/LESS
|
||||
url = https://github.com/danro/LESS-sublime
|
||||
@@ -40,3 +40,54 @@
|
||||
[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
|
||||
|
||||
+21
-18
@@ -17,18 +17,30 @@ matrix:
|
||||
- os: osx
|
||||
rust: stable
|
||||
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.
|
||||
- os: linux
|
||||
rust: 1.24.0
|
||||
rust: 1.26.0
|
||||
env: TARGET=x86_64-unknown-linux-gnu
|
||||
- os: linux
|
||||
rust: 1.24.0
|
||||
rust: 1.26.0
|
||||
env:
|
||||
- TARGET=x86_64-unknown-linux-musl
|
||||
- CC_x86_64_unknown_linux_musl=/usr/bin/musl-gcc
|
||||
- os: osx
|
||||
rust: 1.24.0
|
||||
rust: 1.26.0
|
||||
env: TARGET=x86_64-apple-darwin
|
||||
|
||||
# Code formatting check
|
||||
@@ -39,15 +51,10 @@ matrix:
|
||||
- cargo install --debug --force rustfmt-nightly
|
||||
script: cargo fmt -- --check
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
# needed for i686-unknown-linux-gnu target
|
||||
- gcc-multilib
|
||||
# needed for musl targets
|
||||
- musl-tools
|
||||
# needed to build deb packages
|
||||
- fakeroot
|
||||
sudo: required
|
||||
|
||||
before_install:
|
||||
- ci/before_install.bash
|
||||
|
||||
env:
|
||||
global:
|
||||
@@ -62,11 +69,7 @@ install:
|
||||
- if [[ $TRAVIS_OS_NAME = linux && $HOST != $TARGET ]]; then rustup target add $TARGET; fi
|
||||
|
||||
script:
|
||||
# Incorporate TARGET env var to the build and test process
|
||||
- cargo build --target $TARGET --verbose
|
||||
- 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
|
||||
- ci/script.bash
|
||||
|
||||
before_deploy:
|
||||
- bash ci/before_deploy.bash
|
||||
|
||||
Generated
+346
-318
File diff suppressed because it is too large
Load Diff
+13
-5
@@ -7,13 +7,18 @@ license = "MIT/Apache-2.0"
|
||||
name = "bat"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/sharkdp/bat"
|
||||
version = "0.4.0"
|
||||
version = "0.7.1"
|
||||
exclude = [
|
||||
"assets/syntaxes/*",
|
||||
"assets/themes/*",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
atty = "0.2.2"
|
||||
ansi_term = "0.10"
|
||||
ansi_term = "0.11"
|
||||
ansi_colours = "^1.0"
|
||||
console = "0.6"
|
||||
directories = "0.10"
|
||||
directories = "1.0"
|
||||
lazy_static = "1.0"
|
||||
|
||||
[dependencies.git2]
|
||||
@@ -27,11 +32,14 @@ default-features = false
|
||||
features = ["parsing", "yaml-load", "dump-load", "dump-create"]
|
||||
|
||||
[dependencies.clap]
|
||||
version = "2"
|
||||
version = "2.32"
|
||||
default-features = false
|
||||
features = ["suggestions", "color", "wrap_help"]
|
||||
|
||||
[dependencies.error-chain]
|
||||
version = "0.11"
|
||||
version = "0.12"
|
||||
default-features = false
|
||||
features = []
|
||||
|
||||
[dev-dependencies]
|
||||
tempdir = "0.3"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<p align="center">
|
||||
<img src="doc/logo-header.svg" alt="bat - a cat clone with wings"><br>
|
||||
<a href="Version info"><img src="https://travis-ci.org/sharkdp/bat.svg?branch=master" alt="Build Status"></a>
|
||||
<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.
|
||||
@@ -71,28 +72,37 @@ bat header.md content.md footer.md > document.md
|
||||
|
||||
bat -n main.rs # show line numbers (only)
|
||||
|
||||
cat f - g # output 'f', then stdin, then 'g'.
|
||||
bat f - g # output 'f', then stdin, then 'g'.
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
### From binaries
|
||||
### On Ubuntu
|
||||
*... and other Debian-based Linux distributions.*
|
||||
|
||||
Check out the [Release page](https://github.com/sharkdp/bat/releases) for
|
||||
binary builds and Debian packages.
|
||||
|
||||
#### 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
|
||||
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.7.1_amd64.deb # adapt version number and architecture
|
||||
```
|
||||
|
||||
#### On FreeBSD
|
||||
### 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:
|
||||
|
||||
@@ -107,7 +117,35 @@ cd /usr/ports/textproc/bat
|
||||
make install
|
||||
```
|
||||
|
||||
#### On macOS
|
||||
### 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
|
||||
|
||||
### On macOS
|
||||
|
||||
You can install `bat` with [Homebrew](http://braumeister.org/formula/bat):
|
||||
|
||||
@@ -115,82 +153,199 @@ You can install `bat` with [Homebrew](http://braumeister.org/formula/bat):
|
||||
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.
|
||||
|
||||
### From binaries
|
||||
|
||||
Check out the [Release page](https://github.com/sharkdp/bat/releases) for
|
||||
prebuilt versions of `bat` for many different architectures.
|
||||
|
||||
### 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.26 or
|
||||
higher. You can then use `cargo` to build everything:
|
||||
|
||||
```bash
|
||||
cargo install bat
|
||||
```
|
||||
|
||||
On macOS, you might have to install `cmake` (`brew install cmake`) in order for
|
||||
some dependencies to be built.
|
||||
You may have to install `cmake` and the `libz` development package
|
||||
(`libz-dev` or `libz-devel`) in order for the build to succeed.
|
||||
|
||||
## Customization
|
||||
|
||||
### Highlighting theme
|
||||
|
||||
Use `bat --list-themes` to get a list of all available themes for syntax
|
||||
highlighting. To select the `TwoDark` theme, for example, call `bat` with
|
||||
the `--theme=TwoDark` option. Use `alias bat="bat --theme=TwoDark"` in your
|
||||
shells startup file to make the change permanent.
|
||||
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.
|
||||
|
||||
### 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.
|
||||
and line numbers but no grid and no file header. Use the `BAT_STYLE` environment
|
||||
variable to make these changes permanent.
|
||||
|
||||
### Add new syntaxes and highlighting themes
|
||||
### Adding new syntaxes / language definitions
|
||||
|
||||
`bat` uses the excellent [`syntect`](https://github.com/trishume/syntect/)
|
||||
library for syntax highlighting. `syntect` can read any
|
||||
[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)"
|
||||
|
||||
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)"
|
||||
|
||||
mkdir -p "$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/greggb/sublime-snazzy
|
||||
|
||||
# Create a link for the default theme
|
||||
ln -sf "sublime-snazzy/Sublime Snazzy.tmTheme" Default.tmTheme
|
||||
```
|
||||
|
||||
Create a folder with language definition files:
|
||||
|
||||
```bash
|
||||
mkdir -p "$BAT_CONFIG_DIR/syntaxes"
|
||||
cd "$BAT_CONFIG_DIR/syntaxes"
|
||||
|
||||
# Download some language definition files, for example:
|
||||
git clone https://github.com/sublimehq/Packages
|
||||
git clone https://github.com/danro/LESS-sublime
|
||||
```
|
||||
|
||||
Finally, use the following command to parse all these files into a binary
|
||||
cache:
|
||||
|
||||
```bash
|
||||
# Update the binary cache
|
||||
bat cache --init
|
||||
```
|
||||
|
||||
Use `bat --list-languages` and `bat --list-themes` to check if all languages and themes are
|
||||
available.
|
||||
Finally, use `bat --list-themes` to check if the new themes are available.
|
||||
|
||||
If you ever want to go back to the default settings, call:
|
||||
### Using a different pager
|
||||
|
||||
`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
|
||||
bat cache --clear
|
||||
#!/bin/bash
|
||||
|
||||
less --tabs 4 -RF "$@"
|
||||
```
|
||||
|
||||
## 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
|
||||
don’t 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
|
||||
|
||||
@@ -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
|
||||
@@ -29,3 +29,5 @@ themes (`bat cache --clear`).
|
||||
The following files have been manually modified after converting from a `.tmLanguage` file:
|
||||
|
||||
* `VimL.sublime-syntax` => added `.vimrc` file type.
|
||||
* `Dart.sublime-syntax` => removed `#regex.dart` include.
|
||||
* `INI.sublime-syntax` => added `.hgrc` and `hgrc` file types.
|
||||
|
||||
+1
-1
@@ -2,4 +2,4 @@
|
||||
|
||||
ASSET_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
bat cache --init --source="$ASSET_DIR" --target="$ASSET_DIR"
|
||||
bat cache --init --blank --source="$ASSET_DIR" --target="$ASSET_DIR"
|
||||
|
||||
Binary file not shown.
Submodule
+1
Submodule assets/syntaxes/AWK added at 1ce5f90d44
+1
-1
Submodule assets/syntaxes/CMake updated: a71f52a390...aba96a0862
Submodule
+1
Submodule assets/syntaxes/CSV added at 4786d037a7
@@ -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
|
||||
Submodule
+1
Submodule assets/syntaxes/Cabal added at 1c054d9b36
@@ -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
|
||||
Submodule
+1
Submodule assets/syntaxes/Crystal added at 2f96cec2ca
File diff suppressed because it is too large
Load Diff
Submodule
+1
Submodule assets/syntaxes/Dart added at d891fb36c9
@@ -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
+1
Submodule assets/syntaxes/Elm added at dfbb8bdc9a
Submodule
+1
Submodule assets/syntaxes/FSharp added at da846f4227
@@ -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
|
||||
@@ -15,6 +15,8 @@ file_extensions:
|
||||
- url
|
||||
- URL
|
||||
- .editorconfig
|
||||
- .hgrc
|
||||
- hgrc
|
||||
scope: source.ini
|
||||
contexts:
|
||||
main:
|
||||
|
||||
Submodule
+1
Submodule assets/syntaxes/JavaScript (Babel) added at a9a908fe1d
File diff suppressed because it is too large
Load Diff
Submodule
+1
Submodule assets/syntaxes/Kotlin added at aeeed2780b
@@ -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
|
||||
+1
-1
Submodule assets/syntaxes/LESS updated: 46694c86b9...d3ddfe7b51
Submodule
+1
Submodule assets/syntaxes/Nix added at ebf06571f3
@@ -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
|
||||
+1
-1
Submodule assets/syntaxes/Packages updated: 1cb4c3ec36...289782ff2e
Submodule
+1
Submodule assets/syntaxes/PowerShell added at 12b7d7257e
@@ -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
|
||||
Submodule
+1
Submodule assets/syntaxes/Puppet added at 2a224343d2
Submodule
+1
Submodule assets/syntaxes/PureScript added at 42a61e39ad
Submodule
+1
Submodule assets/syntaxes/Swift added at fef17119ce
@@ -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
|
||||
Submodule
+1
Submodule assets/syntaxes/TypeScript added at 19a599ad0e
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
Binary file not shown.
Submodule assets/themes/1337-Scheme updated: 82db0222c3...ca6a329cfd
@@ -1 +0,0 @@
|
||||
sublime-monokai-extended/Monokai Extended.tmTheme
|
||||
Submodule
+1
Submodule assets/themes/onehalf added at 2516b37c3f
Submodule
+1
Submodule assets/themes/zenburn added at b7f27e2f65
+31
-5
@@ -11,19 +11,29 @@ pack() {
|
||||
local tempdir
|
||||
local out_dir
|
||||
local package_name
|
||||
local gcc_prefix
|
||||
|
||||
tempdir=$(mktemp -d 2>/dev/null || mktemp -d -t tmp)
|
||||
out_dir=$(pwd)
|
||||
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
|
||||
mkdir "$tempdir/$package_name"
|
||||
|
||||
# copying the main binary
|
||||
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 LICENSE-MIT "$tempdir/$package_name"
|
||||
cp LICENSE-APACHE "$tempdir/$package_name"
|
||||
@@ -41,17 +51,28 @@ make_deb() {
|
||||
local version
|
||||
local dpkgname
|
||||
local conflictname
|
||||
local gcc_prefix
|
||||
|
||||
case $TARGET in
|
||||
x86_64*)
|
||||
architecture=amd64
|
||||
gcc_prefix=""
|
||||
;;
|
||||
i686*)
|
||||
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
|
||||
return 1
|
||||
echo "make_deb: skipping target '${TARGET}'" >&2
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
version=${TRAVIS_TAG#v}
|
||||
@@ -67,7 +88,11 @@ make_deb() {
|
||||
|
||||
# copy the main binary
|
||||
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
|
||||
install -Dm644 README.md "$tempdir/usr/share/doc/$PROJECT_NAME/README.md"
|
||||
@@ -86,6 +111,7 @@ Architecture: $architecture
|
||||
Provides: $PROJECT_NAME
|
||||
Conflicts: $conflictname
|
||||
Description: A cat(1) clone with wings.
|
||||
A cat(1) clone with syntax highlighting and Git integration.
|
||||
EOF
|
||||
|
||||
fakeroot dpkg-deb --build "$tempdir" "${dpkgname}_${version}_${architecture}.deb"
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# 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" '.\'
|
||||
|
||||
# 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
|
||||
Executable
+37
@@ -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
@@ -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
|
||||
+5
-2
@@ -6,10 +6,10 @@ if you are not looking for a program like `bat`, this comparison might not be fo
|
||||
|
||||
| | 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: |
|
||||
| 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) | 60 | 300 | 200 | 7 | 80 | 130 | 30 | 130 |
|
||||
| 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 |
|
||||
@@ -18,3 +18,6 @@ if you are not looking for a program like `bat`, this comparison might not be fo
|
||||
|
||||
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)
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
.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\-\-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
|
||||
.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. [default: auto] [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. [default: auto] [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. [default: auto] [possible values: auto, never, always]
|
||||
.HP
|
||||
\fB\-\-wrap\fR <mode>
|
||||
.TP
|
||||
Specify the text\-wrapping mode. [default: auto]
|
||||
[possible values: auto,
|
||||
.IP
|
||||
never, character]
|
||||
.HP
|
||||
\fB\-u\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\-\-tabs\fR <tabs>
|
||||
.IP
|
||||
Sets the tab width. Use a width of 0 to pass tabs through directly
|
||||
.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
|
||||
+391
-234
@@ -1,14 +1,88 @@
|
||||
use atty::{self, Stream};
|
||||
use clap::{App as ClapApp, AppSettings, Arg, ArgGroup, ArgMatches, SubCommand};
|
||||
use console::Term;
|
||||
use errors::*;
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use style::{OutputComponent, OutputComponents, OutputWrap};
|
||||
use std::path::Path;
|
||||
use std::str::FromStr;
|
||||
|
||||
use atty::{self, Stream};
|
||||
|
||||
use clap::{App as ClapApp, AppSettings, Arg, ArgGroup, ArgMatches, SubCommand};
|
||||
|
||||
use console::Term;
|
||||
|
||||
#[cfg(windows)]
|
||||
use ansi_term;
|
||||
|
||||
use assets::BAT_THEME_DEFAULT;
|
||||
use errors::*;
|
||||
use line_range::LineRange;
|
||||
use style::{OutputComponent, OutputComponents, OutputWrap};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum PagingMode {
|
||||
Always,
|
||||
QuitIfOneScreen,
|
||||
Never,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum InputFile<'a> {
|
||||
StdIn,
|
||||
Ordinary(&'a str),
|
||||
ThemePreviewFile,
|
||||
}
|
||||
|
||||
#[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,
|
||||
}
|
||||
|
||||
fn is_truecolor_terminal() -> bool {
|
||||
env::var("COLORTERM")
|
||||
.map(|colorterm| colorterm == "truecolor" || colorterm == "24bit")
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Helper function that should might appear in Rust stable at some point
|
||||
/// (https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.transpose)
|
||||
fn transpose<T>(opt: Option<Result<T>>) -> Result<Option<T>> {
|
||||
opt.map_or(Ok(None), |res| res.map(Some))
|
||||
}
|
||||
|
||||
pub struct App {
|
||||
pub matches: ArgMatches<'static>,
|
||||
interactive_output: bool,
|
||||
@@ -16,10 +90,10 @@ pub struct App {
|
||||
|
||||
impl App {
|
||||
pub fn new() -> Self {
|
||||
let interactive_output = atty::is(Stream::Stdout);
|
||||
|
||||
#[cfg(windows)]
|
||||
let interactive_output = interactive_output && ansi_term::enable_ansi_support().is_ok();
|
||||
let _ = ansi_term::enable_ansi_support();
|
||||
|
||||
let interactive_output = atty::is(Stream::Stdout);
|
||||
|
||||
App {
|
||||
matches: Self::matches(interactive_output),
|
||||
@@ -34,6 +108,10 @@ impl App {
|
||||
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)
|
||||
@@ -48,188 +126,264 @@ impl App {
|
||||
.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),
|
||||
)
|
||||
.long_about("A cat(1) clone with syntax highlighting and Git integration.")
|
||||
.arg(
|
||||
Arg::with_name("language")
|
||||
.short("l")
|
||||
.long("language")
|
||||
.overrides_with("language")
|
||||
.help("Set the language for highlighting")
|
||||
.help("Set the language for syntax highlighting.")
|
||||
.long_help(
|
||||
"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("FILE")
|
||||
.help("File(s) to print / concatenate. Use '-' for standard input.")
|
||||
.long_help(
|
||||
"File(s) to print. Use no argument or '-' to read from standard \
|
||||
input",
|
||||
)
|
||||
.multiple(true)
|
||||
.empty_values(false),
|
||||
)
|
||||
.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",
|
||||
])
|
||||
.default_value("auto")
|
||||
.help("Comma-separated list of style elements to display")
|
||||
.long_help(
|
||||
"Configure which elements (line numbers, file headers, grid \
|
||||
"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("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.")
|
||||
.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')",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("color")
|
||||
.long("color")
|
||||
.overrides_with("color")
|
||||
.takes_value(true)
|
||||
.value_name("when")
|
||||
.possible_values(&["auto", "never", "always"])
|
||||
.default_value("auto")
|
||||
.help("When to use colors"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("paging")
|
||||
.long("paging")
|
||||
.overrides_with("paging")
|
||||
.takes_value(true)
|
||||
.value_name("when")
|
||||
.possible_values(&["auto", "never", "always"])
|
||||
.default_value("auto")
|
||||
.help("When to use the pager")
|
||||
.long_help("Specify when to use the pager (less)"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("wrap")
|
||||
.long("wrap")
|
||||
.overrides_with("wrap")
|
||||
.takes_value(true)
|
||||
.value_name("mode")
|
||||
.possible_values(&["character", "never"])
|
||||
.default_value("character")
|
||||
.help("When to wrap text"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("list-languages")
|
||||
.long("list-languages")
|
||||
.help("Displays supported languages")
|
||||
.long_help("Display a list of supported languages"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("theme")
|
||||
.long("theme")
|
||||
.overrides_with("theme")
|
||||
.takes_value(true)
|
||||
.help("Set the theme for highlighting")
|
||||
.long_help(
|
||||
"Set the theme for syntax highlighting. Use '--list-themes' to \
|
||||
see all available themes",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("list-themes")
|
||||
.long("list-themes")
|
||||
.help("Displays supported themes")
|
||||
.help("Display a list of supported themes for syntax highlighting"),
|
||||
)
|
||||
.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(
|
||||
"Show line numbers (no other decorations). This is an alias for \
|
||||
pre-defined style ('full'). To set a default theme, export the \
|
||||
BAT_STYLE environment variable (e.g.: export BAT_STYLE=\"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("unbuffered")
|
||||
.short("u")
|
||||
.help("(ignored)")
|
||||
// TODO: use '.hidden_short_help(true)' when the next clap version is released
|
||||
.long_help(
|
||||
"This option exists for POSIX-compliance reasons ('u' is for \
|
||||
),
|
||||
).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"])
|
||||
.default_value("auto")
|
||||
.help("When to use colors.")
|
||||
.long_help("Specify when to use colored output. The automatic mode \
|
||||
only enables colors if an interactive terminal is detected."),
|
||||
).arg(
|
||||
Arg::with_name("decorations")
|
||||
.long("decorations")
|
||||
.overrides_with("decorations")
|
||||
.takes_value(true)
|
||||
.value_name("when")
|
||||
.possible_values(&["auto", "never", "always"])
|
||||
.default_value("auto")
|
||||
.help("When to show the decorations specified by '--style'.")
|
||||
.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."),
|
||||
).arg(
|
||||
Arg::with_name("paging")
|
||||
.long("paging")
|
||||
.overrides_with("paging")
|
||||
.takes_value(true)
|
||||
.value_name("when")
|
||||
.possible_values(&["auto", "never", "always"])
|
||||
.default_value("auto")
|
||||
.help("Specify when to use the pager.")
|
||||
.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."),
|
||||
).arg(
|
||||
Arg::with_name("wrap")
|
||||
.long("wrap")
|
||||
.overrides_with("wrap")
|
||||
.takes_value(true)
|
||||
.value_name("mode")
|
||||
.possible_values(&["auto", "never", "character"])
|
||||
.default_value("auto")
|
||||
.help("Specify the text-wrapping mode.")
|
||||
.long_help("Specify the text-wrapping mode."),
|
||||
).arg(
|
||||
Arg::with_name("unbuffered")
|
||||
.short("u")
|
||||
.hidden_short_help(true)
|
||||
.long_help(
|
||||
"This option exists for POSIX-compliance reasons ('u' is for \
|
||||
'unbuffered'). The output is always unbuffered - this option \
|
||||
it simply ignored.",
|
||||
is simply ignored.",
|
||||
),
|
||||
).arg(
|
||||
Arg::with_name("tabs")
|
||||
.long("tabs")
|
||||
.takes_value(true)
|
||||
.value_name("tabs")
|
||||
.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("Sets the tab width.")
|
||||
.long_help("Sets the tab width. Use a width of 0 to pass tabs through \
|
||||
directly"),
|
||||
).arg(
|
||||
Arg::with_name("terminal-width")
|
||||
.long("terminal-width")
|
||||
.takes_value(true)
|
||||
.value_name("width")
|
||||
.hidden(true)
|
||||
.help("Set the width of the terminal"),
|
||||
).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.",
|
||||
),
|
||||
)
|
||||
.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("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),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("source")
|
||||
.long("source")
|
||||
.requires("init")
|
||||
.takes_value(true)
|
||||
.value_name("dir")
|
||||
.help("Use a different source for loading syntaxes and themes from"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("target")
|
||||
.long("target")
|
||||
.requires("init")
|
||||
.takes_value(true)
|
||||
.value_name("dir")
|
||||
.help(
|
||||
"Use a different source to store the cached syntax and theme set",
|
||||
),
|
||||
),
|
||||
)
|
||||
.help_message("Print this help message.")
|
||||
).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.")
|
||||
.get_matches()
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Ok(Config {
|
||||
true_color: is_truecolor_terminal(),
|
||||
output_components: self.output_components()?,
|
||||
language: self.matches.value_of("language"),
|
||||
output_wrap: if !self.interactive_output {
|
||||
// We don't have the tty width when piping to another program.
|
||||
@@ -238,7 +392,12 @@ impl App {
|
||||
} else {
|
||||
match self.matches.value_of("wrap") {
|
||||
Some("character") => OutputWrap::Character,
|
||||
Some("never") | _ => OutputWrap::None,
|
||||
Some("never") => OutputWrap::None,
|
||||
Some("auto") | _ => if output_components.plain() {
|
||||
OutputWrap::None
|
||||
} else {
|
||||
OutputWrap::Character
|
||||
},
|
||||
}
|
||||
},
|
||||
colored_output: match self.matches.value_of("color") {
|
||||
@@ -246,86 +405,84 @@ impl App {
|
||||
Some("never") => false,
|
||||
Some("auto") | _ => self.interactive_output,
|
||||
},
|
||||
paging_mode: match self.matches.value_of("paging") {
|
||||
Some("always") => PagingMode::Always,
|
||||
Some("never") => PagingMode::Never,
|
||||
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.
|
||||
if self.interactive_output && !atty::is(Stream::Stdin) {
|
||||
PagingMode::QuitIfOneScreen
|
||||
} else {
|
||||
PagingMode::Never
|
||||
}
|
||||
} else {
|
||||
if self.interactive_output {
|
||||
PagingMode::QuitIfOneScreen
|
||||
} else {
|
||||
PagingMode::Never
|
||||
}
|
||||
},
|
||||
},
|
||||
term_width: Term::stdout().size().1 as usize,
|
||||
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,
|
||||
theme: self.matches.value_of("theme"),
|
||||
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,
|
||||
})
|
||||
}
|
||||
|
||||
fn files(&self) -> Vec<Option<&str>> {
|
||||
fn files(&self) -> Vec<InputFile> {
|
||||
self.matches
|
||||
.values_of("FILE")
|
||||
.map(|values| {
|
||||
values
|
||||
.map(|filename| {
|
||||
if filename == "-" {
|
||||
None
|
||||
InputFile::StdIn
|
||||
} else {
|
||||
Some(filename)
|
||||
InputFile::Ordinary(filename)
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_else(|| vec![None]) // read from stdin (None) if no args are given
|
||||
}).collect()
|
||||
}).unwrap_or_else(|| vec![InputFile::StdIn])
|
||||
}
|
||||
|
||||
fn output_components(&self) -> Result<OutputComponents> {
|
||||
let matches = &self.matches;
|
||||
Ok(OutputComponents(if matches.is_present("number") {
|
||||
[OutputComponent::Numbers].iter().cloned().collect()
|
||||
} else {
|
||||
values_t!(matches.values_of("style"), OutputComponent)?
|
||||
.into_iter()
|
||||
.map(|style| style.components(self.interactive_output))
|
||||
.fold(HashSet::new(), |mut acc, components| {
|
||||
acc.extend(components.iter().cloned());
|
||||
acc
|
||||
})
|
||||
}))
|
||||
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
|
||||
})
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum PagingMode {
|
||||
Always,
|
||||
QuitIfOneScreen,
|
||||
Never,
|
||||
}
|
||||
|
||||
pub struct Config<'a> {
|
||||
pub true_color: bool,
|
||||
pub output_wrap: OutputWrap,
|
||||
pub output_components: OutputComponents,
|
||||
pub language: Option<&'a str>,
|
||||
pub colored_output: bool,
|
||||
pub paging_mode: PagingMode,
|
||||
pub term_width: usize,
|
||||
pub files: Vec<Option<&'a str>>,
|
||||
pub theme: Option<&'a str>,
|
||||
}
|
||||
|
||||
fn is_truecolor_terminal() -> bool {
|
||||
env::var("COLORTERM")
|
||||
.map(|colorterm| colorterm == "truecolor" || colorterm == "24bit")
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
+85
-35
@@ -1,8 +1,8 @@
|
||||
use directories::ProjectDirs;
|
||||
use errors::*;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs::{self, File};
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
use syntect::dumps::{dump_to_file, from_binary, from_reader};
|
||||
use syntect::highlighting::{Theme, ThemeSet};
|
||||
@@ -11,10 +11,15 @@ use syntect::parsing::{SyntaxDefinition, SyntaxSet};
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::FileTypeExt;
|
||||
|
||||
use app::InputFile;
|
||||
|
||||
lazy_static! {
|
||||
static ref PROJECT_DIRS: ProjectDirs = ProjectDirs::from("", "", crate_name!());
|
||||
static ref PROJECT_DIRS: ProjectDirs =
|
||||
ProjectDirs::from("", "", crate_name!()).expect("Could not get home directory");
|
||||
}
|
||||
|
||||
pub const BAT_THEME_DEFAULT: &str = "Monokai Extended";
|
||||
|
||||
pub struct HighlightingAssets {
|
||||
pub syntax_set: SyntaxSet,
|
||||
pub theme_set: ThemeSet,
|
||||
@@ -25,31 +30,49 @@ impl HighlightingAssets {
|
||||
Self::from_cache().unwrap_or_else(|_| Self::from_binary())
|
||||
}
|
||||
|
||||
pub fn from_files(dir: Option<&Path>) -> Result<Self> {
|
||||
let source_dir = dir.unwrap_or_else(|| PROJECT_DIRS.config_dir());
|
||||
|
||||
let theme_dir = source_dir.join("themes");
|
||||
let theme_set = ThemeSet::load_from_folder(&theme_dir).chain_err(|| {
|
||||
format!(
|
||||
"Could not load themes from '{}'",
|
||||
theme_dir.to_string_lossy()
|
||||
)
|
||||
})?;
|
||||
fn empty() -> Self {
|
||||
let mut syntax_set = SyntaxSet::new();
|
||||
let syntax_dir = source_dir.join("syntaxes");
|
||||
if !syntax_dir.exists() {
|
||||
return Err(format!(
|
||||
"Could not load syntaxes from '{}'",
|
||||
syntax_dir.to_string_lossy()
|
||||
).into());
|
||||
}
|
||||
syntax_set.load_syntaxes(syntax_dir, true)?;
|
||||
syntax_set.load_plain_text_syntax();
|
||||
|
||||
Ok(HighlightingAssets {
|
||||
let theme_set = ThemeSet {
|
||||
themes: BTreeMap::new(),
|
||||
};
|
||||
HighlightingAssets {
|
||||
syntax_set,
|
||||
theme_set,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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 assets = if start_empty {
|
||||
Self::empty()
|
||||
} else {
|
||||
Self::from_binary_unlinked()
|
||||
};
|
||||
|
||||
let theme_dir = source_dir.join("themes");
|
||||
|
||||
let res = extend_theme_set(&mut assets.theme_set, &theme_dir);
|
||||
if !res.is_ok() {
|
||||
println!(
|
||||
"No themes were found in '{}', using the default set",
|
||||
theme_dir.to_string_lossy()
|
||||
);
|
||||
}
|
||||
|
||||
let syntax_dir = source_dir.join("syntaxes");
|
||||
if syntax_dir.exists() {
|
||||
assets.syntax_set.load_syntaxes(syntax_dir, true)?;
|
||||
} else {
|
||||
println!(
|
||||
"No syntaxes were found in '{}', using the default set.",
|
||||
syntax_dir.to_string_lossy()
|
||||
);
|
||||
}
|
||||
|
||||
Ok(assets)
|
||||
}
|
||||
|
||||
fn from_cache() -> Result<Self> {
|
||||
@@ -79,9 +102,8 @@ impl HighlightingAssets {
|
||||
})
|
||||
}
|
||||
|
||||
fn from_binary() -> Self {
|
||||
let mut syntax_set: SyntaxSet = from_binary(include_bytes!("../assets/syntaxes.bin"));
|
||||
syntax_set.link_syntaxes();
|
||||
fn from_binary_unlinked() -> Self {
|
||||
let syntax_set: SyntaxSet = from_binary(include_bytes!("../assets/syntaxes.bin"));
|
||||
let theme_set: ThemeSet = from_binary(include_bytes!("../assets/themes.bin"));
|
||||
|
||||
HighlightingAssets {
|
||||
@@ -90,6 +112,12 @@ impl HighlightingAssets {
|
||||
}
|
||||
}
|
||||
|
||||
fn from_binary() -> Self {
|
||||
let mut assets = Self::from_binary_unlinked();
|
||||
assets.syntax_set.link_syntaxes();
|
||||
assets
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -123,19 +151,25 @@ impl HighlightingAssets {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_theme(&self, theme: &str) -> Result<&Theme> {
|
||||
Ok(self.theme_set.themes.get(theme).ok_or_else(|| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("Could not find '{}' theme", theme),
|
||||
)
|
||||
})?)
|
||||
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: Option<&str>) -> &SyntaxDefinition {
|
||||
pub fn get_syntax(&self, language: Option<&str>, filename: InputFile) -> &SyntaxDefinition {
|
||||
let syntax = match (language, filename) {
|
||||
(Some(language), _) => self.syntax_set.find_syntax_by_token(language),
|
||||
(None, Some(filename)) => {
|
||||
(None, InputFile::Ordinary(filename)) => {
|
||||
#[cfg(not(unix))]
|
||||
let may_read_from_file = true;
|
||||
|
||||
@@ -154,13 +188,29 @@ impl HighlightingAssets {
|
||||
None
|
||||
}
|
||||
}
|
||||
(None, None) => None,
|
||||
(None, InputFile::StdIn) => None,
|
||||
(_, InputFile::ThemePreviewFile) => self.syntax_set.find_syntax_by_name("Rust"),
|
||||
};
|
||||
|
||||
syntax.unwrap_or_else(|| self.syntax_set.find_syntax_plain_text())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this function will soon be part of syntect's `ThemeSet`.
|
||||
fn extend_theme_set<P: AsRef<Path>>(theme_set: &mut ThemeSet, folder: P) -> Result<()> {
|
||||
let paths = ThemeSet::discover_theme_paths(folder)?;
|
||||
for p in &paths {
|
||||
let theme = ThemeSet::get_theme(p)?;
|
||||
let basename = p
|
||||
.file_stem()
|
||||
.and_then(|x| x.to_str())
|
||||
.ok_or("Could not get theme basename")?;
|
||||
theme_set.themes.insert(basename.to_owned(), theme);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn theme_set_path() -> PathBuf {
|
||||
PROJECT_DIRS.cache_dir().join("themes.bin")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufRead, BufReader, Write};
|
||||
|
||||
use app::{Config, InputFile};
|
||||
use assets::HighlightingAssets;
|
||||
use errors::*;
|
||||
use line_range::LineRange;
|
||||
use output::OutputType;
|
||||
use printer::{InteractivePrinter, Printer, SimplePrinter};
|
||||
|
||||
const THEME_PREVIEW_FILE: &[u8] = include_bytes!("../assets/theme_preview.rs");
|
||||
|
||||
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;
|
||||
|
||||
for filename in &self.config.files {
|
||||
let result = if self.config.loop_through {
|
||||
let mut printer = SimplePrinter::new();
|
||||
self.print_file(&mut printer, writer, *filename)
|
||||
} else {
|
||||
let mut printer = InteractivePrinter::new(&self.config, &self.assets, *filename);
|
||||
self.print_file(&mut printer, writer, *filename)
|
||||
};
|
||||
|
||||
if let Err(error) = result {
|
||||
handle_error(&error);
|
||||
no_errors = false;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(no_errors)
|
||||
}
|
||||
|
||||
fn print_file<'a, P: Printer>(
|
||||
&self,
|
||||
printer: &mut P,
|
||||
writer: &mut Write,
|
||||
filename: InputFile<'a>,
|
||||
) -> Result<()> {
|
||||
let stdin = io::stdin();
|
||||
{
|
||||
let reader: Box<BufRead> = match filename {
|
||||
InputFile::StdIn => Box::new(stdin.lock()),
|
||||
InputFile::Ordinary(filename) => {
|
||||
let file = File::open(filename)?;
|
||||
|
||||
if file.metadata()?.is_dir() {
|
||||
return Err(format!("'{}' is a directory.", filename).into());
|
||||
}
|
||||
|
||||
Box::new(BufReader::new(file))
|
||||
}
|
||||
InputFile::ThemePreviewFile => Box::new(THEME_PREVIEW_FILE),
|
||||
};
|
||||
|
||||
printer.print_header(writer, filename)?;
|
||||
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: Box<BufRead + 'a>,
|
||||
line_ranges: &Option<LineRange>,
|
||||
) -> Result<()> {
|
||||
let mut line_buffer = Vec::new();
|
||||
|
||||
let mut line_number: usize = 1;
|
||||
|
||||
while reader.read_until(b'\n', &mut line_buffer)? > 0 {
|
||||
{
|
||||
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(())
|
||||
}
|
||||
}
|
||||
+10
-9
@@ -1,6 +1,6 @@
|
||||
use ansi_term::Style;
|
||||
use diff::LineChange;
|
||||
use printer::{Colors, Printer};
|
||||
use printer::{Colors, InteractivePrinter};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DecorationText {
|
||||
@@ -9,12 +9,15 @@ pub struct DecorationText {
|
||||
}
|
||||
|
||||
pub trait Decoration {
|
||||
fn generate(&self, line_number: usize, continuation: bool, printer: &Printer)
|
||||
-> DecorationText;
|
||||
fn generate(
|
||||
&self,
|
||||
line_number: usize,
|
||||
continuation: bool,
|
||||
printer: &InteractivePrinter,
|
||||
) -> DecorationText;
|
||||
fn width(&self) -> usize;
|
||||
}
|
||||
|
||||
// Line number decoration.
|
||||
pub struct LineNumberDecoration {
|
||||
color: Style,
|
||||
cached_wrap: DecorationText,
|
||||
@@ -39,7 +42,7 @@ impl Decoration for LineNumberDecoration {
|
||||
&self,
|
||||
line_number: usize,
|
||||
continuation: bool,
|
||||
_printer: &Printer,
|
||||
_printer: &InteractivePrinter,
|
||||
) -> DecorationText {
|
||||
if continuation {
|
||||
if line_number > self.cached_wrap_invalid_at {
|
||||
@@ -65,7 +68,6 @@ impl Decoration for LineNumberDecoration {
|
||||
}
|
||||
}
|
||||
|
||||
// Line changes decoration.
|
||||
pub struct LineChangesDecoration {
|
||||
cached_none: DecorationText,
|
||||
cached_added: DecorationText,
|
||||
@@ -99,7 +101,7 @@ impl Decoration for LineChangesDecoration {
|
||||
&self,
|
||||
line_number: usize,
|
||||
continuation: bool,
|
||||
printer: &Printer,
|
||||
printer: &InteractivePrinter,
|
||||
) -> DecorationText {
|
||||
if !continuation {
|
||||
if let Some(ref changes) = printer.line_changes {
|
||||
@@ -121,7 +123,6 @@ impl Decoration for LineChangesDecoration {
|
||||
}
|
||||
}
|
||||
|
||||
// Grid border decoration.
|
||||
pub struct GridBorderDecoration {
|
||||
cached: DecorationText,
|
||||
}
|
||||
@@ -142,7 +143,7 @@ impl Decoration for GridBorderDecoration {
|
||||
&self,
|
||||
_line_number: usize,
|
||||
_continuation: bool,
|
||||
_printer: &Printer,
|
||||
_printer: &InteractivePrinter,
|
||||
) -> DecorationText {
|
||||
self.cached.clone()
|
||||
}
|
||||
|
||||
+7
-4
@@ -15,11 +15,14 @@ pub type LineChanges = HashMap<u32, LineChange>;
|
||||
|
||||
pub fn get_git_diff(filename: &str) -> Option<LineChanges> {
|
||||
let repo = Repository::discover(&filename).ok()?;
|
||||
let path_absolute = fs::canonicalize(&filename).ok()?;
|
||||
let path_relative_to_repo = path_absolute.strip_prefix(repo.workdir()?).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 = path_relative_to_repo.into_c_string().ok()?;
|
||||
let pathspec = filepath_relative_to_repo.into_c_string().ok()?;
|
||||
diff_options.pathspec(pathspec);
|
||||
diff_options.context_lines(0);
|
||||
|
||||
@@ -42,7 +45,7 @@ pub fn get_git_diff(filename: &str) -> Option<LineChanges> {
|
||||
Some(&mut |delta, hunk| {
|
||||
let path = delta.new_file().path().unwrap_or_else(|| Path::new(""));
|
||||
|
||||
if path_relative_to_repo != path {
|
||||
if filepath_relative_to_repo != path {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
-112
@@ -1,112 +0,0 @@
|
||||
use ansi_term::Colour::Green;
|
||||
use app::Config;
|
||||
use assets::HighlightingAssets;
|
||||
use diff::get_git_diff;
|
||||
use errors::*;
|
||||
use output::OutputType;
|
||||
use printer::Printer;
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufRead, BufReader};
|
||||
use syntect::easy::HighlightLines;
|
||||
use syntect::highlighting::Theme;
|
||||
use syntect::parsing::SyntaxDefinition;
|
||||
|
||||
pub fn list_languages(assets: &HighlightingAssets, term_width: usize) {
|
||||
let mut languages = assets
|
||||
.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 longest = languages
|
||||
.iter()
|
||||
.map(|syntax| syntax.name.len())
|
||||
.max()
|
||||
.unwrap_or(32); // Fallback width if they have no language definitions.
|
||||
|
||||
let comma_separator = ", ";
|
||||
let separator = " ";
|
||||
// Line-wrapping for the possible file extension overflow.
|
||||
let desired_width = term_width - longest - separator.len();
|
||||
|
||||
for lang in languages {
|
||||
print!("{:width$}{}", lang.name, separator, width = longest);
|
||||
|
||||
// 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;
|
||||
print!("\n{:width$}{}", "", separator, width = longest);
|
||||
}
|
||||
|
||||
num_chars += new_chars;
|
||||
print!("{}", Green.paint(&word[..]));
|
||||
if extension.peek().is_some() {
|
||||
print!("{}", comma_separator);
|
||||
}
|
||||
}
|
||||
println!();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_files(assets: &HighlightingAssets, config: &Config) -> Result<bool> {
|
||||
let theme = assets.get_theme(config.theme.unwrap_or("Default"))?;
|
||||
let mut output_type = OutputType::from_mode(config.paging_mode);
|
||||
let handle = output_type.handle()?;
|
||||
let mut printer = Printer::new(handle, &config);
|
||||
let mut no_errors: bool = true;
|
||||
|
||||
for file in &config.files {
|
||||
printer.line_changes = file.and_then(|filename| get_git_diff(filename));
|
||||
let syntax = assets.get_syntax(config.language, *file);
|
||||
|
||||
let result = print_file(theme, &syntax, &mut printer, *file);
|
||||
|
||||
if let Err(error) = result {
|
||||
handle_error(&error);
|
||||
no_errors = false;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(no_errors)
|
||||
}
|
||||
|
||||
fn print_file(
|
||||
theme: &Theme,
|
||||
syntax: &SyntaxDefinition,
|
||||
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 mut highlighter = HighlightLines::new(syntax, theme);
|
||||
|
||||
printer.print_header(filename)?;
|
||||
|
||||
let mut buffer = Vec::new();
|
||||
while reader.read_until(b'\n', &mut buffer)? > 0 {
|
||||
{
|
||||
let line = String::from_utf8_lossy(&buffer);
|
||||
let regions = highlighter.highlight(line.as_ref());
|
||||
|
||||
printer.print_line(®ions)?;
|
||||
}
|
||||
buffer.clear();
|
||||
}
|
||||
|
||||
printer.print_footer()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
+143
-26
@@ -19,21 +19,29 @@ extern crate syntect;
|
||||
|
||||
mod app;
|
||||
mod assets;
|
||||
mod controller;
|
||||
mod decorations;
|
||||
mod diff;
|
||||
mod features;
|
||||
mod line_range;
|
||||
mod output;
|
||||
mod preprocessor;
|
||||
mod printer;
|
||||
mod style;
|
||||
mod terminal;
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::io;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::process;
|
||||
|
||||
use app::App;
|
||||
use ansi_term::Colour::Green;
|
||||
use ansi_term::Style;
|
||||
|
||||
use app::{App, Config, InputFile};
|
||||
use assets::{clear_assets, config_dir, HighlightingAssets};
|
||||
use features::{list_languages, print_files};
|
||||
use controller::Controller;
|
||||
use style::{OutputComponent, OutputComponents};
|
||||
|
||||
mod errors {
|
||||
error_chain! {
|
||||
@@ -41,6 +49,7 @@ mod errors {
|
||||
Clap(::clap::Error);
|
||||
Io(::std::io::Error);
|
||||
SyntectError(::syntect::LoadingError);
|
||||
ParseIntError(::std::num::ParseIntError);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +70,119 @@ mod errors {
|
||||
|
||||
use errors::*;
|
||||
|
||||
fn run_cache_subcommand(matches: &clap::ArgMatches) -> Result<()> {
|
||||
if matches.is_present("init") {
|
||||
let source_dir = matches.value_of("source").map(Path::new);
|
||||
let target_dir = matches.value_of("target").map(Path::new);
|
||||
|
||||
let blank = matches.is_present("blank");
|
||||
|
||||
let assets = HighlightingAssets::from_files(source_dir, blank)?;
|
||||
assets.save(target_dir)?;
|
||||
} else if matches.is_present("clear") {
|
||||
clear_assets();
|
||||
} else if matches.is_present("config-dir") {
|
||||
writeln!(io::stdout(), "{}", config_dir())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn list_languages(config: &Config) -> Result<()> {
|
||||
let assets = HighlightingAssets::new();
|
||||
let mut languages = assets
|
||||
.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 longest = languages
|
||||
.iter()
|
||||
.map(|syntax| syntax.name.len())
|
||||
.max()
|
||||
.unwrap_or(32); // Fallback width if they have no language definitions.
|
||||
|
||||
let comma_separator = ", ";
|
||||
let separator = " ";
|
||||
// Line-wrapping for the possible file extension overflow.
|
||||
let desired_width = config.term_width - longest - separator.len();
|
||||
|
||||
let stdout = io::stdout();
|
||||
let mut stdout = stdout.lock();
|
||||
|
||||
let style = if config.colored_output {
|
||||
Green.normal()
|
||||
} else {
|
||||
Style::default()
|
||||
};
|
||||
|
||||
for lang in languages {
|
||||
write!(stdout, "{:width$}{}", lang.name, separator, width = longest)?;
|
||||
|
||||
// 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> {
|
||||
@@ -68,38 +190,33 @@ fn run() -> Result<bool> {
|
||||
|
||||
match app.matches.subcommand() {
|
||||
("cache", Some(cache_matches)) => {
|
||||
if cache_matches.is_present("init") {
|
||||
let source_dir = cache_matches.value_of("source").map(Path::new);
|
||||
let target_dir = cache_matches.value_of("target").map(Path::new);
|
||||
// If there is a file named 'cache' in the current working directory,
|
||||
// arguments for subcommand 'cache' are not mandatory.
|
||||
// If there are non-zero arguments, execute the subcommand cache, else, open the file cache.
|
||||
if !cache_matches.args.is_empty() {
|
||||
run_cache_subcommand(cache_matches)?;
|
||||
Ok(true)
|
||||
} else {
|
||||
let mut config = app.config()?;
|
||||
config.files = vec![InputFile::Ordinary(&"cache")];
|
||||
|
||||
let assets = HighlightingAssets::from_files(source_dir)?;
|
||||
assets.save(target_dir)?;
|
||||
} else if cache_matches.is_present("clear") {
|
||||
clear_assets();
|
||||
} else if cache_matches.is_present("config-dir") {
|
||||
println!("{}", config_dir());
|
||||
run_controller(&config)
|
||||
}
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
_ => {
|
||||
let config = app.config()?;
|
||||
let assets = HighlightingAssets::new();
|
||||
|
||||
if app.matches.is_present("list-languages") {
|
||||
list_languages(&assets, config.term_width);
|
||||
return Ok(true);
|
||||
}
|
||||
list_languages(&config)?;
|
||||
|
||||
if app.matches.is_present("list-themes") {
|
||||
let themes = &assets.theme_set.themes;
|
||||
for (theme, _) in themes.iter() {
|
||||
println!("{}", theme);
|
||||
}
|
||||
return Ok(true);
|
||||
}
|
||||
Ok(true)
|
||||
} else if app.matches.is_present("list-themes") {
|
||||
list_themes(&config)?;
|
||||
|
||||
print_files(&assets, &config)
|
||||
Ok(true)
|
||||
} else {
|
||||
run_controller(&config)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+27
-9
@@ -1,7 +1,11 @@
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::io::{self, Write};
|
||||
use std::path::PathBuf;
|
||||
use std::process::{Child, Command, Stdio};
|
||||
|
||||
use app::PagingMode;
|
||||
use errors::*;
|
||||
use std::io::{self, Write};
|
||||
use std::process::{Child, Command, Stdio};
|
||||
|
||||
pub enum OutputType {
|
||||
Pager(Child),
|
||||
@@ -20,13 +24,27 @@ impl OutputType {
|
||||
|
||||
/// Try to launch the pager. Fall back to stdout in case of errors.
|
||||
fn try_pager(quit_if_one_screen: bool) -> Self {
|
||||
let mut args = vec!["--RAW-CONTROL-CHARS", "--no-init"];
|
||||
if quit_if_one_screen {
|
||||
args.push("--quit-if-one-screen");
|
||||
}
|
||||
Command::new("less")
|
||||
.args(&args)
|
||||
.env("LESSCHARSET", "UTF-8")
|
||||
let pager = env::var("BAT_PAGER")
|
||||
.or_else(|_| env::var("PAGER"))
|
||||
.unwrap_or(String::from("less"));
|
||||
|
||||
let less_path = PathBuf::from(&pager);
|
||||
let is_less = less_path.file_stem() == Some(&OsString::from("less"));
|
||||
|
||||
let mut process = if is_less {
|
||||
let mut args = vec!["--RAW-CONTROL-CHARS", "--no-init"];
|
||||
if quit_if_one_screen {
|
||||
args.push("--quit-if-one-screen");
|
||||
}
|
||||
|
||||
let mut p = Command::new(&less_path);
|
||||
p.args(&args).env("LESSCHARSET", "UTF-8");
|
||||
p
|
||||
} else {
|
||||
Command::new(pager)
|
||||
};
|
||||
|
||||
process
|
||||
.stdin(Stdio::piped())
|
||||
.spawn()
|
||||
.map(OutputType::Pager)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
+197
-86
@@ -1,31 +1,84 @@
|
||||
use ansi_term::Colour::{Fixed, Green, Red, White, Yellow};
|
||||
use ansi_term::Style;
|
||||
use app::Config;
|
||||
use console::AnsiCodeIterator;
|
||||
use decorations::{Decoration, GridBorderDecoration, LineChangesDecoration, LineNumberDecoration};
|
||||
use diff::LineChanges;
|
||||
use errors::*;
|
||||
use std::boxed::Box;
|
||||
use std::io::Write;
|
||||
use std::vec::Vec;
|
||||
use style::OutputWrap;
|
||||
use syntect::highlighting;
|
||||
use terminal::as_terminal_escaped;
|
||||
|
||||
pub struct Printer<'a> {
|
||||
handle: &'a mut Write,
|
||||
use ansi_term::Colour::{Fixed, Green, Red, Yellow};
|
||||
use ansi_term::Style;
|
||||
|
||||
use console::AnsiCodeIterator;
|
||||
|
||||
use syntect::easy::HighlightLines;
|
||||
use syntect::highlighting::Theme;
|
||||
|
||||
use app::{Config, InputFile};
|
||||
use assets::HighlightingAssets;
|
||||
use decorations::{Decoration, GridBorderDecoration, LineChangesDecoration, LineNumberDecoration};
|
||||
use diff::get_git_diff;
|
||||
use diff::LineChanges;
|
||||
use errors::*;
|
||||
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<()>;
|
||||
}
|
||||
|
||||
pub struct SimplePrinter;
|
||||
|
||||
impl SimplePrinter {
|
||||
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<Decoration>>,
|
||||
panel_width: usize,
|
||||
line_number: usize,
|
||||
ansi_prefix_sgr: String,
|
||||
pub line_changes: Option<LineChanges>,
|
||||
highlighter: HighlightLines<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Printer<'a> {
|
||||
pub fn new(handle: &'a mut Write, config: &'a Config) -> Self {
|
||||
impl<'a> InteractivePrinter<'a> {
|
||||
pub fn new(config: &'a Config, assets: &'a HighlightingAssets, file: InputFile) -> Self {
|
||||
let theme = assets.get_theme(&config.theme);
|
||||
|
||||
let colors = if config.colored_output {
|
||||
Colors::colored()
|
||||
Colors::colored(theme, config.true_color)
|
||||
} else {
|
||||
Colors::plain()
|
||||
};
|
||||
@@ -60,30 +113,67 @@ impl<'a> Printer<'a> {
|
||||
panel_width = 0;
|
||||
}
|
||||
|
||||
// Create printer.
|
||||
Printer {
|
||||
// Get the Git modifications
|
||||
let 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);
|
||||
let highlighter = HighlightLines::new(syntax, theme);
|
||||
|
||||
InteractivePrinter {
|
||||
panel_width,
|
||||
handle,
|
||||
colors,
|
||||
config,
|
||||
decorations,
|
||||
line_number: 0,
|
||||
line_changes: None,
|
||||
ansi_prefix_sgr: String::new(),
|
||||
line_changes,
|
||||
highlighter,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_header(&mut self, filename: Option<&str>) -> Result<()> {
|
||||
self.line_number = 0;
|
||||
fn print_horizontal_line(&mut self, handle: &mut Write, grid_char: char) -> Result<()> {
|
||||
if self.panel_width == 0 {
|
||||
writeln!(
|
||||
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))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn preprocess(&self, text: &str, cursor: &mut usize) -> String {
|
||||
if self.config.tab_width > 0 {
|
||||
expand(text, self.config.tab_width, cursor)
|
||||
} else {
|
||||
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('┬')?;
|
||||
self.print_horizontal_line(handle, '┬')?;
|
||||
|
||||
write!(
|
||||
self.handle,
|
||||
handle,
|
||||
"{}{}",
|
||||
" ".repeat(self.panel_width),
|
||||
self.colors
|
||||
@@ -91,35 +181,48 @@ impl<'a> Printer<'a> {
|
||||
.paint(if self.panel_width > 0 { "│ " } else { "" }),
|
||||
)?;
|
||||
} else {
|
||||
write!(self.handle, "{}", " ".repeat(self.panel_width))?;
|
||||
write!(handle, "{}", " ".repeat(self.panel_width))?;
|
||||
}
|
||||
|
||||
writeln!(
|
||||
self.handle,
|
||||
"{}{}",
|
||||
filename.map_or("", |_| "File: "),
|
||||
self.colors.filename.paint(filename.unwrap_or("STDIN"))
|
||||
)?;
|
||||
let (prefix, name) = match file {
|
||||
InputFile::Ordinary(filename) => ("File: ", filename),
|
||||
_ => ("", "STDIN"),
|
||||
};
|
||||
|
||||
writeln!(handle, "{}{}", prefix, self.colors.filename.paint(name))?;
|
||||
|
||||
if self.config.output_components.grid() {
|
||||
self.print_horizontal_line('┼')?;
|
||||
self.print_horizontal_line(handle, '┼')?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn print_footer(&mut self) -> Result<()> {
|
||||
fn print_footer(&mut self, handle: &mut Write) -> Result<()> {
|
||||
if self.config.output_components.grid() {
|
||||
self.print_horizontal_line('┴')
|
||||
self.print_horizontal_line(handle, '┴')
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_line(&mut self, regions: &[(highlighting::Style, &str)]) -> Result<()> {
|
||||
self.line_number += 1;
|
||||
fn print_line(
|
||||
&mut self,
|
||||
out_of_range: bool,
|
||||
handle: &mut Write,
|
||||
line_number: usize,
|
||||
line_buffer: &[u8],
|
||||
) -> Result<()> {
|
||||
let line = String::from_utf8_lossy(&line_buffer).to_string();
|
||||
let regions = self.highlighter.highlight(line.as_ref());
|
||||
|
||||
if out_of_range {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// Line decorations.
|
||||
@@ -127,11 +230,11 @@ impl<'a> Printer<'a> {
|
||||
let decorations = self
|
||||
.decorations
|
||||
.iter()
|
||||
.map(|ref d| d.generate(self.line_number, false, self))
|
||||
.map(|ref d| d.generate(line_number, false, self))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for deco in decorations {
|
||||
write!(self.handle, "{} ", deco.text)?;
|
||||
write!(handle, "{} ", deco.text)?;
|
||||
cursor_max -= deco.width + 1;
|
||||
}
|
||||
}
|
||||
@@ -141,34 +244,45 @@ impl<'a> Printer<'a> {
|
||||
let true_color = self.config.true_color;
|
||||
let colored_output = self.config.colored_output;
|
||||
|
||||
write!(
|
||||
self.handle,
|
||||
"{}",
|
||||
regions
|
||||
.iter()
|
||||
.map(|&(style, text)| as_terminal_escaped(
|
||||
style,
|
||||
text,
|
||||
true_color,
|
||||
colored_output,
|
||||
))
|
||||
.collect::<Vec<_>>()
|
||||
.join("")
|
||||
)?;
|
||||
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 = "";
|
||||
let mut ansi_prefix: String = String::new();
|
||||
for chunk in ansi_iterator {
|
||||
match chunk {
|
||||
// ANSI escape passthrough.
|
||||
(text, true) => {
|
||||
ansi_prefix = text;
|
||||
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 = text.trim_right_matches(|c| c == '\r' || c == '\n');
|
||||
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();
|
||||
|
||||
@@ -181,11 +295,14 @@ impl<'a> Printer<'a> {
|
||||
cursor += remaining;
|
||||
|
||||
write!(
|
||||
self.handle,
|
||||
handle,
|
||||
"{}",
|
||||
as_terminal_escaped(
|
||||
style,
|
||||
&*format!("{}{}", ansi_prefix, text),
|
||||
&*format!(
|
||||
"{}{}{}",
|
||||
self.ansi_prefix_sgr, ansi_prefix, text
|
||||
),
|
||||
self.config.true_color,
|
||||
self.config.colored_output,
|
||||
)
|
||||
@@ -201,9 +318,8 @@ impl<'a> Printer<'a> {
|
||||
self.decorations
|
||||
.iter()
|
||||
.map(|ref d| d
|
||||
.generate(self.line_number, true, self)
|
||||
.text)
|
||||
.collect::<Vec<String>>()
|
||||
.generate(line_number, true, self)
|
||||
.text).collect::<Vec<String>>()
|
||||
.join(" ")
|
||||
))
|
||||
} else {
|
||||
@@ -217,47 +333,36 @@ impl<'a> Printer<'a> {
|
||||
remaining -= available;
|
||||
|
||||
write!(
|
||||
self.handle,
|
||||
handle,
|
||||
"{}\n{}",
|
||||
as_terminal_escaped(
|
||||
style,
|
||||
&*format!("{}{}", ansi_prefix, text),
|
||||
&*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!(self.handle, "\n")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_horizontal_line(&mut self, grid_char: char) -> Result<()> {
|
||||
if self.panel_width == 0 {
|
||||
writeln!(
|
||||
self.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!(self.handle, "{}", self.colors.grid.paint(hline))?;
|
||||
write!(handle, "\n")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
const GRID_COLOR: u8 = 238;
|
||||
const LINE_NUMBER_COLOR: u8 = 244;
|
||||
const DEFAULT_GUTTER_COLOR: u8 = 238;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Colors {
|
||||
@@ -274,14 +379,20 @@ impl Colors {
|
||||
Colors::default()
|
||||
}
|
||||
|
||||
fn colored() -> Self {
|
||||
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: Fixed(GRID_COLOR).normal(),
|
||||
filename: White.bold(),
|
||||
grid: gutter_color.normal(),
|
||||
filename: Style::new().bold(),
|
||||
git_added: Green.normal(),
|
||||
git_removed: Red.normal(),
|
||||
git_modified: Yellow.normal(),
|
||||
line_number: Fixed(LINE_NUMBER_COLOR).normal(),
|
||||
line_number: gutter_color.normal(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-2
@@ -1,7 +1,8 @@
|
||||
use errors::*;
|
||||
use std::collections::HashSet;
|
||||
use std::str::FromStr;
|
||||
|
||||
use errors::*;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
|
||||
pub enum OutputComponent {
|
||||
Auto,
|
||||
@@ -53,11 +54,13 @@ impl FromStr for OutputComponent {
|
||||
"header" => Ok(OutputComponent::Header),
|
||||
"numbers" => Ok(OutputComponent::Numbers),
|
||||
"full" => Ok(OutputComponent::Full),
|
||||
"plain" | _ => Ok(OutputComponent::Plain),
|
||||
"plain" => Ok(OutputComponent::Plain),
|
||||
_ => Err(format!("Unknown style '{}'", s).into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct OutputComponents(pub HashSet<OutputComponent>);
|
||||
|
||||
impl OutputComponents {
|
||||
@@ -76,4 +79,8 @@ impl OutputComponents {
|
||||
pub fn numbers(&self) -> bool {
|
||||
self.0.contains(&OutputComponent::Numbers)
|
||||
}
|
||||
|
||||
pub fn plain(&self) -> bool {
|
||||
self.0.iter().all(|c| c == &OutputComponent::Plain)
|
||||
}
|
||||
}
|
||||
|
||||
+9
-49
@@ -1,26 +1,15 @@
|
||||
extern crate ansi_colours;
|
||||
|
||||
use ansi_term::Colour::{Fixed, RGB};
|
||||
use ansi_term::Style;
|
||||
use ansi_term::{self, Style};
|
||||
|
||||
use syntect::highlighting::{self, FontStyle};
|
||||
|
||||
/// Approximate a 24 bit color value by a 8 bit ANSI code
|
||||
fn rgb2ansi(r: u8, g: u8, b: u8) -> u8 {
|
||||
const BLACK: u8 = 16;
|
||||
const WHITE: u8 = 231;
|
||||
|
||||
if r == g && g == b {
|
||||
if r < 8 {
|
||||
BLACK
|
||||
} else if r > 248 {
|
||||
WHITE
|
||||
} else {
|
||||
let fr = f32::from(r);
|
||||
(((fr - 8.) / 247.) * 24.) as u8 + 232
|
||||
}
|
||||
pub fn to_ansi_color(color: highlighting::Color, true_color: bool) -> ansi_term::Colour {
|
||||
if true_color {
|
||||
RGB(color.r, color.g, color.b)
|
||||
} else {
|
||||
let fr = f32::from(r);
|
||||
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
|
||||
Fixed(ansi_colours::ansi256_from_rgb((color.r, color.g, color.b)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,12 +22,7 @@ pub fn as_terminal_escaped(
|
||||
let style = if !colored {
|
||||
Style::default()
|
||||
} else {
|
||||
let color = if true_color {
|
||||
RGB(style.foreground.r, style.foreground.g, style.foreground.b)
|
||||
} else {
|
||||
let ansi = rgb2ansi(style.foreground.r, style.foreground.g, style.foreground.b);
|
||||
Fixed(ansi)
|
||||
};
|
||||
let color = to_ansi_color(style.foreground, true_color);
|
||||
|
||||
if style.font_style.contains(FontStyle::BOLD) {
|
||||
color.bold()
|
||||
@@ -53,27 +37,3 @@ pub fn as_terminal_escaped(
|
||||
|
||||
style.paint(text).to_string()
|
||||
}
|
||||
|
||||
#[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));
|
||||
}
|
||||
|
||||
@@ -1,43 +1,64 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import itertools
|
||||
import subprocess
|
||||
import pathlib
|
||||
import shutil
|
||||
|
||||
|
||||
def generate_snapshots():
|
||||
single_styles = ["changes", "grid", "header", "numbers"]
|
||||
collective_styles = ["full", "plain"]
|
||||
|
||||
for num in range(len(single_styles)):
|
||||
for grouped in itertools.combinations(single_styles, num + 1):
|
||||
generate_snapshot(",".join(grouped))
|
||||
generate_style_snapshot(",".join(grouped))
|
||||
|
||||
for style in collective_styles:
|
||||
generate_snapshot(style)
|
||||
generate_style_snapshot(style)
|
||||
|
||||
def generate_snapshot(option):
|
||||
command = "../../target/debug/bat --style={0} sample.rs > output/{0}.snapshot.txt".format(
|
||||
option
|
||||
generate_snapshot("tabs_passthrough", "--tabs=0 --style=full --wrap=never")
|
||||
generate_snapshot("tabs_passthrough_wrapped", "--tabs=0 --style=full --wrap=character")
|
||||
generate_snapshot("tabs_4", "--tabs=4 --style=full --wrap=never")
|
||||
generate_snapshot("tabs_4_wrapped", "--tabs=4 --style=full --wrap=character")
|
||||
generate_snapshot("tabs_8", "--tabs=8 --style=full --wrap=never")
|
||||
generate_snapshot("tabs_8_wrapped", "--tabs=8 --style=full --wrap=character")
|
||||
|
||||
|
||||
def generate_style_snapshot(style):
|
||||
generate_snapshot(style.replace(",", "_"), "--style={}".format(style))
|
||||
|
||||
|
||||
def generate_snapshot(name, arguments):
|
||||
command = "cargo run -- --paging=never --color=never --decorations=always "
|
||||
command += "{args} sample.rs > output/{name}.snapshot.txt".format(
|
||||
name=name,
|
||||
args=arguments
|
||||
)
|
||||
print("generating snapshot for {}".format(option))
|
||||
print("generating snapshot for {}".format(name))
|
||||
subprocess.call(command, shell=True)
|
||||
|
||||
|
||||
def build_bat():
|
||||
print("building bat")
|
||||
subprocess.call("cargo build", cwd="../..", shell=True)
|
||||
|
||||
|
||||
def prepare_output_dir():
|
||||
shutil.rmtree("output", ignore_errors=True)
|
||||
pathlib.Path("output").mkdir()
|
||||
|
||||
|
||||
def modify_sample_file():
|
||||
print("modifying sample.rs to show changes")
|
||||
shutil.copyfile("sample.modified.rs", "sample.rs")
|
||||
|
||||
|
||||
def undo_sample_file_modification():
|
||||
print("undoing sample.rs modifications")
|
||||
subprocess.call("git checkout -- sample.rs", shell=True)
|
||||
|
||||
|
||||
build_bat()
|
||||
prepare_output_dir()
|
||||
modify_sample_file()
|
||||
|
||||
@@ -16,7 +16,21 @@ _ fn main() {
|
||||
fn area(rectangle: &Rectangle) -> u32 {
|
||||
rectangle.width * rectangle.height
|
||||
}
|
||||
+
|
||||
|
||||
+ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
+ (rectangle.width + rectangle.height) * 2
|
||||
+ }
|
||||
+
|
||||
// Tab alignment:
|
||||
/*
|
||||
Indent
|
||||
1 2 3 4
|
||||
1 ?
|
||||
22 ?
|
||||
333 ?
|
||||
4444 ?
|
||||
55555 ?
|
||||
666666 ?
|
||||
7777777 ?
|
||||
88888888 ?
|
||||
~ */
|
||||
|
||||
+15
-1
@@ -16,8 +16,22 @@ _ │ fn main() {
|
||||
│ fn area(rectangle: &Rectangle) -> u32 {
|
||||
│ rectangle.width * rectangle.height
|
||||
│ }
|
||||
+ │
|
||||
│
|
||||
+ │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
+ │ (rectangle.width + rectangle.height) * 2
|
||||
+ │ }
|
||||
+ │
|
||||
│ // Tab alignment:
|
||||
│ /*
|
||||
│ Indent
|
||||
│ 1 2 3 4
|
||||
│ 1 ?
|
||||
│ 22 ?
|
||||
│ 333 ?
|
||||
│ 4444 ?
|
||||
│ 55555 ?
|
||||
│ 666666 ?
|
||||
│ 7777777 ?
|
||||
│ 88888888 ?
|
||||
~ │ */
|
||||
──┴─────────────────────────────────────────────────────────────────────────────
|
||||
+15
-1
@@ -19,8 +19,22 @@ _ │ fn main() {
|
||||
│ fn area(rectangle: &Rectangle) -> u32 {
|
||||
│ rectangle.width * rectangle.height
|
||||
│ }
|
||||
+ │
|
||||
│
|
||||
+ │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
+ │ (rectangle.width + rectangle.height) * 2
|
||||
+ │ }
|
||||
+ │
|
||||
│ // Tab alignment:
|
||||
│ /*
|
||||
│ Indent
|
||||
│ 1 2 3 4
|
||||
│ 1 ?
|
||||
│ 22 ?
|
||||
│ 333 ?
|
||||
│ 4444 ?
|
||||
│ 55555 ?
|
||||
│ 666666 ?
|
||||
│ 7777777 ?
|
||||
│ 88888888 ?
|
||||
~ │ */
|
||||
──┴─────────────────────────────────────────────────────────────────────────────
|
||||
@@ -0,0 +1,40 @@
|
||||
───────┬────────────────────────────────────────────────────────────────────────
|
||||
│ File: sample.rs
|
||||
───────┼────────────────────────────────────────────────────────────────────────
|
||||
1 │ struct Rectangle {
|
||||
2 │ width: u32,
|
||||
3 │ height: u32,
|
||||
4 │ }
|
||||
5 │
|
||||
6 _ │ fn main() {
|
||||
7 │ let rect1 = Rectangle { width: 30, height: 50 };
|
||||
8 │
|
||||
9 │ println!(
|
||||
10 ~ │ "The perimeter of the rectangle is {} pixels.",
|
||||
11 ~ │ perimeter(&rect1)
|
||||
12 │ );
|
||||
13 + │ println!(r#"This line contains invalid utf8: "�����"#;
|
||||
14 │ }
|
||||
15 │
|
||||
16 │ fn area(rectangle: &Rectangle) -> u32 {
|
||||
17 │ rectangle.width * rectangle.height
|
||||
18 │ }
|
||||
19 │
|
||||
20 + │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
21 + │ (rectangle.width + rectangle.height) * 2
|
||||
22 + │ }
|
||||
23 + │
|
||||
24 │ // Tab alignment:
|
||||
25 │ /*
|
||||
26 │ Indent
|
||||
27 │ 1 2 3 4
|
||||
28 │ 1 ?
|
||||
29 │ 22 ?
|
||||
30 │ 333 ?
|
||||
31 │ 4444 ?
|
||||
32 │ 55555 ?
|
||||
33 │ 666666 ?
|
||||
34 │ 7777777 ?
|
||||
35 │ 88888888 ?
|
||||
36 ~ │ */
|
||||
───────┴────────────────────────────────────────────────────────────────────────
|
||||
+15
-1
@@ -16,8 +16,22 @@
|
||||
16 │ fn area(rectangle: &Rectangle) -> u32 {
|
||||
17 │ rectangle.width * rectangle.height
|
||||
18 │ }
|
||||
19 + │
|
||||
19 │
|
||||
20 + │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
21 + │ (rectangle.width + rectangle.height) * 2
|
||||
22 + │ }
|
||||
23 + │
|
||||
24 │ // Tab alignment:
|
||||
25 │ /*
|
||||
26 │ Indent
|
||||
27 │ 1 2 3 4
|
||||
28 │ 1 ?
|
||||
29 │ 22 ?
|
||||
30 │ 333 ?
|
||||
31 │ 4444 ?
|
||||
32 │ 55555 ?
|
||||
33 │ 666666 ?
|
||||
34 │ 7777777 ?
|
||||
35 │ 88888888 ?
|
||||
36 ~ │ */
|
||||
───────┴────────────────────────────────────────────────────────────────────────
|
||||
+15
-1
@@ -17,7 +17,21 @@ _ fn main() {
|
||||
fn area(rectangle: &Rectangle) -> u32 {
|
||||
rectangle.width * rectangle.height
|
||||
}
|
||||
+
|
||||
|
||||
+ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
+ (rectangle.width + rectangle.height) * 2
|
||||
+ }
|
||||
+
|
||||
// Tab alignment:
|
||||
/*
|
||||
Indent
|
||||
1 2 3 4
|
||||
1 ?
|
||||
22 ?
|
||||
333 ?
|
||||
4444 ?
|
||||
55555 ?
|
||||
666666 ?
|
||||
7777777 ?
|
||||
88888888 ?
|
||||
~ */
|
||||
+15
-1
@@ -17,7 +17,21 @@
|
||||
16 fn area(rectangle: &Rectangle) -> u32 {
|
||||
17 rectangle.width * rectangle.height
|
||||
18 }
|
||||
19 +
|
||||
19
|
||||
20 + fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
21 + (rectangle.width + rectangle.height) * 2
|
||||
22 + }
|
||||
23 +
|
||||
24 // Tab alignment:
|
||||
25 /*
|
||||
26 Indent
|
||||
27 1 2 3 4
|
||||
28 1 ?
|
||||
29 22 ?
|
||||
30 333 ?
|
||||
31 4444 ?
|
||||
32 55555 ?
|
||||
33 666666 ?
|
||||
34 7777777 ?
|
||||
35 88888888 ?
|
||||
36 ~ */
|
||||
+15
-1
@@ -16,7 +16,21 @@
|
||||
16 fn area(rectangle: &Rectangle) -> u32 {
|
||||
17 rectangle.width * rectangle.height
|
||||
18 }
|
||||
19 +
|
||||
19
|
||||
20 + fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
21 + (rectangle.width + rectangle.height) * 2
|
||||
22 + }
|
||||
23 +
|
||||
24 // Tab alignment:
|
||||
25 /*
|
||||
26 Indent
|
||||
27 1 2 3 4
|
||||
28 1 ?
|
||||
29 22 ?
|
||||
30 333 ?
|
||||
31 4444 ?
|
||||
32 55555 ?
|
||||
33 666666 ?
|
||||
34 7777777 ?
|
||||
35 88888888 ?
|
||||
36 ~ */
|
||||
@@ -19,8 +19,22 @@
|
||||
16 │ fn area(rectangle: &Rectangle) -> u32 {
|
||||
17 │ rectangle.width * rectangle.height
|
||||
18 │ }
|
||||
19 + │
|
||||
19 │
|
||||
20 + │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
21 + │ (rectangle.width + rectangle.height) * 2
|
||||
22 + │ }
|
||||
23 + │
|
||||
24 │ // Tab alignment:
|
||||
25 │ /*
|
||||
26 │ Indent
|
||||
27 │ 1 2 3 4
|
||||
28 │ 1 ?
|
||||
29 │ 22 ?
|
||||
30 │ 333 ?
|
||||
31 │ 4444 ?
|
||||
32 │ 55555 ?
|
||||
33 │ 666666 ?
|
||||
34 │ 7777777 ?
|
||||
35 │ 88888888 ?
|
||||
36 ~ │ */
|
||||
───────┴────────────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -20,4 +20,18 @@ fn area(rectangle: &Rectangle) -> u32 {
|
||||
fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
(rectangle.width + rectangle.height) * 2
|
||||
}
|
||||
|
||||
// Tab alignment:
|
||||
/*
|
||||
Indent
|
||||
1 2 3 4
|
||||
1 ?
|
||||
22 ?
|
||||
333 ?
|
||||
4444 ?
|
||||
55555 ?
|
||||
666666 ?
|
||||
7777777 ?
|
||||
88888888 ?
|
||||
*/
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
+14
@@ -23,4 +23,18 @@ fn area(rectangle: &Rectangle) -> u32 {
|
||||
fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
(rectangle.width + rectangle.height) * 2
|
||||
}
|
||||
|
||||
// Tab alignment:
|
||||
/*
|
||||
Indent
|
||||
1 2 3 4
|
||||
1 ?
|
||||
22 ?
|
||||
333 ?
|
||||
4444 ?
|
||||
55555 ?
|
||||
666666 ?
|
||||
7777777 ?
|
||||
88888888 ?
|
||||
*/
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
+14
@@ -23,4 +23,18 @@
|
||||
20 │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
21 │ (rectangle.width + rectangle.height) * 2
|
||||
22 │ }
|
||||
23 │
|
||||
24 │ // Tab alignment:
|
||||
25 │ /*
|
||||
26 │ Indent
|
||||
27 │ 1 2 3 4
|
||||
28 │ 1 ?
|
||||
29 │ 22 ?
|
||||
30 │ 333 ?
|
||||
31 │ 4444 ?
|
||||
32 │ 55555 ?
|
||||
33 │ 666666 ?
|
||||
34 │ 7777777 ?
|
||||
35 │ 88888888 ?
|
||||
36 │ */
|
||||
─────┴──────────────────────────────────────────────────────────────────────────
|
||||
+14
@@ -20,4 +20,18 @@
|
||||
20 │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
21 │ (rectangle.width + rectangle.height) * 2
|
||||
22 │ }
|
||||
23 │
|
||||
24 │ // Tab alignment:
|
||||
25 │ /*
|
||||
26 │ Indent
|
||||
27 │ 1 2 3 4
|
||||
28 │ 1 ?
|
||||
29 │ 22 ?
|
||||
30 │ 333 ?
|
||||
31 │ 4444 ?
|
||||
32 │ 55555 ?
|
||||
33 │ 666666 ?
|
||||
34 │ 7777777 ?
|
||||
35 │ 88888888 ?
|
||||
36 │ */
|
||||
─────┴──────────────────────────────────────────────────────────────────────────
|
||||
@@ -21,3 +21,17 @@ fn area(rectangle: &Rectangle) -> u32 {
|
||||
fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
(rectangle.width + rectangle.height) * 2
|
||||
}
|
||||
|
||||
// Tab alignment:
|
||||
/*
|
||||
Indent
|
||||
1 2 3 4
|
||||
1 ?
|
||||
22 ?
|
||||
333 ?
|
||||
4444 ?
|
||||
55555 ?
|
||||
666666 ?
|
||||
7777777 ?
|
||||
88888888 ?
|
||||
*/
|
||||
|
||||
+14
@@ -21,3 +21,17 @@
|
||||
20 fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
21 (rectangle.width + rectangle.height) * 2
|
||||
22 }
|
||||
23
|
||||
24 // Tab alignment:
|
||||
25 /*
|
||||
26 Indent
|
||||
27 1 2 3 4
|
||||
28 1 ?
|
||||
29 22 ?
|
||||
30 333 ?
|
||||
31 4444 ?
|
||||
32 55555 ?
|
||||
33 666666 ?
|
||||
34 7777777 ?
|
||||
35 88888888 ?
|
||||
36 */
|
||||
@@ -20,3 +20,17 @@
|
||||
20 fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
21 (rectangle.width + rectangle.height) * 2
|
||||
22 }
|
||||
23
|
||||
24 // Tab alignment:
|
||||
25 /*
|
||||
26 Indent
|
||||
27 1 2 3 4
|
||||
28 1 ?
|
||||
29 22 ?
|
||||
30 333 ?
|
||||
31 4444 ?
|
||||
32 55555 ?
|
||||
33 666666 ?
|
||||
34 7777777 ?
|
||||
35 88888888 ?
|
||||
36 */
|
||||
|
||||
@@ -20,3 +20,17 @@ fn area(rectangle: &Rectangle) -> u32 {
|
||||
fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
(rectangle.width + rectangle.height) * 2
|
||||
}
|
||||
|
||||
// Tab alignment:
|
||||
/*
|
||||
Indent
|
||||
1 2 3 4
|
||||
1 ?
|
||||
22 ?
|
||||
333 ?
|
||||
4444 ?
|
||||
55555 ?
|
||||
666666 ?
|
||||
7777777 ?
|
||||
88888888 ?
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
───────┬────────────────────────────────────────────────────────────────────────
|
||||
│ File: sample.rs
|
||||
───────┼────────────────────────────────────────────────────────────────────────
|
||||
1 │ struct Rectangle {
|
||||
2 │ width: u32,
|
||||
3 │ height: u32,
|
||||
4 │ }
|
||||
5 │
|
||||
6 _ │ fn main() {
|
||||
7 │ let rect1 = Rectangle { width: 30, height: 50 };
|
||||
8 │
|
||||
9 │ println!(
|
||||
10 ~ │ "The perimeter of the rectangle is {} pixels.",
|
||||
11 ~ │ perimeter(&rect1)
|
||||
12 │ );
|
||||
13 + │ println!(r#"This line contains invalid utf8: "�����"#;
|
||||
14 │ }
|
||||
15 │
|
||||
16 │ fn area(rectangle: &Rectangle) -> u32 {
|
||||
17 │ rectangle.width * rectangle.height
|
||||
18 │ }
|
||||
19 │
|
||||
20 + │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
21 + │ (rectangle.width + rectangle.height) * 2
|
||||
22 + │ }
|
||||
23 + │
|
||||
24 │ // Tab alignment:
|
||||
25 │ /*
|
||||
26 │ Indent
|
||||
27 │ 1 2 3 4
|
||||
28 │ 1 ?
|
||||
29 │ 22 ?
|
||||
30 │ 333 ?
|
||||
31 │ 4444 ?
|
||||
32 │ 55555 ?
|
||||
33 │ 666666 ?
|
||||
34 │ 7777777 ?
|
||||
35 │ 88888888 ?
|
||||
36 ~ │ */
|
||||
───────┴────────────────────────────────────────────────────────────────────────
|
||||
@@ -0,0 +1,40 @@
|
||||
───────┬────────────────────────────────────────────────────────────────────────
|
||||
│ File: sample.rs
|
||||
───────┼────────────────────────────────────────────────────────────────────────
|
||||
1 │ struct Rectangle {
|
||||
2 │ width: u32,
|
||||
3 │ height: u32,
|
||||
4 │ }
|
||||
5 │
|
||||
6 _ │ fn main() {
|
||||
7 │ let rect1 = Rectangle { width: 30, height: 50 };
|
||||
8 │
|
||||
9 │ println!(
|
||||
10 ~ │ "The perimeter of the rectangle is {} pixels.",
|
||||
11 ~ │ perimeter(&rect1)
|
||||
12 │ );
|
||||
13 + │ println!(r#"This line contains invalid utf8: "�����"#;
|
||||
14 │ }
|
||||
15 │
|
||||
16 │ fn area(rectangle: &Rectangle) -> u32 {
|
||||
17 │ rectangle.width * rectangle.height
|
||||
18 │ }
|
||||
19 │
|
||||
20 + │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
21 + │ (rectangle.width + rectangle.height) * 2
|
||||
22 + │ }
|
||||
23 + │
|
||||
24 │ // Tab alignment:
|
||||
25 │ /*
|
||||
26 │ Indent
|
||||
27 │ 1 2 3 4
|
||||
28 │ 1 ?
|
||||
29 │ 22 ?
|
||||
30 │ 333 ?
|
||||
31 │ 4444 ?
|
||||
32 │ 55555 ?
|
||||
33 │ 666666 ?
|
||||
34 │ 7777777 ?
|
||||
35 │ 88888888 ?
|
||||
36 ~ │ */
|
||||
───────┴────────────────────────────────────────────────────────────────────────
|
||||
@@ -0,0 +1,40 @@
|
||||
───────┬────────────────────────────────────────────────────────────────────────
|
||||
│ File: sample.rs
|
||||
───────┼────────────────────────────────────────────────────────────────────────
|
||||
1 │ struct Rectangle {
|
||||
2 │ width: u32,
|
||||
3 │ height: u32,
|
||||
4 │ }
|
||||
5 │
|
||||
6 _ │ fn main() {
|
||||
7 │ let rect1 = Rectangle { width: 30, height: 50 };
|
||||
8 │
|
||||
9 │ println!(
|
||||
10 ~ │ "The perimeter of the rectangle is {} pixels.",
|
||||
11 ~ │ perimeter(&rect1)
|
||||
12 │ );
|
||||
13 + │ println!(r#"This line contains invalid utf8: "�����"#;
|
||||
14 │ }
|
||||
15 │
|
||||
16 │ fn area(rectangle: &Rectangle) -> u32 {
|
||||
17 │ rectangle.width * rectangle.height
|
||||
18 │ }
|
||||
19 │
|
||||
20 + │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
21 + │ (rectangle.width + rectangle.height) * 2
|
||||
22 + │ }
|
||||
23 + │
|
||||
24 │ // Tab alignment:
|
||||
25 │ /*
|
||||
26 │ Indent
|
||||
27 │ 1 2 3 4
|
||||
28 │ 1 ?
|
||||
29 │ 22 ?
|
||||
30 │ 333 ?
|
||||
31 │ 4444 ?
|
||||
32 │ 55555 ?
|
||||
33 │ 666666 ?
|
||||
34 │ 7777777 ?
|
||||
35 │ 88888888 ?
|
||||
36 ~ │ */
|
||||
───────┴────────────────────────────────────────────────────────────────────────
|
||||
@@ -0,0 +1,40 @@
|
||||
───────┬────────────────────────────────────────────────────────────────────────
|
||||
│ File: sample.rs
|
||||
───────┼────────────────────────────────────────────────────────────────────────
|
||||
1 │ struct Rectangle {
|
||||
2 │ width: u32,
|
||||
3 │ height: u32,
|
||||
4 │ }
|
||||
5 │
|
||||
6 _ │ fn main() {
|
||||
7 │ let rect1 = Rectangle { width: 30, height: 50 };
|
||||
8 │
|
||||
9 │ println!(
|
||||
10 ~ │ "The perimeter of the rectangle is {} pixels.",
|
||||
11 ~ │ perimeter(&rect1)
|
||||
12 │ );
|
||||
13 + │ println!(r#"This line contains invalid utf8: "�����"#;
|
||||
14 │ }
|
||||
15 │
|
||||
16 │ fn area(rectangle: &Rectangle) -> u32 {
|
||||
17 │ rectangle.width * rectangle.height
|
||||
18 │ }
|
||||
19 │
|
||||
20 + │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
21 + │ (rectangle.width + rectangle.height) * 2
|
||||
22 + │ }
|
||||
23 + │
|
||||
24 │ // Tab alignment:
|
||||
25 │ /*
|
||||
26 │ Indent
|
||||
27 │ 1 2 3 4
|
||||
28 │ 1 ?
|
||||
29 │ 22 ?
|
||||
30 │ 333 ?
|
||||
31 │ 4444 ?
|
||||
32 │ 55555 ?
|
||||
33 │ 666666 ?
|
||||
34 │ 7777777 ?
|
||||
35 │ 88888888 ?
|
||||
36 ~ │ */
|
||||
───────┴────────────────────────────────────────────────────────────────────────
|
||||
+15
-1
@@ -19,8 +19,22 @@
|
||||
16 │ fn area(rectangle: &Rectangle) -> u32 {
|
||||
17 │ rectangle.width * rectangle.height
|
||||
18 │ }
|
||||
19 + │
|
||||
19 │
|
||||
20 + │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
21 + │ (rectangle.width + rectangle.height) * 2
|
||||
22 + │ }
|
||||
23 + │
|
||||
24 │ // Tab alignment:
|
||||
25 │ /*
|
||||
26 │ Indent
|
||||
27 │ 1 2 3 4
|
||||
28 │ 1 ?
|
||||
29 │ 22 ?
|
||||
30 │ 333 ?
|
||||
31 │ 4444 ?
|
||||
32 │ 55555 ?
|
||||
33 │ 666666 ?
|
||||
34 │ 7777777 ?
|
||||
35 │ 88888888 ?
|
||||
36 ~ │ */
|
||||
───────┴────────────────────────────────────────────────────────────────────────
|
||||
@@ -0,0 +1,40 @@
|
||||
───────┬────────────────────────────────────────────────────────────────────────
|
||||
│ File: sample.rs
|
||||
───────┼────────────────────────────────────────────────────────────────────────
|
||||
1 │ struct Rectangle {
|
||||
2 │ width: u32,
|
||||
3 │ height: u32,
|
||||
4 │ }
|
||||
5 │
|
||||
6 _ │ fn main() {
|
||||
7 │ let rect1 = Rectangle { width: 30, height: 50 };
|
||||
8 │
|
||||
9 │ println!(
|
||||
10 ~ │ "The perimeter of the rectangle is {} pixels.",
|
||||
11 ~ │ perimeter(&rect1)
|
||||
12 │ );
|
||||
13 + │ println!(r#"This line contains invalid utf8: "�����"#;
|
||||
14 │ }
|
||||
15 │
|
||||
16 │ fn area(rectangle: &Rectangle) -> u32 {
|
||||
17 │ rectangle.width * rectangle.height
|
||||
18 │ }
|
||||
19 │
|
||||
20 + │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
21 + │ (rectangle.width + rectangle.height) * 2
|
||||
22 + │ }
|
||||
23 + │
|
||||
24 │ // Tab alignment:
|
||||
25 │ /*
|
||||
26 │ Indent
|
||||
27 │ 1 2 3 4
|
||||
28 │ 1 ?
|
||||
29 │ 22 ?
|
||||
30 │ 333 ?
|
||||
31 │ 4444 ?
|
||||
32 │ 55555 ?
|
||||
33 │ 666666 ?
|
||||
34 │ 7777777 ?
|
||||
35 │ 88888888 ?
|
||||
36 ~ │ */
|
||||
───────┴────────────────────────────────────────────────────────────────────────
|
||||
@@ -20,3 +20,17 @@ fn area(rectangle: &Rectangle) -> u32 {
|
||||
fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
(rectangle.width + rectangle.height) * 2
|
||||
}
|
||||
|
||||
// Tab alignment:
|
||||
/*
|
||||
Indent
|
||||
1 2 3 4
|
||||
1 ?
|
||||
22 ?
|
||||
333 ?
|
||||
4444 ?
|
||||
55555 ?
|
||||
666666 ?
|
||||
7777777 ?
|
||||
88888888 ?
|
||||
*/
|
||||
|
||||
@@ -16,3 +16,17 @@ fn main() {
|
||||
fn area(rectangle: &Rectangle) -> u32 {
|
||||
rectangle.width * rectangle.height
|
||||
}
|
||||
|
||||
// Tab alignment:
|
||||
/*
|
||||
Indent
|
||||
1 2 3 4
|
||||
1 ?
|
||||
22 ?
|
||||
333 ?
|
||||
4444 ?
|
||||
55555 ?
|
||||
666666 ?
|
||||
7777777 ?
|
||||
88888888 ?
|
||||
*/
|
||||
+59
-29
@@ -1,17 +1,29 @@
|
||||
use std::env;
|
||||
use std::fs::{self, File};
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
extern crate tempdir;
|
||||
use self::tempdir::TempDir;
|
||||
|
||||
extern crate git2;
|
||||
use self::git2::build::CheckoutBuilder;
|
||||
use self::git2::Repository;
|
||||
use self::git2::Signature;
|
||||
|
||||
pub struct BatTester {
|
||||
/// Temporary working directory
|
||||
temp_dir: TempDir,
|
||||
|
||||
/// Path to the *bat* executable
|
||||
exe: PathBuf,
|
||||
}
|
||||
|
||||
impl BatTester {
|
||||
pub fn new() -> Self {
|
||||
modify_sample_file();
|
||||
// Lifted from fd :)
|
||||
let temp_dir = create_sample_directory().expect("sample directory");
|
||||
|
||||
let root = env::current_exe()
|
||||
.expect("tests executable")
|
||||
.parent()
|
||||
@@ -21,24 +33,33 @@ impl BatTester {
|
||||
.to_path_buf();
|
||||
|
||||
let exe_name = if cfg!(windows) { "bat.exe" } else { "bat" };
|
||||
let exe = root.join(exe_name);
|
||||
|
||||
BatTester {
|
||||
exe: root.join(exe_name),
|
||||
}
|
||||
BatTester { temp_dir, exe }
|
||||
}
|
||||
|
||||
pub fn test_snapshot(&self, style: &str) {
|
||||
pub fn test_snapshot(&self, name: &str, style: &str, tab_width: u32, wrap: bool) {
|
||||
let output = Command::new(&self.exe)
|
||||
.args(&["tests/snapshots/sample.rs", &format!("--style={}", style)])
|
||||
.output()
|
||||
.current_dir(self.temp_dir.path())
|
||||
.args(&[
|
||||
"sample.rs",
|
||||
"--paging=never",
|
||||
"--color=never",
|
||||
"--decorations=always",
|
||||
"--terminal-width=80",
|
||||
&format!("--wrap={}", if wrap { "character" } else { "never" }),
|
||||
&format!("--tabs={}", tab_width),
|
||||
&format!("--style={}", style),
|
||||
]).output()
|
||||
.expect("bat failed");
|
||||
|
||||
// have to do the replace because the filename in the header changes based on the current working directory
|
||||
let actual = String::from_utf8_lossy(&output.stdout)
|
||||
.as_ref()
|
||||
.replace("tests/snapshots/", "");
|
||||
|
||||
let mut expected = String::new();
|
||||
let mut file = File::open(format!("tests/snapshots/output/{}.snapshot.txt", style))
|
||||
let mut file = File::open(format!("tests/snapshots/output/{}.snapshot.txt", name))
|
||||
.expect("snapshot file missing");
|
||||
file.read_to_string(&mut expected)
|
||||
.expect("could not read snapshot file");
|
||||
@@ -47,26 +68,35 @@ impl BatTester {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for BatTester {
|
||||
fn drop(&mut self) {
|
||||
undo_sample_file_modification();
|
||||
}
|
||||
}
|
||||
fn create_sample_directory() -> Result<TempDir, git2::Error> {
|
||||
// Create temp directory and initialize repository
|
||||
let temp_dir = TempDir::new("bat-tests").expect("Temp directory");
|
||||
let repo = Repository::init(&temp_dir)?;
|
||||
|
||||
fn modify_sample_file() {
|
||||
fs::copy(
|
||||
"tests/snapshots/sample.modified.rs",
|
||||
"tests/snapshots/sample.rs",
|
||||
).expect("generating modified sample file failed");
|
||||
}
|
||||
// Copy over `sample.rs`
|
||||
let sample_path = temp_dir.path().join("sample.rs");
|
||||
println!("{:?}", &sample_path);
|
||||
fs::copy("tests/snapshots/sample.rs", &sample_path).expect("successful copy");
|
||||
|
||||
fn undo_sample_file_modification() {
|
||||
let output = Command::new("git")
|
||||
.args(&["checkout", "--", "tests/snapshots/sample.rs"])
|
||||
.output()
|
||||
.expect("git checkout failed");
|
||||
// Commit
|
||||
let mut index = repo.index()?;
|
||||
index.add_path(Path::new("sample.rs"))?;
|
||||
|
||||
if !output.status.success() {
|
||||
panic!("undoing modified sample changes failed")
|
||||
}
|
||||
let oid = index.write_tree()?;
|
||||
let signature = Signature::now("bat test runner", "bat@test.runner")?;
|
||||
let tree = repo.find_tree(oid)?;
|
||||
let _ = repo.commit(
|
||||
Some("HEAD"), // point HEAD to our new commit
|
||||
&signature, // author
|
||||
&signature, // committer
|
||||
"initial commit",
|
||||
&tree,
|
||||
&[],
|
||||
);
|
||||
let mut opts = CheckoutBuilder::new();
|
||||
repo.checkout_head(Some(opts.force()))?;
|
||||
|
||||
fs::copy("tests/snapshots/sample.modified.rs", &sample_path).expect("successful copy");
|
||||
|
||||
Ok(temp_dir)
|
||||
}
|
||||
|
||||
+36
-28
@@ -2,32 +2,40 @@ mod tester;
|
||||
|
||||
use tester::BatTester;
|
||||
|
||||
static STYLES: &'static [&'static str] = &[
|
||||
"changes",
|
||||
"grid",
|
||||
"header",
|
||||
"numbers",
|
||||
"changes,grid",
|
||||
"changes,header",
|
||||
"changes,numbers",
|
||||
"grid,header",
|
||||
"grid,numbers",
|
||||
"header,numbers",
|
||||
"changes,grid,header",
|
||||
"changes,grid,numbers",
|
||||
"changes,header,numbers",
|
||||
"grid,header,numbers",
|
||||
"changes,grid,header,numbers",
|
||||
"full",
|
||||
"plain",
|
||||
];
|
||||
|
||||
#[test]
|
||||
fn test_snapshots() {
|
||||
let bat_tester = BatTester::new();
|
||||
|
||||
for style in STYLES {
|
||||
println!("testing {}", style);
|
||||
bat_tester.test_snapshot(&*style);
|
||||
}
|
||||
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],
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user