mirror of
https://github.com/cheat/cheat.git
synced 2025-09-01 17:48:30 +02:00
Compare commits
31 Commits
Author | SHA1 | Date | |
---|---|---|---|
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 |
@ -3,6 +3,10 @@ language: go
|
||||
go:
|
||||
- 1.13.x
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
|
||||
|
23
Makefile
23
Makefile
@ -21,6 +21,7 @@ ZIP := zip -m
|
||||
# build flags
|
||||
BUILD_FLAGS := -ldflags="-s -w" -mod vendor -trimpath
|
||||
GOBIN :=
|
||||
TMPDIR := /tmp
|
||||
|
||||
# release binaries
|
||||
releases := \
|
||||
@ -33,7 +34,7 @@ releases := \
|
||||
|
||||
## build: builds an executable for your architecture
|
||||
.PHONY: build
|
||||
build: $(dist_dir)
|
||||
build: $(dist_dir) clean generate
|
||||
$(GO) build $(BUILD_FLAGS) -o $(dist_dir)/cheat $(cmd_dir)
|
||||
|
||||
## build-release: builds release executables
|
||||
@ -47,27 +48,27 @@ ci: | setup prepare build
|
||||
# cheat-darwin-amd64
|
||||
$(dist_dir)/cheat-darwin-amd64: prepare
|
||||
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-amd64
|
||||
$(dist_dir)/cheat-linux-amd64: prepare
|
||||
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
|
||||
$(dist_dir)/cheat-linux-arm5: prepare
|
||||
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
|
||||
$(dist_dir)/cheat-linux-arm6: prepare
|
||||
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
|
||||
$(dist_dir)/cheat-linux-arm7: prepare
|
||||
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-windows-amd64
|
||||
$(dist_dir)/cheat-windows-amd64.exe: prepare
|
||||
@ -95,7 +96,7 @@ clean: $(dist_dir)
|
||||
## distclean: removes the tags file
|
||||
.PHONY: distclean
|
||||
distclean:
|
||||
$(RM) tags
|
||||
$(RM) -f tags
|
||||
|
||||
## setup: installs revive (linter) and scc (sloc tool)
|
||||
.PHONY: setup
|
||||
@ -110,7 +111,7 @@ sloc:
|
||||
## tags: builds a tags file
|
||||
.PHONY: tags
|
||||
tags:
|
||||
$(CTAGS) -R . --exclude=vendor
|
||||
$(CTAGS) -R --exclude=vendor --languages=go
|
||||
|
||||
## vendor: downloads, tidies, and verifies dependencies
|
||||
.PHONY: vendor
|
||||
@ -137,6 +138,12 @@ vet:
|
||||
test:
|
||||
$(GO) test ./...
|
||||
|
||||
## coverage: generates a test coverage report
|
||||
.PHONY: coverage
|
||||
coverage:
|
||||
$(GO) test ./... -coverprofile=$(TMPDIR)/cheat-coverage.out && \
|
||||
$(GO) tool cover -html=$(TMPDIR)/cheat-coverage.out
|
||||
|
||||
## check: formats, lints, vets, vendors, and run unit-tests
|
||||
.PHONY: check
|
||||
check: | vendor fmt lint vet test
|
||||
|
12
README.md
12
README.md
@ -193,9 +193,17 @@ cheat -p personal -t networking --regex -s '(?:[0-9]{1,3}\.){3}[0-9]{1,3}'
|
||||
|
||||
Advanced Usage
|
||||
--------------
|
||||
`cheat` may be integrated with [fzf][]. See [fzf.bash][bash] for instructions.
|
||||
(Support for other shells will be added in future releases.)
|
||||
Shell autocompletion is currently available for the `bash` and `fish` shells.
|
||||
Copy the relevant [completion script][completion-scripts] 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][]. (This feature is currently available on bash only.) 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
|
||||
[bash]: https://github.com/cheat/cheat/blob/master/scripts/fzf.bash
|
||||
|
@ -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
|
@ -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
|
||||
cmd := exec.Command(conf.Editor, editpath)
|
||||
cmd := exec.Command(editor, args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stderr = os.Stderr
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/cheat/cheat/internal/config"
|
||||
"github.com/cheat/cheat/internal/sheet"
|
||||
"github.com/cheat/cheat/internal/sheets"
|
||||
)
|
||||
|
||||
@ -35,6 +36,23 @@ func cmdSearch(opts map[string]interface{}, conf config.Config) {
|
||||
// local cheatsheets)
|
||||
consolidated := sheets.Consolidate(cheatsheets)
|
||||
|
||||
// if <cheatsheet> was provided, search that single sheet only
|
||||
if opts["<cheatsheet>"] != nil {
|
||||
|
||||
cheatsheet := opts["<cheatsheet>"].(string)
|
||||
|
||||
// assert that the cheatsheet exists
|
||||
s, ok := consolidated[cheatsheet]
|
||||
if !ok {
|
||||
fmt.Printf("No cheatsheet found for '%s'.\n", cheatsheet)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
consolidated = map[string]sheet.Sheet{
|
||||
cheatsheet: s,
|
||||
}
|
||||
}
|
||||
|
||||
// sort the cheatsheets alphabetically, and search for matches
|
||||
for _, sheet := range sheets.Sort(consolidated) {
|
||||
|
||||
@ -53,17 +71,28 @@ func cmdSearch(opts map[string]interface{}, conf config.Config) {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// search the sheet
|
||||
matches := sheet.Search(reg, conf.Color(opts))
|
||||
// `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)
|
||||
|
||||
// display the results
|
||||
if len(matches) > 0 {
|
||||
// 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)
|
||||
}
|
||||
|
||||
// output the cheatsheet title
|
||||
fmt.Printf("%s:\n", sheet.Title)
|
||||
for _, m := range matches {
|
||||
fmt.Printf(" %d: %s\n", m.Line, m.Text)
|
||||
}
|
||||
fmt.Print("\n")
|
||||
}
|
||||
}
|
||||
|
||||
// indent each line of content with two spaces
|
||||
for _, line := range strings.Split(sheet.Text, "\n") {
|
||||
fmt.Printf(" %s\n", line)
|
||||
}
|
||||
fmt.Println("")
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,6 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/alecthomas/chroma/quick"
|
||||
|
||||
"github.com/cheat/cheat/internal/config"
|
||||
"github.com/cheat/cheat/internal/sheets"
|
||||
)
|
||||
@ -43,29 +41,11 @@ func cmdView(opts map[string]interface{}, conf config.Config) {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if !conf.Color(opts) {
|
||||
fmt.Print(sheet.Text)
|
||||
os.Exit(0)
|
||||
// apply colorization if requested
|
||||
if conf.Color(opts) {
|
||||
sheet.Colorize(conf)
|
||||
}
|
||||
|
||||
// otherwise, colorize the output
|
||||
// if the syntax was not specified, default to bash
|
||||
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 {
|
||||
// display the cheatsheet
|
||||
fmt.Print(sheet.Text)
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/docopt/docopt-go"
|
||||
|
||||
@ -13,7 +14,7 @@ import (
|
||||
"github.com/cheat/cheat/internal/config"
|
||||
)
|
||||
|
||||
const version = "3.3.2"
|
||||
const version = "3.6.0"
|
||||
|
||||
func main() {
|
||||
|
||||
@ -31,13 +32,42 @@ func main() {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// load the config file
|
||||
confpath, err := config.Path(runtime.GOOS)
|
||||
// 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 os-specifc paths at which the config file may be located
|
||||
confpaths, err := config.Paths(runtime.GOOS, envvars)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "could not locate config file")
|
||||
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 {
|
||||
|
||||
// the config file does not exist, so we'll try to create one
|
||||
if err = config.Init(confpaths[0], configs()); err != nil {
|
||||
fmt.Fprintf(
|
||||
os.Stderr,
|
||||
"failed to create config file: %s: %v\n",
|
||||
confpaths[0],
|
||||
err,
|
||||
)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
confpath = confpaths[0]
|
||||
|
||||
fmt.Printf("Created config file: %s\n", confpath)
|
||||
fmt.Println("Please edit this file now to configure cheat.")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// initialize the configs
|
||||
conf, err := config.New(opts, confpath, true)
|
||||
if err != nil {
|
||||
|
@ -43,22 +43,23 @@ cheatpaths:
|
||||
#
|
||||
# Note that the paths and tags listed below are just examples. You may freely
|
||||
# change them to suit your needs.
|
||||
#
|
||||
# TODO: regarding community cheatsheets: these must be installed separately.
|
||||
# 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
|
||||
path: ~/.dotfiles/cheat/community
|
||||
path: ~/cheat/cheatsheets/community
|
||||
tags: [ community ]
|
||||
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
|
||||
# precedence over the more global cheatsheets.
|
||||
- name: personal
|
||||
path: ~/.dotfiles/cheat/personal
|
||||
path: ~/cheat/cheatsheets/personal
|
||||
tags: [ personal ]
|
||||
readonly: false
|
||||
|
||||
|
@ -34,22 +34,23 @@ cheatpaths:
|
||||
#
|
||||
# Note that the paths and tags listed below are just examples. You may freely
|
||||
# change them to suit your needs.
|
||||
#
|
||||
# TODO: regarding community cheatsheets: these must be installed separately.
|
||||
# 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
|
||||
path: ~/.dotfiles/cheat/community
|
||||
path: ~/cheat/cheatsheets/community
|
||||
tags: [ community ]
|
||||
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
|
||||
# precedence over the more global cheatsheets.
|
||||
- name: personal
|
||||
path: ~/.dotfiles/cheat/personal
|
||||
path: ~/cheat/cheatsheets/personal
|
||||
tags: [ personal ]
|
||||
readonly: false
|
||||
|
||||
|
1
go.mod
1
go.mod
@ -7,7 +7,6 @@ require (
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
|
||||
github.com/mattn/go-isatty v0.0.12
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
|
2
go.sum
2
go.sum
@ -22,8 +22,6 @@ 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/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
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/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
|
@ -75,14 +75,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
|
||||
// running the config tests.
|
||||
if resolve {
|
||||
expanded, err = filepath.EvalSymlinks(expanded)
|
||||
evaled, err := filepath.EvalSymlinks(expanded)
|
||||
if err != nil {
|
||||
return Config{}, fmt.Errorf(
|
||||
"failed to resolve symlink: %s, %v",
|
||||
"failed to resolve symlink: %s: %v",
|
||||
expanded,
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
expanded = evaled
|
||||
}
|
||||
|
||||
conf.Cheatpaths[i].Path = expanded
|
||||
|
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
|
||||
}
|
@ -3,43 +3,10 @@ package config
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/mitchellh/go-homedir"
|
||||
)
|
||||
|
||||
// Path returns the config file path
|
||||
func Path(sys 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)
|
||||
}
|
||||
func Path(paths []string) (string, error) {
|
||||
|
||||
// check if the config file exists on any paths
|
||||
for _, p := range paths {
|
||||
|
50
internal/config/paths.go
Normal file
50
internal/config/paths.go
Normal file
@ -0,0 +1,50 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
|
||||
"github.com/mitchellh/go-homedir"
|
||||
)
|
||||
|
||||
// Paths returns config file paths that are appropriate for the operating
|
||||
// system
|
||||
func Paths(sys 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 "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, path.Join(xdgpath, "/cheat/conf.yml"))
|
||||
}
|
||||
|
||||
// `HOME` will always be set on a POSIX-compliant system, though
|
||||
paths = append(paths, []string{
|
||||
path.Join(envvars["HOME"], ".config/cheat/conf.yml"),
|
||||
path.Join(envvars["HOME"], ".cheat/conf.yml"),
|
||||
}...)
|
||||
|
||||
return paths, nil
|
||||
case "windows":
|
||||
return []string{
|
||||
path.Join(envvars["APPDATA"], "/cheat/conf.yml"),
|
||||
path.Join(envvars["PROGRAMDATA"], "/cheat/conf.yml"),
|
||||
}, nil
|
||||
default:
|
||||
return []string{}, fmt.Errorf("unsupported os: %s", sys)
|
||||
}
|
||||
}
|
165
internal/config/paths_test.go
Normal file
165
internal/config/paths_test.go
Normal file
@ -0,0 +1,165 @@
|
||||
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 some envvars
|
||||
envvars := map[string]string{
|
||||
"HOME": "/home/foo",
|
||||
"XDG_CONFIG_HOME": "/home/bar",
|
||||
}
|
||||
|
||||
// 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, 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",
|
||||
}
|
||||
|
||||
// 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 some envvars
|
||||
envvars := map[string]string{
|
||||
"HOME": "/home/foo",
|
||||
}
|
||||
|
||||
// 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, 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",
|
||||
}
|
||||
|
||||
// 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 some envvars
|
||||
envvars := map[string]string{
|
||||
"APPDATA": "/apps",
|
||||
"PROGRAMDATA": "/programs",
|
||||
}
|
||||
|
||||
// get the paths for the platform
|
||||
paths, err := Paths("windows", 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 some envvars
|
||||
envvars := map[string]string{
|
||||
"HOME": "/home/foo",
|
||||
"XDG_CONFIG_HOME": "/home/bar",
|
||||
"CHEAT_CONFIG_PATH": "/home/baz/conf.yml",
|
||||
}
|
||||
|
||||
// get the paths for the platform
|
||||
paths, err := Paths("linux", 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),
|
||||
)
|
||||
}
|
||||
}
|
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()
|
||||
}
|
@ -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 (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/mgutz/ansi"
|
||||
)
|
||||
|
||||
// Search searches for regexp matches in a cheatsheet's text, and optionally
|
||||
// colorizes matching strings.
|
||||
func (s *Sheet) Search(reg *regexp.Regexp, colorize bool) []Match {
|
||||
// Search returns lines within a sheet's Text that match the search regex
|
||||
func (s *Sheet) Search(reg *regexp.Regexp) string {
|
||||
|
||||
// record matches
|
||||
matches := []Match{}
|
||||
matches := ""
|
||||
|
||||
// search through the cheatsheet's text line by line
|
||||
// TODO: searching line-by-line is surely the "naive" approach. Revisit this
|
||||
// later with an eye for performance improvements.
|
||||
for linenum, line := range strings.Split(s.Text, "\n") {
|
||||
for _, line := range strings.Split(s.Text, "\n\n") {
|
||||
|
||||
// exit early if the line doesn't match the regex
|
||||
if !reg.MatchString(line) {
|
||||
continue
|
||||
if reg.MatchString(line) {
|
||||
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"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
)
|
||||
|
||||
// TestSearchNoMatch ensures that the expected output is returned when no
|
||||
@ -24,21 +22,21 @@ func TestSearchNoMatch(t *testing.T) {
|
||||
}
|
||||
|
||||
// search the sheet
|
||||
matches := sheet.Search(reg, false)
|
||||
matches := sheet.Search(reg)
|
||||
|
||||
// assert that no matches were found
|
||||
if len(matches) != 0 {
|
||||
t.Errorf("failure: expected no matches: got: %s", spew.Sdump(matches))
|
||||
if matches != "" {
|
||||
t.Errorf("failure: expected no matches: got: %s", matches)
|
||||
}
|
||||
}
|
||||
|
||||
// TestSearchSingleMatchNoColor asserts that the expected output is returned
|
||||
// when a single match is returned, and no colorization is applied.
|
||||
func TestSearchSingleMatchNoColor(t *testing.T) {
|
||||
// TestSearchSingleMatch asserts that the expected output is returned
|
||||
// when a single match is returned
|
||||
func TestSearchSingleMatch(t *testing.T) {
|
||||
|
||||
// mock a cheatsheet
|
||||
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
|
||||
@ -48,69 +46,28 @@ func TestSearchSingleMatchNoColor(t *testing.T) {
|
||||
}
|
||||
|
||||
// search the sheet
|
||||
matches := sheet.Search(reg, false)
|
||||
matches := sheet.Search(reg)
|
||||
|
||||
// specify the expected results
|
||||
want := []Match{
|
||||
Match{
|
||||
Line: 1,
|
||||
Text: "The quick brown fox",
|
||||
},
|
||||
}
|
||||
want := "The quick brown fox\njumped over"
|
||||
|
||||
// assert that the correct matches were returned
|
||||
if !reflect.DeepEqual(matches, want) {
|
||||
if matches != want {
|
||||
t.Errorf(
|
||||
"failed to return expected matches: want:\n%s, got:\n%s",
|
||||
spew.Sdump(want),
|
||||
spew.Sdump(matches),
|
||||
want,
|
||||
matches,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// TestSearchSingleMatchColorized asserts that the expected output is returned
|
||||
// when a single match is returned, and colorization is applied
|
||||
func TestSearchSingleMatchColorized(t *testing.T) {
|
||||
// TestSearchMultiMatch asserts that the expected output is returned
|
||||
// when a multiple matches are returned
|
||||
func TestSearchMultiMatch(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)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.",
|
||||
Text: "The quick brown fox\n\njumped over\n\nthe lazy dog.",
|
||||
}
|
||||
|
||||
// compile the search regex
|
||||
@ -120,66 +77,17 @@ func TestSearchMultiMatchNoColor(t *testing.T) {
|
||||
}
|
||||
|
||||
// search the sheet
|
||||
matches := sheet.Search(reg, false)
|
||||
matches := sheet.Search(reg)
|
||||
|
||||
// specify the expected results
|
||||
want := []Match{
|
||||
Match{
|
||||
Line: 1,
|
||||
Text: "The quick brown fox",
|
||||
},
|
||||
Match{
|
||||
Line: 3,
|
||||
Text: "the lazy dog.",
|
||||
},
|
||||
}
|
||||
want := "The quick brown fox\n\nthe 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),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 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),
|
||||
want,
|
||||
matches,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
@ -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 }'`
|
||||
}
|
9
vendor/github.com/mattn/go-colorable/.travis.yml
generated
vendored
9
vendor/github.com/mattn/go-colorable/.travis.yml
generated
vendored
@ -1,9 +0,0 @@
|
||||
language: go
|
||||
go:
|
||||
- tip
|
||||
|
||||
before_install:
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
script:
|
||||
- $HOME/gopath/bin/goveralls -repotoken xnXqRGwgW3SXIguzxf90ZSK1GPYZPaGrw
|
21
vendor/github.com/mattn/go-colorable/LICENSE
generated
vendored
21
vendor/github.com/mattn/go-colorable/LICENSE
generated
vendored
@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Yasuhiro Matsumoto
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
48
vendor/github.com/mattn/go-colorable/README.md
generated
vendored
48
vendor/github.com/mattn/go-colorable/README.md
generated
vendored
@ -1,48 +0,0 @@
|
||||
# go-colorable
|
||||
|
||||
[](http://godoc.org/github.com/mattn/go-colorable)
|
||||
[](https://travis-ci.org/mattn/go-colorable)
|
||||
[](https://coveralls.io/github/mattn/go-colorable?branch=master)
|
||||
[](https://goreportcard.com/report/mattn/go-colorable)
|
||||
|
||||
Colorable writer for windows.
|
||||
|
||||
For example, most of logger packages doesn't show colors on windows. (I know we can do it with ansicon. But I don't want.)
|
||||
This package is possible to handle escape sequence for ansi color on windows.
|
||||
|
||||
## Too Bad!
|
||||
|
||||

|
||||
|
||||
|
||||
## So Good!
|
||||
|
||||

|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true})
|
||||
logrus.SetOutput(colorable.NewColorableStdout())
|
||||
|
||||
logrus.Info("succeeded")
|
||||
logrus.Warn("not correct")
|
||||
logrus.Error("something error")
|
||||
logrus.Fatal("panic")
|
||||
```
|
||||
|
||||
You can compile above code on non-windows OSs.
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
$ go get github.com/mattn/go-colorable
|
||||
```
|
||||
|
||||
# License
|
||||
|
||||
MIT
|
||||
|
||||
# Author
|
||||
|
||||
Yasuhiro Matsumoto (a.k.a mattn)
|
29
vendor/github.com/mattn/go-colorable/colorable_appengine.go
generated
vendored
29
vendor/github.com/mattn/go-colorable/colorable_appengine.go
generated
vendored
@ -1,29 +0,0 @@
|
||||
// +build appengine
|
||||
|
||||
package colorable
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
_ "github.com/mattn/go-isatty"
|
||||
)
|
||||
|
||||
// NewColorable return new instance of Writer which handle escape sequence.
|
||||
func NewColorable(file *os.File) io.Writer {
|
||||
if file == nil {
|
||||
panic("nil passed instead of *os.File to NewColorable()")
|
||||
}
|
||||
|
||||
return file
|
||||
}
|
||||
|
||||
// NewColorableStdout return new instance of Writer which handle escape sequence for stdout.
|
||||
func NewColorableStdout() io.Writer {
|
||||
return os.Stdout
|
||||
}
|
||||
|
||||
// NewColorableStderr return new instance of Writer which handle escape sequence for stderr.
|
||||
func NewColorableStderr() io.Writer {
|
||||
return os.Stderr
|
||||
}
|
30
vendor/github.com/mattn/go-colorable/colorable_others.go
generated
vendored
30
vendor/github.com/mattn/go-colorable/colorable_others.go
generated
vendored
@ -1,30 +0,0 @@
|
||||
// +build !windows
|
||||
// +build !appengine
|
||||
|
||||
package colorable
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
_ "github.com/mattn/go-isatty"
|
||||
)
|
||||
|
||||
// NewColorable return new instance of Writer which handle escape sequence.
|
||||
func NewColorable(file *os.File) io.Writer {
|
||||
if file == nil {
|
||||
panic("nil passed instead of *os.File to NewColorable()")
|
||||
}
|
||||
|
||||
return file
|
||||
}
|
||||
|
||||
// NewColorableStdout return new instance of Writer which handle escape sequence for stdout.
|
||||
func NewColorableStdout() io.Writer {
|
||||
return os.Stdout
|
||||
}
|
||||
|
||||
// NewColorableStderr return new instance of Writer which handle escape sequence for stderr.
|
||||
func NewColorableStderr() io.Writer {
|
||||
return os.Stderr
|
||||
}
|
884
vendor/github.com/mattn/go-colorable/colorable_windows.go
generated
vendored
884
vendor/github.com/mattn/go-colorable/colorable_windows.go
generated
vendored
@ -1,884 +0,0 @@
|
||||
// +build windows
|
||||
// +build !appengine
|
||||
|
||||
package colorable
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/mattn/go-isatty"
|
||||
)
|
||||
|
||||
const (
|
||||
foregroundBlue = 0x1
|
||||
foregroundGreen = 0x2
|
||||
foregroundRed = 0x4
|
||||
foregroundIntensity = 0x8
|
||||
foregroundMask = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity)
|
||||
backgroundBlue = 0x10
|
||||
backgroundGreen = 0x20
|
||||
backgroundRed = 0x40
|
||||
backgroundIntensity = 0x80
|
||||
backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity)
|
||||
)
|
||||
|
||||
type wchar uint16
|
||||
type short int16
|
||||
type dword uint32
|
||||
type word uint16
|
||||
|
||||
type coord struct {
|
||||
x short
|
||||
y short
|
||||
}
|
||||
|
||||
type smallRect struct {
|
||||
left short
|
||||
top short
|
||||
right short
|
||||
bottom short
|
||||
}
|
||||
|
||||
type consoleScreenBufferInfo struct {
|
||||
size coord
|
||||
cursorPosition coord
|
||||
attributes word
|
||||
window smallRect
|
||||
maximumWindowSize coord
|
||||
}
|
||||
|
||||
type consoleCursorInfo struct {
|
||||
size dword
|
||||
visible int32
|
||||
}
|
||||
|
||||
var (
|
||||
kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
|
||||
procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
|
||||
procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition")
|
||||
procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
|
||||
procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute")
|
||||
procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo")
|
||||
procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo")
|
||||
procSetConsoleTitle = kernel32.NewProc("SetConsoleTitleW")
|
||||
)
|
||||
|
||||
// Writer provide colorable Writer to the console
|
||||
type Writer struct {
|
||||
out io.Writer
|
||||
handle syscall.Handle
|
||||
oldattr word
|
||||
oldpos coord
|
||||
}
|
||||
|
||||
// NewColorable return new instance of Writer which handle escape sequence from File.
|
||||
func NewColorable(file *os.File) io.Writer {
|
||||
if file == nil {
|
||||
panic("nil passed instead of *os.File to NewColorable()")
|
||||
}
|
||||
|
||||
if isatty.IsTerminal(file.Fd()) {
|
||||
var csbi consoleScreenBufferInfo
|
||||
handle := syscall.Handle(file.Fd())
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
return &Writer{out: file, handle: handle, oldattr: csbi.attributes, oldpos: coord{0, 0}}
|
||||
}
|
||||
return file
|
||||
}
|
||||
|
||||
// NewColorableStdout return new instance of Writer which handle escape sequence for stdout.
|
||||
func NewColorableStdout() io.Writer {
|
||||
return NewColorable(os.Stdout)
|
||||
}
|
||||
|
||||
// NewColorableStderr return new instance of Writer which handle escape sequence for stderr.
|
||||
func NewColorableStderr() io.Writer {
|
||||
return NewColorable(os.Stderr)
|
||||
}
|
||||
|
||||
var color256 = map[int]int{
|
||||
0: 0x000000,
|
||||
1: 0x800000,
|
||||
2: 0x008000,
|
||||
3: 0x808000,
|
||||
4: 0x000080,
|
||||
5: 0x800080,
|
||||
6: 0x008080,
|
||||
7: 0xc0c0c0,
|
||||
8: 0x808080,
|
||||
9: 0xff0000,
|
||||
10: 0x00ff00,
|
||||
11: 0xffff00,
|
||||
12: 0x0000ff,
|
||||
13: 0xff00ff,
|
||||
14: 0x00ffff,
|
||||
15: 0xffffff,
|
||||
16: 0x000000,
|
||||
17: 0x00005f,
|
||||
18: 0x000087,
|
||||
19: 0x0000af,
|
||||
20: 0x0000d7,
|
||||
21: 0x0000ff,
|
||||
22: 0x005f00,
|
||||
23: 0x005f5f,
|
||||
24: 0x005f87,
|
||||
25: 0x005faf,
|
||||
26: 0x005fd7,
|
||||
27: 0x005fff,
|
||||
28: 0x008700,
|
||||
29: 0x00875f,
|
||||
30: 0x008787,
|
||||
31: 0x0087af,
|
||||
32: 0x0087d7,
|
||||
33: 0x0087ff,
|
||||
34: 0x00af00,
|
||||
35: 0x00af5f,
|
||||
36: 0x00af87,
|
||||
37: 0x00afaf,
|
||||
38: 0x00afd7,
|
||||
39: 0x00afff,
|
||||
40: 0x00d700,
|
||||
41: 0x00d75f,
|
||||
42: 0x00d787,
|
||||
43: 0x00d7af,
|
||||
44: 0x00d7d7,
|
||||
45: 0x00d7ff,
|
||||
46: 0x00ff00,
|
||||
47: 0x00ff5f,
|
||||
48: 0x00ff87,
|
||||
49: 0x00ffaf,
|
||||
50: 0x00ffd7,
|
||||
51: 0x00ffff,
|
||||
52: 0x5f0000,
|
||||
53: 0x5f005f,
|
||||
54: 0x5f0087,
|
||||
55: 0x5f00af,
|
||||
56: 0x5f00d7,
|
||||
57: 0x5f00ff,
|
||||
58: 0x5f5f00,
|
||||
59: 0x5f5f5f,
|
||||
60: 0x5f5f87,
|
||||
61: 0x5f5faf,
|
||||
62: 0x5f5fd7,
|
||||
63: 0x5f5fff,
|
||||
64: 0x5f8700,
|
||||
65: 0x5f875f,
|
||||
66: 0x5f8787,
|
||||
67: 0x5f87af,
|
||||
68: 0x5f87d7,
|
||||
69: 0x5f87ff,
|
||||
70: 0x5faf00,
|
||||
71: 0x5faf5f,
|
||||
72: 0x5faf87,
|
||||
73: 0x5fafaf,
|
||||
74: 0x5fafd7,
|
||||
75: 0x5fafff,
|
||||
76: 0x5fd700,
|
||||
77: 0x5fd75f,
|
||||
78: 0x5fd787,
|
||||
79: 0x5fd7af,
|
||||
80: 0x5fd7d7,
|
||||
81: 0x5fd7ff,
|
||||
82: 0x5fff00,
|
||||
83: 0x5fff5f,
|
||||
84: 0x5fff87,
|
||||
85: 0x5fffaf,
|
||||
86: 0x5fffd7,
|
||||
87: 0x5fffff,
|
||||
88: 0x870000,
|
||||
89: 0x87005f,
|
||||
90: 0x870087,
|
||||
91: 0x8700af,
|
||||
92: 0x8700d7,
|
||||
93: 0x8700ff,
|
||||
94: 0x875f00,
|
||||
95: 0x875f5f,
|
||||
96: 0x875f87,
|
||||
97: 0x875faf,
|
||||
98: 0x875fd7,
|
||||
99: 0x875fff,
|
||||
100: 0x878700,
|
||||
101: 0x87875f,
|
||||
102: 0x878787,
|
||||
103: 0x8787af,
|
||||
104: 0x8787d7,
|
||||
105: 0x8787ff,
|
||||
106: 0x87af00,
|
||||
107: 0x87af5f,
|
||||
108: 0x87af87,
|
||||
109: 0x87afaf,
|
||||
110: 0x87afd7,
|
||||
111: 0x87afff,
|
||||
112: 0x87d700,
|
||||
113: 0x87d75f,
|
||||
114: 0x87d787,
|
||||
115: 0x87d7af,
|
||||
116: 0x87d7d7,
|
||||
117: 0x87d7ff,
|
||||
118: 0x87ff00,
|
||||
119: 0x87ff5f,
|
||||
120: 0x87ff87,
|
||||
121: 0x87ffaf,
|
||||
122: 0x87ffd7,
|
||||
123: 0x87ffff,
|
||||
124: 0xaf0000,
|
||||
125: 0xaf005f,
|
||||
126: 0xaf0087,
|
||||
127: 0xaf00af,
|
||||
128: 0xaf00d7,
|
||||
129: 0xaf00ff,
|
||||
130: 0xaf5f00,
|
||||
131: 0xaf5f5f,
|
||||
132: 0xaf5f87,
|
||||
133: 0xaf5faf,
|
||||
134: 0xaf5fd7,
|
||||
135: 0xaf5fff,
|
||||
136: 0xaf8700,
|
||||
137: 0xaf875f,
|
||||
138: 0xaf8787,
|
||||
139: 0xaf87af,
|
||||
140: 0xaf87d7,
|
||||
141: 0xaf87ff,
|
||||
142: 0xafaf00,
|
||||
143: 0xafaf5f,
|
||||
144: 0xafaf87,
|
||||
145: 0xafafaf,
|
||||
146: 0xafafd7,
|
||||
147: 0xafafff,
|
||||
148: 0xafd700,
|
||||
149: 0xafd75f,
|
||||
150: 0xafd787,
|
||||
151: 0xafd7af,
|
||||
152: 0xafd7d7,
|
||||
153: 0xafd7ff,
|
||||
154: 0xafff00,
|
||||
155: 0xafff5f,
|
||||
156: 0xafff87,
|
||||
157: 0xafffaf,
|
||||
158: 0xafffd7,
|
||||
159: 0xafffff,
|
||||
160: 0xd70000,
|
||||
161: 0xd7005f,
|
||||
162: 0xd70087,
|
||||
163: 0xd700af,
|
||||
164: 0xd700d7,
|
||||
165: 0xd700ff,
|
||||
166: 0xd75f00,
|
||||
167: 0xd75f5f,
|
||||
168: 0xd75f87,
|
||||
169: 0xd75faf,
|
||||
170: 0xd75fd7,
|
||||
171: 0xd75fff,
|
||||
172: 0xd78700,
|
||||
173: 0xd7875f,
|
||||
174: 0xd78787,
|
||||
175: 0xd787af,
|
||||
176: 0xd787d7,
|
||||
177: 0xd787ff,
|
||||
178: 0xd7af00,
|
||||
179: 0xd7af5f,
|
||||
180: 0xd7af87,
|
||||
181: 0xd7afaf,
|
||||
182: 0xd7afd7,
|
||||
183: 0xd7afff,
|
||||
184: 0xd7d700,
|
||||
185: 0xd7d75f,
|
||||
186: 0xd7d787,
|
||||
187: 0xd7d7af,
|
||||
188: 0xd7d7d7,
|
||||
189: 0xd7d7ff,
|
||||
190: 0xd7ff00,
|
||||
191: 0xd7ff5f,
|
||||
192: 0xd7ff87,
|
||||
193: 0xd7ffaf,
|
||||
194: 0xd7ffd7,
|
||||
195: 0xd7ffff,
|
||||
196: 0xff0000,
|
||||
197: 0xff005f,
|
||||
198: 0xff0087,
|
||||
199: 0xff00af,
|
||||
200: 0xff00d7,
|
||||
201: 0xff00ff,
|
||||
202: 0xff5f00,
|
||||
203: 0xff5f5f,
|
||||
204: 0xff5f87,
|
||||
205: 0xff5faf,
|
||||
206: 0xff5fd7,
|
||||
207: 0xff5fff,
|
||||
208: 0xff8700,
|
||||
209: 0xff875f,
|
||||
210: 0xff8787,
|
||||
211: 0xff87af,
|
||||
212: 0xff87d7,
|
||||
213: 0xff87ff,
|
||||
214: 0xffaf00,
|
||||
215: 0xffaf5f,
|
||||
216: 0xffaf87,
|
||||
217: 0xffafaf,
|
||||
218: 0xffafd7,
|
||||
219: 0xffafff,
|
||||
220: 0xffd700,
|
||||
221: 0xffd75f,
|
||||
222: 0xffd787,
|
||||
223: 0xffd7af,
|
||||
224: 0xffd7d7,
|
||||
225: 0xffd7ff,
|
||||
226: 0xffff00,
|
||||
227: 0xffff5f,
|
||||
228: 0xffff87,
|
||||
229: 0xffffaf,
|
||||
230: 0xffffd7,
|
||||
231: 0xffffff,
|
||||
232: 0x080808,
|
||||
233: 0x121212,
|
||||
234: 0x1c1c1c,
|
||||
235: 0x262626,
|
||||
236: 0x303030,
|
||||
237: 0x3a3a3a,
|
||||
238: 0x444444,
|
||||
239: 0x4e4e4e,
|
||||
240: 0x585858,
|
||||
241: 0x626262,
|
||||
242: 0x6c6c6c,
|
||||
243: 0x767676,
|
||||
244: 0x808080,
|
||||
245: 0x8a8a8a,
|
||||
246: 0x949494,
|
||||
247: 0x9e9e9e,
|
||||
248: 0xa8a8a8,
|
||||
249: 0xb2b2b2,
|
||||
250: 0xbcbcbc,
|
||||
251: 0xc6c6c6,
|
||||
252: 0xd0d0d0,
|
||||
253: 0xdadada,
|
||||
254: 0xe4e4e4,
|
||||
255: 0xeeeeee,
|
||||
}
|
||||
|
||||
// `\033]0;TITLESTR\007`
|
||||
func doTitleSequence(er *bytes.Reader) error {
|
||||
var c byte
|
||||
var err error
|
||||
|
||||
c, err = er.ReadByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c != '0' && c != '2' {
|
||||
return nil
|
||||
}
|
||||
c, err = er.ReadByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c != ';' {
|
||||
return nil
|
||||
}
|
||||
title := make([]byte, 0, 80)
|
||||
for {
|
||||
c, err = er.ReadByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c == 0x07 || c == '\n' {
|
||||
break
|
||||
}
|
||||
title = append(title, c)
|
||||
}
|
||||
if len(title) > 0 {
|
||||
title8, err := syscall.UTF16PtrFromString(string(title))
|
||||
if err == nil {
|
||||
procSetConsoleTitle.Call(uintptr(unsafe.Pointer(title8)))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Write write data on console
|
||||
func (w *Writer) Write(data []byte) (n int, err error) {
|
||||
var csbi consoleScreenBufferInfo
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
|
||||
er := bytes.NewReader(data)
|
||||
var bw [1]byte
|
||||
loop:
|
||||
for {
|
||||
c1, err := er.ReadByte()
|
||||
if err != nil {
|
||||
break loop
|
||||
}
|
||||
if c1 != 0x1b {
|
||||
bw[0] = c1
|
||||
w.out.Write(bw[:])
|
||||
continue
|
||||
}
|
||||
c2, err := er.ReadByte()
|
||||
if err != nil {
|
||||
break loop
|
||||
}
|
||||
|
||||
if c2 == ']' {
|
||||
if err := doTitleSequence(er); err != nil {
|
||||
break loop
|
||||
}
|
||||
continue
|
||||
}
|
||||
if c2 != 0x5b {
|
||||
continue
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
var m byte
|
||||
for {
|
||||
c, err := er.ReadByte()
|
||||
if err != nil {
|
||||
break loop
|
||||
}
|
||||
if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
|
||||
m = c
|
||||
break
|
||||
}
|
||||
buf.Write([]byte(string(c)))
|
||||
}
|
||||
|
||||
switch m {
|
||||
case 'A':
|
||||
n, err = strconv.Atoi(buf.String())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
csbi.cursorPosition.y -= short(n)
|
||||
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
|
||||
case 'B':
|
||||
n, err = strconv.Atoi(buf.String())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
csbi.cursorPosition.y += short(n)
|
||||
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
|
||||
case 'C':
|
||||
n, err = strconv.Atoi(buf.String())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
csbi.cursorPosition.x += short(n)
|
||||
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
|
||||
case 'D':
|
||||
n, err = strconv.Atoi(buf.String())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
csbi.cursorPosition.x -= short(n)
|
||||
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
|
||||
case 'E':
|
||||
n, err = strconv.Atoi(buf.String())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
csbi.cursorPosition.x = 0
|
||||
csbi.cursorPosition.y += short(n)
|
||||
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
|
||||
case 'F':
|
||||
n, err = strconv.Atoi(buf.String())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
csbi.cursorPosition.x = 0
|
||||
csbi.cursorPosition.y -= short(n)
|
||||
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
|
||||
case 'G':
|
||||
n, err = strconv.Atoi(buf.String())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
csbi.cursorPosition.x = short(n - 1)
|
||||
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
|
||||
case 'H', 'f':
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
if buf.Len() > 0 {
|
||||
token := strings.Split(buf.String(), ";")
|
||||
switch len(token) {
|
||||
case 1:
|
||||
n1, err := strconv.Atoi(token[0])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
csbi.cursorPosition.y = short(n1 - 1)
|
||||
case 2:
|
||||
n1, err := strconv.Atoi(token[0])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
n2, err := strconv.Atoi(token[1])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
csbi.cursorPosition.x = short(n2 - 1)
|
||||
csbi.cursorPosition.y = short(n1 - 1)
|
||||
}
|
||||
} else {
|
||||
csbi.cursorPosition.y = 0
|
||||
}
|
||||
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
|
||||
case 'J':
|
||||
n := 0
|
||||
if buf.Len() > 0 {
|
||||
n, err = strconv.Atoi(buf.String())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
var count, written dword
|
||||
var cursor coord
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
switch n {
|
||||
case 0:
|
||||
cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y}
|
||||
count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x)
|
||||
case 1:
|
||||
cursor = coord{x: csbi.window.left, y: csbi.window.top}
|
||||
count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.window.top-csbi.cursorPosition.y)*csbi.size.x)
|
||||
case 2:
|
||||
cursor = coord{x: csbi.window.left, y: csbi.window.top}
|
||||
count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x)
|
||||
}
|
||||
procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
|
||||
procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
|
||||
case 'K':
|
||||
n := 0
|
||||
if buf.Len() > 0 {
|
||||
n, err = strconv.Atoi(buf.String())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
var cursor coord
|
||||
var count, written dword
|
||||
switch n {
|
||||
case 0:
|
||||
cursor = coord{x: csbi.cursorPosition.x + 1, y: csbi.cursorPosition.y}
|
||||
count = dword(csbi.size.x - csbi.cursorPosition.x - 1)
|
||||
case 1:
|
||||
cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y}
|
||||
count = dword(csbi.size.x - csbi.cursorPosition.x)
|
||||
case 2:
|
||||
cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y}
|
||||
count = dword(csbi.size.x)
|
||||
}
|
||||
procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
|
||||
procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
|
||||
case 'm':
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
attr := csbi.attributes
|
||||
cs := buf.String()
|
||||
if cs == "" {
|
||||
procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr))
|
||||
continue
|
||||
}
|
||||
token := strings.Split(cs, ";")
|
||||
for i := 0; i < len(token); i++ {
|
||||
ns := token[i]
|
||||
if n, err = strconv.Atoi(ns); err == nil {
|
||||
switch {
|
||||
case n == 0 || n == 100:
|
||||
attr = w.oldattr
|
||||
case 1 <= n && n <= 5:
|
||||
attr |= foregroundIntensity
|
||||
case n == 7:
|
||||
attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
|
||||
case n == 22 || n == 25:
|
||||
attr |= foregroundIntensity
|
||||
case n == 27:
|
||||
attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
|
||||
case 30 <= n && n <= 37:
|
||||
attr &= backgroundMask
|
||||
if (n-30)&1 != 0 {
|
||||
attr |= foregroundRed
|
||||
}
|
||||
if (n-30)&2 != 0 {
|
||||
attr |= foregroundGreen
|
||||
}
|
||||
if (n-30)&4 != 0 {
|
||||
attr |= foregroundBlue
|
||||
}
|
||||
case n == 38: // set foreground color.
|
||||
if i < len(token)-2 && (token[i+1] == "5" || token[i+1] == "05") {
|
||||
if n256, err := strconv.Atoi(token[i+2]); err == nil {
|
||||
if n256foreAttr == nil {
|
||||
n256setup()
|
||||
}
|
||||
attr &= backgroundMask
|
||||
attr |= n256foreAttr[n256]
|
||||
i += 2
|
||||
}
|
||||
} else {
|
||||
attr = attr & (w.oldattr & backgroundMask)
|
||||
}
|
||||
case n == 39: // reset foreground color.
|
||||
attr &= backgroundMask
|
||||
attr |= w.oldattr & foregroundMask
|
||||
case 40 <= n && n <= 47:
|
||||
attr &= foregroundMask
|
||||
if (n-40)&1 != 0 {
|
||||
attr |= backgroundRed
|
||||
}
|
||||
if (n-40)&2 != 0 {
|
||||
attr |= backgroundGreen
|
||||
}
|
||||
if (n-40)&4 != 0 {
|
||||
attr |= backgroundBlue
|
||||
}
|
||||
case n == 48: // set background color.
|
||||
if i < len(token)-2 && token[i+1] == "5" {
|
||||
if n256, err := strconv.Atoi(token[i+2]); err == nil {
|
||||
if n256backAttr == nil {
|
||||
n256setup()
|
||||
}
|
||||
attr &= foregroundMask
|
||||
attr |= n256backAttr[n256]
|
||||
i += 2
|
||||
}
|
||||
} else {
|
||||
attr = attr & (w.oldattr & foregroundMask)
|
||||
}
|
||||
case n == 49: // reset foreground color.
|
||||
attr &= foregroundMask
|
||||
attr |= w.oldattr & backgroundMask
|
||||
case 90 <= n && n <= 97:
|
||||
attr = (attr & backgroundMask)
|
||||
attr |= foregroundIntensity
|
||||
if (n-90)&1 != 0 {
|
||||
attr |= foregroundRed
|
||||
}
|
||||
if (n-90)&2 != 0 {
|
||||
attr |= foregroundGreen
|
||||
}
|
||||
if (n-90)&4 != 0 {
|
||||
attr |= foregroundBlue
|
||||
}
|
||||
case 100 <= n && n <= 107:
|
||||
attr = (attr & foregroundMask)
|
||||
attr |= backgroundIntensity
|
||||
if (n-100)&1 != 0 {
|
||||
attr |= backgroundRed
|
||||
}
|
||||
if (n-100)&2 != 0 {
|
||||
attr |= backgroundGreen
|
||||
}
|
||||
if (n-100)&4 != 0 {
|
||||
attr |= backgroundBlue
|
||||
}
|
||||
}
|
||||
procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr))
|
||||
}
|
||||
}
|
||||
case 'h':
|
||||
var ci consoleCursorInfo
|
||||
cs := buf.String()
|
||||
if cs == "5>" {
|
||||
procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
|
||||
ci.visible = 0
|
||||
procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
|
||||
} else if cs == "?25" {
|
||||
procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
|
||||
ci.visible = 1
|
||||
procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
|
||||
}
|
||||
case 'l':
|
||||
var ci consoleCursorInfo
|
||||
cs := buf.String()
|
||||
if cs == "5>" {
|
||||
procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
|
||||
ci.visible = 1
|
||||
procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
|
||||
} else if cs == "?25" {
|
||||
procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
|
||||
ci.visible = 0
|
||||
procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
|
||||
}
|
||||
case 's':
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
w.oldpos = csbi.cursorPosition
|
||||
case 'u':
|
||||
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&w.oldpos)))
|
||||
}
|
||||
}
|
||||
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
type consoleColor struct {
|
||||
rgb int
|
||||
red bool
|
||||
green bool
|
||||
blue bool
|
||||
intensity bool
|
||||
}
|
||||
|
||||
func (c consoleColor) foregroundAttr() (attr word) {
|
||||
if c.red {
|
||||
attr |= foregroundRed
|
||||
}
|
||||
if c.green {
|
||||
attr |= foregroundGreen
|
||||
}
|
||||
if c.blue {
|
||||
attr |= foregroundBlue
|
||||
}
|
||||
if c.intensity {
|
||||
attr |= foregroundIntensity
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c consoleColor) backgroundAttr() (attr word) {
|
||||
if c.red {
|
||||
attr |= backgroundRed
|
||||
}
|
||||
if c.green {
|
||||
attr |= backgroundGreen
|
||||
}
|
||||
if c.blue {
|
||||
attr |= backgroundBlue
|
||||
}
|
||||
if c.intensity {
|
||||
attr |= backgroundIntensity
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var color16 = []consoleColor{
|
||||
{0x000000, false, false, false, false},
|
||||
{0x000080, false, false, true, false},
|
||||
{0x008000, false, true, false, false},
|
||||
{0x008080, false, true, true, false},
|
||||
{0x800000, true, false, false, false},
|
||||
{0x800080, true, false, true, false},
|
||||
{0x808000, true, true, false, false},
|
||||
{0xc0c0c0, true, true, true, false},
|
||||
{0x808080, false, false, false, true},
|
||||
{0x0000ff, false, false, true, true},
|
||||
{0x00ff00, false, true, false, true},
|
||||
{0x00ffff, false, true, true, true},
|
||||
{0xff0000, true, false, false, true},
|
||||
{0xff00ff, true, false, true, true},
|
||||
{0xffff00, true, true, false, true},
|
||||
{0xffffff, true, true, true, true},
|
||||
}
|
||||
|
||||
type hsv struct {
|
||||
h, s, v float32
|
||||
}
|
||||
|
||||
func (a hsv) dist(b hsv) float32 {
|
||||
dh := a.h - b.h
|
||||
switch {
|
||||
case dh > 0.5:
|
||||
dh = 1 - dh
|
||||
case dh < -0.5:
|
||||
dh = -1 - dh
|
||||
}
|
||||
ds := a.s - b.s
|
||||
dv := a.v - b.v
|
||||
return float32(math.Sqrt(float64(dh*dh + ds*ds + dv*dv)))
|
||||
}
|
||||
|
||||
func toHSV(rgb int) hsv {
|
||||
r, g, b := float32((rgb&0xFF0000)>>16)/256.0,
|
||||
float32((rgb&0x00FF00)>>8)/256.0,
|
||||
float32(rgb&0x0000FF)/256.0
|
||||
min, max := minmax3f(r, g, b)
|
||||
h := max - min
|
||||
if h > 0 {
|
||||
if max == r {
|
||||
h = (g - b) / h
|
||||
if h < 0 {
|
||||
h += 6
|
||||
}
|
||||
} else if max == g {
|
||||
h = 2 + (b-r)/h
|
||||
} else {
|
||||
h = 4 + (r-g)/h
|
||||
}
|
||||
}
|
||||
h /= 6.0
|
||||
s := max - min
|
||||
if max != 0 {
|
||||
s /= max
|
||||
}
|
||||
v := max
|
||||
return hsv{h: h, s: s, v: v}
|
||||
}
|
||||
|
||||
type hsvTable []hsv
|
||||
|
||||
func toHSVTable(rgbTable []consoleColor) hsvTable {
|
||||
t := make(hsvTable, len(rgbTable))
|
||||
for i, c := range rgbTable {
|
||||
t[i] = toHSV(c.rgb)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (t hsvTable) find(rgb int) consoleColor {
|
||||
hsv := toHSV(rgb)
|
||||
n := 7
|
||||
l := float32(5.0)
|
||||
for i, p := range t {
|
||||
d := hsv.dist(p)
|
||||
if d < l {
|
||||
l, n = d, i
|
||||
}
|
||||
}
|
||||
return color16[n]
|
||||
}
|
||||
|
||||
func minmax3f(a, b, c float32) (min, max float32) {
|
||||
if a < b {
|
||||
if b < c {
|
||||
return a, c
|
||||
} else if a < c {
|
||||
return a, b
|
||||
} else {
|
||||
return c, b
|
||||
}
|
||||
} else {
|
||||
if a < c {
|
||||
return b, c
|
||||
} else if b < c {
|
||||
return b, a
|
||||
} else {
|
||||
return c, a
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var n256foreAttr []word
|
||||
var n256backAttr []word
|
||||
|
||||
func n256setup() {
|
||||
n256foreAttr = make([]word, 256)
|
||||
n256backAttr = make([]word, 256)
|
||||
t := toHSVTable(color16)
|
||||
for i, rgb := range color256 {
|
||||
c := t.find(rgb)
|
||||
n256foreAttr[i] = c.foregroundAttr()
|
||||
n256backAttr[i] = c.backgroundAttr()
|
||||
}
|
||||
}
|
55
vendor/github.com/mattn/go-colorable/noncolorable.go
generated
vendored
55
vendor/github.com/mattn/go-colorable/noncolorable.go
generated
vendored
@ -1,55 +0,0 @@
|
||||
package colorable
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
)
|
||||
|
||||
// NonColorable hold writer but remove escape sequence.
|
||||
type NonColorable struct {
|
||||
out io.Writer
|
||||
}
|
||||
|
||||
// NewNonColorable return new instance of Writer which remove escape sequence from Writer.
|
||||
func NewNonColorable(w io.Writer) io.Writer {
|
||||
return &NonColorable{out: w}
|
||||
}
|
||||
|
||||
// Write write data on console
|
||||
func (w *NonColorable) Write(data []byte) (n int, err error) {
|
||||
er := bytes.NewReader(data)
|
||||
var bw [1]byte
|
||||
loop:
|
||||
for {
|
||||
c1, err := er.ReadByte()
|
||||
if err != nil {
|
||||
break loop
|
||||
}
|
||||
if c1 != 0x1b {
|
||||
bw[0] = c1
|
||||
w.out.Write(bw[:])
|
||||
continue
|
||||
}
|
||||
c2, err := er.ReadByte()
|
||||
if err != nil {
|
||||
break loop
|
||||
}
|
||||
if c2 != 0x5b {
|
||||
continue
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
for {
|
||||
c, err := er.ReadByte()
|
||||
if err != nil {
|
||||
break loop
|
||||
}
|
||||
if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
|
||||
break
|
||||
}
|
||||
buf.Write([]byte(string(c)))
|
||||
}
|
||||
}
|
||||
|
||||
return len(data), nil
|
||||
}
|
1
vendor/github.com/mgutz/ansi/.gitignore
generated
vendored
1
vendor/github.com/mgutz/ansi/.gitignore
generated
vendored
@ -1 +0,0 @@
|
||||
*.test
|
9
vendor/github.com/mgutz/ansi/LICENSE
generated
vendored
9
vendor/github.com/mgutz/ansi/LICENSE
generated
vendored
@ -1,9 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2013 Mario L. Gutierrez
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
121
vendor/github.com/mgutz/ansi/README.md
generated
vendored
121
vendor/github.com/mgutz/ansi/README.md
generated
vendored
@ -1,121 +0,0 @@
|
||||
# ansi
|
||||
|
||||
Package ansi is a small, fast library to create ANSI colored strings and codes.
|
||||
|
||||
## Install
|
||||
|
||||
Get it
|
||||
|
||||
```sh
|
||||
go get -u github.com/mgutz/ansi
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```go
|
||||
import "github.com/mgutz/ansi"
|
||||
|
||||
// colorize a string, SLOW
|
||||
msg := ansi.Color("foo", "red+b:white")
|
||||
|
||||
// create a FAST closure function to avoid computation of ANSI code
|
||||
phosphorize := ansi.ColorFunc("green+h:black")
|
||||
msg = phosphorize("Bring back the 80s!")
|
||||
msg2 := phospohorize("Look, I'm a CRT!")
|
||||
|
||||
// cache escape codes and build strings manually
|
||||
lime := ansi.ColorCode("green+h:black")
|
||||
reset := ansi.ColorCode("reset")
|
||||
|
||||
fmt.Println(lime, "Bring back the 80s!", reset)
|
||||
```
|
||||
|
||||
Other examples
|
||||
|
||||
```go
|
||||
Color(s, "red") // red
|
||||
Color(s, "red+b") // red bold
|
||||
Color(s, "red+B") // red blinking
|
||||
Color(s, "red+u") // red underline
|
||||
Color(s, "red+bh") // red bold bright
|
||||
Color(s, "red:white") // red on white
|
||||
Color(s, "red+b:white+h") // red bold on white bright
|
||||
Color(s, "red+B:white+h") // red blink on white bright
|
||||
Color(s, "off") // turn off ansi codes
|
||||
```
|
||||
|
||||
To view color combinations, from project directory in terminal.
|
||||
|
||||
```sh
|
||||
go test
|
||||
```
|
||||
|
||||
## Style format
|
||||
|
||||
```go
|
||||
"foregroundColor+attributes:backgroundColor+attributes"
|
||||
```
|
||||
|
||||
Colors
|
||||
|
||||
* black
|
||||
* red
|
||||
* green
|
||||
* yellow
|
||||
* blue
|
||||
* magenta
|
||||
* cyan
|
||||
* white
|
||||
* 0...255 (256 colors)
|
||||
|
||||
Foreground Attributes
|
||||
|
||||
* B = Blink
|
||||
* b = bold
|
||||
* h = high intensity (bright)
|
||||
* i = inverse
|
||||
* s = strikethrough
|
||||
* u = underline
|
||||
|
||||
Background Attributes
|
||||
|
||||
* h = high intensity (bright)
|
||||
|
||||
## Constants
|
||||
|
||||
* ansi.Reset
|
||||
* ansi.DefaultBG
|
||||
* ansi.DefaultFG
|
||||
* ansi.Black
|
||||
* ansi.Red
|
||||
* ansi.Green
|
||||
* ansi.Yellow
|
||||
* ansi.Blue
|
||||
* ansi.Magenta
|
||||
* ansi.Cyan
|
||||
* ansi.White
|
||||
* ansi.LightBlack
|
||||
* ansi.LightRed
|
||||
* ansi.LightGreen
|
||||
* ansi.LightYellow
|
||||
* ansi.LightBlue
|
||||
* ansi.LightMagenta
|
||||
* ansi.LightCyan
|
||||
* ansi.LightWhite
|
||||
|
||||
## References
|
||||
|
||||
Wikipedia ANSI escape codes [Colors](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors)
|
||||
|
||||
General [tips and formatting](http://misc.flogisoft.com/bash/tip_colors_and_formatting)
|
||||
|
||||
What about support on Windows? Use [colorable by mattn](https://github.com/mattn/go-colorable).
|
||||
Ansi and colorable are used by [logxi](https://github.com/mgutz/logxi) to support logging in
|
||||
color on Windows.
|
||||
|
||||
## MIT License
|
||||
|
||||
Copyright (c) 2013 Mario Gutierrez mario@mgutz.com
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
|
285
vendor/github.com/mgutz/ansi/ansi.go
generated
vendored
285
vendor/github.com/mgutz/ansi/ansi.go
generated
vendored
@ -1,285 +0,0 @@
|
||||
package ansi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
black = iota
|
||||
red
|
||||
green
|
||||
yellow
|
||||
blue
|
||||
magenta
|
||||
cyan
|
||||
white
|
||||
defaultt = 9
|
||||
|
||||
normalIntensityFG = 30
|
||||
highIntensityFG = 90
|
||||
normalIntensityBG = 40
|
||||
highIntensityBG = 100
|
||||
|
||||
start = "\033["
|
||||
bold = "1;"
|
||||
blink = "5;"
|
||||
underline = "4;"
|
||||
inverse = "7;"
|
||||
strikethrough = "9;"
|
||||
|
||||
// Reset is the ANSI reset escape sequence
|
||||
Reset = "\033[0m"
|
||||
// DefaultBG is the default background
|
||||
DefaultBG = "\033[49m"
|
||||
// DefaultFG is the default foreground
|
||||
DefaultFG = "\033[39m"
|
||||
)
|
||||
|
||||
// Black FG
|
||||
var Black string
|
||||
|
||||
// Red FG
|
||||
var Red string
|
||||
|
||||
// Green FG
|
||||
var Green string
|
||||
|
||||
// Yellow FG
|
||||
var Yellow string
|
||||
|
||||
// Blue FG
|
||||
var Blue string
|
||||
|
||||
// Magenta FG
|
||||
var Magenta string
|
||||
|
||||
// Cyan FG
|
||||
var Cyan string
|
||||
|
||||
// White FG
|
||||
var White string
|
||||
|
||||
// LightBlack FG
|
||||
var LightBlack string
|
||||
|
||||
// LightRed FG
|
||||
var LightRed string
|
||||
|
||||
// LightGreen FG
|
||||
var LightGreen string
|
||||
|
||||
// LightYellow FG
|
||||
var LightYellow string
|
||||
|
||||
// LightBlue FG
|
||||
var LightBlue string
|
||||
|
||||
// LightMagenta FG
|
||||
var LightMagenta string
|
||||
|
||||
// LightCyan FG
|
||||
var LightCyan string
|
||||
|
||||
// LightWhite FG
|
||||
var LightWhite string
|
||||
|
||||
var (
|
||||
plain = false
|
||||
// Colors maps common color names to their ANSI color code.
|
||||
Colors = map[string]int{
|
||||
"black": black,
|
||||
"red": red,
|
||||
"green": green,
|
||||
"yellow": yellow,
|
||||
"blue": blue,
|
||||
"magenta": magenta,
|
||||
"cyan": cyan,
|
||||
"white": white,
|
||||
"default": defaultt,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
for i := 0; i < 256; i++ {
|
||||
Colors[strconv.Itoa(i)] = i
|
||||
}
|
||||
|
||||
Black = ColorCode("black")
|
||||
Red = ColorCode("red")
|
||||
Green = ColorCode("green")
|
||||
Yellow = ColorCode("yellow")
|
||||
Blue = ColorCode("blue")
|
||||
Magenta = ColorCode("magenta")
|
||||
Cyan = ColorCode("cyan")
|
||||
White = ColorCode("white")
|
||||
LightBlack = ColorCode("black+h")
|
||||
LightRed = ColorCode("red+h")
|
||||
LightGreen = ColorCode("green+h")
|
||||
LightYellow = ColorCode("yellow+h")
|
||||
LightBlue = ColorCode("blue+h")
|
||||
LightMagenta = ColorCode("magenta+h")
|
||||
LightCyan = ColorCode("cyan+h")
|
||||
LightWhite = ColorCode("white+h")
|
||||
}
|
||||
|
||||
// ColorCode returns the ANSI color color code for style.
|
||||
func ColorCode(style string) string {
|
||||
return colorCode(style).String()
|
||||
}
|
||||
|
||||
// Gets the ANSI color code for a style.
|
||||
func colorCode(style string) *bytes.Buffer {
|
||||
buf := bytes.NewBufferString("")
|
||||
if plain || style == "" {
|
||||
return buf
|
||||
}
|
||||
if style == "reset" {
|
||||
buf.WriteString(Reset)
|
||||
return buf
|
||||
} else if style == "off" {
|
||||
return buf
|
||||
}
|
||||
|
||||
foregroundBackground := strings.Split(style, ":")
|
||||
foreground := strings.Split(foregroundBackground[0], "+")
|
||||
fgKey := foreground[0]
|
||||
fg := Colors[fgKey]
|
||||
fgStyle := ""
|
||||
if len(foreground) > 1 {
|
||||
fgStyle = foreground[1]
|
||||
}
|
||||
|
||||
bg, bgStyle := "", ""
|
||||
|
||||
if len(foregroundBackground) > 1 {
|
||||
background := strings.Split(foregroundBackground[1], "+")
|
||||
bg = background[0]
|
||||
if len(background) > 1 {
|
||||
bgStyle = background[1]
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteString(start)
|
||||
base := normalIntensityFG
|
||||
if len(fgStyle) > 0 {
|
||||
if strings.Contains(fgStyle, "b") {
|
||||
buf.WriteString(bold)
|
||||
}
|
||||
if strings.Contains(fgStyle, "B") {
|
||||
buf.WriteString(blink)
|
||||
}
|
||||
if strings.Contains(fgStyle, "u") {
|
||||
buf.WriteString(underline)
|
||||
}
|
||||
if strings.Contains(fgStyle, "i") {
|
||||
buf.WriteString(inverse)
|
||||
}
|
||||
if strings.Contains(fgStyle, "s") {
|
||||
buf.WriteString(strikethrough)
|
||||
}
|
||||
if strings.Contains(fgStyle, "h") {
|
||||
base = highIntensityFG
|
||||
}
|
||||
}
|
||||
|
||||
// if 256-color
|
||||
n, err := strconv.Atoi(fgKey)
|
||||
if err == nil {
|
||||
fmt.Fprintf(buf, "38;5;%d;", n)
|
||||
} else {
|
||||
fmt.Fprintf(buf, "%d;", base+fg)
|
||||
}
|
||||
|
||||
base = normalIntensityBG
|
||||
if len(bg) > 0 {
|
||||
if strings.Contains(bgStyle, "h") {
|
||||
base = highIntensityBG
|
||||
}
|
||||
// if 256-color
|
||||
n, err := strconv.Atoi(bg)
|
||||
if err == nil {
|
||||
fmt.Fprintf(buf, "48;5;%d;", n)
|
||||
} else {
|
||||
fmt.Fprintf(buf, "%d;", base+Colors[bg])
|
||||
}
|
||||
}
|
||||
|
||||
// remove last ";"
|
||||
buf.Truncate(buf.Len() - 1)
|
||||
buf.WriteRune('m')
|
||||
return buf
|
||||
}
|
||||
|
||||
// Color colors a string based on the ANSI color code for style.
|
||||
func Color(s, style string) string {
|
||||
if plain || len(style) < 1 {
|
||||
return s
|
||||
}
|
||||
buf := colorCode(style)
|
||||
buf.WriteString(s)
|
||||
buf.WriteString(Reset)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// ColorFunc creates a closure to avoid computation ANSI color code.
|
||||
func ColorFunc(style string) func(string) string {
|
||||
if style == "" {
|
||||
return func(s string) string {
|
||||
return s
|
||||
}
|
||||
}
|
||||
color := ColorCode(style)
|
||||
return func(s string) string {
|
||||
if plain || s == "" {
|
||||
return s
|
||||
}
|
||||
buf := bytes.NewBufferString(color)
|
||||
buf.WriteString(s)
|
||||
buf.WriteString(Reset)
|
||||
result := buf.String()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
// DisableColors disables ANSI color codes. The default is false (colors are on).
|
||||
func DisableColors(disable bool) {
|
||||
plain = disable
|
||||
if plain {
|
||||
Black = ""
|
||||
Red = ""
|
||||
Green = ""
|
||||
Yellow = ""
|
||||
Blue = ""
|
||||
Magenta = ""
|
||||
Cyan = ""
|
||||
White = ""
|
||||
LightBlack = ""
|
||||
LightRed = ""
|
||||
LightGreen = ""
|
||||
LightYellow = ""
|
||||
LightBlue = ""
|
||||
LightMagenta = ""
|
||||
LightCyan = ""
|
||||
LightWhite = ""
|
||||
} else {
|
||||
Black = ColorCode("black")
|
||||
Red = ColorCode("red")
|
||||
Green = ColorCode("green")
|
||||
Yellow = ColorCode("yellow")
|
||||
Blue = ColorCode("blue")
|
||||
Magenta = ColorCode("magenta")
|
||||
Cyan = ColorCode("cyan")
|
||||
White = ColorCode("white")
|
||||
LightBlack = ColorCode("black+h")
|
||||
LightRed = ColorCode("red+h")
|
||||
LightGreen = ColorCode("green+h")
|
||||
LightYellow = ColorCode("yellow+h")
|
||||
LightBlue = ColorCode("blue+h")
|
||||
LightMagenta = ColorCode("magenta+h")
|
||||
LightCyan = ColorCode("cyan+h")
|
||||
LightWhite = ColorCode("white+h")
|
||||
}
|
||||
}
|
65
vendor/github.com/mgutz/ansi/doc.go
generated
vendored
65
vendor/github.com/mgutz/ansi/doc.go
generated
vendored
@ -1,65 +0,0 @@
|
||||
/*
|
||||
Package ansi is a small, fast library to create ANSI colored strings and codes.
|
||||
|
||||
Installation
|
||||
|
||||
# this installs the color viewer and the package
|
||||
go get -u github.com/mgutz/ansi/cmd/ansi-mgutz
|
||||
|
||||
Example
|
||||
|
||||
// colorize a string, SLOW
|
||||
msg := ansi.Color("foo", "red+b:white")
|
||||
|
||||
// create a closure to avoid recalculating ANSI code compilation
|
||||
phosphorize := ansi.ColorFunc("green+h:black")
|
||||
msg = phosphorize("Bring back the 80s!")
|
||||
msg2 := phospohorize("Look, I'm a CRT!")
|
||||
|
||||
// cache escape codes and build strings manually
|
||||
lime := ansi.ColorCode("green+h:black")
|
||||
reset := ansi.ColorCode("reset")
|
||||
|
||||
fmt.Println(lime, "Bring back the 80s!", reset)
|
||||
|
||||
Other examples
|
||||
|
||||
Color(s, "red") // red
|
||||
Color(s, "red+b") // red bold
|
||||
Color(s, "red+B") // red blinking
|
||||
Color(s, "red+u") // red underline
|
||||
Color(s, "red+bh") // red bold bright
|
||||
Color(s, "red:white") // red on white
|
||||
Color(s, "red+b:white+h") // red bold on white bright
|
||||
Color(s, "red+B:white+h") // red blink on white bright
|
||||
|
||||
To view color combinations, from terminal
|
||||
|
||||
ansi-mgutz
|
||||
|
||||
Style format
|
||||
|
||||
"foregroundColor+attributes:backgroundColor+attributes"
|
||||
|
||||
Colors
|
||||
|
||||
black
|
||||
red
|
||||
green
|
||||
yellow
|
||||
blue
|
||||
magenta
|
||||
cyan
|
||||
white
|
||||
|
||||
Attributes
|
||||
|
||||
b = bold foreground
|
||||
B = Blink foreground
|
||||
u = underline foreground
|
||||
h = high intensity (bright) foreground, background
|
||||
i = inverse
|
||||
|
||||
Wikipedia ANSI escape codes [Colors](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors)
|
||||
*/
|
||||
package ansi
|
57
vendor/github.com/mgutz/ansi/print.go
generated
vendored
57
vendor/github.com/mgutz/ansi/print.go
generated
vendored
@ -1,57 +0,0 @@
|
||||
package ansi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
colorable "github.com/mattn/go-colorable"
|
||||
)
|
||||
|
||||
// PrintStyles prints all style combinations to the terminal.
|
||||
func PrintStyles() {
|
||||
// for compatibility with Windows, not needed for *nix
|
||||
stdout := colorable.NewColorableStdout()
|
||||
|
||||
bgColors := []string{
|
||||
"",
|
||||
":black",
|
||||
":red",
|
||||
":green",
|
||||
":yellow",
|
||||
":blue",
|
||||
":magenta",
|
||||
":cyan",
|
||||
":white",
|
||||
}
|
||||
|
||||
keys := make([]string, 0, len(Colors))
|
||||
for k := range Colors {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
sort.Sort(sort.StringSlice(keys))
|
||||
|
||||
for _, fg := range keys {
|
||||
for _, bg := range bgColors {
|
||||
fmt.Fprintln(stdout, padColor(fg, []string{"" + bg, "+b" + bg, "+bh" + bg, "+u" + bg}))
|
||||
fmt.Fprintln(stdout, padColor(fg, []string{"+s" + bg, "+i" + bg}))
|
||||
fmt.Fprintln(stdout, padColor(fg, []string{"+uh" + bg, "+B" + bg, "+Bb" + bg /* backgrounds */, "" + bg + "+h"}))
|
||||
fmt.Fprintln(stdout, padColor(fg, []string{"+b" + bg + "+h", "+bh" + bg + "+h", "+u" + bg + "+h", "+uh" + bg + "+h"}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func pad(s string, length int) string {
|
||||
for len(s) < length {
|
||||
s += " "
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func padColor(color string, styles []string) string {
|
||||
buffer := ""
|
||||
for _, style := range styles {
|
||||
buffer += Color(pad(color+style, 20), color+style)
|
||||
}
|
||||
return buffer
|
||||
}
|
4
vendor/modules.txt
vendored
4
vendor/modules.txt
vendored
@ -41,12 +41,8 @@ github.com/dlclark/regexp2
|
||||
github.com/dlclark/regexp2/syntax
|
||||
# github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
|
||||
github.com/docopt/docopt-go
|
||||
# github.com/mattn/go-colorable v0.0.9
|
||||
github.com/mattn/go-colorable
|
||||
# github.com/mattn/go-isatty v0.0.12
|
||||
github.com/mattn/go-isatty
|
||||
# github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b
|
||||
github.com/mgutz/ansi
|
||||
# github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/mitchellh/go-homedir
|
||||
# golang.org/x/sys v0.0.0-20200116001909-b77594299b42
|
||||
|
Reference in New Issue
Block a user