mirror of
https://github.com/cheat/cheat.git
synced 2025-09-01 09:38:29 +02:00
Compare commits
137 Commits
Author | SHA1 | Date | |
---|---|---|---|
14f321b0e6 | |||
d3250fda79 | |||
c482488c41 | |||
fe8f39013e | |||
1016b20ef2 | |||
def8985dcd | |||
e6f12147df | |||
a8c2c396ed | |||
35262df4f2 | |||
12ffa4cb5c | |||
d9c602f9e1 | |||
b67ff8b6a8 | |||
a500a621a1 | |||
23b6928874 | |||
9de39fb12b | |||
ad501c4cbe | |||
f17de401e5 | |||
2c097adeda | |||
b825e0f535 | |||
8385277b28 | |||
768d55e5d4 | |||
6aedc5c116 | |||
e881bb1f97 | |||
501f9c66ad | |||
a2aa82d9f3 | |||
018bce7ad5 | |||
17acefdd9b | |||
37918e09a4 | |||
86967873a8 | |||
d237d98c15 | |||
eb9b3e7798 | |||
b0a351033d | |||
1eb44e8809 | |||
55b18b4897 | |||
883a17092f | |||
4f2a57fce8 | |||
ecc96c64f9 | |||
a81dd96ff4 | |||
fb538baba5 | |||
1a7b5c6127 | |||
cdddfbb516 | |||
4ef4c35d8c | |||
a58294859e | |||
606092e288 | |||
233a9de1aa | |||
aa16f68620 | |||
367673d5d9 | |||
08fb9e11a9 | |||
3f4d4bddb2 | |||
6c6753b35c | |||
0718b606e1 | |||
857119b443 | |||
f421483eea | |||
4adddbf504 | |||
b9c86b6975 | |||
0b21ccf6f8 | |||
a3ad8c5101 | |||
bacb74929a | |||
82e1c27494 | |||
45beeb2edb | |||
c2c479b36c | |||
cb0243e7fc | |||
e5d04d41ea | |||
2474ea4fb1 | |||
7467c9fbc0 | |||
dfba3da003 | |||
ad7ad64a75 | |||
c4dcfd5da0 | |||
278a5d9154 | |||
9fa0c466fd | |||
4e9b2928b3 | |||
fa5eb44be8 | |||
49afd7c16b | |||
59d5c96c24 | |||
8e602b0e93 | |||
fb04cb1fcd | |||
d42726101e | |||
93b3a711f5 | |||
9c3d41c8bd | |||
4eeec6c868 | |||
1b17ab1914 | |||
477650ee44 | |||
c4dd3b52fd | |||
e8a0ea0dc3 | |||
992ee66a56 | |||
c9840c2d6f | |||
bd53768f67 | |||
8092687956 | |||
16ade50672 | |||
62c80d76eb | |||
3e67eaa3b7 | |||
38b13655fe | |||
749d5c1182 | |||
521f83377c | |||
b15ff10537 | |||
5288bd0c1c | |||
bddbee4158 | |||
ce27cf2cc0 | |||
5733b1d6d4 | |||
2d221050d8 | |||
ce37b670c7 | |||
47a9eeb4fd | |||
be56c9cf0c | |||
7be57cb01c | |||
8453af8601 | |||
6e388c3693 | |||
b13246978a | |||
a39d36cd34 | |||
87cba04ff2 | |||
bc623da74b | |||
a6c25d4b9c | |||
e24ac2b385 | |||
e0c35a74d4 | |||
3e4c1818a9 | |||
7b4a268ebd | |||
f7183aa17a | |||
1ce6c29e6a | |||
219db679e1 | |||
53177cb09d | |||
ef7a41f9a9 | |||
008316d030 | |||
a59c019642 | |||
57225442be | |||
2c7ce48859 | |||
a3fe4f40bb | |||
506fb8be15 | |||
408e944eea | |||
8a313b92ca | |||
6912771c39 | |||
d4c6200702 | |||
9251849d23 | |||
313b5ebd27 | |||
ca91b25b02 | |||
bbf6af50b1 | |||
9f05442bce | |||
3fc4c2f89e | |||
9e88ff2642 |
11
.github/dependabot.yml
vendored
Normal file
11
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: gomod
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
open-pull-requests-limit: 10
|
||||||
|
ignore:
|
||||||
|
- dependency-name: github.com/alecthomas/chroma
|
||||||
|
versions:
|
||||||
|
- 0.9.1
|
57
.github/workflows/build.yml
vendored
Normal file
57
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
name: Go
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# TODO: is it possible to DRY out these jobs? Aside from `runs-on`, they are
|
||||||
|
# identical.
|
||||||
|
build-linux:
|
||||||
|
runs-on: [ ubuntu-latest ]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: 1.16
|
||||||
|
|
||||||
|
- name: Set up Revive (linter)
|
||||||
|
run: go get -u github.com/boyter/scc github.com/mgechev/revive
|
||||||
|
env:
|
||||||
|
GO111MODULE: off
|
||||||
|
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: make build
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: make test
|
||||||
|
|
||||||
|
build-osx:
|
||||||
|
runs-on: [ macos-latest ]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: 1.16
|
||||||
|
|
||||||
|
- name: Set up Revive (linter)
|
||||||
|
run: go get -u github.com/boyter/scc github.com/mgechev/revive
|
||||||
|
env:
|
||||||
|
GO111MODULE: off
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: make build
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: make test
|
||||||
|
|
||||||
|
# TODO: windows
|
36
.github/workflows/codeql-analysis.yml
vendored
Normal file
36
.github/workflows/codeql-analysis.yml
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
name: CodeQL
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
schedule:
|
||||||
|
- cron: '45 23 * * 0'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: [ 'go' ]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v1
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v1
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v1
|
17
.github/workflows/homebrew.yml
vendored
Normal file
17
.github/workflows/homebrew.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
name: homebrew
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags: '*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
homebrew:
|
||||||
|
name: Bump Homebrew formula
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: mislav/bump-homebrew-formula-action@v1
|
||||||
|
with:
|
||||||
|
# A PR will be sent to github.com/Homebrew/homebrew-core to update this formula:
|
||||||
|
formula-name: cheat
|
||||||
|
env:
|
||||||
|
COMMITTER_TOKEN: ${{ secrets.COMMITTER_TOKEN }}
|
11
.travis.yml
11
.travis.yml
@ -1,11 +0,0 @@
|
|||||||
language: go
|
|
||||||
|
|
||||||
go:
|
|
||||||
- 1.13.x
|
|
||||||
|
|
||||||
env:
|
|
||||||
- GO111MODULE=on
|
|
||||||
|
|
||||||
install: true
|
|
||||||
|
|
||||||
script: make ci
|
|
@ -35,6 +35,9 @@ Are you unable to do the above, but still want to contribute? You can help
|
|||||||
`cheat` simply by telling others about it. Share it with friends and coworkers
|
`cheat` simply by telling others about it. Share it with friends and coworkers
|
||||||
that might benefit from using it.
|
that might benefit from using it.
|
||||||
|
|
||||||
|
#### Pull Requests ####
|
||||||
|
Please open all pull-requests against the `develop` branch.
|
||||||
|
|
||||||
|
|
||||||
[cheat]: https://github.com/cheat/cheat
|
[cheat]: https://github.com/cheat/cheat
|
||||||
[cheatsheets]: https://github.com/cheat/cheatsheets
|
[cheatsheets]: https://github.com/cheat/cheatsheets
|
||||||
|
8
Dockerfile
Normal file
8
Dockerfile
Normal 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
|
104
Makefile
104
Makefile
@ -7,72 +7,86 @@ dist_dir := ./dist
|
|||||||
CAT := cat
|
CAT := cat
|
||||||
COLUMN := column
|
COLUMN := column
|
||||||
CTAGS := ctags
|
CTAGS := ctags
|
||||||
|
DOCKER := docker
|
||||||
GO := go
|
GO := go
|
||||||
GREP := grep
|
GREP := grep
|
||||||
GZIP := gzip --best
|
GZIP := gzip --best
|
||||||
LINT := revive
|
LINT := revive
|
||||||
|
MAN := man
|
||||||
MKDIR := mkdir -p
|
MKDIR := mkdir -p
|
||||||
|
PANDOC := pandoc
|
||||||
RM := rm
|
RM := rm
|
||||||
SCC := scc
|
SCC := scc
|
||||||
SED := sed
|
SED := sed
|
||||||
SORT := sort
|
SORT := sort
|
||||||
ZIP := zip -m
|
ZIP := zip -m
|
||||||
|
|
||||||
|
docker_image := cheat-devel:latest
|
||||||
|
|
||||||
# build flags
|
# build flags
|
||||||
BUILD_FLAGS := -ldflags="-s -w" -mod vendor -trimpath
|
BUILD_FLAGS := -ldflags="-s -w" -mod vendor -trimpath
|
||||||
GOBIN :=
|
GOBIN :=
|
||||||
|
TMPDIR := /tmp
|
||||||
|
|
||||||
# release binaries
|
# release binaries
|
||||||
releases := \
|
releases := \
|
||||||
$(dist_dir)/cheat-darwin-amd64 \
|
$(dist_dir)/cheat-darwin-amd64 \
|
||||||
|
$(dist_dir)/cheat-linux-386 \
|
||||||
$(dist_dir)/cheat-linux-amd64 \
|
$(dist_dir)/cheat-linux-amd64 \
|
||||||
$(dist_dir)/cheat-linux-arm5 \
|
$(dist_dir)/cheat-linux-arm5 \
|
||||||
$(dist_dir)/cheat-linux-arm6 \
|
$(dist_dir)/cheat-linux-arm6 \
|
||||||
$(dist_dir)/cheat-linux-arm7 \
|
$(dist_dir)/cheat-linux-arm7 \
|
||||||
|
$(dist_dir)/cheat-linux-arm64 \
|
||||||
$(dist_dir)/cheat-windows-amd64.exe
|
$(dist_dir)/cheat-windows-amd64.exe
|
||||||
|
|
||||||
## build: builds an executable for your architecture
|
## build: build an executable for your architecture
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build: $(dist_dir)
|
build: $(dist_dir) clean fmt lint vet vendor generate man
|
||||||
$(GO) build $(BUILD_FLAGS) -o $(dist_dir)/cheat $(cmd_dir)
|
$(GO) build $(BUILD_FLAGS) -o $(dist_dir)/cheat $(cmd_dir)
|
||||||
|
|
||||||
## build-release: builds release executables
|
## build-release: build release executables
|
||||||
.PHONY: build-release
|
.PHONY: build-release
|
||||||
build-release: $(releases)
|
build-release: $(releases)
|
||||||
|
|
||||||
## ci: builds a "release" executable for the current architecture (used in ci)
|
|
||||||
.PHONY: ci
|
|
||||||
ci: | setup prepare build
|
|
||||||
|
|
||||||
# cheat-darwin-amd64
|
# cheat-darwin-amd64
|
||||||
$(dist_dir)/cheat-darwin-amd64: prepare
|
$(dist_dir)/cheat-darwin-amd64: prepare
|
||||||
GOARCH=amd64 GOOS=darwin \
|
GOARCH=amd64 GOOS=darwin \
|
||||||
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@
|
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@ && chmod -x $@.gz
|
||||||
|
|
||||||
|
# cheat-linux-386
|
||||||
|
$(dist_dir)/cheat-linux-386: prepare
|
||||||
|
GOARCH=386 GOOS=linux \
|
||||||
|
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@ && chmod -x $@.gz
|
||||||
|
|
||||||
# cheat-linux-amd64
|
# cheat-linux-amd64
|
||||||
$(dist_dir)/cheat-linux-amd64: prepare
|
$(dist_dir)/cheat-linux-amd64: prepare
|
||||||
GOARCH=amd64 GOOS=linux \
|
GOARCH=amd64 GOOS=linux \
|
||||||
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@
|
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@ && chmod -x $@.gz
|
||||||
|
|
||||||
# cheat-linux-arm5
|
# cheat-linux-arm5
|
||||||
$(dist_dir)/cheat-linux-arm5: prepare
|
$(dist_dir)/cheat-linux-arm5: prepare
|
||||||
GOARCH=arm GOOS=linux GOARM=5 \
|
GOARCH=arm GOOS=linux GOARM=5 \
|
||||||
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@
|
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@ && chmod -x $@.gz
|
||||||
|
|
||||||
# cheat-linux-arm6
|
# cheat-linux-arm6
|
||||||
$(dist_dir)/cheat-linux-arm6: prepare
|
$(dist_dir)/cheat-linux-arm6: prepare
|
||||||
GOARCH=arm GOOS=linux GOARM=6 \
|
GOARCH=arm GOOS=linux GOARM=6 \
|
||||||
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@
|
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@ && chmod -x $@.gz
|
||||||
|
|
||||||
# cheat-linux-arm7
|
# cheat-linux-arm7
|
||||||
$(dist_dir)/cheat-linux-arm7: prepare
|
$(dist_dir)/cheat-linux-arm7: prepare
|
||||||
GOARCH=arm GOOS=linux GOARM=7 \
|
GOARCH=arm GOOS=linux GOARM=7 \
|
||||||
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@
|
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@ && chmod -x $@.gz
|
||||||
|
|
||||||
|
# cheat-linux-arm64
|
||||||
|
$(dist_dir)/cheat-linux-arm64: prepare
|
||||||
|
GOARCH=arm64 GOOS=linux \
|
||||||
|
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@ && chmod -x $@.gz
|
||||||
|
|
||||||
# cheat-windows-amd64
|
# cheat-windows-amd64
|
||||||
$(dist_dir)/cheat-windows-amd64.exe: prepare
|
$(dist_dir)/cheat-windows-amd64.exe: prepare
|
||||||
GOARCH=amd64 GOOS=windows \
|
GOARCH=amd64 GOOS=windows \
|
||||||
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(ZIP) $@.zip $@
|
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(ZIP) $@.zip $@ -j
|
||||||
|
|
||||||
# ./dist
|
# ./dist
|
||||||
$(dist_dir):
|
$(dist_dir):
|
||||||
@ -82,69 +96,101 @@ $(dist_dir):
|
|||||||
generate:
|
generate:
|
||||||
$(GO) generate $(cmd_dir)
|
$(GO) generate $(cmd_dir)
|
||||||
|
|
||||||
## install: builds and installs cheat on your PATH
|
## install: build and install cheat on your PATH
|
||||||
.PHONY: install
|
.PHONY: install
|
||||||
install:
|
install: build
|
||||||
$(GO) install $(BUILD_FLAGS) $(GOBIN) $(cmd_dir)
|
$(GO) install $(BUILD_FLAGS) $(GOBIN) $(cmd_dir)
|
||||||
|
|
||||||
## clean: removes compiled executables
|
## clean: remove compiled executables
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean: $(dist_dir)
|
clean: $(dist_dir)
|
||||||
$(RM) -f $(dist_dir)/*
|
$(RM) -f $(dist_dir)/*
|
||||||
|
|
||||||
## distclean: removes the tags file
|
## distclean: remove the tags file
|
||||||
.PHONY: distclean
|
.PHONY: distclean
|
||||||
distclean:
|
distclean:
|
||||||
$(RM) tags
|
$(RM) -f tags
|
||||||
|
@$(DOCKER) image rm -f $(docker_image)
|
||||||
|
|
||||||
## setup: installs revive (linter) and scc (sloc tool)
|
## setup: install revive (linter) and scc (sloc tool)
|
||||||
.PHONY: setup
|
.PHONY: setup
|
||||||
setup:
|
setup:
|
||||||
GO111MODULE=off $(GO) get -u github.com/boyter/scc github.com/mgechev/revive
|
GO111MODULE=off $(GO) get -u github.com/boyter/scc github.com/mgechev/revive
|
||||||
|
|
||||||
## sloc: counts "semantic lines of code"
|
## sloc: count "semantic lines of code"
|
||||||
.PHONY: sloc
|
.PHONY: sloc
|
||||||
sloc:
|
sloc:
|
||||||
$(SCC) --exclude-dir=vendor
|
$(SCC) --exclude-dir=vendor
|
||||||
|
|
||||||
## tags: builds a tags file
|
## tags: build a tags file
|
||||||
.PHONY: tags
|
.PHONY: tags
|
||||||
tags:
|
tags:
|
||||||
$(CTAGS) -R . --exclude=vendor
|
$(CTAGS) -R --exclude=vendor --languages=go
|
||||||
|
|
||||||
## vendor: downloads, tidies, and verifies dependencies
|
## man: build a man page
|
||||||
|
# NB: pandoc may not be installed, so we're ignoring this error on failure
|
||||||
|
.PHONY: man
|
||||||
|
man:
|
||||||
|
-$(PANDOC) -s -t man doc/cheat.1.md -o doc/cheat.1
|
||||||
|
|
||||||
|
## vendor: download, tidy, and verify dependencies
|
||||||
.PHONY: vendor
|
.PHONY: vendor
|
||||||
vendor:
|
vendor:
|
||||||
$(GO) mod vendor && $(GO) mod tidy && $(GO) mod verify
|
$(GO) mod vendor && $(GO) mod tidy && $(GO) mod verify
|
||||||
|
|
||||||
## fmt: runs go fmt
|
## vendor-update: update vendored dependencies
|
||||||
|
vendor-update:
|
||||||
|
$(GO) get -t -u ./... && $(GO) mod vendor
|
||||||
|
|
||||||
|
## fmt: run go fmt
|
||||||
.PHONY: fmt
|
.PHONY: fmt
|
||||||
fmt:
|
fmt:
|
||||||
$(GO) fmt ./...
|
$(GO) fmt ./...
|
||||||
|
|
||||||
## lint: lints go source files
|
## lint: lint go source files
|
||||||
.PHONY: lint
|
.PHONY: lint
|
||||||
lint: vendor
|
lint: vendor
|
||||||
$(LINT) -exclude vendor/... ./...
|
$(LINT) -exclude vendor/... ./...
|
||||||
|
|
||||||
## vet: vets go source files
|
## vet: vet go source files
|
||||||
.PHONY: vet
|
.PHONY: vet
|
||||||
vet:
|
vet:
|
||||||
$(GO) vet ./...
|
$(GO) vet ./...
|
||||||
|
|
||||||
## test: runs unit-tests
|
## test: run unit-tests
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
test:
|
test:
|
||||||
$(GO) test ./...
|
$(GO) test ./...
|
||||||
|
|
||||||
## check: formats, lints, vets, vendors, and run unit-tests
|
## coverage: generate a test coverage report
|
||||||
|
.PHONY: coverage
|
||||||
|
coverage:
|
||||||
|
$(GO) test ./... -coverprofile=$(TMPDIR)/cheat-coverage.out && \
|
||||||
|
$(GO) tool cover -html=$(TMPDIR)/cheat-coverage.out
|
||||||
|
|
||||||
|
## check: format, lint, vet, vendor, and run unit-tests
|
||||||
.PHONY: check
|
.PHONY: check
|
||||||
check: | vendor fmt lint vet test
|
check: | vendor fmt lint vet test
|
||||||
|
|
||||||
.PHONY: prepare
|
.PHONY: prepare
|
||||||
prepare: | $(dist_dir) clean generate vendor fmt lint vet test
|
prepare: | $(dist_dir) clean generate vendor fmt lint vet test
|
||||||
|
|
||||||
## help: displays this help text
|
## docker-setup: create a docker image for use during development
|
||||||
|
.PHONY: docker-setup
|
||||||
|
docker-setup:
|
||||||
|
$(DOCKER) build -t $(docker_image) -f Dockerfile .
|
||||||
|
|
||||||
|
## docker-run: shell into the development docker container
|
||||||
|
.PHONY: docker-run
|
||||||
|
docker-run:
|
||||||
|
$(DOCKER) run -v `pwd`:/app -ti $(docker_image) sh
|
||||||
|
|
||||||
|
## 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
|
.PHONY: help
|
||||||
help:
|
help:
|
||||||
@$(CAT) $(makefile) | \
|
@$(CAT) $(makefile) | \
|
||||||
|
51
README.md
51
README.md
@ -1,8 +1,9 @@
|
|||||||
|

|
||||||
|
|
||||||
|
|
||||||
cheat
|
cheat
|
||||||
=====
|
=====
|
||||||
|
|
||||||
[](https://travis-ci.com/cheat/cheat)
|
|
||||||
|
|
||||||
`cheat` allows you to create and view interactive cheatsheets on the
|
`cheat` allows you to create and view interactive cheatsheets on the
|
||||||
command-line. It was designed to help remind \*nix system administrators of
|
command-line. It was designed to help remind \*nix system administrators of
|
||||||
options for commands that they use frequently, but not frequently enough to
|
options for commands that they use frequently, but not frequently enough to
|
||||||
@ -47,15 +48,17 @@ Installing
|
|||||||
`cheat` has no dependencies. To install it, download the executable from the
|
`cheat` has no dependencies. To install it, download the executable from the
|
||||||
[releases][] page and place it on your `PATH`.
|
[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
|
Configuring
|
||||||
-----------
|
-----------
|
||||||
### conf.yml ###
|
### conf.yml ###
|
||||||
`cheat` is configured by a YAML file that can be generated with `cheat --init`:
|
`cheat` is configured by a YAML file that will be auto-generated on first run.
|
||||||
|
|
||||||
```sh
|
|
||||||
mkdir -p ~/.config/cheat && cheat --init > ~/.config/cheat/conf.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
By default, the config file is assumed to exist on an XDG-compliant
|
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
|
configuration path like `~/.config/cheat/conf.yml`. If you would like to store
|
||||||
@ -89,13 +92,29 @@ const squares = [1, 2, 3, 4].map(x => x * x);
|
|||||||
```
|
```
|
||||||
|
|
||||||
The `cheat` executable includes no cheatsheets, but [community-sourced
|
The `cheat` executable includes no cheatsheets, but [community-sourced
|
||||||
cheatsheets are available][cheatsheets].
|
cheatsheets are available][cheatsheets]. You will be asked if you would like to
|
||||||
|
install the community-sourced cheatsheets the first time you run `cheat`.
|
||||||
|
|
||||||
|
### Script ###
|
||||||
|
You can manage the cheatsheets via a script `cheatsheets`.
|
||||||
|
|
||||||
|
#### Download and install ####
|
||||||
|
```sh
|
||||||
|
mkdir -p ~/.local/bin
|
||||||
|
wget -O ~/.local/bin/cheatsheets https://raw.githubusercontent.com/cheat/cheat/master/scripts/git/cheatsheets
|
||||||
|
chmod +x ~/.local/bin/cheatsheets
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Pull changes ####
|
||||||
|
To pull the community and personal cheatsheets call `cheatsheets pull`
|
||||||
|
|
||||||
|
#### Push changes ####
|
||||||
|
To push your personal cheatsheets call `cheatsheets push`
|
||||||
|
|
||||||
Cheatpaths
|
Cheatpaths
|
||||||
----------
|
----------
|
||||||
Cheatsheets are stored on "cheatpaths", which are directories that contain
|
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
|
It can be useful to configure `cheat` against multiple cheatpaths. A common
|
||||||
pattern is to store cheatsheets from multiple repositories on individual
|
pattern is to store cheatsheets from multiple repositories on individual
|
||||||
@ -193,11 +212,19 @@ cheat -p personal -t networking --regex -s '(?:[0-9]{1,3}\.){3}[0-9]{1,3}'
|
|||||||
|
|
||||||
Advanced Usage
|
Advanced Usage
|
||||||
--------------
|
--------------
|
||||||
`cheat` may be integrated with [fzf][]. See [fzf.bash][bash] for instructions.
|
Shell autocompletion is currently available for `bash`, `fish`, and `zsh`. Copy
|
||||||
(Support for other shells will be added in future releases.)
|
the relevant [completion script][completions] into the appropriate directory on
|
||||||
|
your filesystem to enable autocompletion. (This directory will vary depending
|
||||||
|
on operating system and shell specifics.)
|
||||||
|
|
||||||
|
Additionally, `cheat` supports enhanced autocompletion via integration with
|
||||||
|
[fzf][]. To enable `fzf` integration:
|
||||||
|
|
||||||
|
1. Ensure that `fzf` is available on your `$PATH`
|
||||||
|
2. Set an envvar: `export CHEAT_USE_FZF=true`
|
||||||
|
|
||||||
[Releases]: https://github.com/cheat/cheat/releases
|
[Releases]: https://github.com/cheat/cheat/releases
|
||||||
[bash]: https://github.com/cheat/cheat/blob/master/scripts/fzf.bash
|
|
||||||
[cheatsheets]: https://github.com/cheat/cheatsheets
|
[cheatsheets]: https://github.com/cheat/cheatsheets
|
||||||
|
[completions]: https://github.com/cheat/cheat/tree/master/scripts
|
||||||
[fzf]: https://github.com/junegunn/fzf
|
[fzf]: https://github.com/junegunn/fzf
|
||||||
|
[go]: https://golang.org
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# TODO: this script has been made obsolete by the Makefile, yet downstream
|
|
||||||
# package managers plausibly rely on it for compiling locally. Remove this file
|
|
||||||
# after downstream maintainers have had time to modify their packages to simply
|
|
||||||
# invoke `make` in the project root.
|
|
||||||
|
|
||||||
# locate the cheat project root
|
|
||||||
BINDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
||||||
APPDIR=$(readlink -f "$BINDIR/..")
|
|
||||||
|
|
||||||
# compile the executable
|
|
||||||
cd $APPDIR
|
|
||||||
|
|
||||||
make
|
|
@ -1,3 +1,4 @@
|
|||||||
|
//go:build ignore
|
||||||
// +build ignore
|
// +build ignore
|
||||||
|
|
||||||
// This script embeds `docopt.txt and `conf.yml` into the binary during at
|
// This script embeds `docopt.txt and `conf.yml` into the binary during at
|
||||||
@ -5,13 +6,11 @@
|
|||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -52,10 +51,10 @@ func main() {
|
|||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
|
|
||||||
// delete the outfile
|
// delete the outfile
|
||||||
os.Remove(path.Join(root, file.Out))
|
os.Remove(filepath.Join(root, file.Out))
|
||||||
|
|
||||||
// read the static template
|
// read the static template
|
||||||
bytes, err := ioutil.ReadFile(path.Join(root, file.In))
|
bytes, err := ioutil.ReadFile(filepath.Join(root, file.In))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -64,7 +63,7 @@ func main() {
|
|||||||
data := template(file.Method, string(bytes))
|
data := template(file.Method, string(bytes))
|
||||||
|
|
||||||
// write the file to the specified outpath
|
// write the file to the specified outpath
|
||||||
spath := path.Join(root, file.Out)
|
spath := filepath.Join(root, file.Out)
|
||||||
err = ioutil.WriteFile(spath, []byte(data), 0644)
|
err = ioutil.WriteFile(spath, []byte(data), 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
|
||||||
"github.com/cheat/cheat/internal/config"
|
"github.com/cheat/cheat/internal/config"
|
||||||
|
"github.com/cheat/cheat/internal/display"
|
||||||
)
|
)
|
||||||
|
|
||||||
// cmdDirectories lists the configured cheatpaths.
|
// cmdDirectories lists the configured cheatpaths.
|
||||||
func cmdDirectories(opts map[string]interface{}, conf config.Config) {
|
func cmdDirectories(opts map[string]interface{}, conf config.Config) {
|
||||||
|
|
||||||
// initialize a tabwriter to produce cleanly columnized output
|
// initialize a tabwriter to produce cleanly columnized output
|
||||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
|
var out bytes.Buffer
|
||||||
|
w := tabwriter.NewWriter(&out, 0, 0, 1, ' ', 0)
|
||||||
|
|
||||||
// generate sorted, columnized output
|
// generate sorted, columnized output
|
||||||
for _, path := range conf.Cheatpaths {
|
for _, path := range conf.Cheatpaths {
|
||||||
@ -25,4 +27,5 @@ func cmdDirectories(opts map[string]interface{}, conf config.Config) {
|
|||||||
|
|
||||||
// write columnized output to stdout
|
// write columnized output to stdout
|
||||||
w.Flush()
|
w.Flush()
|
||||||
|
display.Write(out.String(), conf)
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/cheat/cheat/internal/cheatpath"
|
"github.com/cheat/cheat/internal/cheatpath"
|
||||||
@ -58,10 +58,10 @@ func cmdEdit(opts map[string]interface{}, conf config.Config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// compute the new edit path
|
// compute the new edit path
|
||||||
editpath = path.Join(writepath.Path, sheet.Title)
|
editpath = filepath.Join(writepath.Path, sheet.Title)
|
||||||
|
|
||||||
// create any necessary subdirectories
|
// create any necessary subdirectories
|
||||||
dirs := path.Dir(editpath)
|
dirs := filepath.Dir(editpath)
|
||||||
if dirs != "." {
|
if dirs != "." {
|
||||||
if err := os.MkdirAll(dirs, 0755); err != nil {
|
if err := os.MkdirAll(dirs, 0755); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "failed to create directory: %s, %v\n", dirs, err)
|
fmt.Fprintf(os.Stderr, "failed to create directory: %s, %v\n", dirs, err)
|
||||||
@ -87,10 +87,10 @@ func cmdEdit(opts map[string]interface{}, conf config.Config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// compute the new edit path
|
// compute the new edit path
|
||||||
editpath = path.Join(writepath.Path, cheatsheet)
|
editpath = filepath.Join(writepath.Path, cheatsheet)
|
||||||
|
|
||||||
// create any necessary subdirectories
|
// create any necessary subdirectories
|
||||||
dirs := path.Dir(editpath)
|
dirs := filepath.Dir(editpath)
|
||||||
if dirs != "." {
|
if dirs != "." {
|
||||||
if err := os.MkdirAll(dirs, 0755); err != nil {
|
if err := os.MkdirAll(dirs, 0755); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "failed to create directory: %s, %v\n", dirs, err)
|
fmt.Fprintf(os.Stderr, "failed to create directory: %s, %v\n", dirs, err)
|
||||||
@ -99,8 +99,15 @@ func cmdEdit(opts map[string]interface{}, conf config.Config) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// split `conf.Editor` into parts to separate the editor's executable from
|
||||||
|
// any arguments it may have been passed. If this is not done, the nearby
|
||||||
|
// call to `exec.Command` will fail.
|
||||||
|
parts := strings.Fields(conf.Editor)
|
||||||
|
editor := parts[0]
|
||||||
|
args := append(parts[1:], editpath)
|
||||||
|
|
||||||
// edit the cheatsheet
|
// edit the cheatsheet
|
||||||
cmd := exec.Command(conf.Editor, editpath)
|
cmd := exec.Command(editor, args...)
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stdin = os.Stdin
|
cmd.Stdin = os.Stdin
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
|
@ -2,9 +2,56 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mitchellh/go-homedir"
|
||||||
|
|
||||||
|
"github.com/cheat/cheat/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// cmdInit displays an example config file.
|
// cmdInit displays an example config file.
|
||||||
func cmdInit() {
|
func cmdInit() {
|
||||||
fmt.Println(configs())
|
|
||||||
|
// get the user's home directory
|
||||||
|
home, err := homedir.Dir()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "failed to get user home directory: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the envvars into a map of strings
|
||||||
|
envvars := map[string]string{}
|
||||||
|
for _, e := range os.Environ() {
|
||||||
|
pair := strings.SplitN(e, "=", 2)
|
||||||
|
envvars[pair[0]] = pair[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// load the config template
|
||||||
|
configs := configs()
|
||||||
|
|
||||||
|
// identify the os-specifc paths at which configs may be located
|
||||||
|
confpaths, err := config.Paths(runtime.GOOS, home, envvars)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "failed to read config paths: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine the appropriate paths for config data and (optional) community
|
||||||
|
// cheatsheets based on the user's platform
|
||||||
|
confpath := confpaths[0]
|
||||||
|
confdir := filepath.Dir(confpath)
|
||||||
|
|
||||||
|
// create paths for community and personal cheatsheets
|
||||||
|
community := filepath.Join(confdir, "cheatsheets", "community")
|
||||||
|
personal := filepath.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)
|
||||||
|
|
||||||
|
// output the templated configs
|
||||||
|
fmt.Println(configs)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
@ -9,6 +10,7 @@ import (
|
|||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
|
||||||
"github.com/cheat/cheat/internal/config"
|
"github.com/cheat/cheat/internal/config"
|
||||||
|
"github.com/cheat/cheat/internal/display"
|
||||||
"github.com/cheat/cheat/internal/sheet"
|
"github.com/cheat/cheat/internal/sheet"
|
||||||
"github.com/cheat/cheat/internal/sheets"
|
"github.com/cheat/cheat/internal/sheets"
|
||||||
)
|
)
|
||||||
@ -23,7 +25,7 @@ func cmdList(opts map[string]interface{}, conf config.Config) {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// filter cheatcheats by tag if --tag was provided
|
// filter cheatsheets by tag if --tag was provided
|
||||||
if opts["--tag"] != nil {
|
if opts["--tag"] != nil {
|
||||||
cheatsheets = sheets.Filter(
|
cheatsheets = sheets.Filter(
|
||||||
cheatsheets,
|
cheatsheets,
|
||||||
@ -35,8 +37,8 @@ func cmdList(opts map[string]interface{}, conf config.Config) {
|
|||||||
// sheets with local sheets), here we simply want to create a slice
|
// sheets with local sheets), here we simply want to create a slice
|
||||||
// containing all sheets.
|
// containing all sheets.
|
||||||
flattened := []sheet.Sheet{}
|
flattened := []sheet.Sheet{}
|
||||||
for _, pathSheets := range cheatsheets {
|
for _, pathsheets := range cheatsheets {
|
||||||
for _, s := range pathSheets {
|
for _, s := range pathsheets {
|
||||||
flattened = append(flattened, s)
|
flattened = append(flattened, s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,16 +81,19 @@ func cmdList(opts map[string]interface{}, conf config.Config) {
|
|||||||
flattened = filtered
|
flattened = filtered
|
||||||
}
|
}
|
||||||
|
|
||||||
// exit early if no cheatsheets are available
|
// return exit code 2 if no cheatsheets are available
|
||||||
if len(flattened) == 0 {
|
if len(flattened) == 0 {
|
||||||
os.Exit(0)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize a tabwriter to produce cleanly columnized output
|
// initialize a tabwriter to produce cleanly columnized output
|
||||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
|
var out bytes.Buffer
|
||||||
|
w := tabwriter.NewWriter(&out, 0, 0, 1, ' ', 0)
|
||||||
|
|
||||||
|
// write a header row
|
||||||
|
fmt.Fprintln(w, "title:\tfile:\ttags:")
|
||||||
|
|
||||||
// generate sorted, columnized output
|
// generate sorted, columnized output
|
||||||
fmt.Fprintln(w, "title:\tfile:\ttags:")
|
|
||||||
for _, sheet := range flattened {
|
for _, sheet := range flattened {
|
||||||
fmt.Fprintln(w, fmt.Sprintf(
|
fmt.Fprintln(w, fmt.Sprintf(
|
||||||
"%s\t%s\t%s",
|
"%s\t%s\t%s",
|
||||||
@ -100,4 +105,5 @@ func cmdList(opts map[string]interface{}, conf config.Config) {
|
|||||||
|
|
||||||
// write columnized output to stdout
|
// write columnized output to stdout
|
||||||
w.Flush()
|
w.Flush()
|
||||||
|
display.Write(out.String(), conf)
|
||||||
}
|
}
|
||||||
|
@ -37,8 +37,8 @@ func cmdRemove(opts map[string]interface{}, conf config.Config) {
|
|||||||
// fail early if the requested cheatsheet does not exist
|
// fail early if the requested cheatsheet does not exist
|
||||||
sheet, ok := consolidated[cheatsheet]
|
sheet, ok := consolidated[cheatsheet]
|
||||||
if !ok {
|
if !ok {
|
||||||
fmt.Fprintln(os.Stderr, fmt.Sprintf("no cheatsheet found for '%s'.\n", cheatsheet))
|
fmt.Fprintln(os.Stderr, fmt.Sprintf("No cheatsheet found for '%s'.\n", cheatsheet))
|
||||||
os.Exit(1)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// fail early if the sheet is read-only
|
// fail early if the sheet is read-only
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/cheat/cheat/internal/config"
|
"github.com/cheat/cheat/internal/config"
|
||||||
|
"github.com/cheat/cheat/internal/display"
|
||||||
"github.com/cheat/cheat/internal/sheets"
|
"github.com/cheat/cheat/internal/sheets"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -30,40 +31,65 @@ func cmdSearch(opts map[string]interface{}, conf config.Config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// consolidate the cheatsheets found on all paths into a single map of
|
// iterate over each cheatpath
|
||||||
// `title` => `sheet` (ie, allow more local cheatsheets to override less
|
out := ""
|
||||||
// local cheatsheets)
|
for _, pathcheats := range cheatsheets {
|
||||||
consolidated := sheets.Consolidate(cheatsheets)
|
|
||||||
|
|
||||||
// sort the cheatsheets alphabetically, and search for matches
|
// sort the cheatsheets alphabetically, and search for matches
|
||||||
for _, sheet := range sheets.Sort(consolidated) {
|
for _, sheet := range sheets.Sort(pathcheats) {
|
||||||
|
|
||||||
// assume that we want to perform a case-insensitive search for <phrase>
|
// if <cheatsheet> was provided, constrain the search only to
|
||||||
pattern := "(?i)" + phrase
|
// matching cheatsheets
|
||||||
|
if opts["<cheatsheet>"] != nil && sheet.Title != opts["<cheatsheet>"] {
|
||||||
// unless --regex is provided, in which case we pass the regex unaltered
|
continue
|
||||||
if opts["--regex"] == true {
|
|
||||||
pattern = phrase
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// search the sheet
|
|
||||||
matches := sheet.Search(reg, conf.Color(opts))
|
|
||||||
|
|
||||||
// display the results
|
|
||||||
if len(matches) > 0 {
|
|
||||||
fmt.Printf("%s:\n", sheet.Title)
|
|
||||||
for _, m := range matches {
|
|
||||||
fmt.Printf(" %d: %s\n", m.Line, m.Text)
|
|
||||||
}
|
}
|
||||||
fmt.Print("\n")
|
|
||||||
|
// assume that we want to perform a case-insensitive search for <phrase>
|
||||||
|
pattern := "(?i)" + phrase
|
||||||
|
|
||||||
|
// unless --regex is provided, in which case we pass the regex unaltered
|
||||||
|
if opts["--regex"] == true {
|
||||||
|
pattern = phrase
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// `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)
|
||||||
|
|
||||||
|
// if the sheet did not match the search, ignore it and move on
|
||||||
|
if sheet.Text == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// 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)
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/cheat/cheat/internal/config"
|
"github.com/cheat/cheat/internal/config"
|
||||||
|
"github.com/cheat/cheat/internal/display"
|
||||||
"github.com/cheat/cheat/internal/sheets"
|
"github.com/cheat/cheat/internal/sheets"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,8 +19,12 @@ func cmdTags(opts map[string]interface{}, conf config.Config) {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// write sheet tags to stdout
|
// assemble the output
|
||||||
|
out := ""
|
||||||
for _, tag := range sheets.Tags(cheatsheets) {
|
for _, tag := range sheets.Tags(cheatsheets) {
|
||||||
fmt.Println(tag)
|
out += fmt.Sprintln(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// display the output
|
||||||
|
display.Write(out, conf)
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/chroma/quick"
|
|
||||||
|
|
||||||
"github.com/cheat/cheat/internal/config"
|
"github.com/cheat/cheat/internal/config"
|
||||||
|
"github.com/cheat/cheat/internal/display"
|
||||||
"github.com/cheat/cheat/internal/sheets"
|
"github.com/cheat/cheat/internal/sheets"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -31,41 +30,53 @@ func cmdView(opts map[string]interface{}, conf config.Config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// consolidate the cheatsheets found on all paths into a single map of
|
// if --all was passed, display cheatsheets from all cheatpaths
|
||||||
// `title` => `sheet` (ie, allow more local cheatsheets to override less
|
if opts["--all"].(bool) {
|
||||||
// local cheatsheets)
|
// 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)
|
consolidated := sheets.Consolidate(cheatsheets)
|
||||||
|
|
||||||
// fail early if the requested cheatsheet does not exist
|
// fail early if the requested cheatsheet does not exist
|
||||||
sheet, ok := consolidated[cheatsheet]
|
sheet, ok := consolidated[cheatsheet]
|
||||||
if !ok {
|
if !ok {
|
||||||
fmt.Printf("No cheatsheet found for '%s'.\n", cheatsheet)
|
fmt.Printf("No cheatsheet found for '%s'.\n", cheatsheet)
|
||||||
os.Exit(0)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !conf.Color(opts) {
|
// apply colorization if requested
|
||||||
fmt.Print(sheet.Text)
|
if conf.Color(opts) {
|
||||||
os.Exit(0)
|
sheet.Colorize(conf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// otherwise, colorize the output
|
// display the cheatsheet
|
||||||
// if the syntax was not specified, default to bash
|
display.Write(sheet.Text, conf)
|
||||||
lex := sheet.Syntax
|
|
||||||
if lex == "" {
|
|
||||||
lex = "bash"
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply syntax highlighting
|
|
||||||
err = quick.Highlight(
|
|
||||||
os.Stdout,
|
|
||||||
sheet.Text,
|
|
||||||
lex,
|
|
||||||
conf.Formatter,
|
|
||||||
conf.Style,
|
|
||||||
)
|
|
||||||
|
|
||||||
// if colorization somehow failed, output non-colorized text
|
|
||||||
if err != nil {
|
|
||||||
fmt.Print(sheet.Text)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,18 +2,19 @@ Usage:
|
|||||||
cheat [options] [<cheatsheet>]
|
cheat [options] [<cheatsheet>]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--init Write a default config file to stdout
|
--init Write a default config file to stdout
|
||||||
-c --colorize Colorize output
|
-a --all Search among all cheatpaths
|
||||||
-d --directories List cheatsheet directories
|
-c --colorize Colorize output
|
||||||
-e --edit=<sheet> Edit <sheet>
|
-d --directories List cheatsheet directories
|
||||||
-l --list List cheatsheets
|
-e --edit=<cheatsheet> Edit <cheatsheet>
|
||||||
-p --path=<name> Return only sheets found on path <name>
|
-l --list List cheatsheets
|
||||||
-r --regex Treat search <phrase> as a regex
|
-p --path=<name> Return only sheets found on cheatpath <name>
|
||||||
-s --search=<phrase> Search cheatsheets for <phrase>
|
-r --regex Treat search <phrase> as a regex
|
||||||
-t --tag=<tag> Return only sheets matching <tag>
|
-s --search=<phrase> Search cheatsheets for <phrase>
|
||||||
-T --tags List all tags in use
|
-t --tag=<tag> Return only sheets matching <tag>
|
||||||
-v --version Print the version number
|
-T --tags List all tags in use
|
||||||
--rm=<sheet> Remove (delete) <sheet>
|
-v --version Print the version number
|
||||||
|
--rm=<cheatsheet> Remove (delete) <cheatsheet>
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
|
@ -6,19 +6,22 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/docopt/docopt-go"
|
"github.com/docopt/docopt-go"
|
||||||
|
"github.com/mitchellh/go-homedir"
|
||||||
|
|
||||||
"github.com/cheat/cheat/internal/cheatpath"
|
"github.com/cheat/cheat/internal/cheatpath"
|
||||||
"github.com/cheat/cheat/internal/config"
|
"github.com/cheat/cheat/internal/config"
|
||||||
|
"github.com/cheat/cheat/internal/installer"
|
||||||
)
|
)
|
||||||
|
|
||||||
const version = "3.3.2"
|
const version = "4.2.5"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
// initialize options
|
// initialize options
|
||||||
opts, err := docopt.Parse(usage(), nil, true, version, false)
|
opts, err := docopt.ParseArgs(usage(), nil, version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// panic here, because this should never happen
|
// panic here, because this should never happen
|
||||||
panic(fmt.Errorf("docopt failed to parse: %v", err))
|
panic(fmt.Errorf("docopt failed to parse: %v", err))
|
||||||
@ -31,13 +34,63 @@ func main() {
|
|||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// load the config file
|
// get the user's home directory
|
||||||
confpath, err := config.Path(runtime.GOOS)
|
home, err := homedir.Dir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, "could not locate config file")
|
fmt.Fprintf(os.Stderr, "failed to get user home directory: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// read the envvars into a map of strings
|
||||||
|
envvars := map[string]string{}
|
||||||
|
for _, e := range os.Environ() {
|
||||||
|
pair := strings.SplitN(e, "=", 2)
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
pair[0] = strings.ToUpper(pair[0])
|
||||||
|
}
|
||||||
|
envvars[pair[0]] = pair[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// identify the os-specifc paths at which configs may be located
|
||||||
|
confpaths, err := config.Paths(runtime.GOOS, home, envvars)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "failed to load config: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// search for the config file in the above paths
|
||||||
|
confpath, err := config.Path(confpaths)
|
||||||
|
if err != nil {
|
||||||
|
// prompt the user to create a config file
|
||||||
|
yes, err := installer.Prompt(
|
||||||
|
"A config file was not found. Would you like to create one now? [Y/n]",
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "failed to create config: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// exit early on a negative answer
|
||||||
|
if !yes {
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// choose a confpath
|
||||||
|
confpath = confpaths[0]
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
// initialize the configs
|
// initialize the configs
|
||||||
conf, err := config.New(opts, confpath, true)
|
conf, err := config.New(opts, confpath, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -88,6 +141,9 @@ func main() {
|
|||||||
case opts["<cheatsheet>"] != nil:
|
case opts["<cheatsheet>"] != nil:
|
||||||
cmd = cmdView
|
cmd = cmdView
|
||||||
|
|
||||||
|
case opts["--tag"] != nil && opts["--tag"].(string) != "":
|
||||||
|
cmd = cmdList
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fmt.Println(usage())
|
fmt.Println(usage())
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
|
@ -9,19 +9,23 @@ import (
|
|||||||
func configs() string {
|
func configs() string {
|
||||||
return strings.TrimSpace(`---
|
return strings.TrimSpace(`---
|
||||||
# The editor to use with 'cheat -e <sheet>'. Defaults to $EDITOR or $VISUAL.
|
# The editor to use with 'cheat -e <sheet>'. Defaults to $EDITOR or $VISUAL.
|
||||||
editor: vim
|
# editor: vim
|
||||||
|
|
||||||
# Should 'cheat' always colorize output?
|
# Should 'cheat' always colorize output?
|
||||||
colorize: true
|
colorize: false
|
||||||
|
|
||||||
# Which 'chroma' colorscheme should be applied to the output?
|
# Which 'chroma' colorscheme should be applied to the output?
|
||||||
# Options are available here:
|
# Options are available here:
|
||||||
# https://github.com/alecthomas/chroma/tree/master/styles
|
# https://github.com/alecthomas/chroma/tree/master/styles
|
||||||
style: monokai
|
# style: monokai
|
||||||
|
|
||||||
# Which 'chroma' "formatter" should be applied?
|
# Which 'chroma' "formatter" should be applied?
|
||||||
# One of: "terminal", "terminal256", "terminal16m"
|
# One of: "terminal", "terminal256", "terminal16m"
|
||||||
formatter: terminal16m
|
formatter: terminal
|
||||||
|
|
||||||
|
# Through which pager should output be piped? (Unset this key for no pager.)
|
||||||
|
pager: more
|
||||||
|
# pager: less -FRX # <- recommended where available
|
||||||
|
|
||||||
# The paths at which cheatsheets are available. Tags associated with a cheatpath
|
# The paths at which cheatsheets are available. Tags associated with a cheatpath
|
||||||
# are automatically attached to all cheatsheets residing on that path.
|
# are automatically attached to all cheatsheets residing on that path.
|
||||||
@ -41,32 +45,34 @@ cheatpaths:
|
|||||||
# thus be overridden by more local cheatsheets. That being the case, you
|
# thus be overridden by more local cheatsheets. That being the case, you
|
||||||
# should probably list community cheatsheets first.
|
# should probably list community cheatsheets first.
|
||||||
#
|
#
|
||||||
# Note that the paths and tags listed below are just examples. You may freely
|
# Note that the paths and tags listed below are placeholders. You may freely
|
||||||
# change them to suit your needs.
|
# change them to suit your needs.
|
||||||
|
#
|
||||||
|
# Community cheatsheets must be installed separately, though you may have
|
||||||
|
# downloaded them automatically when installing 'cheat'. If not, you may
|
||||||
|
# download them here:
|
||||||
|
#
|
||||||
|
# https://github.com/cheat/cheatsheets
|
||||||
|
#
|
||||||
|
# Once downloaded, ensure that 'path' below points to the location at which
|
||||||
|
# you downloaded the community cheatsheets.
|
||||||
- name: community
|
- name: community
|
||||||
path: ~/.dotfiles/cheat/community
|
path: COMMUNITY_PATH
|
||||||
tags: [ community ]
|
tags: [ community ]
|
||||||
readonly: true
|
readonly: true
|
||||||
|
|
||||||
# Maybe your company or department maintains a repository of cheatsheets as
|
|
||||||
# well. It's probably sensible to list those second.
|
|
||||||
- name: work
|
|
||||||
path: ~/.dotfiles/cheat/work
|
|
||||||
tags: [ work ]
|
|
||||||
readonly: false
|
|
||||||
|
|
||||||
# If you have personalized cheatsheets, list them last. They will take
|
# If you have personalized cheatsheets, list them last. They will take
|
||||||
# precedence over the more global cheatsheets.
|
# precedence over the more global cheatsheets.
|
||||||
- name: personal
|
- name: personal
|
||||||
path: ~/.dotfiles/cheat/personal
|
path: PERSONAL_PATH
|
||||||
tags: [ personal ]
|
tags: [ personal ]
|
||||||
readonly: false
|
readonly: false
|
||||||
|
|
||||||
# While it requires no specific configuration here, it's also worth noting
|
# While it requires no configuration here, it's also worth noting that
|
||||||
# that 'cheat' will automatically append directories named '.cheat' within
|
# 'cheat' will automatically append directories named '.cheat' within the
|
||||||
# the current working directory to the 'cheatpath'. This can be very useful
|
# current working directory to the 'cheatpath'. This can be very useful if
|
||||||
# if you'd like to closely associate cheatsheets with, for example, a
|
# you'd like to closely associate cheatsheets with, for example, a directory
|
||||||
# directory containing source code.
|
# containing source code.
|
||||||
#
|
#
|
||||||
# Such "directory-scoped" cheatsheets will be treated as the most "local"
|
# Such "directory-scoped" cheatsheets will be treated as the most "local"
|
||||||
# cheatsheets, and will override less "local" cheatsheets. Likewise,
|
# cheatsheets, and will override less "local" cheatsheets. Likewise,
|
||||||
|
@ -11,18 +11,19 @@ func usage() string {
|
|||||||
cheat [options] [<cheatsheet>]
|
cheat [options] [<cheatsheet>]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--init Write a default config file to stdout
|
--init Write a default config file to stdout
|
||||||
-c --colorize Colorize output
|
-a --all Search among all cheatpaths
|
||||||
-d --directories List cheatsheet directories
|
-c --colorize Colorize output
|
||||||
-e --edit=<sheet> Edit <sheet>
|
-d --directories List cheatsheet directories
|
||||||
-l --list List cheatsheets
|
-e --edit=<cheatsheet> Edit <cheatsheet>
|
||||||
-p --path=<name> Return only sheets found on path <name>
|
-l --list List cheatsheets
|
||||||
-r --regex Treat search <phrase> as a regex
|
-p --path=<name> Return only sheets found on cheatpath <name>
|
||||||
-s --search=<phrase> Search cheatsheets for <phrase>
|
-r --regex Treat search <phrase> as a regex
|
||||||
-t --tag=<tag> Return only sheets matching <tag>
|
-s --search=<phrase> Search cheatsheets for <phrase>
|
||||||
-T --tags List all tags in use
|
-t --tag=<tag> Return only sheets matching <tag>
|
||||||
-v --version Print the version number
|
-T --tags List all tags in use
|
||||||
--rm=<sheet> Remove (delete) <sheet>
|
-v --version Print the version number
|
||||||
|
--rm=<cheatsheet> Remove (delete) <cheatsheet>
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
|
@ -1,18 +1,22 @@
|
|||||||
---
|
---
|
||||||
# The editor to use with 'cheat -e <sheet>'. Defaults to $EDITOR or $VISUAL.
|
# The editor to use with 'cheat -e <sheet>'. Defaults to $EDITOR or $VISUAL.
|
||||||
editor: vim
|
# editor: vim
|
||||||
|
|
||||||
# Should 'cheat' always colorize output?
|
# Should 'cheat' always colorize output?
|
||||||
colorize: true
|
colorize: false
|
||||||
|
|
||||||
# Which 'chroma' colorscheme should be applied to the output?
|
# Which 'chroma' colorscheme should be applied to the output?
|
||||||
# Options are available here:
|
# Options are available here:
|
||||||
# https://github.com/alecthomas/chroma/tree/master/styles
|
# https://github.com/alecthomas/chroma/tree/master/styles
|
||||||
style: monokai
|
# style: monokai
|
||||||
|
|
||||||
# Which 'chroma' "formatter" should be applied?
|
# Which 'chroma' "formatter" should be applied?
|
||||||
# One of: "terminal", "terminal256", "terminal16m"
|
# One of: "terminal", "terminal256", "terminal16m"
|
||||||
formatter: terminal16m
|
formatter: terminal
|
||||||
|
|
||||||
|
# Through which pager should output be piped? (Unset this key for no pager.)
|
||||||
|
pager: more
|
||||||
|
# pager: less -FRX # <- recommended where available
|
||||||
|
|
||||||
# The paths at which cheatsheets are available. Tags associated with a cheatpath
|
# The paths at which cheatsheets are available. Tags associated with a cheatpath
|
||||||
# are automatically attached to all cheatsheets residing on that path.
|
# are automatically attached to all cheatsheets residing on that path.
|
||||||
@ -32,32 +36,34 @@ cheatpaths:
|
|||||||
# thus be overridden by more local cheatsheets. That being the case, you
|
# thus be overridden by more local cheatsheets. That being the case, you
|
||||||
# should probably list community cheatsheets first.
|
# should probably list community cheatsheets first.
|
||||||
#
|
#
|
||||||
# Note that the paths and tags listed below are just examples. You may freely
|
# Note that the paths and tags listed below are placeholders. You may freely
|
||||||
# change them to suit your needs.
|
# change them to suit your needs.
|
||||||
|
#
|
||||||
|
# Community cheatsheets must be installed separately, though you may have
|
||||||
|
# downloaded them automatically when installing 'cheat'. If not, you may
|
||||||
|
# download them here:
|
||||||
|
#
|
||||||
|
# https://github.com/cheat/cheatsheets
|
||||||
|
#
|
||||||
|
# Once downloaded, ensure that 'path' below points to the location at which
|
||||||
|
# you downloaded the community cheatsheets.
|
||||||
- name: community
|
- name: community
|
||||||
path: ~/.dotfiles/cheat/community
|
path: COMMUNITY_PATH
|
||||||
tags: [ community ]
|
tags: [ community ]
|
||||||
readonly: true
|
readonly: true
|
||||||
|
|
||||||
# Maybe your company or department maintains a repository of cheatsheets as
|
|
||||||
# well. It's probably sensible to list those second.
|
|
||||||
- name: work
|
|
||||||
path: ~/.dotfiles/cheat/work
|
|
||||||
tags: [ work ]
|
|
||||||
readonly: false
|
|
||||||
|
|
||||||
# If you have personalized cheatsheets, list them last. They will take
|
# If you have personalized cheatsheets, list them last. They will take
|
||||||
# precedence over the more global cheatsheets.
|
# precedence over the more global cheatsheets.
|
||||||
- name: personal
|
- name: personal
|
||||||
path: ~/.dotfiles/cheat/personal
|
path: PERSONAL_PATH
|
||||||
tags: [ personal ]
|
tags: [ personal ]
|
||||||
readonly: false
|
readonly: false
|
||||||
|
|
||||||
# While it requires no specific configuration here, it's also worth noting
|
# While it requires no configuration here, it's also worth noting that
|
||||||
# that 'cheat' will automatically append directories named '.cheat' within
|
# 'cheat' will automatically append directories named '.cheat' within the
|
||||||
# the current working directory to the 'cheatpath'. This can be very useful
|
# current working directory to the 'cheatpath'. This can be very useful if
|
||||||
# if you'd like to closely associate cheatsheets with, for example, a
|
# you'd like to closely associate cheatsheets with, for example, a directory
|
||||||
# directory containing source code.
|
# containing source code.
|
||||||
#
|
#
|
||||||
# Such "directory-scoped" cheatsheets will be treated as the most "local"
|
# Such "directory-scoped" cheatsheets will be treated as the most "local"
|
||||||
# cheatsheets, and will override less "local" cheatsheets. Likewise,
|
# cheatsheets, and will override less "local" cheatsheets. Likewise,
|
||||||
|
221
doc/cheat.1
Normal file
221
doc/cheat.1
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
.\" Automatically generated by Pandoc 2.2.1
|
||||||
|
.\"
|
||||||
|
.TH "CHEAT" "1" "" "" "General Commands Manual"
|
||||||
|
.hy
|
||||||
|
.SH NAME
|
||||||
|
.PP
|
||||||
|
\f[B]cheat\f[] \[em] create and view command\-line cheatsheets
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.PP
|
||||||
|
\f[B]cheat\f[] [options] [\f[I]CHEATSHEET\f[]]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.PP
|
||||||
|
\f[B]cheat\f[] allows you to create and view interactive cheatsheets on
|
||||||
|
the command\-line.
|
||||||
|
It was designed to help remind *nix system administrators of options for
|
||||||
|
commands that they use frequently, but not frequently enough to
|
||||||
|
remember.
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
.B \[en]init
|
||||||
|
Print a config file to stdout.
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
|
.B \-c, \[en]colorize
|
||||||
|
Colorize output.
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
|
.B \-d, \[en]directories
|
||||||
|
List cheatsheet directories.
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
|
.B \-e, \[en]edit=\f[I]CHEATSHEET\f[]
|
||||||
|
Open \f[I]CHEATSHEET\f[] for editing.
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
|
.B \-l, \[en]list
|
||||||
|
List available cheatsheets.
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
|
.B \-p, \[en]path=\f[I]PATH\f[]
|
||||||
|
Filter only to sheets found on path \f[I]PATH\f[].
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
|
.B \-r, \[en]regex
|
||||||
|
Treat search \f[I]PHRASE\f[] as a regular expression.
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
|
.B \-s, \[en]search=\f[I]PHRASE\f[]
|
||||||
|
Search cheatsheets for \f[I]PHRASE\f[].
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
|
.B \-t, \[en]tag=\f[I]TAG\f[]
|
||||||
|
Filter only to sheets tagged with \f[I]TAG\f[].
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
|
.B \-T, \[en]tags
|
||||||
|
List all tags in use.
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
|
.B \-v, \[en]version
|
||||||
|
Print the version number.
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
|
.B \[en]rm=\f[I]CHEATSHEET\f[]
|
||||||
|
Remove (deletes) \f[I]CHEATSHEET\f[].
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.SH EXAMPLES
|
||||||
|
.TP
|
||||||
|
.B To view the foo cheatsheet:
|
||||||
|
cheat \f[I]foo\f[]
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
|
.B To edit (or create) the foo cheatsheet:
|
||||||
|
cheat \-e \f[I]foo\f[]
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
|
.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
|
||||||
|
.TP
|
||||||
|
.B To view all cheatsheet directories:
|
||||||
|
cheat \-d
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
|
.B To list all available cheatsheets:
|
||||||
|
cheat \-l
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
|
.B To list all cheatsheets whose titles match `apt':
|
||||||
|
cheat \-l \f[I]apt\f[]
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
|
.B To list all tags in use:
|
||||||
|
cheat \-T
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
|
.B To list available cheatsheets that are tagged as `personal':
|
||||||
|
cheat \-l \-t \f[I]personal\f[]
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
|
.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]`(?:[0\-9]{1,3}.){3}[0\-9]{1,3}'\f[]
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
|
.B To remove (delete) the foo/bar cheatsheet:
|
||||||
|
cheat \[en]rm \f[I]foo/bar\f[]
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.SH FILES
|
||||||
|
.SS Configuration
|
||||||
|
.PP
|
||||||
|
\f[B]cheat\f[] is configured via a YAML file that is conventionally
|
||||||
|
named \f[I]conf.yaml\f[].
|
||||||
|
\f[B]cheat\f[] will search for \f[I]conf.yaml\f[] in varying locations,
|
||||||
|
depending upon your platform:
|
||||||
|
.SS Linux, OSX, and other Unixes
|
||||||
|
.IP "1." 3
|
||||||
|
\f[B]CHEAT_CONFIG_PATH\f[]
|
||||||
|
.IP "2." 3
|
||||||
|
\f[B]XDG_CONFIG_HOME\f[]/cheat/conf.yaml
|
||||||
|
.IP "3." 3
|
||||||
|
\f[B]$HOME\f[]/.config/cheat/conf.yml
|
||||||
|
.IP "4." 3
|
||||||
|
\f[B]$HOME\f[]/.cheat/conf.yml
|
||||||
|
.SS Windows
|
||||||
|
.IP "1." 3
|
||||||
|
\f[B]CHEAT_CONFIG_PATH\f[]
|
||||||
|
.IP "2." 3
|
||||||
|
\f[B]APPDATA\f[]/cheat/conf.yml
|
||||||
|
.IP "3." 3
|
||||||
|
\f[B]PROGRAMDATA\f[]/cheat/conf.yml
|
||||||
|
.PP
|
||||||
|
\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'd like
|
||||||
|
to generate one automatically.
|
||||||
|
Alternatively, you may also generate a config file manually by running
|
||||||
|
\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 \[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
|
||||||
|
For detailed instructions on how to configure cheatpaths, please refer
|
||||||
|
to the comments in conf.yml.
|
||||||
|
.SS Autocompletion
|
||||||
|
.PP
|
||||||
|
Autocompletion scripts for \f[B]bash\f[], \f[B]zsh\f[], and
|
||||||
|
\f[B]fish\f[] are available for download:
|
||||||
|
.IP \[bu] 2
|
||||||
|
<https://github.com/cheat/cheat/blob/master/scripts/cheat.bash>
|
||||||
|
.IP \[bu] 2
|
||||||
|
<https://github.com/cheat/cheat/blob/master/scripts/cheat.fish>
|
||||||
|
.IP \[bu] 2
|
||||||
|
<https://github.com/cheat/cheat/blob/master/scripts/cheat.zsh>
|
||||||
|
.PP
|
||||||
|
The \f[B]bash\f[] and \f[B]zsh\f[] scripts provide optional integration
|
||||||
|
with \f[B]fzf\f[], if the latter is available on your \f[B]PATH\f[].
|
||||||
|
.PP
|
||||||
|
The installation process will vary per system and shell configuration,
|
||||||
|
and thus will not be discussed here.
|
||||||
|
.SH ENVIRONMENT
|
||||||
|
.TP
|
||||||
|
.B \f[B]CHEAT_CONFIG_PATH\f[]
|
||||||
|
The path at which the config file is available.
|
||||||
|
If \f[B]CHEAT_CONFIG_PATH\f[] is set, all other config paths will be
|
||||||
|
ignored.
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
|
.B \f[B]CHEAT_USE_FZF\f[]
|
||||||
|
If set, autocompletion scripts will attempt to integrate with
|
||||||
|
\f[B]fzf\f[].
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.SH RETURN VALUES
|
||||||
|
.IP "0." 3
|
||||||
|
Successful termination
|
||||||
|
.IP "1." 3
|
||||||
|
Application error
|
||||||
|
.IP "2." 3
|
||||||
|
Cheatsheet(s) not found
|
||||||
|
.SH BUGS
|
||||||
|
.PP
|
||||||
|
See GitHub issues: <https://github.com/cheat/cheat/issues>
|
||||||
|
.SH AUTHOR
|
||||||
|
.PP
|
||||||
|
Christopher Allen Lane <chris@chris-allen-lane.com>
|
||||||
|
.SH SEE ALSO
|
||||||
|
.PP
|
||||||
|
\f[B]fzf(1)\f[]
|
192
doc/cheat.1.md
Normal file
192
doc/cheat.1.md
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
% CHEAT(1) | General Commands Manual
|
||||||
|
|
||||||
|
NAME
|
||||||
|
====
|
||||||
|
|
||||||
|
**cheat** — create and view command-line cheatsheets
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
========
|
||||||
|
|
||||||
|
| **cheat** \[options] \[_CHEATSHEET_]
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
===========
|
||||||
|
**cheat** allows you to create and view interactive cheatsheets on the
|
||||||
|
command-line. It was designed to help remind \*nix system administrators of
|
||||||
|
options for commands that they use frequently, but not frequently enough to
|
||||||
|
remember.
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
=======
|
||||||
|
|
||||||
|
--init
|
||||||
|
: Print a config file to stdout.
|
||||||
|
|
||||||
|
-c, --colorize
|
||||||
|
: Colorize output.
|
||||||
|
|
||||||
|
-d, --directories
|
||||||
|
: List cheatsheet directories.
|
||||||
|
|
||||||
|
-e, --edit=_CHEATSHEET_
|
||||||
|
: Open _CHEATSHEET_ for editing.
|
||||||
|
|
||||||
|
-l, --list
|
||||||
|
: List available cheatsheets.
|
||||||
|
|
||||||
|
-p, --path=_PATH_
|
||||||
|
: Filter only to sheets found on path _PATH_.
|
||||||
|
|
||||||
|
-r, --regex
|
||||||
|
: Treat search _PHRASE_ as a regular expression.
|
||||||
|
|
||||||
|
-s, --search=_PHRASE_
|
||||||
|
: Search cheatsheets for _PHRASE_.
|
||||||
|
|
||||||
|
-t, --tag=_TAG_
|
||||||
|
: Filter only to sheets tagged with _TAG_.
|
||||||
|
|
||||||
|
-T, --tags
|
||||||
|
: List all tags in use.
|
||||||
|
|
||||||
|
-v, --version
|
||||||
|
: Print the version number.
|
||||||
|
|
||||||
|
--rm=_CHEATSHEET_
|
||||||
|
: Remove (deletes) _CHEATSHEET_.
|
||||||
|
|
||||||
|
|
||||||
|
EXAMPLES
|
||||||
|
========
|
||||||
|
|
||||||
|
To view the foo cheatsheet:
|
||||||
|
: cheat _foo_
|
||||||
|
|
||||||
|
To edit (or create) the foo cheatsheet:
|
||||||
|
: cheat -e _foo_
|
||||||
|
|
||||||
|
To edit (or create) the foo/bar cheatsheet on the 'work' cheatpath:
|
||||||
|
: cheat -p _work_ -e _foo/bar_
|
||||||
|
|
||||||
|
To view all cheatsheet directories:
|
||||||
|
: cheat -d
|
||||||
|
|
||||||
|
To list all available cheatsheets:
|
||||||
|
: cheat -l
|
||||||
|
|
||||||
|
To list all cheatsheets whose titles match 'apt':
|
||||||
|
: cheat -l _apt_
|
||||||
|
|
||||||
|
To list all tags in use:
|
||||||
|
: cheat -T
|
||||||
|
|
||||||
|
To list available cheatsheets that are tagged as 'personal':
|
||||||
|
: cheat -l -t _personal_
|
||||||
|
|
||||||
|
To search for 'ssh' among all cheatsheets, and colorize matches:
|
||||||
|
: cheat -c -s _ssh_
|
||||||
|
|
||||||
|
To search (by regex) for cheatsheets that contain an IP address:
|
||||||
|
: cheat -c -r -s _'(?:[0-9]{1,3}\.){3}[0-9]{1,3}'_
|
||||||
|
|
||||||
|
To remove (delete) the foo/bar cheatsheet:
|
||||||
|
: cheat --rm _foo/bar_
|
||||||
|
|
||||||
|
|
||||||
|
FILES
|
||||||
|
=====
|
||||||
|
|
||||||
|
Configuration
|
||||||
|
-------------
|
||||||
|
**cheat** is configured via a YAML file that is conventionally named
|
||||||
|
_conf.yaml_. **cheat** will search for _conf.yaml_ in varying locations,
|
||||||
|
depending upon your platform:
|
||||||
|
|
||||||
|
### Linux, OSX, and other Unixes ###
|
||||||
|
|
||||||
|
1. **CHEAT_CONFIG_PATH**
|
||||||
|
2. **XDG_CONFIG_HOME**/cheat/conf.yaml
|
||||||
|
3. **$HOME**/.config/cheat/conf.yml
|
||||||
|
4. **$HOME**/.cheat/conf.yml
|
||||||
|
|
||||||
|
### Windows ###
|
||||||
|
|
||||||
|
1. **CHEAT_CONFIG_PATH**
|
||||||
|
2. **APPDATA**/cheat/conf.yml
|
||||||
|
3. **PROGRAMDATA**/cheat/conf.yml
|
||||||
|
|
||||||
|
**cheat** will search in the order specified above. The first _conf.yaml_
|
||||||
|
encountered will be respected.
|
||||||
|
|
||||||
|
If **cheat** 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 **cheat --init** and saving its output to the appropriate location
|
||||||
|
for your platform.
|
||||||
|
|
||||||
|
|
||||||
|
Cheatpaths
|
||||||
|
----------
|
||||||
|
**cheat** reads its cheatsheets from "cheatpaths", which are the directories in
|
||||||
|
which cheatsheets are stored. Cheatpaths may be configured in _conf.yaml_, and
|
||||||
|
viewed via **cheat -d**.
|
||||||
|
|
||||||
|
For detailed instructions on how to configure cheatpaths, please refer to the
|
||||||
|
comments in conf.yml.
|
||||||
|
|
||||||
|
|
||||||
|
Autocompletion
|
||||||
|
--------------
|
||||||
|
Autocompletion scripts for **bash**, **zsh**, and **fish** are available for
|
||||||
|
download:
|
||||||
|
|
||||||
|
- <https://github.com/cheat/cheat/blob/master/scripts/cheat.bash>
|
||||||
|
- <https://github.com/cheat/cheat/blob/master/scripts/cheat.fish>
|
||||||
|
- <https://github.com/cheat/cheat/blob/master/scripts/cheat.zsh>
|
||||||
|
|
||||||
|
The **bash** and **zsh** scripts provide optional integration with **fzf**, if
|
||||||
|
the latter is available on your **PATH**.
|
||||||
|
|
||||||
|
The installation process will vary per system and shell configuration, and thus
|
||||||
|
will not be discussed here.
|
||||||
|
|
||||||
|
|
||||||
|
ENVIRONMENT
|
||||||
|
===========
|
||||||
|
|
||||||
|
**CHEAT_CONFIG_PATH**
|
||||||
|
|
||||||
|
: The path at which the config file is available. If **CHEAT_CONFIG_PATH** is
|
||||||
|
set, all other config paths will be ignored.
|
||||||
|
|
||||||
|
**CHEAT_USE_FZF**
|
||||||
|
|
||||||
|
: If set, autocompletion scripts will attempt to integrate with **fzf**.
|
||||||
|
|
||||||
|
RETURN VALUES
|
||||||
|
=============
|
||||||
|
|
||||||
|
0. Successful termination
|
||||||
|
|
||||||
|
1. Application error
|
||||||
|
|
||||||
|
2. Cheatsheet(s) not found
|
||||||
|
|
||||||
|
|
||||||
|
BUGS
|
||||||
|
====
|
||||||
|
|
||||||
|
See GitHub issues: <https://github.com/cheat/cheat/issues>
|
||||||
|
|
||||||
|
|
||||||
|
AUTHOR
|
||||||
|
======
|
||||||
|
|
||||||
|
Christopher Allen Lane <chris@chris-allen-lane.com>
|
||||||
|
|
||||||
|
|
||||||
|
SEE ALSO
|
||||||
|
========
|
||||||
|
|
||||||
|
**fzf(1)**
|
||||||
|
|
13
go.mod
13
go.mod
@ -1,14 +1,17 @@
|
|||||||
module github.com/cheat/cheat
|
module github.com/cheat/cheat
|
||||||
|
|
||||||
go 1.13
|
go 1.14
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/alecthomas/chroma v0.7.1
|
github.com/alecthomas/chroma v0.10.0
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
|
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
|
||||||
github.com/mattn/go-isatty v0.0.12
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b
|
github.com/mattn/go-isatty v0.0.14
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e // indirect
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0
|
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0
|
||||||
gopkg.in/yaml.v2 v2.2.8
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
)
|
)
|
||||||
|
59
go.sum
59
go.sum
@ -1,48 +1,37 @@
|
|||||||
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U=
|
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
|
||||||
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
|
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
|
||||||
github.com/alecthomas/chroma v0.7.1 h1:G1i02OhUbRi2nJxcNkwJaY/J1gHXj9tt72qN6ZouLFQ=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/alecthomas/chroma v0.7.1/go.mod h1:gHw09mkX1Qp80JlYbmN9L3+4R5o6DJJ3GRShh+AICNc=
|
|
||||||
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.1-0.20190708041108-0548c6b1afae/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI=
|
|
||||||
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY=
|
|
||||||
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
|
|
||||||
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ=
|
|
||||||
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dlclark/regexp2 v1.1.6 h1:CqB4MjHw0MFCDj+PHHjiESmHX+N7t0tJzKvC6M97BRg=
|
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
|
||||||
github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
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 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=
|
||||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||||
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
|
|
||||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
|
||||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
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/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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
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.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35 h1:YAFjXN64LMvktoUZH9zgY4lGc/msGN7HQfoSuKCgaDU=
|
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e h1:CsOuNlbOuf0mzxJIefr6Q4uAUetRUwZE4qt7VfzP+xo=
|
||||||
golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
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=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 h1:POO/ycCATvegFmVuPpQzZFJ+pGZeX22Ufu6fibxDVjU=
|
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 h1:POO/ycCATvegFmVuPpQzZFJ+pGZeX22Ufu6fibxDVjU=
|
||||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
|
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
|
||||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
22
internal/config/color_test.go
Normal file
22
internal/config/color_test.go
Normal 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)")
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
cp "github.com/cheat/cheat/internal/cheatpath"
|
cp "github.com/cheat/cheat/internal/cheatpath"
|
||||||
|
|
||||||
@ -19,6 +22,7 @@ type Config struct {
|
|||||||
Cheatpaths []cp.Cheatpath `yaml:"cheatpaths"`
|
Cheatpaths []cp.Cheatpath `yaml:"cheatpaths"`
|
||||||
Style string `yaml:"style"`
|
Style string `yaml:"style"`
|
||||||
Formatter string `yaml:"formatter"`
|
Formatter string `yaml:"formatter"`
|
||||||
|
Pager string `yaml:"pager"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new Config struct
|
// New returns a new Config struct
|
||||||
@ -75,14 +79,16 @@ func New(opts map[string]interface{}, confPath string, resolve bool) (Config, er
|
|||||||
// `resolve` is a switch that allows us to turn off symlink resolution when
|
// `resolve` is a switch that allows us to turn off symlink resolution when
|
||||||
// running the config tests.
|
// running the config tests.
|
||||||
if resolve {
|
if resolve {
|
||||||
expanded, err = filepath.EvalSymlinks(expanded)
|
evaled, err := filepath.EvalSymlinks(expanded)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Config{}, fmt.Errorf(
|
return Config{}, fmt.Errorf(
|
||||||
"failed to resolve symlink: %s, %v",
|
"failed to resolve symlink: %s: %v",
|
||||||
expanded,
|
expanded,
|
||||||
err,
|
err,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expanded = evaled
|
||||||
}
|
}
|
||||||
|
|
||||||
conf.Cheatpaths[i].Path = expanded
|
conf.Cheatpaths[i].Path = expanded
|
||||||
@ -94,8 +100,22 @@ func New(opts map[string]interface{}, confPath string, resolve bool) (Config, er
|
|||||||
conf.Editor = os.Getenv("VISUAL")
|
conf.Editor = os.Getenv("VISUAL")
|
||||||
} else if os.Getenv("EDITOR") != "" {
|
} else if os.Getenv("EDITOR") != "" {
|
||||||
conf.Editor = os.Getenv("EDITOR")
|
conf.Editor = os.Getenv("EDITOR")
|
||||||
|
} else if runtime.GOOS == "windows" {
|
||||||
|
conf.Editor = "notepad"
|
||||||
} else {
|
} else {
|
||||||
return Config{}, fmt.Errorf("no editor set")
|
// try to fall back to `nano`
|
||||||
|
path, err := exec.LookPath("nano")
|
||||||
|
if err != nil {
|
||||||
|
return Config{}, fmt.Errorf("failed to locate nano: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// use `nano` if we found it
|
||||||
|
if path != "" {
|
||||||
|
conf.Editor = "nano"
|
||||||
|
// otherwise, give up
|
||||||
|
} else {
|
||||||
|
return Config{}, fmt.Errorf("no editor set")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +126,13 @@ func New(opts map[string]interface{}, confPath string, resolve bool) (Config, er
|
|||||||
|
|
||||||
// if a chroma formatter was not provided, set a default
|
// if a chroma formatter was not provided, set a default
|
||||||
if conf.Formatter == "" {
|
if conf.Formatter == "" {
|
||||||
conf.Formatter = "terminal16m"
|
conf.Formatter = "terminal"
|
||||||
|
}
|
||||||
|
|
||||||
|
// attempt to fall back to `PAGER` if a pager is not specified in configs
|
||||||
|
conf.Pager = strings.TrimSpace(conf.Pager)
|
||||||
|
if conf.Pager == "" && os.Getenv("PAGER") != "" {
|
||||||
|
conf.Pager = os.Getenv("PAGER")
|
||||||
}
|
}
|
||||||
|
|
||||||
return conf, nil
|
return conf, nil
|
||||||
|
@ -39,17 +39,17 @@ func TestConfigSuccessful(t *testing.T) {
|
|||||||
// assert that the cheatpaths are correct
|
// assert that the cheatpaths are correct
|
||||||
want := []cheatpath.Cheatpath{
|
want := []cheatpath.Cheatpath{
|
||||||
cheatpath.Cheatpath{
|
cheatpath.Cheatpath{
|
||||||
Path: filepath.Join(home, ".dotfiles/cheat/community"),
|
Path: filepath.Join(home, ".dotfiles", "cheat", "community"),
|
||||||
ReadOnly: true,
|
ReadOnly: true,
|
||||||
Tags: []string{"community"},
|
Tags: []string{"community"},
|
||||||
},
|
},
|
||||||
cheatpath.Cheatpath{
|
cheatpath.Cheatpath{
|
||||||
Path: filepath.Join(home, ".dotfiles/cheat/work"),
|
Path: filepath.Join(home, ".dotfiles", "cheat", "work"),
|
||||||
ReadOnly: false,
|
ReadOnly: false,
|
||||||
Tags: []string{"work"},
|
Tags: []string{"work"},
|
||||||
},
|
},
|
||||||
cheatpath.Cheatpath{
|
cheatpath.Cheatpath{
|
||||||
Path: filepath.Join(home, ".dotfiles/cheat/personal"),
|
Path: filepath.Join(home, ".dotfiles", "cheat", "personal"),
|
||||||
ReadOnly: false,
|
ReadOnly: false,
|
||||||
Tags: []string{"personal"},
|
Tags: []string{"personal"},
|
||||||
},
|
},
|
||||||
@ -85,8 +85,8 @@ func TestEmptyEditor(t *testing.T) {
|
|||||||
|
|
||||||
// initialize a config
|
// initialize a config
|
||||||
conf, err := New(map[string]interface{}{}, mock.Path("conf/empty.yml"), false)
|
conf, err := New(map[string]interface{}{}, mock.Path("conf/empty.yml"), false)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
t.Errorf("failed to return an error on empty editor")
|
t.Errorf("failed to initialize test: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// set editor, and assert that it is respected
|
// set editor, and assert that it is respected
|
||||||
|
24
internal/config/init.go
Normal file
24
internal/config/init.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Init initializes a config file
|
||||||
|
func Init(confpath string, configs string) error {
|
||||||
|
|
||||||
|
// assert that the config directory exists
|
||||||
|
if err := os.MkdirAll(filepath.Dir(confpath), 0755); err != nil {
|
||||||
|
return fmt.Errorf("failed to create directory: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the config file
|
||||||
|
if err := ioutil.WriteFile(confpath, []byte(configs), 0644); err != nil {
|
||||||
|
return fmt.Errorf("failed to create file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
38
internal/config/init_test.go
Normal file
38
internal/config/init_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
@ -3,43 +3,10 @@ package config
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
|
|
||||||
"github.com/mitchellh/go-homedir"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Path returns the config file path
|
// Path returns the config file path
|
||||||
func Path(sys string) (string, error) {
|
func Path(paths []string) (string, error) {
|
||||||
|
|
||||||
var paths []string
|
|
||||||
|
|
||||||
// if CHEAT_CONFIG_PATH is set, return it
|
|
||||||
if os.Getenv("CHEAT_CONFIG_PATH") != "" {
|
|
||||||
|
|
||||||
// expand ~
|
|
||||||
expanded, err := homedir.Expand(os.Getenv("CHEAT_CONFIG_PATH"))
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to expand ~: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return expanded, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
switch sys {
|
|
||||||
case "darwin", "linux", "freebsd":
|
|
||||||
paths = []string{
|
|
||||||
path.Join(os.Getenv("XDG_CONFIG_HOME"), "/cheat/conf.yml"),
|
|
||||||
path.Join(os.Getenv("HOME"), ".config/cheat/conf.yml"),
|
|
||||||
path.Join(os.Getenv("HOME"), ".cheat/conf.yml"),
|
|
||||||
}
|
|
||||||
case "windows":
|
|
||||||
paths = []string{
|
|
||||||
fmt.Sprintf("%s/cheat/conf.yml", os.Getenv("APPDATA")),
|
|
||||||
fmt.Sprintf("%s/cheat/conf.yml", os.Getenv("PROGRAMDATA")),
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return "", fmt.Errorf("unsupported os: %s", sys)
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if the config file exists on any paths
|
// check if the config file exists on any paths
|
||||||
for _, p := range paths {
|
for _, p := range paths {
|
||||||
|
53
internal/config/path_test.go
Normal file
53
internal/config/path_test.go
Normal 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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
54
internal/config/paths.go
Normal file
54
internal/config/paths.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/mitchellh/go-homedir"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Paths returns config file paths that are appropriate for the operating
|
||||||
|
// system
|
||||||
|
func Paths(
|
||||||
|
sys string,
|
||||||
|
home string,
|
||||||
|
envvars map[string]string,
|
||||||
|
) ([]string, error) {
|
||||||
|
|
||||||
|
// if `CHEAT_CONFIG_PATH` is set, expand ~ and return it
|
||||||
|
if confpath, ok := envvars["CHEAT_CONFIG_PATH"]; ok {
|
||||||
|
|
||||||
|
// expand ~
|
||||||
|
expanded, err := homedir.Expand(confpath)
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, fmt.Errorf("failed to expand ~: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return []string{expanded}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch sys {
|
||||||
|
case "android", "darwin", "linux", "freebsd":
|
||||||
|
paths := []string{}
|
||||||
|
|
||||||
|
// don't include the `XDG_CONFIG_HOME` path if that envvar is not set
|
||||||
|
if xdgpath, ok := envvars["XDG_CONFIG_HOME"]; ok {
|
||||||
|
paths = append(paths, filepath.Join(xdgpath, "cheat", "conf.yml"))
|
||||||
|
}
|
||||||
|
|
||||||
|
paths = append(paths, []string{
|
||||||
|
filepath.Join(home, ".config", "cheat", "conf.yml"),
|
||||||
|
filepath.Join(home, ".cheat", "conf.yml"),
|
||||||
|
"/etc/cheat/conf.yml",
|
||||||
|
}...)
|
||||||
|
|
||||||
|
return paths, nil
|
||||||
|
case "windows":
|
||||||
|
return []string{
|
||||||
|
filepath.Join(envvars["APPDATA"], "cheat", "conf.yml"),
|
||||||
|
filepath.Join(envvars["PROGRAMDATA"], "cheat", "conf.yml"),
|
||||||
|
}, nil
|
||||||
|
default:
|
||||||
|
return []string{}, fmt.Errorf("unsupported os: %s", sys)
|
||||||
|
}
|
||||||
|
}
|
176
internal/config/paths_test.go
Normal file
176
internal/config/paths_test.go
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestValidatePathsNix asserts that the proper config paths are returned on
|
||||||
|
// *nix platforms
|
||||||
|
func TestValidatePathsNix(t *testing.T) {
|
||||||
|
|
||||||
|
// mock the user's home directory
|
||||||
|
home := "/home/foo"
|
||||||
|
|
||||||
|
// mock some envvars
|
||||||
|
envvars := map[string]string{
|
||||||
|
"XDG_CONFIG_HOME": "/home/bar",
|
||||||
|
}
|
||||||
|
|
||||||
|
// specify the platforms to test
|
||||||
|
oses := []string{
|
||||||
|
"android",
|
||||||
|
"darwin",
|
||||||
|
"freebsd",
|
||||||
|
"linux",
|
||||||
|
}
|
||||||
|
|
||||||
|
// test each *nix os
|
||||||
|
for _, os := range oses {
|
||||||
|
// get the paths for the platform
|
||||||
|
paths, err := Paths(os, home, envvars)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("paths returned an error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// specify the expected output
|
||||||
|
want := []string{
|
||||||
|
"/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
|
||||||
|
if !reflect.DeepEqual(paths, want) {
|
||||||
|
t.Errorf(
|
||||||
|
"failed to return expected paths: want:\n%s, got:\n%s",
|
||||||
|
spew.Sdump(want),
|
||||||
|
spew.Sdump(paths),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestValidatePathsNixNoXDG asserts that the proper config paths are returned
|
||||||
|
// on *nix platforms when `XDG_CONFIG_HOME is not set
|
||||||
|
func TestValidatePathsNixNoXDG(t *testing.T) {
|
||||||
|
|
||||||
|
// mock the user's home directory
|
||||||
|
home := "/home/foo"
|
||||||
|
|
||||||
|
// mock some envvars
|
||||||
|
envvars := map[string]string{}
|
||||||
|
|
||||||
|
// specify the platforms to test
|
||||||
|
oses := []string{
|
||||||
|
"darwin",
|
||||||
|
"freebsd",
|
||||||
|
"linux",
|
||||||
|
}
|
||||||
|
|
||||||
|
// test each *nix os
|
||||||
|
for _, os := range oses {
|
||||||
|
// get the paths for the platform
|
||||||
|
paths, err := Paths(os, home, envvars)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("paths returned an error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// specify the expected output
|
||||||
|
want := []string{
|
||||||
|
"/home/foo/.config/cheat/conf.yml",
|
||||||
|
"/home/foo/.cheat/conf.yml",
|
||||||
|
"/etc/cheat/conf.yml",
|
||||||
|
}
|
||||||
|
|
||||||
|
// assert that output matches expectations
|
||||||
|
if !reflect.DeepEqual(paths, want) {
|
||||||
|
t.Errorf(
|
||||||
|
"failed to return expected paths: want:\n%s, got:\n%s",
|
||||||
|
spew.Sdump(want),
|
||||||
|
spew.Sdump(paths),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestValidatePathsWindows asserts that the proper config paths are returned
|
||||||
|
// on Windows platforms
|
||||||
|
func TestValidatePathsWindows(t *testing.T) {
|
||||||
|
|
||||||
|
// mock the user's home directory
|
||||||
|
home := "not-used-on-windows"
|
||||||
|
|
||||||
|
// mock some envvars
|
||||||
|
envvars := map[string]string{
|
||||||
|
"APPDATA": "/apps",
|
||||||
|
"PROGRAMDATA": "/programs",
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the paths for the platform
|
||||||
|
paths, err := Paths("windows", home, envvars)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("paths returned an error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// specify the expected output
|
||||||
|
want := []string{
|
||||||
|
"/apps/cheat/conf.yml",
|
||||||
|
"/programs/cheat/conf.yml",
|
||||||
|
}
|
||||||
|
|
||||||
|
// assert that output matches expectations
|
||||||
|
if !reflect.DeepEqual(paths, want) {
|
||||||
|
t.Errorf(
|
||||||
|
"failed to return expected paths: want:\n%s, got:\n%s",
|
||||||
|
spew.Sdump(want),
|
||||||
|
spew.Sdump(paths),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestValidatePathsUnsupported asserts that an error is returned on
|
||||||
|
// unsupported platforms
|
||||||
|
func TestValidatePathsUnsupported(t *testing.T) {
|
||||||
|
_, err := Paths("unsupported", "", map[string]string{})
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("failed to return error on unsupported platform")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestValidatePathsCheatConfigPath asserts that the proper config path is
|
||||||
|
// returned when `CHEAT_CONFIG_PATH` is explicitly specified.
|
||||||
|
func TestValidatePathsCheatConfigPath(t *testing.T) {
|
||||||
|
|
||||||
|
// mock the user's home directory
|
||||||
|
home := "/home/foo"
|
||||||
|
|
||||||
|
// mock some envvars
|
||||||
|
envvars := map[string]string{
|
||||||
|
"XDG_CONFIG_HOME": "/home/bar",
|
||||||
|
"CHEAT_CONFIG_PATH": "/home/baz/conf.yml",
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the paths for the platform
|
||||||
|
paths, err := Paths("linux", home, envvars)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("paths returned an error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// specify the expected output
|
||||||
|
want := []string{
|
||||||
|
"/home/baz/conf.yml",
|
||||||
|
}
|
||||||
|
|
||||||
|
// assert that output matches expectations
|
||||||
|
if !reflect.DeepEqual(paths, want) {
|
||||||
|
t.Errorf(
|
||||||
|
"failed to return expected paths: want:\n%s, got:\n%s",
|
||||||
|
spew.Sdump(want),
|
||||||
|
spew.Sdump(paths),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
18
internal/display/faint.go
Normal file
18
internal/display/faint.go
Normal 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
|
||||||
|
}
|
27
internal/display/faint_test.go
Normal file
27
internal/display/faint_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
21
internal/display/indent.go
Normal file
21
internal/display/indent.go
Normal 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
|
||||||
|
}
|
12
internal/display/indent_test.go
Normal file
12
internal/display/indent_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
8
internal/display/underline.go
Normal file
8
internal/display/underline.go
Normal 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))
|
||||||
|
}
|
14
internal/display/underline_test.go
Normal file
14
internal/display/underline_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
37
internal/display/write.go
Normal file
37
internal/display/write.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package display
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/cheat/cheat/internal/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Write writes output either directly to stdout, or through a pager,
|
||||||
|
// depending upon configuration.
|
||||||
|
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)
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, pipe output through the pager
|
||||||
|
parts := strings.Split(conf.Pager, " ")
|
||||||
|
pager := parts[0]
|
||||||
|
args := parts[1:]
|
||||||
|
|
||||||
|
// run the pager
|
||||||
|
cmd := exec.Command(pager, args...)
|
||||||
|
cmd.Stdin = strings.NewReader(out)
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
|
||||||
|
// handle errors
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, fmt.Sprintf("failed to write to pager: %v", err))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package frontmatter
|
package frontmatter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"gopkg.in/yaml.v1"
|
"gopkg.in/yaml.v1"
|
||||||
@ -28,7 +29,16 @@ func Parse(markdown string) (string, Frontmatter, error) {
|
|||||||
|
|
||||||
// otherwise, split the frontmatter and cheatsheet text
|
// otherwise, split the frontmatter and cheatsheet text
|
||||||
parts := strings.SplitN(markdown, delim, 3)
|
parts := strings.SplitN(markdown, delim, 3)
|
||||||
err := yaml.Unmarshal([]byte(parts[1]), &fm)
|
|
||||||
|
|
||||||
return strings.TrimSpace(parts[2]), fm, err
|
// return an error if the frontmatter parses into the wrong number of parts
|
||||||
|
if len(parts) != 3 {
|
||||||
|
return markdown, fm, fmt.Errorf("failed to delimit frontmatter")
|
||||||
|
}
|
||||||
|
|
||||||
|
// return an error if the YAML cannot be unmarshalled
|
||||||
|
if err := yaml.Unmarshal([]byte(parts[1]), &fm); err != nil {
|
||||||
|
return markdown, fm, fmt.Errorf("failed to unmarshal frontmatter: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.TrimSpace(parts[2]), fm, nil
|
||||||
}
|
}
|
||||||
|
@ -69,3 +69,27 @@ func TestHasNoFrontmatter(t *testing.T) {
|
|||||||
t.Errorf("failed to parse tags: want: len 0, got: len %d", len(fm.Tags))
|
t.Errorf("failed to parse tags: want: len 0, got: len %d", len(fm.Tags))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestHasInvalidFrontmatter asserts that markdown is properly parsed when it
|
||||||
|
// contains invalid frontmatter
|
||||||
|
func TestHasInvalidFrontmatter(t *testing.T) {
|
||||||
|
|
||||||
|
// stub our cheatsheet content (with invalid frontmatter)
|
||||||
|
markdown := `---
|
||||||
|
syntax: go
|
||||||
|
tags: [ test ]
|
||||||
|
To foo the bar: baz`
|
||||||
|
|
||||||
|
// parse the frontmatter
|
||||||
|
text, _, err := Parse(markdown)
|
||||||
|
|
||||||
|
// assert that an error was returned
|
||||||
|
if err == nil {
|
||||||
|
t.Error("failed to error on invalid frontmatter")
|
||||||
|
}
|
||||||
|
|
||||||
|
// assert that the "raw" markdown was returned
|
||||||
|
if text != markdown {
|
||||||
|
t.Errorf("failed to parse text: want: %s, got: %s", markdown, text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
24
internal/installer/clone.go
Normal file
24
internal/installer/clone.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package installer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
const cloneURL = "https://github.com/cheat/cheatsheets.git"
|
||||||
|
|
||||||
|
// clone clones the community cheatsheets
|
||||||
|
func clone(path string) error {
|
||||||
|
|
||||||
|
// perform the clone in a shell
|
||||||
|
cmd := exec.Command("git", "clone", cloneURL, path)
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to clone cheatsheets: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
37
internal/installer/prompt.go
Normal file
37
internal/installer/prompt.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package installer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Prompt prompts the user for a answer
|
||||||
|
func Prompt(prompt string, def bool) (bool, error) {
|
||||||
|
|
||||||
|
// initialize a line reader
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
|
||||||
|
// display the prompt
|
||||||
|
fmt.Print(fmt.Sprintf("%s: ", prompt))
|
||||||
|
|
||||||
|
// read the answer
|
||||||
|
ans, err := reader.ReadString('\n')
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("failed to parse input: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalize the answer
|
||||||
|
ans = strings.ToLower(strings.TrimSpace(ans))
|
||||||
|
|
||||||
|
// return the appropriate response
|
||||||
|
switch ans {
|
||||||
|
case "y":
|
||||||
|
return true, nil
|
||||||
|
case "":
|
||||||
|
return def, nil
|
||||||
|
default:
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
57
internal/installer/run.go
Normal file
57
internal/installer/run.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package installer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"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 := filepath.Dir(confpath)
|
||||||
|
|
||||||
|
// create paths for community and personal cheatsheets
|
||||||
|
community := filepath.Join(confdir, "cheatsheets", "community")
|
||||||
|
personal := filepath.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
|
||||||
|
fmt.Printf("Cloning community cheatsheets to %s.\n", community)
|
||||||
|
if err := clone(community); err != nil {
|
||||||
|
return fmt.Errorf("failed to clone cheatsheets: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// also create a directory for personal cheatsheets
|
||||||
|
fmt.Printf("Cloning personal cheatsheets to %s.\n", personal)
|
||||||
|
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
|
||||||
|
}
|
@ -13,7 +13,7 @@ func Path(filename string) string {
|
|||||||
// determine the path of this file during runtime
|
// determine the path of this file during runtime
|
||||||
_, thisfile, _, _ := runtime.Caller(0)
|
_, thisfile, _, _ := runtime.Caller(0)
|
||||||
|
|
||||||
// compute the config path
|
// compute the mock path
|
||||||
file, err := filepath.Abs(
|
file, err := filepath.Abs(
|
||||||
path.Join(
|
path.Join(
|
||||||
filepath.Dir(thisfile),
|
filepath.Dir(thisfile),
|
||||||
@ -22,7 +22,7 @@ func Path(filename string) string {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
if err != nil {
|
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
|
return file
|
||||||
|
37
internal/sheet/colorize.go
Normal file
37
internal/sheet/colorize.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package sheet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
|
||||||
|
"github.com/cheat/cheat/internal/config"
|
||||||
|
|
||||||
|
"github.com/alecthomas/chroma/quick"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Colorize applies syntax-highlighting to a cheatsheet's Text.
|
||||||
|
func (s *Sheet) Colorize(conf config.Config) {
|
||||||
|
|
||||||
|
// if the syntax was not specified, default to bash
|
||||||
|
lex := s.Syntax
|
||||||
|
if lex == "" {
|
||||||
|
lex = "bash"
|
||||||
|
}
|
||||||
|
|
||||||
|
// write colorized text into a buffer
|
||||||
|
var buf bytes.Buffer
|
||||||
|
err := quick.Highlight(
|
||||||
|
&buf,
|
||||||
|
s.Text,
|
||||||
|
lex,
|
||||||
|
conf.Formatter,
|
||||||
|
conf.Style,
|
||||||
|
)
|
||||||
|
|
||||||
|
// if colorization somehow failed, do nothing
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, swap the cheatsheet's Text with its colorized equivalent
|
||||||
|
s.Text = buf.String()
|
||||||
|
}
|
34
internal/sheet/colorize_test.go
Normal file
34
internal/sheet/colorize_test.go
Normal 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 := "[38;2;181;137;0mecho[0m[38;2;147;161;161m"
|
||||||
|
want += " [0m[38;2;42;161;152m'foo'[0m"
|
||||||
|
|
||||||
|
// assert
|
||||||
|
if s.Text != want {
|
||||||
|
t.Errorf("failed to colorize sheet: want: %s, got: %s", want, s.Text)
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Copy copies a cheatsheet to a new location
|
// Copy copies a cheatsheet to a new location
|
||||||
@ -22,7 +22,7 @@ func (s *Sheet) Copy(dest string) error {
|
|||||||
defer infile.Close()
|
defer infile.Close()
|
||||||
|
|
||||||
// create any necessary subdirectories
|
// create any necessary subdirectories
|
||||||
dirs := path.Dir(dest)
|
dirs := filepath.Dir(dest)
|
||||||
if dirs != "." {
|
if dirs != "." {
|
||||||
if err := os.MkdirAll(dirs, 0755); err != nil {
|
if err := os.MkdirAll(dirs, 0755); err != nil {
|
||||||
return fmt.Errorf("failed to create directory: %s, %v", dirs, err)
|
return fmt.Errorf("failed to create directory: %s, %v", dirs, err)
|
||||||
|
@ -25,7 +25,7 @@ func TestCopyFlat(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// mock a cheatsheet struct
|
// mock a cheatsheet struct
|
||||||
sheet, err := New("foo", src.Name(), []string{}, false)
|
sheet, err := New("foo", "community", src.Name(), []string{}, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("failed to init cheatsheet: %v", err)
|
t.Errorf("failed to init cheatsheet: %v", err)
|
||||||
}
|
}
|
||||||
@ -72,7 +72,13 @@ func TestCopyDeep(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// mock a cheatsheet struct
|
// 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 {
|
if err != nil {
|
||||||
t.Errorf("failed to init cheatsheet: %v", err)
|
t.Errorf("failed to init cheatsheet: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
package sheet
|
|
||||||
|
|
||||||
// Match encapsulates search matches within cheatsheets
|
|
||||||
type Match struct {
|
|
||||||
Line int
|
|
||||||
Text string
|
|
||||||
}
|
|
@ -3,43 +3,22 @@ package sheet
|
|||||||
import (
|
import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/mgutz/ansi"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Search searches for regexp matches in a cheatsheet's text, and optionally
|
// Search returns lines within a sheet's Text that match the search regex
|
||||||
// colorizes matching strings.
|
func (s *Sheet) Search(reg *regexp.Regexp) string {
|
||||||
func (s *Sheet) Search(reg *regexp.Regexp, colorize bool) []Match {
|
|
||||||
|
|
||||||
// record matches
|
// record matches
|
||||||
matches := []Match{}
|
matches := ""
|
||||||
|
|
||||||
// search through the cheatsheet's text line by line
|
// search through the cheatsheet's text line by line
|
||||||
// TODO: searching line-by-line is surely the "naive" approach. Revisit this
|
for _, line := range strings.Split(s.Text, "\n\n") {
|
||||||
// later with an eye for performance improvements.
|
|
||||||
for linenum, line := range strings.Split(s.Text, "\n") {
|
|
||||||
|
|
||||||
// exit early if the line doesn't match the regex
|
// exit early if the line doesn't match the regex
|
||||||
if !reg.MatchString(line) {
|
if reg.MatchString(line) {
|
||||||
continue
|
matches += line + "\n\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
// init the match
|
|
||||||
m := Match{
|
|
||||||
Line: linenum + 1,
|
|
||||||
Text: strings.TrimSpace(line),
|
|
||||||
}
|
|
||||||
|
|
||||||
// colorize the matching text if so configured
|
|
||||||
if colorize {
|
|
||||||
m.Text = reg.ReplaceAllStringFunc(m.Text, func(matched string) string {
|
|
||||||
return ansi.Color(matched, "red+b")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// record the match
|
|
||||||
matches = append(matches, m)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return matches
|
return strings.TrimSpace(matches)
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,6 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestSearchNoMatch ensures that the expected output is returned when no
|
// TestSearchNoMatch ensures that the expected output is returned when no
|
||||||
@ -24,21 +22,21 @@ func TestSearchNoMatch(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// search the sheet
|
// search the sheet
|
||||||
matches := sheet.Search(reg, false)
|
matches := sheet.Search(reg)
|
||||||
|
|
||||||
// assert that no matches were found
|
// assert that no matches were found
|
||||||
if len(matches) != 0 {
|
if matches != "" {
|
||||||
t.Errorf("failure: expected no matches: got: %s", spew.Sdump(matches))
|
t.Errorf("failure: expected no matches: got: %s", matches)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestSearchSingleMatchNoColor asserts that the expected output is returned
|
// TestSearchSingleMatch asserts that the expected output is returned
|
||||||
// when a single match is returned, and no colorization is applied.
|
// when a single match is returned
|
||||||
func TestSearchSingleMatchNoColor(t *testing.T) {
|
func TestSearchSingleMatch(t *testing.T) {
|
||||||
|
|
||||||
// mock a cheatsheet
|
// mock a cheatsheet
|
||||||
sheet := Sheet{
|
sheet := Sheet{
|
||||||
Text: "The quick brown fox\njumped over\nthe lazy dog.",
|
Text: "The quick brown fox\njumped over\n\nthe lazy dog.",
|
||||||
}
|
}
|
||||||
|
|
||||||
// compile the search regex
|
// compile the search regex
|
||||||
@ -48,69 +46,28 @@ func TestSearchSingleMatchNoColor(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// search the sheet
|
// search the sheet
|
||||||
matches := sheet.Search(reg, false)
|
matches := sheet.Search(reg)
|
||||||
|
|
||||||
// specify the expected results
|
// specify the expected results
|
||||||
want := []Match{
|
want := "The quick brown fox\njumped over"
|
||||||
Match{
|
|
||||||
Line: 1,
|
|
||||||
Text: "The quick brown fox",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// assert that the correct matches were returned
|
// assert that the correct matches were returned
|
||||||
if !reflect.DeepEqual(matches, want) {
|
if matches != want {
|
||||||
t.Errorf(
|
t.Errorf(
|
||||||
"failed to return expected matches: want:\n%s, got:\n%s",
|
"failed to return expected matches: want:\n%s, got:\n%s",
|
||||||
spew.Sdump(want),
|
want,
|
||||||
spew.Sdump(matches),
|
matches,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestSearchSingleMatchColorized asserts that the expected output is returned
|
// TestSearchMultiMatch asserts that the expected output is returned
|
||||||
// when a single match is returned, and colorization is applied
|
// when a multiple matches are returned
|
||||||
func TestSearchSingleMatchColorized(t *testing.T) {
|
func TestSearchMultiMatch(t *testing.T) {
|
||||||
|
|
||||||
// mock a cheatsheet
|
// mock a cheatsheet
|
||||||
sheet := Sheet{
|
sheet := Sheet{
|
||||||
Text: "The quick brown fox\njumped over\nthe lazy dog.",
|
Text: "The quick brown fox\n\njumped over\n\nthe lazy dog.",
|
||||||
}
|
|
||||||
|
|
||||||
// compile the search regex
|
|
||||||
reg, err := regexp.Compile("(?i)fox")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("failed to compile regex: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// search the sheet
|
|
||||||
matches := sheet.Search(reg, true)
|
|
||||||
|
|
||||||
// specify the expected results
|
|
||||||
want := []Match{
|
|
||||||
Match{
|
|
||||||
Line: 1,
|
|
||||||
Text: "The quick brown \x1b[1;31mfox\x1b[0m",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// assert that the correct matches were returned
|
|
||||||
if !reflect.DeepEqual(matches, want) {
|
|
||||||
t.Errorf(
|
|
||||||
"failed to return expected matches: want:\n%s, got:\n%s",
|
|
||||||
spew.Sdump(want),
|
|
||||||
spew.Sdump(matches),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestSearchMultiMatchNoColor asserts that the expected output is returned
|
|
||||||
// when a multiple matches are returned, and no colorization is applied
|
|
||||||
func TestSearchMultiMatchNoColor(t *testing.T) {
|
|
||||||
|
|
||||||
// mock a cheatsheet
|
|
||||||
sheet := Sheet{
|
|
||||||
Text: "The quick brown fox\njumped over\nthe lazy dog.",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// compile the search regex
|
// compile the search regex
|
||||||
@ -120,66 +77,17 @@ func TestSearchMultiMatchNoColor(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// search the sheet
|
// search the sheet
|
||||||
matches := sheet.Search(reg, false)
|
matches := sheet.Search(reg)
|
||||||
|
|
||||||
// specify the expected results
|
// specify the expected results
|
||||||
want := []Match{
|
want := "The quick brown fox\n\nthe lazy dog."
|
||||||
Match{
|
|
||||||
Line: 1,
|
|
||||||
Text: "The quick brown fox",
|
|
||||||
},
|
|
||||||
Match{
|
|
||||||
Line: 3,
|
|
||||||
Text: "the lazy dog.",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// assert that the correct matches were returned
|
// assert that the correct matches were returned
|
||||||
if !reflect.DeepEqual(matches, want) {
|
if !reflect.DeepEqual(matches, want) {
|
||||||
t.Errorf(
|
t.Errorf(
|
||||||
"failed to return expected matches: want:\n%s, got:\n%s",
|
"failed to return expected matches: want:\n%s, got:\n%s",
|
||||||
spew.Sdump(want),
|
want,
|
||||||
spew.Sdump(matches),
|
matches,
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestSearchMultiMatchColorized asserts that the expected output is returned
|
|
||||||
// when a multiple matches are returned, and colorization is applied
|
|
||||||
func TestSearchMultiMatchColorized(t *testing.T) {
|
|
||||||
|
|
||||||
// mock a cheatsheet
|
|
||||||
sheet := Sheet{
|
|
||||||
Text: "The quick brown fox\njumped over\nthe lazy dog.",
|
|
||||||
}
|
|
||||||
|
|
||||||
// compile the search regex
|
|
||||||
reg, err := regexp.Compile("(?i)the")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("failed to compile regex: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// search the sheet
|
|
||||||
matches := sheet.Search(reg, true)
|
|
||||||
|
|
||||||
// specify the expected results
|
|
||||||
want := []Match{
|
|
||||||
Match{
|
|
||||||
Line: 1,
|
|
||||||
Text: "\x1b[1;31mThe\x1b[0m quick brown fox",
|
|
||||||
},
|
|
||||||
Match{
|
|
||||||
Line: 3,
|
|
||||||
Text: "\x1b[1;31mthe\x1b[0m lazy dog.",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// assert that the correct matches were returned
|
|
||||||
if !reflect.DeepEqual(matches, want) {
|
|
||||||
t.Errorf(
|
|
||||||
"failed to return expected matches: want:\n%s, got:\n%s",
|
|
||||||
spew.Sdump(want),
|
|
||||||
spew.Sdump(matches),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,17 +10,19 @@ import (
|
|||||||
|
|
||||||
// Sheet encapsulates sheet information
|
// Sheet encapsulates sheet information
|
||||||
type Sheet struct {
|
type Sheet struct {
|
||||||
Title string
|
Title string
|
||||||
Path string
|
CheatPath string
|
||||||
Text string
|
Path string
|
||||||
Tags []string
|
Text string
|
||||||
Syntax string
|
Tags []string
|
||||||
ReadOnly bool
|
Syntax string
|
||||||
|
ReadOnly bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// New initializes a new Sheet
|
// New initializes a new Sheet
|
||||||
func New(
|
func New(
|
||||||
title string,
|
title string,
|
||||||
|
cheatpath string,
|
||||||
path string,
|
path string,
|
||||||
tags []string,
|
tags []string,
|
||||||
readOnly bool,
|
readOnly bool,
|
||||||
@ -46,11 +48,12 @@ func New(
|
|||||||
|
|
||||||
// initialize and return a sheet
|
// initialize and return a sheet
|
||||||
return Sheet{
|
return Sheet{
|
||||||
Title: title,
|
Title: title,
|
||||||
Path: path,
|
CheatPath: cheatpath,
|
||||||
Text: text + "\n",
|
Path: path,
|
||||||
Tags: tags,
|
Text: text + "\n",
|
||||||
Syntax: fm.Syntax,
|
Tags: tags,
|
||||||
ReadOnly: readOnly,
|
Syntax: fm.Syntax,
|
||||||
|
ReadOnly: readOnly,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ func TestSheetSuccess(t *testing.T) {
|
|||||||
// initialize a sheet
|
// initialize a sheet
|
||||||
sheet, err := New(
|
sheet, err := New(
|
||||||
"foo",
|
"foo",
|
||||||
|
"community",
|
||||||
mock.Path("sheet/foo"),
|
mock.Path("sheet/foo"),
|
||||||
[]string{"alpha", "bravo"},
|
[]string{"alpha", "bravo"},
|
||||||
false,
|
false,
|
||||||
@ -61,6 +62,7 @@ func TestSheetFailure(t *testing.T) {
|
|||||||
// initialize a sheet
|
// initialize a sheet
|
||||||
_, err := New(
|
_, err := New(
|
||||||
"foo",
|
"foo",
|
||||||
|
"community",
|
||||||
mock.Path("/does-not-exist"),
|
mock.Path("/does-not-exist"),
|
||||||
[]string{"alpha", "bravo"},
|
[]string{"alpha", "bravo"},
|
||||||
false,
|
false,
|
||||||
@ -69,3 +71,20 @@ func TestSheetFailure(t *testing.T) {
|
|||||||
t.Errorf("failed to return an error on unreadable sheet")
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -33,7 +33,7 @@ func Load(cheatpaths []cp.Cheatpath) ([]map[string]sheet.Sheet, error) {
|
|||||||
|
|
||||||
// fail if an error occurred while walking the directory
|
// fail if an error occurred while walking the directory
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error walking path: %v", err)
|
return fmt.Errorf("failed to walk path: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't register directories as cheatsheets
|
// don't register directories as cheatsheets
|
||||||
@ -59,9 +59,20 @@ func Load(cheatpaths []cp.Cheatpath) ([]map[string]sheet.Sheet, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parse the cheatsheet file into a `sheet` struct
|
// 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 {
|
if err != nil {
|
||||||
return fmt.Errorf("could not create sheet: %v", err)
|
return fmt.Errorf(
|
||||||
|
"failed to load sheet: %s, path: %s, err: %v",
|
||||||
|
title,
|
||||||
|
path,
|
||||||
|
err,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// register the cheatsheet on its cheatpath, keyed by its title
|
// register the cheatsheet on its cheatpath, keyed by its title
|
||||||
|
@ -1,3 +1,62 @@
|
|||||||
package sheets
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/cheat/cheat/internal/sheet"
|
"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) {
|
func TestTags(t *testing.T) {
|
||||||
|
|
||||||
// mock cheatsheets available on multiple cheatpaths
|
// mock cheatsheets available on multiple cheatpaths
|
||||||
|
0
mocks/cheatsheets/community/.hiddenfile
Normal file
0
mocks/cheatsheets/community/.hiddenfile
Normal file
4
mocks/cheatsheets/community/bar
Normal file
4
mocks/cheatsheets/community/bar
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
tags: [ community ]
|
||||||
|
---
|
||||||
|
This is the bar cheatsheet.
|
4
mocks/cheatsheets/community/foo
Normal file
4
mocks/cheatsheets/community/foo
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
tags: [ community ]
|
||||||
|
---
|
||||||
|
This is the foo cheatsheet.
|
4
mocks/cheatsheets/personal/bat
Normal file
4
mocks/cheatsheets/personal/bat
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
tags: [ personal ]
|
||||||
|
---
|
||||||
|
This is the bat cheatsheet.
|
4
mocks/cheatsheets/personal/baz
Normal file
4
mocks/cheatsheets/personal/baz
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
tags: [ personal ]
|
||||||
|
---
|
||||||
|
This is the baz cheatsheet.
|
4
mocks/sheet/bad-fm
Normal file
4
mocks/sheet/bad-fm
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
syntax: sh
|
||||||
|
|
||||||
|
This is malformed frontmatter.
|
@ -1,9 +0,0 @@
|
|||||||
function _cheat_autocomplete {
|
|
||||||
sheets=$(cheat -l | sed -n '2,$p'|cut -d' ' -f1)
|
|
||||||
COMPREPLY=()
|
|
||||||
if [ $COMP_CWORD = 1 ]; then
|
|
||||||
COMPREPLY=(`compgen -W "$sheets" -- $2`)
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
complete -F _cheat_autocomplete cheat
|
|
74
scripts/cheat.bash
Executable file
74
scripts/cheat.bash
Executable file
@ -0,0 +1,74 @@
|
|||||||
|
# cheat(1) completion -*- shell-script -*-
|
||||||
|
|
||||||
|
# generate cheatsheet completions, optionally using `fzf`
|
||||||
|
_cheat_complete_cheatsheets()
|
||||||
|
{
|
||||||
|
if [[ "$CHEAT_USE_FZF" = true ]]; then
|
||||||
|
FZF_COMPLETION_TRIGGER='' _fzf_complete "--no-multi" "$@" < <(
|
||||||
|
cheat -l | tail -n +2 | cut -d' ' -f1
|
||||||
|
)
|
||||||
|
else
|
||||||
|
COMPREPLY=( $(compgen -W "$(cheat -l | tail -n +2 | cut -d' ' -f1)" -- "$cur") )
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# generate tag completions, optionally using `fzf`
|
||||||
|
_cheat_complete_tags()
|
||||||
|
{
|
||||||
|
if [ "$CHEAT_USE_FZF" = true ]; then
|
||||||
|
FZF_COMPLETION_TRIGGER='' _fzf_complete "--no-multi" "$@" < <(cheat -T)
|
||||||
|
else
|
||||||
|
COMPREPLY=( $(compgen -W "$(cheat -T)" -- "$cur") )
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# implement the `cheat` autocompletions
|
||||||
|
_cheat()
|
||||||
|
{
|
||||||
|
local cur prev words cword split
|
||||||
|
_init_completion -s || return
|
||||||
|
|
||||||
|
# complete options that are currently being typed: `--col` => `--colorize`
|
||||||
|
if [[ $cur == -* ]]; then
|
||||||
|
COMPREPLY=( $(compgen -W '$(_parse_help "$1" | sed "s/=//g")' -- "$cur") )
|
||||||
|
[[ $COMPREPLY == *= ]] && compopt -o nospace
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# implement completions
|
||||||
|
case $prev in
|
||||||
|
--colorize|-c|\
|
||||||
|
--directories|-d|\
|
||||||
|
--init|\
|
||||||
|
--regex|-r|\
|
||||||
|
--search|-s|\
|
||||||
|
--tags|-T|\
|
||||||
|
--version|-v)
|
||||||
|
# noop the above, which should implement no completions
|
||||||
|
;;
|
||||||
|
--edit|-e)
|
||||||
|
_cheat_complete_cheatsheets
|
||||||
|
;;
|
||||||
|
--list|-l)
|
||||||
|
_cheat_complete_cheatsheets
|
||||||
|
;;
|
||||||
|
--path|-p)
|
||||||
|
COMPREPLY=( $(compgen -W "$(cheat -d | cut -d':' -f1)" -- "$cur") )
|
||||||
|
;;
|
||||||
|
--rm)
|
||||||
|
_cheat_complete_cheatsheets
|
||||||
|
;;
|
||||||
|
--tag|-t)
|
||||||
|
_cheat_complete_tags
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
_cheat_complete_cheatsheets
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
$split && return
|
||||||
|
|
||||||
|
} &&
|
||||||
|
complete -F _cheat cheat
|
||||||
|
|
||||||
|
# ex: filetype=sh
|
65
scripts/cheat.zsh
Executable file
65
scripts/cheat.zsh
Executable file
@ -0,0 +1,65 @@
|
|||||||
|
#compdef cheat
|
||||||
|
|
||||||
|
local cheats taglist pathlist
|
||||||
|
|
||||||
|
_cheat_complete_personal_cheatsheets()
|
||||||
|
{
|
||||||
|
cheats=("${(f)$(cheat -l -t personal | tail -n +2 | cut -d' ' -f1)}")
|
||||||
|
_describe -t cheats 'cheats' cheats
|
||||||
|
}
|
||||||
|
|
||||||
|
_cheat_complete_full_cheatsheets()
|
||||||
|
{
|
||||||
|
cheats=("${(f)$(cheat -l | tail -n +2 | cut -d' ' -f1)}")
|
||||||
|
_describe -t cheats 'cheats' cheats
|
||||||
|
}
|
||||||
|
|
||||||
|
_cheat_complete_tags()
|
||||||
|
{
|
||||||
|
taglist=("${(f)$(cheat -T)}")
|
||||||
|
_describe -t taglist 'taglist' taglist
|
||||||
|
}
|
||||||
|
|
||||||
|
_cheat_complete_paths()
|
||||||
|
{
|
||||||
|
pathlist=("${(f)$(cheat -d | cut -d':' -f1)}")
|
||||||
|
_describe -t pathlist 'pathlist' pathlist
|
||||||
|
}
|
||||||
|
|
||||||
|
_cheat() {
|
||||||
|
|
||||||
|
_arguments -C \
|
||||||
|
'(--init)--init[Write a default config file to stdout]: :->none' \
|
||||||
|
'(-c --colorize)'{-c,--colorize}'[Colorize output]: :->none' \
|
||||||
|
'(-d --directories)'{-d,--directories}'[List cheatsheet directories]: :->none' \
|
||||||
|
'(-e --edit)'{-e,--edit}'[Edit <sheet>]: :->personal' \
|
||||||
|
'(-l --list)'{-l,--list}'[List cheatsheets]: :->full' \
|
||||||
|
'(-p --path)'{-p,--path}'[Return only sheets found on path <name>]: :->pathlist' \
|
||||||
|
'(-r --regex)'{-r,--regex}'[Treat search <phrase> as a regex]: :->none' \
|
||||||
|
'(-s --search)'{-s,--search}'[Search cheatsheets for <phrase>]: :->none' \
|
||||||
|
'(-t --tag)'{-t,--tag}'[Return only sheets matching <tag>]: :->taglist' \
|
||||||
|
'(-T --tags)'{-T,--tags}'[List all tags in use]: :->none' \
|
||||||
|
'(-v --version)'{-v,--version}'[Print the version number]: :->none' \
|
||||||
|
'(--rm)--rm[Remove (delete) <sheet>]: :->personal'
|
||||||
|
|
||||||
|
case $state in
|
||||||
|
(none)
|
||||||
|
;;
|
||||||
|
(full)
|
||||||
|
_cheat_complete_full_cheatsheets
|
||||||
|
;;
|
||||||
|
(personal)
|
||||||
|
_cheat_complete_personal_cheatsheets
|
||||||
|
;;
|
||||||
|
(taglist)
|
||||||
|
_cheat_complete_tags
|
||||||
|
;;
|
||||||
|
(pathlist)
|
||||||
|
_cheat_complete_paths
|
||||||
|
;;
|
||||||
|
(*)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
compdef _cheat cheat
|
@ -1,11 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# This function enables you to choose a cheatsheet to view by selecting output
|
|
||||||
# from `cheat -l`. `source` it in your shell to enable it. (Consider renaming
|
|
||||||
# or aliasing it to something convenient.)
|
|
||||||
|
|
||||||
# Arguments passed to this function (like --color) will be passed to the second
|
|
||||||
# invokation of `cheat`.
|
|
||||||
function cheat-fzf {
|
|
||||||
eval `cheat -l | tail -n +2 | fzf | awk -v vars="$*" '{ print "cheat " $1 " -t " $3, vars }'`
|
|
||||||
}
|
|
46
scripts/git/cheatsheets
Executable file
46
scripts/git/cheatsheets
Executable file
@ -0,0 +1,46 @@
|
|||||||
|
#!/bin/sh -e
|
||||||
|
|
||||||
|
pull() {
|
||||||
|
for d in `cheat -d | awk '{print $2}'`;
|
||||||
|
do
|
||||||
|
echo "Update $d"
|
||||||
|
cd "$d"
|
||||||
|
[ -d ".git" ] && git pull || :
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Finished update"
|
||||||
|
}
|
||||||
|
|
||||||
|
push() {
|
||||||
|
for d in `cheat -d | grep -v "community" | awk '{print $2}'`;
|
||||||
|
do
|
||||||
|
cd "$d"
|
||||||
|
if [ -d ".git" ]
|
||||||
|
then
|
||||||
|
echo "Push modifications $d"
|
||||||
|
files=$(git ls-files -mo | tr '\n' ' ')
|
||||||
|
git add -A && git commit -m "Edited files: $files" && git push || :
|
||||||
|
else
|
||||||
|
echo "$(pwd) is not a git managed folder"
|
||||||
|
echo "First connect this to your personal git repository"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Finished push operation"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if [ "$1" = "pull" ]; then
|
||||||
|
pull
|
||||||
|
elif [ "$1" = "push" ]; then
|
||||||
|
push
|
||||||
|
else
|
||||||
|
echo "Usage:
|
||||||
|
# pull changes
|
||||||
|
cheatsheets pull
|
||||||
|
|
||||||
|
# push changes
|
||||||
|
cheatsheets push"
|
||||||
|
fi
|
21
vendor/github.com/alecthomas/chroma/.golangci.yml
generated
vendored
21
vendor/github.com/alecthomas/chroma/.golangci.yml
generated
vendored
@ -20,6 +20,22 @@ linters:
|
|||||||
- wsl
|
- wsl
|
||||||
- gomnd
|
- gomnd
|
||||||
- gocognit
|
- gocognit
|
||||||
|
- goerr113
|
||||||
|
- nolintlint
|
||||||
|
- testpackage
|
||||||
|
- godot
|
||||||
|
- nestif
|
||||||
|
- paralleltest
|
||||||
|
- nlreturn
|
||||||
|
- cyclop
|
||||||
|
- exhaustivestruct
|
||||||
|
- gci
|
||||||
|
- gofumpt
|
||||||
|
- errorlint
|
||||||
|
- exhaustive
|
||||||
|
- ifshort
|
||||||
|
- wrapcheck
|
||||||
|
- stylecheck
|
||||||
|
|
||||||
linters-settings:
|
linters-settings:
|
||||||
govet:
|
govet:
|
||||||
@ -31,6 +47,11 @@ linters-settings:
|
|||||||
goconst:
|
goconst:
|
||||||
min-len: 8
|
min-len: 8
|
||||||
min-occurrences: 3
|
min-occurrences: 3
|
||||||
|
forbidigo:
|
||||||
|
forbid:
|
||||||
|
- (Must)?NewLexer
|
||||||
|
exclude_godoc_examples: false
|
||||||
|
|
||||||
|
|
||||||
issues:
|
issues:
|
||||||
max-per-linter: 0
|
max-per-linter: 0
|
||||||
|
36
vendor/github.com/alecthomas/chroma/.goreleaser.yml
generated
vendored
36
vendor/github.com/alecthomas/chroma/.goreleaser.yml
generated
vendored
@ -3,28 +3,34 @@ release:
|
|||||||
github:
|
github:
|
||||||
owner: alecthomas
|
owner: alecthomas
|
||||||
name: chroma
|
name: chroma
|
||||||
brew:
|
brews:
|
||||||
install: bin.install "chroma"
|
-
|
||||||
|
install: bin.install "chroma"
|
||||||
|
env:
|
||||||
|
- CGO_ENABLED=0
|
||||||
builds:
|
builds:
|
||||||
- goos:
|
- goos:
|
||||||
- linux
|
- linux
|
||||||
- darwin
|
- darwin
|
||||||
- windows
|
- windows
|
||||||
goarch:
|
goarch:
|
||||||
- amd64
|
- arm64
|
||||||
- "386"
|
- amd64
|
||||||
|
- "386"
|
||||||
goarm:
|
goarm:
|
||||||
- "6"
|
- "6"
|
||||||
main: ./cmd/chroma/main.go
|
dir: ./cmd/chroma
|
||||||
|
main: .
|
||||||
ldflags: -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}
|
ldflags: -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}
|
||||||
binary: chroma
|
binary: chroma
|
||||||
archive:
|
archives:
|
||||||
format: tar.gz
|
-
|
||||||
name_template: '{{ .Binary }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{
|
format: tar.gz
|
||||||
|
name_template: '{{ .Binary }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{
|
||||||
.Arm }}{{ end }}'
|
.Arm }}{{ end }}'
|
||||||
files:
|
files:
|
||||||
- COPYING
|
- COPYING
|
||||||
- README*
|
- README*
|
||||||
snapshot:
|
snapshot:
|
||||||
name_template: SNAPSHOT-{{ .Commit }}
|
name_template: SNAPSHOT-{{ .Commit }}
|
||||||
checksum:
|
checksum:
|
||||||
|
12
vendor/github.com/alecthomas/chroma/.travis.yml
generated
vendored
12
vendor/github.com/alecthomas/chroma/.travis.yml
generated
vendored
@ -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
|
|
||||||
|
|
6
vendor/github.com/alecthomas/chroma/Makefile
generated
vendored
6
vendor/github.com/alecthomas/chroma/Makefile
generated
vendored
@ -1,5 +1,7 @@
|
|||||||
.PHONY: chromad upload all
|
.PHONY: chromad upload all
|
||||||
|
|
||||||
|
VERSION ?= $(shell git describe --tags --dirty --always)
|
||||||
|
|
||||||
all: README.md tokentype_string.go
|
all: README.md tokentype_string.go
|
||||||
|
|
||||||
README.md: lexers/*/*.go
|
README.md: lexers/*/*.go
|
||||||
@ -9,10 +11,8 @@ tokentype_string.go: types.go
|
|||||||
go generate
|
go generate
|
||||||
|
|
||||||
chromad:
|
chromad:
|
||||||
(cd ./cmd/chromad && go get github.com/GeertJohan/go.rice/rice@master && go install github.com/GeertJohan/go.rice/rice)
|
|
||||||
rm -f chromad
|
rm -f chromad
|
||||||
(export CGOENABLED=0 GOOS=linux ; cd ./cmd/chromad && go build -o ../../chromad .)
|
(export CGOENABLED=0 GOOS=linux GOARCH=amd64; cd ./cmd/chromad && go build -ldflags="-X 'main.version=$(VERSION)'" -o ../../chromad .)
|
||||||
rice append -i ./cmd/chromad --exec=./chromad
|
|
||||||
|
|
||||||
upload: chromad
|
upload: chromad
|
||||||
scp chromad root@swapoff.org: && \
|
scp chromad root@swapoff.org: && \
|
||||||
|
60
vendor/github.com/alecthomas/chroma/README.md
generated
vendored
60
vendor/github.com/alecthomas/chroma/README.md
generated
vendored
@ -1,4 +1,5 @@
|
|||||||
# Chroma — A general purpose syntax highlighter in pure Go [](https://godoc.org/github.com/alecthomas/chroma) [](https://travis-ci.org/alecthomas/chroma) [](https://gitter.im/alecthomas/Lobby)
|
# Chroma — A general purpose syntax highlighter in pure Go
|
||||||
|
[](https://godoc.org/github.com/alecthomas/chroma) [](https://github.com/alecthomas/chroma/actions/workflows/ci.yml) [](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.
|
> **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 +37,30 @@ translators for Pygments lexers and styles.
|
|||||||
Prefix | Language
|
Prefix | Language
|
||||||
:----: | --------
|
:----: | --------
|
||||||
A | ABAP, ABNF, ActionScript, ActionScript 3, Ada, Angular2, ANTLR, ApacheConf, APL, AppleScript, Arduino, Awk
|
A | ABAP, ABNF, ActionScript, ActionScript 3, Ada, Angular2, ANTLR, ApacheConf, APL, AppleScript, Arduino, Awk
|
||||||
B | Ballerina, Base Makefile, Bash, Batchfile, BlitzBasic, BNF, Brainfuck
|
B | Ballerina, Base Makefile, Bash, Batchfile, BibTeX, Bicep, 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
|
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
|
D | D, Dart, Diff, Django/Jinja, Docker, DTD, Dylan
|
||||||
E | EBNF, Elixir, Elm, EmacsLisp, Erlang
|
E | EBNF, Elixir, Elm, EmacsLisp, Erlang
|
||||||
F | Factor, Fish, Forth, Fortran, FSharp
|
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
|
G | GAS, GDScript, Genshi, Genshi HTML, Genshi Text, Gherkin, GLSL, Gnuplot, Go, Go HTML Template, Go Text Template, GraphQL, Groff, Groovy
|
||||||
H | Handlebars, Haskell, Haxe, HCL, Hexdump, HTML, HTTP, Hy
|
H | Handlebars, Haskell, Haxe, HCL, Hexdump, HLB, HTML, HTTP, Hy
|
||||||
I | Idris, INI, Io
|
I | Idris, Igor, INI, Io
|
||||||
J | J, Java, JavaScript, JSON, Julia, Jungle
|
J | J, Java, JavaScript, JSON, Julia, Jungle
|
||||||
K | Kotlin
|
K | Kotlin
|
||||||
L | Lighttpd configuration file, LLVM, Lua
|
L | Lighttpd configuration file, LLVM, Lua
|
||||||
M | Mako, markdown, Mason, Mathematica, Matlab, MiniZinc, MLIR, Modula-2, MonkeyC, MorrowindScript, Myghty, MySQL
|
M | Mako, markdown, Mason, Mathematica, Matlab, MiniZinc, MLIR, Modula-2, MonkeyC, MorrowindScript, Myghty, MySQL
|
||||||
N | NASM, Newspeak, Nginx configuration file, Nim, Nix
|
N | NASM, Newspeak, Nginx configuration file, Nim, Nix
|
||||||
O | Objective-C, OCaml, Octave, OpenSCAD, Org Mode
|
O | Objective-C, OCaml, Octave, OnesEnterprise, OpenEdge ABL, 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 2, Python
|
||||||
Q | QBasic
|
Q | QBasic
|
||||||
R | R, Racket, Ragel, react, reg, reStructuredText, Rexx, Ruby, Rust
|
R | R, Racket, Ragel, Raku, react, ReasonML, reg, reStructuredText, Rexx, Ruby, Rust
|
||||||
S | Sass, Scala, Scheme, Scilab, SCSS, Smalltalk, Smarty, SML, Snobol, Solidity, SPARQL, SQL, SquidConf, Swift, SYSTEMD, systemverilog
|
S | SAS, Sass, Scala, Scheme, Scilab, SCSS, Smalltalk, Smarty, Snobol, Solidity, SPARQL, SQL, SquidConf, Standard ML, Stylus, Svelte, Swift, SYSTEMD, systemverilog
|
||||||
T | TableGen, TASM, Tcl, Tcsh, Termcap, Terminfo, Terraform, TeX, Thrift, TOML, TradingView, Transact-SQL, Turing, Turtle, Twig, TypeScript, TypoScript, TypoScriptCssData, TypoScriptHtmlData
|
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
|
V | VB.net, verilog, VHDL, VimL, vue
|
||||||
W | WDTE
|
W | WDTE
|
||||||
X | XML, Xorg
|
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
|
_I will attempt to keep this section up to date, but an authoritative list can be
|
||||||
@ -183,7 +185,7 @@ following constructor options:
|
|||||||
- `ClassPrefix(prefix)` - prefix each generated CSS class.
|
- `ClassPrefix(prefix)` - prefix each generated CSS class.
|
||||||
- `TabWidth(width)` - Set the rendered tab width, in characters.
|
- `TabWidth(width)` - Set the rendered tab width, in characters.
|
||||||
- `WithLineNumbers()` - Render line numbers (style with `LineNumbers`).
|
- `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`).
|
- `HighlightLines(ranges)` - Highlight lines in these ranges (style with `LineHighlight`).
|
||||||
- `LineNumbersInTable()` - Use a table for formatting line numbers and code, rather than spans.
|
- `LineNumbersInTable()` - Use a table for formatting line numbers and code, rather than spans.
|
||||||
|
|
||||||
@ -209,13 +211,13 @@ using the included Python 3 script `pygments2chroma.py`. I use something like
|
|||||||
the following:
|
the following:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
python3 ~/Projects/chroma/_tools/pygments2chroma.py \
|
python3 _tools/pygments2chroma.py \
|
||||||
pygments.lexers.jvm.KotlinLexer \
|
pygments.lexers.jvm.KotlinLexer \
|
||||||
> ~/Projects/chroma/lexers/kotlin.go \
|
> lexers/k/kotlin.go \
|
||||||
&& gofmt -s -w ~/Projects/chroma/lexers/*.go
|
&& gofmt -s -w lexers/k/kotlin.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.
|
for a list of lexers, and notes on some of the issues importing them.
|
||||||
|
|
||||||
<a id="markdown-formatters" name="formatters"></a>
|
<a id="markdown-formatters" name="formatters"></a>
|
||||||
@ -248,18 +250,34 @@ For a quick overview of the available styles and how they look, check out the [C
|
|||||||
<a id="markdown-command-line-interface" name="command-line-interface"></a>
|
<a id="markdown-command-line-interface" name="command-line-interface"></a>
|
||||||
## Command-line interface
|
## Command-line interface
|
||||||
|
|
||||||
A command-line interface to Chroma is included. It can be installed with:
|
A command-line interface to Chroma is included.
|
||||||
|
|
||||||
```sh
|
Binaries are available to install from [the releases page](https://github.com/alecthomas/chroma/releases).
|
||||||
go get -u github.com/alecthomas/chroma/cmd/chroma
|
|
||||||
|
The CLI can be used as a preprocessor to colorise output of `less(1)`,
|
||||||
|
see documentation for the `LESSOPEN` environment variable.
|
||||||
|
|
||||||
|
The `--fail` flag can be used to suppress output and return with exit status
|
||||||
|
1 to facilitate falling back to some other preprocessor in case chroma
|
||||||
|
does not resolve a specific lexer to use for the given file. For example:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
export LESSOPEN='| p() { chroma --fail "$1" || cat "$1"; }; p "%s"'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Replace `cat` with your favourite fallback preprocessor.
|
||||||
|
|
||||||
|
When invoked as `.lessfilter`, the `--fail` flag is automatically turned
|
||||||
|
on under the hood for easy integration with [lesspipe shipping with
|
||||||
|
Debian and derivatives](https://manpages.debian.org/lesspipe#USER_DEFINED_FILTERS);
|
||||||
|
for that setup the `chroma` executable can be just symlinked to `~/.lessfilter`.
|
||||||
|
|
||||||
<a id="markdown-whats-missing-compared-to-pygments" name="whats-missing-compared-to-pygments"></a>
|
<a id="markdown-whats-missing-compared-to-pygments" name="whats-missing-compared-to-pygments"></a>
|
||||||
## What's missing compared to Pygments?
|
## What's missing compared to Pygments?
|
||||||
|
|
||||||
- Quite a few lexers, for various reasons (pull-requests welcome):
|
- Quite a few lexers, for various reasons (pull-requests welcome):
|
||||||
- Pygments lexers for complex languages often include custom code to
|
- Pygments lexers for complex languages often include custom code to
|
||||||
handle certain aspects, such as Perl6's ability to nest code inside
|
handle certain aspects, such as Raku's ability to nest code inside
|
||||||
regular expressions. These require time and effort to convert.
|
regular expressions. These require time and effort to convert.
|
||||||
- I mostly only converted languages I had heard of, to reduce the porting cost.
|
- I mostly only converted languages I had heard of, to reduce the porting cost.
|
||||||
- Some more esoteric features of Pygments are omitted for simplicity.
|
- Some more esoteric features of Pygments are omitted for simplicity.
|
||||||
|
105
vendor/github.com/alecthomas/chroma/formatters/html/html.go
generated
vendored
105
vendor/github.com/alecthomas/chroma/formatters/html/html.go
generated
vendored
@ -22,6 +22,9 @@ func ClassPrefix(prefix string) Option { return func(f *Formatter) { f.prefix =
|
|||||||
// WithClasses emits HTML using CSS classes, rather than inline styles.
|
// WithClasses emits HTML using CSS classes, rather than inline styles.
|
||||||
func WithClasses(b bool) Option { return func(f *Formatter) { f.Classes = b } }
|
func WithClasses(b bool) Option { return func(f *Formatter) { f.Classes = b } }
|
||||||
|
|
||||||
|
// WithAllClasses disables an optimisation that omits redundant CSS classes.
|
||||||
|
func WithAllClasses(b bool) Option { return func(f *Formatter) { f.allClasses = b } }
|
||||||
|
|
||||||
// TabWidth sets the number of characters for a tab. Defaults to 8.
|
// TabWidth sets the number of characters for a tab. Defaults to 8.
|
||||||
func TabWidth(width int) Option { return func(f *Formatter) { f.tabWidth = width } }
|
func TabWidth(width int) Option { return func(f *Formatter) { f.tabWidth = width } }
|
||||||
|
|
||||||
@ -43,6 +46,13 @@ func WithPreWrapper(wrapper PreWrapper) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WrapLongLines wraps long lines.
|
||||||
|
func WrapLongLines(b bool) Option {
|
||||||
|
return func(f *Formatter) {
|
||||||
|
f.wrapLongLines = b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WithLineNumbers formats output with line numbers.
|
// WithLineNumbers formats output with line numbers.
|
||||||
func WithLineNumbers(b bool) Option {
|
func WithLineNumbers(b bool) Option {
|
||||||
return func(f *Formatter) {
|
return func(f *Formatter) {
|
||||||
@ -128,10 +138,18 @@ var (
|
|||||||
}
|
}
|
||||||
defaultPreWrapper = preWrapper{
|
defaultPreWrapper = preWrapper{
|
||||||
start: func(code bool, styleAttr string) string {
|
start: func(code bool, styleAttr string) string {
|
||||||
return fmt.Sprintf("<pre%s>", styleAttr)
|
if code {
|
||||||
|
return fmt.Sprintf(`<pre tabindex="0"%s><code>`, styleAttr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf(`<pre tabindex="0"%s>`, styleAttr)
|
||||||
},
|
},
|
||||||
end: func(code bool) string {
|
end: func(code bool) string {
|
||||||
return "</pre>"
|
if code {
|
||||||
|
return `</code></pre>`
|
||||||
|
}
|
||||||
|
|
||||||
|
return `</pre>`
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -141,8 +159,10 @@ type Formatter struct {
|
|||||||
standalone bool
|
standalone bool
|
||||||
prefix string
|
prefix string
|
||||||
Classes bool // Exported field to detect when classes are being used
|
Classes bool // Exported field to detect when classes are being used
|
||||||
|
allClasses bool
|
||||||
preWrapper PreWrapper
|
preWrapper PreWrapper
|
||||||
tabWidth int
|
tabWidth int
|
||||||
|
wrapLongLines bool
|
||||||
lineNumbers bool
|
lineNumbers bool
|
||||||
lineNumbersInTable bool
|
lineNumbersInTable bool
|
||||||
linkableLineNumbers bool
|
linkableLineNumbers bool
|
||||||
@ -188,15 +208,15 @@ func (f *Formatter) writeHTML(w io.Writer, style *chroma.Style, tokens []chroma.
|
|||||||
wrapInTable := f.lineNumbers && f.lineNumbersInTable
|
wrapInTable := f.lineNumbers && f.lineNumbersInTable
|
||||||
|
|
||||||
lines := chroma.SplitTokensIntoLines(tokens)
|
lines := chroma.SplitTokensIntoLines(tokens)
|
||||||
lineDigits := len(fmt.Sprintf("%d", len(lines)))
|
lineDigits := len(fmt.Sprintf("%d", f.baseLineNumber+len(lines)-1))
|
||||||
highlightIndex := 0
|
highlightIndex := 0
|
||||||
|
|
||||||
if wrapInTable {
|
if wrapInTable {
|
||||||
// List line numbers in its own <td>
|
// List line numbers in its own <td>
|
||||||
fmt.Fprintf(w, "<div%s>\n", f.styleAttr(css, chroma.Background))
|
fmt.Fprintf(w, "<div%s>\n", f.styleAttr(css, chroma.PreWrapper))
|
||||||
fmt.Fprintf(w, "<table%s><tr>", f.styleAttr(css, chroma.LineTable))
|
fmt.Fprintf(w, "<table%s><tr>", f.styleAttr(css, chroma.LineTable))
|
||||||
fmt.Fprintf(w, "<td%s>\n", f.styleAttr(css, chroma.LineTableTD))
|
fmt.Fprintf(w, "<td%s>\n", f.styleAttr(css, chroma.LineTableTD))
|
||||||
fmt.Fprintf(w, f.preWrapper.Start(false, f.styleAttr(css, chroma.Background)))
|
fmt.Fprintf(w, f.preWrapper.Start(false, f.styleAttr(css, chroma.PreWrapper)))
|
||||||
for index := range lines {
|
for index := range lines {
|
||||||
line := f.baseLineNumber + index
|
line := f.baseLineNumber + index
|
||||||
highlight, next := f.shouldHighlight(highlightIndex, line)
|
highlight, next := f.shouldHighlight(highlightIndex, line)
|
||||||
@ -207,7 +227,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>", 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 {
|
if highlight {
|
||||||
fmt.Fprintf(w, "</span>")
|
fmt.Fprintf(w, "</span>")
|
||||||
@ -218,7 +238,7 @@ func (f *Formatter) writeHTML(w io.Writer, style *chroma.Style, tokens []chroma.
|
|||||||
fmt.Fprintf(w, "<td%s>\n", f.styleAttr(css, chroma.LineTableTD, "width:100%"))
|
fmt.Fprintf(w, "<td%s>\n", f.styleAttr(css, chroma.LineTableTD, "width:100%"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(w, f.preWrapper.Start(true, f.styleAttr(css, chroma.Background)))
|
fmt.Fprintf(w, f.preWrapper.Start(true, f.styleAttr(css, chroma.PreWrapper)))
|
||||||
|
|
||||||
highlightIndex = 0
|
highlightIndex = 0
|
||||||
for index, tokens := range lines {
|
for index, tokens := range lines {
|
||||||
@ -228,14 +248,28 @@ func (f *Formatter) writeHTML(w io.Writer, style *chroma.Style, tokens []chroma.
|
|||||||
if next {
|
if next {
|
||||||
highlightIndex++
|
highlightIndex++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start of Line
|
||||||
|
fmt.Fprint(w, `<span`)
|
||||||
if highlight {
|
if highlight {
|
||||||
fmt.Fprintf(w, "<span%s>", f.styleAttr(css, chroma.LineHighlight))
|
// Line + LineHighlight
|
||||||
|
if f.Classes {
|
||||||
|
fmt.Fprintf(w, ` class="%s %s"`, f.class(chroma.Line), f.class(chroma.LineHighlight))
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(w, ` style="%s %s"`, css[chroma.Line], css[chroma.LineHighlight])
|
||||||
|
}
|
||||||
|
fmt.Fprint(w, `>`)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(w, "%s>", f.styleAttr(css, chroma.Line))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Line number
|
||||||
if f.lineNumbers && !wrapInTable {
|
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))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(w, `<span%s>`, f.styleAttr(css, chroma.CodeLine))
|
||||||
|
|
||||||
for _, token := range tokens {
|
for _, token := range tokens {
|
||||||
html := html.EscapeString(token.String())
|
html := html.EscapeString(token.String())
|
||||||
attr := f.styleAttr(css, token.Type)
|
attr := f.styleAttr(css, token.Type)
|
||||||
@ -244,9 +278,10 @@ func (f *Formatter) writeHTML(w io.Writer, style *chroma.Style, tokens []chroma.
|
|||||||
}
|
}
|
||||||
fmt.Fprint(w, html)
|
fmt.Fprint(w, html)
|
||||||
}
|
}
|
||||||
if highlight {
|
|
||||||
fmt.Fprintf(w, "</span>")
|
fmt.Fprint(w, `</span>`) // End of CodeLine
|
||||||
}
|
|
||||||
|
fmt.Fprint(w, `</span>`) // End of Line
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(w, f.preWrapper.End(true))
|
fmt.Fprintf(w, f.preWrapper.End(true))
|
||||||
@ -268,7 +303,19 @@ func (f *Formatter) lineIDAttribute(line int) string {
|
|||||||
if !f.linkableLineNumbers {
|
if !f.linkableLineNumbers {
|
||||||
return ""
|
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) {
|
func (f *Formatter) shouldHighlight(highlightIndex, line int) (bool, bool) {
|
||||||
@ -335,7 +382,11 @@ func (f *Formatter) tabWidthStyle() string {
|
|||||||
func (f *Formatter) WriteCSS(w io.Writer, style *chroma.Style) error {
|
func (f *Formatter) WriteCSS(w io.Writer, style *chroma.Style) error {
|
||||||
css := f.styleToCSS(style)
|
css := f.styleToCSS(style)
|
||||||
// Special-case background as it is mapped to the outer ".chroma" class.
|
// Special-case background as it is mapped to the outer ".chroma" class.
|
||||||
if _, err := fmt.Fprintf(w, "/* %s */ .%schroma { %s }\n", chroma.Background, f.prefix, css[chroma.Background]); err != nil {
|
if _, err := fmt.Fprintf(w, "/* %s */ .%sbg { %s }\n", chroma.Background, f.prefix, css[chroma.Background]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Special-case PreWrapper as it is the ".chroma" class.
|
||||||
|
if _, err := fmt.Fprintf(w, "/* %s */ .%schroma { %s }\n", chroma.PreWrapper, f.prefix, css[chroma.PreWrapper]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Special-case code column of table to expand width.
|
// Special-case code column of table to expand width.
|
||||||
@ -359,11 +410,16 @@ func (f *Formatter) WriteCSS(w io.Writer, style *chroma.Style) error {
|
|||||||
sort.Ints(tts)
|
sort.Ints(tts)
|
||||||
for _, ti := range tts {
|
for _, ti := range tts {
|
||||||
tt := chroma.TokenType(ti)
|
tt := chroma.TokenType(ti)
|
||||||
if tt == chroma.Background {
|
switch tt {
|
||||||
|
case chroma.Background, chroma.PreWrapper:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
class := f.class(tt)
|
||||||
|
if class == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
styles := css[tt]
|
styles := css[tt]
|
||||||
if _, err := fmt.Fprintf(w, "/* %s */ .%schroma .%s { %s }\n", tt, f.prefix, f.class(tt), styles); err != nil {
|
if _, err := fmt.Fprintf(w, "/* %s */ .%schroma .%s { %s }\n", tt, f.prefix, class, styles); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -379,18 +435,27 @@ func (f *Formatter) styleToCSS(style *chroma.Style) map[chroma.TokenType]string
|
|||||||
if t != chroma.Background {
|
if t != chroma.Background {
|
||||||
entry = entry.Sub(bg)
|
entry = entry.Sub(bg)
|
||||||
}
|
}
|
||||||
if entry.IsZero() {
|
if !f.allClasses && entry.IsZero() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
classes[t] = StyleEntryToCSS(entry)
|
classes[t] = StyleEntryToCSS(entry)
|
||||||
}
|
}
|
||||||
classes[chroma.Background] += f.tabWidthStyle()
|
classes[chroma.Background] += f.tabWidthStyle()
|
||||||
lineNumbersStyle := "margin-right: 0.4em; padding: 0 0.4em 0 0.4em;"
|
classes[chroma.PreWrapper] += classes[chroma.Background] + `;`
|
||||||
|
// Make PreWrapper a grid to show highlight style with full width.
|
||||||
|
if len(f.highlightRanges) > 0 {
|
||||||
|
classes[chroma.PreWrapper] += `display: grid;`
|
||||||
|
}
|
||||||
|
// Make PreWrapper wrap long lines.
|
||||||
|
if f.wrapLongLines {
|
||||||
|
classes[chroma.PreWrapper] += `white-space: pre-wrap; word-break: break-word;`
|
||||||
|
}
|
||||||
|
lineNumbersStyle := `white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;`
|
||||||
// All rules begin with default rules followed by user provided rules
|
// All rules begin with default rules followed by user provided rules
|
||||||
|
classes[chroma.Line] = `display: flex;` + classes[chroma.Line]
|
||||||
classes[chroma.LineNumbers] = lineNumbersStyle + classes[chroma.LineNumbers]
|
classes[chroma.LineNumbers] = lineNumbersStyle + classes[chroma.LineNumbers]
|
||||||
classes[chroma.LineNumbersTable] = lineNumbersStyle + classes[chroma.LineNumbersTable]
|
classes[chroma.LineNumbersTable] = lineNumbersStyle + classes[chroma.LineNumbersTable]
|
||||||
classes[chroma.LineHighlight] = "display: block; width: 100%;" + classes[chroma.LineHighlight]
|
classes[chroma.LineTable] = "border-spacing: 0; padding: 0; margin: 0; border: 0;" + classes[chroma.LineTable]
|
||||||
classes[chroma.LineTable] = "border-spacing: 0; padding: 0; margin: 0; border: 0; width: auto; overflow: auto; display: block;" + classes[chroma.LineTable]
|
|
||||||
classes[chroma.LineTableTD] = "vertical-align: top; padding: 0; margin: 0; border: 0;" + classes[chroma.LineTableTD]
|
classes[chroma.LineTableTD] = "vertical-align: top; padding: 0; margin: 0; border: 0;" + classes[chroma.LineTableTD]
|
||||||
return classes
|
return classes
|
||||||
}
|
}
|
||||||
|
4
vendor/github.com/alecthomas/chroma/formatters/svg/svg.go
generated
vendored
4
vendor/github.com/alecthomas/chroma/formatters/svg/svg.go
generated
vendored
@ -120,7 +120,7 @@ func maxLineWidth(lines [][]chroma.Token) int {
|
|||||||
for _, tokens := range lines {
|
for _, tokens := range lines {
|
||||||
length := 0
|
length := 0
|
||||||
for _, token := range tokens {
|
for _, token := range tokens {
|
||||||
length += len(strings.Replace(token.String(), ` `, " ", -1))
|
length += len(strings.ReplaceAll(token.String(), ` `, " "))
|
||||||
}
|
}
|
||||||
if length > maxWidth {
|
if length > maxWidth {
|
||||||
maxWidth = length
|
maxWidth = length
|
||||||
@ -136,7 +136,7 @@ func (f *Formatter) writeTokenBackgrounds(w io.Writer, lines [][]chroma.Token, s
|
|||||||
for index, tokens := range lines {
|
for index, tokens := range lines {
|
||||||
lineLength := 0
|
lineLength := 0
|
||||||
for _, token := range tokens {
|
for _, token := range tokens {
|
||||||
length := len(strings.Replace(token.String(), ` `, " ", -1))
|
length := len(strings.ReplaceAll(token.String(), ` `, " "))
|
||||||
tokenBackground := style.Get(token.Type).Background
|
tokenBackground := style.Get(token.Type).Background
|
||||||
if tokenBackground.IsSet() && tokenBackground != style.Get(chroma.Background).Background {
|
if tokenBackground.IsSet() && tokenBackground != style.Get(chroma.Background).Background {
|
||||||
fmt.Fprintf(w, "<rect id=\"%s\" x=\"%dch\" y=\"%fem\" width=\"%dch\" height=\"1.2em\" fill=\"%s\" />\n", escapeString(token.String()), lineLength, 1.2*float64(index)+0.25, length, style.Get(token.Type).Background.String())
|
fmt.Fprintf(w, "<rect id=\"%s\" x=\"%dch\" y=\"%fem\" width=\"%dch\" height=\"1.2em\" fill=\"%s\" />\n", escapeString(token.String()), lineLength, 1.2*float64(index)+0.25, length, style.Get(token.Type).Background.String())
|
||||||
|
32
vendor/github.com/alecthomas/chroma/formatters/tty_indexed.go
generated
vendored
32
vendor/github.com/alecthomas/chroma/formatters/tty_indexed.go
generated
vendored
@ -17,6 +17,20 @@ var c = chroma.MustParseColour
|
|||||||
|
|
||||||
var ttyTables = map[int]*ttyTable{
|
var ttyTables = map[int]*ttyTable{
|
||||||
8: {
|
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{
|
foreground: map[chroma.Colour]string{
|
||||||
c("#000000"): "\033[30m", c("#7f0000"): "\033[31m", c("#007f00"): "\033[32m", c("#7f7fe0"): "\033[33m",
|
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("#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) {
|
func (c *indexedTTYFormatter) Format(w io.Writer, style *chroma.Style, it chroma.Iterator) (err error) {
|
||||||
theme := styleToEscapeSequence(c.table, style)
|
theme := styleToEscapeSequence(c.table, style)
|
||||||
for token := it(); token != chroma.EOF; token = it() {
|
for token := it(); token != chroma.EOF; token = it() {
|
||||||
// TODO: Cache token lookups?
|
|
||||||
clr, ok := theme[token.Type]
|
clr, ok := theme[token.Type]
|
||||||
if !ok {
|
if !ok {
|
||||||
clr, ok = theme[token.Type.SubCategory()]
|
clr, ok = theme[token.Type.SubCategory()]
|
||||||
if !ok {
|
if !ok {
|
||||||
clr = theme[token.Type.Category()]
|
clr = theme[token.Type.Category()]
|
||||||
// if !ok {
|
|
||||||
// clr = theme[chroma.InheritStyle]
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if clr != "" {
|
if clr != "" {
|
||||||
@ -249,10 +259,22 @@ func (c *indexedTTYFormatter) Format(w io.Writer, style *chroma.Style, it chroma
|
|||||||
return nil
|
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.
|
// TTY8 is an 8-colour terminal formatter.
|
||||||
//
|
//
|
||||||
// The Lab colour space is used to map RGB values to the most appropriate index colour.
|
// 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.
|
// TTY256 is a 256-colour terminal formatter.
|
||||||
//
|
//
|
||||||
|
22
vendor/github.com/alecthomas/chroma/go.mod
generated
vendored
22
vendor/github.com/alecthomas/chroma/go.mod
generated
vendored
@ -1,19 +1,9 @@
|
|||||||
module github.com/alecthomas/chroma
|
module github.com/alecthomas/chroma
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38
|
|
||||||
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 // indirect
|
|
||||||
github.com/alecthomas/kong v0.2.1-0.20190708041108-0548c6b1afae
|
|
||||||
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 // indirect
|
|
||||||
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964
|
|
||||||
github.com/dlclark/regexp2 v1.1.6
|
|
||||||
github.com/mattn/go-colorable v0.0.9
|
|
||||||
github.com/mattn/go-isatty v0.0.4
|
|
||||||
github.com/sergi/go-diff v1.0.0 // indirect
|
|
||||||
github.com/stretchr/testify v1.3.0 // indirect
|
|
||||||
golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35 // indirect
|
|
||||||
)
|
|
||||||
|
|
||||||
replace github.com/GeertJohan/go.rice => github.com/alecthomas/go.rice v1.0.1-0.20190719113735-961b99d742e7
|
|
||||||
|
|
||||||
go 1.13
|
go 1.13
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/dlclark/regexp2 v1.4.0
|
||||||
|
github.com/stretchr/testify v1.7.0
|
||||||
|
)
|
||||||
|
35
vendor/github.com/alecthomas/chroma/go.sum
generated
vendored
35
vendor/github.com/alecthomas/chroma/go.sum
generated
vendored
@ -1,33 +1,14 @@
|
|||||||
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/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.1-0.20190708041108-0548c6b1afae h1:C4Q9m+oXOxcSWwYk9XzzafY2xAVAaeubZbUHJkw3PlY=
|
|
||||||
github.com/alecthomas/kong v0.2.1-0.20190708041108-0548c6b1afae/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI=
|
|
||||||
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY=
|
|
||||||
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
|
|
||||||
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ=
|
|
||||||
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dlclark/regexp2 v1.1.6 h1:CqB4MjHw0MFCDj+PHHjiESmHX+N7t0tJzKvC6M97BRg=
|
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
|
||||||
github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||||
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
|
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
|
||||||
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
|
|
||||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
|
||||||
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
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/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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35 h1:YAFjXN64LMvktoUZH9zgY4lGc/msGN7HQfoSuKCgaDU=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
2
vendor/github.com/alecthomas/chroma/iterator.go
generated
vendored
2
vendor/github.com/alecthomas/chroma/iterator.go
generated
vendored
@ -4,7 +4,7 @@ import "strings"
|
|||||||
|
|
||||||
// An Iterator across tokens.
|
// 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.
|
// If an error occurs within an Iterator, it may propagate this in a panic. Formatters should recover.
|
||||||
type Iterator func() Token
|
type Iterator func() Token
|
||||||
|
16
vendor/github.com/alecthomas/chroma/lexer.go
generated
vendored
16
vendor/github.com/alecthomas/chroma/lexer.go
generated
vendored
@ -2,11 +2,13 @@ package chroma
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
defaultOptions = &TokeniseOptions{
|
defaultOptions = &TokeniseOptions{
|
||||||
State: "root",
|
State: "root",
|
||||||
|
EnsureLF: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -80,6 +82,10 @@ type TokeniseOptions struct {
|
|||||||
State string
|
State string
|
||||||
// Nested tokenisation.
|
// Nested tokenisation.
|
||||||
Nested bool
|
Nested bool
|
||||||
|
|
||||||
|
// If true, all EOLs are converted into LF
|
||||||
|
// by replacing CRLF and CR
|
||||||
|
EnsureLF bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Lexer for tokenising source code.
|
// A Lexer for tokenising source code.
|
||||||
@ -93,9 +99,11 @@ type Lexer interface {
|
|||||||
// Lexers is a slice of lexers sortable by name.
|
// Lexers is a slice of lexers sortable by name.
|
||||||
type Lexers []Lexer
|
type Lexers []Lexer
|
||||||
|
|
||||||
func (l Lexers) Len() int { return len(l) }
|
func (l Lexers) Len() int { return len(l) }
|
||||||
func (l Lexers) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
|
func (l Lexers) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
|
||||||
func (l Lexers) Less(i, j int) bool { return l[i].Config().Name < l[j].Config().Name }
|
func (l Lexers) Less(i, j int) bool {
|
||||||
|
return strings.ToLower(l[i].Config().Name) < strings.ToLower(l[j].Config().Name)
|
||||||
|
}
|
||||||
|
|
||||||
// PrioritisedLexers is a slice of lexers sortable by priority.
|
// PrioritisedLexers is a slice of lexers sortable by priority.
|
||||||
type PrioritisedLexers []Lexer
|
type PrioritisedLexers []Lexer
|
||||||
|
3
vendor/github.com/alecthomas/chroma/lexers/README.md
generated
vendored
3
vendor/github.com/alecthomas/chroma/lexers/README.md
generated
vendored
@ -3,6 +3,9 @@
|
|||||||
The tests in this directory feed a known input `testdata/<name>.actual` into the parser for `<name>` and check
|
The tests in this directory feed a known input `testdata/<name>.actual` into the parser for `<name>` and check
|
||||||
that its output matches `<name>.exported`.
|
that its output matches `<name>.exported`.
|
||||||
|
|
||||||
|
It is also possible to perform several tests on a same parser `<name>`, by placing know inputs `*.actual` into a
|
||||||
|
directory `testdata/<name>/`.
|
||||||
|
|
||||||
## Running the tests
|
## Running the tests
|
||||||
|
|
||||||
Run the tests as normal:
|
Run the tests as normal:
|
||||||
|
12
vendor/github.com/alecthomas/chroma/lexers/a/abap.go
generated
vendored
12
vendor/github.com/alecthomas/chroma/lexers/a/abap.go
generated
vendored
@ -6,7 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ABAP lexer.
|
// ABAP lexer.
|
||||||
var Abap = internal.Register(MustNewLexer(
|
var Abap = internal.Register(MustNewLazyLexer(
|
||||||
&Config{
|
&Config{
|
||||||
Name: "ABAP",
|
Name: "ABAP",
|
||||||
Aliases: []string{"abap"},
|
Aliases: []string{"abap"},
|
||||||
@ -14,7 +14,11 @@ var Abap = internal.Register(MustNewLexer(
|
|||||||
MimeTypes: []string{"text/x-abap"},
|
MimeTypes: []string{"text/x-abap"},
|
||||||
CaseInsensitive: true,
|
CaseInsensitive: true,
|
||||||
},
|
},
|
||||||
Rules{
|
abapRules,
|
||||||
|
))
|
||||||
|
|
||||||
|
func abapRules() Rules {
|
||||||
|
return Rules{
|
||||||
"common": {
|
"common": {
|
||||||
{`\s+`, Text, nil},
|
{`\s+`, Text, nil},
|
||||||
{`^\*.*$`, CommentSingle, nil},
|
{`^\*.*$`, CommentSingle, nil},
|
||||||
@ -52,5 +56,5 @@ var Abap = internal.Register(MustNewLexer(
|
|||||||
{`[/;:()\[\],.]`, Punctuation, nil},
|
{`[/;:()\[\],.]`, Punctuation, nil},
|
||||||
{`(!)(\w+)`, ByGroups(Operator, Name), nil},
|
{`(!)(\w+)`, ByGroups(Operator, Name), nil},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
))
|
}
|
||||||
|
12
vendor/github.com/alecthomas/chroma/lexers/a/abnf.go
generated
vendored
12
vendor/github.com/alecthomas/chroma/lexers/a/abnf.go
generated
vendored
@ -6,14 +6,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Abnf lexer.
|
// Abnf lexer.
|
||||||
var Abnf = internal.Register(MustNewLexer(
|
var Abnf = internal.Register(MustNewLazyLexer(
|
||||||
&Config{
|
&Config{
|
||||||
Name: "ABNF",
|
Name: "ABNF",
|
||||||
Aliases: []string{"abnf"},
|
Aliases: []string{"abnf"},
|
||||||
Filenames: []string{"*.abnf"},
|
Filenames: []string{"*.abnf"},
|
||||||
MimeTypes: []string{"text/x-abnf"},
|
MimeTypes: []string{"text/x-abnf"},
|
||||||
},
|
},
|
||||||
Rules{
|
abnfRules,
|
||||||
|
))
|
||||||
|
|
||||||
|
func abnfRules() Rules {
|
||||||
|
return Rules{
|
||||||
"root": {
|
"root": {
|
||||||
{`;.*$`, CommentSingle, nil},
|
{`;.*$`, CommentSingle, nil},
|
||||||
{`(%[si])?"[^"]*"`, Literal, nil},
|
{`(%[si])?"[^"]*"`, Literal, nil},
|
||||||
@ -34,5 +38,5 @@ var Abnf = internal.Register(MustNewLexer(
|
|||||||
{`\s+`, Text, nil},
|
{`\s+`, Text, nil},
|
||||||
{`.`, Text, nil},
|
{`.`, Text, nil},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
))
|
}
|
||||||
|
12
vendor/github.com/alecthomas/chroma/lexers/a/actionscript.go
generated
vendored
12
vendor/github.com/alecthomas/chroma/lexers/a/actionscript.go
generated
vendored
@ -6,7 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Actionscript lexer.
|
// Actionscript lexer.
|
||||||
var Actionscript = internal.Register(MustNewLexer(
|
var Actionscript = internal.Register(MustNewLazyLexer(
|
||||||
&Config{
|
&Config{
|
||||||
Name: "ActionScript",
|
Name: "ActionScript",
|
||||||
Aliases: []string{"as", "actionscript"},
|
Aliases: []string{"as", "actionscript"},
|
||||||
@ -15,7 +15,11 @@ var Actionscript = internal.Register(MustNewLexer(
|
|||||||
NotMultiline: true,
|
NotMultiline: true,
|
||||||
DotAll: true,
|
DotAll: true,
|
||||||
},
|
},
|
||||||
Rules{
|
actionscriptRules,
|
||||||
|
))
|
||||||
|
|
||||||
|
func actionscriptRules() Rules {
|
||||||
|
return Rules{
|
||||||
"root": {
|
"root": {
|
||||||
{`\s+`, Text, nil},
|
{`\s+`, Text, nil},
|
||||||
{`//.*?\n`, CommentSingle, nil},
|
{`//.*?\n`, CommentSingle, nil},
|
||||||
@ -35,5 +39,5 @@ var Actionscript = internal.Register(MustNewLexer(
|
|||||||
{`"(\\\\|\\"|[^"])*"`, LiteralStringDouble, nil},
|
{`"(\\\\|\\"|[^"])*"`, LiteralStringDouble, nil},
|
||||||
{`'(\\\\|\\'|[^'])*'`, LiteralStringSingle, nil},
|
{`'(\\\\|\\'|[^'])*'`, LiteralStringSingle, nil},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
))
|
}
|
||||||
|
12
vendor/github.com/alecthomas/chroma/lexers/a/actionscript3.go
generated
vendored
12
vendor/github.com/alecthomas/chroma/lexers/a/actionscript3.go
generated
vendored
@ -6,7 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Actionscript 3 lexer.
|
// Actionscript 3 lexer.
|
||||||
var Actionscript3 = internal.Register(MustNewLexer(
|
var Actionscript3 = internal.Register(MustNewLazyLexer(
|
||||||
&Config{
|
&Config{
|
||||||
Name: "ActionScript 3",
|
Name: "ActionScript 3",
|
||||||
Aliases: []string{"as3", "actionscript3"},
|
Aliases: []string{"as3", "actionscript3"},
|
||||||
@ -14,7 +14,11 @@ var Actionscript3 = internal.Register(MustNewLexer(
|
|||||||
MimeTypes: []string{"application/x-actionscript3", "text/x-actionscript3", "text/actionscript3"},
|
MimeTypes: []string{"application/x-actionscript3", "text/x-actionscript3", "text/actionscript3"},
|
||||||
DotAll: true,
|
DotAll: true,
|
||||||
},
|
},
|
||||||
Rules{
|
actionscript3Rules,
|
||||||
|
))
|
||||||
|
|
||||||
|
func actionscript3Rules() Rules {
|
||||||
|
return Rules{
|
||||||
"root": {
|
"root": {
|
||||||
{`\s+`, Text, nil},
|
{`\s+`, Text, nil},
|
||||||
{`(function\s+)([$a-zA-Z_]\w*)(\s*)(\()`, ByGroups(KeywordDeclaration, NameFunction, Text, Operator), Push("funcparams")},
|
{`(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)},
|
{`,`, Operator, Pop(1)},
|
||||||
Default(Pop(1)),
|
Default(Pop(1)),
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
))
|
}
|
||||||
|
12
vendor/github.com/alecthomas/chroma/lexers/a/ada.go
generated
vendored
12
vendor/github.com/alecthomas/chroma/lexers/a/ada.go
generated
vendored
@ -6,7 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Ada lexer.
|
// Ada lexer.
|
||||||
var Ada = internal.Register(MustNewLexer(
|
var Ada = internal.Register(MustNewLazyLexer(
|
||||||
&Config{
|
&Config{
|
||||||
Name: "Ada",
|
Name: "Ada",
|
||||||
Aliases: []string{"ada", "ada95", "ada2005"},
|
Aliases: []string{"ada", "ada95", "ada2005"},
|
||||||
@ -14,7 +14,11 @@ var Ada = internal.Register(MustNewLexer(
|
|||||||
MimeTypes: []string{"text/x-ada"},
|
MimeTypes: []string{"text/x-ada"},
|
||||||
CaseInsensitive: true,
|
CaseInsensitive: true,
|
||||||
},
|
},
|
||||||
Rules{
|
adaRules,
|
||||||
|
))
|
||||||
|
|
||||||
|
func adaRules() Rules {
|
||||||
|
return Rules{
|
||||||
"root": {
|
"root": {
|
||||||
{`[^\S\n]+`, Text, nil},
|
{`[^\S\n]+`, Text, nil},
|
||||||
{`--.*?\n`, CommentSingle, nil},
|
{`--.*?\n`, CommentSingle, nil},
|
||||||
@ -110,5 +114,5 @@ var Ada = internal.Register(MustNewLexer(
|
|||||||
{`\)`, Punctuation, Pop(1)},
|
{`\)`, Punctuation, Pop(1)},
|
||||||
Include("root"),
|
Include("root"),
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
))
|
}
|
||||||
|
47
vendor/github.com/alecthomas/chroma/lexers/a/al.go
generated
vendored
Normal file
47
vendor/github.com/alecthomas/chroma/lexers/a/al.go
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
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},
|
||||||
|
{`\b(?i:(CODEUNIT|PAGE|PAGEEXTENSION|PAGECUSTOMIZATION|DOTNET|ENUM|ENUMEXTENSION|VALUE|QUERY|REPORT|TABLE|TABLEEXTENSION|XMLPORT|PROFILE|CONTROLADDIN|REPORTEXTENSION|INTERFACE|PERMISSIONSET|PERMISSIONSETEXTENSION|ENTITLEMENT))\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:(ADD|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},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
12
vendor/github.com/alecthomas/chroma/lexers/a/angular2.go
generated
vendored
12
vendor/github.com/alecthomas/chroma/lexers/a/angular2.go
generated
vendored
@ -6,14 +6,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Angular2 lexer.
|
// Angular2 lexer.
|
||||||
var Angular2 = internal.Register(MustNewLexer(
|
var Angular2 = internal.Register(MustNewLazyLexer(
|
||||||
&Config{
|
&Config{
|
||||||
Name: "Angular2",
|
Name: "Angular2",
|
||||||
Aliases: []string{"ng2"},
|
Aliases: []string{"ng2"},
|
||||||
Filenames: []string{},
|
Filenames: []string{},
|
||||||
MimeTypes: []string{},
|
MimeTypes: []string{},
|
||||||
},
|
},
|
||||||
Rules{
|
angular2Rules,
|
||||||
|
))
|
||||||
|
|
||||||
|
func angular2Rules() Rules {
|
||||||
|
return Rules{
|
||||||
"root": {
|
"root": {
|
||||||
{`[^{([*#]+`, Other, nil},
|
{`[^{([*#]+`, Other, nil},
|
||||||
{`(\{\{)(\s*)`, ByGroups(CommentPreproc, Text), Push("ngExpression")},
|
{`(\{\{)(\s*)`, ByGroups(CommentPreproc, Text), Push("ngExpression")},
|
||||||
@ -38,5 +42,5 @@ var Angular2 = internal.Register(MustNewLexer(
|
|||||||
{`'.*?'`, LiteralString, Pop(1)},
|
{`'.*?'`, LiteralString, Pop(1)},
|
||||||
{`[^\s>]+`, LiteralString, Pop(1)},
|
{`[^\s>]+`, LiteralString, Pop(1)},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
))
|
}
|
||||||
|
12
vendor/github.com/alecthomas/chroma/lexers/a/antlr.go
generated
vendored
12
vendor/github.com/alecthomas/chroma/lexers/a/antlr.go
generated
vendored
@ -6,14 +6,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ANTLR lexer.
|
// ANTLR lexer.
|
||||||
var ANTLR = internal.Register(MustNewLexer(
|
var ANTLR = internal.Register(MustNewLazyLexer(
|
||||||
&Config{
|
&Config{
|
||||||
Name: "ANTLR",
|
Name: "ANTLR",
|
||||||
Aliases: []string{"antlr"},
|
Aliases: []string{"antlr"},
|
||||||
Filenames: []string{},
|
Filenames: []string{},
|
||||||
MimeTypes: []string{},
|
MimeTypes: []string{},
|
||||||
},
|
},
|
||||||
Rules{
|
antlrRules,
|
||||||
|
))
|
||||||
|
|
||||||
|
func antlrRules() Rules {
|
||||||
|
return Rules{
|
||||||
"whitespace": {
|
"whitespace": {
|
||||||
{`\s+`, TextWhitespace, nil},
|
{`\s+`, TextWhitespace, nil},
|
||||||
},
|
},
|
||||||
@ -97,5 +101,5 @@ var ANTLR = internal.Register(MustNewLexer(
|
|||||||
{`(\$[a-zA-Z]+)(\.?)(text|value)?`, ByGroups(NameVariable, Punctuation, NameProperty), nil},
|
{`(\$[a-zA-Z]+)(\.?)(text|value)?`, ByGroups(NameVariable, Punctuation, NameProperty), nil},
|
||||||
{`(\\\\|\\\]|\\\[|[^\[\]])+`, Other, nil},
|
{`(\\\\|\\\]|\\\[|[^\[\]])+`, Other, nil},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
))
|
}
|
||||||
|
12
vendor/github.com/alecthomas/chroma/lexers/a/apache.go
generated
vendored
12
vendor/github.com/alecthomas/chroma/lexers/a/apache.go
generated
vendored
@ -6,7 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Apacheconf lexer.
|
// Apacheconf lexer.
|
||||||
var Apacheconf = internal.Register(MustNewLexer(
|
var Apacheconf = internal.Register(MustNewLazyLexer(
|
||||||
&Config{
|
&Config{
|
||||||
Name: "ApacheConf",
|
Name: "ApacheConf",
|
||||||
Aliases: []string{"apacheconf", "aconf", "apache"},
|
Aliases: []string{"apacheconf", "aconf", "apache"},
|
||||||
@ -14,7 +14,11 @@ var Apacheconf = internal.Register(MustNewLexer(
|
|||||||
MimeTypes: []string{"text/x-apacheconf"},
|
MimeTypes: []string{"text/x-apacheconf"},
|
||||||
CaseInsensitive: true,
|
CaseInsensitive: true,
|
||||||
},
|
},
|
||||||
Rules{
|
apacheconfRules,
|
||||||
|
))
|
||||||
|
|
||||||
|
func apacheconfRules() Rules {
|
||||||
|
return Rules{
|
||||||
"root": {
|
"root": {
|
||||||
{`\s+`, Text, nil},
|
{`\s+`, Text, nil},
|
||||||
{`(#.*?)$`, Comment, nil},
|
{`(#.*?)$`, Comment, nil},
|
||||||
@ -34,5 +38,5 @@ var Apacheconf = internal.Register(MustNewLexer(
|
|||||||
{`"([^"\\]*(?:\\.[^"\\]*)*)"`, LiteralStringDouble, nil},
|
{`"([^"\\]*(?:\\.[^"\\]*)*)"`, LiteralStringDouble, nil},
|
||||||
{`[^\s"\\]+`, Text, nil},
|
{`[^\s"\\]+`, Text, nil},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
))
|
}
|
||||||
|
18
vendor/github.com/alecthomas/chroma/lexers/a/apl.go
generated
vendored
18
vendor/github.com/alecthomas/chroma/lexers/a/apl.go
generated
vendored
@ -6,14 +6,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Apl lexer.
|
// Apl lexer.
|
||||||
var Apl = internal.Register(MustNewLexer(
|
var Apl = internal.Register(MustNewLazyLexer(
|
||||||
&Config{
|
&Config{
|
||||||
Name: "APL",
|
Name: "APL",
|
||||||
Aliases: []string{"apl"},
|
Aliases: []string{"apl"},
|
||||||
Filenames: []string{"*.apl"},
|
Filenames: []string{"*.apl"},
|
||||||
MimeTypes: []string{},
|
MimeTypes: []string{},
|
||||||
},
|
},
|
||||||
Rules{
|
aplRules,
|
||||||
|
))
|
||||||
|
|
||||||
|
func aplRules() Rules {
|
||||||
|
return Rules{
|
||||||
"root": {
|
"root": {
|
||||||
{`\s+`, Text, nil},
|
{`\s+`, Text, nil},
|
||||||
{`[⍝#].*$`, CommentSingle, nil},
|
{`[⍝#].*$`, CommentSingle, nil},
|
||||||
@ -22,15 +26,15 @@ var Apl = internal.Register(MustNewLexer(
|
|||||||
{`[⋄◇()]`, Punctuation, nil},
|
{`[⋄◇()]`, Punctuation, nil},
|
||||||
{`[\[\];]`, LiteralStringRegex, nil},
|
{`[\[\];]`, LiteralStringRegex, nil},
|
||||||
{`⎕[A-Za-zΔ∆⍙][A-Za-zΔ∆⍙_¯0-9]*`, NameFunction, nil},
|
{`⎕[A-Za-zΔ∆⍙][A-Za-zΔ∆⍙_¯0-9]*`, NameFunction, nil},
|
||||||
{`[A-Za-zΔ∆⍙][A-Za-zΔ∆⍙_¯0-9]*`, NameVariable, nil},
|
{`[A-Za-zΔ∆⍙_][A-Za-zΔ∆⍙_¯0-9]*`, NameVariable, nil},
|
||||||
{`¯?(0[Xx][0-9A-Fa-f]+|[0-9]*\.?[0-9]+([Ee][+¯]?[0-9]+)?|¯|∞)([Jj]¯?(0[Xx][0-9A-Fa-f]+|[0-9]*\.?[0-9]+([Ee][+¯]?[0-9]+)?|¯|∞))?`, LiteralNumber, nil},
|
{`¯?(0[Xx][0-9A-Fa-f]+|[0-9]*\.?[0-9]+([Ee][+¯]?[0-9]+)?|¯|∞)([Jj]¯?(0[Xx][0-9A-Fa-f]+|[0-9]*\.?[0-9]+([Ee][+¯]?[0-9]+)?|¯|∞))?`, LiteralNumber, nil},
|
||||||
{`[\.\\/⌿⍀¨⍣⍨⍠⍤∘]`, NameAttribute, nil},
|
{`[\.\\/⌿⍀¨⍣⍨⍠⍤∘⍥@⌺⌶⍢]`, NameAttribute, nil},
|
||||||
{`[+\-×÷⌈⌊∣|⍳?*⍟○!⌹<≤=>≥≠≡≢∊⍷∪∩~∨∧⍱⍲⍴,⍪⌽⊖⍉↑↓⊂⊃⌷⍋⍒⊤⊥⍕⍎⊣⊢⍁⍂≈⌸⍯↗]`, Operator, nil},
|
{`[+\-×÷⌈⌊∣|⍳?*⍟○!⌹<≤=>≥≠≡≢∊⍷∪∩~∨∧⍱⍲⍴,⍪⌽⊖⍉↑↓⊂⊃⌷⍋⍒⊤⊥⍕⍎⊣⊢⍁⍂≈⌸⍯↗⊆⍸]`, Operator, nil},
|
||||||
{`⍬`, NameConstant, nil},
|
{`⍬`, NameConstant, nil},
|
||||||
{`[⎕⍞]`, NameVariableGlobal, nil},
|
{`[⎕⍞]`, NameVariableGlobal, nil},
|
||||||
{`[←→]`, KeywordDeclaration, nil},
|
{`[←→]`, KeywordDeclaration, nil},
|
||||||
{`[⍺⍵⍶⍹∇:]`, NameBuiltinPseudo, nil},
|
{`[⍺⍵⍶⍹∇:]`, NameBuiltinPseudo, nil},
|
||||||
{`[{}]`, KeywordType, nil},
|
{`[{}]`, KeywordType, nil},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
))
|
}
|
||||||
|
12
vendor/github.com/alecthomas/chroma/lexers/a/applescript.go
generated
vendored
12
vendor/github.com/alecthomas/chroma/lexers/a/applescript.go
generated
vendored
@ -6,7 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Applescript lexer.
|
// Applescript lexer.
|
||||||
var Applescript = internal.Register(MustNewLexer(
|
var Applescript = internal.Register(MustNewLazyLexer(
|
||||||
&Config{
|
&Config{
|
||||||
Name: "AppleScript",
|
Name: "AppleScript",
|
||||||
Aliases: []string{"applescript"},
|
Aliases: []string{"applescript"},
|
||||||
@ -14,7 +14,11 @@ var Applescript = internal.Register(MustNewLexer(
|
|||||||
MimeTypes: []string{},
|
MimeTypes: []string{},
|
||||||
DotAll: true,
|
DotAll: true,
|
||||||
},
|
},
|
||||||
Rules{
|
applescriptRules,
|
||||||
|
))
|
||||||
|
|
||||||
|
func applescriptRules() Rules {
|
||||||
|
return Rules{
|
||||||
"root": {
|
"root": {
|
||||||
{`\s+`, Text, nil},
|
{`\s+`, Text, nil},
|
||||||
{`¬\n`, LiteralStringEscape, nil},
|
{`¬\n`, LiteralStringEscape, nil},
|
||||||
@ -51,5 +55,5 @@ var Applescript = internal.Register(MustNewLexer(
|
|||||||
{`[^*(]+`, CommentMultiline, nil},
|
{`[^*(]+`, CommentMultiline, nil},
|
||||||
{`[*(]`, CommentMultiline, nil},
|
{`[*(]`, CommentMultiline, nil},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
))
|
}
|
||||||
|
12
vendor/github.com/alecthomas/chroma/lexers/a/arduino.go
generated
vendored
12
vendor/github.com/alecthomas/chroma/lexers/a/arduino.go
generated
vendored
@ -6,7 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Arduino lexer.
|
// Arduino lexer.
|
||||||
var Arduino = internal.Register(MustNewLexer(
|
var Arduino = internal.Register(MustNewLazyLexer(
|
||||||
&Config{
|
&Config{
|
||||||
Name: "Arduino",
|
Name: "Arduino",
|
||||||
Aliases: []string{"arduino"},
|
Aliases: []string{"arduino"},
|
||||||
@ -14,7 +14,11 @@ var Arduino = internal.Register(MustNewLexer(
|
|||||||
MimeTypes: []string{"text/x-arduino"},
|
MimeTypes: []string{"text/x-arduino"},
|
||||||
EnsureNL: true,
|
EnsureNL: true,
|
||||||
},
|
},
|
||||||
Rules{
|
arduinoRules,
|
||||||
|
))
|
||||||
|
|
||||||
|
func arduinoRules() Rules {
|
||||||
|
return Rules{
|
||||||
"statements": {
|
"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},
|
{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},
|
{`char(16_t|32_t)\b`, KeywordType, nil},
|
||||||
@ -106,5 +110,5 @@ var Arduino = internal.Register(MustNewLexer(
|
|||||||
{`^\s*#endif.*?(?<!\\)\n`, CommentPreproc, Pop(1)},
|
{`^\s*#endif.*?(?<!\\)\n`, CommentPreproc, Pop(1)},
|
||||||
{`.*?\n`, Comment, nil},
|
{`.*?\n`, Comment, nil},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
))
|
}
|
||||||
|
72
vendor/github.com/alecthomas/chroma/lexers/a/armasm.go
generated
vendored
Normal file
72
vendor/github.com/alecthomas/chroma/lexers/a/armasm.go
generated
vendored
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package a
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/alecthomas/chroma" // nolint
|
||||||
|
"github.com/alecthomas/chroma/lexers/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ArmAsm = internal.Register(MustNewLazyLexer(
|
||||||
|
&Config{
|
||||||
|
Name: "ArmAsm",
|
||||||
|
Aliases: []string{"armasm"},
|
||||||
|
EnsureNL: true,
|
||||||
|
Filenames: []string{"*.s", "*.S"},
|
||||||
|
MimeTypes: []string{"text/x-armasm", "text/x-asm"},
|
||||||
|
},
|
||||||
|
armasmRules,
|
||||||
|
))
|
||||||
|
|
||||||
|
func armasmRules() Rules {
|
||||||
|
return Rules{
|
||||||
|
"commentsandwhitespace": {
|
||||||
|
{`\s+`, Text, nil},
|
||||||
|
{`[@;].*?\n`, CommentSingle, nil},
|
||||||
|
{`/\*.*?\*/`, CommentMultiline, nil},
|
||||||
|
},
|
||||||
|
"literal": {
|
||||||
|
// Binary
|
||||||
|
{`0b[01]+`, NumberBin, Pop(1)},
|
||||||
|
// Hex
|
||||||
|
{`0x\w{1,8}`, NumberHex, Pop(1)},
|
||||||
|
// Octal
|
||||||
|
{`0\d+`, NumberOct, Pop(1)},
|
||||||
|
// Float
|
||||||
|
{`\d+?\.\d+?`, NumberFloat, Pop(1)},
|
||||||
|
// Integer
|
||||||
|
{`\d+`, NumberInteger, Pop(1)},
|
||||||
|
// String
|
||||||
|
{`(")(.+)(")`, ByGroups(Punctuation, StringDouble, Punctuation), Pop(1)},
|
||||||
|
// Char
|
||||||
|
{`(')(.{1}|\\.{1})(')`, ByGroups(Punctuation, StringChar, Punctuation), Pop(1)},
|
||||||
|
},
|
||||||
|
"opcode": {
|
||||||
|
// Escape at line end
|
||||||
|
{`\n`, Text, Pop(1)},
|
||||||
|
// Comment
|
||||||
|
{`(@|;).*\n`, CommentSingle, Pop(1)},
|
||||||
|
// Whitespace
|
||||||
|
{`(\s+|,)`, Text, nil},
|
||||||
|
// Register by number
|
||||||
|
{`[rapcfxwbhsdqv]\d{1,2}`, NameClass, nil},
|
||||||
|
// Address by hex
|
||||||
|
{`=0x\w+`, ByGroups(Text, NameLabel), nil},
|
||||||
|
// Pseudo address by label
|
||||||
|
{`(=)(\w+)`, ByGroups(Text, NameLabel), nil},
|
||||||
|
// Immediate
|
||||||
|
{`#`, Text, Push("literal")},
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
Include("commentsandwhitespace"),
|
||||||
|
// Directive with optional param
|
||||||
|
{`(\.\w+)([ \t]+\w+\s+?)?`, ByGroups(KeywordNamespace, NameLabel), nil},
|
||||||
|
// Label with data
|
||||||
|
{`(\w+)(:)(\s+\.\w+\s+)`, ByGroups(NameLabel, Punctuation, KeywordNamespace), Push("literal")},
|
||||||
|
// Label
|
||||||
|
{`(\w+)(:)`, ByGroups(NameLabel, Punctuation), nil},
|
||||||
|
// Syscall Op
|
||||||
|
{`svc\s+\w+`, NameNamespace, nil},
|
||||||
|
// Opcode
|
||||||
|
{`[a-zA-Z]+`, Text, Push("opcode")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user