Compare commits

..

36 Commits
4.0.1 ... 4.2.1

Author SHA1 Message Date
1eb44e8809 Merge pull request #621 from chrisallenlane/v4.2.1
Squashed commit of the following:
2021-04-28 12:55:17 -04:00
55b18b4897 Squashed commit of the following:
commit 95479c8ad744db48386a5c78e54ef8da80e9120b
Author: Chris Lane <chris@chris-allen-lane.com>
Date:   Wed Apr 28 12:26:32 2021 -0400

    chore(version): bump version to 4.2.1

commit 6956f51cae
Author: Chris Lane <chris@chris-allen-lane.com>
Date:   Wed Apr 28 12:24:21 2021 -0400

    fix(Makefile): `vendor-update`

    Update the `vendor-update` build target to run `go mod vendor` after
    updating dependencies.

commit 0aca411279
Author: Chris Lane <chris@chris-allen-lane.com>
Date:   Wed Apr 28 12:23:24 2021 -0400

    chore(deps): update dependencies

commit e847956b02
Author: Chris Lane <chris@chris-allen-lane.com>
Date:   Wed Apr 28 08:26:51 2021 -0400

    chore(deps): build updates

    - Upgrade `go` to `1.16.3`

    - Attempt to fix build errors regarding dependencies
2021-04-28 12:35:32 -04:00
883a17092f Merge pull request #606 from chrisallenlane/4.2.0
4.2.0
2020-11-28 11:27:09 -05:00
4f2a57fce8 fix(view): whitespace corrections
- Fix bug whereby `--all` flag would conflict with pager

