mirror of
https://github.com/sharkdp/bat.git
synced 2026-11-15 01:05:55 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e09499b3df | ||
|
|
cff01d81fa | ||
|
|
31608c9a03 | ||
|
|
357ce84c56 | ||
|
|
3a5c52641b | ||
|
|
6e8fca5bb2 | ||
|
|
63c77383ce | ||
|
|
4df22e617f | ||
|
|
6473e8c1be | ||
|
|
972a764a74 | ||
|
|
54143d1403 | ||
|
|
6523bbf62f | ||
|
|
05e2c2c66b | ||
|
|
69227222b5 | ||
|
|
49af3e854b | ||
|
|
6a8e4757b7 | ||
|
|
91deef8b13 | ||
|
|
61e888de7f | ||
|
|
f3f9f10f05 | ||
|
|
29ffa2a832 | ||
|
|
42a873fdb8 | ||
|
|
82f048aedb | ||
|
|
ae08785ec8 | ||
|
|
a500629359 | ||
|
|
724a5fac99 | ||
|
|
c483e49b92 | ||
|
|
94c9b40694 | ||
|
|
0c9dc3b257 | ||
|
|
3b5174bb1d | ||
|
|
3324505383 | ||
|
|
de7872f8a8 | ||
|
|
abf0229741 | ||
|
|
e04bccd12d | ||
|
|
668c8a6703 | ||
|
|
bd68684537 | ||
|
|
c2847f6a9f | ||
|
|
cf7ed042c1 | ||
|
|
6b92814ea0 | ||
|
|
a236a9b195 | ||
|
|
b68c5d8576 | ||
|
|
fee57d71d9 | ||
|
|
5d3205acc0 | ||
|
|
4e6816abd6 | ||
|
|
72e8036edc | ||
|
|
397def1320 | ||
|
|
d2d29180a7 | ||
|
|
2f263c9fbf | ||
|
|
4ff360669f | ||
|
|
549e5d7355 | ||
|
|
dd48d29c28 | ||
|
|
98ee5f7400 | ||
|
|
638c04c13e | ||
|
|
b1c865acaa | ||
|
|
d3d795ffb2 | ||
|
|
0571c51487 | ||
|
|
348c9f3562 | ||
|
|
6b6a8f8e16 | ||
|
|
6aa002850c | ||
|
|
49c22c8d39 | ||
|
|
673caf6b59 | ||
|
|
e6ffab3cb4 | ||
|
|
4e43f8fa74 | ||
|
|
bac1b16885 | ||
|
|
778a4929a8 | ||
|
|
5c22dd4248 | ||
|
|
214cd0f8ea | ||
|
|
9fd61fcb6d | ||
|
|
edf1d3b256 | ||
|
|
eca47b2a28 | ||
|
|
62424e70d7 | ||
|
|
4791f15222 | ||
|
|
159f234b78 | ||
|
|
3ec96127f2 | ||
|
|
a9acb2711b | ||
|
|
a3182e68e4 | ||
|
|
0691b18231 | ||
|
|
c711cd1b2e | ||
|
|
14e6b41a5f | ||
|
|
532af6556d | ||
|
|
26717b0cd2 | ||
|
|
1f177f0a1c | ||
|
|
54c81fa543 | ||
|
|
34dee9e3aa | ||
|
|
c073d4a118 | ||
|
|
e79c5516bf | ||
|
|
4776c2a575 | ||
|
|
f98a96c1ed | ||
|
|
8a3446d219 | ||
|
|
5d5bf616ca | ||
|
|
b68c038db8 | ||
|
|
1117d2f9cb | ||
|
|
d0ba5bcb32 | ||
|
|
f8d39d5624 | ||
|
|
9998e2eac6 | ||
|
|
7cac07d845 | ||
|
|
148caa1381 | ||
|
|
ab27cac0cc | ||
|
|
01fcbf2183 | ||
|
|
8a0c30b385 | ||
|
|
bc21c4d0e0 | ||
|
|
0800562ba2 | ||
|
|
1f9befbcd1 | ||
|
|
a5c779c518 | ||
|
|
f37f100352 | ||
|
|
18d1a3b973 | ||
|
|
dc10246bd2 | ||
|
|
44bdae0212 | ||
|
|
1ece38a4c4 | ||
|
|
e90308e1f8 | ||
|
|
d702d6740c | ||
|
|
c6a526f99c | ||
|
|
278d841408 | ||
|
|
5f576f1ecf | ||
|
|
48c6ea6b25 | ||
|
|
558134f6c8 | ||
|
|
1dd57e6d7e | ||
|
|
20ba84d1fa | ||
|
|
e81f9b23e6 | ||
|
|
50dc4a79b0 | ||
|
|
8fa8f44706 | ||
|
|
ecd862d9ff | ||
|
|
cbed338c3a | ||
|
|
4492d99556 | ||
|
|
d96ee2261f | ||
|
|
dda27b253b | ||
|
|
78f26d0caf | ||
|
|
abcd09f869 | ||
|
|
41a5ff039b | ||
|
|
155bad3862 | ||
|
|
7c98a1c901 | ||
|
|
c1246fcd53 | ||
|
|
9f401ea122 | ||
|
|
9c782fb692 | ||
|
|
154186a58d | ||
|
|
b22a9f8fe3 | ||
|
|
5219c40ed8 | ||
|
|
a25ee0e6fd | ||
|
|
496e0bc046 | ||
|
|
7082fd09f0 | ||
|
|
857cc215b4 | ||
|
|
481268f018 | ||
|
|
f7d9f49503 | ||
|
|
88fcfd76aa | ||
|
|
76e34b29ec | ||
|
|
01984e1d02 | ||
|
|
536390509f | ||
|
|
58198d0700 | ||
|
|
afc5aacb28 | ||
|
|
30b742e984 | ||
|
|
671deeef8c | ||
|
|
a892caeb33 | ||
|
|
a770cbf25e | ||
|
|
931c6e9414 | ||
|
|
8dc7e2efa3 | ||
|
|
10965a6122 | ||
|
|
e43d97dc15 | ||
|
|
2c7087b8de | ||
|
|
bb1f5aa841 | ||
|
|
2109a7830b | ||
|
|
ec27c78a8a | ||
|
|
67fe833bc8 | ||
|
|
e956225b4d | ||
|
|
314ec881ef | ||
|
|
25a6a55437 | ||
|
|
5bff4548be | ||
|
|
866b9e16a8 | ||
|
|
5af176c94f | ||
|
|
9e7da05459 | ||
|
|
1ae02c65fb | ||
|
|
495e7fd3b1 | ||
|
|
b48f0fe389 | ||
|
|
c19c704a43 | ||
|
|
693bd5929d | ||
|
|
8275b0436d | ||
|
|
278bde5cee | ||
|
|
eee7e5a575 | ||
|
|
ad7b634ee6 | ||
|
|
1310f83c8d | ||
|
|
897b9e7030 | ||
|
|
1891e194b5 | ||
|
|
cea05e9f22 | ||
|
|
d2d01b9fe8 | ||
|
|
2a7851530d | ||
|
|
1a6709c2cb | ||
|
|
5842d58c01 | ||
|
|
e3c71adba7 | ||
|
|
504f28b3a1 | ||
|
|
d977ba9194 | ||
|
|
9c09799e1f | ||
|
|
d83c93c805 | ||
|
|
fc8fd1e63f | ||
|
|
404d6a4a81 | ||
|
|
25d96da4a2 | ||
|
|
e97095b724 | ||
|
|
ce96df00b6 | ||
|
|
f98fc5f06a | ||
|
|
1dbb4ef683 | ||
|
|
0502a3bd4a | ||
|
|
869cf6368c | ||
|
|
078228deac | ||
|
|
e09d7dabb8 | ||
|
|
6d1cc8c2c8 | ||
|
|
87f021078e | ||
|
|
d5b0502419 | ||
|
|
860f3e9006 | ||
|
|
1be346a038 | ||
|
|
f9fd5e4851 | ||
|
|
da09f3877b | ||
|
|
e30e1bab2e | ||
|
|
f140f6da46 | ||
|
|
3446fdf5f2 | ||
|
|
e1345cdc2a | ||
|
|
a2676ccc55 | ||
|
|
b39e28d2c8 | ||
|
|
0d71968615 | ||
|
|
80da0dc619 | ||
|
|
64903bb858 | ||
|
|
3456ce1187 | ||
|
|
886a5b3d24 | ||
|
|
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 |
No files matched your search
+63
-1
@@ -6,7 +6,7 @@
|
||||
url = https://github.com/sublimehq/Packages/
|
||||
[submodule "assets/syntaxes/TOML"]
|
||||
path = assets/syntaxes/TOML
|
||||
url = https://github.com/sharkdp/sublime_toml_highlighting
|
||||
url = https://github.com/jasonwilliams/sublime_toml_highlighting
|
||||
[submodule "assets/syntaxes/Julia"]
|
||||
path = assets/syntaxes/Julia
|
||||
url = https://github.com/JuliaEditorSupport/Julia-sublime
|
||||
@@ -61,3 +61,65 @@
|
||||
[submodule "assets/syntaxes/Puppet"]
|
||||
path = assets/syntaxes/Puppet
|
||||
url = https://github.com/russCloak/SublimePuppet
|
||||
[submodule "assets/syntaxes/CSV"]
|
||||
path = assets/syntaxes/CSV
|
||||
url = https://github.com/wadetb/Sublime-Text-Advanced-CSV
|
||||
[submodule "assets/themes/onehalf"]
|
||||
path = assets/themes/onehalf
|
||||
url = https://github.com/sonph/onehalf
|
||||
[submodule "assets/syntaxes/JavaScript (Babel)"]
|
||||
path = assets/syntaxes/JavaScript (Babel)
|
||||
url = https://github.com/babel/babel-sublime
|
||||
[submodule "assets/syntaxes/Cabal"]
|
||||
path = assets/syntaxes/Cabal
|
||||
url = https://github.com/SublimeHaskell/SublimeHaskell
|
||||
[submodule "assets/syntaxes/Dart"]
|
||||
path = assets/syntaxes/Dart
|
||||
url = https://github.com/guillermooo/dart-sublime-bundle
|
||||
[submodule "assets/syntaxes/FSharp"]
|
||||
path = assets/syntaxes/FSharp
|
||||
url = https://github.com/hoest/sublimetext-fsharp
|
||||
[submodule "assets/syntaxes/PureScript"]
|
||||
path = assets/syntaxes/PureScript
|
||||
url = https://github.com/tellnobody1/sublime-purescript-syntax
|
||||
[submodule "assets/syntaxes/Swift"]
|
||||
path = assets/syntaxes/Swift
|
||||
url = https://github.com/quiqueg/Swift-Sublime-Package
|
||||
[submodule "assets/syntaxes/Crystal"]
|
||||
path = assets/syntaxes/Crystal
|
||||
url = https://github.com/crystal-lang-tools/sublime-crystal.git
|
||||
[submodule "assets/syntaxes/PowerShell"]
|
||||
path = assets/syntaxes/PowerShell
|
||||
url = https://github.com/PowerShell/EditorSyntax
|
||||
[submodule "assets/syntaxes/Robot"]
|
||||
path = assets/syntaxes/Robot
|
||||
url = https://github.com/andriyko/sublime-robot-framework-assistant.git
|
||||
[submodule "assets/themes/sublime-snazzy"]
|
||||
path = assets/themes/sublime-snazzy
|
||||
url = https://github.com/greggb/sublime-snazzy
|
||||
[submodule "assets/syntaxes/HTML (Twig)"]
|
||||
path = assets/syntaxes/HTML (Twig)
|
||||
url = https://github.com/Anomareh/PHP-Twig.tmbundle.git
|
||||
[submodule "assets/syntaxes/AsciiDoc"]
|
||||
path = assets/syntaxes/AsciiDoc
|
||||
url = https://github.com/SublimeText/AsciiDoc.git
|
||||
[submodule "assets/syntaxes/Assembly (ARM)"]
|
||||
path = assets/syntaxes/Assembly (ARM)
|
||||
url = https://github.com/tvi/Sublime-ARM-Assembly
|
||||
[submodule "assets/syntaxes/syslog-syntax"]
|
||||
path = assets/syntaxes/Syslog
|
||||
url = https://github.com/caos21/syslog-syntax.git
|
||||
branch = master
|
||||
[submodule "assets/syntaxes/protobuf-syntax-highlighting"]
|
||||
path = assets/syntaxes/Protobuf
|
||||
url = https://github.com/VcamX/protobuf-syntax-highlighting.git
|
||||
branch = master
|
||||
[submodule "assets/syntaxes/Terraform"]
|
||||
path = assets/syntaxes/Terraform
|
||||
url = https://github.com/alexlouden/Terraform.tmLanguage.git
|
||||
[submodule "assets/syntaxes/Jsonnet"]
|
||||
path = assets/syntaxes/Jsonnet
|
||||
url = https://github.com/gburiola/sublime-jsonnet-syntax.git
|
||||
[submodule "assets/syntaxes/varlink"]
|
||||
path = assets/syntaxes/varlink
|
||||
url = https://github.com/varlink/syntax-highlight-varlink.git
|
||||
+17
-4
@@ -1,5 +1,5 @@
|
||||
language: rust
|
||||
cache: cargo
|
||||
|
||||
matrix:
|
||||
include:
|
||||
# Stable channel.
|
||||
@@ -23,18 +23,24 @@ matrix:
|
||||
- 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.26.0
|
||||
rust: 1.30.0
|
||||
env: TARGET=x86_64-unknown-linux-gnu
|
||||
- os: linux
|
||||
rust: 1.26.0
|
||||
rust: 1.30.0
|
||||
env:
|
||||
- TARGET=x86_64-unknown-linux-musl
|
||||
- CC_x86_64_unknown_linux_musl=/usr/bin/musl-gcc
|
||||
- os: osx
|
||||
rust: 1.26.0
|
||||
rust: 1.30.0
|
||||
env: TARGET=x86_64-apple-darwin
|
||||
|
||||
# Code formatting check
|
||||
@@ -97,3 +103,10 @@ deploy:
|
||||
notifications:
|
||||
email:
|
||||
on_success: never
|
||||
|
||||
# Caching
|
||||
cache:
|
||||
directories:
|
||||
- /home/travis/.cargo
|
||||
before_cache:
|
||||
- rm -rf /home/travis/.cargo/registry
|
||||
Generated
+586
-206
File diff suppressed because it is too large.
Load diff
+17
-6
@@ -7,26 +7,32 @@ license = "MIT/Apache-2.0"
|
||||
name = "bat"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/sharkdp/bat"
|
||||
version = "0.6.0"
|
||||
version = "0.10.0"
|
||||
exclude = [
|
||||
"assets/syntaxes/*",
|
||||
"assets/themes/*",
|
||||
]
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
atty = "0.2.2"
|
||||
ansi_term = "0.11"
|
||||
console = "0.6"
|
||||
directories = "1.0"
|
||||
lazy_static = "1.0"
|
||||
ansi_colours = "^1.0"
|
||||
console = "0.7"
|
||||
dirs = "1.0"
|
||||
lazy_static = "1.2"
|
||||
wild = "2.0"
|
||||
content_inspector = "0.2.4"
|
||||
encoding = "0.2"
|
||||
shell-words = "0.1.0"
|
||||
|
||||
[dependencies.git2]
|
||||
version = "0.7"
|
||||
version = "0.8"
|
||||
default-features = false
|
||||
features = []
|
||||
|
||||
[dependencies.syntect]
|
||||
version = "2.1"
|
||||
version = "3.0.2"
|
||||
default-features = false
|
||||
features = ["parsing", "yaml-load", "dump-load", "dump-create"]
|
||||
|
||||
@@ -42,3 +48,8 @@ features = []
|
||||
|
||||
[dev-dependencies]
|
||||
tempdir = "0.3"
|
||||
assert_cmd = "0.11.0"
|
||||
escargot = "0.4.0"
|
||||
|
||||
[build-dependencies]
|
||||
clap = "2.32"
|
||||
@@ -1,3 +1,5 @@
|
||||
Copyright (c) 2018 bat-developers (https://github.com/sharkdp/bat).
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<p align="center">
|
||||
<img src="doc/logo-header.svg" alt="bat - a cat clone with wings"><br>
|
||||
<a href="https://travis-ci.org/sharkdp/bat"><img src="https://travis-ci.org/sharkdp/bat.svg?branch=master" alt="Build Status"></a>
|
||||
<a href="https://ci.appveyor.com/project/sharkdp/bat"><img src="https://ci.appveyor.com/api/projects/status/cptsmtbiwbnr2vhf?svg=true"></a>
|
||||
<img src="https://img.shields.io/crates/l/bat.svg" alt="license">
|
||||
<a href="https://crates.io/crates/bat"><img src="https://img.shields.io/crates/v/bat.svg?colorB=319e8c" alt="Version info"></a><br>
|
||||
A <i>cat(1)</i> clone with syntax highlighting and Git integration.
|
||||
@@ -11,7 +12,8 @@
|
||||
<a href="#how-to-use">How To Use</a> •
|
||||
<a href="#installation">Installation</a> •
|
||||
<a href="#customization">Customization</a> •
|
||||
<a href="#project-goals-and-alternatives">Project goals, alternatives</a>
|
||||
<a href="#project-goals-and-alternatives">Project goals, alternatives</a> •
|
||||
Translation [<a href="https://github.com/chinanf-boy/bat-zh">中文</a>][<a href="doc/README-ja.md">日本文</a>]
|
||||
</p>
|
||||
|
||||
### Syntax highlighting
|
||||
@@ -28,6 +30,13 @@ languages:
|
||||
|
||||

|
||||
|
||||
### Show non-printable characters
|
||||
|
||||
You can use the `-A`/`--show-all` option to show and highlight non-printable
|
||||
characters:
|
||||
|
||||

|
||||
|
||||
### Automatic paging
|
||||
|
||||
`bat` can pipe its own output to `less` if the output is too large for one screen.
|
||||
@@ -35,8 +44,9 @@ languages:
|
||||
### File concatenation
|
||||
|
||||
Oh.. you can also use it to concatenate files :wink:. Whenever
|
||||
`bat` detects a non-interactive terminal, it will fall back to printing
|
||||
the plain file contents.
|
||||
`bat` detects a non-interactive terminal (i.e. when you pipe into another process
|
||||
or into a file), `bat` will act as a drop-in replacement for `cat` and
|
||||
fall back to printing the plain file contents.
|
||||
|
||||
## How to use
|
||||
|
||||
@@ -52,17 +62,24 @@ Display multiple files at once
|
||||
> bat src/*.rs
|
||||
```
|
||||
|
||||
Read from stdin, explicitly specify the language
|
||||
Read from stdin, determine the syntax automatically
|
||||
|
||||
```bash
|
||||
> curl -s https://sh.rustup.rs | bat
|
||||
```
|
||||
|
||||
Read from stdin, specify the language explicitly
|
||||
|
||||
```bash
|
||||
> yaml2json .travis.yml | json_pp | bat -l json
|
||||
```
|
||||
|
||||
Show and highlight non-printable characters:
|
||||
```bash
|
||||
> curl -s https://raw.githubusercontent.com/sharkdp/bat/master/src/main.rs | bat -l rs
|
||||
> bat -A /etc/hosts
|
||||
```
|
||||
|
||||
As a replacement for `cat`:
|
||||
Use it as a `cat` replacement:
|
||||
|
||||
```bash
|
||||
bat > note.md # quickly create a new file
|
||||
@@ -82,7 +99,7 @@ bat f - g # output 'f', then stdin, then 'g'.
|
||||
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.6.0_amd64.deb # adapt version number and architecture
|
||||
sudo dpkg -i bat_0.10.0_amd64.deb # adapt version number and architecture
|
||||
```
|
||||
|
||||
### On Arch Linux
|
||||
@@ -94,6 +111,14 @@ from the official sources:
|
||||
pacman -S bat
|
||||
```
|
||||
|
||||
### On Fedora
|
||||
|
||||
You can install `bat` from the [Fedora Modular](https://docs.fedoraproject.org/en-US/modularity/using-modules/) repository. On Fedora 29 and higher, it is enabled by default. Otherwise, run `dnf install fedora-repos-modular` to set up, and make sure that the `fedora-modular` and `fedora-updates-modular` repos are enabled in `/etc/yum.repos.d`.
|
||||
|
||||
```bash
|
||||
dnf module install bat
|
||||
```
|
||||
|
||||
### On Void Linux
|
||||
|
||||
You can install `bat` via xbps-install:
|
||||
@@ -116,6 +141,22 @@ cd /usr/ports/textproc/bat
|
||||
make install
|
||||
```
|
||||
|
||||
### Via nix
|
||||
|
||||
You can install `bat` using the [nix package manager](https://nixos.org/nix):
|
||||
|
||||
```bash
|
||||
nix-env -i bat
|
||||
```
|
||||
|
||||
### On openSUSE
|
||||
|
||||
You can install `bat` with zypper:
|
||||
|
||||
```
|
||||
zypper install bat
|
||||
```
|
||||
|
||||
### On macOS
|
||||
|
||||
You can install `bat` with [Homebrew](http://braumeister.org/formula/bat):
|
||||
@@ -124,22 +165,70 @@ 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.
|
||||
|
||||
### Via Docker
|
||||
|
||||
There is a [Docker image](https://hub.docker.com/r/danlynn/bat/) that you can use to run `bat` in a container:
|
||||
```bash
|
||||
docker pull danlynn/bat
|
||||
alias bat='docker run -it --rm -e BAT_THEME -e BAT_STYLE -e BAT_TABS -v "$(pwd):/myapp" danlynn/bat'
|
||||
```
|
||||
|
||||
### Via Ansible
|
||||
|
||||
You can install `bat` with [Ansible](https://www.ansible.com/):
|
||||
|
||||
```bash
|
||||
# Install role on local machine
|
||||
ansible-galaxy install aeimer.install_bat
|
||||
```
|
||||
|
||||
```yaml
|
||||
---
|
||||
# Playbook to install bat
|
||||
- host: all
|
||||
roles:
|
||||
- aeimer.install_bat
|
||||
```
|
||||
|
||||
- [Ansible Galaxy](https://galaxy.ansible.com/aeimer/install_bat)
|
||||
- [GitHub](https://github.com/aeimer/ansible-install-bat)
|
||||
|
||||
This should work with the following distributions:
|
||||
- Debian/Ubuntu
|
||||
- ARM (eg. Raspberry PI)
|
||||
- Arch Linux
|
||||
- Void Linux
|
||||
- FreeBSD
|
||||
- MacOS
|
||||
|
||||
### From binaries
|
||||
|
||||
Check out the [Release page](https://github.com/sharkdp/bat/releases) for
|
||||
prebuilt versions of `bat` for many different architectures.
|
||||
prebuilt versions of `bat` for many different architectures. Statically-linked
|
||||
binaries are also available: look for archives with `musl` in the file name.
|
||||
|
||||
### From source
|
||||
|
||||
If you want to build `bat` from source, you need Rust 1.26 or
|
||||
If you want to build `bat` from source, you need Rust 1.30 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
|
||||
|
||||
@@ -148,14 +237,28 @@ some dependencies to be built.
|
||||
Use `bat --list-themes` to get a list of all available themes for syntax
|
||||
highlighting. To select the `TwoDark` theme, call `bat` with the
|
||||
`--theme=TwoDark` option or set the `BAT_THEME` environment variable to
|
||||
`TwoDark`. Use `export BAT_THEME="TwoDark"` in your shells startup file to
|
||||
make the change permanent.
|
||||
`TwoDark`. Use `export BAT_THEME="TwoDark"` in your shell's startup file to
|
||||
make the change permanent. Alternatively, use `bat`s
|
||||
[configuration file](https://github.com/sharkdp/bat#configuration-file).
|
||||
|
||||
If you want to preview the different themes on a custom file, you can use
|
||||
the following command (you need [`fzf`](https://github.com/junegunn/fzf) for this):
|
||||
``` bash
|
||||
bat --list-themes | fzf --preview="bat --theme={} --color=always /path/to/file"
|
||||
```
|
||||
|
||||
`bat` looks good on a dark background by default. However, if your terminal uses a
|
||||
light background, some themes like `GitHub` or `OneHalfLight` will work better for you.
|
||||
You can also use a custom theme by following the
|
||||
['Adding new themes' section below](https://github.com/sharkdp/bat#adding-new-themes).
|
||||
|
||||
### Output style
|
||||
|
||||
You can use the `--style` option to control the appearance of `bat`s output.
|
||||
You can use `--style=numbers,changes`, for example, to show only Git changes
|
||||
and line numbers but no grid and no file header.
|
||||
and line numbers but no grid and no file header. Set the `BAT_STYLE` environment
|
||||
variable to make these changes permanent or use `bat`s
|
||||
[configuration file](https://github.com/sharkdp/bat#configuration-file).
|
||||
|
||||
### Adding new syntaxes / language definitions
|
||||
|
||||
@@ -167,10 +270,8 @@ and theme. To add new syntax definitions, do the following.
|
||||
Create a folder with syntax definition files:
|
||||
|
||||
```bash
|
||||
BAT_CONFIG_DIR="$(bat cache --config-dir)"
|
||||
|
||||
mkdir -p "$BAT_CONFIG_DIR/syntaxes"
|
||||
cd "$BAT_CONFIG_DIR/syntaxes"
|
||||
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:
|
||||
@@ -180,7 +281,7 @@ 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
|
||||
bat cache --build
|
||||
```
|
||||
|
||||
Finally, use `bat --list-languages` to check if the new languages are available.
|
||||
@@ -197,16 +298,14 @@ 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"
|
||||
mkdir -p "$(bat --config-dir)/themes"
|
||||
cd "$(bat --config-dir)/themes"
|
||||
|
||||
# Download a theme in '.tmTheme' format, for example:
|
||||
git clone https://github.com/greggb/sublime-snazzy
|
||||
|
||||
# Update the binary cache
|
||||
bat cache --init
|
||||
bat cache --build
|
||||
```
|
||||
|
||||
Finally, use `bat --list-themes` to check if the new themes are available.
|
||||
@@ -216,13 +315,111 @@ Finally, use `bat --list-themes` to check if the new themes are available.
|
||||
`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:
|
||||
`PAGER`.
|
||||
|
||||
If you want to pass command-line arguments to the pager, you can also set them via the
|
||||
`PAGER`/`BAT_PAGER` variables:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
export BAT_PAGER="less -RF"
|
||||
```
|
||||
|
||||
less --tabs 4 -RF "$@"
|
||||
Instead of using environment variables, you can also use `bat`s [configuration file](https://github.com/sharkdp/bat#configuration-file) to configure the pager (`--pager` option).
|
||||
|
||||
**Note**: By default, if the pager is set to `less` (and no command-line options are specified),
|
||||
`bat` will pass the following command line
|
||||
options to the pager: `-R`/`--RAW-CONTROL-CHARS`, `-F`/`--quit-if-one-screen` and `-X`/`--no-init`.
|
||||
The first (`-R`) is needed to interpret ANSI colors correctly. The second option (`-F`) instructs
|
||||
less to exit immediately if the output size is smaller than the vertical size of the terminal.
|
||||
This is convenient for small files because you do not have to press `q` to quit the pager. The
|
||||
third option (`-X`) is needed to fix a bug with the `--quit-if-one-screen` feature in old versions
|
||||
of `less`. Unfortunately, it also breaks mouse-wheel support in `less`. If you want to enable
|
||||
mouse-wheel scrolling, you can either pass just `-R` (as in the example above, this will disable
|
||||
the quit-if-one-screen feature), or you can use a recent version of `less` and pass `-RF` which
|
||||
will hopefully enable both quit-if-one-screen and mouse-wheel scrolling.
|
||||
|
||||
If scrolling still doesn't work for you, you can try to pass the `-S` option in addition.
|
||||
|
||||
## Configuration file
|
||||
|
||||
`bat` can also be customized with a configuration file. The location of the file is dependent
|
||||
on your operating system. To get the default path for your system, call
|
||||
```
|
||||
bat --config-file
|
||||
```
|
||||
|
||||
Alternatively, you can use the `BAT_CONFIG_PATH` environment variable to point `bat` to a
|
||||
non-default location of the configuration file:
|
||||
```bash
|
||||
export BAT_CONFIG_PATH="/path/to/bat.conf"
|
||||
```
|
||||
|
||||
### Format
|
||||
|
||||
The configuration file is a simple list of command line arguments. Use `bat --help` to see a full list of possible options and values. In addition, you can add comments by prepending a line with the `#` character.
|
||||
|
||||
Example configuration file:
|
||||
```bash
|
||||
# Set the theme to "TwoDark"
|
||||
--theme="TwoDark"
|
||||
|
||||
# Show line numbers, Git modifications and file header (but no grid)
|
||||
--style="numbers,changes,header"
|
||||
|
||||
# Use italic text on the terminal (not supported on all terminals)
|
||||
--italic-text=always
|
||||
|
||||
# Add mouse scrolling support in less (does not work with older
|
||||
# versions of "less")
|
||||
--pager="less -FR"
|
||||
|
||||
# Use C++ syntax (instead of C) for .h header files
|
||||
--map-syntax h:cpp
|
||||
|
||||
# Use "gitignore" highlighting for ".ignore" files
|
||||
--map-syntax .ignore:.gitignore
|
||||
```
|
||||
|
||||
## 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).
|
||||
|
||||
### Colors
|
||||
|
||||
Windows 10 natively supports colors 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 colors 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
|
||||
@@ -239,6 +436,11 @@ Make sure that your truecolor terminal sets the `COLORTERM` variable to either `
|
||||
`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
|
||||
|
||||
@@ -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
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
* linguist-vendored
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
diff --git syntaxes/Packages/Java/JavaDoc.sublime-syntax syntaxes/Packages/Java/JavaDoc.sublime-syntax
|
||||
index 422a6a9..40a741e 100644
|
||||
--- syntaxes/Packages/Java/JavaDoc.sublime-syntax
|
||||
+++ syntaxes/Packages/Java/JavaDoc.sublime-syntax
|
||||
@@ -13,7 +13,7 @@ variables:
|
||||
contexts:
|
||||
prototype:
|
||||
# https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#leadingasterisks
|
||||
- - match: ^\s*(\*)\s*(?!\s*@)
|
||||
+ - match: ^\s*(\*)(?!/)\s*(?!\s*@)
|
||||
captures:
|
||||
1: punctuation.definition.comment.javadoc
|
||||
|
||||
Vendored
+10
-2
@@ -13,12 +13,15 @@ In order to add new syntaxes to `bat`, follow these steps:
|
||||
Sublime Text and convert it to a `.sublime-syntax` file via *Tools* -> *Developer* ->
|
||||
*New Syntax from XXX.tmLanguage...*. Save the new file in the `assets/syntaxes` folder.
|
||||
|
||||
3. Run the `create.sh` script. It calls `bat cache --init` to parse all available
|
||||
3. Run the `create.sh` script. It calls `bat cache --build` to parse all available
|
||||
`.sublime-syntax` files and serialize them to a `syntaxes.bin` file (in this folder).
|
||||
|
||||
4. Re-compile `bat`. At compilation time, the `syntaxes.bin` file will be stored inside the
|
||||
`bat` binary.
|
||||
|
||||
5. If you send a pull request with your changes, please do *not* include the changed `syntaxes.bin`
|
||||
file. A new binary cache file will be created once before every new release of `bat`.
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
Make sure that the local cache does not interfere with the internally stored syntaxes and
|
||||
@@ -28,4 +31,9 @@ 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`, `hgrc`, and `desktop` file types.
|
||||
|
||||
### Non-submodule additions
|
||||
|
||||
* `Assembly (x86_64)` has been manually added from https://github.com/13xforever/x86-assembly-textmate-bundle due to `git clone` recursion problems
|
||||
+12
-1
@@ -2,4 +2,15 @@
|
||||
|
||||
ASSET_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
bat cache --init --blank --source="$ASSET_DIR" --target="$ASSET_DIR"
|
||||
# Always remove the local cache to avoid any confusion
|
||||
bat cache --clear
|
||||
|
||||
# TODO: Remove this (and the reverse part below) when
|
||||
# https://github.com/trishume/syntect/issues/222 has been fixed
|
||||
JAVADOC_FILE="${ASSET_DIR}/syntaxes/Packages/Java/JavaDoc.sublime-syntax"
|
||||
JAVADOC_PATCH="${ASSET_DIR}/JavaDoc.sublime-syntax.patch"
|
||||
patch "$JAVADOC_FILE" "$JAVADOC_PATCH"
|
||||
|
||||
bat cache --build --blank --source="$ASSET_DIR" --target="$ASSET_DIR"
|
||||
|
||||
patch -R "$JAVADOC_FILE" "$JAVADOC_PATCH"
|
||||
Vendored
BIN
Binary file not shown.
+1
Submodule assets/syntaxes/AsciiDoc added at d0089991e5.
+283
@@ -0,0 +1,283 @@
|
||||
%YAML 1.2
|
||||
---
|
||||
# http://www.sublimetext.com/docs/3/syntax.html
|
||||
name: AsciiDoc
|
||||
comment: |
|
||||
A very early hack. Mostly ripped from other syntaxes.
|
||||
Only the very basic stuff is working.
|
||||
file_extensions:
|
||||
- adoc
|
||||
- asciidoc
|
||||
- asc
|
||||
scope: text.html.asciidoc
|
||||
contexts:
|
||||
main:
|
||||
- include: heading_inline
|
||||
- include: heading-block
|
||||
- include: heading-blockattr
|
||||
- match: \$\$(?!\$)
|
||||
push:
|
||||
- meta_scope: comment.block.passthrough.macro.doubledollar.asciidoc
|
||||
- match: \$\$(?!\$)
|
||||
pop: true
|
||||
- match: \+\+\+(?!\+)
|
||||
push:
|
||||
- meta_scope: comment.block.passthrough.macro.tripeplus.asciidoc
|
||||
- match: \+\+\+(?!\+)
|
||||
pop: true
|
||||
- match: (//).*$\n?
|
||||
scope: comment.line.double-slash.asciidoc
|
||||
- match: |-
|
||||
(?x)^
|
||||
(?= ([/+-.*_=]{4,})\s*$
|
||||
| ([ \t]{1,})
|
||||
| [=]{1,6}\s*+
|
||||
| [ ]{,3}(?<marker>[-*_])([ ]{,2}\k<marker>){2,}[ \t]*+$
|
||||
)
|
||||
push:
|
||||
- meta_scope: meta.block-level.asciidoc
|
||||
- match: |-
|
||||
(?x)^
|
||||
(?! \1
|
||||
| ([ \t]{1,})
|
||||
| [=]{1,6}\s*+
|
||||
| [ ]{,3}(?<marker>[-*_])([ ]{,2}\k<marker>){2,}[ \t]*+$
|
||||
)
|
||||
pop: true
|
||||
- include: block_quote
|
||||
- include: block_raw
|
||||
- include: heading_inline
|
||||
- include: heading-block
|
||||
- include: separator
|
||||
- match: '^[ ]{0,3}([*+-])(?=\s)'
|
||||
captures:
|
||||
1: punctuation.definition.list_item.asciidoc
|
||||
push:
|
||||
- meta_scope: markup.list.unnumbered.asciidoc
|
||||
- match: ^(?=\S)
|
||||
captures:
|
||||
1: punctuation.definition.list_item.asciidoc
|
||||
pop: true
|
||||
- include: list-paragraph
|
||||
- match: '^[ ]{0,3}[0-9]+(\.)(?=\s)'
|
||||
captures:
|
||||
1: punctuation.definition.list_item.asciidoc
|
||||
push:
|
||||
- meta_scope: markup.list.numbered.asciidoc
|
||||
- match: ^(?=\S)
|
||||
captures:
|
||||
1: punctuation.definition.list_item.asciidoc
|
||||
pop: true
|
||||
- include: list-paragraph
|
||||
- match: '^([/+-.*_=]){4,}\s*$'
|
||||
push:
|
||||
- meta_scope: comment.block.asciidoc
|
||||
- match: '^\1{4,}\s*$'
|
||||
pop: true
|
||||
- match: '^([/+.]){4,}\s*$'
|
||||
comment: asciidoc formatting is disabled inside certain blocks.
|
||||
push:
|
||||
- meta_scope: meta.disable-asciidoc
|
||||
- match: '^[/+.]{4,}\s*$'
|
||||
pop: true
|
||||
- match: '^(?=\S)(?![=-]{3,}(?=$))(?!\.\S+)'
|
||||
push:
|
||||
- meta_scope: meta.paragraph.asciidoc
|
||||
- match: '^(?:\s*$|(?=[ ]{,3}>.))|(?=[ \t]*\n)(?<=^===|^====|=====|^---|^----|-----)[ \t]*\n'
|
||||
pop: true
|
||||
- include: inline
|
||||
- include: scope:text.html.basic
|
||||
- match: '^(={3,})(?=[ \t]*$)'
|
||||
scope: markup.heading.0.asciidoc
|
||||
captures:
|
||||
1: punctuation.definition.heading.asciidoc
|
||||
- match: '^(-{3,})(?=[ \t]*$)'
|
||||
scope: markup.heading.1.asciidoc
|
||||
captures:
|
||||
1: punctuation.definition.heading.asciidoc
|
||||
- match: '^(~{3,})(?=[ \t]*$)'
|
||||
scope: markup.heading.2.asciidoc
|
||||
captures:
|
||||
1: punctuation.definition.heading.asciidoc
|
||||
- match: '^(\^{3,})(?=[ \t]*$)'
|
||||
scope: markup.heading.3.asciidoc
|
||||
captures:
|
||||
1: punctuation.definition.heading.asciidoc
|
||||
- match: '^(\+{3,})(?=[ \t]*$)'
|
||||
scope: markup.heading.4.asciidoc
|
||||
captures:
|
||||
1: punctuation.definition.heading.asciidoc
|
||||
attribute-entry:
|
||||
- match: '^:[-_. A-Za-z0-9]+:\s*(.*)\s*$'
|
||||
scope: variable.other
|
||||
attribute-reference:
|
||||
- match: "{[-_. A-Za-z0-9]+}"
|
||||
scope: variable.other
|
||||
attribute-reference-predefined:
|
||||
- match: "{(?i:amp|asciidoc-dir|asciidoc-file|asciidoc-version|author|authored|authorinitials|backend-docbook|backend-xhtml11|backend-html4|docbook-article|xhtml11-article|html4-article|docbook-book|xhtml11-book|html4-book|docbook-manpage|xhtml11-manpage|html4-manpage|backend|backslash|basebackend|brvbar|date|docdate|doctime|docname|docfile|docdir|doctitle|doctype-article|doctype-book|doctype-manpage|doctype|email|empty|encoding|filetype|firstname|gt|id|indir|infile|lastname|level|listindex|localdate|localtime|lt|manname|manpurpose|mantitle|manvolnum|middlename|nbsp|outdir|outfile|reftext|revision|sectnum|showcomments|title|two_colons|two_semicolons|user-dir|verbose)}"
|
||||
scope: support.variable
|
||||
block_quote:
|
||||
- match: '^([/+-.*_=]){4,}\s*$'
|
||||
push:
|
||||
- meta_scope: comment.block.asciidoc
|
||||
- match: '^\1{4,}\s*$'
|
||||
pop: true
|
||||
block_raw:
|
||||
- match: '\G([ ]{4}|\t).*$\n?'
|
||||
scope: markup.raw.block.asciidoc
|
||||
bracket:
|
||||
- match: '<(?![a-z/?\$!])'
|
||||
comment: |
|
||||
asciidoc will convert this for us. We match it so that the
|
||||
HTML grammar will not mark it up as invalid.
|
||||
scope: meta.other.valid-bracket.asciidoc
|
||||
character-replacements:
|
||||
- match: \(C\)|\(R\)|\(TM\)|--(?!-)|\.\.\.(?!\.)|->|<-|=>|<=
|
||||
scope: constant.character.asciidoc
|
||||
escape:
|
||||
- match: '\\[-`*_#+.!(){}\[\]\\>:]'
|
||||
scope: constant.character.escape.asciidoc
|
||||
heading:
|
||||
- match: '(?m)^(\S+)$([=-~^+])+\s*$'
|
||||
scope: markup.heading.asciidoc
|
||||
captures:
|
||||
1: punctuation.definition.heading.asciidoc
|
||||
heading-block:
|
||||
- match: ^\.(\w.*)$
|
||||
scope: markup.heading.asciidoc
|
||||
captures:
|
||||
1: punctuation.definition.heading.asciidoc
|
||||
heading-blockattr:
|
||||
- match: '^\[\[?(\w.*)\]$'
|
||||
scope: markup.heading.asciidoc
|
||||
captures:
|
||||
1: punctuation.definition.heading.asciidoc
|
||||
heading_inline:
|
||||
- match: '\G(={1,6})(?!=)\s*(?=\S)'
|
||||
captures:
|
||||
1: punctuation.definition.heading.asciidoc
|
||||
push:
|
||||
- meta_scope: markup.heading.asciidoc
|
||||
- meta_content_scope: entity.name.section.asciidoc
|
||||
- match: \s*(=*)$\n?
|
||||
captures:
|
||||
1: punctuation.definition.heading.asciidoc
|
||||
pop: true
|
||||
- include: inline
|
||||
inline:
|
||||
- include: line-break
|
||||
- include: line-page-break
|
||||
- include: line-ruler
|
||||
- include: escape
|
||||
- include: passthrough-macro-trippleplus-inline
|
||||
- include: passthrough-macro-doubledollar-inline
|
||||
- include: character-replacements
|
||||
- include: bracket
|
||||
- include: raw
|
||||
- include: text-quote-single
|
||||
- include: text-quote-double
|
||||
- include: text-quote-other
|
||||
- include: text-bold-unconstrained
|
||||
- include: text-italic-unconstrained
|
||||
- include: text-monospace-unconstrained
|
||||
- include: text-unquoted-unconstrained
|
||||
- include: text-bold
|
||||
- include: text-italic
|
||||
- include: text-monospace
|
||||
- include: text-unquoted
|
||||
- include: attribute-entry
|
||||
- include: attribute-reference-predefined
|
||||
- include: attribute-reference
|
||||
line-break:
|
||||
- match: (?<=\S)\s+\+$
|
||||
scope: constant.character.escape.asciidoc
|
||||
line-page-break:
|
||||
- match: "^<{3,}$"
|
||||
scope: constant.character.escape.asciidoc
|
||||
line-ruler:
|
||||
- match: "^'{3,}$"
|
||||
scope: constant.character.escape.asciidoc
|
||||
list-paragraph:
|
||||
- match: \G\s+(?=\S)
|
||||
push:
|
||||
- meta_scope: meta.paragraph.list.asciidoc
|
||||
- match: ^\s*$
|
||||
pop: true
|
||||
- include: inline
|
||||
passthrough-macro-doubledollar-inline:
|
||||
- match: '(?:\[.*\])?\$\$(?!\$).+\$\$(?!\$)'
|
||||
scope: comment.block.passthrough.asciidoc
|
||||
passthrough-macro-trippleplus-inline:
|
||||
- match: '(?:\[.*\])?\+\+\+(?!\+).+\+\+\+(?!\+)'
|
||||
scope: comment.block.passthrough.asciidoc
|
||||
raw:
|
||||
- match: '(`+)(?:[^`]|(?!(?<!`)\1(?!`))`)*+(\1)'
|
||||
scope: markup.raw.inline.asciidoc
|
||||
captures:
|
||||
1: punctuation.definition.raw.asciidoc
|
||||
2: punctuation.definition.raw.asciidoc
|
||||
separator:
|
||||
- match: '\G[ ]{,3}([-*_])([ ]{,2}\1){2,}[ \t]*$\n?'
|
||||
scope: meta.separator.asciidoc
|
||||
text-bold:
|
||||
- match: (?<!\w)(\*)(?=\S)
|
||||
captures:
|
||||
1: punctuation.definition.bold.asciidoc
|
||||
push:
|
||||
- meta_scope: markup.bold.asciidoc
|
||||
- match: (?<=\S)(\1)(?!\w)
|
||||
captures:
|
||||
1: punctuation.definition.bold.asciidoc
|
||||
pop: true
|
||||
text-bold-unconstrained:
|
||||
- match: (\*\*)(?=\S)
|
||||
captures:
|
||||
1: punctuation.definition.bold.asciidoc
|
||||
push:
|
||||
- meta_scope: markup.bold.asciidoc
|
||||
- match: (?<=\S)(\1)
|
||||
captures:
|
||||
1: punctuation.definition.bold.asciidoc
|
||||
pop: true
|
||||
text-italic:
|
||||
- match: (?<!\w)('|_)(?=\S)
|
||||
captures:
|
||||
1: punctuation.definition.italic.asciidoc
|
||||
push:
|
||||
- meta_scope: markup.italic.asciidoc
|
||||
- match: (?<=\S)(\1)((?!\1)|(?=\1\1))(?!\w)
|
||||
captures:
|
||||
1: punctuation.definition.italic.asciidoc
|
||||
pop: true
|
||||
text-italic-unconstrained:
|
||||
- match: (__)(?=\S)
|
||||
captures:
|
||||
1: punctuation.definition.italic.asciidoc
|
||||
push:
|
||||
- meta_scope: markup.italic.asciidoc
|
||||
- match: (?<=\S)(\1)
|
||||
captures:
|
||||
1: punctuation.definition.italic.asciidoc
|
||||
pop: true
|
||||
text-monospace:
|
||||
- match: '(?<!\w)([\+`])[^\+]*(\1)(?!\w)'
|
||||
scope: string.interpolated.asciidoc
|
||||
text-monospace-unconstrained:
|
||||
- match: (\+\+).*(\1)
|
||||
scope: string.interpolated.asciidoc
|
||||
text-quote-double:
|
||||
- match: '(?<!\w)(?:\[.*\])?``(?!`).*''''(?!'')(?!\w)'
|
||||
scope: string.quoted.double.asciidoc
|
||||
text-quote-other:
|
||||
- match: '(?<!\w)(?:\[.*\])?([~^]).*(\1)(?!\w)'
|
||||
scope: string.quoted.single.asciidoc
|
||||
text-quote-single:
|
||||
- match: '(?<!\w)(?:\[.*\])?`(?!`).*''(?!'')(?!\w)'
|
||||
comment: "TODO: Sub- and Superscript are really unconstrained"
|
||||
scope: string.quoted.single.asciidoc
|
||||
text-unquoted:
|
||||
- match: (?<!\w)(#).*(\1)(?!\w)
|
||||
scope: string.unquoted.asciidoc
|
||||
text-unquoted-unconstrained:
|
||||
- match: (##).*(\1)
|
||||
scope: string.unquoted.asciidoc
|
||||
+1
Submodule assets/syntaxes/Assembly (ARM) added at 08f33d80de.
+172
@@ -0,0 +1,172 @@
|
||||
%YAML 1.2
|
||||
---
|
||||
# http://www.sublimetext.com/docs/3/syntax.html
|
||||
name: ARM Assembly
|
||||
file_extensions:
|
||||
- s
|
||||
- S
|
||||
scope: source.asm.arm
|
||||
contexts:
|
||||
main:
|
||||
- match: "@.*$"
|
||||
scope: comment.line
|
||||
- match: //.*$
|
||||
scope: comment.line
|
||||
- match: ;.*$
|
||||
scope: comment.line
|
||||
- match: ^\s*\#\s*if\s+0\b
|
||||
push:
|
||||
- meta_scope: comment.preprocessor
|
||||
- match: ^\s*\#\s*endif\b
|
||||
pop: true
|
||||
- match: /\*
|
||||
push:
|
||||
- meta_scope: comment.block
|
||||
- match: \*/
|
||||
pop: true
|
||||
- match: |-
|
||||
(?x)
|
||||
^\s*\#\s*(define)\s+ # define
|
||||
((?<id>[a-zA-Z_][a-zA-Z0-9_]*)) # macro name
|
||||
(?: # and optionally:
|
||||
(\() # an open parenthesis
|
||||
(
|
||||
\s* \g<id> \s* # first argument
|
||||
((,) \s* \g<id> \s*)* # additional arguments
|
||||
(?:\.\.\.)? # varargs ellipsis?
|
||||
)
|
||||
(\)) # a close parenthesis
|
||||
)?
|
||||
captures:
|
||||
1: keyword.control.import.define.c
|
||||
2: entity.name.function.preprocessor.c
|
||||
4: punctuation.definition.parameters.c
|
||||
5: variable.parameter.preprocessor.c
|
||||
7: punctuation.separator.parameters.c
|
||||
8: punctuation.definition.parameters.c
|
||||
push:
|
||||
- meta_scope: meta.preprocessor.macro.c
|
||||
- match: (?=(?://|/\*))|$
|
||||
pop: true
|
||||
- match: (?>\\\s*\n)
|
||||
scope: punctuation.separator.continuation.c
|
||||
- include: $top_level_main
|
||||
- match: ^\s*#\s*(error|warning)\b
|
||||
captures:
|
||||
1: keyword.control.import.error.c
|
||||
push:
|
||||
- meta_scope: meta.preprocessor.diagnostic.c
|
||||
- match: $
|
||||
captures:
|
||||
1: keyword.control.import.error.c
|
||||
pop: true
|
||||
- match: (?>\\\s*\n)
|
||||
scope: punctuation.separator.continuation.c
|
||||
- match: ^\s*#\s*(include|import)\b\s+
|
||||
captures:
|
||||
1: keyword.control.import.include.c
|
||||
push:
|
||||
- meta_scope: meta.preprocessor.c.include
|
||||
- match: (?=(?://|/\*))|$
|
||||
captures:
|
||||
1: keyword.control.import.include.c
|
||||
pop: true
|
||||
- match: (?>\\\s*\n)
|
||||
scope: punctuation.separator.continuation.c
|
||||
- match: '"'
|
||||
captures:
|
||||
0: punctuation.definition.string.begin.c
|
||||
push:
|
||||
- meta_scope: string.quoted.double.include.c
|
||||
- match: '"'
|
||||
captures:
|
||||
0: punctuation.definition.string.end.c
|
||||
pop: true
|
||||
- match: <
|
||||
captures:
|
||||
0: punctuation.definition.string.begin.c
|
||||
push:
|
||||
- meta_scope: string.quoted.other.lt-gt.include.c
|
||||
- match: ">"
|
||||
captures:
|
||||
0: punctuation.definition.string.end.c
|
||||
pop: true
|
||||
- match: '((?i)([xw][0-9]|[xw]1[0-9]||[xw]2[0-9]|[wx]30|wzr|xzr|wsp|fpsr|fpcr|[rcp]1[0-5]|[rcp][0-9]|a[1-4]|v[1-8]|sl|sb|fp|ip|sp|lr|(c|s)psr(_c)?|pc|[sd]3[0-1]|[sd][12][0-9]|[sd][0-9]|fpsid|fpscr|fpexc|q3[0-1]|q2[0-9]|q1[0-9]|q[0-9]|APSR_nzcv|sy)!?(?-i))?\b'
|
||||
scope: storage.other.register
|
||||
- match: \.(?i)(globl|global|macro|endm|purgem|if|elseif|else|endif|section|text|arm|align|balign|irp|rept|endr|req|unreq|error|short|func|endfunc|hidden|type|fpu|arch|code|altmacro|object_arch|word|int|string)(?-i)\b
|
||||
scope: keyword.control.directive
|
||||
- match: armv(2a?|3m?|4t?|5t?e?6(j|t2|zk?|-m)?|7v?e?(-(a|r|m))?|8-a(\+crc)?)
|
||||
scope: keyword.control.arch.arm
|
||||
- match: ^\s*#\s*(define|defined|elif|else|if|ifdef|ifndef|line|pragma|undef|endif)\b
|
||||
captures:
|
||||
1: keyword.control.import.c
|
||||
push:
|
||||
- meta_scope: meta.preprocessor.c
|
||||
- match: (?=(?://|/\*))|$
|
||||
captures:
|
||||
1: keyword.control.import.c
|
||||
pop: true
|
||||
- match: (?>\\\s*\n)
|
||||
scope: punctuation.separator.continuation.c
|
||||
- match: |-
|
||||
(?x)\b((?i)
|
||||
(
|
||||
(bf(c|i)|(u|s)bfx|(u|s)xta?(h|b)?) |
|
||||
(v(add|cvt|sub|mov|trn|cmp|div|qdmulh|mrs|mul|ld1|qadd|qshrun|st[1234]|addw|mull|mlal|rshrn|swp|qmovun)|qmovun)(\.([isup]?8|[isupf]?16|[isuf]?32|[isu]?64))* |
|
||||
(and|m(rs|sr)|eor|sub|rsb|add|adc|sbc|rsc|tst|teq|cmp|cmn|orr|mov|bic|mvn |
|
||||
(neg) |
|
||||
(lsr|lsl|ror|asr) # shift ops either pseudo ops or actual shifts
|
||||
)s? |
|
||||
(mul|mla|mull|smlabb) |
|
||||
(mov(w|t)) |
|
||||
rev(8|16)? |
|
||||
(pld|adr|adrl|vswp)
|
||||
)
|
||||
(ne|eq|cs|hs|cc|lo|mi|pl|vs|vc|hi|ls|lt|le|gt|ge|al)?(?-i))?\b
|
||||
scope: support.function.mnemonic.arithmetic
|
||||
- match: |-
|
||||
(?x)\b((?i)(
|
||||
swi|svc|wfi|
|
||||
dmb | clrex | dsb | isb |
|
||||
v(ldr|str|push|pop) |
|
||||
(push|pop) |
|
||||
(st|ld)(
|
||||
p |
|
||||
r(ex|s?(h|b)|d)? |
|
||||
m(
|
||||
(f|e)(d|a) |
|
||||
(d|i)(b|a)
|
||||
)?
|
||||
) |
|
||||
b(l|x|lx|lr|r)? |
|
||||
(i|e)?ret|
|
||||
b\.(eq|ne|hs|cs|lo|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le|al|nv)+ |
|
||||
(c|t)?bn?z|
|
||||
)+(ne|eq|cs|hs|cc|lo|mi|pl|vs|vc|hi|ls|lt|le|gt|ge|al)?(?-i))\b
|
||||
scope: support.function.mnemonic.memory
|
||||
- match: '\b((?i)(def(b|w|s)|equ|(include|get)(\s+([a-zA-Z_]+[0-9a-zA-Z_]*|[0-9]+[a-zA-Z_]+[0-9a-zA-Z_]*?)\.s)?)?(?-i))\b'
|
||||
scope: meta.preprocessor.c.include
|
||||
- match: \b((?i)(align)(?-i))?\b
|
||||
scope: storage.type.c.memaccess
|
||||
- match: \s+\".+\"
|
||||
scope: string
|
||||
- match: \b((?i)nop(ne|eq|cs|hs|cc|lo|mi|pl|vs|vc|hi|ls|lt|le|gt|ge|al)?(?-i))?\b
|
||||
scope: comment.nop
|
||||
- match: '\s\['
|
||||
push:
|
||||
- meta_scope: storage.type.c.memaccess
|
||||
- match: '\]'
|
||||
pop: true
|
||||
- match: (?>\\\s*\n)
|
||||
scope: punctuation.separator.continuation.c
|
||||
- include: $top_level_main
|
||||
- match: (\b|\s+)\=\b
|
||||
scope: keyword.control.evaluation
|
||||
- match: '(\b|\s+)(\#)?-?(0x|&)[0-9a-fA-F_]+\b'
|
||||
scope: constant.numeric.hex
|
||||
- match: '(\b|\s+)\#-?[0-9a-zA-Z_]+\b'
|
||||
scope: constant.numeric.literal
|
||||
- match: '(\b|\s+)[0-9]+\b'
|
||||
scope: constant.numeric.dec
|
||||
- match: '\b([a-zA-Z_]+[0-9a-zA-Z_]*|[0-9]+[a-zA-Z_]+[0-9a-zA-Z_]*)\b'
|
||||
scope: meta.function.source.arm.label
|
||||
+1367
File diff suppressed because it is too large.
Load diff
+1
Submodule assets/syntaxes/CSV added at 4786d037a7.
Vendored
+46
@@ -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
|
||||
+1
Submodule assets/syntaxes/Cabal added at 1c054d9b36.
Vendored
+47
@@ -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
|
||||
+1
Submodule assets/syntaxes/Crystal added at 2f96cec2ca.
+1036
File diff suppressed because it is too large.
Load diff
+1
Submodule assets/syntaxes/Dart added at d891fb36c9.
Vendored
+369
@@ -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
|
||||
+1
Submodule assets/syntaxes/FSharp added at da846f4227.
+234
@@ -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
|
||||
+662
@@ -0,0 +1,662 @@
|
||||
%YAML 1.2
|
||||
---
|
||||
# http://www.sublimetext.com/docs/3/syntax.html
|
||||
name: HTML (Twig)
|
||||
file_extensions:
|
||||
- twig
|
||||
- html.twig
|
||||
scope: text.html.twig
|
||||
contexts:
|
||||
main:
|
||||
- match: '(<)([a-zA-Z0-9:]++)(?=[^>]*></\2>)'
|
||||
captures:
|
||||
1: punctuation.definition.tag.html
|
||||
2: entity.name.tag.html
|
||||
push:
|
||||
- meta_scope: meta.tag.any.html
|
||||
- match: (>(<)/)(\2)(>)
|
||||
captures:
|
||||
1: punctuation.definition.tag.html
|
||||
2: meta.scope.between-tag-pair.html
|
||||
3: entity.name.tag.html
|
||||
4: punctuation.definition.tag.html
|
||||
pop: true
|
||||
- include: tag-stuff
|
||||
- match: (<\?)(xml)
|
||||
captures:
|
||||
1: punctuation.definition.tag.html
|
||||
2: entity.name.tag.xml.html
|
||||
push:
|
||||
- meta_scope: meta.tag.preprocessor.xml.html
|
||||
- match: (\?>)
|
||||
captures:
|
||||
1: punctuation.definition.tag.html
|
||||
2: entity.name.tag.xml.html
|
||||
pop: true
|
||||
- include: tag-generic-attribute
|
||||
- include: string-double-quoted
|
||||
- include: string-single-quoted
|
||||
- match: <!--
|
||||
captures:
|
||||
0: punctuation.definition.comment.html
|
||||
push:
|
||||
- meta_scope: comment.block.html
|
||||
- match: '--\s*>'
|
||||
captures:
|
||||
0: punctuation.definition.comment.html
|
||||
pop: true
|
||||
- match: "--"
|
||||
scope: invalid.illegal.bad-comments-or-CDATA.html
|
||||
- include: embedded-code
|
||||
- match: <!
|
||||
captures:
|
||||
0: punctuation.definition.tag.html
|
||||
push:
|
||||
- meta_scope: meta.tag.sgml.html
|
||||
- match: ">"
|
||||
captures:
|
||||
0: punctuation.definition.tag.html
|
||||
pop: true
|
||||
- match: (?i:DOCTYPE)
|
||||
captures:
|
||||
1: entity.name.tag.doctype.html
|
||||
push:
|
||||
- meta_scope: meta.tag.sgml.doctype.html
|
||||
- match: (?=>)
|
||||
captures:
|
||||
1: entity.name.tag.doctype.html
|
||||
pop: true
|
||||
- match: '"[^">]*"'
|
||||
scope: string.quoted.double.doctype.identifiers-and-DTDs.html
|
||||
- match: '\[CDATA\['
|
||||
push:
|
||||
- meta_scope: constant.other.inline-data.html
|
||||
- match: "]](?=>)"
|
||||
pop: true
|
||||
- match: (\s*)(?!--|>)\S(\s*)
|
||||
scope: invalid.illegal.bad-comments-or-CDATA.html
|
||||
- include: embedded-code
|
||||
- match: '(?:^\s+)?(<)((?i:style))\b(?![^>]*/>)'
|
||||
captures:
|
||||
1: punctuation.definition.tag.html
|
||||
2: entity.name.tag.style.html
|
||||
3: punctuation.definition.tag.html
|
||||
push:
|
||||
- meta_scope: source.css.embedded.html
|
||||
- match: (</)((?i:style))(>)(?:\s*\n)?
|
||||
captures:
|
||||
1: punctuation.definition.tag.html
|
||||
2: entity.name.tag.style.html
|
||||
3: punctuation.definition.tag.html
|
||||
pop: true
|
||||
- include: tag-stuff
|
||||
- match: (>)
|
||||
captures:
|
||||
1: punctuation.definition.tag.html
|
||||
push:
|
||||
- match: (?=</(?i:style))
|
||||
pop: true
|
||||
- include: embedded-code
|
||||
- include: scope:source.css
|
||||
- match: '(?:^\s+)?(<)((?i:script))\b(?![^>]*/>)'
|
||||
captures:
|
||||
1: punctuation.definition.tag.html
|
||||
2: entity.name.tag.script.html
|
||||
push:
|
||||
- meta_scope: source.js.embedded.html
|
||||
- match: (?<=</(script|SCRIPT))(>)(?:\s*\n)?
|
||||
captures:
|
||||
2: punctuation.definition.tag.html
|
||||
pop: true
|
||||
- include: tag-stuff
|
||||
- match: (?<!</(?:script|SCRIPT))(>)
|
||||
captures:
|
||||
1: punctuation.definition.tag.html
|
||||
2: entity.name.tag.script.html
|
||||
push:
|
||||
- match: (</)((?i:script))
|
||||
captures:
|
||||
1: punctuation.definition.tag.html
|
||||
2: entity.name.tag.script.html
|
||||
pop: true
|
||||
- match: (//).*?((?=</script)|$\n?)
|
||||
scope: comment.line.double-slash.js
|
||||
captures:
|
||||
1: punctuation.definition.comment.js
|
||||
- match: /\*
|
||||
captures:
|
||||
0: punctuation.definition.comment.js
|
||||
push:
|
||||
- meta_scope: comment.block.js
|
||||
- match: \*/|(?=</script)
|
||||
captures:
|
||||
0: punctuation.definition.comment.js
|
||||
pop: true
|
||||
- include: php
|
||||
- include: twig-print-tag
|
||||
- include: twig-statement-tag
|
||||
- include: twig-comment-tag
|
||||
- include: scope:source.js
|
||||
- match: (</?)((?i:body|head|html)\b)
|
||||
captures:
|
||||
1: punctuation.definition.tag.html
|
||||
2: entity.name.tag.structure.any.html
|
||||
push:
|
||||
- meta_scope: meta.tag.structure.any.html
|
||||
- match: (>)
|
||||
captures:
|
||||
1: punctuation.definition.tag.html
|
||||
2: entity.name.tag.structure.any.html
|
||||
pop: true
|
||||
- include: tag-stuff
|
||||
- match: (</?)((?i:address|blockquote|dd|div|dl|dt|fieldset|form|frame|frameset|h1|h2|h3|h4|h5|h6|iframe|noframes|object|ol|p|ul|applet|center|dir|hr|menu|pre)\b)
|
||||
captures:
|
||||
1: punctuation.definition.tag.begin.html
|
||||
2: entity.name.tag.block.any.html
|
||||
push:
|
||||
- meta_scope: meta.tag.block.any.html
|
||||
- match: (>)
|
||||
captures:
|
||||
1: punctuation.definition.tag.end.html
|
||||
pop: true
|
||||
- include: tag-stuff
|
||||
- match: (</?)((?i:a|abbr|acronym|area|b|base|basefont|bdo|big|br|button|caption|cite|code|col|colgroup|del|dfn|em|font|head|html|i|img|input|ins|isindex|kbd|label|legend|li|link|map|meta|noscript|optgroup|option|param|q|s|samp|script|select|small|span|strike|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|title|tr|tt|u|var)\b)
|
||||
captures:
|
||||
1: punctuation.definition.tag.begin.html
|
||||
2: entity.name.tag.inline.any.html
|
||||
push:
|
||||
- meta_scope: meta.tag.inline.any.html
|
||||
- match: "((?: ?/)?>)"
|
||||
captures:
|
||||
1: punctuation.definition.tag.end.html
|
||||
pop: true
|
||||
- include: tag-stuff
|
||||
- match: "(</?)([a-zA-Z0-9:]+)"
|
||||
captures:
|
||||
1: punctuation.definition.tag.begin.html
|
||||
2: entity.name.tag.other.html
|
||||
push:
|
||||
- meta_scope: meta.tag.other.html
|
||||
- match: (>)
|
||||
captures:
|
||||
1: punctuation.definition.tag.end.html
|
||||
pop: true
|
||||
- include: tag-stuff
|
||||
- include: entities
|
||||
- match: <>
|
||||
scope: invalid.illegal.incomplete.html
|
||||
- match: <
|
||||
scope: invalid.illegal.bad-angle-bracket.html
|
||||
- include: twig-print-tag
|
||||
- include: twig-statement-tag
|
||||
- include: twig-comment-tag
|
||||
embedded-code:
|
||||
- include: ruby
|
||||
- include: php
|
||||
- include: twig-print-tag
|
||||
- include: twig-statement-tag
|
||||
- include: twig-comment-tag
|
||||
- include: python
|
||||
entities:
|
||||
- match: "(&)([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+)(;)"
|
||||
scope: constant.character.entity.html
|
||||
captures:
|
||||
1: punctuation.definition.entity.html
|
||||
3: punctuation.definition.entity.html
|
||||
- match: "&"
|
||||
scope: invalid.illegal.bad-ampersand.html
|
||||
php:
|
||||
- match: (?=(^\s*)?<\?)
|
||||
push:
|
||||
- match: (?!(^\s*)?<\?)
|
||||
pop: true
|
||||
- include: scope:text.html.php
|
||||
python:
|
||||
- match: (?:^\s*)<\?python(?!.*\?>)
|
||||
push:
|
||||
- meta_scope: source.python.embedded.html
|
||||
- match: \?>(?:\s*$\n)?
|
||||
pop: true
|
||||
- include: scope:source.python
|
||||
ruby:
|
||||
- match: "<%+#"
|
||||
captures:
|
||||
0: punctuation.definition.comment.erb
|
||||
push:
|
||||
- meta_scope: comment.block.erb
|
||||
- match: "%>"
|
||||
captures:
|
||||
0: punctuation.definition.comment.erb
|
||||
pop: true
|
||||
- match: <%+(?!>)=?
|
||||
captures:
|
||||
0: punctuation.section.embedded.ruby
|
||||
push:
|
||||
- meta_scope: source.ruby.embedded.html
|
||||
- match: "-?%>"
|
||||
captures:
|
||||
0: punctuation.section.embedded.ruby
|
||||
pop: true
|
||||
- match: (#).*?(?=-?%>)
|
||||
scope: comment.line.number-sign.ruby
|
||||
captures:
|
||||
1: punctuation.definition.comment.ruby
|
||||
- include: scope:source.ruby
|
||||
- match: <\?r(?!>)=?
|
||||
captures:
|
||||
0: punctuation.section.embedded.ruby.nitro
|
||||
push:
|
||||
- meta_scope: source.ruby.nitro.embedded.html
|
||||
- match: '-?\?>'
|
||||
captures:
|
||||
0: punctuation.section.embedded.ruby.nitro
|
||||
pop: true
|
||||
- match: (#).*?(?=-?\?>)
|
||||
scope: comment.line.number-sign.ruby.nitro
|
||||
captures:
|
||||
1: punctuation.definition.comment.ruby.nitro
|
||||
- include: scope:source.ruby
|
||||
string-double-quoted:
|
||||
- match: '"'
|
||||
captures:
|
||||
0: punctuation.definition.string.begin.html
|
||||
push:
|
||||
- meta_scope: string.quoted.double.html
|
||||
- match: '"'
|
||||
captures:
|
||||
0: punctuation.definition.string.end.html
|
||||
pop: true
|
||||
- include: embedded-code
|
||||
- include: entities
|
||||
string-single-quoted:
|
||||
- match: "'"
|
||||
captures:
|
||||
0: punctuation.definition.string.begin.html
|
||||
push:
|
||||
- meta_scope: string.quoted.single.html
|
||||
- match: "'"
|
||||
captures:
|
||||
0: punctuation.definition.string.end.html
|
||||
pop: true
|
||||
- include: embedded-code
|
||||
- include: entities
|
||||
tag-generic-attribute:
|
||||
- match: '\b([a-zA-Z\-:]+)'
|
||||
scope: entity.other.attribute-name.html
|
||||
tag-id-attribute:
|
||||
- match: \b(id)\b\s*(=)
|
||||
captures:
|
||||
1: entity.other.attribute-name.id.html
|
||||
2: punctuation.separator.key-value.html
|
||||
push:
|
||||
- meta_scope: meta.attribute-with-value.id.html
|
||||
- match: (?<='|")
|
||||
captures:
|
||||
1: entity.other.attribute-name.id.html
|
||||
2: punctuation.separator.key-value.html
|
||||
pop: true
|
||||
- match: '"'
|
||||
captures:
|
||||
0: punctuation.definition.string.begin.html
|
||||
push:
|
||||
- meta_scope: string.quoted.double.html
|
||||
- meta_content_scope: meta.toc-list.id.html
|
||||
- match: '"'
|
||||
captures:
|
||||
0: punctuation.definition.string.end.html
|
||||
pop: true
|
||||
- include: embedded-code
|
||||
- include: entities
|
||||
- match: "'"
|
||||
captures:
|
||||
0: punctuation.definition.string.begin.html
|
||||
push:
|
||||
- meta_scope: string.quoted.single.html
|
||||
- meta_content_scope: meta.toc-list.id.html
|
||||
- match: "'"
|
||||
captures:
|
||||
0: punctuation.definition.string.end.html
|
||||
pop: true
|
||||
- include: embedded-code
|
||||
- include: entities
|
||||
tag-stuff:
|
||||
- include: tag-id-attribute
|
||||
- include: tag-generic-attribute
|
||||
- include: string-double-quoted
|
||||
- include: string-single-quoted
|
||||
- include: embedded-code
|
||||
twig-arrays:
|
||||
- match: '(?<=[\s\(\{\[:,])\['
|
||||
captures:
|
||||
0: punctuation.section.array.begin.twig
|
||||
push:
|
||||
- meta_scope: meta.array.twig
|
||||
- match: '\]'
|
||||
captures:
|
||||
0: punctuation.section.array.end.twig
|
||||
pop: true
|
||||
- include: twig-arrays
|
||||
- include: twig-hashes
|
||||
- include: twig-constants
|
||||
- include: twig-strings
|
||||
- include: twig-functions-warg
|
||||
- include: twig-functions
|
||||
- include: twig-macros
|
||||
- include: twig-objects
|
||||
- include: twig-properties
|
||||
- include: twig-filters-warg
|
||||
- include: twig-filters
|
||||
- include: twig-filters-warg-ud
|
||||
- include: twig-filters-ud
|
||||
- match: ","
|
||||
scope: punctuation.separator.object.twig
|
||||
twig-comment-tag:
|
||||
- match: '\{#-?'
|
||||
captures:
|
||||
0: punctuation.definition.comment.begin.twig
|
||||
push:
|
||||
- meta_scope: comment.block.twig
|
||||
- match: '-?#\}'
|
||||
captures:
|
||||
0: punctuation.definition.comment.end.twig
|
||||
pop: true
|
||||
twig-constants:
|
||||
- match: '(?i)(?<=[\s\[\(\{:,])(?:true|false|null|none)(?=[\s\)\]\}\,])'
|
||||
scope: constant.language.twig
|
||||
- match: '(?<=[\s\[\(\{:,]|\.\.|\*\*)[0-9]+(?:\.[0-9]+)?(?=[\s\)\]\}\,]|\.\.|\*\*)'
|
||||
scope: constant.numeric.twig
|
||||
twig-filters:
|
||||
- match: '(?<=(?:[a-zA-Z0-9_\x{7f}-\x{ff}\]\)\''\"]\|)|\{%\sfilter\s)(abs|capitalize|e(?:scape)?|first|join|(?:json|url)_encode|keys|last|length|lower|nl2br|number_format|raw|reverse|round|sort|striptags|title|trim|upper)(?=[\s\|\]\}\):,]|\.\.|\*\*)'
|
||||
captures:
|
||||
1: support.function.twig
|
||||
twig-filters-ud:
|
||||
- match: '(?<=(?:[a-zA-Z0-9_\x{7f}-\x{ff}\]\)\''\"]\|)|\{%\sfilter\s)([a-zA-Z_\x{7f}-\x{ff}][a-zA-Z0-9_\x{7f}-\x{ff}]*)'
|
||||
captures:
|
||||
1: meta.function-call.other.twig
|
||||
twig-filters-warg:
|
||||
- match: '(?<=(?:[a-zA-Z0-9_\x{7f}-\x{ff}\]\)\''\"]\|)|\{%\sfilter\s)(batch|convert_encoding|date|date_modify|default|e(?:scape)?|format|join|merge|number_format|replace|round|slice|split|trim)(\()'
|
||||
captures:
|
||||
1: support.function.twig
|
||||
2: punctuation.definition.parameters.begin.twig
|
||||
push:
|
||||
- meta_content_scope: meta.function.arguments.twig
|
||||
- match: \)
|
||||
captures:
|
||||
0: punctuation.definition.parameters.end.twig
|
||||
pop: true
|
||||
- include: twig-constants
|
||||
- include: twig-functions-warg
|
||||
- include: twig-functions
|
||||
- include: twig-macros
|
||||
- include: twig-objects
|
||||
- include: twig-properties
|
||||
- include: twig-filters-warg
|
||||
- include: twig-filters
|
||||
- include: twig-filters-warg-ud
|
||||
- include: twig-filters-ud
|
||||
- include: twig-strings
|
||||
- include: twig-arrays
|
||||
- include: twig-hashes
|
||||
twig-filters-warg-ud:
|
||||
- match: '(?<=(?:[a-zA-Z0-9_\x{7f}-\x{ff}\]\)\''\"]\|)|\{%\sfilter\s)([a-zA-Z_\x{7f}-\x{ff}][a-zA-Z0-9_\x{7f}-\x{ff}]*)(\()'
|
||||
captures:
|
||||
1: meta.function-call.other.twig
|
||||
2: punctuation.definition.parameters.begin.twig
|
||||
push:
|
||||
- meta_content_scope: meta.function.arguments.twig
|
||||
- match: \)
|
||||
captures:
|
||||
0: punctuation.definition.parameters.end.twig
|
||||
pop: true
|
||||
- include: twig-constants
|
||||
- include: twig-functions-warg
|
||||
- include: twig-functions
|
||||
- include: twig-macros
|
||||
- include: twig-objects
|
||||
- include: twig-properties
|
||||
- include: twig-filters-warg
|
||||
- include: twig-filters
|
||||
- include: twig-filters-warg-ud
|
||||
- include: twig-filters-ud
|
||||
- include: twig-strings
|
||||
- include: twig-arrays
|
||||
- include: twig-hashes
|
||||
twig-functions:
|
||||
- match: (?<=is\s)(defined|empty|even|iterable|odd)
|
||||
captures:
|
||||
1: support.function.twig
|
||||
twig-functions-warg:
|
||||
- match: '(?<=[\s\(\[\{:,])(attribute|block|constant|cycle|date|divisible by|dump|include|max|min|parent|random|range|same as|source|template_from_string)(\()'
|
||||
captures:
|
||||
1: support.function.twig
|
||||
2: punctuation.definition.parameters.begin.twig
|
||||
push:
|
||||
- meta_content_scope: meta.function.arguments.twig
|
||||
- match: \)
|
||||
captures:
|
||||
0: punctuation.definition.parameters.end.twig
|
||||
pop: true
|
||||
- include: twig-constants
|
||||
- include: twig-functions-warg
|
||||
- include: twig-functions
|
||||
- include: twig-macros
|
||||
- include: twig-objects
|
||||
- include: twig-properties
|
||||
- include: twig-filters-warg
|
||||
- include: twig-filters
|
||||
- include: twig-filters-warg-ud
|
||||
- include: twig-filters-ud
|
||||
- include: twig-strings
|
||||
- include: twig-arrays
|
||||
twig-hashes:
|
||||
- match: '(?<=[\s\(\{\[:,])\{'
|
||||
captures:
|
||||
0: punctuation.section.hash.begin.twig
|
||||
push:
|
||||
- meta_scope: meta.hash.twig
|
||||
- match: '\}'
|
||||
captures:
|
||||
0: punctuation.section.hash.end.twig
|
||||
pop: true
|
||||
- include: twig-hashes
|
||||
- include: twig-arrays
|
||||
- include: twig-constants
|
||||
- include: twig-strings
|
||||
- include: twig-functions-warg
|
||||
- include: twig-functions
|
||||
- include: twig-macros
|
||||
- include: twig-objects
|
||||
- include: twig-properties
|
||||
- include: twig-filters-warg
|
||||
- include: twig-filters
|
||||
- include: twig-filters-warg-ud
|
||||
- include: twig-filters-ud
|
||||
- match: ":"
|
||||
scope: punctuation.separator.key-value.twig
|
||||
- match: ","
|
||||
scope: punctuation.separator.object.twig
|
||||
twig-keywords:
|
||||
- match: (?<=\s)((?:end)?(?:autoescape|block|embed|filter|for|if|macro|raw|sandbox|set|spaceless|trans|verbatim)|as|do|else|elseif|extends|flush|from|ignore missing|import|include|only|use|with)(?=\s)
|
||||
scope: keyword.control.twig
|
||||
twig-macros:
|
||||
- match: |-
|
||||
(?x)
|
||||
(?<=[\s\(\[\{:,])
|
||||
([a-zA-Z_\x{7f}-\x{ff}][a-zA-Z0-9_\x{7f}-\x{ff}]*)
|
||||
(?:
|
||||
(\.)([a-zA-Z_\x{7f}-\x{ff}][a-zA-Z0-9_\x{7f}-\x{ff}]*)
|
||||
)?
|
||||
(\()
|
||||
captures:
|
||||
1: meta.function-call.twig
|
||||
2: punctuation.separator.property.twig
|
||||
3: variable.other.property.twig
|
||||
4: punctuation.definition.parameters.begin.twig
|
||||
push:
|
||||
- meta_content_scope: meta.function.arguments.twig
|
||||
- match: \)
|
||||
captures:
|
||||
0: punctuation.definition.parameters.end.twig
|
||||
pop: true
|
||||
- include: twig-constants
|
||||
- include: twig-operators
|
||||
- include: twig-functions-warg
|
||||
- include: twig-functions
|
||||
- include: twig-macros
|
||||
- include: twig-objects
|
||||
- include: twig-properties
|
||||
- include: twig-filters-warg
|
||||
- include: twig-filters
|
||||
- include: twig-filters-warg-ud
|
||||
- include: twig-filters-ud
|
||||
- include: twig-strings
|
||||
- include: twig-arrays
|
||||
- include: twig-hashes
|
||||
twig-objects:
|
||||
- match: '(?<=[\s\{\[\(:,])([a-zA-Z_\x{7f}-\x{ff}][a-zA-Z0-9_\x{7f}-\x{ff}]*)(?=[\s\}\[\]\(\)\.\|,:])'
|
||||
captures:
|
||||
1: variable.other.twig
|
||||
twig-operators:
|
||||
- match: (?<=\s)(\+|-|//?|%|\*\*?)(?=\s)
|
||||
captures:
|
||||
1: keyword.operator.arithmetic.twig
|
||||
- match: (?<=\s)(=|~)(?=\s)
|
||||
captures:
|
||||
1: keyword.operator.assignment.twig
|
||||
- match: (?<=\s)(b-(?:and|or|xor))(?=\s)
|
||||
captures:
|
||||
1: keyword.operator.bitwise.twig
|
||||
- match: '(?<=\s)((?:!|=)=|<=?|>=?|(?:not )?in|is(?: not)?|(?:ends|starts) with|matches)(?=\s)'
|
||||
captures:
|
||||
1: keyword.operator.comparison.twig
|
||||
- match: (?<=\s)(\?|:|and|not|or)(?=\s)
|
||||
captures:
|
||||
1: keyword.operator.logical.twig
|
||||
- match: '(?<=[a-zA-Z0-9_\x{7f}-\x{ff}\]\)''"])\.\.(?=[a-zA-Z0-9_\x{7f}-\x{ff}''"])'
|
||||
captures:
|
||||
0: keyword.operator.other.twig
|
||||
- match: '(?<=[a-zA-Z0-9_\x{7f}-\x{ff}\]\}\)''"])\|(?=[a-zA-Z_\x{7f}-\x{ff}])'
|
||||
captures:
|
||||
0: keyword.operator.other.twig
|
||||
twig-print-tag:
|
||||
- match: '\{\{-?'
|
||||
captures:
|
||||
0: punctuation.section.tag.twig
|
||||
push:
|
||||
- meta_scope: meta.tag.template.value.twig
|
||||
- match: '-?\}\}'
|
||||
captures:
|
||||
0: punctuation.section.tag.twig
|
||||
pop: true
|
||||
- include: twig-constants
|
||||
- include: twig-operators
|
||||
- include: twig-functions-warg
|
||||
- include: twig-functions
|
||||
- include: twig-macros
|
||||
- include: twig-objects
|
||||
- include: twig-properties
|
||||
- include: twig-filters-warg
|
||||
- include: twig-filters
|
||||
- include: twig-filters-warg-ud
|
||||
- include: twig-filters-ud
|
||||
- include: twig-strings
|
||||
- include: twig-arrays
|
||||
- include: twig-hashes
|
||||
twig-properties:
|
||||
- match: |-
|
||||
(?x)
|
||||
(?<=[a-zA-Z0-9_\x{7f}-\x{ff}])
|
||||
(\.)([a-zA-Z_\x{7f}-\x{ff}][a-zA-Z0-9_\x{7f}-\x{ff}]*)
|
||||
(?=[\.\s\|\[\)\]\}:,])
|
||||
captures:
|
||||
1: punctuation.separator.property.twig
|
||||
2: variable.other.property.twig
|
||||
- match: |-
|
||||
(?x)
|
||||
(?<=[a-zA-Z0-9_\x{7f}-\x{ff}])
|
||||
(\.)([a-zA-Z_\x{7f}-\x{ff}][a-zA-Z0-9_\x{7f}-\x{ff}]*)
|
||||
(\()
|
||||
captures:
|
||||
1: punctuation.separator.property.twig
|
||||
2: variable.other.property.twig
|
||||
3: punctuation.definition.parameters.begin.twig
|
||||
push:
|
||||
- meta_content_scope: meta.function.arguments.twig
|
||||
- match: \)
|
||||
captures:
|
||||
0: punctuation.definition.parameters.end.twig
|
||||
pop: true
|
||||
- include: twig-constants
|
||||
- include: twig-functions-warg
|
||||
- include: twig-functions
|
||||
- include: twig-macros
|
||||
- include: twig-objects
|
||||
- include: twig-properties
|
||||
- include: twig-filters-warg
|
||||
- include: twig-filters
|
||||
- include: twig-filters-warg-ud
|
||||
- include: twig-filters-ud
|
||||
- include: twig-strings
|
||||
- include: twig-arrays
|
||||
- match: |-
|
||||
(?x)
|
||||
(?<=[a-zA-Z0-9_\x{7f}-\x{ff}\]])
|
||||
(?:
|
||||
(\[)('[a-zA-Z_\x{7f}-\x{ff}][a-zA-Z0-9_\x{7f}-\x{ff}]*')(\])
|
||||
|(\[)("[a-zA-Z_\x{7f}-\x{ff}][a-zA-Z0-9_\x{7f}-\x{ff}]*")(\])
|
||||
|(\[)([a-zA-Z_\x{7f}-\x{ff}][a-zA-Z0-9_\x{7f}-\x{ff}]*)(\])
|
||||
)
|
||||
captures:
|
||||
1: punctuation.section.array.begin.twig
|
||||
2: variable.other.property.twig
|
||||
3: punctuation.section.array.end.twig
|
||||
4: punctuation.section.array.begin.twig
|
||||
5: variable.other.property.twig
|
||||
6: punctuation.section.array.end.twig
|
||||
7: punctuation.section.array.begin.twig
|
||||
8: variable.other.property.twig
|
||||
9: punctuation.section.array.end.twig
|
||||
twig-statement-tag:
|
||||
- match: '\{%-?'
|
||||
captures:
|
||||
0: punctuation.section.tag.twig
|
||||
push:
|
||||
- meta_scope: meta.tag.template.block.twig
|
||||
- match: '-?%\}'
|
||||
captures:
|
||||
0: punctuation.section.tag.twig
|
||||
pop: true
|
||||
- include: twig-constants
|
||||
- include: twig-keywords
|
||||
- include: twig-operators
|
||||
- include: twig-functions-warg
|
||||
- include: twig-functions
|
||||
- include: twig-macros
|
||||
- include: twig-filters-warg
|
||||
- include: twig-filters
|
||||
- include: twig-filters-warg-ud
|
||||
- include: twig-filters-ud
|
||||
- include: twig-objects
|
||||
- include: twig-properties
|
||||
- include: twig-strings
|
||||
- include: twig-arrays
|
||||
- include: twig-hashes
|
||||
twig-strings:
|
||||
- match: (?:(?<!\\)|(?<=\\\\))'
|
||||
captures:
|
||||
0: punctuation.definition.string.begin.twig
|
||||
push:
|
||||
- meta_scope: string.quoted.single.twig
|
||||
- match: (?:(?<!\\)|(?<=\\\\))'
|
||||
captures:
|
||||
0: punctuation.definition.string.end.twig
|
||||
pop: true
|
||||
- match: (?:(?<!\\)|(?<=\\\\))"
|
||||
captures:
|
||||
0: punctuation.definition.string.begin.twig
|
||||
push:
|
||||
- meta_scope: string.quoted.double.twig
|
||||
- match: (?:(?<!\\)|(?<=\\\\))"
|
||||
captures:
|
||||
0: punctuation.definition.string.end.twig
|
||||
pop: true
|
||||
Vendored
+3
@@ -12,9 +12,12 @@ file_extensions:
|
||||
- lng
|
||||
- cfg
|
||||
- CFG
|
||||
- desktop
|
||||
- url
|
||||
- URL
|
||||
- .editorconfig
|
||||
- .hgrc
|
||||
- hgrc
|
||||
scope: source.ini
|
||||
contexts:
|
||||
main:
|
||||
|
||||
+1
Submodule assets/syntaxes/JavaScript (Babel) added at a9a908fe1d.
+1288
File diff suppressed because it is too large.
Load diff
+1
Submodule assets/syntaxes/Jsonnet added at 80775c616e.
Vendored
+1
-1
Submodule assets/syntaxes/Packages updated: 289782ff2e...c1a7427015.
+1
Submodule assets/syntaxes/PowerShell added at 12b7d7257e.
+466
@@ -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
|
||||
+1
Submodule assets/syntaxes/Protobuf added at 5115c1c59a.
+1
Submodule assets/syntaxes/PureScript added at 42a61e39ad.
+1
Submodule assets/syntaxes/Robot added at 8e5a349a3e.
Vendored
+54
@@ -0,0 +1,54 @@
|
||||
%YAML 1.2
|
||||
---
|
||||
# http://www.sublimetext.com/docs/3/syntax.html
|
||||
name: Robot Framework syntax highlighting.
|
||||
file_extensions:
|
||||
- robot
|
||||
scope: source.robot
|
||||
contexts:
|
||||
main:
|
||||
- match: '\$\{(\d+|\d+\.\d*|0[bB][01]+|0[oO][0-7]+|0[xX][0-9a-fA-F]+)\}'
|
||||
comment: "Robot Framework numbers, like ${1} or ${12.3}"
|
||||
scope: constant.numeric.robot
|
||||
- match: '(?i)(%\{[\w|\s]+\})'
|
||||
comment: "Robot Framework environment variable, like %{USER}"
|
||||
scope: variable.parameter.robot
|
||||
- match: '((?<!\\)|(?<=\\\\))[$&]{'
|
||||
comment: Robot Framework scalar and dictionary variables
|
||||
push:
|
||||
- meta_scope: entity.name.class
|
||||
- match: '\}'
|
||||
pop: true
|
||||
- match: '((?<!\\)(@{)|(?<=\\\\)(@{))'
|
||||
comment: Robot Framework list variables
|
||||
push:
|
||||
- meta_scope: entity.name.class
|
||||
- match: '(}\[.+])|(})'
|
||||
pop: true
|
||||
- match: '(?i)^(\|\s*)?(\*{1,3} ?)(settings?|variables?|keywords?|test cases?)( ?\*{1,3})?(\s*\|)?'
|
||||
comment: Robot Framework data tables
|
||||
scope: string.robot.header
|
||||
- match: '(?i)(^\|\s*)?\[?Documentation\]?\s+'
|
||||
comment: Test case, keyword and settings table documentation
|
||||
push:
|
||||
- meta_scope: comment
|
||||
- match: ^(?!\s*+\.\.\.)
|
||||
pop: true
|
||||
- match: '(^| {2,}|\t|\\| {1,})(?<!\\\\)#'
|
||||
comment: Comment character
|
||||
push:
|
||||
- meta_scope: comment
|
||||
- match: $
|
||||
pop: true
|
||||
- match: '(?i)\s+\[(Tags|Setup|Teardown|Template|Timeout|Arguments|Return)\]'
|
||||
comment: Tests case and keyword settings
|
||||
scope: storage.type
|
||||
- match: (?i)^(\|\s*)?(Library|Resource|Test Timeout|Test Template|Test Teardown|Test Setup|Default Tags|Force Tags|Metadata|Variables|Suite Setup|Suite Teardown)(?:( )|( \| ))
|
||||
comment: Settings table settings, like Library
|
||||
scope: constant.language
|
||||
- match: '^(\|\s+)?(?!^\.{3})(?![\|$&])\S+'
|
||||
comment: Keywords and test cases
|
||||
push:
|
||||
- meta_scope: keyword.control.robot
|
||||
- match: '($|\||\s{2,})'
|
||||
pop: true
|
||||
+1
Submodule assets/syntaxes/Swift added at fef17119ce.
Vendored
+371
@@ -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
|
||||
+1
Submodule assets/syntaxes/Syslog added at 7628d4e0b8.
Vendored
+1
-1
Submodule assets/syntaxes/TOML updated: b5e3064e99...4e74b2b41b.
+1
Submodule assets/syntaxes/Terraform added at 3227a2d2a2.
+3161
File diff suppressed because it is too large.
Load diff
Vendored
+1
-1
Submodule assets/syntaxes/VimL updated: b453aff6f7...ed40c3bc81.
Vendored
+1
-1
@@ -63,7 +63,7 @@ contexts:
|
||||
- match: \b(if|while|for|try|return|throw|end(if|for|while|try)?|au(g|group)|else(if|)?|do|in|catch|finally|:)\b
|
||||
scope: keyword.control.viml
|
||||
number_hex:
|
||||
- match: "#[0-9a-f]{6}"
|
||||
- match: "0x[0-9a-f]+"
|
||||
scope: constant.numeric.hex
|
||||
number_int:
|
||||
- match: '-?\d+'
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
%YAML 1.2
|
||||
---
|
||||
# http://www.sublimetext.com/docs/3/syntax.html
|
||||
name: Highlight non-printables
|
||||
file_extensions:
|
||||
- show-nonprintable
|
||||
scope: whitespace
|
||||
contexts:
|
||||
main:
|
||||
- match: "•"
|
||||
scope: support.function.show-nonprintable.space
|
||||
- match: "├─*┤"
|
||||
scope: constant.character.escape.show-nonprintable.tab
|
||||
- match: "↹"
|
||||
scope: constant.character.escape.show-nonprintable.tab
|
||||
- match: "␊"
|
||||
scope: keyword.operator.show-nonprintable.line-feed
|
||||
- match: "␍"
|
||||
scope: string.show-nonprintable.carriage-return
|
||||
- match: "␀"
|
||||
scope: entity.other.attribute-name.show-nonprintable.null
|
||||
- match: "␇"
|
||||
scope: entity.other.attribute-name.show-nonprintable.bell
|
||||
- match: "␛"
|
||||
scope: entity.other.attribute-name.show-nonprintable.escape
|
||||
- match: "␈"
|
||||
scope: entity.other.attribute-name.show-nonprintable.backspace
|
||||
+1
Submodule assets/syntaxes/varlink added at 04f30d4b83.
Vendored
BIN
Binary file not shown.
+1
Submodule assets/themes/onehalf added at 2516b37c3f.
+1
Submodule assets/themes/sublime-snazzy added at 70343201f1.
@@ -0,0 +1,31 @@
|
||||
// TODO: Re-enable generation of shell completion files (below) when clap 3 is out.
|
||||
// For more details, see https://github.com/sharkdp/bat/issues/372
|
||||
|
||||
fn main() {}
|
||||
|
||||
// #[macro_use]
|
||||
// extern crate clap;
|
||||
|
||||
// use clap::Shell;
|
||||
// use std::fs;
|
||||
|
||||
// include!("src/clap_app.rs");
|
||||
|
||||
// const BIN_NAME: &str = "bat";
|
||||
|
||||
// fn main() {
|
||||
// let outdir = std::env::var_os("SHELL_COMPLETIONS_DIR").or(std::env::var_os("OUT_DIR"));
|
||||
|
||||
// let outdir = match outdir {
|
||||
// None => return,
|
||||
// Some(outdir) => outdir,
|
||||
// };
|
||||
|
||||
// fs::create_dir_all(&outdir).unwrap();
|
||||
|
||||
// let mut app = build_app(true);
|
||||
// app.gen_completions(BIN_NAME, Shell::Bash, &outdir);
|
||||
// app.gen_completions(BIN_NAME, Shell::Fish, &outdir);
|
||||
// app.gen_completions(BIN_NAME, Shell::Zsh, &outdir);
|
||||
// app.gen_completions(BIN_NAME, Shell::PowerShell, &outdir);
|
||||
// }
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
* linguist-vendored
|
||||
Vendored
+21
-1
@@ -19,12 +19,15 @@ pack() {
|
||||
|
||||
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"
|
||||
mkdir "$tempdir/$package_name/autocomplete"
|
||||
|
||||
# copying the main binary
|
||||
cp "target/$TARGET/release/$PROJECT_NAME" "$tempdir/$package_name/"
|
||||
@@ -36,6 +39,12 @@ pack() {
|
||||
cp LICENSE-MIT "$tempdir/$package_name"
|
||||
cp LICENSE-APACHE "$tempdir/$package_name"
|
||||
|
||||
# various autocomplete
|
||||
# TODO: disabled for now, see issue #372
|
||||
# cp target/"$TARGET"/release/build/"$PROJECT_NAME"-*/out/"$PROJECT_NAME".bash "$tempdir/$package_name/autocomplete/${PROJECT_NAME}.bash-completion"
|
||||
# cp target/"$TARGET"/release/build/"$PROJECT_NAME"-*/out/"$PROJECT_NAME".fish "$tempdir/$package_name/autocomplete"
|
||||
# cp target/"$TARGET"/release/build/"$PROJECT_NAME"-*/out/_"$PROJECT_NAME" "$tempdir/$package_name/autocomplete"
|
||||
|
||||
# archiving
|
||||
pushd "$tempdir"
|
||||
tar czf "$out_dir/$package_name.tar.gz" "$package_name"/*
|
||||
@@ -49,13 +58,24 @@ 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 "make_deb: skipping target '${TARGET}'" >&2
|
||||
@@ -75,7 +95,7 @@ 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"
|
||||
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
# 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" '.\'
|
||||
# TODO: disabled for now, see issue #372
|
||||
# Copy-Item $SRC_DIR\target\release\build\bat-*\out\_bat.ps1 '.\'
|
||||
|
||||
# readme and license
|
||||
Copy-Item $SRC_DIR\README.md '.\'
|
||||
Copy-Item $SRC_DIR\LICENSE-MIT '.\'
|
||||
Copy-Item $SRC_DIR\LICENSE-APACHE '.\'
|
||||
|
||||
7z a "$ZIP" *
|
||||
|
||||
Push-AppveyorArtifact "$ZIP"
|
||||
|
||||
Set-Location ..
|
||||
Remove-Item $STAGE -Force -Recurse
|
||||
Set-Location $SRC_DIR
|
||||
Vendored
+8
@@ -27,3 +27,11 @@ if [[ $TARGET == arm-unknown-linux-gnueabihf ]]; then
|
||||
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
|
||||
Vendored
+1
-1
@@ -6,7 +6,7 @@ set -ex
|
||||
cargo build --target "$TARGET" --verbose
|
||||
|
||||
# We cannot run arm executables on linux
|
||||
if [[ $TARGET != arm-unknown-linux-gnueabihf ]]; then
|
||||
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
|
||||
|
||||
@@ -0,0 +1,447 @@
|
||||
<p align="center">
|
||||
<img src="logo-header.svg" alt="bat - a cat clone with wings"><br>
|
||||
<a href="https://travis-ci.org/sharkdp/bat"><img src="https://travis-ci.org/sharkdp/bat.svg?branch=master" alt="Build Status"></a>
|
||||
<a href="https://ci.appveyor.com/project/sharkdp/bat"><img src="https://ci.appveyor.com/api/projects/status/cptsmtbiwbnr2vhf?svg=true"></a>
|
||||
<img src="https://img.shields.io/crates/l/bat.svg" alt="license">
|
||||
<a href="https://crates.io/crates/bat"><img src="https://img.shields.io/crates/v/bat.svg?colorB=319e8c" alt="Version info"></a><br>
|
||||
A <i>cat(1)</i> clone with syntax highlighting and Git integration.
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="#syntax-highlighting">特徴</a> •
|
||||
<a href="#how-to-use">使い方</a> •
|
||||
<a href="#installation">インストール</a> •
|
||||
<a href="#customization">カスタマイズ</a> •
|
||||
<a href="#project-goals-and-alternatives">プロジェクトの目標と既存の類似したOSS</a> •
|
||||
翻訳 [<a href="https://github.com/chinanf-boy/bat-zh">中文</a>][<a href="README-ja">日本文</a>]
|
||||
</p>
|
||||
|
||||
### シンタックスハイライト
|
||||
|
||||
`bat` は多くのプログラミング言語やマークアップ言語のシンタックスハイライトに対応しています。
|
||||
|
||||

|
||||
|
||||
### Gitの統合
|
||||
|
||||
|
||||
`bat` は `git` とも連携しており、差分を表現する記号が表示されます(図の左端):
|
||||
|
||||

|
||||
|
||||
### 空白文字の可視化
|
||||
|
||||
`-A`/`--show-all` オプションをつけることで、空白文字を可視化できます:
|
||||
|
||||

|
||||
|
||||
### 自動呼び出し
|
||||
|
||||
出力が1つの画面に対して大きすぎる場合、`bat` は自身の出力を `less` にパイプで繋げることが可能です。
|
||||
|
||||
### ファイルの連結
|
||||
|
||||
あなたはさらにファイルを連結させるに使うことも可能です:wink:。
|
||||
`bat` は非対話型のターミナルを検出すると、いつでも `cat` の完全互換として振る舞い、
|
||||
プレーンなファイルを表示します。
|
||||
|
||||
## 使い方
|
||||
|
||||
単一のファイルを表示させたい
|
||||
|
||||
```bash
|
||||
> bat README.md
|
||||
```
|
||||
|
||||
複数のファイルを一度に表示させたい場合
|
||||
|
||||
```bash
|
||||
> bat src/*.rs
|
||||
```
|
||||
|
||||
標準入力から自動的に構文を決定させたい場合
|
||||
|
||||
```bash
|
||||
> curl -s https://sh.rustup.rs | bat
|
||||
```
|
||||
|
||||
Read from stdin, specify the language explicitly
|
||||
標準入力から明示的に言語を指定したい場合
|
||||
|
||||
```bash
|
||||
> yaml2json .travis.yml | json_pp | bat -l json
|
||||
```
|
||||
|
||||
空白文字を可視化させたい場合:
|
||||
```bash
|
||||
> bat -A /etc/hosts
|
||||
```
|
||||
|
||||
`cat` の代わりに `bat` を使用する際の例:
|
||||
|
||||
```bash
|
||||
bat > note.md # quickly create a new file
|
||||
|
||||
bat header.md content.md footer.md > document.md
|
||||
|
||||
bat -n main.rs # show line numbers (only)
|
||||
|
||||
bat f - g # output 'f', then stdin, then 'g'.
|
||||
```
|
||||
|
||||
## インストール
|
||||
|
||||
### Ubuntu
|
||||
*... や他のDebianベースのLinuxディストリビューション*
|
||||
|
||||
最新の `.deb` パッケージを[こちら](https://github.com/sharkdp/bat/releases)からダウンロードして、インストールしてください:
|
||||
|
||||
``` bash
|
||||
sudo dpkg -i bat_0.10.0_amd64.deb # adapt version number and architecture
|
||||
```
|
||||
|
||||
### Arch Linux
|
||||
|
||||
[Arch Linuxの公式リソース](https://www.archlinux.org/packages/community/x86_64/bat/)からインストールできます。
|
||||
|
||||
```bash
|
||||
pacman -S bat
|
||||
```
|
||||
|
||||
### Void Linux
|
||||
|
||||
xbps-ininstall経由で `bat` をインストールできます。
|
||||
|
||||
```
|
||||
xbps-install -S bat
|
||||
```
|
||||
|
||||
### Fedora
|
||||
|
||||
[Fedora Modular](https://docs.fedoraproject.org/en-US/modularity/using-modules/)経由で `bat` をインストールできます。これはFedora 29以上ではデフォルトで有効化されています。 もしそうでなければ、 `dnf install fedora-repos-modular` を実行してセットアップし、 `fedora-modular` と `fedora-updates-modular` が `/etc/yum.repos.d` で有効化されていることを確認してください。
|
||||
|
||||
```bash
|
||||
dnf module install bat
|
||||
```
|
||||
|
||||
### FreeBSD
|
||||
|
||||
事前にコンパイル済みである[pkg](https://www.freshports.org/textproc/bat)をインストールできます:
|
||||
|
||||
```bash
|
||||
pkg install bat
|
||||
```
|
||||
|
||||
または、FreeBSDのportsから自身でビルドすることも可能です:
|
||||
|
||||
```bash
|
||||
cd /usr/ports/textproc/bat
|
||||
make install
|
||||
```
|
||||
|
||||
### nix
|
||||
|
||||
`bat` を[nix package manager](https://nixos.org/nix)経由でインストールすることができます:
|
||||
|
||||
```bash
|
||||
nix-env -i bat
|
||||
```
|
||||
|
||||
### openSUSE
|
||||
|
||||
You can install `bat` with zypper:
|
||||
|
||||
`bat` をzypperでインストールすることができます:
|
||||
|
||||
```
|
||||
zypper install bat
|
||||
```
|
||||
|
||||
### macOS
|
||||
|
||||
[Homebrew](http://braumeister.org/formula/bat)でインストールすることができます:
|
||||
|
||||
|
||||
```bash
|
||||
brew install bat
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
You can download prebuilt binaries from the [Release page],
|
||||
or install it with :
|
||||
|
||||
事前にビルド済みのバイナリを[リリースページ](https://github.com/sharkdp/bat/releases)からダウンロードすることができます。または、[scoop](https://scoop.sh/)でインストールすることも可能です。
|
||||
|
||||
```bash
|
||||
scoop install bat
|
||||
```
|
||||
|
||||
[See below](#using-bat-on-windows) for notes.
|
||||
|
||||
### Docker
|
||||
|
||||
|
||||
コンテナ内で`bat` を使いたい方のために[Docker image](https://hub.docker.com/r/danlynn/bat/)が用意されています。
|
||||
|
||||
```bash
|
||||
docker pull danlynn/bat
|
||||
alias bat='docker run -it --rm -e BAT_THEME -e BAT_STYLE -e BAT_TABS -v "$(pwd):/myapp" danlynn/bat'
|
||||
```
|
||||
|
||||
### Ansible
|
||||
|
||||
[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)
|
||||
|
||||
これは以下のディストリビューションで動作するはずです:
|
||||
- Debian/Ubuntu
|
||||
- ARM (eg. Raspberry PI)
|
||||
- Arch Linux
|
||||
- Void Linux
|
||||
- FreeBSD
|
||||
- MacOS
|
||||
|
||||
### From binaries
|
||||
|
||||
|
||||
多くの異なるアーキテクチャのためのプレビルドバージョンを[リリースページ](https://github.com/sharkdp/bat/releases)からチェックしてみてください。静的にリンクされている多くのバイナリも利用できます: ファイル名に `musl` を含むアーカイブを探します。
|
||||
|
||||
### From source
|
||||
|
||||
|
||||
`bat` をソースからビルドしたいならば、Rust 1.29 以上の環境が必要です。そして、 `cargo` をビルドに対して使用します:
|
||||
|
||||
```bash
|
||||
cargo install bat
|
||||
```
|
||||
|
||||
|
||||
`cmake` と `libz` 開発パッケージ(`libz-dev` または `libz-devel`)が正しくビルドをするためにインストールする必要があるかもしれません。
|
||||
|
||||
## カスタマイズ
|
||||
|
||||
### ハイライト テーマ
|
||||
|
||||
`bat --list-themes` を使うと現在利用可能なシンタックスハイライトのテーマを入手できます。 `TwoDark` テーマを選ぶためには `--theme=TwoDark` オプションをつけるか `BAT_THEME` という環境変数に `TwoDark` を代入する必要があります。 シェルの起動ファイルに `export BAT_THEME="TwoDark"` と定義すればその設定が変わることはないでしょう。あるいは、 `bat` の[設定ファイル](https://github.com/sharkdp/bat#configuration-file)を利用してください。
|
||||
|
||||
|
||||
もし、ファイルにより異なるテーマを利用したい場合は、以下の[`fzf`](https://github.com/junegunn/fzf)を利用した以下のコマンドを使うことができます:
|
||||
``` bash
|
||||
bat --list-themes | fzf --preview="bat --theme={} --color=always /path/to/file"
|
||||
```
|
||||
|
||||
`bat` はデフォルトだと黒い背景色のターミナルに適しています。しかし、`GitHub` や `OneHalfLight` のような白い背景色のテーマでもいい感じにすることができます。
|
||||
以下のカスタムテーマを参考にしてみてください。
|
||||
['Adding new themes' section below](https://github.com/sharkdp/bat#adding-new-themes)
|
||||
|
||||
### 出力のスタイル
|
||||
|
||||
`--style` を使うことで `bat` の表示の見た目を変更することができます。例えば、 `--style=numbers,changes` と入力します。すると、Gitの差分と行番号だけが表示され、グリッド線とファイルヘッダーは表示されません。
|
||||
環境変数に `BAT_STYLE` を定義するとこれらの設定を永続的に使用することができます。
|
||||
[設定ファイル](https://github.com/sharkdp/bat#configuration-file)を参考にしても良いでしょう。
|
||||
|
||||
### 新しい構文の追加 / 言語の定義
|
||||
|
||||
`bat` はシンタックスハイライトのための[`syntext`](https://github.com/trishume/syntect/)という最高にイケてるライブラリを使用しています。`syntect` はSublime Textのために作られた[`.sublime-syntax` file](https://www.sublimetext.com/docs/3/syntax.html)テーマです。新しい構文を定義するために以下の手順を行います。
|
||||
|
||||
構文定義ファイルを入れておくためのフォルダを作る:
|
||||
|
||||
```bash
|
||||
mkdir -p "$(bat --config-dir)/syntaxes"
|
||||
cd "$(bat --config-dir)/syntaxes"
|
||||
|
||||
# Put new '.sublime-syntax' language definition files
|
||||
# in this folder (or its subdirectories), for example:
|
||||
git clone https://github.com/tellnobody1/sublime-purescript-syntax
|
||||
```
|
||||
|
||||
次のコマンドを使用して、これらのファイルをバイナリキャッシュに解析します:
|
||||
|
||||
```bash
|
||||
bat cache --build
|
||||
```
|
||||
|
||||
最後に `bat --list-languages` と入力すると新しい言語が利用可能かどうかチェックします。
|
||||
デフォルトの設定に戻したいときは以下のコマンドを実行します:
|
||||
|
||||
```bash
|
||||
bat cache --clear
|
||||
```
|
||||
|
||||
### 新しいテーマの追加
|
||||
|
||||
これは構文を新しく定義するやり方と非常に似ています。
|
||||
|
||||
まず、新しいシンタックスハイライトのテーマのフォルダを作ります:
|
||||
```bash
|
||||
mkdir -p "$(bat --config-dir)/themes"
|
||||
cd "$(bat --config-dir)/themes"
|
||||
|
||||
# Download a theme in '.tmTheme' format, for example:
|
||||
git clone https://github.com/greggb/sublime-snazzy
|
||||
|
||||
# Update the binary cache
|
||||
bat cache --build
|
||||
```
|
||||
|
||||
最後に、 `bat --list-themes` で新しいテーマが利用可能がチェックします
|
||||
|
||||
### 異なるページャーの使用
|
||||
|
||||
`bat` は環境変数 `PAGER` に使用するページャーを明記します。
|
||||
この環境変数が定義されていない場合、デフォルトで `less` が使用されます。もし、異なるページャーが使用したい場合は、`PAGER` を修正してください。または、`PAGER` を上書きする環境変数として `BAT_PAGER` を定義することも可能です。
|
||||
|
||||
もし、ページャーにコマンドライン引数を渡したい場合は、 `PAGER`/`BAT_PAGER` 環境変数を定義してください:
|
||||
```bash
|
||||
export BAT_PAGER="less -RF"
|
||||
```
|
||||
|
||||
環境変数を利用する代わりに、 `bat` の[設定ファイル](https://github.com/sharkdp/bat#configuration-file)の `--pager` オプションを使用することも可能です。
|
||||
|
||||
**注意**: デフォルトにより、ページャーが `less` にセットされているならば `bat` は以下のコマンドラインを受け付けるでしょう。
|
||||
ページャーのオプション: `-R`/`--RAW-CONTROL-CHARS`, `-F`/`--quit-if-one-screen` , `-X`/`--no-init`
|
||||
最初の `-R` はANSIカラーを正しく解釈するために必要です。2番目の `-F` は出力サイズがターミナルの縦のサイズよりも小さいならば `less` に即座に終了するように命令します。したがって、少量のファイルのためにページャーを終了する `q` を押す必要がありません。3番目のオプションの `-X` は `less` の古いバージョンの機能である `--quit-if-one-screen` でバグを修正するために必要です。運の悪いことに、これは `less` のマウス-ホイールのサポートを無効にします。もし、マウス-ホイール スクローリングを有効にしたいなら、`-R` だけをオプションとしてつけてください(ただし、これは `--quit-if-one-screen` を無効にするでしょう)。または、 `less` の最近バージョンを利用し、 `-RF` をつけてください。 これは望ましいことに `--quit-if-one-screen` と マウス-ホイールスクローリングの両方を有効にするでしょう。
|
||||
|
||||
スクロールが未だ動作しないのであれば、加えて `-S` オプションを追加してみてください。
|
||||
|
||||
## 設定ファイル
|
||||
|
||||
|
||||
`bat` は設定ファイルでカスタマイズすることが可能です。ファイルの場所はOSに依存します。使用しているOSのデフォルトパスを調べるには以下のコマンドを実行してください:
|
||||
```
|
||||
bat --config-file
|
||||
```
|
||||
|
||||
また、環境変数 `BAT_CONFIG_PATH` に設定ファイルの場所を明記することもできます:
|
||||
```bash
|
||||
export BAT_CONFIG_PATH="/path/to/bat.conf"
|
||||
```
|
||||
|
||||
### フォーマット
|
||||
|
||||
|
||||
この設定ファイルはコマンドライン引数の単純なリストです。 `bat --help` を利用すると、利用可能なオプションとその値を閲覧することができます。さらに、`#` でコメント文を加えることができます。
|
||||
|
||||
設定ファイルの例:
|
||||
```bash
|
||||
# Set the theme to "TwoDark"
|
||||
--theme="TwoDark"
|
||||
|
||||
# Show line numbers, Git modifications and file header (but no grid)
|
||||
--style="numbers,changes,header"
|
||||
|
||||
# Use italic text on the terminal (not supported on all terminals)
|
||||
--italic-text=always
|
||||
|
||||
# Add mouse scrolling support in less (does not work with older
|
||||
# versions of "less")
|
||||
--pager="less -FR"
|
||||
|
||||
# Use C++ syntax (instead of C) for .h header files
|
||||
--map-syntax h:cpp
|
||||
|
||||
# Use "gitignore" highlighting for ".ignore" files
|
||||
--map-syntax .ignore:.gitignore
|
||||
```
|
||||
|
||||
## Windows での `bat` の利用
|
||||
|
||||
Windows 上で `bat` はほとんど動作しますが、いくつかの機能は設定を必要をする場合があります。
|
||||
|
||||
### ページング
|
||||
|
||||
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).
|
||||
|
||||
|
||||
|
||||
### 色
|
||||
|
||||
Windows 10 は[v1151](https://en.wikipedia.org/wiki/Windows_10_version_history#Version_1511_(November_Update))からbashの新しいバージョンと同様に `conhost.exe`(コマンドプロンプト)と PowerShell の色をネイティブサポートしていません。Windows の新しいバージョンでは、[Cmder](http://cmder.net/)を使うことができます。これは[ConEmu](https://conemu.github.io/)を含んでいます。
|
||||
|
||||
**注意:** Git と MSYS の `less` はWindows上で色を正しく解釈しません。もし、あなたが他のページャーをインストールしていないのであれば、 `--paging=never` オプションを付け加えるまたは `BAT_PAGER` に空文字を設定することでページングを完全に無効にできます。
|
||||
|
||||
### Cygwin
|
||||
|
||||
Windows上の `bat` は Cygwin のunix風のpath(`/cygdrive/*`)をネイティブサポートしていません。
|
||||
絶対的なcygwinパスを引数として受けたときに、 `bat` は以下のエラーを返すでしょう: `The system cannot find the path specified. (os error 3)`
|
||||
|
||||
wrapperを作成するまたは以下の関数を `.bash_profile` に追記することでこの問題を解決することができます:
|
||||
```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[@]}"
|
||||
}
|
||||
```
|
||||
|
||||
## トラブルシューティング
|
||||
|
||||
### ターミナルと色
|
||||
|
||||
`bat` はターミナルがトゥルーカラーをサポートしている/していない関係なくサポートします。しかし、シンタックスハイライトのテーマの色が8-bitカラーに最適化されていない場合、24-bitであるトゥルーカラーをサポートしているターミナルを使用することを強く推奨します(`terminator`, `konsole`, `iTerm2`, ...)。
|
||||
この[記事](https://gist.github.com/XVilka/8346728)には24-bitカラーがサポートされているターミナルの一覧が掲載されています。
|
||||
|
||||
本当の色をターミナルにセットするために、環境変数 `COLORTERM` に `truecolor` か `24bit` のどちらかを代入してください。さもなければ、 `bat` はどの色を使うのか決定することができません。または、24-bit エスケープシーケンスがサポートされません(そして、8-bit colorに戻ります)。
|
||||
|
||||
### 行番号とグリッド線がほとんど見えない
|
||||
|
||||
異なるテーマを試してみてください(`bat --list-themes` でテーマを閲覧できます)。 `OneHalfDark` と `OneHalfLight` テーマはグリッド線と線の色を明るくします。
|
||||
|
||||
|
||||
## 開発
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
## プロジェクトの目標と既存の類似したOSS
|
||||
|
||||
`bat` は以下の目標を達成しようと試みています:
|
||||
|
||||
- 美しい高度なシンタックスハイライトの提供
|
||||
- ファイルの差分を表示するためのGitとの連携
|
||||
- (POSIX) `cat` との完全互換
|
||||
- ユーザーフレンドリーがコマンドラインインターフェースの提供
|
||||
|
||||
既存の類似したOSSはたくさんあります。
|
||||
`bat` とこれらを比較した表が[こちら](alternatives.md)にあります。
|
||||
+6
-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,7 @@ 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)
|
||||
- [vimpager](https://github.com/rkitover/vimpager)
|
||||
@@ -12,20 +12,25 @@ bat <SUBCOMMAND>
|
||||
.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.
|
||||
Explicitly set the language for syntax highlighting. The language can be specified as a
|
||||
name (like 'C++' or 'LaTeX') or possible file extension (like 'cpp', 'hpp' or 'md'). Use
|
||||
\&'\-\-list\-languages' to show all supported language names and file extensions.
|
||||
.HP
|
||||
\fB\-\-list\-languages\fR
|
||||
.IP
|
||||
Display a list of supported languages for syntax highlighting.
|
||||
.HP
|
||||
\fB\-m\fR, \fB\-\-map\-syntax\fR <from:to>...
|
||||
.IP
|
||||
Map a file extension or file name to an existing syntax. For example, to highlight
|
||||
*.conf files with the INI syntax, use '\-m conf:ini'. To highlight files named
|
||||
\&'.myignore' with the Git Ignore syntax, use '\-m .myignore:gitignore'.
|
||||
.HP
|
||||
\fB\-\-theme\fR <theme>
|
||||
.IP
|
||||
Set the theme for syntax highlighting. Use '\-\-list\-themes' to see all
|
||||
available themes. To set a default theme, export the BAT_THEME environment
|
||||
variable (e.g.: export BAT_THEME="TwoDark").
|
||||
Set the theme for syntax highlighting. Use '\-\-list\-themes' to see all available themes.
|
||||
To set a default theme, add the '\-\-theme="..."' option to the configuration file or
|
||||
export the BAT_THEME environment variable (e.g.: export BAT_THEME="...").
|
||||
.HP
|
||||
\fB\-\-list\-themes\fR
|
||||
.IP
|
||||
@@ -33,22 +38,27 @@ 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') [default: auto]
|
||||
[possible values: auto, full, plain, changes, header, grid, numbers]
|
||||
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 style, add the '\-\-style=".."' option to the configuration file or
|
||||
export the BAT_STYLE environment variable (e.g.: export BAT_STYLE=".."). Possible
|
||||
values: *auto*, full, plain, changes, header, grid, numbers.
|
||||
.HP
|
||||
\fB\-p\fR
|
||||
\fB\-p\fR, \fB\-\-plain\fR
|
||||
.IP
|
||||
Only show plain style, no decorations. This is an alias for '\-\-style=plain'
|
||||
.HP
|
||||
\fB\-n\fR, \fB\-\-number\fR
|
||||
.IP
|
||||
Only show line numbers, no other decorations. This is an alias for
|
||||
\&'\-\-style=numbers'
|
||||
Only show line numbers, no other decorations. This is an alias for '\-\-style=numbers'
|
||||
.HP
|
||||
\fB\-\-line\-range\fR <N:M>
|
||||
\fB\-A\fR, \fB\-\-show\-all\fR
|
||||
.IP
|
||||
Show non\-printable characters like space, tab or newline. Use '\-\-tabs' to control the
|
||||
width of the tab\-placeholders.
|
||||
.HP
|
||||
\fB\-\-line\-range\fR <N:M>...
|
||||
.IP
|
||||
Only print the specified range of lines for each file. For example:
|
||||
.RS
|
||||
@@ -62,32 +72,51 @@ prints lines 40 to the end of the file
|
||||
.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]
|
||||
Specify when to use colored output. The automatic mode only enables colors if an
|
||||
interactive terminal is detected. Possible values: *auto*, never, always.
|
||||
.HP
|
||||
\fB\-\-italic\-text\fR <when>
|
||||
.IP
|
||||
Specify when to use ANSI sequences for italic text in the output. Possible values:
|
||||
always, *never*.
|
||||
.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]
|
||||
Specify when to use the decorations that have been specified via '\-\-style'. The
|
||||
automatic mode only enables decorations if an interactive terminal is detected. Possible
|
||||
values: *auto*, never, always.
|
||||
.HP
|
||||
\fB\-\-paging\fR <when>
|
||||
.IP
|
||||
Specify when to use the pager. To control which pager is used, set the PAGER
|
||||
or BAT_PAGER environment variables (the latter takes precedence). The default
|
||||
pager is 'less'. To disable the pager permanently, set BAT_PAGER to an empty
|
||||
string. [default: auto] [possible values: auto, never, always]
|
||||
Specify when to use the pager. To control which pager is used, set the PAGER or
|
||||
BAT_PAGER environment variables (the latter takes precedence) or use the '\-\-pager'
|
||||
option. To disable the pager permanently, set BAT_PAGER to an empty string or set
|
||||
\&'\-\-paging=never' in the configuration file. Possible values: *auto*, never, always.
|
||||
.HP
|
||||
\fB\-\-pager\fR <command>
|
||||
.IP
|
||||
Determine which pager is used. This option will overwrite the PAGER and BAT_PAGER
|
||||
environment variables. The default pager is 'less'. To disable the pager completely, use
|
||||
the '\-\-paging' option. Example: '\-\-pager "less \fB\-RF\fR"'.
|
||||
.HP
|
||||
\fB\-\-wrap\fR <mode>
|
||||
.IP
|
||||
Specify the text\-wrapping mode. [default: character]
|
||||
[possible values: character, never]
|
||||
Specify the text\-wrapping mode (*auto*, never, character).
|
||||
.HP
|
||||
\fB\-u\fR
|
||||
\fB\-\-tabs\fR <T>
|
||||
.IP
|
||||
This option exists for POSIX\-compliance reasons ('u' is for 'unbuffered'). The
|
||||
output is always unbuffered \- this option is simply ignored.
|
||||
Set the tab width to T spaces. Use a width of 0 to pass tabs through directly
|
||||
.HP
|
||||
\fB\-u\fR, \fB\-\-unbuffered\fR
|
||||
.IP
|
||||
This option exists for POSIX\-compliance reasons ('u' is for 'unbuffered'). The output is
|
||||
always unbuffered \- this option is simply ignored.
|
||||
.HP
|
||||
\fB\-\-terminal\-width\fR <width>
|
||||
.IP
|
||||
Explicitly set the width of the terminal instead of determining it automatically. If
|
||||
prefixed with '+' or '\-', the value will be treated as an offset to the actual terminal
|
||||
width.
|
||||
.HP
|
||||
\fB\-h\fR, \fB\-\-help\fR
|
||||
.IP
|
||||
@@ -105,5 +134,4 @@ from standard input.
|
||||
.SH "SUBCOMMANDS"
|
||||
.IP
|
||||
cache
|
||||
.IP
|
||||
Modify the syntax\-definition and theme cache. See "bat cache --help" for more information
|
||||
Modify the syntax\-definition and theme cache
|
||||
+193
-279
@@ -1,9 +1,12 @@
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::str::FromStr;
|
||||
|
||||
use atty::{self, Stream};
|
||||
|
||||
use clap::{App as ClapApp, AppSettings, Arg, ArgGroup, ArgMatches, SubCommand};
|
||||
use clap::ArgMatches;
|
||||
use clap_app;
|
||||
use wild;
|
||||
|
||||
use console::Term;
|
||||
|
||||
@@ -11,24 +14,21 @@ use console::Term;
|
||||
use ansi_term;
|
||||
|
||||
use assets::BAT_THEME_DEFAULT;
|
||||
use config::{get_args_from_config_file, get_args_from_env_var};
|
||||
use errors::*;
|
||||
use line_range::LineRange;
|
||||
use inputfile::InputFile;
|
||||
use line_range::{LineRange, LineRanges};
|
||||
use style::{OutputComponent, OutputComponents, OutputWrap};
|
||||
use syntax_mapping::SyntaxMapping;
|
||||
use util::transpose;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[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
|
||||
@@ -37,9 +37,16 @@ pub struct Config<'a> {
|
||||
/// The explicitly configured language, if any
|
||||
pub language: Option<&'a str>,
|
||||
|
||||
/// Whether or not to show/replace non-printable characters like space, tab and newline.
|
||||
pub show_nonprintable: bool,
|
||||
|
||||
/// 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,
|
||||
|
||||
@@ -58,11 +65,23 @@ pub struct Config<'a> {
|
||||
/// Pager or STDOUT
|
||||
pub paging_mode: PagingMode,
|
||||
|
||||
/// The range lines that should be printed, if specified
|
||||
pub line_range: Option<LineRange>,
|
||||
/// Specifies the lines that should be printed
|
||||
pub line_ranges: LineRanges,
|
||||
|
||||
/// The syntax highlighting theme
|
||||
pub theme: String,
|
||||
|
||||
/// File extension/name mappings
|
||||
pub syntax_mapping: SyntaxMapping,
|
||||
|
||||
/// Command to start the pager
|
||||
pub pager: Option<&'a str>,
|
||||
|
||||
/// Whether or not to use ANSI italics
|
||||
pub use_italic_text: bool,
|
||||
|
||||
/// Lines to highlight
|
||||
pub highlight_lines: Vec<usize>,
|
||||
}
|
||||
|
||||
fn is_truecolor_terminal() -> bool {
|
||||
@@ -71,286 +90,60 @@ fn is_truecolor_terminal() -> bool {
|
||||
.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,
|
||||
}
|
||||
|
||||
impl App {
|
||||
pub fn new() -> Self {
|
||||
pub fn new() -> Result<Self> {
|
||||
#[cfg(windows)]
|
||||
let _ = ansi_term::enable_ansi_support();
|
||||
|
||||
let interactive_output = atty::is(Stream::Stdout);
|
||||
|
||||
#[cfg(windows)]
|
||||
let interactive_output = interactive_output && ansi_term::enable_ansi_support().is_ok();
|
||||
|
||||
App {
|
||||
matches: Self::matches(interactive_output),
|
||||
Ok(App {
|
||||
matches: Self::matches(interactive_output)?,
|
||||
interactive_output,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn matches(interactive_output: bool) -> ArgMatches<'static> {
|
||||
let clap_color_setting = if interactive_output {
|
||||
AppSettings::ColoredHelp
|
||||
fn matches(interactive_output: bool) -> Result<ArgMatches<'static>> {
|
||||
let args = if wild::args_os().nth(1) == Some("cache".into())
|
||||
|| wild::args_os().any(|arg| arg == "--no-config")
|
||||
{
|
||||
// Skip the arguments in bats config file
|
||||
|
||||
wild::args_os().collect::<Vec<_>>()
|
||||
} else {
|
||||
AppSettings::ColorNever
|
||||
let mut cli_args = wild::args_os();
|
||||
|
||||
// Read arguments from bats config file
|
||||
let mut args = get_args_from_env_var()
|
||||
.unwrap_or_else(|| get_args_from_config_file())
|
||||
.chain_err(|| "Could not parse configuration file")?;
|
||||
|
||||
// Put the zero-th CLI argument (program name) first
|
||||
args.insert(0, cli_args.next().unwrap());
|
||||
|
||||
// .. and the rest at the end
|
||||
cli_args.for_each(|a| args.push(a));
|
||||
|
||||
args
|
||||
};
|
||||
|
||||
ClapApp::new(crate_name!())
|
||||
.version(crate_version!())
|
||||
.global_setting(clap_color_setting)
|
||||
.global_setting(AppSettings::DeriveDisplayOrder)
|
||||
.global_setting(AppSettings::UnifiedHelpMessage)
|
||||
.global_setting(AppSettings::NextLineHelp)
|
||||
.setting(AppSettings::InferSubcommands)
|
||||
.setting(AppSettings::ArgsNegateSubcommands)
|
||||
.setting(AppSettings::DisableHelpSubcommand)
|
||||
.setting(AppSettings::VersionlessSubcommands)
|
||||
.max_term_width(90)
|
||||
.about(
|
||||
"A cat(1) clone with wings.\n\n\
|
||||
Use '--help' instead of '-h' to see a more detailed version of the help text.",
|
||||
).long_about("A cat(1) clone with syntax highlighting and Git integration.")
|
||||
.arg(
|
||||
Arg::with_name("FILE")
|
||||
.help("File(s) to print / concatenate. Use '-' for standard input.")
|
||||
.long_help(
|
||||
"File(s) to print / concatenate. Use a dash ('-') or no argument at all \
|
||||
to read from standard input.",
|
||||
).multiple(true)
|
||||
.empty_values(false),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("language")
|
||||
.short("l")
|
||||
.long("language")
|
||||
.overrides_with("language")
|
||||
.help("Set the language for syntax highlighting.")
|
||||
.long_help(
|
||||
"Explicitly set the language for syntax highlighting. The language can be \
|
||||
specified as a name (like 'C++' or 'LaTeX') or possible file extension \
|
||||
(like 'cpp', 'hpp' or 'md'). Use '--list-languages' to show all supported \
|
||||
language names and file extensions."
|
||||
).takes_value(true),
|
||||
).arg(
|
||||
Arg::with_name("list-languages")
|
||||
.long("list-languages")
|
||||
.conflicts_with("list-themes")
|
||||
.help("Display all supported languages.")
|
||||
.long_help("Display a list of supported languages for syntax highlighting."),
|
||||
).arg(
|
||||
Arg::with_name("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",
|
||||
]).default_value("auto")
|
||||
.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("plain")
|
||||
.overrides_with("plain")
|
||||
.short("p")
|
||||
.long("plain")
|
||||
.conflicts_with("style")
|
||||
.conflicts_with("number")
|
||||
.help("Show plain style (alias for '--style=plain').")
|
||||
.long_help(
|
||||
"Only show plain style, no decorations. This is an alias for \
|
||||
'--style=plain'",
|
||||
),
|
||||
).arg(
|
||||
Arg::with_name("number")
|
||||
.long("number")
|
||||
.overrides_with("number")
|
||||
.short("n")
|
||||
.conflicts_with("style")
|
||||
.help("Show line numbers (alias for '--style=numbers').")
|
||||
.long_help(
|
||||
"Only show line numbers, no other decorations. This is an alias for \
|
||||
'--style=numbers'",
|
||||
),
|
||||
).arg(
|
||||
Arg::with_name("line-range")
|
||||
.long("line-range")
|
||||
.overrides_with("line-range")
|
||||
.takes_value(true)
|
||||
.value_name("N:M")
|
||||
.help("Only print the lines from N to M.")
|
||||
.long_help(
|
||||
"Only print the specified range of lines for each file. \
|
||||
For example:\n \
|
||||
'--line-range 30:40' prints lines 30 to 40\n \
|
||||
'--line-range :40' prints lines 1 to 40\n \
|
||||
'--line-range 40:' prints lines 40 to the end of the file",
|
||||
),
|
||||
).arg(
|
||||
Arg::with_name("color")
|
||||
.long("color")
|
||||
.overrides_with("color")
|
||||
.takes_value(true)
|
||||
.value_name("when")
|
||||
.possible_values(&["auto", "never", "always"])
|
||||
.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(&["character", "never"])
|
||||
.default_value("character")
|
||||
.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 \
|
||||
is simply ignored.",
|
||||
),
|
||||
).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(true),
|
||||
).arg(
|
||||
Arg::with_name("source")
|
||||
.long("source")
|
||||
.requires("init")
|
||||
.takes_value(true)
|
||||
.value_name("dir")
|
||||
.help("Use a different directory to load syntaxes and themes from."),
|
||||
).arg(
|
||||
Arg::with_name("target")
|
||||
.long("target")
|
||||
.requires("init")
|
||||
.takes_value(true)
|
||||
.value_name("dir")
|
||||
.help(
|
||||
"Use a different directory to store the cached syntax and theme set.",
|
||||
),
|
||||
).arg(
|
||||
Arg::with_name("blank")
|
||||
.long("blank")
|
||||
.requires("init")
|
||||
.help("Create completely new syntax and theme sets \
|
||||
(instead of appending to the default sets).")
|
||||
),
|
||||
).help_message("Print this help message.")
|
||||
.version_message("Show version information.")
|
||||
.get_matches()
|
||||
Ok(clap_app::build_app(interactive_output).get_matches_from(args))
|
||||
}
|
||||
|
||||
pub fn config(&self) -> Result<Config> {
|
||||
let files = self.files();
|
||||
let output_components = self.output_components()?;
|
||||
|
||||
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.
|
||||
// There's no point in wrapping when this is the case.
|
||||
OutputWrap::None
|
||||
} else {
|
||||
match self.matches.value_of("wrap") {
|
||||
Some("character") => OutputWrap::Character,
|
||||
Some("never") | _ => OutputWrap::None,
|
||||
}
|
||||
},
|
||||
colored_output: match self.matches.value_of("color") {
|
||||
Some("always") => true,
|
||||
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(&InputFile::StdIn) {
|
||||
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.
|
||||
@@ -365,20 +158,121 @@ impl App {
|
||||
} else {
|
||||
PagingMode::Never
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let mut syntax_mapping = SyntaxMapping::new();
|
||||
|
||||
if let Some(values) = self.matches.values_of("map-syntax") {
|
||||
for from_to in values {
|
||||
let parts: Vec<_> = from_to.split(":").collect();
|
||||
|
||||
if parts.len() != 2 {
|
||||
return Err("Invalid syntax mapping. The format of the -m/--map-syntax option is 'from:to'.".into());
|
||||
}
|
||||
|
||||
syntax_mapping.insert(parts[0], parts[1]);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Config {
|
||||
true_color: is_truecolor_terminal(),
|
||||
language: self.matches.value_of("language").or_else(|| {
|
||||
if self.matches.is_present("show-all") {
|
||||
Some("show-nonprintable")
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}),
|
||||
show_nonprintable: self.matches.is_present("show-all"),
|
||||
output_wrap: if !self.interactive_output {
|
||||
// We don't have the tty width when piping to another program.
|
||||
// There's no point in wrapping when this is the case.
|
||||
OutputWrap::None
|
||||
} else {
|
||||
match self.matches.value_of("wrap") {
|
||||
Some("character") => OutputWrap::Character,
|
||||
Some("never") => OutputWrap::None,
|
||||
Some("auto") | _ => {
|
||||
if output_components.plain() {
|
||||
OutputWrap::None
|
||||
} else {
|
||||
OutputWrap::Character
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
term_width: Term::stdout().size().1 as usize,
|
||||
colored_output: match self.matches.value_of("color") {
|
||||
Some("always") => true,
|
||||
Some("never") => false,
|
||||
Some("auto") | _ => self.interactive_output,
|
||||
},
|
||||
paging_mode,
|
||||
term_width: self
|
||||
.matches
|
||||
.value_of("terminal-width")
|
||||
.and_then(|w| {
|
||||
if w.starts_with("+") || w.starts_with("-") {
|
||||
// Treat argument as a delta to the current terminal width
|
||||
w.parse().ok().map(|delta: i16| {
|
||||
let old_width: u16 = Term::stdout().size().1;
|
||||
let new_width: i32 = old_width as i32 + delta as i32;
|
||||
|
||||
if new_width <= 0 {
|
||||
old_width as usize
|
||||
} else {
|
||||
new_width as usize
|
||||
}
|
||||
})
|
||||
} else {
|
||||
w.parse().ok()
|
||||
}
|
||||
})
|
||||
.unwrap_or(Term::stdout().size().1 as usize),
|
||||
loop_through: !(self.interactive_output
|
||||
|| self.matches.value_of("color") == Some("always")
|
||||
|| self.matches.value_of("decorations") == Some("always")),
|
||||
files,
|
||||
tab_width: self
|
||||
.matches
|
||||
.value_of("tabs")
|
||||
.map(String::from)
|
||||
.or_else(|| env::var("BAT_TABS").ok())
|
||||
.and_then(|t| t.parse().ok())
|
||||
.unwrap_or(
|
||||
if output_components.plain() && paging_mode == PagingMode::Never {
|
||||
0
|
||||
} else {
|
||||
4
|
||||
},
|
||||
),
|
||||
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))?,
|
||||
line_ranges: LineRanges::from(
|
||||
transpose(
|
||||
self.matches
|
||||
.values_of("line-range")
|
||||
.map(|vs| vs.map(LineRange::from).collect()),
|
||||
)?
|
||||
.unwrap_or(vec![]),
|
||||
),
|
||||
output_components,
|
||||
syntax_mapping,
|
||||
pager: self.matches.value_of("pager"),
|
||||
use_italic_text: match self.matches.value_of("italic-text") {
|
||||
Some("always") => true,
|
||||
_ => false,
|
||||
},
|
||||
highlight_lines: self
|
||||
.matches
|
||||
.values_of("highlight-line")
|
||||
.and_then(|ws| ws.map(|w| w.parse().ok()).collect())
|
||||
.unwrap_or_default(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -393,8 +287,10 @@ impl App {
|
||||
} else {
|
||||
InputFile::Ordinary(filename)
|
||||
}
|
||||
}).collect()
|
||||
}).unwrap_or_else(|| vec![InputFile::StdIn])
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_else(|| vec![InputFile::StdIn])
|
||||
}
|
||||
|
||||
fn output_components(&self) -> Result<OutputComponents> {
|
||||
@@ -407,7 +303,25 @@ impl App {
|
||||
} else if matches.is_present("plain") {
|
||||
[OutputComponent::Plain].iter().cloned().collect()
|
||||
} else {
|
||||
values_t!(matches.values_of("style"), OutputComponent)?
|
||||
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>>>()
|
||||
}))?;
|
||||
|
||||
matches
|
||||
.value_of("style")
|
||||
.map(|styles| {
|
||||
styles
|
||||
.split(",")
|
||||
.map(|style| style.parse::<OutputComponent>())
|
||||
.filter_map(|style| style.ok())
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.or(env_style_components)
|
||||
.unwrap_or(vec![OutputComponent::Full])
|
||||
.into_iter()
|
||||
.map(|style| style.components(self.interactive_output))
|
||||
.fold(HashSet::new(), |mut acc, components| {
|
||||
|
||||
+71
-74
@@ -1,22 +1,18 @@
|
||||
use directories::ProjectDirs;
|
||||
use errors::*;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs::{self, File};
|
||||
use std::io::BufReader;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use syntect::dumps::{dump_to_file, from_binary, from_reader};
|
||||
use syntect::highlighting::{Theme, ThemeSet};
|
||||
use syntect::parsing::{SyntaxDefinition, SyntaxSet};
|
||||
use syntect::parsing::{SyntaxReference, SyntaxSet, SyntaxSetBuilder};
|
||||
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::FileTypeExt;
|
||||
use dirs::PROJECT_DIRS;
|
||||
|
||||
use app::InputFile;
|
||||
|
||||
lazy_static! {
|
||||
static ref PROJECT_DIRS: ProjectDirs =
|
||||
ProjectDirs::from("", "", crate_name!()).expect("Could not get home directory");
|
||||
}
|
||||
use errors::*;
|
||||
use inputfile::{InputFile, InputFileReader};
|
||||
use syntax_mapping::SyntaxMapping;
|
||||
|
||||
pub const BAT_THEME_DEFAULT: &str = "Monokai Extended";
|
||||
|
||||
@@ -30,31 +26,20 @@ impl HighlightingAssets {
|
||||
Self::from_cache().unwrap_or_else(|_| Self::from_binary())
|
||||
}
|
||||
|
||||
fn empty() -> Self {
|
||||
let mut syntax_set = SyntaxSet::new();
|
||||
syntax_set.load_plain_text_syntax();
|
||||
|
||||
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()
|
||||
let mut theme_set = if start_empty {
|
||||
ThemeSet {
|
||||
themes: BTreeMap::new(),
|
||||
}
|
||||
} else {
|
||||
Self::from_binary_unlinked()
|
||||
Self::get_integrated_themeset()
|
||||
};
|
||||
|
||||
let theme_dir = source_dir.join("themes");
|
||||
|
||||
let res = extend_theme_set(&mut assets.theme_set, &theme_dir);
|
||||
let res = theme_set.add_from_folder(&theme_dir);
|
||||
if !res.is_ok() {
|
||||
println!(
|
||||
"No themes were found in '{}', using the default set",
|
||||
@@ -62,9 +47,17 @@ impl HighlightingAssets {
|
||||
);
|
||||
}
|
||||
|
||||
let mut syntax_set_builder = if start_empty {
|
||||
let mut builder = SyntaxSetBuilder::new();
|
||||
builder.add_plain_text_syntax();
|
||||
builder
|
||||
} else {
|
||||
Self::get_integrated_syntaxset().into_builder()
|
||||
};
|
||||
|
||||
let syntax_dir = source_dir.join("syntaxes");
|
||||
if syntax_dir.exists() {
|
||||
assets.syntax_set.load_syntaxes(syntax_dir, true)?;
|
||||
syntax_set_builder.add_from_folder(syntax_dir, true)?;
|
||||
} else {
|
||||
println!(
|
||||
"No syntaxes were found in '{}', using the default set.",
|
||||
@@ -72,7 +65,10 @@ impl HighlightingAssets {
|
||||
);
|
||||
}
|
||||
|
||||
Ok(assets)
|
||||
Ok(HighlightingAssets {
|
||||
syntax_set: syntax_set_builder.build(),
|
||||
theme_set,
|
||||
})
|
||||
}
|
||||
|
||||
fn from_cache() -> Result<Self> {
|
||||
@@ -83,9 +79,8 @@ impl HighlightingAssets {
|
||||
syntax_set_path().to_string_lossy()
|
||||
)
|
||||
})?;
|
||||
let mut syntax_set: SyntaxSet =
|
||||
from_reader(syntax_set_file).chain_err(|| "Could not parse cached syntax set")?;
|
||||
syntax_set.link_syntaxes();
|
||||
let syntax_set: SyntaxSet = from_reader(BufReader::new(syntax_set_file))
|
||||
.chain_err(|| "Could not parse cached syntax set")?;
|
||||
|
||||
let theme_set_file = File::open(&theme_set_path).chain_err(|| {
|
||||
format!(
|
||||
@@ -93,8 +88,8 @@ impl HighlightingAssets {
|
||||
theme_set_path.to_string_lossy()
|
||||
)
|
||||
})?;
|
||||
let theme_set: ThemeSet =
|
||||
from_reader(theme_set_file).chain_err(|| "Could not parse cached theme set")?;
|
||||
let theme_set: ThemeSet = from_reader(BufReader::new(theme_set_file))
|
||||
.chain_err(|| "Could not parse cached theme set")?;
|
||||
|
||||
Ok(HighlightingAssets {
|
||||
syntax_set,
|
||||
@@ -102,9 +97,17 @@ impl HighlightingAssets {
|
||||
})
|
||||
}
|
||||
|
||||
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"));
|
||||
fn get_integrated_syntaxset() -> SyntaxSet {
|
||||
from_binary(include_bytes!("../assets/syntaxes.bin"))
|
||||
}
|
||||
|
||||
fn get_integrated_themeset() -> ThemeSet {
|
||||
from_binary(include_bytes!("../assets/themes.bin"))
|
||||
}
|
||||
|
||||
fn from_binary() -> Self {
|
||||
let syntax_set = Self::get_integrated_syntaxset();
|
||||
let theme_set = Self::get_integrated_themeset();
|
||||
|
||||
HighlightingAssets {
|
||||
syntax_set,
|
||||
@@ -112,12 +115,6 @@ 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);
|
||||
@@ -166,29 +163,40 @@ impl HighlightingAssets {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_syntax(&self, language: Option<&str>, filename: InputFile) -> &SyntaxDefinition {
|
||||
pub fn get_syntax(
|
||||
&self,
|
||||
language: Option<&str>,
|
||||
filename: InputFile,
|
||||
reader: &mut InputFileReader,
|
||||
mapping: &SyntaxMapping,
|
||||
) -> &SyntaxReference {
|
||||
let syntax = match (language, filename) {
|
||||
(Some(language), _) => self.syntax_set.find_syntax_by_token(language),
|
||||
(None, InputFile::Ordinary(filename)) => {
|
||||
#[cfg(not(unix))]
|
||||
let may_read_from_file = true;
|
||||
let path = Path::new(filename);
|
||||
let file_name = path.file_name().and_then(|n| n.to_str()).unwrap_or("");
|
||||
let extension = path.extension().and_then(|x| x.to_str()).unwrap_or("");
|
||||
|
||||
// Do not peek at the file (to determine the syntax) if it is a FIFO because they can
|
||||
// only be read once.
|
||||
#[cfg(unix)]
|
||||
let may_read_from_file = !fs::metadata(filename)
|
||||
.map(|m| m.file_type().is_fifo())
|
||||
.unwrap_or(false);
|
||||
let file_name = mapping.replace(file_name);
|
||||
let extension = mapping.replace(extension);
|
||||
|
||||
if may_read_from_file {
|
||||
self.syntax_set
|
||||
.find_syntax_for_file(filename)
|
||||
.unwrap_or(None)
|
||||
let ext_syntax = self
|
||||
.syntax_set
|
||||
.find_syntax_by_extension(&file_name)
|
||||
.or_else(|| self.syntax_set.find_syntax_by_extension(&extension));
|
||||
let line_syntax = if ext_syntax.is_none() {
|
||||
String::from_utf8(reader.first_line.clone())
|
||||
.ok()
|
||||
.and_then(|l| self.syntax_set.find_syntax_by_first_line(&l))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
let syntax = ext_syntax.or(line_syntax);
|
||||
syntax
|
||||
}
|
||||
(None, InputFile::StdIn) => None,
|
||||
(None, InputFile::StdIn) => String::from_utf8(reader.first_line.clone())
|
||||
.ok()
|
||||
.and_then(|l| self.syntax_set.find_syntax_by_first_line(&l)),
|
||||
(_, InputFile::ThemePreviewFile) => self.syntax_set.find_syntax_by_name("Rust"),
|
||||
};
|
||||
|
||||
@@ -196,21 +204,6 @@ impl HighlightingAssets {
|
||||
}
|
||||
}
|
||||
|
||||
// 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")
|
||||
}
|
||||
@@ -223,6 +216,10 @@ pub fn config_dir() -> Cow<'static, str> {
|
||||
PROJECT_DIRS.config_dir().to_string_lossy()
|
||||
}
|
||||
|
||||
pub fn cache_dir() -> Cow<'static, str> {
|
||||
PROJECT_DIRS.cache_dir().to_string_lossy()
|
||||
}
|
||||
|
||||
pub fn clear_assets() {
|
||||
print!("Clearing theme set cache ... ");
|
||||
fs::remove_file(theme_set_path()).ok();
|
||||
|
||||
+413
@@ -0,0 +1,413 @@
|
||||
use clap::{App as ClapApp, AppSettings, Arg, ArgGroup, SubCommand};
|
||||
use std::path::Path;
|
||||
|
||||
pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
|
||||
let clap_color_setting = if interactive_output {
|
||||
AppSettings::ColoredHelp
|
||||
} else {
|
||||
AppSettings::ColorNever
|
||||
};
|
||||
|
||||
// Check if the current directory contains a file name cache, if it does
|
||||
// do not make the arguements for subcommand 'cache' required.
|
||||
let arg_group_required = !Path::new("cache").exists();
|
||||
|
||||
ClapApp::new(crate_name!())
|
||||
.version(crate_version!())
|
||||
.global_setting(clap_color_setting)
|
||||
.global_setting(AppSettings::DeriveDisplayOrder)
|
||||
.global_setting(AppSettings::UnifiedHelpMessage)
|
||||
.global_setting(AppSettings::HidePossibleValuesInHelp)
|
||||
.setting(AppSettings::InferSubcommands)
|
||||
.setting(AppSettings::ArgsNegateSubcommands)
|
||||
.setting(AppSettings::DisableHelpSubcommand)
|
||||
.setting(AppSettings::VersionlessSubcommands)
|
||||
.max_term_width(100)
|
||||
.about(
|
||||
"A cat(1) clone with wings.\n\n\
|
||||
Use '--help' instead of '-h' to see a more detailed version of the help text.",
|
||||
)
|
||||
.long_about("A cat(1) clone with syntax highlighting and Git integration.")
|
||||
.arg(
|
||||
Arg::with_name("FILE")
|
||||
.help("File(s) to print / concatenate. Use '-' for standard input.")
|
||||
.long_help(
|
||||
"File(s) to print / concatenate. Use a dash ('-') or no argument at all \
|
||||
to read from standard input.",
|
||||
)
|
||||
.multiple(true)
|
||||
.empty_values(false),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("language")
|
||||
.short("l")
|
||||
.long("language")
|
||||
.overrides_with("language")
|
||||
.help("Set the language for syntax highlighting.")
|
||||
.long_help(
|
||||
"Explicitly set the language for syntax highlighting. The language can be \
|
||||
specified as a name (like 'C++' or 'LaTeX') or possible file extension \
|
||||
(like 'cpp', 'hpp' or 'md'). Use '--list-languages' to show all supported \
|
||||
language names and file extensions.",
|
||||
)
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("list-languages")
|
||||
.long("list-languages")
|
||||
.conflicts_with("list-themes")
|
||||
.help("Display all supported languages.")
|
||||
.long_help("Display a list of supported languages for syntax highlighting."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("map-syntax")
|
||||
.short("m")
|
||||
.long("map-syntax")
|
||||
.multiple(true)
|
||||
.takes_value(true)
|
||||
.number_of_values(1)
|
||||
.value_name("from:to")
|
||||
.help("Map a file extension or name to an existing syntax.")
|
||||
.long_help(
|
||||
"Map a file extension or file name to an existing syntax. For example, \
|
||||
to highlight *.conf files with the INI syntax, use '-m conf:ini'. \
|
||||
To highlight files named '.myignore' with the Git Ignore syntax, use \
|
||||
'-m .myignore:gitignore'.",
|
||||
)
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("theme")
|
||||
.long("theme")
|
||||
.overrides_with("theme")
|
||||
.takes_value(true)
|
||||
.help("Set the color theme for syntax highlighting.")
|
||||
.long_help(
|
||||
"Set the theme for syntax highlighting. Use '--list-themes' to \
|
||||
see all available themes. To set a default theme, add the \
|
||||
'--theme=\"...\"' option to the configuration file or export the \
|
||||
BAT_THEME environment variable (e.g.: export \
|
||||
BAT_THEME=\"...\").",
|
||||
),
|
||||
)
|
||||
.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")
|
||||
// Need to turn this off for overrides_with to work as we want. See the bottom most
|
||||
// example at https://docs.rs/clap/2.32.0/clap/struct.Arg.html#method.overrides_with
|
||||
.use_delimiter(false)
|
||||
.takes_value(true)
|
||||
.overrides_with("style")
|
||||
.overrides_with("plain")
|
||||
.overrides_with("number")
|
||||
// Cannot use clap's built in validation because we have to turn off clap's delimiters
|
||||
.validator(|val| {
|
||||
let mut invalid_vals = val.split(",").filter(|style| {
|
||||
!&[
|
||||
"auto", "full", "plain", "changes", "header", "grid", "numbers",
|
||||
]
|
||||
.contains(style)
|
||||
});
|
||||
|
||||
if let Some(invalid) = invalid_vals.next() {
|
||||
Err(format!("Unknown style, '{}'", invalid))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
.help(
|
||||
"Comma-separated list of style elements to display \
|
||||
(*auto*, full, plain, changes, header, grid, numbers).",
|
||||
)
|
||||
.long_help(
|
||||
"Configure which elements (line numbers, file headers, grid \
|
||||
borders, Git modifications, ..) to display in addition to the \
|
||||
file contents. The argument is a comma-separated list of \
|
||||
components to display (e.g. 'numbers,changes,grid') or a \
|
||||
pre-defined style ('full'). To set a default style, add the \
|
||||
'--style=\"..\"' option to the configuration file or export the \
|
||||
BAT_STYLE environment variable (e.g.: export BAT_STYLE=\"..\"). \
|
||||
Possible values: *auto*, full, plain, changes, header, grid, numbers.",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("plain")
|
||||
.overrides_with("plain")
|
||||
.overrides_with("number")
|
||||
.short("p")
|
||||
.long("plain")
|
||||
.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")
|
||||
.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("show-all")
|
||||
.long("show-all")
|
||||
.alias("show-nonprintable")
|
||||
.short("A")
|
||||
.conflicts_with("language")
|
||||
.help("Show non-printable characters (space, tab, newline, ..).")
|
||||
.long_help(
|
||||
"Show non-printable characters like space, tab or newline. \
|
||||
Use '--tabs' to control the width of the tab-placeholders.",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("line-range")
|
||||
.long("line-range")
|
||||
.short("r")
|
||||
.multiple(true)
|
||||
.takes_value(true)
|
||||
.number_of_values(1)
|
||||
.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("highlight-line")
|
||||
.long("highlight-line")
|
||||
.short("H")
|
||||
.takes_value(true)
|
||||
.number_of_values(1)
|
||||
.multiple(true)
|
||||
.value_name("N")
|
||||
.help("Highlight the given line.")
|
||||
.long_help(
|
||||
"Highlight the N-th line with a different background color",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("color")
|
||||
.long("color")
|
||||
.overrides_with("color")
|
||||
.takes_value(true)
|
||||
.value_name("when")
|
||||
.possible_values(&["auto", "never", "always"])
|
||||
.hide_default_value(true)
|
||||
.default_value("auto")
|
||||
.help("When to use colors (*auto*, never, always).")
|
||||
.long_help(
|
||||
"Specify when to use colored output. The automatic mode \
|
||||
only enables colors if an interactive terminal is detected. \
|
||||
Possible values: *auto*, never, always.",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("italic-text")
|
||||
.long("italic-text")
|
||||
.takes_value(true)
|
||||
.value_name("when")
|
||||
.possible_values(&["always", "never"])
|
||||
.default_value("never")
|
||||
.hide_default_value(true)
|
||||
.help("Use italics in output (always, *never*)")
|
||||
.long_help("Specify when to use ANSI sequences for italic text in the output. Possible values: always, *never*."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("decorations")
|
||||
.long("decorations")
|
||||
.overrides_with("decorations")
|
||||
.takes_value(true)
|
||||
.value_name("when")
|
||||
.possible_values(&["auto", "never", "always"])
|
||||
.default_value("auto")
|
||||
.hide_default_value(true)
|
||||
.help("When to show the decorations (*auto*, never, always).")
|
||||
.long_help(
|
||||
"Specify when to use the decorations that have been specified \
|
||||
via '--style'. The automatic mode only enables decorations if \
|
||||
an interactive terminal is detected. Possible values: *auto*, never, always.",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("paging")
|
||||
.long("paging")
|
||||
.overrides_with("paging")
|
||||
.takes_value(true)
|
||||
.value_name("when")
|
||||
.possible_values(&["auto", "never", "always"])
|
||||
.default_value("auto")
|
||||
.hide_default_value(true)
|
||||
.help("Specify when to use the pager (*auto*, never, always).")
|
||||
.long_help(
|
||||
"Specify when to use the pager. To control which pager \
|
||||
is used, set the PAGER or BAT_PAGER environment \
|
||||
variables (the latter takes precedence) or use the '--pager' option. \
|
||||
To disable the pager permanently, set BAT_PAGER to an empty string \
|
||||
or set '--paging=never' in the configuration file. \
|
||||
Possible values: *auto*, never, always.",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("pager")
|
||||
.long("pager")
|
||||
.overrides_with("pager")
|
||||
.takes_value(true)
|
||||
.value_name("command")
|
||||
.hidden_short_help(true)
|
||||
.help("Determine which pager to use.")
|
||||
.long_help(
|
||||
"Determine which pager is used. This option will overwrite \
|
||||
the PAGER and BAT_PAGER environment variables. The default \
|
||||
pager is 'less'. To disable the pager completely, use the \
|
||||
'--paging' option. \
|
||||
Example: '--pager \"less -RF\"'.",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("wrap")
|
||||
.long("wrap")
|
||||
.overrides_with("wrap")
|
||||
.takes_value(true)
|
||||
.value_name("mode")
|
||||
.possible_values(&["auto", "never", "character"])
|
||||
.default_value("auto")
|
||||
.hide_default_value(true)
|
||||
.help("Specify the text-wrapping mode (*auto*, never, character).")
|
||||
.long_help("Specify the text-wrapping mode (*auto*, never, character)."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("tabs")
|
||||
.long("tabs")
|
||||
.overrides_with("tabs")
|
||||
.takes_value(true)
|
||||
.value_name("T")
|
||||
.validator(
|
||||
|t| {
|
||||
t.parse::<u32>()
|
||||
.map_err(|_t| "must be a number")
|
||||
.map(|_t| ()) // Convert to Result<(), &str>
|
||||
.map_err(|e| e.to_string())
|
||||
}, // Convert to Result<(), String>
|
||||
)
|
||||
.help("Set the tab width to T spaces.")
|
||||
.long_help(
|
||||
"Set the tab width to T spaces. Use a width of 0 to pass tabs through \
|
||||
directly",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("unbuffered")
|
||||
.short("u")
|
||||
.long("unbuffered")
|
||||
.hidden_short_help(true)
|
||||
.long_help(
|
||||
"This option exists for POSIX-compliance reasons ('u' is for \
|
||||
'unbuffered'). The output is always unbuffered - this option \
|
||||
is simply ignored.",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("terminal-width")
|
||||
.long("terminal-width")
|
||||
.takes_value(true)
|
||||
.value_name("width")
|
||||
.hidden_short_help(true)
|
||||
.help(
|
||||
"Explicitly set the width of the terminal instead of determining it \
|
||||
automatically. If prefixed with '+' or '-', the value will be treated \
|
||||
as an offset to the actual terminal width.",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("no-config")
|
||||
.long("no-config")
|
||||
.hidden(true)
|
||||
.help("Do not use the configuration file"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("config-file")
|
||||
.long("config-file")
|
||||
.conflicts_with("list-languages")
|
||||
.conflicts_with("list-themes")
|
||||
.hidden(true)
|
||||
.help("Show path to the configuration file."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("config-dir")
|
||||
.long("config-dir")
|
||||
.hidden(true)
|
||||
.help("Show bat's configuration directory."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("cache-dir")
|
||||
.long("cache-dir")
|
||||
.hidden(true)
|
||||
.help("Show bat's cache directory."),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("cache")
|
||||
.about("Modify the syntax-definition and theme cache")
|
||||
.arg(
|
||||
Arg::with_name("build")
|
||||
.long("build")
|
||||
.short("b")
|
||||
.help("Initialize (or update) the syntax/theme cache.")
|
||||
.long_help(
|
||||
"Initialize (or update) 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."),
|
||||
)
|
||||
.group(
|
||||
ArgGroup::with_name("cache-actions")
|
||||
.args(&["build", "clear"])
|
||||
.required(arg_group_required),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("source")
|
||||
.long("source")
|
||||
.requires("build")
|
||||
.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("build")
|
||||
.takes_value(true)
|
||||
.value_name("dir")
|
||||
.help(
|
||||
"Use a different directory to store the cached syntax and theme set.",
|
||||
),
|
||||
)
|
||||
.arg(Arg::with_name("blank").long("blank").requires("build").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.")
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use shell_words;
|
||||
|
||||
use dirs::PROJECT_DIRS;
|
||||
use util::transpose;
|
||||
|
||||
pub fn config_file() -> PathBuf {
|
||||
env::var("BAT_CONFIG_PATH")
|
||||
.ok()
|
||||
.map(PathBuf::from)
|
||||
.filter(|config_path| config_path.is_file())
|
||||
.unwrap_or(PROJECT_DIRS.config_dir().join("config"))
|
||||
}
|
||||
|
||||
pub fn get_args_from_config_file() -> Result<Vec<OsString>, shell_words::ParseError> {
|
||||
Ok(transpose(
|
||||
fs::read_to_string(config_file())
|
||||
.ok()
|
||||
.map(|content| get_args_from_str(&content)),
|
||||
)?
|
||||
.unwrap_or(vec![]))
|
||||
}
|
||||
|
||||
pub fn get_args_from_env_var() -> Option<Result<Vec<OsString>, shell_words::ParseError>> {
|
||||
env::var("BAT_OPTS").ok().map(|s| get_args_from_str(&s))
|
||||
}
|
||||
|
||||
fn get_args_from_str<'a>(content: &'a str) -> Result<Vec<OsString>, shell_words::ParseError> {
|
||||
let args_per_line = content
|
||||
.split('\n')
|
||||
.map(|line| line.trim())
|
||||
.filter(|line| !line.is_empty())
|
||||
.filter(|line| !line.starts_with("#"))
|
||||
.map(|line| shell_words::split(line))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
Ok(args_per_line
|
||||
.iter()
|
||||
.flatten()
|
||||
.map(|line| line.into())
|
||||
.collect())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty() {
|
||||
let args = get_args_from_str("").unwrap();
|
||||
assert!(args.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single() {
|
||||
assert_eq!(vec!["--plain"], get_args_from_str("--plain").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple() {
|
||||
assert_eq!(
|
||||
vec!["--plain", "--language=cpp"],
|
||||
get_args_from_str("--plain --language=cpp").unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn quotes() {
|
||||
assert_eq!(
|
||||
vec!["--theme", "Sublime Snazzy"],
|
||||
get_args_from_str("--theme \"Sublime Snazzy\"").unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_line() {
|
||||
let config = "
|
||||
-p
|
||||
--style numbers,changes
|
||||
|
||||
--color=always
|
||||
";
|
||||
assert_eq!(
|
||||
vec!["-p", "--style", "numbers,changes", "--color=always"],
|
||||
get_args_from_str(config).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn comments() {
|
||||
let config = "
|
||||
# plain style
|
||||
-p
|
||||
|
||||
# show line numbers and Git modifications
|
||||
--style numbers,changes
|
||||
|
||||
# Always show ANSI colors
|
||||
--color=always
|
||||
";
|
||||
assert_eq!(
|
||||
vec!["-p", "--style", "numbers,changes", "--color=always"],
|
||||
get_args_from_str(config).unwrap()
|
||||
);
|
||||
}
|
||||
+69
-53
@@ -1,15 +1,14 @@
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufRead, BufReader, Write};
|
||||
use std::io::{self, Write};
|
||||
use std::path::Path;
|
||||
|
||||
use app::{Config, InputFile};
|
||||
use app::{Config, PagingMode};
|
||||
use assets::HighlightingAssets;
|
||||
use errors::*;
|
||||
use line_range::LineRange;
|
||||
use inputfile::{InputFile, InputFileReader};
|
||||
use line_range::{LineRanges, RangeCheckResult};
|
||||
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,
|
||||
@@ -21,22 +20,53 @@ impl<'b> Controller<'b> {
|
||||
}
|
||||
|
||||
pub fn run(&self) -> Result<bool> {
|
||||
let mut output_type = OutputType::from_mode(self.config.paging_mode);
|
||||
// Do not launch the pager if NONE of the input files exist
|
||||
let mut paging_mode = self.config.paging_mode;
|
||||
if self.config.paging_mode != PagingMode::Never {
|
||||
let call_pager = self.config.files.iter().any(|file| {
|
||||
if let InputFile::Ordinary(path) = file {
|
||||
return Path::new(path).exists();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if !call_pager {
|
||||
paging_mode = PagingMode::Never;
|
||||
}
|
||||
}
|
||||
|
||||
let mut output_type = OutputType::from_mode(paging_mode, self.config.pager)?;
|
||||
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)
|
||||
};
|
||||
let stdin = io::stdin();
|
||||
|
||||
if let Err(error) = result {
|
||||
handle_error(&error);
|
||||
no_errors = false;
|
||||
for input_file in &self.config.files {
|
||||
match input_file.get_reader(&stdin) {
|
||||
Err(Error(ErrorKind::ImmediateEOF, _)) => (),
|
||||
Err(error) => {
|
||||
handle_error(&error);
|
||||
no_errors = false;
|
||||
}
|
||||
Ok(mut reader) => {
|
||||
let result = if self.config.loop_through {
|
||||
let mut printer = SimplePrinter::new();
|
||||
self.print_file(reader, &mut printer, writer, *input_file)
|
||||
} else {
|
||||
let mut printer = InteractivePrinter::new(
|
||||
&self.config,
|
||||
&self.assets,
|
||||
*input_file,
|
||||
&mut reader,
|
||||
);
|
||||
self.print_file(reader, &mut printer, writer, *input_file)
|
||||
};
|
||||
|
||||
if let Err(error) = result {
|
||||
handle_error(&error);
|
||||
no_errors = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,22 +75,15 @@ impl<'b> Controller<'b> {
|
||||
|
||||
fn print_file<'a, P: Printer>(
|
||||
&self,
|
||||
reader: InputFileReader,
|
||||
printer: &mut P,
|
||||
writer: &mut Write,
|
||||
filename: InputFile<'a>,
|
||||
input_file: InputFile<'a>,
|
||||
) -> Result<()> {
|
||||
let stdin = io::stdin();
|
||||
{
|
||||
let reader: Box<BufRead> = match filename {
|
||||
InputFile::StdIn => Box::new(stdin.lock()),
|
||||
InputFile::Ordinary(filename) => Box::new(BufReader::new(File::open(filename)?)),
|
||||
InputFile::ThemePreviewFile => Box::new(THEME_PREVIEW_FILE),
|
||||
};
|
||||
printer.print_header(writer, input_file)?;
|
||||
self.print_file_ranges(printer, writer, reader, &self.config.line_ranges)?;
|
||||
printer.print_footer(writer)?;
|
||||
|
||||
printer.print_header(writer, filename)?;
|
||||
self.print_file_ranges(printer, writer, reader, &self.config.line_range)?;
|
||||
printer.print_footer(writer)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -68,35 +91,28 @@ impl<'b> Controller<'b> {
|
||||
&self,
|
||||
printer: &mut P,
|
||||
writer: &mut Write,
|
||||
mut reader: Box<BufRead + 'a>,
|
||||
line_ranges: &Option<LineRange>,
|
||||
mut reader: InputFileReader,
|
||||
line_ranges: &LineRanges,
|
||||
) -> 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)?;
|
||||
}
|
||||
while reader.read_line(&mut line_buffer)? {
|
||||
match line_ranges.check(line_number) {
|
||||
RangeCheckResult::OutsideRange => {
|
||||
// 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)?;
|
||||
}
|
||||
RangeCheckResult::InRange => {
|
||||
printer.print_line(false, writer, line_number, &line_buffer)?;
|
||||
}
|
||||
RangeCheckResult::AfterLastRange => {
|
||||
break;
|
||||
}
|
||||
|
||||
line_number += 1;
|
||||
}
|
||||
|
||||
line_number += 1;
|
||||
line_buffer.clear();
|
||||
}
|
||||
Ok(())
|
||||
|
||||
+8
-5
@@ -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);
|
||||
|
||||
@@ -31,7 +34,7 @@ pub fn get_git_diff(filename: &str) -> Option<LineChanges> {
|
||||
|
||||
let mark_section =
|
||||
|line_changes: &mut LineChanges, start: u32, end: i32, change: LineChange| {
|
||||
for line in start..(end + 1) as u32 {
|
||||
for line in start..=end as u32 {
|
||||
line_changes.insert(line, change);
|
||||
}
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
use dirs_rs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
use std::env;
|
||||
|
||||
/// Wrapper for 'dirs' that treats MacOS more like Linux, by following the XDG specification.
|
||||
/// This means that the `XDG_CACHE_HOME` and `XDG_CONFIG_HOME` environment variables are
|
||||
/// checked first. The fallback directories are `~/.cache/bat` and `~/.config/bat`, respectively.
|
||||
pub struct BatProjectDirs {
|
||||
cache_dir: PathBuf,
|
||||
config_dir: PathBuf,
|
||||
}
|
||||
|
||||
impl BatProjectDirs {
|
||||
fn new() -> Option<BatProjectDirs> {
|
||||
#[cfg(target_os = "macos")]
|
||||
let cache_dir_op = env::var_os("XDG_CACHE_HOME")
|
||||
.map(PathBuf::from)
|
||||
.filter(|p| p.is_absolute())
|
||||
.or_else(|| dirs_rs::home_dir().map(|d| d.join(".cache")));
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let cache_dir_op = dirs_rs::cache_dir();
|
||||
|
||||
let cache_dir = cache_dir_op.map(|d| d.join("bat"))?;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
let config_dir_op = env::var_os("XDG_CONFIG_HOME")
|
||||
.map(PathBuf::from)
|
||||
.filter(|p| p.is_absolute())
|
||||
.or_else(|| dirs_rs::home_dir().map(|d| d.join(".config")));
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let config_dir_op = dirs_rs::config_dir();
|
||||
|
||||
let config_dir = config_dir_op.map(|d| d.join("bat"))?;
|
||||
|
||||
Some(BatProjectDirs {
|
||||
cache_dir,
|
||||
config_dir,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn cache_dir(&self) -> &Path {
|
||||
&self.cache_dir
|
||||
}
|
||||
|
||||
pub fn config_dir(&self) -> &Path {
|
||||
&self.config_dir
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref PROJECT_DIRS: BatProjectDirs =
|
||||
BatProjectDirs::new().expect("Could not get home directory");
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufRead, BufReader};
|
||||
|
||||
use content_inspector::{self, ContentType};
|
||||
|
||||
use errors::*;
|
||||
|
||||
const THEME_PREVIEW_FILE: &[u8] = include_bytes!("../assets/theme_preview.rs");
|
||||
|
||||
pub struct InputFileReader<'a> {
|
||||
inner: Box<dyn BufRead + 'a>,
|
||||
pub first_line: Vec<u8>,
|
||||
pub content_type: ContentType,
|
||||
}
|
||||
|
||||
impl<'a> InputFileReader<'a> {
|
||||
fn new<R: BufRead + 'a>(mut reader: R) -> Result<InputFileReader<'a>> {
|
||||
let mut first_line = vec![];
|
||||
if reader.read_until(b'\n', &mut first_line)? == 0 {
|
||||
return Err(ErrorKind::ImmediateEOF.into());
|
||||
}
|
||||
|
||||
let content_type = content_inspector::inspect(&first_line[..]);
|
||||
|
||||
if content_type == ContentType::UTF_16LE {
|
||||
reader.read_until(0x00, &mut first_line).ok();
|
||||
}
|
||||
|
||||
Ok(InputFileReader {
|
||||
inner: Box::new(reader),
|
||||
first_line,
|
||||
content_type,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn read_line(&mut self, buf: &mut Vec<u8>) -> io::Result<bool> {
|
||||
if self.first_line.is_empty() {
|
||||
let res = self.inner.read_until(b'\n', buf).map(|size| size > 0)?;
|
||||
|
||||
if self.content_type == ContentType::UTF_16LE {
|
||||
self.inner.read_until(0x00, buf).ok();
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
} else {
|
||||
buf.append(&mut self.first_line);
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum InputFile<'a> {
|
||||
StdIn,
|
||||
Ordinary(&'a str),
|
||||
ThemePreviewFile,
|
||||
}
|
||||
|
||||
impl<'a> InputFile<'a> {
|
||||
pub fn get_reader(&self, stdin: &'a io::Stdin) -> Result<InputFileReader> {
|
||||
match self {
|
||||
InputFile::StdIn => InputFileReader::new(stdin.lock()),
|
||||
InputFile::Ordinary(filename) => {
|
||||
let file = File::open(filename).map_err(|e| format!("'{}': {}", filename, e))?;
|
||||
|
||||
if file.metadata()?.is_dir() {
|
||||
return Err(format!("'{}' is a directory.", filename).into());
|
||||
}
|
||||
|
||||
InputFileReader::new(BufReader::new(file))
|
||||
}
|
||||
InputFile::ThemePreviewFile => InputFileReader::new(THEME_PREVIEW_FILE),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
let content = b"#!/bin/bash\necho hello";
|
||||
let mut reader = InputFileReader::new(&content[..]).unwrap();
|
||||
|
||||
assert_eq!(b"#!/bin/bash\n", &reader.first_line[..]);
|
||||
|
||||
let mut buffer = vec![];
|
||||
|
||||
let res = reader.read_line(&mut buffer);
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(true, res.unwrap());
|
||||
assert_eq!(b"#!/bin/bash\n", &buffer[..]);
|
||||
|
||||
buffer.clear();
|
||||
|
||||
let res = reader.read_line(&mut buffer);
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(true, res.unwrap());
|
||||
assert_eq!(b"echo hello", &buffer[..]);
|
||||
|
||||
buffer.clear();
|
||||
|
||||
let res = reader.read_line(&mut buffer);
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(false, res.unwrap());
|
||||
assert!(buffer.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn utf16le() {
|
||||
let content = b"\xFF\xFE\x73\x00\x0A\x00\x64\x00";
|
||||
let mut reader = InputFileReader::new(&content[..]).unwrap();
|
||||
|
||||
assert_eq!(b"\xFF\xFE\x73\x00\x0A\x00", &reader.first_line[..]);
|
||||
|
||||
let mut buffer = vec![];
|
||||
|
||||
let res = reader.read_line(&mut buffer);
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(true, res.unwrap());
|
||||
assert_eq!(b"\xFF\xFE\x73\x00\x0A\x00", &buffer[..]);
|
||||
|
||||
buffer.clear();
|
||||
|
||||
let res = reader.read_line(&mut buffer);
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(true, res.unwrap());
|
||||
assert_eq!(b"\x64\x00", &buffer[..]);
|
||||
|
||||
buffer.clear();
|
||||
|
||||
let res = reader.read_line(&mut buffer);
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(false, res.unwrap());
|
||||
assert!(buffer.is_empty());
|
||||
}
|
||||
@@ -38,6 +38,10 @@ impl LineRange {
|
||||
|
||||
Err("expected single ':' character".into())
|
||||
}
|
||||
|
||||
pub fn is_inside(&self, line: usize) -> bool {
|
||||
line >= self.lower && line <= self.upper
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -72,3 +76,105 @@ fn test_parse_fail() {
|
||||
let range = LineRange::from("40");
|
||||
assert!(range.is_err());
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum RangeCheckResult {
|
||||
// Within one of the given ranges
|
||||
InRange,
|
||||
|
||||
// Before the first range or within two ranges
|
||||
OutsideRange,
|
||||
|
||||
// Line number is outside of all ranges and larger than the last range.
|
||||
AfterLastRange,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct LineRanges {
|
||||
ranges: Vec<LineRange>,
|
||||
largest_upper_bound: usize,
|
||||
}
|
||||
|
||||
impl LineRanges {
|
||||
pub fn from(ranges: Vec<LineRange>) -> LineRanges {
|
||||
let largest_upper_bound = ranges
|
||||
.iter()
|
||||
.map(|r| r.upper)
|
||||
.max()
|
||||
.unwrap_or(usize::max_value());
|
||||
LineRanges {
|
||||
ranges,
|
||||
largest_upper_bound,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check(&self, line: usize) -> RangeCheckResult {
|
||||
if self.ranges.is_empty() {
|
||||
RangeCheckResult::InRange
|
||||
} else {
|
||||
if self.ranges.iter().any(|r| r.is_inside(line)) {
|
||||
RangeCheckResult::InRange
|
||||
} else {
|
||||
if line < self.largest_upper_bound {
|
||||
RangeCheckResult::OutsideRange
|
||||
} else {
|
||||
RangeCheckResult::AfterLastRange
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn ranges(rs: &[&str]) -> LineRanges {
|
||||
LineRanges::from(rs.iter().map(|r| LineRange::from(r).unwrap()).collect())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ranges_simple() {
|
||||
let ranges = ranges(&["3:8"]);
|
||||
|
||||
assert_eq!(RangeCheckResult::OutsideRange, ranges.check(2));
|
||||
assert_eq!(RangeCheckResult::InRange, ranges.check(5));
|
||||
assert_eq!(RangeCheckResult::AfterLastRange, ranges.check(9));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ranges_advanced() {
|
||||
let ranges = ranges(&["3:8", "11:20", "25:30"]);
|
||||
|
||||
assert_eq!(RangeCheckResult::OutsideRange, ranges.check(2));
|
||||
assert_eq!(RangeCheckResult::InRange, ranges.check(5));
|
||||
assert_eq!(RangeCheckResult::OutsideRange, ranges.check(9));
|
||||
assert_eq!(RangeCheckResult::InRange, ranges.check(11));
|
||||
assert_eq!(RangeCheckResult::OutsideRange, ranges.check(22));
|
||||
assert_eq!(RangeCheckResult::InRange, ranges.check(28));
|
||||
assert_eq!(RangeCheckResult::AfterLastRange, ranges.check(31));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ranges_open_low() {
|
||||
let ranges = ranges(&["3:8", ":5"]);
|
||||
|
||||
assert_eq!(RangeCheckResult::InRange, ranges.check(1));
|
||||
assert_eq!(RangeCheckResult::InRange, ranges.check(3));
|
||||
assert_eq!(RangeCheckResult::InRange, ranges.check(7));
|
||||
assert_eq!(RangeCheckResult::AfterLastRange, ranges.check(9));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ranges_open_high() {
|
||||
let ranges = ranges(&["3:", "2:5"]);
|
||||
|
||||
assert_eq!(RangeCheckResult::OutsideRange, ranges.check(1));
|
||||
assert_eq!(RangeCheckResult::InRange, ranges.check(3));
|
||||
assert_eq!(RangeCheckResult::InRange, ranges.check(5));
|
||||
assert_eq!(RangeCheckResult::InRange, ranges.check(9));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ranges_empty() {
|
||||
let ranges = ranges(&[]);
|
||||
|
||||
assert_eq!(RangeCheckResult::InRange, ranges.check(1));
|
||||
}
|
||||
+97
-29
@@ -13,32 +13,46 @@ extern crate lazy_static;
|
||||
extern crate ansi_term;
|
||||
extern crate atty;
|
||||
extern crate console;
|
||||
extern crate directories;
|
||||
extern crate content_inspector;
|
||||
extern crate dirs as dirs_rs;
|
||||
extern crate encoding;
|
||||
extern crate git2;
|
||||
extern crate shell_words;
|
||||
extern crate syntect;
|
||||
extern crate wild;
|
||||
|
||||
mod app;
|
||||
mod assets;
|
||||
mod clap_app;
|
||||
mod config;
|
||||
mod controller;
|
||||
mod decorations;
|
||||
mod diff;
|
||||
mod dirs;
|
||||
mod inputfile;
|
||||
mod line_range;
|
||||
mod output;
|
||||
mod preprocessor;
|
||||
mod printer;
|
||||
mod style;
|
||||
mod syntax_mapping;
|
||||
mod terminal;
|
||||
mod util;
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::io;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::process;
|
||||
|
||||
use ansi_term::Colour::Green;
|
||||
use ansi_term::Style;
|
||||
|
||||
use app::{App, Config, InputFile};
|
||||
use assets::{clear_assets, config_dir, HighlightingAssets};
|
||||
use app::{App, Config};
|
||||
use assets::{cache_dir, clear_assets, config_dir, HighlightingAssets};
|
||||
use config::config_file;
|
||||
use controller::Controller;
|
||||
use inputfile::InputFile;
|
||||
use style::{OutputComponent, OutputComponents};
|
||||
|
||||
mod errors {
|
||||
@@ -49,6 +63,9 @@ mod errors {
|
||||
SyntectError(::syntect::LoadingError);
|
||||
ParseIntError(::std::num::ParseIntError);
|
||||
}
|
||||
errors {
|
||||
ImmediateEOF
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_error(error: &Error) {
|
||||
@@ -69,7 +86,7 @@ mod errors {
|
||||
use errors::*;
|
||||
|
||||
fn run_cache_subcommand(matches: &clap::ArgMatches) -> Result<()> {
|
||||
if matches.is_present("init") {
|
||||
if matches.is_present("build") {
|
||||
let source_dir = matches.value_of("source").map(Path::new);
|
||||
let target_dir = matches.value_of("target").map(Path::new);
|
||||
|
||||
@@ -79,14 +96,13 @@ fn run_cache_subcommand(matches: &clap::ArgMatches) -> Result<()> {
|
||||
assets.save(target_dir)?;
|
||||
} else if matches.is_present("clear") {
|
||||
clear_assets();
|
||||
} else if matches.is_present("config-dir") {
|
||||
println!("{}", config_dir());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn list_languages(assets: &HighlightingAssets, term_width: usize) {
|
||||
pub fn list_languages(config: &Config) -> Result<()> {
|
||||
let assets = HighlightingAssets::new();
|
||||
let mut languages = assets
|
||||
.syntax_set
|
||||
.syntaxes()
|
||||
@@ -104,10 +120,19 @@ pub fn list_languages(assets: &HighlightingAssets, term_width: usize) {
|
||||
let comma_separator = ", ";
|
||||
let separator = " ";
|
||||
// Line-wrapping for the possible file extension overflow.
|
||||
let desired_width = term_width - longest - separator.len();
|
||||
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 {
|
||||
print!("{:width$}{}", lang.name, separator, width = longest);
|
||||
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;
|
||||
@@ -118,59 +143,102 @@ pub fn list_languages(assets: &HighlightingAssets, term_width: usize) {
|
||||
let new_chars = word.len() + comma_separator.len();
|
||||
if num_chars + new_chars >= desired_width {
|
||||
num_chars = 0;
|
||||
print!("\n{:width$}{}", "", separator, width = longest);
|
||||
write!(stdout, "\n{:width$}{}", "", separator, width = longest)?;
|
||||
}
|
||||
|
||||
num_chars += new_chars;
|
||||
print!("{}", Green.paint(&word[..]));
|
||||
write!(stdout, "{}", style.paint(&word[..]))?;
|
||||
if extension.peek().is_some() {
|
||||
print!("{}", comma_separator);
|
||||
write!(stdout, "{}", comma_separator)?;
|
||||
}
|
||||
}
|
||||
println!();
|
||||
writeln!(stdout)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn list_themes(assets: &HighlightingAssets, cfg: &Config) {
|
||||
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);
|
||||
for (theme, _) in themes.iter() {
|
||||
println!("Theme: {}\n", Style::new().bold().paint(theme.to_string()));
|
||||
config.theme = theme.to_string();
|
||||
let _controller = Controller::new(&config, &assets).run();
|
||||
println!()
|
||||
|
||||
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(())
|
||||
}
|
||||
|
||||
/// Returns `Err(..)` upon fatal errors. Otherwise, returns `Some(true)` on full success and
|
||||
/// `Some(false)` if any intermediate errors occurred (were printed).
|
||||
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 `Ok(true)` on full success and
|
||||
/// `Ok(false)` if any intermediate errors occurred (were printed).
|
||||
fn run() -> Result<bool> {
|
||||
let app = App::new();
|
||||
let app = App::new()?;
|
||||
|
||||
match app.matches.subcommand() {
|
||||
("cache", Some(cache_matches)) => {
|
||||
run_cache_subcommand(cache_matches)?;
|
||||
Ok(true)
|
||||
// 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")];
|
||||
|
||||
run_controller(&config)
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let config = app.config()?;
|
||||
let assets = HighlightingAssets::new();
|
||||
|
||||
if app.matches.is_present("list-languages") {
|
||||
list_languages(&assets, config.term_width);
|
||||
list_languages(&config)?;
|
||||
|
||||
Ok(true)
|
||||
} else if app.matches.is_present("list-themes") {
|
||||
list_themes(&assets, &config);
|
||||
list_themes(&config)?;
|
||||
|
||||
Ok(true)
|
||||
} else if app.matches.is_present("config-file") {
|
||||
println!("{}", config_file().to_string_lossy());
|
||||
|
||||
Ok(true)
|
||||
} else if app.matches.is_present("config-dir") {
|
||||
writeln!(io::stdout(), "{}", config_dir())?;
|
||||
Ok(true)
|
||||
} else if app.matches.is_present("cache-dir") {
|
||||
writeln!(io::stdout(), "{}", cache_dir())?;
|
||||
Ok(true)
|
||||
} else {
|
||||
let controller = Controller::new(&config, &assets);
|
||||
controller.run()
|
||||
run_controller(&config)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+67
-24
@@ -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 shell_words;
|
||||
|
||||
use app::PagingMode;
|
||||
use errors::*;
|
||||
|
||||
@@ -11,39 +15,78 @@ pub enum OutputType {
|
||||
}
|
||||
|
||||
impl OutputType {
|
||||
pub fn from_mode(mode: PagingMode) -> Self {
|
||||
pub fn from_mode(mode: PagingMode, pager: Option<&str>) -> Result<Self> {
|
||||
use self::PagingMode::*;
|
||||
match mode {
|
||||
Always => OutputType::try_pager(false),
|
||||
QuitIfOneScreen => OutputType::try_pager(true),
|
||||
Ok(match mode {
|
||||
Always => OutputType::try_pager(false, pager)?,
|
||||
QuitIfOneScreen => OutputType::try_pager(true, pager)?,
|
||||
_ => OutputType::stdout(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Try to launch the pager. Fall back to stdout in case of errors.
|
||||
fn try_pager(quit_if_one_screen: bool) -> Self {
|
||||
let pager = env::var("BAT_PAGER")
|
||||
.or_else(|_| env::var("PAGER"))
|
||||
.unwrap_or(String::from("less"));
|
||||
fn try_pager(quit_if_one_screen: bool, pager_from_config: Option<&str>) -> Result<Self> {
|
||||
let mut replace_arguments_to_less = false;
|
||||
|
||||
let mut process = if pager == "less" {
|
||||
let mut args = vec!["--RAW-CONTROL-CHARS", "--no-init"];
|
||||
if quit_if_one_screen {
|
||||
args.push("--quit-if-one-screen");
|
||||
let pager_from_env = match (env::var("BAT_PAGER"), env::var("PAGER")) {
|
||||
(Ok(bat_pager), _) => Some(bat_pager),
|
||||
(_, Ok(pager)) => {
|
||||
// less needs to be called with the '-R' option in order to properly interpret the
|
||||
// ANSI color sequences printed by bat. If someone has set PAGER="less -F", we
|
||||
// therefore need to overwrite the arguments and add '-R'.
|
||||
//
|
||||
// We only do this for PAGER (as it is not specific to 'bat'), not for BAT_PAGER
|
||||
// or bats '--pager' command line option.
|
||||
replace_arguments_to_less = true;
|
||||
Some(pager)
|
||||
}
|
||||
|
||||
let mut p = Command::new("less");
|
||||
p.args(&args).env("LESSCHARSET", "UTF-8");
|
||||
p
|
||||
} else {
|
||||
Command::new(pager)
|
||||
_ => None,
|
||||
};
|
||||
|
||||
process
|
||||
.stdin(Stdio::piped())
|
||||
.spawn()
|
||||
.map(OutputType::Pager)
|
||||
.unwrap_or_else(|_| OutputType::stdout())
|
||||
let pager = pager_from_config
|
||||
.map(|p| p.to_string())
|
||||
.or(pager_from_env)
|
||||
.unwrap_or(String::from("less"));
|
||||
|
||||
let pagerflags =
|
||||
shell_words::split(&pager).chain_err(|| "Could not parse pager command.")?;
|
||||
|
||||
match pagerflags.split_first() {
|
||||
Some((pager_name, args)) => {
|
||||
let mut pager_path = PathBuf::from(pager_name);
|
||||
|
||||
if pager_path.file_stem() == Some(&OsString::from("bat")) {
|
||||
pager_path = PathBuf::from("less");
|
||||
}
|
||||
|
||||
let is_less = pager_path.file_stem() == Some(&OsString::from("less"));
|
||||
|
||||
let mut process = if is_less {
|
||||
let mut p = Command::new(&pager_path);
|
||||
if args.is_empty() || replace_arguments_to_less {
|
||||
p.args(vec!["--RAW-CONTROL-CHARS", "--no-init"]);
|
||||
if quit_if_one_screen {
|
||||
p.arg("--quit-if-one-screen");
|
||||
}
|
||||
} else {
|
||||
p.args(args);
|
||||
}
|
||||
p.env("LESSCHARSET", "UTF-8");
|
||||
p
|
||||
} else {
|
||||
let mut p = Command::new(&pager_path);
|
||||
p.args(args);
|
||||
p
|
||||
};
|
||||
|
||||
Ok(process
|
||||
.stdin(Stdio::piped())
|
||||
.spawn()
|
||||
.map(OutputType::Pager)
|
||||
.unwrap_or_else(|_| OutputType::stdout()))
|
||||
}
|
||||
None => Ok(OutputType::stdout()),
|
||||
}
|
||||
}
|
||||
|
||||
fn stdout() -> Self {
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
use console::AnsiCodeIterator;
|
||||
|
||||
/// Expand tabs like an ANSI-enabled expand(1).
|
||||
pub fn expand_tabs(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
|
||||
}
|
||||
|
||||
pub fn replace_nonprintable(input: &str, tab_width: usize) -> String {
|
||||
let mut output = String::new();
|
||||
|
||||
let tab_width = if tab_width == 0 { 4 } else { tab_width };
|
||||
|
||||
for chr in input.chars() {
|
||||
match chr {
|
||||
// space
|
||||
' ' => output.push('•'),
|
||||
// tab
|
||||
'\t' => {
|
||||
if tab_width == 1 {
|
||||
output.push('↹');
|
||||
} else {
|
||||
output.push('├');
|
||||
output.push_str(&"─".repeat(tab_width - 2));
|
||||
output.push('┤');
|
||||
}
|
||||
}
|
||||
// line feed
|
||||
'\x0A' => output.push('␊'),
|
||||
// carriage return
|
||||
'\x0D' => output.push('␍'),
|
||||
// null
|
||||
'\x00' => output.push('␀'),
|
||||
// bell
|
||||
'\x07' => output.push('␇'),
|
||||
// backspace
|
||||
'\x08' => output.push('␈'),
|
||||
// escape
|
||||
'\x1B' => output.push('␛'),
|
||||
// anything else
|
||||
_ => output.push(chr),
|
||||
}
|
||||
}
|
||||
|
||||
output
|
||||
}
|
||||
+165
-31
@@ -1,4 +1,3 @@
|
||||
use std::boxed::Box;
|
||||
use std::io::Write;
|
||||
use std::vec::Vec;
|
||||
|
||||
@@ -8,14 +7,23 @@ use ansi_term::Style;
|
||||
use console::AnsiCodeIterator;
|
||||
|
||||
use syntect::easy::HighlightLines;
|
||||
use syntect::highlighting::Color;
|
||||
use syntect::highlighting::Theme;
|
||||
use syntect::parsing::SyntaxSet;
|
||||
|
||||
use app::{Config, InputFile};
|
||||
use content_inspector::ContentType;
|
||||
|
||||
use encoding::all::{UTF_16BE, UTF_16LE};
|
||||
use encoding::{DecoderTrap, Encoding};
|
||||
|
||||
use app::Config;
|
||||
use assets::HighlightingAssets;
|
||||
use decorations::{Decoration, GridBorderDecoration, LineChangesDecoration, LineNumberDecoration};
|
||||
use diff::get_git_diff;
|
||||
use diff::LineChanges;
|
||||
use errors::*;
|
||||
use inputfile::{InputFile, InputFileReader};
|
||||
use preprocessor::{expand_tabs, replace_nonprintable};
|
||||
use style::OutputWrap;
|
||||
use terminal::{as_terminal_escaped, to_ansi_color};
|
||||
|
||||
@@ -65,17 +73,27 @@ impl Printer for SimplePrinter {
|
||||
pub struct InteractivePrinter<'a> {
|
||||
colors: Colors,
|
||||
config: &'a Config<'a>,
|
||||
decorations: Vec<Box<Decoration>>,
|
||||
decorations: Vec<Box<dyn Decoration>>,
|
||||
panel_width: usize,
|
||||
ansi_prefix_sgr: String,
|
||||
content_type: ContentType,
|
||||
pub line_changes: Option<LineChanges>,
|
||||
highlighter: HighlightLines<'a>,
|
||||
highlighter: Option<HighlightLines<'a>>,
|
||||
syntax_set: &'a SyntaxSet,
|
||||
background_color_highlight: Option<Color>,
|
||||
}
|
||||
|
||||
impl<'a> InteractivePrinter<'a> {
|
||||
pub fn new(config: &'a Config, assets: &'a HighlightingAssets, file: InputFile) -> Self {
|
||||
pub fn new(
|
||||
config: &'a Config,
|
||||
assets: &'a HighlightingAssets,
|
||||
file: InputFile,
|
||||
reader: &mut InputFileReader,
|
||||
) -> Self {
|
||||
let theme = assets.get_theme(&config.theme);
|
||||
|
||||
let background_color_highlight = theme.settings.line_highlight;
|
||||
|
||||
let colors = if config.colored_output {
|
||||
Colors::colored(theme, config.true_color)
|
||||
} else {
|
||||
@@ -83,7 +101,7 @@ impl<'a> InteractivePrinter<'a> {
|
||||
};
|
||||
|
||||
// Create decorations.
|
||||
let mut decorations: Vec<Box<Decoration>> = Vec::new();
|
||||
let mut decorations: Vec<Box<dyn Decoration>> = Vec::new();
|
||||
|
||||
if config.output_components.numbers() {
|
||||
decorations.push(Box::new(LineNumberDecoration::new(&colors)));
|
||||
@@ -112,24 +130,37 @@ impl<'a> InteractivePrinter<'a> {
|
||||
panel_width = 0;
|
||||
}
|
||||
|
||||
// Get the Git modifications
|
||||
let line_changes = match file {
|
||||
InputFile::Ordinary(filename) => get_git_diff(filename),
|
||||
_ => None,
|
||||
};
|
||||
let mut line_changes = None;
|
||||
|
||||
// Determine the type of syntax for highlighting
|
||||
let syntax = assets.get_syntax(config.language, file);
|
||||
let highlighter = HighlightLines::new(syntax, theme);
|
||||
let highlighter = if reader.content_type.is_binary() {
|
||||
None
|
||||
} else {
|
||||
// Get the Git modifications
|
||||
line_changes = if config.output_components.changes() {
|
||||
match file {
|
||||
InputFile::Ordinary(filename) => get_git_diff(filename),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Determine the type of syntax for highlighting
|
||||
let syntax = assets.get_syntax(config.language, file, reader, &config.syntax_mapping);
|
||||
Some(HighlightLines::new(syntax, theme))
|
||||
};
|
||||
|
||||
InteractivePrinter {
|
||||
panel_width,
|
||||
colors,
|
||||
config,
|
||||
decorations,
|
||||
content_type: reader.content_type,
|
||||
ansi_prefix_sgr: String::new(),
|
||||
line_changes,
|
||||
highlighter,
|
||||
syntax_set: &assets.syntax_set,
|
||||
background_color_highlight,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,6 +179,14 @@ impl<'a> InteractivePrinter<'a> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn preprocess(&self, text: &str, cursor: &mut usize) -> String {
|
||||
if self.config.tab_width > 0 {
|
||||
expand_tabs(text, self.config.tab_width, cursor)
|
||||
} else {
|
||||
text.to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Printer for InteractivePrinter<'a> {
|
||||
@@ -176,17 +215,34 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
||||
_ => ("", "STDIN"),
|
||||
};
|
||||
|
||||
writeln!(handle, "{}{}", prefix, self.colors.filename.paint(name))?;
|
||||
let mode = match self.content_type {
|
||||
ContentType::BINARY => " <BINARY>",
|
||||
ContentType::UTF_16LE => " <UTF-16LE>",
|
||||
ContentType::UTF_16BE => " <UTF-16BE>",
|
||||
_ => "",
|
||||
};
|
||||
|
||||
writeln!(
|
||||
handle,
|
||||
"{}{}{}",
|
||||
prefix,
|
||||
self.colors.filename.paint(name),
|
||||
mode
|
||||
)?;
|
||||
|
||||
if self.config.output_components.grid() {
|
||||
self.print_horizontal_line(handle, '┼')?;
|
||||
if self.content_type.is_text() {
|
||||
self.print_horizontal_line(handle, '┼')?;
|
||||
} else {
|
||||
self.print_horizontal_line(handle, '┴')?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_footer(&mut self, handle: &mut Write) -> Result<()> {
|
||||
if self.config.output_components.grid() {
|
||||
if self.config.output_components.grid() && self.content_type.is_text() {
|
||||
self.print_horizontal_line(handle, '┴')
|
||||
} else {
|
||||
Ok(())
|
||||
@@ -200,8 +256,32 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
||||
line_number: usize,
|
||||
line_buffer: &[u8],
|
||||
) -> Result<()> {
|
||||
let line = String::from_utf8_lossy(&line_buffer);
|
||||
let regions = self.highlighter.highlight(line.as_ref());
|
||||
let mut line = match self.content_type {
|
||||
ContentType::BINARY => {
|
||||
return Ok(());
|
||||
}
|
||||
ContentType::UTF_16LE => UTF_16LE
|
||||
.decode(&line_buffer, DecoderTrap::Strict)
|
||||
.unwrap_or("Invalid UTF-16LE".into()),
|
||||
ContentType::UTF_16BE => UTF_16BE
|
||||
.decode(&line_buffer, DecoderTrap::Strict)
|
||||
.unwrap_or("Invalid UTF-16BE".into()),
|
||||
_ => String::from_utf8_lossy(&line_buffer).to_string(),
|
||||
};
|
||||
|
||||
if self.config.show_nonprintable {
|
||||
line = replace_nonprintable(&mut line, self.config.tab_width);
|
||||
}
|
||||
|
||||
let regions = {
|
||||
let highlighter = match self.highlighter {
|
||||
Some(ref mut highlighter) => highlighter,
|
||||
_ => {
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
highlighter.highlight(line.as_ref(), self.syntax_set)
|
||||
};
|
||||
|
||||
if out_of_range {
|
||||
return Ok(());
|
||||
@@ -209,8 +289,20 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
||||
|
||||
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 highlighting
|
||||
let highlight_this_line = self
|
||||
.config
|
||||
.highlight_lines
|
||||
.iter()
|
||||
.any(|&l| l == line_number);
|
||||
|
||||
let background_color = self
|
||||
.background_color_highlight
|
||||
.filter(|_| highlight_this_line);
|
||||
|
||||
// Line decorations.
|
||||
if self.panel_width > 0 {
|
||||
let decorations = self
|
||||
@@ -229,20 +321,42 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
||||
if self.config.output_wrap == OutputWrap::None {
|
||||
let true_color = self.config.true_color;
|
||||
let colored_output = self.config.colored_output;
|
||||
let italics = self.config.use_italic_text;
|
||||
|
||||
write!(
|
||||
handle,
|
||||
"{}",
|
||||
regions
|
||||
.iter()
|
||||
.map(|&(style, text)| as_terminal_escaped(
|
||||
for &(style, region) in regions.iter() {
|
||||
let text = &*self.preprocess(region, &mut cursor_total);
|
||||
let text_trimmed = text.trim_end_matches(|c| c == '\r' || c == '\n');
|
||||
write!(
|
||||
handle,
|
||||
"{}",
|
||||
as_terminal_escaped(
|
||||
style,
|
||||
text,
|
||||
text_trimmed,
|
||||
true_color,
|
||||
colored_output,
|
||||
)).collect::<Vec<_>>()
|
||||
.join("")
|
||||
)?;
|
||||
italics,
|
||||
background_color
|
||||
)
|
||||
)?;
|
||||
|
||||
if text.len() != text_trimmed.len() {
|
||||
if let Some(background_color) = background_color {
|
||||
let mut ansi_style = Style::default();
|
||||
ansi_style.background = Some(to_ansi_color(background_color, true_color));
|
||||
let width = if cursor_total <= cursor_max {
|
||||
cursor_max - cursor_total + 1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
write!(handle, "{}", ansi_style.paint(" ".repeat(width)))?;
|
||||
}
|
||||
write!(handle, "{}", &text[text_trimmed.len()..])?;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -265,7 +379,11 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
||||
|
||||
// Regular text.
|
||||
(text, false) => {
|
||||
let text = text.trim_right_matches(|c| c == '\r' || c == '\n');
|
||||
let text = self.preprocess(
|
||||
text.trim_end_matches(|c| c == '\r' || c == '\n'),
|
||||
&mut cursor_total,
|
||||
);
|
||||
|
||||
let mut chars = text.chars();
|
||||
let mut remaining = text.chars().count();
|
||||
|
||||
@@ -288,6 +406,8 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
||||
),
|
||||
self.config.true_color,
|
||||
self.config.colored_output,
|
||||
self.config.use_italic_text,
|
||||
background_color
|
||||
)
|
||||
)?;
|
||||
break;
|
||||
@@ -302,7 +422,8 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
||||
.iter()
|
||||
.map(|ref d| d
|
||||
.generate(line_number, true, self)
|
||||
.text).collect::<Vec<String>>()
|
||||
.text)
|
||||
.collect::<Vec<String>>()
|
||||
.join(" ")
|
||||
))
|
||||
} else {
|
||||
@@ -326,6 +447,8 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
||||
),
|
||||
self.config.true_color,
|
||||
self.config.colored_output,
|
||||
self.config.use_italic_text,
|
||||
background_color
|
||||
),
|
||||
panel_wrap.clone().unwrap()
|
||||
)?;
|
||||
@@ -338,6 +461,17 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(background_color) = background_color {
|
||||
let mut ansi_style = Style::default();
|
||||
ansi_style.background =
|
||||
Some(to_ansi_color(background_color, self.config.true_color));
|
||||
|
||||
write!(
|
||||
handle,
|
||||
"{}",
|
||||
ansi_style.paint(" ".repeat(cursor_max - cursor))
|
||||
)?;
|
||||
}
|
||||
write!(handle, "\n")?;
|
||||
}
|
||||
|
||||
|
||||
+13
-6
@@ -23,11 +23,13 @@ pub enum OutputWrap {
|
||||
impl OutputComponent {
|
||||
pub fn components(&self, interactive_terminal: bool) -> &'static [OutputComponent] {
|
||||
match *self {
|
||||
OutputComponent::Auto => if interactive_terminal {
|
||||
OutputComponent::Full.components(interactive_terminal)
|
||||
} else {
|
||||
OutputComponent::Plain.components(interactive_terminal)
|
||||
},
|
||||
OutputComponent::Auto => {
|
||||
if interactive_terminal {
|
||||
OutputComponent::Full.components(interactive_terminal)
|
||||
} else {
|
||||
OutputComponent::Plain.components(interactive_terminal)
|
||||
}
|
||||
}
|
||||
OutputComponent::Changes => &[OutputComponent::Changes],
|
||||
OutputComponent::Grid => &[OutputComponent::Grid],
|
||||
OutputComponent::Header => &[OutputComponent::Header],
|
||||
@@ -54,7 +56,8 @@ 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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,4 +81,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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SyntaxMapping(HashMap<String, String>);
|
||||
|
||||
impl SyntaxMapping {
|
||||
pub fn new() -> SyntaxMapping {
|
||||
SyntaxMapping(HashMap::new())
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, from: impl Into<String>, to: impl Into<String>) -> Option<String> {
|
||||
self.0.insert(from.into(), to.into())
|
||||
}
|
||||
|
||||
pub fn replace<'a>(&self, input: impl Into<Cow<'a, str>>) -> Cow<'a, str> {
|
||||
let input = input.into();
|
||||
match self.0.get(input.as_ref()) {
|
||||
Some(s) => Cow::from(s.clone()),
|
||||
None => input,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
let mut map = SyntaxMapping::new();
|
||||
map.insert("Cargo.lock", "toml");
|
||||
map.insert(".ignore", ".gitignore");
|
||||
|
||||
assert_eq!("toml", map.replace("Cargo.lock"));
|
||||
assert_eq!("other.lock", map.replace("other.lock"));
|
||||
|
||||
assert_eq!(".gitignore", map.replace(".ignore"));
|
||||
}
|
||||
+8
-46
@@ -1,32 +1,15 @@
|
||||
extern crate ansi_colours;
|
||||
|
||||
use ansi_term::Colour::{Fixed, RGB};
|
||||
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 {
|
||||
((r - 8) as u16 * 24 / 247) as u8 + 232
|
||||
}
|
||||
} else {
|
||||
36 * (r / 51) + 6 * (g / 51) + (b / 51) + 16
|
||||
}
|
||||
}
|
||||
|
||||
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 ansi_code = rgb2ansi(color.r, color.g, color.b);
|
||||
Fixed(ansi_code)
|
||||
Fixed(ansi_colours::ansi256_from_rgb((color.r, color.g, color.b)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +18,10 @@ pub fn as_terminal_escaped(
|
||||
text: &str,
|
||||
true_color: bool,
|
||||
colored: bool,
|
||||
italics: bool,
|
||||
background_color: Option<highlighting::Color>,
|
||||
) -> String {
|
||||
let style = if !colored {
|
||||
let mut style = if !colored {
|
||||
Style::default()
|
||||
} else {
|
||||
let color = to_ansi_color(style.foreground, true_color);
|
||||
@@ -45,36 +30,13 @@ pub fn as_terminal_escaped(
|
||||
color.bold()
|
||||
} else if style.font_style.contains(FontStyle::UNDERLINE) {
|
||||
color.underline()
|
||||
} else if style.font_style.contains(FontStyle::ITALIC) {
|
||||
} else if italics && style.font_style.contains(FontStyle::ITALIC) {
|
||||
color.italic()
|
||||
} else {
|
||||
color.normal()
|
||||
}
|
||||
};
|
||||
|
||||
style.background = background_color.map(|c| to_ansi_color(c, true_color));
|
||||
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));
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/// Helper function that might appear in Rust stable at some point
|
||||
/// (https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.transpose)
|
||||
pub fn transpose<T, E>(opt: Option<Result<T, E>>) -> Result<Option<T>, E> {
|
||||
opt.map_or(Ok(None), |res| res.map(Some))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::transpose;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct TestError;
|
||||
|
||||
type TestResult<T> = Result<T, TestError>;
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
let a: Option<TestResult<i32>> = Some(Ok(2));
|
||||
assert_eq!(Ok(Some(2)), transpose(a));
|
||||
|
||||
let b: Option<TestResult<i32>> = Some(Err(TestError));
|
||||
assert_eq!(Err(TestError), transpose(b));
|
||||
|
||||
let c: Option<TestResult<i32>> = None;
|
||||
assert_eq!(Ok(None), transpose(c));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
examples/* linguist-vendored
|
||||
snapshots/* linguist-vendored
|
||||
benchmarks/* linguist-vendored
|
||||
benchmarks/test-src/* linguist-vendored
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
test-src/* linguist-vendored
|
||||
Vendored
+2
@@ -10,6 +10,7 @@ SRC="test-src/jquery-3.3.1.js"
|
||||
|
||||
|
||||
cmd_bat="bat --style=full --color=always --paging=never '$SRC'"
|
||||
cmd_bat_simple="bat --plain --wrap=never --tabs=0 --color=always --paging=never '$SRC'"
|
||||
cmd_pygmentize="pygmentize -g '$SRC'"
|
||||
cmd_highlight="highlight -O truecolor '$SRC'"
|
||||
cmd_ccat="ccat --color=always '$SRC'"
|
||||
@@ -20,6 +21,7 @@ cmd_rouge="rougify '$SRC'"
|
||||
|
||||
hyperfine --warmup 3 \
|
||||
"$cmd_bat" \
|
||||
"$cmd_bat_simple" \
|
||||
"$cmd_pygmentize" \
|
||||
"$cmd_highlight" \
|
||||
"$cmd_ccat" \
|
||||
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
# Make sure that the pager gets executed
|
||||
--paging=always
|
||||
|
||||
# Output a dummy message for the integration test.
|
||||
--pager="echo dummy-pager-from-config"
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
line 1
|
||||
line 2
|
||||
line 3
|
||||
line 4
|
||||
Whitespace-only changes.
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
1 2 3 4
|
||||
1 ?
|
||||
22 ?
|
||||
333 ?
|
||||
4444 ?
|
||||
55555 ?
|
||||
666666 ?
|
||||
7777777 ?
|
||||
88888888 ?
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
hello world
|
||||
@@ -0,0 +1,365 @@
|
||||
extern crate assert_cmd;
|
||||
extern crate escargot;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
use assert_cmd::prelude::*;
|
||||
use escargot::CargoRun;
|
||||
use std::process::Command;
|
||||
|
||||
lazy_static! {
|
||||
static ref CARGO_RUN: CargoRun = escargot::CargoBuild::new()
|
||||
.bin("bat")
|
||||
.current_release()
|
||||
.run()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn bat_with_config() -> Command {
|
||||
let mut cmd = CARGO_RUN.command();
|
||||
cmd.current_dir("tests/examples");
|
||||
cmd.env_remove("PAGER");
|
||||
cmd.env_remove("BAT_PAGER");
|
||||
cmd.env_remove("BAT_CONFIG_PATH");
|
||||
cmd.env_remove("BAT_STYLE");
|
||||
cmd.env_remove("BAT_THEME");
|
||||
cmd.env_remove("BAT_TABS");
|
||||
cmd
|
||||
}
|
||||
|
||||
fn bat() -> Command {
|
||||
let mut cmd = bat_with_config();
|
||||
cmd.arg("--no-config");
|
||||
cmd
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
bat()
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("hello world\n")
|
||||
.stderr("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stdin() {
|
||||
bat()
|
||||
.with_stdin()
|
||||
.buffer("foo\nbar\n")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("foo\nbar\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn concatenate() {
|
||||
bat()
|
||||
.arg("test.txt")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("hello world\nhello world\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn concatenate_stdin() {
|
||||
bat()
|
||||
.arg("test.txt")
|
||||
.arg("-")
|
||||
.arg("test.txt")
|
||||
.with_stdin()
|
||||
.buffer("stdin\n")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("hello world\nstdin\nhello world\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn line_numbers() {
|
||||
bat()
|
||||
.arg("multiline.txt")
|
||||
.arg("--style=numbers")
|
||||
.arg("--decorations=always")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(" 1 line 1\n 2 line 2\n 3 line 3\n 4 line 4\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn line_range_2_3() {
|
||||
bat()
|
||||
.arg("multiline.txt")
|
||||
.arg("--line-range=2:3")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("line 2\nline 3\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn line_range_first_two() {
|
||||
bat()
|
||||
.arg("multiline.txt")
|
||||
.arg("--line-range=:2")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("line 1\nline 2\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn line_range_last_3() {
|
||||
bat()
|
||||
.arg("multiline.txt")
|
||||
.arg("--line-range=2:")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("line 2\nline 3\nline 4\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn line_range_multiple() {
|
||||
bat()
|
||||
.arg("multiline.txt")
|
||||
.arg("--line-range=1:2")
|
||||
.arg("--line-range=4:4")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("line 1\nline 2\nline 4\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tabs_numbers() {
|
||||
bat()
|
||||
.arg("tabs.txt")
|
||||
.arg("--tabs=4")
|
||||
.arg("--style=numbers")
|
||||
.arg("--decorations=always")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(
|
||||
" 1 1 2 3 4
|
||||
2 1 ?
|
||||
3 22 ?
|
||||
4 333 ?
|
||||
5 4444 ?
|
||||
6 55555 ?
|
||||
7 666666 ?
|
||||
8 7777777 ?
|
||||
9 88888888 ?
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tabs_passthrough_wrapped() {
|
||||
bat()
|
||||
.arg("tabs.txt")
|
||||
.arg("--tabs=0")
|
||||
.arg("--style=plain")
|
||||
.arg("--decorations=always")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(
|
||||
" 1 2 3 4
|
||||
1 ?
|
||||
22 ?
|
||||
333 ?
|
||||
4444 ?
|
||||
55555 ?
|
||||
666666 ?
|
||||
7777777 ?
|
||||
88888888 ?
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tabs_4_wrapped() {
|
||||
bat()
|
||||
.arg("tabs.txt")
|
||||
.arg("--tabs=4")
|
||||
.arg("--style=plain")
|
||||
.arg("--decorations=always")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(
|
||||
" 1 2 3 4
|
||||
1 ?
|
||||
22 ?
|
||||
333 ?
|
||||
4444 ?
|
||||
55555 ?
|
||||
666666 ?
|
||||
7777777 ?
|
||||
88888888 ?
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tabs_8_wrapped() {
|
||||
bat()
|
||||
.arg("tabs.txt")
|
||||
.arg("--tabs=8")
|
||||
.arg("--style=plain")
|
||||
.arg("--decorations=always")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(
|
||||
" 1 2 3 4
|
||||
1 ?
|
||||
22 ?
|
||||
333 ?
|
||||
4444 ?
|
||||
55555 ?
|
||||
666666 ?
|
||||
7777777 ?
|
||||
88888888 ?
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tabs_passthrough() {
|
||||
bat()
|
||||
.arg("tabs.txt")
|
||||
.arg("--tabs=0")
|
||||
.arg("--style=plain")
|
||||
.arg("--decorations=always")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(
|
||||
" 1 2 3 4
|
||||
1 ?
|
||||
22 ?
|
||||
333 ?
|
||||
4444 ?
|
||||
55555 ?
|
||||
666666 ?
|
||||
7777777 ?
|
||||
88888888 ?
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tabs_4() {
|
||||
bat()
|
||||
.arg("tabs.txt")
|
||||
.arg("--tabs=4")
|
||||
.arg("--style=plain")
|
||||
.arg("--decorations=always")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(
|
||||
" 1 2 3 4
|
||||
1 ?
|
||||
22 ?
|
||||
333 ?
|
||||
4444 ?
|
||||
55555 ?
|
||||
666666 ?
|
||||
7777777 ?
|
||||
88888888 ?
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tabs_8() {
|
||||
bat()
|
||||
.arg("tabs.txt")
|
||||
.arg("--tabs=8")
|
||||
.arg("--style=plain")
|
||||
.arg("--decorations=always")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(
|
||||
" 1 2 3 4
|
||||
1 ?
|
||||
22 ?
|
||||
333 ?
|
||||
4444 ?
|
||||
55555 ?
|
||||
666666 ?
|
||||
7777777 ?
|
||||
88888888 ?
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fail_non_existing() {
|
||||
bat().arg("non-existing-file").assert().failure();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fail_directory() {
|
||||
bat().arg("sub_directory").assert().failure();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn do_not_exit_directory() {
|
||||
bat()
|
||||
.arg("sub_directory")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.stdout("hello world\n")
|
||||
.failure();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pager_basic() {
|
||||
bat()
|
||||
.env("PAGER", "echo pager-output")
|
||||
.arg("--paging=always")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("pager-output\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pager_overwrite() {
|
||||
bat()
|
||||
.env("PAGER", "echo other-pager")
|
||||
.env("BAT_PAGER", "echo pager-output")
|
||||
.arg("--paging=always")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("pager-output\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pager_disable() {
|
||||
bat()
|
||||
.env("PAGER", "echo other-pager")
|
||||
.env("BAT_PAGER", "")
|
||||
.arg("--paging=always")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("hello world\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_location_test() {
|
||||
bat_with_config()
|
||||
.env("BAT_CONFIG_PATH", "bat.conf")
|
||||
.arg("--config-file")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("bat.conf\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_read_arguments_from_file() {
|
||||
bat_with_config()
|
||||
.env("BAT_CONFIG_PATH", "bat.conf")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("dummy-pager-from-config\n");
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
mod tester;
|
||||
|
||||
use tester::BatTester;
|
||||
|
||||
macro_rules! snapshot_tests {
|
||||
($($test_name: ident: $style: expr,)*) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $test_name() {
|
||||
let bat_tester = BatTester::new();
|
||||
bat_tester.test_snapshot(stringify!($test_name), $style);
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
snapshot_tests! {
|
||||
changes: "changes",
|
||||
grid: "grid",
|
||||
header: "header",
|
||||
numbers: "numbers",
|
||||
changes_grid: "changes,grid",
|
||||
changes_header: "changes,header",
|
||||
changes_numbers: "changes,numbers",
|
||||
grid_header: "grid,header",
|
||||
grid_numbers: "grid,numbers",
|
||||
header_numbers: "header,numbers",
|
||||
changes_grid_header: "changes,grid,header",
|
||||
changes_grid_numbers: "changes,grid,numbers",
|
||||
changes_header_numbers: "changes,header,numbers",
|
||||
grid_header_numbers: "grid,header,numbers",
|
||||
changes_grid_header_numbers: "changes,grid,header,numbers",
|
||||
full: "full",
|
||||
plain: "plain",
|
||||
}
|
||||
+20
-6
@@ -1,43 +1,57 @@
|
||||
#!/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
|
||||
|
||||
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()
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loaded 100 of 102 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user