- Fix whitespace inconsistencies among view and search outputs
2020-11-28 11:18:16 -05:00
ecc96c64f9 refactor(installer): externalize installer
Move installation-related code out of `main.go` and into a new
`installer.Run` method.
2020-11-28 10:32:37 -05:00
a81dd96ff4 fix: rename display.go
Rename `display.go` to `write.go`. (I forgot to do this previously.)
2020-11-27 23:05:02 -05:00
fb538baba5 chore(version): bump to 4.2.0 2020-11-27 22:57:25 -05:00
1a7b5c6127 feat(display): make Faint respect Colorize
Make `display.Faint` respect the `Colorize` config value.
2020-11-27 22:50:55 -05:00
cdddfbb516 chore: rename display.Display
Rename `display.Display` to `display.Write` for clarity and to reduce
"stutter".
2020-11-27 22:35:24 -05:00
4ef4c35d8c feat(search): search all cheatpaths
Update the search function. It now searches all cheatpaths all the time,
as if `--all` were implicitly passed.
2020-11-27 22:31:16 -05:00
a58294859e chore: spelling
`s/pathSheets/pathsheets/g` in `cmd_list` for consistency elsewhere.
2020-11-27 22:26:14 -05:00
606092e288 feat(search): improve search output formatting
Improve the search output formatting.
2020-11-27 17:06:02 -05:00
233a9de1aa feat: implement --all flag
Implement an `--all` flag that can be used to view cheatsheets on all
chaetpaths. (Resolves #548)
2020-11-27 16:39:34 -05:00
aa16f68620 feat(display): add methods to display
- Add `indent`, `faint`, and `underline` methods to `display`
- Add tests for the above
2020-11-27 16:14:33 -05:00
367673d5d9 chore(dependencies): update dependencies
Run `make vendor-update`.
2020-11-27 09:51:39 -05:00
08fb9e11a9 feat(Makefile): add vendor-update
Add `vendor-update` target to `Makefile`, which updates all dependencies
to their newest versions.
2020-11-27 09:50:11 -05:00
3f4d4bddb2 feat(tests): add unit-tests
Add unit-tests for `sheets.Load`.
2020-11-11 19:33:31 -05:00
6c6753b35c Merge pull request #599 from chrisallenlane/issue-597
fix: update installation instructions in README
2020-11-07 18:56:37 -05:00
0718b606e1 fix(README): clarify installation verbiage
Update the installation verbiage in the `README` for clarity
(issue #597).
2020-11-07 18:48:24 -05:00
857119b443 feat(Docker): create development Docker image
- Create Docker image to be used for experimentation during development
- Create targets in `Makefile` pertaining to the above
2020-11-07 18:47:24 -05:00
f421483eea Merge pull request #596 from chrisallenlane/v4.1.1
v4.1.1
2020-11-03 18:32:25 -05:00
4adddbf504 chore: bump version to v4.1.1 2020-11-03 18:05:46 -05:00
b9c86b6975 chore(dependencies): update dependencies 2020-11-03 17:59:56 -05:00
0b21ccf6f8 feat(tests): improve test coverage 2020-11-03 17:29:49 -05:00
a3ad8c5101 Merge pull request #595 from chrisallenlane/codeql
feat: integrate CodeQL build action
2020-11-01 10:51:38 -05:00
bacb74929a feat: integrate CodeQL build action 2020-11-01 10:47:25 -05:00
82e1c27494 Merge pull request #588 from chrisallenlane/bare-tag
feat: implement `cheat -t` shorthand
2020-09-05 09:05:09 -04:00
45beeb2edb chore: bump version to 4.1.0 2020-09-05 08:56:51 -04:00
c2c479b36c feat: support -t shorthand
Make `cheat -t <tag>` function as a shorthand for `cheat -l -t <tag>`.
2020-09-02 17:17:44 -04:00
cb0243e7fc Merge pull request #580 from ryaanwells/patch-1
Fixing "cheetsheet" typo in README.md
2020-08-23 15:25:55 -04:00
e5d04d41ea Fixing "cheetsheet" typo in tags_test.go 2020-08-21 15:45:49 +01:00
2474ea4fb1 Fixing "cheetsheet" typo in README.md 2020-08-18 14:53:15 +01:00
7467c9fbc0 Merge pull request #578 from chrisallenlane/v4.0.3
chore: update dependencies
2020-08-08 13:45:10 -04:00
dfba3da003 chore: update dependencies 2020-08-08 10:29:29 -04:00
ad7ad64a75 Merge pull request #573 from chrisallenlane/linux-conf
fix(config): add /etc/cheat config path
2020-07-11 08:12:04 -04:00
c4dcfd5da0 fix(config): add /etc/cheat config path
Add `/etc/cheat/conf.yml` to default config paths. See #568 for context.
2020-07-09 18:28:10 -04:00
560 changed files with 23817 additions and 9614 deletions

66
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@ -0,0 +1,66 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
# ******** NOTE ********
name: "CodeQL"
on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '45 23 * * 0'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: [ 'go' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more...
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
#- name: Autobuild
#uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
- run: make
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

8
Dockerfile Normal file
View File

@ -0,0 +1,8 @@
# NB: this image isn't used anywhere in the build pipeline. It exists to
# conveniently facilitate ad-hoc experimentation in a sandboxed environment
# during development.
FROM golang:1.15-alpine
RUN apk add git less make
WORKDIR /app

View File

@ -7,6 +7,7 @@ dist_dir := ./dist
CAT := cat
COLUMN := column
CTAGS := ctags
DOCKER := docker
GO := go
GREP := grep
GZIP := gzip --best
@ -20,6 +21,8 @@ SED := sed
SORT := sort
ZIP := zip -m
docker_image := cheat-devel:latest
# build flags
BUILD_FLAGS := -ldflags="-s -w" -mod vendor -trimpath
GOBIN :=
@ -105,6 +108,7 @@ clean: $(dist_dir)
.PHONY: distclean
distclean:
$(RM) -f tags
@$(DOCKER) image rm -f $(docker_image)
## setup: install revive (linter) and scc (sloc tool)
.PHONY: setup
@ -132,6 +136,10 @@ man:
vendor:
$(GO) mod vendor && $(GO) mod tidy && $(GO) mod verify
## vendor-update: update vendored dependencies
vendor-update:
$(GO) get -t -u ./... && $(GO) mod vendor
## fmt: run go fmt
.PHONY: fmt
fmt:
@ -165,6 +173,16 @@ check: | vendor fmt lint vet test
.PHONY: prepare
prepare: | $(dist_dir) clean generate vendor fmt lint vet test
## docker-setup: create a docker image for use during development
.PHONY: docker-setup
docker-setup:
$(DOCKER) build -t $(docker_image) -f Dockerfile .
## docker-sh: shell into the docker development container
.PHONY: docker-sh
docker-sh:
$(DOCKER) run -v $(shell pwd):/app -ti $(docker_image) /bin/ash
## help: display this help text
.PHONY: help
help:

View File

@ -47,17 +47,17 @@ Installing
`cheat` has no dependencies. To install it, download the executable from the
[releases][] page and place it on your `PATH`.
Alternatively, if you have [go][] installed, you may install `cheat` using `go
get`:
```sh
go get -u github.com/cheat/cheat/cmd/cheat
```
Configuring
-----------
### conf.yml ###
`cheat` is configured by a YAML file that will be auto-generated on first run.
Should you need to create a config file manually, you can do
so via:
```sh
mkdir -p ~/.config/cheat && cheat --init > ~/.config/cheat/conf.yml
```
By default, the config file is assumed to exist on an XDG-compliant
configuration path like `~/.config/cheat/conf.yml`. If you would like to store
@ -98,7 +98,7 @@ install the community-sourced cheatsheets the first time you run `cheat`.
Cheatpaths
----------
Cheatsheets are stored on "cheatpaths", which are directories that contain
cheetsheets. Cheatpaths are specified in the `conf.yml` file.
cheatsheets. Cheatpaths are specified in the `conf.yml` file.
It can be useful to configure `cheat` against multiple cheatpaths. A common
pattern is to store cheatsheets from multiple repositories on individual
@ -211,3 +211,4 @@ Additionally, `cheat` supports enhanced autocompletion via integration with
[cheatsheets]: https://github.com/cheat/cheatsheets
[completions]: https://github.com/cheat/cheat/tree/master/scripts
[fzf]: https://github.com/junegunn/fzf
[go]: https://golang.org

View File

@ -27,5 +27,5 @@ func cmdDirectories(opts map[string]interface{}, conf config.Config) {
// write columnized output to stdout
w.Flush()
display.Display(out.String(), conf)
display.Write(out.String(), conf)
}

View File

@ -37,8 +37,8 @@ func cmdList(opts map[string]interface{}, conf config.Config) {
// sheets with local sheets), here we simply want to create a slice
// containing all sheets.
flattened := []sheet.Sheet{}
for _, pathSheets := range cheatsheets {
for _, s := range pathSheets {
for _, pathsheets := range cheatsheets {
for _, s := range pathsheets {
flattened = append(flattened, s)
}
}
@ -105,5 +105,5 @@ func cmdList(opts map[string]interface{}, conf config.Config) {
// write columnized output to stdout
w.Flush()
display.Display(out.String(), conf)
display.Write(out.String(), conf)
}

View File

@ -8,7 +8,6 @@ import (
"github.com/cheat/cheat/internal/config"
"github.com/cheat/cheat/internal/display"
"github.com/cheat/cheat/internal/sheet"
"github.com/cheat/cheat/internal/sheets"
)
@ -32,71 +31,65 @@ func cmdSearch(opts map[string]interface{}, conf config.Config) {
)
}
// consolidate the cheatsheets found on all paths into a single map of
// `title` => `sheet` (ie, allow more local cheatsheets to override less
// local cheatsheets)
consolidated := sheets.Consolidate(cheatsheets)
// if <cheatsheet> was provided, search that single sheet only
if opts["<cheatsheet>"] != nil {
cheatsheet := opts["<cheatsheet>"].(string)
// assert that the cheatsheet exists
s, ok := consolidated[cheatsheet]
if !ok {
fmt.Printf("No cheatsheet found for '%s'.\n", cheatsheet)
os.Exit(2)
}
consolidated = map[string]sheet.Sheet{
cheatsheet: s,
}
}
// sort the cheatsheets alphabetically, and search for matches
// iterate over each cheatpath
out := ""
for _, sheet := range sheets.Sort(consolidated) {
for _, pathcheats := range cheatsheets {
// assume that we want to perform a case-insensitive search for <phrase>
pattern := "(?i)" + phrase
// sort the cheatsheets alphabetically, and search for matches
for _, sheet := range sheets.Sort(pathcheats) {
// unless --regex is provided, in which case we pass the regex unaltered
if opts["--regex"] == true {
pattern = phrase
}
// if <cheatsheet> was provided, constrain the search only to
// matching cheatsheets
if opts["<cheatsheet>"] != nil && sheet.Title != opts["<cheatsheet>"] {
continue
}
// compile the regex
reg, err := regexp.Compile(pattern)
if err != nil {
fmt.Fprintln(os.Stderr, fmt.Sprintf("failed to compile regexp: %s, %v", pattern, err))
os.Exit(1)
}
// assume that we want to perform a case-insensitive search for <phrase>
pattern := "(?i)" + phrase
// `Search` will return text entries that match the search terms. We're
// using it here to overwrite the prior cheatsheet Text, filtering it to
// only what is relevant
sheet.Text = sheet.Search(reg)
// unless --regex is provided, in which case we pass the regex unaltered
if opts["--regex"] == true {
pattern = phrase
}
// if the sheet did not match the search, ignore it and move on
if sheet.Text == "" {
continue
}
// compile the regex
reg, err := regexp.Compile(pattern)
if err != nil {
fmt.Fprintln(os.Stderr, fmt.Sprintf("failed to compile regexp: %s, %v", pattern, err))
os.Exit(1)
}
// if colorization was requested, apply it here
if conf.Color(opts) {
sheet.Colorize(conf)
}
// `Search` will return text entries that match the search terms. We're
// using it here to overwrite the prior cheatsheet Text, filtering it to
// only what is relevant
sheet.Text = sheet.Search(reg)
// output the cheatsheet title
out += fmt.Sprintf("%s:\n", sheet.Title)
// if the sheet did not match the search, ignore it and move on
if sheet.Text == "" {
continue
}
// indent each line of content with two spaces
for _, line := range strings.Split(sheet.Text, "\n") {
out += fmt.Sprintf(" %s\n", line)
// if colorization was requested, apply it here
if conf.Color(opts) {
sheet.Colorize(conf)
}
// display the cheatsheet title and path
out += fmt.Sprintf("%s %s\n",
display.Underline(sheet.Title),
display.Faint(fmt.Sprintf("(%s)", sheet.CheatPath), conf),
)
// indent each line of content
out += display.Indent(sheet.Text) + "\n"
}
}
// trim superfluous newlines
out = strings.TrimSpace(out)
// display the output
display.Display(out, conf)
// NB: resist the temptation to call `display.Display` multiple times in
// the loop above. That will not play nicely with the paginator.
display.Write(out, conf)
}

View File

@ -26,5 +26,5 @@ func cmdTags(opts map[string]interface{}, conf config.Config) {
}
// display the output
display.Display(out, conf)
display.Write(out, conf)
}

View File

@ -30,9 +30,39 @@ func cmdView(opts map[string]interface{}, conf config.Config) {
)
}
// consolidate the cheatsheets found on all paths into a single map of
// `title` => `sheet` (ie, allow more local cheatsheets to override less
// local cheatsheets)
// if --all was passed, display cheatsheets from all cheatpaths
if opts["--all"].(bool) {
// iterate over the cheatpaths
out := ""
for _, cheatpath := range cheatsheets {
// if the cheatpath contains the specified cheatsheet, display it
if sheet, ok := cheatpath[cheatsheet]; ok {
// identify the matching cheatsheet
out += fmt.Sprintf("%s %s\n",
display.Underline(sheet.Title),
display.Faint(fmt.Sprintf("(%s)", sheet.CheatPath), conf),
)
// apply colorization if requested
if conf.Color(opts) {
sheet.Colorize(conf)
}
// display the cheatsheet
out += display.Indent(sheet.Text) + "\n"
}
}
// display and exit
display.Write(strings.TrimSuffix(out, "\n"), conf)
os.Exit(0)
}
// otherwise, consolidate the cheatsheets found on all paths into a single
// map of `title` => `sheet` (ie, allow more local cheatsheets to override
// less local cheatsheets)
consolidated := sheets.Consolidate(cheatsheets)
// fail early if the requested cheatsheet does not exist
@ -48,5 +78,5 @@ func cmdView(opts map[string]interface{}, conf config.Config) {
}
// display the cheatsheet
display.Display(sheet.Text, conf)
display.Write(sheet.Text, conf)
}

View File

@ -3,11 +3,12 @@ Usage:
Options:
--init Write a default config file to stdout
-a --all Search among all cheatpaths
-c --colorize Colorize output
-d --directories List cheatsheet directories
-e --edit=<cheatsheet> Edit <cheatsheet>
-l --list List cheatsheets
-p --path=<name> Return only sheets found on path <name>
-p --path=<name> Return only sheets found on cheatpath <name>
-r --regex Treat search <phrase> as a regex
-s --search=<phrase> Search cheatsheets for <phrase>
-t --tag=<tag> Return only sheets matching <tag>

View File

@ -5,7 +5,6 @@ package main
import (
"fmt"
"os"
"path"
"runtime"
"strings"
@ -17,7 +16,7 @@ import (
"github.com/cheat/cheat/internal/installer"
)
const version = "4.0.1"
const version = "4.2.1"
func main() {
@ -74,62 +73,16 @@ func main() {
os.Exit(0)
}
// read the config template
configs := configs()
// determine the appropriate paths for config data and (optional) community
// cheatsheets based on the user's platform
// choose a confpath
confpath = confpaths[0]
confdir := path.Dir(confpath)
// create paths for community and personal cheatsheets
community := path.Join(confdir, "/cheatsheets/community")
personal := path.Join(confdir, "/cheatsheets/personal")
// template the above paths into the default configs
configs = strings.Replace(configs, "COMMUNITY_PATH", community, -1)
configs = strings.Replace(configs, "PERSONAL_PATH", personal, -1)
// prompt the user to download the community cheatsheets
yes, err = installer.Prompt(
"Would you like to download the community cheatsheets? [Y/n]",
true,
)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to create config: %v\n", err)
os.Exit(1)
}
// clone the community cheatsheets if so instructed
if yes {
// clone the community cheatsheets
if err := installer.Clone(community); err != nil {
fmt.Fprintf(os.Stderr, "failed to create config: %v\n", err)
os.Exit(1)
}
// also create a directory for personal cheatsheets
if err := os.MkdirAll(personal, os.ModePerm); err != nil {
fmt.Fprintf(
os.Stderr,
"failed to create config: failed to create directory: %s: %v\n",
personal,
err)
os.Exit(1)
}
}
// the config file does not exist, so we'll try to create one
if err = config.Init(confpath, configs); err != nil {
fmt.Fprintf(
os.Stderr,
"failed to create config file: %s: %v\n",
confpath,
err,
)
// run the installer
if err := installer.Run(configs(), confpath); err != nil {
fmt.Fprintf(os.Stderr, "failed to run installer: %v\n", err)
os.Exit(1)
}
// notify the user and exit
fmt.Printf("Created config file: %s\n", confpath)
fmt.Println("Please read this file for advanced configuration information.")
os.Exit(0)
@ -185,6 +138,9 @@ func main() {
case opts["<cheatsheet>"] != nil:
cmd = cmdView
case opts["--tag"] != nil && opts["--tag"].(string) != "":
cmd = cmdList
default:
fmt.Println(usage())
os.Exit(0)

View File

@ -12,11 +12,12 @@ func usage() string {
Options:
--init Write a default config file to stdout
-a --all Search among all cheatpaths
-c --colorize Colorize output
-d --directories List cheatsheet directories
-e --edit=<cheatsheet> Edit <cheatsheet>
-l --list List cheatsheets
-p --path=<name> Return only sheets found on path <name>
-p --path=<name> Return only sheets found on cheatpath <name>
-r --regex Treat search <phrase> as a regex
-s --search=<phrase> Search cheatsheets for <phrase>
-t --tag=<tag> Return only sheets matching <tag>

View File

@ -1,4 +1,4 @@
.\" Automatically generated by Pandoc 1.17.2
.\" Automatically generated by Pandoc 2.2.1
.\"
.TH "CHEAT" "1" "" "" "General Commands Manual"
.hy
@ -17,62 +17,62 @@ commands that they use frequently, but not frequently enough to
remember.
.SH OPTIONS
.TP
.B \-\-init
.B \[en]init
Print a config file to stdout.
.RS
.RE
.TP
.B \-c, \-\-colorize
.B \-c, \[en]colorize
Colorize output.
.RS
.RE
.TP
.B \-d, \-\-directories
.B \-d, \[en]directories
List cheatsheet directories.
.RS
.RE
.TP
.B \-e, \-\-edit=\f[I]CHEATSHEET\f[]
.B \-e, \[en]edit=\f[I]CHEATSHEET\f[]
Open \f[I]CHEATSHEET\f[] for editing.
.RS
.RE
.TP
.B \-l, \-\-list
.B \-l, \[en]list
List available cheatsheets.
.RS
.RE
.TP
.B \-p, \-\-path=\f[I]PATH\f[]
.B \-p, \[en]path=\f[I]PATH\f[]
Filter only to sheets found on path \f[I]PATH\f[].
.RS
.RE
.TP
.B \-r, \-\-regex
.B \-r, \[en]regex
Treat search \f[I]PHRASE\f[] as a regular expression.
.RS
.RE
.TP
.B \-s, \-\-search=\f[I]PHRASE\f[]
.B \-s, \[en]search=\f[I]PHRASE\f[]
Search cheatsheets for \f[I]PHRASE\f[].
.RS
.RE
.TP
.B \-t, \-\-tag=\f[I]TAG\f[]
.B \-t, \[en]tag=\f[I]TAG\f[]
Filter only to sheets tagged with \f[I]TAG\f[].
.RS
.RE
.TP
.B \-T, \-\-tags
.B \-T, \[en]tags
List all tags in use.
.RS
.RE
.TP
.B \-v, \-\-version
.B \-v, \[en]version
Print the version number.
.RS
.RE
.TP
.B \-\-rm=\f[I]CHEATSHEET\f[]
.B \[en]rm=\f[I]CHEATSHEET\f[]
Remove (deletes) \f[I]CHEATSHEET\f[].
.RS
.RE
@ -88,7 +88,7 @@ cheat \-e \f[I]foo\f[]
.RS
.RE
.TP
.B To edit (or create) the foo/bar cheatsheet on the \[aq]work\[aq] cheatpath:
.B To edit (or create) the foo/bar cheatsheet on the `work' cheatpath:
cheat \-p \f[I]work\f[] \-e \f[I]foo/bar\f[]
.RS
.RE
@ -103,7 +103,7 @@ cheat \-l
.RS
.RE
.TP
.B To list all cheatsheets whose titles match \[aq]apt\[aq]:
.B To list all cheatsheets whose titles match `apt':
cheat \-l \f[I]apt\f[]
.RS
.RE
@ -113,23 +113,23 @@ cheat \-T
.RS
.RE
.TP
.B To list available cheatsheets that are tagged as \[aq]personal\[aq]:
.B To list available cheatsheets that are tagged as `personal':
cheat \-l \-t \f[I]personal\f[]
.RS
.RE
.TP
.B To search for \[aq]ssh\[aq] among all cheatsheets, and colorize matches:
.B To search for `ssh' among all cheatsheets, and colorize matches:
cheat \-c \-s \f[I]ssh\f[]
.RS
.RE
.TP
.B To search (by regex) for cheatsheets that contain an IP address:
cheat \-c \-r \-s \f[I]\[aq](?:[0\-9]{1,3}.){3}[0\-9]{1,3}\[aq]\f[]
cheat \-c \-r \-s \f[I]`(?:[0\-9]{1,3}.){3}[0\-9]{1,3}'\f[]
.RS
.RE
.TP
.B To remove (delete) the foo/bar cheatsheet:
cheat \-\-rm \f[I]foo/bar\f[]
cheat \[en]rm \f[I]foo/bar\f[]
.RS
.RE
.SH FILES
@ -159,15 +159,15 @@ depending upon your platform:
\f[B]cheat\f[] will search in the order specified above.
The first \f[I]conf.yaml\f[] encountered will be respected.
.PP
If \f[B]cheat\f[] cannot locate a config file, it will ask if you\[aq]d
like to generate one automatically.
If \f[B]cheat\f[] cannot locate a config file, it will ask if you'd like
to generate one automatically.
Alternatively, you may also generate a config file manually by running
\f[B]cheat \-\-init\f[] and saving its output to the appropriate
\f[B]cheat \[en]init\f[] and saving its output to the appropriate
location for your platform.
.SS Cheatpaths
.PP
\f[B]cheat\f[] reads its cheatsheets from "cheatpaths", which are the
directories in which cheatsheets are stored.
\f[B]cheat\f[] reads its cheatsheets from \[lq]cheatpaths\[rq], which
are the directories in which cheatsheets are stored.
Cheatpaths may be configured in \f[I]conf.yaml\f[], and viewed via
\f[B]cheat \-d\f[].
.PP

5
go.mod
View File

@ -3,7 +3,7 @@ module github.com/cheat/cheat
go 1.14
require (
github.com/alecthomas/chroma v0.7.3
github.com/alecthomas/chroma v0.9.1
github.com/davecgh/go-spew v1.1.1
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
github.com/kr/text v0.2.0 // indirect
@ -11,7 +11,8 @@ require (
github.com/mitchellh/go-homedir v1.1.0
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/sergi/go-diff v1.1.0 // indirect
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 // indirect
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0
gopkg.in/yaml.v2 v2.3.0
gopkg.in/yaml.v2 v2.4.0
)

22
go.sum
View File

@ -1,7 +1,7 @@
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U=
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
github.com/alecthomas/chroma v0.7.3 h1:NfdAERMy+esYQs8OXk0I868/qDxxCEo7FMz1WIqMAeI=
github.com/alecthomas/chroma v0.7.3/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM=
github.com/alecthomas/chroma v0.9.1 h1:cBmvQqRImzR5aWqdMxYZByND4S7BCS/g0svZb28h0Dc=
github.com/alecthomas/chroma v0.9.1/go.mod h1:eMuEnpA18XbG/WhOWtCzJHS7WqEtDAI+HxdwoW0nVSk=
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo=
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE=
@ -13,14 +13,12 @@ github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
@ -31,27 +29,23 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 h1:opSr2sbRXk5X5/givKrrKj9HXxFpW2sdCiP8MJSKLQY=
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
@ -60,5 +54,5 @@ gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 h1:POO/ycCATvegFmVuPpQzZFJ+p
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=

View File

@ -0,0 +1,22 @@
package config
import (
"testing"
)
// TestColor asserts that colorization rules are properly respected
func TestColor(t *testing.T) {
// mock a config
conf := Config{}
opts := map[string]interface{}{"--colorize": false}
if conf.Color(opts) {
t.Errorf("failed to respect --colorize (false)")
}
opts = map[string]interface{}{"--colorize": true}
if !conf.Color(opts) {
t.Errorf("failed to respect --colorize (true)")
}
}

View File

@ -0,0 +1,38 @@
package config
import (
"io/ioutil"
"os"
"testing"
)
// TestInit asserts that configs are properly initialized
func TestInit(t *testing.T) {
// initialize a temporary config file
confFile, err := ioutil.TempFile("", "cheat-test")
if err != nil {
t.Errorf("failed to create temp file: %v", err)
}
// clean up the temp file
defer os.Remove(confFile.Name())
// initialize the config file
conf := "mock config data"
if err = Init(confFile.Name(), conf); err != nil {
t.Errorf("failed to init config file: %v", err)
}
// read back the config file contents
bytes, err := ioutil.ReadFile(confFile.Name())
if err != nil {
t.Errorf("failed to read config file: %v", err)
}
// assert that the contents were written correctly
got := string(bytes)
if got != conf {
t.Errorf("failed to write configs: want: %s, got: %s", conf, got)
}
}

View File

@ -0,0 +1,53 @@
package config
import (
"io/ioutil"
"os"
"testing"
)
// TestPathConfigNotExists asserts that `Path` identifies non-existent config
// files
func TestPathConfigNotExists(t *testing.T) {
// package (invalid) cheatpaths
paths := []string{"/cheat-test-conf-does-not-exist"}
// assert
if _, err := Path(paths); err == nil {
t.Errorf("failed to identify non-existent config file")
}
}
// TestPathConfigExists asserts that `Path` identifies existent config files
func TestPathConfigExists(t *testing.T) {
// initialize a temporary config file
confFile, err := ioutil.TempFile("", "cheat-test")
if err != nil {
t.Errorf("failed to create temp file: %v", err)
}
// clean up the temp file
defer os.Remove(confFile.Name())
// package cheatpaths
paths := []string{
"/cheat-test-conf-does-not-exist",
confFile.Name(),
}
// assert
got, err := Path(paths)
if err != nil {
t.Errorf("failed to identify config file: %v", err)
}
if got != confFile.Name() {
t.Errorf(
"failed to return config path: want: %s, got: %s",
confFile.Name(),
got,
)
}
}

View File

@ -36,10 +36,10 @@ func Paths(
paths = append(paths, path.Join(xdgpath, "/cheat/conf.yml"))
}
// if `XDG_CONFIG_HOME` is not set, search the user's home directory
paths = append(paths, []string{
path.Join(home, ".config/cheat/conf.yml"),
path.Join(home, ".cheat/conf.yml"),
"/etc/cheat/conf.yml",
}...)
return paths, nil

View File

@ -39,6 +39,7 @@ func TestValidatePathsNix(t *testing.T) {
"/home/bar/cheat/conf.yml",
"/home/foo/.config/cheat/conf.yml",
"/home/foo/.cheat/conf.yml",
"/etc/cheat/conf.yml",
}
// assert that output matches expectations
@ -81,6 +82,7 @@ func TestValidatePathsNixNoXDG(t *testing.T) {
want := []string{
"/home/foo/.config/cheat/conf.yml",
"/home/foo/.cheat/conf.yml",
"/etc/cheat/conf.yml",
}
// assert that output matches expectations

18
internal/display/faint.go Normal file
View File

@ -0,0 +1,18 @@
package display
import (
"fmt"
"github.com/cheat/cheat/internal/config"
)
// Faint returns an faint string
func Faint(str string, conf config.Config) string {
// make `str` faint only if colorization has been requested
if conf.Colorize {
return fmt.Sprintf(fmt.Sprintf("\033[2m%s\033[0m", str))
}
// otherwise, return the string unmodified
return str
}

View File

@ -0,0 +1,27 @@
package display
import (
"testing"
"github.com/cheat/cheat/internal/config"
)
// TestFaint asserts that Faint applies faint formatting
func TestFaint(t *testing.T) {
// case: apply colorization
conf := config.Config{Colorize: true}
want := "\033[2mfoo\033[0m"
got := Faint("foo", conf)
if want != got {
t.Errorf("failed to faint: want: %s, got: %s", want, got)
}
// case: do not apply colorization
conf.Colorize = false
want = "foo"
got = Faint("foo", conf)
if want != got {
t.Errorf("failed to faint: want: %s, got: %s", want, got)
}
}

View File

@ -0,0 +1,21 @@
package display
import (
"fmt"
"strings"
)
// Indent prepends each line of a string with a tab
func Indent(str string) string {
// trim superfluous whitespace
str = strings.TrimSpace(str)
// prepend each line with a tab character
out := ""
for _, line := range strings.Split(str, "\n") {
out += fmt.Sprintf("\t%s\n", line)
}
return out
}

View File

@ -0,0 +1,12 @@
package display
import "testing"
// TestIndent asserts that Indent prepends a tab to each line
func TestIndent(t *testing.T) {
got := Indent("foo\nbar\nbaz")
want := "\tfoo\n\tbar\n\tbaz\n"
if got != want {
t.Errorf("failed to indent: want: %s, got: %s", want, got)
}
}

View File

@ -0,0 +1,8 @@
package display
import "fmt"
// Underline returns an underlined string
func Underline(str string) string {
return fmt.Sprintf(fmt.Sprintf("\033[4m%s\033[0m", str))
}

View File

@ -0,0 +1,14 @@
package display
import (
"testing"
)
// TestUnderline asserts that Underline applies underline formatting
func TestUnderline(t *testing.T) {
want := "\033[4mfoo\033[0m"
got := Underline("foo")
if want != got {
t.Errorf("failed to underline: want: %s, got: %s", want, got)
}
}

View File

@ -9,9 +9,9 @@ import (
"github.com/cheat/cheat/internal/config"
)
// Display writes output either directly to stdout, or through a pager,
// Write writes output either directly to stdout, or through a pager,
// depending upon configuration.
func Display(out string, conf config.Config) {
func Write(out string, conf config.Config) {
// if no pager was configured, print the output to stdout and exit
if conf.Pager == "" {
fmt.Print(out)

View File

@ -8,8 +8,8 @@ import (
const cloneURL = "https://github.com/cheat/cheatsheets.git"
// Clone clones the community cheatsheets
func Clone(path string) error {
// clone clones the community cheatsheets
func clone(path string) error {
// perform the clone in a shell
cmd := exec.Command("git", "clone", cloneURL, path)

55
internal/installer/run.go Normal file
View File

@ -0,0 +1,55 @@
package installer
import (
"fmt"
"os"
"path"
"strings"
"github.com/cheat/cheat/internal/config"
)
// Run runs the installer
func Run(configs string, confpath string) error {
// determine the appropriate paths for config data and (optional) community
// cheatsheets based on the user's platform
confdir := path.Dir(confpath)
// create paths for community and personal cheatsheets
community := path.Join(confdir, "/cheatsheets/community")
personal := path.Join(confdir, "/cheatsheets/personal")
// template the above paths into the default configs
configs = strings.Replace(configs, "COMMUNITY_PATH", community, -1)
configs = strings.Replace(configs, "PERSONAL_PATH", personal, -1)
// prompt the user to download the community cheatsheets
yes, err := Prompt(
"Would you like to download the community cheatsheets? [Y/n]",
true,
)
if err != nil {
return fmt.Errorf("failed to prompt: %v", err)
}
// clone the community cheatsheets if so instructed
if yes {
// clone the community cheatsheets
if err := clone(community); err != nil {
return fmt.Errorf("failed to clone cheatsheets: %v", err)
}
// also create a directory for personal cheatsheets
if err := os.MkdirAll(personal, os.ModePerm); err != nil {
return fmt.Errorf("failed to create directory: %v", err)
}
}
// the config file does not exist, so we'll try to create one
if err = config.Init(confpath, configs); err != nil {
return fmt.Errorf("failed to create config file: %v", err)
}
return nil
}

View File

@ -13,7 +13,7 @@ func Path(filename string) string {
// determine the path of this file during runtime
_, thisfile, _, _ := runtime.Caller(0)
// compute the config path
// compute the mock path
file, err := filepath.Abs(
path.Join(
filepath.Dir(thisfile),
@ -22,7 +22,7 @@ func Path(filename string) string {
),
)
if err != nil {
panic(fmt.Errorf("failed to resolve config path: %v", err))
panic(fmt.Errorf("failed to resolve mock path: %v", err))
}
return file

View File

@ -0,0 +1,34 @@
package sheet
import (
"testing"
"github.com/cheat/cheat/internal/config"
)
// TestColorize asserts that syntax-highlighting is correctly applied
func TestColorize(t *testing.T) {
// mock configs
conf := config.Config{
Formatter: "terminal16m",
Style: "solarized-dark",
}
// mock a sheet
s := Sheet{
Text: "echo 'foo'",
}
// colorize the sheet text
s.Colorize(conf)
// initialize expectations
want := "echo"
want += " 'foo'"
// assert
if s.Text != want {
t.Errorf("failed to colorize sheet: want: %s, got: %s", want, s.Text)
}
}

View File

@ -25,7 +25,7 @@ func TestCopyFlat(t *testing.T) {
}
// mock a cheatsheet struct
sheet, err := New("foo", src.Name(), []string{}, false)
sheet, err := New("foo", "community", src.Name(), []string{}, false)
if err != nil {
t.Errorf("failed to init cheatsheet: %v", err)
}
@ -72,7 +72,13 @@ func TestCopyDeep(t *testing.T) {
}
// mock a cheatsheet struct
sheet, err := New("/cheat-tests/alpha/bravo/foo", src.Name(), []string{}, false)
sheet, err := New(
"/cheat-tests/alpha/bravo/foo",
"community",
src.Name(),
[]string{},
false,
)
if err != nil {
t.Errorf("failed to init cheatsheet: %v", err)
}

View File

@ -10,17 +10,19 @@ import (
// Sheet encapsulates sheet information
type Sheet struct {
Title string
Path string
Text string
Tags []string
Syntax string
ReadOnly bool
Title string
CheatPath string
Path string
Text string
Tags []string
Syntax string
ReadOnly bool
}
// New initializes a new Sheet
func New(
title string,
cheatpath string,
path string,
tags []string,
readOnly bool,
@ -46,11 +48,12 @@ func New(
// initialize and return a sheet
return Sheet{
Title: title,
Path: path,
Text: text + "\n",
Tags: tags,
Syntax: fm.Syntax,
ReadOnly: readOnly,
Title: title,
CheatPath: cheatpath,
Path: path,
Text: text + "\n",
Tags: tags,
Syntax: fm.Syntax,
ReadOnly: readOnly,
}, nil
}

View File

@ -13,6 +13,7 @@ func TestSheetSuccess(t *testing.T) {
// initialize a sheet
sheet, err := New(
"foo",
"community",
mock.Path("sheet/foo"),
[]string{"alpha", "bravo"},
false,
@ -61,6 +62,7 @@ func TestSheetFailure(t *testing.T) {
// initialize a sheet
_, err := New(
"foo",
"community",
mock.Path("/does-not-exist"),
[]string{"alpha", "bravo"},
false,
@ -69,3 +71,20 @@ func TestSheetFailure(t *testing.T) {
t.Errorf("failed to return an error on unreadable sheet")
}
}
// TestSheetFrontMatterFailure asserts that an error is returned if the sheet's
// frontmatter cannot be parsed.
func TestSheetFrontMatterFailure(t *testing.T) {
// initialize a sheet
_, err := New(
"foo",
"community",
mock.Path("sheet/bad-fm"),
[]string{"alpha", "bravo"},
false,
)
if err == nil {
t.Errorf("failed to return an error on malformed front-matter")
}
}

View File

@ -59,7 +59,13 @@ func Load(cheatpaths []cp.Cheatpath) ([]map[string]sheet.Sheet, error) {
}
// parse the cheatsheet file into a `sheet` struct
s, err := sheet.New(title, path, cheatpath.Tags, cheatpath.ReadOnly)
s, err := sheet.New(
title,
cheatpath.Name,
path,
cheatpath.Tags,
cheatpath.ReadOnly,
)
if err != nil {
return fmt.Errorf(
"failed to load sheet: %s, path: %s, err: %v",

View File

@ -1,3 +1,62 @@
package sheets
// TODO
import (
"path"
"testing"
"github.com/cheat/cheat/internal/cheatpath"
"github.com/cheat/cheat/internal/mock"
)
// TestLoad asserts that sheets on valid cheatpaths can be loaded successfully
func TestLoad(t *testing.T) {
// mock cheatpaths
cheatpaths := []cheatpath.Cheatpath{
{
Name: "community",
Path: path.Join(mock.Path("cheatsheets"), "community"),
ReadOnly: true,
},
{
Name: "personal",
Path: path.Join(mock.Path("cheatsheets"), "personal"),
ReadOnly: false,
},
}
// load cheatsheets
sheets, err := Load(cheatpaths)
if err != nil {
t.Errorf("failed to load cheatsheets: %v", err)
}
// assert that the correct number of sheets loaded
// (sheet load details are tested in `sheet_test.go`)
want := 4
if len(sheets) != want {
t.Errorf(
"failed to load correct number of cheatsheets: want: %d, got: %d",
want,
len(sheets),
)
}
}
// TestLoadBadPath asserts that an error is returned if a cheatpath is invalid
func TestLoadBadPath(t *testing.T) {
// mock a bad cheatpath
cheatpaths := []cheatpath.Cheatpath{
{
Name: "badpath",
Path: "/cheat/test/path/does/not/exist",
ReadOnly: true,
},
}
// attempt to load the cheatpath
if _, err := Load(cheatpaths); err == nil {
t.Errorf("failed to reject invalid cheatpath")
}
}

View File

@ -9,7 +9,7 @@ import (
"github.com/cheat/cheat/internal/sheet"
)
// TestTags asserts that cheetsheet tags are properly returned
// TestTags asserts that cheatsheet tags are properly returned
func TestTags(t *testing.T) {
// mock cheatsheets available on multiple cheatpaths

View File

View File

@ -0,0 +1,4 @@
---
tags: [ community ]
---
This is the bar cheatsheet.

View File

@ -0,0 +1,4 @@
---
tags: [ community ]
---
This is the foo cheatsheet.

View File

@ -0,0 +1,4 @@
---
tags: [ personal ]
---
This is the bat cheatsheet.

View File

@ -0,0 +1,4 @@
---
tags: [ personal ]
---
This is the baz cheatsheet.

4
mocks/sheet/bad-fm Normal file
View File

@ -0,0 +1,4 @@
---
syntax: sh
This is malformed frontmatter.

View File

@ -20,6 +20,11 @@ linters:
- wsl
- gomnd
- gocognit
- goerr113
- nolintlint
- testpackage
- godot
- nestif
linters-settings:
govet:

View File

@ -6,6 +6,8 @@ release:
brews:
-
install: bin.install "chroma"
env:
- CGO_ENABLED=0
builds:
- goos:
- linux

View File

@ -1,12 +0,0 @@
sudo: false
language: go
go:
- "1.13.x"
script:
- go test -v ./...
- curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s v1.22.2
- ./bin/golangci-lint run
- git clean -fdx .
after_success:
curl -sL https://git.io/goreleaser | bash && goreleaser

View File

@ -1,5 +1,7 @@
.PHONY: chromad upload all
VERSION ?= $(shell git describe --tags --dirty --always)
all: README.md tokentype_string.go
README.md: lexers/*/*.go
@ -9,10 +11,8 @@ tokentype_string.go: types.go
go generate
chromad:
(cd ./cmd/chromad && go get github.com/GeertJohan/go.rice/rice@master && go install github.com/GeertJohan/go.rice/rice)
rm -f chromad
(export CGOENABLED=0 GOOS=linux ; cd ./cmd/chromad && go build -o ../../chromad .)
rice append -i ./cmd/chromad --exec=./chromad
(export CGOENABLED=0 GOOS=linux ; cd ./cmd/chromad && go build -ldflags="-X 'main.version=$(VERSION)'" -o ../../chromad .)
upload: chromad
scp chromad root@swapoff.org: && \

View File

@ -1,4 +1,4 @@
# Chroma — A general purpose syntax highlighter in pure Go [![Golang Documentation](https://godoc.org/github.com/alecthomas/chroma?status.svg)](https://godoc.org/github.com/alecthomas/chroma) [![Build Status](https://travis-ci.org/alecthomas/chroma.svg)](https://travis-ci.org/alecthomas/chroma) [![Gitter chat](https://badges.gitter.im/alecthomas.svg)](https://gitter.im/alecthomas/Lobby)
# Chroma — A general purpose syntax highlighter in pure Go [![Golang Documentation](https://godoc.org/github.com/alecthomas/chroma?status.svg)](https://godoc.org/github.com/alecthomas/chroma) [![CircleCI](https://img.shields.io/circleci/project/github/alecthomas/chroma.svg)](https://circleci.com/gh/alecthomas/chroma) [![Go Report Card](https://goreportcard.com/badge/github.com/alecthomas/chroma)](https://goreportcard.com/report/github.com/alecthomas/chroma) [![Slack chat](https://img.shields.io/static/v1?logo=slack&style=flat&label=slack&color=green&message=gophers)](https://invite.slack.golangbridge.org/)
> **NOTE:** As Chroma has just been released, its API is still in flux. That said, the high-level interface should not change significantly.
@ -36,29 +36,30 @@ translators for Pygments lexers and styles.
Prefix | Language
:----: | --------
A | ABAP, ABNF, ActionScript, ActionScript 3, Ada, Angular2, ANTLR, ApacheConf, APL, AppleScript, Arduino, Awk
B | Ballerina, Base Makefile, Bash, Batchfile, BlitzBasic, BNF, Brainfuck
C | C, C#, C++, Cap'n Proto, Cassandra CQL, Ceylon, CFEngine3, cfstatement, ChaiScript, Cheetah, Clojure, CMake, COBOL, CoffeeScript, Common Lisp, Coq, Crystal, CSS, Cython
D | D, Dart, Diff, Django/Jinja, Docker, DTD
B | Ballerina, Base Makefile, Bash, Batchfile, BibTeX, BlitzBasic, BNF, Brainfuck
C | C, C#, C++, Caddyfile, Caddyfile Directives, Cap'n Proto, Cassandra CQL, Ceylon, CFEngine3, cfstatement, ChaiScript, Cheetah, Clojure, CMake, COBOL, CoffeeScript, Common Lisp, Coq, Crystal, CSS, Cython
D | D, Dart, Diff, Django/Jinja, Docker, DTD, Dylan
E | EBNF, Elixir, Elm, EmacsLisp, Erlang
F | Factor, Fish, Forth, Fortran, FSharp
G | GAS, GDScript, Genshi, Genshi HTML, Genshi Text, GLSL, Gnuplot, Go, Go HTML Template, Go Text Template, GraphQL, Groovy
H | Handlebars, Haskell, Haxe, HCL, Hexdump, HTML, HTTP, Hy
I | Idris, INI, Io
G | GAS, GDScript, Genshi, Genshi HTML, Genshi Text, Gherkin, GLSL, Gnuplot, Go, Go HTML Template, Go Text Template, GraphQL, Groovy
H | Handlebars, Haskell, Haxe, HCL, Hexdump, HLB, HTML, HTTP, Hy
I | Idris, Igor, INI, Io
J | J, Java, JavaScript, JSON, Julia, Jungle
K | Kotlin
L | Lighttpd configuration file, LLVM, Lua
M | Mako, markdown, Mason, Mathematica, Matlab, MiniZinc, MLIR, Modula-2, MonkeyC, MorrowindScript, Myghty, MySQL
N | NASM, Newspeak, Nginx configuration file, Nim, Nix
O | Objective-C, OCaml, Octave, OpenSCAD, Org Mode
P | PacmanConf, Perl, PHP, Pig, PkgConfig, PL/pgSQL, plaintext, PostgreSQL SQL dialect, PostScript, POVRay, PowerShell, Prolog, Protocol Buffer, Puppet, Python, Python 3
P | PacmanConf, Perl, PHP, PHTML, Pig, PkgConfig, PL/pgSQL, plaintext, Pony, PostgreSQL SQL dialect, PostScript, POVRay, PowerShell, Prolog, PromQL, Protocol Buffer, Puppet, Python, Python 3
Q | QBasic
R | R, Racket, Ragel, react, reg, reStructuredText, Rexx, Ruby, Rust
S | Sass, Scala, Scheme, Scilab, SCSS, Smalltalk, Smarty, SML, Snobol, Solidity, SPARQL, SQL, SquidConf, Swift, SYSTEMD, systemverilog
R | R, Racket, Ragel, react, ReasonML, reg, reStructuredText, Rexx, Ruby, Rust
S | SAS, Sass, Scala, Scheme, Scilab, SCSS, Smalltalk, Smarty, Snobol, Solidity, SPARQL, SQL, SquidConf, Standard ML, Stylus, Swift, SYSTEMD, systemverilog
T | TableGen, TASM, Tcl, Tcsh, Termcap, Terminfo, Terraform, TeX, Thrift, TOML, TradingView, Transact-SQL, Turing, Turtle, Twig, TypeScript, TypoScript, TypoScriptCssData, TypoScriptHtmlData
V | VB.net, verilog, VHDL, VimL, vue
W | WDTE
X | XML, Xorg
Y | YAML
Y | YAML, YANG
Z | Zig
_I will attempt to keep this section up to date, but an authoritative list can be
@ -183,7 +184,7 @@ following constructor options:
- `ClassPrefix(prefix)` - prefix each generated CSS class.
- `TabWidth(width)` - Set the rendered tab width, in characters.
- `WithLineNumbers()` - Render line numbers (style with `LineNumbers`).
- `LinkableLineNumbers()` - Make the line numbers linkable.
- `LinkableLineNumbers()` - Make the line numbers linkable and be a link to themselves.
- `HighlightLines(ranges)` - Highlight lines in these ranges (style with `LineHighlight`).
- `LineNumbersInTable()` - Use a table for formatting line numbers and code, rather than spans.
@ -215,7 +216,7 @@ python3 ~/Projects/chroma/_tools/pygments2chroma.py \
&& gofmt -s -w ~/Projects/chroma/lexers/*.go
```
See notes in [pygments-lexers.go](https://github.com/alecthomas/chroma/blob/master/pygments-lexers.txt)
See notes in [pygments-lexers.txt](https://github.com/alecthomas/chroma/blob/master/pygments-lexers.txt)
for a list of lexers, and notes on some of the issues importing them.
<a id="markdown-formatters" name="formatters"></a>

View File

@ -211,7 +211,7 @@ func (f *Formatter) writeHTML(w io.Writer, style *chroma.Style, tokens []chroma.
fmt.Fprintf(w, "<span%s>", f.styleAttr(css, chroma.LineHighlight))
}
fmt.Fprintf(w, "<span%s%s>%*d\n</span>", f.styleAttr(css, chroma.LineNumbersTable), f.lineIDAttribute(line), lineDigits, line)
fmt.Fprintf(w, "<span%s%s>%s\n</span>", f.styleAttr(css, chroma.LineNumbersTable), f.lineIDAttribute(line), f.lineTitleWithLinkIfNeeded(lineDigits, line))
if highlight {
fmt.Fprintf(w, "</span>")
@ -237,7 +237,7 @@ func (f *Formatter) writeHTML(w io.Writer, style *chroma.Style, tokens []chroma.
}
if f.lineNumbers && !wrapInTable {
fmt.Fprintf(w, "<span%s%s>%*d</span>", f.styleAttr(css, chroma.LineNumbers), f.lineIDAttribute(line), lineDigits, line)
fmt.Fprintf(w, "<span%s%s>%s</span>", f.styleAttr(css, chroma.LineNumbers), f.lineIDAttribute(line), f.lineTitleWithLinkIfNeeded(lineDigits, line))
}
for _, token := range tokens {
@ -272,7 +272,19 @@ func (f *Formatter) lineIDAttribute(line int) string {
if !f.linkableLineNumbers {
return ""
}
return fmt.Sprintf(" id=\"%s%d\"", f.lineNumbersIDPrefix, line)
return fmt.Sprintf(" id=\"%s\"", f.lineID(line))
}
func (f *Formatter) lineTitleWithLinkIfNeeded(lineDigits, line int) string {
title := fmt.Sprintf("%*d", lineDigits, line)
if !f.linkableLineNumbers {
return title
}
return fmt.Sprintf("<a style=\"outline: none; text-decoration:none; color:inherit\" href=\"#%s\">%s</a>", f.lineID(line), title)
}
func (f *Formatter) lineID(line int) string {
return fmt.Sprintf("%s%d", f.lineNumbersIDPrefix, line)
}
func (f *Formatter) shouldHighlight(highlightIndex, line int) (bool, bool) {

View File

@ -17,6 +17,20 @@ var c = chroma.MustParseColour
var ttyTables = map[int]*ttyTable{
8: {
foreground: map[chroma.Colour]string{
c("#000000"): "\033[30m", c("#7f0000"): "\033[31m", c("#007f00"): "\033[32m", c("#7f7fe0"): "\033[33m",
c("#00007f"): "\033[34m", c("#7f007f"): "\033[35m", c("#007f7f"): "\033[36m", c("#e5e5e5"): "\033[37m",
c("#555555"): "\033[1m\033[30m", c("#ff0000"): "\033[1m\033[31m", c("#00ff00"): "\033[1m\033[32m", c("#ffff00"): "\033[1m\033[33m",
c("#0000ff"): "\033[1m\033[34m", c("#ff00ff"): "\033[1m\033[35m", c("#00ffff"): "\033[1m\033[36m", c("#ffffff"): "\033[1m\033[37m",
},
background: map[chroma.Colour]string{
c("#000000"): "\033[40m", c("#7f0000"): "\033[41m", c("#007f00"): "\033[42m", c("#7f7fe0"): "\033[43m",
c("#00007f"): "\033[44m", c("#7f007f"): "\033[45m", c("#007f7f"): "\033[46m", c("#e5e5e5"): "\033[47m",
c("#555555"): "\033[1m\033[40m", c("#ff0000"): "\033[1m\033[41m", c("#00ff00"): "\033[1m\033[42m", c("#ffff00"): "\033[1m\033[43m",
c("#0000ff"): "\033[1m\033[44m", c("#ff00ff"): "\033[1m\033[45m", c("#00ffff"): "\033[1m\033[46m", c("#ffffff"): "\033[1m\033[47m",
},
},
16: {
foreground: map[chroma.Colour]string{
c("#000000"): "\033[30m", c("#7f0000"): "\033[31m", c("#007f00"): "\033[32m", c("#7f7fe0"): "\033[33m",
c("#00007f"): "\033[34m", c("#7f007f"): "\033[35m", c("#007f7f"): "\033[36m", c("#e5e5e5"): "\033[37m",
@ -227,15 +241,11 @@ type indexedTTYFormatter struct {
func (c *indexedTTYFormatter) Format(w io.Writer, style *chroma.Style, it chroma.Iterator) (err error) {
theme := styleToEscapeSequence(c.table, style)
for token := it(); token != chroma.EOF; token = it() {
// TODO: Cache token lookups?
clr, ok := theme[token.Type]
if !ok {
clr, ok = theme[token.Type.SubCategory()]
if !ok {
clr = theme[token.Type.Category()]
// if !ok {
// clr = theme[chroma.InheritStyle]
// }
}
}
if clr != "" {
@ -249,10 +259,22 @@ func (c *indexedTTYFormatter) Format(w io.Writer, style *chroma.Style, it chroma
return nil
}
// TTY is an 8-colour terminal formatter.
//
// The Lab colour space is used to map RGB values to the most appropriate index colour.
var TTY = Register("terminal", &indexedTTYFormatter{ttyTables[8]})
// TTY8 is an 8-colour terminal formatter.
//
// The Lab colour space is used to map RGB values to the most appropriate index colour.
var TTY8 = Register("terminal", &indexedTTYFormatter{ttyTables[8]})
var TTY8 = Register("terminal8", &indexedTTYFormatter{ttyTables[8]})
// TTY16 is a 16-colour terminal formatter.
//
// It uses \033[3xm for normal colours and \033[90Xm for bright colours.
//
// The Lab colour space is used to map RGB values to the most appropriate index colour.
var TTY16 = Register("terminal16", &indexedTTYFormatter{ttyTables[16]})
// TTY256 is a 256-colour terminal formatter.
//

View File

@ -8,7 +8,7 @@ require (
github.com/alecthomas/kong v0.2.4
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 // indirect
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964
github.com/dlclark/regexp2 v1.2.0
github.com/dlclark/regexp2 v1.4.0
github.com/mattn/go-colorable v0.1.6
github.com/mattn/go-isatty v0.0.12
github.com/pkg/errors v0.9.1 // indirect

View File

@ -13,6 +13,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=

View File

@ -4,7 +4,7 @@ import "strings"
// An Iterator across tokens.
//
// nil will be returned at the end of the Token stream.
// EOF will be returned at the end of the Token stream.
//
// If an error occurs within an Iterator, it may propagate this in a panic. Formatters should recover.
type Iterator func() Token

View File

@ -6,7 +6,7 @@ import (
)
// ABAP lexer.
var Abap = internal.Register(MustNewLexer(
var Abap = internal.Register(MustNewLazyLexer(
&Config{
Name: "ABAP",
Aliases: []string{"abap"},
@ -14,7 +14,11 @@ var Abap = internal.Register(MustNewLexer(
MimeTypes: []string{"text/x-abap"},
CaseInsensitive: true,
},
Rules{
abapRules,
))
func abapRules() Rules {
return Rules{
"common": {
{`\s+`, Text, nil},
{`^\*.*$`, CommentSingle, nil},
@ -52,5 +56,5 @@ var Abap = internal.Register(MustNewLexer(
{`[/;:()\[\],.]`, Punctuation, nil},
{`(!)(\w+)`, ByGroups(Operator, Name), nil},
},
},
))
}
}

View File

@ -6,14 +6,18 @@ import (
)
// Abnf lexer.
var Abnf = internal.Register(MustNewLexer(
var Abnf = internal.Register(MustNewLazyLexer(
&Config{
Name: "ABNF",
Aliases: []string{"abnf"},
Filenames: []string{"*.abnf"},
MimeTypes: []string{"text/x-abnf"},
},
Rules{
abnfRules,
))
func abnfRules() Rules {
return Rules{
"root": {
{`;.*$`, CommentSingle, nil},
{`(%[si])?"[^"]*"`, Literal, nil},
@ -34,5 +38,5 @@ var Abnf = internal.Register(MustNewLexer(
{`\s+`, Text, nil},
{`.`, Text, nil},
},
},
))
}
}

View File

@ -6,7 +6,7 @@ import (
)
// Actionscript lexer.
var Actionscript = internal.Register(MustNewLexer(
var Actionscript = internal.Register(MustNewLazyLexer(
&Config{
Name: "ActionScript",
Aliases: []string{"as", "actionscript"},
@ -15,7 +15,11 @@ var Actionscript = internal.Register(MustNewLexer(
NotMultiline: true,
DotAll: true,
},
Rules{
actionscriptRules,
))
func actionscriptRules() Rules {
return Rules{
"root": {
{`\s+`, Text, nil},
{`//.*?\n`, CommentSingle, nil},
@ -35,5 +39,5 @@ var Actionscript = internal.Register(MustNewLexer(
{`"(\\\\|\\"|[^"])*"`, LiteralStringDouble, nil},
{`'(\\\\|\\'|[^'])*'`, LiteralStringSingle, nil},
},
},
))
}
}

View File

@ -6,7 +6,7 @@ import (
)
// Actionscript 3 lexer.
var Actionscript3 = internal.Register(MustNewLexer(
var Actionscript3 = internal.Register(MustNewLazyLexer(
&Config{
Name: "ActionScript 3",
Aliases: []string{"as3", "actionscript3"},
@ -14,7 +14,11 @@ var Actionscript3 = internal.Register(MustNewLexer(
MimeTypes: []string{"application/x-actionscript3", "text/x-actionscript3", "text/actionscript3"},
DotAll: true,
},
Rules{
actionscript3Rules,
))
func actionscript3Rules() Rules {
return Rules{
"root": {
{`\s+`, Text, nil},
{`(function\s+)([$a-zA-Z_]\w*)(\s*)(\()`, ByGroups(KeywordDeclaration, NameFunction, Text, Operator), Push("funcparams")},
@ -52,5 +56,5 @@ var Actionscript3 = internal.Register(MustNewLexer(
{`,`, Operator, Pop(1)},
Default(Pop(1)),
},
},
))
}
}

View File

@ -6,7 +6,7 @@ import (
)
// Ada lexer.
var Ada = internal.Register(MustNewLexer(
var Ada = internal.Register(MustNewLazyLexer(
&Config{
Name: "Ada",
Aliases: []string{"ada", "ada95", "ada2005"},
@ -14,7 +14,11 @@ var Ada = internal.Register(MustNewLexer(
MimeTypes: []string{"text/x-ada"},
CaseInsensitive: true,
},
Rules{
adaRules,
))
func adaRules() Rules {
return Rules{
"root": {
{`[^\S\n]+`, Text, nil},
{`--.*?\n`, CommentSingle, nil},
@ -110,5 +114,5 @@ var Ada = internal.Register(MustNewLexer(
{`\)`, Punctuation, Pop(1)},
Include("root"),
},
},
))
}
}

48
vendor/github.com/alecthomas/chroma/lexers/a/al.go generated vendored Normal file
View File

@ -0,0 +1,48 @@
package a
import (
. "github.com/alecthomas/chroma" // nolint
"github.com/alecthomas/chroma/lexers/internal"
)
// Al lexer.
var Al = internal.Register(MustNewLazyLexer(
&Config{
Name: "AL",
Aliases: []string{"al"},
Filenames: []string{"*.al", "*.dal"},
MimeTypes: []string{"text/x-al"},
DotAll: true,
CaseInsensitive: true,
},
alRules,
))
// https://github.com/microsoft/AL/blob/master/grammar/alsyntax.tmlanguage
func alRules() Rules {
return Rules{
"root": {
{`\s+`, TextWhitespace, nil},
{`(?s)\/\*.*?\\*\*\/`, CommentMultiline, nil},
{`(?s)//.*?\n`, CommentSingle, nil},
{`\"([^\"])*\"`, Text, nil},
{`'([^'])*'`, LiteralString, nil},
{`\b(?i:(ARRAY|ASSERTERROR|BEGIN|BREAK|CASE|DO|DOWNTO|ELSE|END|EVENT|EXIT|FOR|FOREACH|FUNCTION|IF|IMPLEMENTS|IN|INDATASET|INTERFACE|INTERNAL|LOCAL|OF|PROCEDURE|PROGRAM|PROTECTED|REPEAT|RUNONCLIENT|SECURITYFILTERING|SUPPRESSDISPOSE|TEMPORARY|THEN|TO|TRIGGER|UNTIL|VAR|WHILE|WITH|WITHEVENTS))\b`, Keyword, nil},
{`\b(?i:(AND|DIV|MOD|NOT|OR|XOR))\b`, OperatorWord, nil},
{`\b(?i:(AVERAGE|CONST|COUNT|EXIST|FIELD|FILTER|LOOKUP|MAX|MIN|ORDER|SORTING|SUM|TABLEDATA|UPPERLIMIT|WHERE|ASCENDING|DESCENDING))\b`, Keyword, nil},
// Added new objects types of BC 2021 wave 1 (REPORTEXTENSION|Entitlement|PermissionSet|PermissionSetExtension)
{`\b(?i:(CODEUNIT|PAGE|PAGEEXTENSION|PAGECUSTOMIZATION|DOTNET|ENUM|ENUMEXTENSION|VALUE|QUERY|REPORT|TABLE|TABLEEXTENSION|XMLPORT|PROFILE|CONTROLADDIN|REPORTEXTENSION|Entitlement|PermissionSet|PermissionSetExtension))\b`, Keyword, nil},
{`\b(?i:(Action|Array|Automation|BigInteger|BigText|Blob|Boolean|Byte|Char|ClientType|Code|Codeunit|CompletionTriggerErrorLevel|ConnectionType|Database|DataClassification|DataScope|Date|DateFormula|DateTime|Decimal|DefaultLayout|Dialog|Dictionary|DotNet|DotNetAssembly|DotNetTypeDeclaration|Duration|Enum|ErrorInfo|ErrorType|ExecutionContext|ExecutionMode|FieldClass|FieldRef|FieldType|File|FilterPageBuilder|Guid|InStream|Integer|Joker|KeyRef|List|ModuleDependencyInfo|ModuleInfo|None|Notification|NotificationScope|ObjectType|Option|OutStream|Page|PageResult|Query|Record|RecordId|RecordRef|Report|ReportFormat|SecurityFilter|SecurityFiltering|Table|TableConnectionType|TableFilter|TestAction|TestField|TestFilterField|TestPage|TestPermissions|TestRequestPage|Text|TextBuilder|TextConst|TextEncoding|Time|TransactionModel|TransactionType|Variant|Verbosity|Version|XmlPort|HttpContent|HttpHeaders|HttpClient|HttpRequestMessage|HttpResponseMessage|JsonToken|JsonValue|JsonArray|JsonObject|View|Views|XmlAttribute|XmlAttributeCollection|XmlComment|XmlCData|XmlDeclaration|XmlDocument|XmlDocumentType|XmlElement|XmlNamespaceManager|XmlNameTable|XmlNode|XmlNodeList|XmlProcessingInstruction|XmlReadOptions|XmlText|XmlWriteOptions|WebServiceActionContext|WebServiceActionResultCode|SessionSettings))\b`, Keyword, nil},
{`\b([<>]=|<>|<|>)\b?`, Operator, nil},
{`\b(\-|\+|\/|\*)\b`, Operator, nil},
{`\s*(\:=|\+=|-=|\/=|\*=)\s*?`, Operator, nil},
{`\b(?i:(ADDFIRST|ADDLAST|ADDAFTER|ADDBEFORE|ACTION|ACTIONS|AREA|ASSEMBLY|CHARTPART|CUEGROUP|CUSTOMIZES|COLUMN|DATAITEM|DATASET|ELEMENTS|EXTENDS|FIELD|FIELDGROUP|FIELDATTRIBUTE|FIELDELEMENT|FIELDGROUPS|FIELDS|FILTER|FIXED|GRID|GROUP|MOVEAFTER|MOVEBEFORE|KEY|KEYS|LABEL|LABELS|LAYOUT|MODIFY|MOVEFIRST|MOVELAST|MOVEBEFORE|MOVEAFTER|PART|REPEATER|USERCONTROL|REQUESTPAGE|SCHEMA|SEPARATOR|SYSTEMPART|TABLEELEMENT|TEXTATTRIBUTE|TEXTELEMENT|TYPE))\b`, Keyword, nil},
{`\s*[(\.\.)&\|]\s*`, Operator, nil},
{`\b((0(x|X)[0-9a-fA-F]*)|(([0-9]+\.?[0-9]*)|(\.[0-9]+))((e|E)(\+|-)?[0-9]+)?)(L|l|UL|ul|u|U|F|f|ll|LL|ull|ULL)?\b`, LiteralNumber, nil},
{`[;:,]`, Punctuation, nil},
{`#[ \t]*(if|else|elif|endif|define|undef|region|endregion|pragma)\b.*?\n`, CommentPreproc, nil},
{`\w+`, Text, nil},
{`.`, Text, nil},
},
}
}

View File

@ -6,14 +6,18 @@ import (
)
// Angular2 lexer.
var Angular2 = internal.Register(MustNewLexer(
var Angular2 = internal.Register(MustNewLazyLexer(
&Config{
Name: "Angular2",
Aliases: []string{"ng2"},
Filenames: []string{},
MimeTypes: []string{},
},
Rules{
angular2Rules,
))
func angular2Rules() Rules {
return Rules{
"root": {
{`[^{([*#]+`, Other, nil},
{`(\{\{)(\s*)`, ByGroups(CommentPreproc, Text), Push("ngExpression")},
@ -38,5 +42,5 @@ var Angular2 = internal.Register(MustNewLexer(
{`'.*?'`, LiteralString, Pop(1)},
{`[^\s>]+`, LiteralString, Pop(1)},
},
},
))
}
}

View File

@ -6,14 +6,18 @@ import (
)
// ANTLR lexer.
var ANTLR = internal.Register(MustNewLexer(
var ANTLR = internal.Register(MustNewLazyLexer(
&Config{
Name: "ANTLR",
Aliases: []string{"antlr"},
Filenames: []string{},
MimeTypes: []string{},
},
Rules{
antlrRules,
))
func antlrRules() Rules {
return Rules{
"whitespace": {
{`\s+`, TextWhitespace, nil},
},
@ -97,5 +101,5 @@ var ANTLR = internal.Register(MustNewLexer(
{`(\$[a-zA-Z]+)(\.?)(text|value)?`, ByGroups(NameVariable, Punctuation, NameProperty), nil},
{`(\\\\|\\\]|\\\[|[^\[\]])+`, Other, nil},
},
},
))
}
}

View File

@ -6,7 +6,7 @@ import (
)
// Apacheconf lexer.
var Apacheconf = internal.Register(MustNewLexer(
var Apacheconf = internal.Register(MustNewLazyLexer(
&Config{
Name: "ApacheConf",
Aliases: []string{"apacheconf", "aconf", "apache"},
@ -14,7 +14,11 @@ var Apacheconf = internal.Register(MustNewLexer(
MimeTypes: []string{"text/x-apacheconf"},
CaseInsensitive: true,
},
Rules{
apacheconfRules,
))
func apacheconfRules() Rules {
return Rules{
"root": {
{`\s+`, Text, nil},
{`(#.*?)$`, Comment, nil},
@ -34,5 +38,5 @@ var Apacheconf = internal.Register(MustNewLexer(
{`"([^"\\]*(?:\\.[^"\\]*)*)"`, LiteralStringDouble, nil},
{`[^\s"\\]+`, Text, nil},
},
},
))
}
}

View File

@ -6,14 +6,18 @@ import (
)
// Apl lexer.
var Apl = internal.Register(MustNewLexer(
var Apl = internal.Register(MustNewLazyLexer(
&Config{
Name: "APL",
Aliases: []string{"apl"},
Filenames: []string{"*.apl"},
MimeTypes: []string{},
},
Rules{
aplRules,
))
func aplRules() Rules {
return Rules{
"root": {
{`\s+`, Text, nil},
{`[⍝#].*$`, CommentSingle, nil},
@ -32,5 +36,5 @@ var Apl = internal.Register(MustNewLexer(
{`[⍺⍵⍶⍹∇:]`, NameBuiltinPseudo, nil},
{`[{}]`, KeywordType, nil},
},
},
))
}
}

View File

@ -6,7 +6,7 @@ import (
)
// Applescript lexer.
var Applescript = internal.Register(MustNewLexer(
var Applescript = internal.Register(MustNewLazyLexer(
&Config{
Name: "AppleScript",
Aliases: []string{"applescript"},
@ -14,7 +14,11 @@ var Applescript = internal.Register(MustNewLexer(
MimeTypes: []string{},
DotAll: true,
},
Rules{
applescriptRules,
))
func applescriptRules() Rules {
return Rules{
"root": {
{`\s+`, Text, nil},
{`¬\n`, LiteralStringEscape, nil},
@ -51,5 +55,5 @@ var Applescript = internal.Register(MustNewLexer(
{`[^*(]+`, CommentMultiline, nil},
{`[*(]`, CommentMultiline, nil},
},
},
))
}
}

View File

@ -6,7 +6,7 @@ import (
)
// Arduino lexer.
var Arduino = internal.Register(MustNewLexer(
var Arduino = internal.Register(MustNewLazyLexer(
&Config{
Name: "Arduino",
Aliases: []string{"arduino"},
@ -14,7 +14,11 @@ var Arduino = internal.Register(MustNewLexer(
MimeTypes: []string{"text/x-arduino"},
EnsureNL: true,
},
Rules{
arduinoRules,
))
func arduinoRules() Rules {
return Rules{
"statements": {
{Words(``, `\b`, `catch`, `const_cast`, `delete`, `dynamic_cast`, `explicit`, `export`, `friend`, `mutable`, `namespace`, `new`, `operator`, `private`, `protected`, `public`, `reinterpret_cast`, `restrict`, `static_cast`, `template`, `this`, `throw`, `throws`, `try`, `typeid`, `typename`, `using`, `virtual`, `constexpr`, `nullptr`, `decltype`, `thread_local`, `alignas`, `alignof`, `static_assert`, `noexcept`, `override`, `final`), Keyword, nil},
{`char(16_t|32_t)\b`, KeywordType, nil},
@ -106,5 +110,5 @@ var Arduino = internal.Register(MustNewLexer(
{`^\s*#endif.*?(?<!\\)\n`, CommentPreproc, Pop(1)},
{`.*?\n`, Comment, nil},
},
},
))
}
}

View File

@ -6,14 +6,18 @@ import (
)
// Awk lexer.
var Awk = internal.Register(MustNewLexer(
var Awk = internal.Register(MustNewLazyLexer(
&Config{
Name: "Awk",
Aliases: []string{"awk", "gawk", "mawk", "nawk"},
Filenames: []string{"*.awk"},
MimeTypes: []string{"application/x-awk"},
},
Rules{
awkRules,
))
func awkRules() Rules {
return Rules{
"commentsandwhitespace": {
{`\s+`, Text, nil},
{`#.*$`, CommentSingle, nil},
@ -30,19 +34,19 @@ var Awk = internal.Register(MustNewLexer(
"root": {
{`^(?=\s|/)`, Text, Push("slashstartsregex")},
Include("commentsandwhitespace"),
{`\+\+|--|\|\||&&|in\b|\$|!?~|(\*\*|[-<>+*%\^/!=|])=?`, Operator, Push("slashstartsregex")},
{`\+\+|--|\|\||&&|in\b|\$|!?~|\|&|(\*\*|[-<>+*%\^/!=|])=?`, Operator, Push("slashstartsregex")},
{`[{(\[;,]`, Punctuation, Push("slashstartsregex")},
{`[})\].]`, Punctuation, nil},
{`(break|continue|do|while|exit|for|if|else|return)\b`, Keyword, Push("slashstartsregex")},
{`(break|continue|do|while|exit|for|if|else|return|switch|case|default)\b`, Keyword, Push("slashstartsregex")},
{`function\b`, KeywordDeclaration, Push("slashstartsregex")},
{`(atan2|cos|exp|int|log|rand|sin|sqrt|srand|gensub|gsub|index|length|match|split|sprintf|sub|substr|tolower|toupper|close|fflush|getline|next|nextfile|print|printf|strftime|systime|delete|system)\b`, KeywordReserved, nil},
{`(ARGC|ARGIND|ARGV|BEGIN|CONVFMT|ENVIRON|END|ERRNO|FIELDWIDTHS|FILENAME|FNR|FS|IGNORECASE|NF|NR|OFMT|OFS|ORFS|RLENGTH|RS|RSTART|RT|SUBSEP)\b`, NameBuiltin, nil},
{`[$a-zA-Z_]\w*`, NameOther, nil},
{`(atan2|cos|exp|int|log|rand|sin|sqrt|srand|gensub|gsub|index|length|match|split|patsplit|sprintf|sub|substr|tolower|toupper|close|fflush|getline|next(file)|print|printf|strftime|systime|mktime|delete|system|strtonum|and|compl|lshift|or|rshift|asorti?|isarray|bindtextdomain|dcn?gettext|@(include|load|namespace))\b`, KeywordReserved, nil},
{`(ARGC|ARGIND|ARGV|BEGIN(FILE)?|BINMODE|CONVFMT|ENVIRON|END(FILE)?|ERRNO|FIELDWIDTHS|FILENAME|FNR|FPAT|FS|IGNORECASE|LINT|NF|NR|OFMT|OFS|ORS|PROCINFO|RLENGTH|RS|RSTART|RT|SUBSEP|TEXTDOMAIN)\b`, NameBuiltin, nil},
{`[@$a-zA-Z_]\w*`, NameOther, nil},
{`[0-9][0-9]*\.[0-9]+([eE][0-9]+)?[fd]?`, LiteralNumberFloat, nil},
{`0x[0-9a-fA-F]+`, LiteralNumberHex, nil},
{`[0-9]+`, LiteralNumberInteger, nil},
{`"(\\\\|\\"|[^"])*"`, LiteralStringDouble, nil},
{`'(\\\\|\\'|[^'])*'`, LiteralStringSingle, nil},
},
},
))
}
}

View File

@ -6,7 +6,7 @@ import (
)
// Ballerina lexer.
var Ballerina = internal.Register(MustNewLexer(
var Ballerina = internal.Register(MustNewLazyLexer(
&Config{
Name: "Ballerina",
Aliases: []string{"ballerina"},
@ -14,7 +14,11 @@ var Ballerina = internal.Register(MustNewLexer(
MimeTypes: []string{"text/x-ballerina"},
DotAll: true,
},
Rules{
ballerinaRules,
))
func ballerinaRules() Rules {
return Rules{
"root": {
{`[^\S\n]+`, Text, nil},
{`//.*?\n`, CommentSingle, nil},
@ -42,5 +46,5 @@ var Ballerina = internal.Register(MustNewLexer(
"import": {
{`[\w.]+`, NameNamespace, Pop(1)},
},
},
))
}
}

View File

@ -7,17 +7,27 @@ import (
"github.com/alecthomas/chroma/lexers/internal"
)
// TODO(moorereason): can this be factored away?
var bashAnalyserRe = regexp.MustCompile(`(?m)^#!.*/bin/(?:env |)(?:bash|zsh|sh|ksh)`)
// Bash lexer.
var Bash = internal.Register(MustNewLexer(
var Bash = internal.Register(MustNewLazyLexer(
&Config{
Name: "Bash",
Aliases: []string{"bash", "sh", "ksh", "zsh", "shell"},
Filenames: []string{"*.sh", "*.ksh", "*.bash", "*.ebuild", "*.eclass", "*.exheres-0", "*.exlib", "*.zsh", "*.zshrc", ".bashrc", "bashrc", ".bash_*", "bash_*", "zshrc", ".zshrc", "PKGBUILD"},
Filenames: []string{"*.sh", "*.ksh", "*.bash", "*.ebuild", "*.eclass", ".env", "*.env", "*.exheres-0", "*.exlib", "*.zsh", "*.zshrc", ".bashrc", "bashrc", ".bash_*", "bash_*", "zshrc", ".zshrc", "PKGBUILD"},
MimeTypes: []string{"application/x-sh", "application/x-shellscript"},
},
Rules{
bashRules,
).SetAnalyser(func(text string) float32 {
if bashAnalyserRe.FindString(text) != "" {
return 1.0
}
return 0.0
}))
func bashRules() Rules {
return Rules{
"root": {
Include("basic"),
{"`", LiteralStringBacktick, Push("backticks")},
@ -36,7 +46,7 @@ var Bash = internal.Register(MustNewLexer(
{`\b(if|fi|else|while|do|done|for|then|return|function|case|select|continue|until|esac|elif)(\s*)\b`, ByGroups(Keyword, Text), nil},
{"\\b(alias|bg|bind|break|builtin|caller|cd|command|compgen|complete|declare|dirs|disown|echo|enable|eval|exec|exit|export|false|fc|fg|getopts|hash|help|history|jobs|kill|let|local|logout|popd|printf|pushd|pwd|read|readonly|set|shift|shopt|source|suspend|test|time|times|trap|true|type|typeset|ulimit|umask|unalias|unset|wait)(?=[\\s)`])", NameBuiltin, nil},
{`\A#!.+\n`, CommentPreproc, nil},
{`#.*\S`, CommentSingle, nil},
{`#.*(\S|$)`, CommentSingle, nil},
{`\\[\w\W]`, LiteralStringEscape, nil},
{`(\b\w+)(\s*)(\+?=)`, ByGroups(NameVariable, Text, Operator), nil},
{`[\[\]{}()=]`, Operator, nil},
@ -86,10 +96,5 @@ var Bash = internal.Register(MustNewLexer(
{"`", LiteralStringBacktick, Pop(1)},
Include("root"),
},
},
).SetAnalyser(func(text string) float32 {
if bashAnalyserRe.FindString(text) != "" {
return 1.0
}
return 0.0
}))
}

View File

@ -6,7 +6,7 @@ import (
)
// Batchfile lexer.
var Batchfile = internal.Register(MustNewLexer(
var Batchfile = internal.Register(MustNewLazyLexer(
&Config{
Name: "Batchfile",
Aliases: []string{"bat", "batch", "dosbatch", "winbatch"},
@ -14,7 +14,11 @@ var Batchfile = internal.Register(MustNewLexer(
MimeTypes: []string{"application/x-dos-batch"},
CaseInsensitive: true,
},
Rules{
batchfileRules,
))
func batchfileRules() Rules {
return Rules{
"root": {
{`\)((?=\()|(?=\^?[\t\v\f\r ,;=\xa0]|[&<>|\n\x1a]))(?:(?:[^\n\x1a^]|\^[\n\x1a]?[\w\W])*)`, CommentSingle, nil},
{`(?=((?:(?<=^[^:])|^[^:]?)[\t\v\f\r ,;=\xa0]*)(:))`, Text, Push("follow")},
@ -190,5 +194,5 @@ var Batchfile = internal.Register(MustNewLexer(
{`else(?=\^?[\t\v\f\r ,;=\xa0]|[&<>|\n\x1a])`, Keyword, Pop(1)},
Default(Pop(1)),
},
},
))
}
}

View File

@ -6,7 +6,7 @@ import (
)
// Bibtex lexer.
var Bibtex = internal.Register(MustNewLexer(
var Bibtex = internal.Register(MustNewLazyLexer(
&Config{
Name: "BibTeX",
Aliases: []string{"bib", "bibtex"},
@ -15,7 +15,11 @@ var Bibtex = internal.Register(MustNewLexer(
NotMultiline: true,
CaseInsensitive: true,
},
Rules{
bibtexRules,
))
func bibtexRules() Rules {
return Rules{
"root": {
Include("whitespace"),
{`@comment`, Comment, nil},
@ -72,5 +76,5 @@ var Bibtex = internal.Register(MustNewLexer(
"whitespace": {
{`\s+`, Text, nil},
},
},
))
}
}

View File

@ -6,7 +6,7 @@ import (
)
// Blitzbasic lexer.
var Blitzbasic = internal.Register(MustNewLexer(
var Blitzbasic = internal.Register(MustNewLazyLexer(
&Config{
Name: "BlitzBasic",
Aliases: []string{"blitzbasic", "b3d", "bplus"},
@ -14,7 +14,11 @@ var Blitzbasic = internal.Register(MustNewLexer(
MimeTypes: []string{"text/x-bb"},
CaseInsensitive: true,
},
Rules{
blitzbasicRules,
))
func blitzbasicRules() Rules {
return Rules{
"root": {
{`[ \t]+`, Text, nil},
{`;.*?\n`, CommentSingle, nil},
@ -44,5 +48,5 @@ var Blitzbasic = internal.Register(MustNewLexer(
{`"C?`, LiteralStringDouble, Pop(1)},
{`[^"]+`, LiteralStringDouble, nil},
},
},
))
}
}

View File

@ -6,19 +6,23 @@ import (
)
// Bnf lexer.
var Bnf = internal.Register(MustNewLexer(
var Bnf = internal.Register(MustNewLazyLexer(
&Config{
Name: "BNF",
Aliases: []string{"bnf"},
Filenames: []string{"*.bnf"},
MimeTypes: []string{"text/x-bnf"},
},
Rules{
bnfRules,
))
func bnfRules() Rules {
return Rules{
"root": {
{`(<)([ -;=?-~]+)(>)`, ByGroups(Punctuation, NameClass, Punctuation), nil},
{`::=`, Operator, nil},
{`[^<>:]+`, Text, nil},
{`.`, Text, nil},
},
},
))
}
}

View File

@ -6,14 +6,18 @@ import (
)
// Brainfuck lexer.
var Brainfuck = internal.Register(MustNewLexer(
var Brainfuck = internal.Register(MustNewLazyLexer(
&Config{
Name: "Brainfuck",
Aliases: []string{"brainfuck", "bf"},
Filenames: []string{"*.bf", "*.b"},
MimeTypes: []string{"application/x-brainfuck"},
},
Rules{
brainfuckRules,
))
func brainfuckRules() Rules {
return Rules{
"common": {
{`[.,]+`, NameTag, nil},
{`[+-]+`, NameBuiltin, nil},
@ -30,5 +34,5 @@ var Brainfuck = internal.Register(MustNewLexer(
{`\]`, Keyword, Pop(1)},
Include("common"),
},
},
))
}
}

View File

@ -6,14 +6,19 @@ import (
)
// C lexer.
var C = internal.Register(MustNewLexer(
var C = internal.Register(MustNewLazyLexer(
&Config{
Name: "C",
Aliases: []string{"c"},
Filenames: []string{"*.c", "*.h", "*.idc"},
MimeTypes: []string{"text/x-chdr", "text/x-csrc"},
EnsureNL: true,
},
Rules{
cRules,
))
func cRules() Rules {
return Rules{
"whitespace": {
{`^#if\s+0`, CommentPreproc, Push("if0")},
{`^#`, CommentPreproc, Push("macro")},
@ -87,5 +92,5 @@ var C = internal.Register(MustNewLexer(
{`^\s*#endif.*?(?<!\\)\n`, CommentPreproc, Pop(1)},
{`.*?\n`, Comment, nil},
},
},
))
}
}

View File

@ -0,0 +1,216 @@
package c
import (
. "github.com/alecthomas/chroma" // nolint
"github.com/alecthomas/chroma/lexers/internal"
)
// caddyfileCommon are the rules common to both of the lexer variants
func caddyfileCommonRules() Rules {
return Rules{
"site_block_common": {
// Import keyword
{`(import)(\s+)([^\s]+)`, ByGroups(Keyword, Text, NameVariableMagic), nil},
// Matcher definition
{`@[^\s]+(?=\s)`, NameDecorator, Push("matcher")},
// Matcher token stub for docs
{`\[\<matcher\>\]`, NameDecorator, Push("matcher")},
// These cannot have matchers but may have things that look like
// matchers in their arguments, so we just parse as a subdirective.
{`try_files`, Keyword, Push("subdirective")},
// These are special, they can nest more directives
{`handle_errors|handle|route|handle_path|not`, Keyword, Push("nested_directive")},
// Any other directive
{`[^\s#]+`, Keyword, Push("directive")},
Include("base"),
},
"matcher": {
{`\{`, Punctuation, Push("block")},
// Not can be one-liner
{`not`, Keyword, Push("deep_not_matcher")},
// Any other same-line matcher
{`[^\s#]+`, Keyword, Push("arguments")},
// Terminators
{`\n`, Text, Pop(1)},
{`\}`, Punctuation, Pop(1)},
Include("base"),
},
"block": {
{`\}`, Punctuation, Pop(2)},
// Not can be one-liner
{`not`, Keyword, Push("not_matcher")},
// Any other subdirective
{`[^\s#]+`, Keyword, Push("subdirective")},
Include("base"),
},
"nested_block": {
{`\}`, Punctuation, Pop(2)},
// Matcher definition
{`@[^\s]+(?=\s)`, NameDecorator, Push("matcher")},
// Something that starts with literally < is probably a docs stub
{`\<[^#]+\>`, Keyword, Push("nested_directive")},
// Any other directive
{`[^\s#]+`, Keyword, Push("nested_directive")},
Include("base"),
},
"not_matcher": {
{`\}`, Punctuation, Pop(2)},
{`\{(?=\s)`, Punctuation, Push("block")},
{`[^\s#]+`, Keyword, Push("arguments")},
{`\s+`, Text, nil},
},
"deep_not_matcher": {
{`\}`, Punctuation, Pop(2)},
{`\{(?=\s)`, Punctuation, Push("block")},
{`[^\s#]+`, Keyword, Push("deep_subdirective")},
{`\s+`, Text, nil},
},
"directive": {
{`\{(?=\s)`, Punctuation, Push("block")},
Include("matcher_token"),
Include("comments_pop_1"),
{`\n`, Text, Pop(1)},
Include("base"),
},
"nested_directive": {
{`\{(?=\s)`, Punctuation, Push("nested_block")},
Include("matcher_token"),
Include("comments_pop_1"),
{`\n`, Text, Pop(1)},
Include("base"),
},
"subdirective": {
{`\{(?=\s)`, Punctuation, Push("block")},
Include("comments_pop_1"),
{`\n`, Text, Pop(1)},
Include("base"),
},
"arguments": {
{`\{(?=\s)`, Punctuation, Push("block")},
Include("comments_pop_2"),
{`\\\n`, Text, nil}, // Skip escaped newlines
{`\n`, Text, Pop(2)},
Include("base"),
},
"deep_subdirective": {
{`\{(?=\s)`, Punctuation, Push("block")},
Include("comments_pop_3"),
{`\n`, Text, Pop(3)},
Include("base"),
},
"matcher_token": {
{`@[^\s]+`, NameDecorator, Push("arguments")}, // Named matcher
{`/[^\s]+`, NameDecorator, Push("arguments")}, // Path matcher
{`\*`, NameDecorator, Push("arguments")}, // Wildcard path matcher
{`\[\<matcher\>\]`, NameDecorator, Push("arguments")}, // Matcher token stub for docs
},
"comments": {
{`^#.*\n`, CommentSingle, nil}, // Comment at start of line
{`\s+#.*\n`, CommentSingle, nil}, // Comment preceded by whitespace
},
"comments_pop_1": {
{`^#.*\n`, CommentSingle, Pop(1)}, // Comment at start of line
{`\s+#.*\n`, CommentSingle, Pop(1)}, // Comment preceded by whitespace
},
"comments_pop_2": {
{`^#.*\n`, CommentSingle, Pop(2)}, // Comment at start of line
{`\s+#.*\n`, CommentSingle, Pop(2)}, // Comment preceded by whitespace
},
"comments_pop_3": {
{`^#.*\n`, CommentSingle, Pop(3)}, // Comment at start of line
{`\s+#.*\n`, CommentSingle, Pop(3)}, // Comment preceded by whitespace
},
"base": {
Include("comments"),
{`(on|off|first|last|before|after|internal|strip_prefix|strip_suffix|replace)\b`, NameConstant, nil},
{`(https?://)?([a-z0-9.-]+)(:)([0-9]+)`, ByGroups(Name, Name, Punctuation, LiteralNumberInteger), nil},
{`[a-z-]+/[a-z-+]+`, LiteralString, nil},
{`[0-9]+[km]?\b`, LiteralNumberInteger, nil},
{`\{[\w+.\$-]+\}`, LiteralStringEscape, nil}, // Placeholder
{`\[(?=[^#{}$]+\])`, Punctuation, nil},
{`\]|\|`, Punctuation, nil},
{`[^\s#{}$\]]+`, LiteralString, nil},
{`/[^\s#]*`, Name, nil},
{`\s+`, Text, nil},
},
}
}
// Caddyfile lexer.
var Caddyfile = internal.Register(MustNewLazyLexer(
&Config{
Name: "Caddyfile",
Aliases: []string{"caddyfile", "caddy"},
Filenames: []string{"Caddyfile*"},
MimeTypes: []string{},
},
caddyfileRules,
))
func caddyfileRules() Rules {
return Rules{
"root": {
Include("comments"),
// Global options block
{`^\s*(\{)\s*$`, ByGroups(Punctuation), Push("globals")},
// Snippets
{`(\([^\s#]+\))(\s*)(\{)`, ByGroups(NameVariableAnonymous, Text, Punctuation), Push("snippet")},
// Site label
{`[^#{(\s,]+`, GenericHeading, Push("label")},
// Site label with placeholder
{`\{[\w+.\$-]+\}`, LiteralStringEscape, Push("label")},
{`\s+`, Text, nil},
},
"globals": {
{`\}`, Punctuation, Pop(1)},
{`[^\s#]+`, Keyword, Push("directive")},
Include("base"),
},
"snippet": {
{`\}`, Punctuation, Pop(1)},
// Matcher definition
{`@[^\s]+(?=\s)`, NameDecorator, Push("matcher")},
// Any directive
{`[^\s#]+`, Keyword, Push("directive")},
Include("base"),
},
"label": {
// Allow multiple labels, comma separated, newlines after
// a comma means another label is coming
{`,\s*\n?`, Text, nil},
{` `, Text, nil},
// Site label with placeholder
{`\{[\w+.\$-]+\}`, LiteralStringEscape, nil},
// Site label
{`[^#{(\s,]+`, GenericHeading, nil},
// Comment after non-block label (hack because comments end in \n)
{`#.*\n`, CommentSingle, Push("site_block")},
// Note: if \n, we'll never pop out of the site_block, it's valid
{`\{(?=\s)|\n`, Punctuation, Push("site_block")},
},
"site_block": {
{`\}`, Punctuation, Pop(2)},
Include("site_block_common"),
},
}.Merge(caddyfileCommonRules())
}
// Caddyfile directive-only lexer.
var CaddyfileDirectives = internal.Register(MustNewLazyLexer(
&Config{
Name: "Caddyfile Directives",
Aliases: []string{"caddyfile-directives", "caddyfile-d", "caddy-d"},
Filenames: []string{},
MimeTypes: []string{},
},
caddyfileDirectivesRules,
))
func caddyfileDirectivesRules() Rules {
return Rules{
// Same as "site_block" in Caddyfile
"root": {
Include("site_block_common"),
},
}.Merge(caddyfileCommonRules())
}

View File

@ -6,14 +6,18 @@ import (
)
// Cap'N'Proto Proto lexer.
var CapNProto = internal.Register(MustNewLexer(
var CapNProto = internal.Register(MustNewLazyLexer(
&Config{
Name: "Cap'n Proto",
Aliases: []string{"capnp"},
Filenames: []string{"*.capnp"},
MimeTypes: []string{},
},
Rules{
capNProtoRules,
))
func capNProtoRules() Rules {
return Rules{
"root": {
{`#.*?$`, CommentSingle, nil},
{`@[0-9a-zA-Z]*`, NameDecorator, nil},
@ -57,5 +61,5 @@ var CapNProto = internal.Register(MustNewLexer(
{`[])]`, NameAttribute, Pop(1)},
Default(Pop(1)),
},
},
))
}
}

View File

@ -6,7 +6,7 @@ import (
)
// Ceylon lexer.
var Ceylon = internal.Register(MustNewLexer(
var Ceylon = internal.Register(MustNewLazyLexer(
&Config{
Name: "Ceylon",
Aliases: []string{"ceylon"},
@ -14,7 +14,11 @@ var Ceylon = internal.Register(MustNewLexer(
MimeTypes: []string{"text/x-ceylon"},
DotAll: true,
},
Rules{
ceylonRules,
))
func ceylonRules() Rules {
return Rules{
"root": {
{`^(\s*(?:[a-zA-Z_][\w.\[\]]*\s+)+?)([a-zA-Z_]\w*)(\s*)(\()`, ByGroups(UsingSelf("root"), NameFunction, Text, Operator), nil},
{`[^\S\n]+`, Text, nil},
@ -59,5 +63,5 @@ var Ceylon = internal.Register(MustNewLexer(
{`\*/`, CommentMultiline, Pop(1)},
{`[*/]`, CommentMultiline, nil},
},
},
))
}
}

View File

@ -6,14 +6,18 @@ import (
)
// Cfengine3 lexer.
var Cfengine3 = internal.Register(MustNewLexer(
var Cfengine3 = internal.Register(MustNewLazyLexer(
&Config{
Name: "CFEngine3",
Aliases: []string{"cfengine3", "cf3"},
Filenames: []string{"*.cf"},
MimeTypes: []string{},
},
Rules{
cfengine3Rules,
))
func cfengine3Rules() Rules {
return Rules{
"root": {
{`#.*?\n`, Comment, nil},
{`(body)(\s+)(\S+)(\s+)(control)`, ByGroups(Keyword, Text, Keyword, Text, Keyword), nil},
@ -52,5 +56,5 @@ var Cfengine3 = internal.Register(MustNewLexer(
{`\w+`, NameVariable, nil},
{`\s+`, Text, nil},
},
},
))
}
}

View File

@ -6,7 +6,7 @@ import (
)
// Chaiscript lexer.
var Chaiscript = internal.Register(MustNewLexer(
var Chaiscript = internal.Register(MustNewLazyLexer(
&Config{
Name: "ChaiScript",
Aliases: []string{"chai", "chaiscript"},
@ -14,7 +14,11 @@ var Chaiscript = internal.Register(MustNewLexer(
MimeTypes: []string{"text/x-chaiscript", "application/x-chaiscript"},
DotAll: true,
},
Rules{
chaiscriptRules,
))
func chaiscriptRules() Rules {
return Rules{
"commentsandwhitespace": {
{`\s+`, Text, nil},
{`//.*?\n`, CommentSingle, nil},
@ -59,5 +63,5 @@ var Chaiscript = internal.Register(MustNewLexer(
{`[^\\"$]+`, LiteralStringDouble, nil},
{`"`, LiteralStringDouble, Pop(1)},
},
},
))
}
}

View File

@ -7,14 +7,18 @@ import (
)
// Cheetah lexer.
var Cheetah = internal.Register(MustNewLexer(
var Cheetah = internal.Register(MustNewLazyLexer(
&Config{
Name: "Cheetah",
Aliases: []string{"cheetah", "spitfire"},
Filenames: []string{"*.tmpl", "*.spt"},
MimeTypes: []string{"application/x-cheetah", "application/x-spitfire"},
},
Rules{
cheetahRules,
))
func cheetahRules() Rules {
return Rules{
"root": {
{`(##[^\n]*)$`, ByGroups(Comment), nil},
{`#[*](.|\n)*?[*]#`, Comment, nil},
@ -33,5 +37,5 @@ var Cheetah = internal.Register(MustNewLexer(
`, Other, nil},
{`\s+`, Text, nil},
},
},
))
}
}

View File

@ -230,7 +230,7 @@ var (
)
// Common Lisp lexer.
var CommonLisp = internal.Register(TypeRemappingLexer(MustNewLexer(
var CommonLisp = internal.Register(TypeRemappingLexer(MustNewLazyLexer(
&Config{
Name: "Common Lisp",
Aliases: []string{"common-lisp", "cl", "lisp"},
@ -238,7 +238,19 @@ var CommonLisp = internal.Register(TypeRemappingLexer(MustNewLexer(
MimeTypes: []string{"text/x-common-lisp"},
CaseInsensitive: true,
},
Rules{
commonLispRules,
), TypeMapping{
{NameVariable, NameFunction, clBuiltinFunctions},
{NameVariable, Keyword, clSpecialForms},
{NameVariable, NameBuiltin, clMacros},
{NameVariable, Keyword, clLambdaListKeywords},
{NameVariable, Keyword, clDeclarations},
{NameVariable, KeywordType, clBuiltinTypes},
{NameVariable, NameClass, clBuiltinClasses},
}))
func commonLispRules() Rules {
return Rules{
"root": {
Default(Push("body")),
},
@ -294,13 +306,5 @@ var CommonLisp = internal.Register(TypeRemappingLexer(MustNewLexer(
{`\(`, Punctuation, Push("body")},
{`\)`, Punctuation, Pop(1)},
},
},
), TypeMapping{
{NameVariable, NameFunction, clBuiltinFunctions},
{NameVariable, Keyword, clSpecialForms},
{NameVariable, NameBuiltin, clMacros},
{NameVariable, Keyword, clLambdaListKeywords},
{NameVariable, Keyword, clDeclarations},
{NameVariable, KeywordType, clBuiltinTypes},
{NameVariable, NameClass, clBuiltinClasses},
}))
}
}

View File

@ -6,14 +6,18 @@ import (
)
// Clojure lexer.
var Clojure = internal.Register(MustNewLexer(
var Clojure = internal.Register(MustNewLazyLexer(
&Config{
Name: "Clojure",
Aliases: []string{"clojure", "clj"},
Filenames: []string{"*.clj"},
MimeTypes: []string{"text/x-clojure", "application/x-clojure"},
},
Rules{
clojureRules,
))
func clojureRules() Rules {
return Rules{
"root": {
{`;.*$`, CommentSingle, nil},
{`[,\s]+`, Text, nil},
@ -34,5 +38,5 @@ var Clojure = internal.Register(MustNewLexer(
{`(\{|\})`, Punctuation, nil},
{`(\(|\))`, Punctuation, nil},
},
},
))
}
}

View File

@ -6,14 +6,18 @@ import (
)
// Cmake lexer.
var Cmake = internal.Register(MustNewLexer(
var Cmake = internal.Register(MustNewLazyLexer(
&Config{
Name: "CMake",
Aliases: []string{"cmake"},
Filenames: []string{"*.cmake", "CMakeLists.txt"},
MimeTypes: []string{"text/x-cmake"},
},
Rules{
cmakeRules,
))
func cmakeRules() Rules {
return Rules{
"root": {
{`\b(\w+)([ \t]*)(\()`, ByGroups(NameBuiltin, Text, Punctuation), Push("args")},
Include("keywords"),
@ -40,5 +44,5 @@ var Cmake = internal.Register(MustNewLexer(
{`[ \t]+`, Text, nil},
{`#.*\n`, Comment, nil},
},
},
))
}
}

View File

@ -6,7 +6,7 @@ import (
)
// Cobol lexer.
var Cobol = internal.Register(MustNewLexer(
var Cobol = internal.Register(MustNewLazyLexer(
&Config{
Name: "COBOL",
Aliases: []string{"cobol"},
@ -14,7 +14,11 @@ var Cobol = internal.Register(MustNewLexer(
MimeTypes: []string{"text/x-cobol"},
CaseInsensitive: true,
},
Rules{
cobolRules,
))
func cobolRules() Rules {
return Rules{
"root": {
Include("comment"),
Include("strings"),
@ -47,5 +51,5 @@ var Cobol = internal.Register(MustNewLexer(
{`[+-]?\d*\.\d+(E[-+]?\d+)?`, LiteralNumberFloat, nil},
{`[+-]?\d+\.\d*(E[-+]?\d+)?`, LiteralNumberFloat, nil},
},
},
))
}
}

View File

@ -6,7 +6,7 @@ import (
)
// Coffeescript lexer.
var Coffeescript = internal.Register(MustNewLexer(
var Coffeescript = internal.Register(MustNewLazyLexer(
&Config{
Name: "CoffeeScript",
Aliases: []string{"coffee-script", "coffeescript", "coffee"},
@ -15,7 +15,11 @@ var Coffeescript = internal.Register(MustNewLexer(
NotMultiline: true,
DotAll: true,
},
Rules{
coffeescriptRules,
))
func coffeescriptRules() Rules {
return Rules{
"commentsandwhitespace": {
{`\s+`, Text, nil},
{`###[^#].*?###`, CommentMultiline, nil},
@ -87,5 +91,5 @@ var Coffeescript = internal.Register(MustNewLexer(
{`#|\\.|\'|"`, LiteralString, nil},
Include("strings"),
},
},
))
}
}

View File

@ -6,7 +6,7 @@ import (
)
// Cfstatement lexer.
var Cfstatement = internal.Register(MustNewLexer(
var Cfstatement = internal.Register(MustNewLazyLexer(
&Config{
Name: "cfstatement",
Aliases: []string{"cfs"},
@ -15,7 +15,11 @@ var Cfstatement = internal.Register(MustNewLexer(
NotMultiline: true,
CaseInsensitive: true,
},
Rules{
cfstatementRules,
))
func cfstatementRules() Rules {
return Rules{
"root": {
{`//.*?\n`, CommentSingle, nil},
{`/\*(?:.|\n)*?\*/`, CommentMultiline, nil},
@ -44,5 +48,5 @@ var Cfstatement = internal.Register(MustNewLexer(
{`#`, LiteralStringDouble, nil},
{`"`, LiteralStringDouble, Pop(1)},
},
},
))
}
}

View File

@ -6,14 +6,18 @@ import (
)
// Coq lexer.
var Coq = internal.Register(MustNewLexer(
var Coq = internal.Register(MustNewLazyLexer(
&Config{
Name: "Coq",
Aliases: []string{"coq"},
Filenames: []string{"*.v"},
MimeTypes: []string{"text/x-coq"},
},
Rules{
coqRules,
))
func coqRules() Rules {
return Rules{
"root": {
{`\s+`, Text, nil},
{`false|true|\(\)|\[\]`, NameBuiltinPseudo, nil},
@ -59,5 +63,5 @@ var Coq = internal.Register(MustNewLexer(
{`[a-z][a-z0-9_\']*`, Name, Pop(1)},
Default(Pop(1)),
},
},
))
}
}

View File

@ -6,7 +6,7 @@ import (
)
// CPP lexer.
var CPP = internal.Register(MustNewLexer(
var CPP = internal.Register(MustNewLazyLexer(
&Config{
Name: "C++",
Aliases: []string{"cpp", "c++"},
@ -14,7 +14,11 @@ var CPP = internal.Register(MustNewLexer(
MimeTypes: []string{"text/x-c++hdr", "text/x-c++src"},
EnsureNL: true,
},
Rules{
cppRules,
))
func cppRules() Rules {
return Rules{
"statements": {
{Words(``, `\b`, `catch`, `const_cast`, `delete`, `dynamic_cast`, `explicit`, `export`, `friend`, `mutable`, `namespace`, `new`, `operator`, `private`, `protected`, `public`, `reinterpret_cast`, `restrict`, `static_cast`, `template`, `this`, `throw`, `throws`, `try`, `typeid`, `typename`, `using`, `virtual`, `constexpr`, `nullptr`, `decltype`, `thread_local`, `alignas`, `alignof`, `static_assert`, `noexcept`, `override`, `final`, `concept`, `requires`, `consteval`, `co_await`, `co_return`, `co_yield`), Keyword, nil},
{`(enum)\b(\s+)(class)\b(\s*)`, ByGroups(Keyword, Text, Keyword, Text), Push("classname")},
@ -102,5 +106,5 @@ var CPP = internal.Register(MustNewLexer(
{`^\s*#endif.*?(?<!\\)\n`, CommentPreproc, Pop(1)},
{`.*?\n`, Comment, nil},
},
},
))
}
}

View File

@ -6,7 +6,7 @@ import (
)
// CassandraCQL lexer.
var CassandraCQL = internal.Register(MustNewLexer(
var CassandraCQL = internal.Register(MustNewLazyLexer(
&Config{
Name: "Cassandra CQL",
Aliases: []string{"cassandra", "cql"},
@ -15,7 +15,11 @@ var CassandraCQL = internal.Register(MustNewLexer(
NotMultiline: true,
CaseInsensitive: true,
},
Rules{
cassandraCQLRules,
))
func cassandraCQLRules() Rules {
return Rules{
"root": {
{`\s+`, TextWhitespace, nil},
{`(--|\/\/).*\n?`, CommentSingle, nil},
@ -23,7 +27,8 @@ var CassandraCQL = internal.Register(MustNewLexer(
{`(ascii|bigint|blob|boolean|counter|date|decimal|double|float|frozen|inet|int|list|map|set|smallint|text|time|timestamp|timeuuid|tinyint|tuple|uuid|varchar|varint)\b`, NameBuiltin, nil},
{Words(``, `\b`, `ADD`, `AGGREGATE`, `ALL`, `ALLOW`, `ALTER`, `AND`, `ANY`, `APPLY`, `AS`, `ASC`, `AUTHORIZE`, `BATCH`, `BEGIN`, `BY`, `CLUSTERING`, `COLUMNFAMILY`, `COMPACT`, `CONSISTENCY`, `COUNT`, `CREATE`, `CUSTOM`, `DELETE`, `DESC`, `DISTINCT`, `DROP`, `EACH_QUORUM`, `ENTRIES`, `EXISTS`, `FILTERING`, `FROM`, `FULL`, `GRANT`, `IF`, `IN`, `INDEX`, `INFINITY`, `INSERT`, `INTO`, `KEY`, `KEYS`, `KEYSPACE`, `KEYSPACES`, `LEVEL`, `LIMIT`, `LOCAL_ONE`, `LOCAL_QUORUM`, `MATERIALIZED`, `MODIFY`, `NAN`, `NORECURSIVE`, `NOSUPERUSER`, `NOT`, `OF`, `ON`, `ONE`, `ORDER`, `PARTITION`, `PASSWORD`, `PER`, `PERMISSION`, `PERMISSIONS`, `PRIMARY`, `QUORUM`, `RENAME`, `REVOKE`, `SCHEMA`, `SELECT`, `STATIC`, `STORAGE`, `SUPERUSER`, `TABLE`, `THREE`, `TO`, `TOKEN`, `TRUNCATE`, `TTL`, `TWO`, `TYPE`, `UNLOGGED`, `UPDATE`, `USE`, `USER`, `USERS`, `USING`, `VALUES`, `VIEW`, `WHERE`, `WITH`, `WRITETIME`, `REPLICATION`, `OR`, `REPLACE`, `FUNCTION`, `CALLED`, `INPUT`, `RETURNS`, `LANGUAGE`, `ROLE`, `ROLES`, `TRIGGER`, `DURABLE_WRITES`, `LOGIN`, `OPTIONS`, `LOGGED`, `SFUNC`, `STYPE`, `FINALFUNC`, `INITCOND`, `IS`, `CONTAINS`, `JSON`, `PAGING`, `OFF`), Keyword, nil},
{"[+*/<>=~!@#%^&|`?-]+", Operator, nil},
{`(?s)(java|javascript)(\s+)(AS)(\s+)('|\$\$)(.*?)(\5)`,
{
`(?s)(java|javascript)(\s+)(AS)(\s+)('|\$\$)(.*?)(\5)`,
UsingByGroup(
internal.Get,
1, 6,
@ -65,5 +70,5 @@ var CassandraCQL = internal.Register(MustNewLexer(
{`[^\$]+`, LiteralStringHeredoc, nil},
{`\$\$`, LiteralStringHeredoc, Pop(1)},
},
},
))
}
}

View File

@ -6,7 +6,7 @@ import (
)
// Crystal lexer.
var Crystal = internal.Register(MustNewLexer(
var Crystal = internal.Register(MustNewLazyLexer(
&Config{
Name: "Crystal",
Aliases: []string{"cr", "crystal"},
@ -14,7 +14,11 @@ var Crystal = internal.Register(MustNewLexer(
MimeTypes: []string{"text/x-crystal"},
DotAll: true,
},
Rules{
crystalRules,
))
func crystalRules() Rules {
return Rules{
"root": {
{`#.*?$`, CommentSingle, nil},
{Words(``, `\b`, `abstract`, `asm`, `as`, `begin`, `break`, `case`, `do`, `else`, `elsif`, `end`, `ensure`, `extend`, `ifdef`, `if`, `include`, `instance_sizeof`, `next`, `of`, `pointerof`, `private`, `protected`, `rescue`, `return`, `require`, `sizeof`, `super`, `then`, `typeof`, `unless`, `until`, `when`, `while`, `with`, `yield`), Keyword, nil},
@ -258,5 +262,5 @@ var Crystal = internal.Register(MustNewLexer(
{`[\\#<>]`, LiteralStringRegex, nil},
{`[^\\#<>]+`, LiteralStringRegex, nil},
},
},
))
}
}

View File

@ -6,7 +6,7 @@ import (
)
// CSharp lexer.
var CSharp = internal.Register(MustNewLexer(
var CSharp = internal.Register(MustNewLazyLexer(
&Config{
Name: "C#",
Aliases: []string{"csharp", "c#"},
@ -15,7 +15,11 @@ var CSharp = internal.Register(MustNewLexer(
DotAll: true,
EnsureNL: true,
},
Rules{
cSharpRules,
))
func cSharpRules() Rules {
return Rules{
"root": {
{`^\s*\[.*?\]`, NameAttribute, nil},
{`[^\S\n]+`, Text, nil},
@ -29,7 +33,7 @@ var CSharp = internal.Register(MustNewLexer(
{`\$@?"(""|[^"])*"`, LiteralString, nil},
{`"(\\\\|\\"|[^"\n])*["\n]`, LiteralString, nil},
{`'\\.'|'[^\\]'`, LiteralStringChar, nil},
{`[0-9](\.[0-9]*)?([eE][+-][0-9]+)?[flFLdD]?|0[xX][0-9a-fA-F]+[Ll]?`, LiteralNumber, nil},
{`0[xX][0-9a-fA-F]+[Ll]?|[0-9_](\.[0-9]*)?([eE][+-]?[0-9]+)?[flFLdD]?`, LiteralNumber, nil},
{`#[ \t]*(if|endif|else|elif|define|undef|line|error|warning|region|endregion|pragma)\b.*?\n`, CommentPreproc, nil},
{`\b(extern)(\s+)(alias)\b`, ByGroups(Keyword, Text, Keyword), nil},
{`(abstract|as|async|await|base|break|by|case|catch|checked|const|continue|default|delegate|do|else|enum|event|explicit|extern|false|finally|fixed|for|foreach|goto|if|implicit|in|interface|internal|is|let|lock|new|null|on|operator|out|override|params|private|protected|public|readonly|ref|return|sealed|sizeof|stackalloc|static|switch|this|throw|true|try|typeof|unchecked|unsafe|virtual|void|while|get|set|new|partial|yield|add|remove|value|alias|ascending|descending|from|group|into|orderby|select|thenby|where|join|equals)\b`, Keyword, nil},
@ -47,5 +51,5 @@ var CSharp = internal.Register(MustNewLexer(
{`(?=\()`, Text, Pop(1)},
{`(@?[_a-zA-Z]\w*|\.)+`, NameNamespace, Pop(1)},
},
},
))
}
}

View File

@ -6,14 +6,18 @@ import (
)
// CSS lexer.
var CSS = internal.Register(MustNewLexer(
var CSS = internal.Register(MustNewLazyLexer(
&Config{
Name: "CSS",
Aliases: []string{"css"},
Filenames: []string{"*.css"},
MimeTypes: []string{"text/css"},
},
Rules{
cssRules,
))
func cssRules() Rules {
return Rules{
"root": {
Include("basics"),
},
@ -39,6 +43,18 @@ var CSS = internal.Register(MustNewLexer(
Include("basics"),
{`\}`, Punctuation, Pop(2)},
},
"atparenthesis": {
Include("common-values"),
{`/\*(?:.|\n)*?\*/`, Comment, nil},
Include("numeric-values"),
{`[*+/-]`, Operator, nil},
{`[,]`, Punctuation, nil},
{`"(\\\\|\\"|[^"])*"`, LiteralStringDouble, nil},
{`'(\\\\|\\'|[^'])*'`, LiteralStringSingle, nil},
{`[a-zA-Z_-]\w*`, Name, nil},
{`\(`, Punctuation, Push("atparenthesis")},
{`\)`, Punctuation, Pop(1)},
},
"content": {
{`\s+`, Text, nil},
{`\}`, Punctuation, Pop(1)},
@ -73,6 +89,7 @@ var CSS = internal.Register(MustNewLexer(
{`"(\\\\|\\"|[^"])*"`, LiteralStringDouble, nil},
{`'(\\\\|\\'|[^'])*'`, LiteralStringSingle, nil},
{`[a-zA-Z_-]\w*`, Name, nil},
{`\(`, Punctuation, Push("atparenthesis")},
{`\)`, Punctuation, Pop(1)},
},
"common-values": {
@ -100,5 +117,5 @@ var CSS = internal.Register(MustNewLexer(
{`%`, KeywordType, nil},
Default(Pop(1)),
},
},
))
}
}

View File

@ -6,14 +6,18 @@ import (
)
// Cython lexer.
var Cython = internal.Register(MustNewLexer(
var Cython = internal.Register(MustNewLazyLexer(
&Config{
Name: "Cython",
Aliases: []string{"cython", "pyx", "pyrex"},
Filenames: []string{"*.pyx", "*.pxd", "*.pxi"},
MimeTypes: []string{"text/x-cython", "application/x-cython"},
},
Rules{
cythonRules,
))
func cythonRules() Rules {
return Rules{
"root": {
{`\n`, Text, nil},
{`^(\s*)("""(?:.|\n)*?""")`, ByGroups(Text, LiteralStringDoc), nil},
@ -131,5 +135,5 @@ var Cython = internal.Register(MustNewLexer(
Include("strings"),
Include("nl"),
},
},
))
}
}

View File

@ -1,15 +1,12 @@
package circular
import (
"strings"
. "github.com/alecthomas/chroma" // nolint
"github.com/alecthomas/chroma/lexers/h"
"github.com/alecthomas/chroma/lexers/internal"
)
// PHP lexer.
var PHP = internal.Register(DelegatingLexer(h.HTML, MustNewLexer(
// PHP lexer for pure PHP code (not embedded in HTML).
var PHP = internal.Register(MustNewLazyLexer(
&Config{
Name: "PHP",
Aliases: []string{"php", "php3", "php4", "php5"},
@ -19,12 +16,15 @@ var PHP = internal.Register(DelegatingLexer(h.HTML, MustNewLexer(
CaseInsensitive: true,
EnsureNL: true,
},
Rules{
"root": {
{`<\?(php)?`, CommentPreproc, Push("php")},
{`[^<]+`, Other, nil},
{`<`, Other, nil},
},
phpRules,
))
func phpRules() Rules {
return phpCommonRules().Rename("php", "root")
}
func phpCommonRules() Rules {
return Rules{
"php": {
{`\?>`, CommentPreproc, Pop(1)},
{`(<<<)([\'"]?)((?:[\\_a-z]|[^\x00-\x7f])(?:[\\\w]|[^\x00-\x7f])*)(\2\n.*?\n\s*)(\3)(;?)(\n)`, ByGroups(LiteralString, LiteralString, LiteralStringDelimiter, LiteralString, LiteralStringDelimiter, Punctuation, Text), nil},
@ -51,8 +51,8 @@ var PHP = internal.Register(DelegatingLexer(h.HTML, MustNewLexer(
{`(\d+\.\d*|\d*\.\d+)(e[+-]?[0-9]+)?`, LiteralNumberFloat, nil},
{`\d+e[+-]?[0-9]+`, LiteralNumberFloat, nil},
{`0[0-7]+`, LiteralNumberOct, nil},
{`0x[a-f0-9]+`, LiteralNumberHex, nil},
{`\d+`, LiteralNumberInteger, nil},
{`0x[a-f0-9_]+`, LiteralNumberHex, nil},
{`[\d_]+`, LiteralNumberInteger, nil},
{`0b[01]+`, LiteralNumberBin, nil},
{`'([^'\\]*(?:\\.[^'\\]*)*)'`, LiteralStringSingle, nil},
{"`([^`\\\\]*(?:\\\\.[^`\\\\]*)*)`", LiteralStringBacktick, nil},
@ -82,10 +82,5 @@ var PHP = internal.Register(DelegatingLexer(h.HTML, MustNewLexer(
{`(\$\{)(\S+)(\})`, ByGroups(LiteralStringInterpol, NameVariable, LiteralStringInterpol), nil},
{`[${\\]`, LiteralStringDouble, nil},
},
},
).SetAnalyser(func(text string) float32 {
if strings.Contains(text, "<?php") {
return 0.5
}
return 0.0
})))
}

View File

@ -0,0 +1,38 @@
package circular
import (
"strings"
. "github.com/alecthomas/chroma" // nolint
"github.com/alecthomas/chroma/lexers/h"
"github.com/alecthomas/chroma/lexers/internal"
)
// PHTML lexer is PHP in HTML.
var PHTML = internal.Register(DelegatingLexer(h.HTML, MustNewLazyLexer(
&Config{
Name: "PHTML",
Aliases: []string{"phtml"},
Filenames: []string{"*.phtml"},
MimeTypes: []string{"application/x-php", "application/x-httpd-php", "application/x-httpd-php3", "application/x-httpd-php4", "application/x-httpd-php5"},
DotAll: true,
CaseInsensitive: true,
EnsureNL: true,
},
phtmlRules,
).SetAnalyser(func(text string) float32 {
if strings.Contains(text, "<?php") {
return 0.5
}
return 0.0
})))
func phtmlRules() Rules {
return Rules{
"root": {
{`<\?(php)?`, CommentPreproc, Push("php")},
{`[^<]+`, Other, nil},
{`<`, Other, nil},
},
}.Merge(phpCommonRules())
}

View File

@ -6,7 +6,7 @@ import (
)
// D lexer. https://dlang.org/spec/lex.html
var D = internal.Register(MustNewLexer(
var D = internal.Register(MustNewLazyLexer(
&Config{
Name: "D",
Aliases: []string{"d"},
@ -14,7 +14,11 @@ var D = internal.Register(MustNewLexer(
MimeTypes: []string{"text/x-d"},
EnsureNL: true,
},
Rules{
dRules,
))
func dRules() Rules {
return Rules{
"root": {
{`[^\S\n]+`, Text, nil},
@ -65,5 +69,5 @@ var D = internal.Register(MustNewLexer(
"import": {
{`[\w.]+\*?`, NameNamespace, Pop(1)},
},
},
))
}
}

View File

@ -6,7 +6,7 @@ import (
)
// Dart lexer.
var Dart = internal.Register(MustNewLexer(
var Dart = internal.Register(MustNewLazyLexer(
&Config{
Name: "Dart",
Aliases: []string{"dart"},
@ -14,7 +14,11 @@ var Dart = internal.Register(MustNewLexer(
MimeTypes: []string{"text/x-dart"},
DotAll: true,
},
Rules{
dartRules,
))
func dartRules() Rules {
return Rules{
"root": {
Include("string_literal"),
{`#!(.*?)$`, CommentPreproc, nil},
@ -87,5 +91,5 @@ var Dart = internal.Register(MustNewLexer(
Include("string_common"),
{`(\$|\')+`, LiteralStringSingle, nil},
},
},
))
}
}

View File

@ -6,7 +6,7 @@ import (
)
// Diff lexer.
var Diff = internal.Register(MustNewLexer(
var Diff = internal.Register(MustNewLazyLexer(
&Config{
Name: "Diff",
Aliases: []string{"diff", "udiff"},
@ -14,7 +14,11 @@ var Diff = internal.Register(MustNewLexer(
Filenames: []string{"*.diff", "*.patch"},
MimeTypes: []string{"text/x-diff", "text/x-patch"},
},
Rules{
diffRules,
))
func diffRules() Rules {
return Rules{
"root": {
{` .*\n`, Text, nil},
{`\+.*\n`, GenericInserted, nil},
@ -25,5 +29,5 @@ var Diff = internal.Register(MustNewLexer(
{`=.*\n`, GenericHeading, nil},
{`.*\n`, Text, nil},
},
},
))
}
}

View File

@ -6,7 +6,7 @@ import (
)
// Django/Jinja lexer.
var DjangoJinja = internal.Register(MustNewLexer(
var DjangoJinja = internal.Register(MustNewLazyLexer(
&Config{
Name: "Django/Jinja",
Aliases: []string{"django", "jinja"},
@ -14,7 +14,11 @@ var DjangoJinja = internal.Register(MustNewLexer(
MimeTypes: []string{"application/x-django-templating", "application/x-jinja"},
DotAll: true,
},
Rules{
djangoJinjaRules,
))
func djangoJinjaRules() Rules {
return Rules{
"root": {
{`[^{]+`, Other, nil},
{`\{\{`, CommentPreproc, Push("var")},
@ -49,5 +53,5 @@ var DjangoJinja = internal.Register(MustNewLexer(
Include("varnames"),
{`.`, Punctuation, nil},
},
},
))
}
}

View File

@ -8,7 +8,7 @@ import (
)
// Docker lexer.
var Docker = internal.Register(MustNewLexer(
var Docker = internal.Register(MustNewLazyLexer(
&Config{
Name: "Docker",
Aliases: []string{"docker", "dockerfile"},
@ -16,7 +16,11 @@ var Docker = internal.Register(MustNewLexer(
MimeTypes: []string{"text/x-dockerfile-config"},
CaseInsensitive: true,
},
Rules{
dockerRules,
))
func dockerRules() Rules {
return Rules{
"root": {
{`#.*`, Comment, nil},
{`(ONBUILD)((?:\s*\\?\s*))`, ByGroups(Keyword, Using(b.Bash)), nil},
@ -27,5 +31,5 @@ var Docker = internal.Register(MustNewLexer(
{`((?:RUN|CMD|ENTRYPOINT|ENV|ARG|LABEL|ADD|COPY))`, Keyword, nil},
{`(.*\\\n)*.+`, Using(b.Bash), nil},
},
},
))
}
}

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