diff --git a/Makefile b/Makefile index 78c0cc9..de88a77 100644 --- a/Makefile +++ b/Makefile @@ -136,6 +136,10 @@ man: vendor: $(GO) mod vendor && $(GO) mod tidy && $(GO) mod verify +## vendor-update: update vendored dependencies +vendor-update: + $(GO) get -t -u ./... + ## fmt: run go fmt .PHONY: fmt fmt: diff --git a/cmd/cheat/cmd_directories.go b/cmd/cheat/cmd_directories.go index 7b20e4c..eeadd36 100644 --- a/cmd/cheat/cmd_directories.go +++ b/cmd/cheat/cmd_directories.go @@ -27,5 +27,5 @@ func cmdDirectories(opts map[string]interface{}, conf config.Config) { // write columnized output to stdout w.Flush() - display.Display(out.String(), conf) + display.Write(out.String(), conf) } diff --git a/cmd/cheat/cmd_list.go b/cmd/cheat/cmd_list.go index 502fa80..a66b7f2 100644 --- a/cmd/cheat/cmd_list.go +++ b/cmd/cheat/cmd_list.go @@ -37,8 +37,8 @@ func cmdList(opts map[string]interface{}, conf config.Config) { // sheets with local sheets), here we simply want to create a slice // containing all sheets. flattened := []sheet.Sheet{} - for _, pathSheets := range cheatsheets { - for _, s := range pathSheets { + for _, pathsheets := range cheatsheets { + for _, s := range pathsheets { flattened = append(flattened, s) } } @@ -105,5 +105,5 @@ func cmdList(opts map[string]interface{}, conf config.Config) { // write columnized output to stdout w.Flush() - display.Display(out.String(), conf) + display.Write(out.String(), conf) } diff --git a/cmd/cheat/cmd_search.go b/cmd/cheat/cmd_search.go index 5ac1aa8..ed11954 100644 --- a/cmd/cheat/cmd_search.go +++ b/cmd/cheat/cmd_search.go @@ -8,7 +8,6 @@ import ( "github.com/cheat/cheat/internal/config" "github.com/cheat/cheat/internal/display" - "github.com/cheat/cheat/internal/sheet" "github.com/cheat/cheat/internal/sheets" ) @@ -32,71 +31,65 @@ func cmdSearch(opts map[string]interface{}, conf config.Config) { ) } - // consolidate the cheatsheets found on all paths into a single map of - // `title` => `sheet` (ie, allow more local cheatsheets to override less - // local cheatsheets) - consolidated := sheets.Consolidate(cheatsheets) - - // if was provided, search that single sheet only - if opts[""] != nil { - - cheatsheet := opts[""].(string) - - // assert that the cheatsheet exists - s, ok := consolidated[cheatsheet] - if !ok { - fmt.Printf("No cheatsheet found for '%s'.\n", cheatsheet) - os.Exit(2) - } - - consolidated = map[string]sheet.Sheet{ - cheatsheet: s, - } - } - - // sort the cheatsheets alphabetically, and search for matches + // iterate over each cheatpath out := "" - for _, sheet := range sheets.Sort(consolidated) { + for _, pathcheats := range cheatsheets { - // assume that we want to perform a case-insensitive search for - pattern := "(?i)" + phrase + // sort the cheatsheets alphabetically, and search for matches + for _, sheet := range sheets.Sort(pathcheats) { - // unless --regex is provided, in which case we pass the regex unaltered - if opts["--regex"] == true { - pattern = phrase - } + // if was provided, constrain the search only to + // matching cheatsheets + if opts[""] != nil && sheet.Title != opts[""] { + continue + } - // compile the regex - reg, err := regexp.Compile(pattern) - if err != nil { - fmt.Fprintln(os.Stderr, fmt.Sprintf("failed to compile regexp: %s, %v", pattern, err)) - os.Exit(1) - } + // assume that we want to perform a case-insensitive search for + pattern := "(?i)" + phrase - // `Search` will return text entries that match the search terms. We're - // using it here to overwrite the prior cheatsheet Text, filtering it to - // only what is relevant - sheet.Text = sheet.Search(reg) + // unless --regex is provided, in which case we pass the regex unaltered + if opts["--regex"] == true { + pattern = phrase + } - // if the sheet did not match the search, ignore it and move on - if sheet.Text == "" { - continue - } + // compile the regex + reg, err := regexp.Compile(pattern) + if err != nil { + fmt.Fprintln(os.Stderr, fmt.Sprintf("failed to compile regexp: %s, %v", pattern, err)) + os.Exit(1) + } - // if colorization was requested, apply it here - if conf.Color(opts) { - sheet.Colorize(conf) - } + // `Search` will return text entries that match the search terms. We're + // using it here to overwrite the prior cheatsheet Text, filtering it to + // only what is relevant + sheet.Text = sheet.Search(reg) - // output the cheatsheet title - out += fmt.Sprintf("%s:\n", sheet.Title) + // if the sheet did not match the search, ignore it and move on + if sheet.Text == "" { + continue + } - // indent each line of content with two spaces - for _, line := range strings.Split(sheet.Text, "\n") { - out += fmt.Sprintf(" %s\n", line) + // if colorization was requested, apply it here + if conf.Color(opts) { + sheet.Colorize(conf) + } + + // display the cheatsheet title and path + out += fmt.Sprintf("%s %s\n", + display.Underline(sheet.Title), + display.Faint(fmt.Sprintf("(%s)", sheet.CheatPath), conf), + ) + + // indent each line of content + out += display.Indent(sheet.Text) + "\n" } } + // trim superfluous newlines + out = strings.TrimSpace(out) + // display the output - display.Display(out, conf) + // NB: resist the temptation to call `display.Display` multiple times in + // the loop above. That will not play nicely with the paginator. + display.Write(out, conf) } diff --git a/cmd/cheat/cmd_tags.go b/cmd/cheat/cmd_tags.go index 3358bdd..6187d88 100644 --- a/cmd/cheat/cmd_tags.go +++ b/cmd/cheat/cmd_tags.go @@ -26,5 +26,5 @@ func cmdTags(opts map[string]interface{}, conf config.Config) { } // display the output - display.Display(out, conf) + display.Write(out, conf) } diff --git a/cmd/cheat/cmd_view.go b/cmd/cheat/cmd_view.go index 2f4c550..13b3c93 100644 --- a/cmd/cheat/cmd_view.go +++ b/cmd/cheat/cmd_view.go @@ -30,9 +30,39 @@ func cmdView(opts map[string]interface{}, conf config.Config) { ) } - // consolidate the cheatsheets found on all paths into a single map of - // `title` => `sheet` (ie, allow more local cheatsheets to override less - // local cheatsheets) + // if --all was passed, display cheatsheets from all cheatpaths + if opts["--all"].(bool) { + // iterate over the cheatpaths + out := "" + for _, cheatpath := range cheatsheets { + + // if the cheatpath contains the specified cheatsheet, display it + if sheet, ok := cheatpath[cheatsheet]; ok { + + // identify the matching cheatsheet + out += fmt.Sprintf("%s %s\n", + display.Underline(sheet.Title), + display.Faint(fmt.Sprintf("(%s)", sheet.CheatPath), conf), + ) + + // apply colorization if requested + if conf.Color(opts) { + sheet.Colorize(conf) + } + + // display the cheatsheet + out += display.Indent(sheet.Text) + "\n" + } + } + + // display and exit + display.Write(strings.TrimSuffix(out, "\n"), conf) + os.Exit(0) + } + + // otherwise, consolidate the cheatsheets found on all paths into a single + // map of `title` => `sheet` (ie, allow more local cheatsheets to override + // less local cheatsheets) consolidated := sheets.Consolidate(cheatsheets) // fail early if the requested cheatsheet does not exist @@ -48,5 +78,5 @@ func cmdView(opts map[string]interface{}, conf config.Config) { } // display the cheatsheet - display.Display(sheet.Text, conf) + display.Write(sheet.Text, conf) } diff --git a/cmd/cheat/docopt.txt b/cmd/cheat/docopt.txt index c841549..e12615e 100644 --- a/cmd/cheat/docopt.txt +++ b/cmd/cheat/docopt.txt @@ -3,11 +3,12 @@ Usage: Options: --init Write a default config file to stdout + -a --all Search among all cheatpaths -c --colorize Colorize output -d --directories List cheatsheet directories -e --edit= Edit -l --list List cheatsheets - -p --path= Return only sheets found on path + -p --path= Return only sheets found on cheatpath -r --regex Treat search as a regex -s --search= Search cheatsheets for -t --tag= Return only sheets matching diff --git a/cmd/cheat/main.go b/cmd/cheat/main.go index 0ba62a0..8f4ce37 100755 --- a/cmd/cheat/main.go +++ b/cmd/cheat/main.go @@ -5,7 +5,6 @@ package main import ( "fmt" "os" - "path" "runtime" "strings" @@ -17,7 +16,7 @@ import ( "github.com/cheat/cheat/internal/installer" ) -const version = "4.1.1" +const version = "4.2.0" func main() { @@ -74,62 +73,16 @@ func main() { os.Exit(0) } - // read the config template - configs := configs() - - // determine the appropriate paths for config data and (optional) community - // cheatsheets based on the user's platform + // choose a confpath confpath = confpaths[0] - confdir := path.Dir(confpath) - // create paths for community and personal cheatsheets - community := path.Join(confdir, "/cheatsheets/community") - personal := path.Join(confdir, "/cheatsheets/personal") - - // template the above paths into the default configs - configs = strings.Replace(configs, "COMMUNITY_PATH", community, -1) - configs = strings.Replace(configs, "PERSONAL_PATH", personal, -1) - - // prompt the user to download the community cheatsheets - yes, err = installer.Prompt( - "Would you like to download the community cheatsheets? [Y/n]", - true, - ) - if err != nil { - fmt.Fprintf(os.Stderr, "failed to create config: %v\n", err) - os.Exit(1) - } - - // clone the community cheatsheets if so instructed - if yes { - // clone the community cheatsheets - if err := installer.Clone(community); err != nil { - fmt.Fprintf(os.Stderr, "failed to create config: %v\n", err) - os.Exit(1) - } - - // also create a directory for personal cheatsheets - if err := os.MkdirAll(personal, os.ModePerm); err != nil { - fmt.Fprintf( - os.Stderr, - "failed to create config: failed to create directory: %s: %v\n", - personal, - err) - os.Exit(1) - } - } - - // the config file does not exist, so we'll try to create one - if err = config.Init(confpath, configs); err != nil { - fmt.Fprintf( - os.Stderr, - "failed to create config file: %s: %v\n", - confpath, - err, - ) + // run the installer + if err := installer.Run(configs(), confpath); err != nil { + fmt.Fprintf(os.Stderr, "failed to run installer: %v\n", err) os.Exit(1) } + // notify the user and exit fmt.Printf("Created config file: %s\n", confpath) fmt.Println("Please read this file for advanced configuration information.") os.Exit(0) diff --git a/cmd/cheat/str_usage.go b/cmd/cheat/str_usage.go index 86be7ea..0d69c57 100644 --- a/cmd/cheat/str_usage.go +++ b/cmd/cheat/str_usage.go @@ -12,11 +12,12 @@ func usage() string { Options: --init Write a default config file to stdout + -a --all Search among all cheatpaths -c --colorize Colorize output -d --directories List cheatsheet directories -e --edit= Edit -l --list List cheatsheets - -p --path= Return only sheets found on path + -p --path= Return only sheets found on cheatpath -r --regex Treat search as a regex -s --search= Search cheatsheets for -t --tag= Return only sheets matching diff --git a/go.mod b/go.mod index ac07047..1fd9289 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/cheat/cheat go 1.14 require ( - github.com/alecthomas/chroma v0.8.1 + github.com/alecthomas/chroma v0.8.2 github.com/davecgh/go-spew v1.1.1 github.com/dlclark/regexp2 v1.4.0 // indirect github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 @@ -12,8 +12,8 @@ require ( github.com/mitchellh/go-homedir v1.1.0 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/sergi/go-diff v1.1.0 // indirect - golang.org/x/sys v0.0.0-20201101102859-da207088b7d1 // indirect + golang.org/x/sys v0.0.0-20201126233918-771906719818 // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 - gopkg.in/yaml.v2 v2.3.0 + gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index b4a6ebc..3941e9e 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U= github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI= -github.com/alecthomas/chroma v0.8.1 h1:ym20sbvyC6RXz45u4qDglcgr8E313oPROshcuCHqiEE= -github.com/alecthomas/chroma v0.8.1/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM= +github.com/alecthomas/chroma v0.8.2 h1:x3zkuE2lUk/RIekyAJ3XRqSCP4zwWDfcw/YJCuCAACg= +github.com/alecthomas/chroma v0.8.2/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM= github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo= github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0= github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE= @@ -53,8 +53,8 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 h1:opSr2sbRXk5X5/givKrrKj9HXxFpW2sdCiP8MJSKLQY= golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201101102859-da207088b7d1 h1:a/mKvvZr9Jcc8oKfcmgzyp7OwF73JPWsQLvH1z2Kxck= -golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201126233918-771906719818 h1:f1CIuDlJhwANEC2MM87MBEVMr3jl5bifgsfj90XAF9c= +golang.org/x/sys v0.0.0-20201126233918-771906719818/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 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -64,5 +64,5 @@ gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 h1:POO/ycCATvegFmVuPpQzZFJ+p gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/internal/display/faint.go b/internal/display/faint.go new file mode 100644 index 0000000..aafdd27 --- /dev/null +++ b/internal/display/faint.go @@ -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 +} diff --git a/internal/display/faint_test.go b/internal/display/faint_test.go new file mode 100644 index 0000000..f590236 --- /dev/null +++ b/internal/display/faint_test.go @@ -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) + } +} diff --git a/internal/display/indent.go b/internal/display/indent.go new file mode 100644 index 0000000..9399879 --- /dev/null +++ b/internal/display/indent.go @@ -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 +} diff --git a/internal/display/indent_test.go b/internal/display/indent_test.go new file mode 100644 index 0000000..94b1ac9 --- /dev/null +++ b/internal/display/indent_test.go @@ -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) + } +} diff --git a/internal/display/underline.go b/internal/display/underline.go new file mode 100644 index 0000000..4ac914c --- /dev/null +++ b/internal/display/underline.go @@ -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)) +} diff --git a/internal/display/underline_test.go b/internal/display/underline_test.go new file mode 100644 index 0000000..e9743ee --- /dev/null +++ b/internal/display/underline_test.go @@ -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) + } +} diff --git a/internal/display/display.go b/internal/display/write.go similarity index 84% rename from internal/display/display.go rename to internal/display/write.go index d0930cd..c1bd2b4 100644 --- a/internal/display/display.go +++ b/internal/display/write.go @@ -9,9 +9,9 @@ import ( "github.com/cheat/cheat/internal/config" ) -// Display writes output either directly to stdout, or through a pager, +// Write writes output either directly to stdout, or through a pager, // depending upon configuration. -func Display(out string, conf config.Config) { +func Write(out string, conf config.Config) { // if no pager was configured, print the output to stdout and exit if conf.Pager == "" { fmt.Print(out) diff --git a/internal/installer/clone.go b/internal/installer/clone.go index ee005a2..1bc8c01 100644 --- a/internal/installer/clone.go +++ b/internal/installer/clone.go @@ -8,8 +8,8 @@ import ( const cloneURL = "https://github.com/cheat/cheatsheets.git" -// Clone clones the community cheatsheets -func Clone(path string) error { +// clone clones the community cheatsheets +func clone(path string) error { // perform the clone in a shell cmd := exec.Command("git", "clone", cloneURL, path) diff --git a/internal/installer/run.go b/internal/installer/run.go new file mode 100644 index 0000000..50267bf --- /dev/null +++ b/internal/installer/run.go @@ -0,0 +1,55 @@ +package installer + +import ( + "fmt" + "os" + "path" + "strings" + + "github.com/cheat/cheat/internal/config" +) + +// Run runs the installer +func Run(configs string, confpath string) error { + + // determine the appropriate paths for config data and (optional) community + // cheatsheets based on the user's platform + confdir := path.Dir(confpath) + + // create paths for community and personal cheatsheets + community := path.Join(confdir, "/cheatsheets/community") + personal := path.Join(confdir, "/cheatsheets/personal") + + // template the above paths into the default configs + configs = strings.Replace(configs, "COMMUNITY_PATH", community, -1) + configs = strings.Replace(configs, "PERSONAL_PATH", personal, -1) + + // prompt the user to download the community cheatsheets + yes, err := Prompt( + "Would you like to download the community cheatsheets? [Y/n]", + true, + ) + if err != nil { + return fmt.Errorf("failed to prompt: %v", err) + } + + // clone the community cheatsheets if so instructed + if yes { + // clone the community cheatsheets + if err := clone(community); err != nil { + return fmt.Errorf("failed to clone cheatsheets: %v", err) + } + + // also create a directory for personal cheatsheets + if err := os.MkdirAll(personal, os.ModePerm); err != nil { + return fmt.Errorf("failed to create directory: %v", err) + } + } + + // the config file does not exist, so we'll try to create one + if err = config.Init(confpath, configs); err != nil { + return fmt.Errorf("failed to create config file: %v", err) + } + + return nil +} diff --git a/internal/mock/path.go b/internal/mock/path.go index 3967155..d38ce5a 100644 --- a/internal/mock/path.go +++ b/internal/mock/path.go @@ -13,7 +13,7 @@ func Path(filename string) string { // determine the path of this file during runtime _, thisfile, _, _ := runtime.Caller(0) - // compute the config path + // compute the mock path file, err := filepath.Abs( path.Join( filepath.Dir(thisfile), @@ -22,7 +22,7 @@ func Path(filename string) string { ), ) if err != nil { - panic(fmt.Errorf("failed to resolve config path: %v", err)) + panic(fmt.Errorf("failed to resolve mock path: %v", err)) } return file diff --git a/internal/sheet/copy_test.go b/internal/sheet/copy_test.go index 63915dc..1cd868b 100644 --- a/internal/sheet/copy_test.go +++ b/internal/sheet/copy_test.go @@ -25,7 +25,7 @@ func TestCopyFlat(t *testing.T) { } // mock a cheatsheet struct - sheet, err := New("foo", src.Name(), []string{}, false) + sheet, err := New("foo", "community", src.Name(), []string{}, false) if err != nil { t.Errorf("failed to init cheatsheet: %v", err) } @@ -72,7 +72,13 @@ func TestCopyDeep(t *testing.T) { } // mock a cheatsheet struct - sheet, err := New("/cheat-tests/alpha/bravo/foo", src.Name(), []string{}, false) + sheet, err := New( + "/cheat-tests/alpha/bravo/foo", + "community", + src.Name(), + []string{}, + false, + ) if err != nil { t.Errorf("failed to init cheatsheet: %v", err) } diff --git a/internal/sheet/sheet.go b/internal/sheet/sheet.go index 9d6ade1..4471401 100644 --- a/internal/sheet/sheet.go +++ b/internal/sheet/sheet.go @@ -10,17 +10,19 @@ import ( // Sheet encapsulates sheet information type Sheet struct { - Title string - Path string - Text string - Tags []string - Syntax string - ReadOnly bool + Title string + CheatPath string + Path string + Text string + Tags []string + Syntax string + ReadOnly bool } // New initializes a new Sheet func New( title string, + cheatpath string, path string, tags []string, readOnly bool, @@ -46,11 +48,12 @@ func New( // initialize and return a sheet return Sheet{ - Title: title, - Path: path, - Text: text + "\n", - Tags: tags, - Syntax: fm.Syntax, - ReadOnly: readOnly, + Title: title, + CheatPath: cheatpath, + Path: path, + Text: text + "\n", + Tags: tags, + Syntax: fm.Syntax, + ReadOnly: readOnly, }, nil } diff --git a/internal/sheet/sheet_test.go b/internal/sheet/sheet_test.go index 6ab3ad2..fd69eb1 100644 --- a/internal/sheet/sheet_test.go +++ b/internal/sheet/sheet_test.go @@ -13,6 +13,7 @@ func TestSheetSuccess(t *testing.T) { // initialize a sheet sheet, err := New( "foo", + "community", mock.Path("sheet/foo"), []string{"alpha", "bravo"}, false, @@ -61,6 +62,7 @@ func TestSheetFailure(t *testing.T) { // initialize a sheet _, err := New( "foo", + "community", mock.Path("/does-not-exist"), []string{"alpha", "bravo"}, false, @@ -77,6 +79,7 @@ func TestSheetFrontMatterFailure(t *testing.T) { // initialize a sheet _, err := New( "foo", + "community", mock.Path("sheet/bad-fm"), []string{"alpha", "bravo"}, false, diff --git a/internal/sheets/load.go b/internal/sheets/load.go index 9ea85fb..409f505 100644 --- a/internal/sheets/load.go +++ b/internal/sheets/load.go @@ -59,7 +59,13 @@ func Load(cheatpaths []cp.Cheatpath) ([]map[string]sheet.Sheet, error) { } // parse the cheatsheet file into a `sheet` struct - s, err := sheet.New(title, path, cheatpath.Tags, cheatpath.ReadOnly) + s, err := sheet.New( + title, + cheatpath.Name, + path, + cheatpath.Tags, + cheatpath.ReadOnly, + ) if err != nil { return fmt.Errorf( "failed to load sheet: %s, path: %s, err: %v", diff --git a/internal/sheets/load_test.go b/internal/sheets/load_test.go index 5147c09..762e2f2 100644 --- a/internal/sheets/load_test.go +++ b/internal/sheets/load_test.go @@ -1,3 +1,62 @@ package sheets -// TODO +import ( + "path" + "testing" + + "github.com/cheat/cheat/internal/cheatpath" + "github.com/cheat/cheat/internal/mock" +) + +// TestLoad asserts that sheets on valid cheatpaths can be loaded successfully +func TestLoad(t *testing.T) { + + // mock cheatpaths + cheatpaths := []cheatpath.Cheatpath{ + { + Name: "community", + Path: path.Join(mock.Path("cheatsheets"), "community"), + ReadOnly: true, + }, + { + Name: "personal", + Path: path.Join(mock.Path("cheatsheets"), "personal"), + ReadOnly: false, + }, + } + + // load cheatsheets + sheets, err := Load(cheatpaths) + if err != nil { + t.Errorf("failed to load cheatsheets: %v", err) + } + + // assert that the correct number of sheets loaded + // (sheet load details are tested in `sheet_test.go`) + want := 4 + if len(sheets) != want { + t.Errorf( + "failed to load correct number of cheatsheets: want: %d, got: %d", + want, + len(sheets), + ) + } +} + +// TestLoadBadPath asserts that an error is returned if a cheatpath is invalid +func TestLoadBadPath(t *testing.T) { + + // mock a bad cheatpath + cheatpaths := []cheatpath.Cheatpath{ + { + Name: "badpath", + Path: "/cheat/test/path/does/not/exist", + ReadOnly: true, + }, + } + + // attempt to load the cheatpath + if _, err := Load(cheatpaths); err == nil { + t.Errorf("failed to reject invalid cheatpath") + } +} diff --git a/mocks/cheatsheets/community/.hiddenfile b/mocks/cheatsheets/community/.hiddenfile new file mode 100644 index 0000000..e69de29 diff --git a/mocks/cheatsheets/community/bar b/mocks/cheatsheets/community/bar new file mode 100644 index 0000000..4792bbc --- /dev/null +++ b/mocks/cheatsheets/community/bar @@ -0,0 +1,4 @@ +--- +tags: [ community ] +--- +This is the bar cheatsheet. diff --git a/mocks/cheatsheets/community/foo b/mocks/cheatsheets/community/foo new file mode 100644 index 0000000..330cbc5 --- /dev/null +++ b/mocks/cheatsheets/community/foo @@ -0,0 +1,4 @@ +--- +tags: [ community ] +--- +This is the foo cheatsheet. diff --git a/mocks/cheatsheets/personal/bat b/mocks/cheatsheets/personal/bat new file mode 100644 index 0000000..fa2a841 --- /dev/null +++ b/mocks/cheatsheets/personal/bat @@ -0,0 +1,4 @@ +--- +tags: [ personal ] +--- +This is the bat cheatsheet. diff --git a/mocks/cheatsheets/personal/baz b/mocks/cheatsheets/personal/baz new file mode 100644 index 0000000..833264b --- /dev/null +++ b/mocks/cheatsheets/personal/baz @@ -0,0 +1,4 @@ +--- +tags: [ personal ] +--- +This is the baz cheatsheet. diff --git a/vendor/github.com/alecthomas/chroma/.goreleaser.yml b/vendor/github.com/alecthomas/chroma/.goreleaser.yml index 99d13e3..f8abfdd 100644 --- a/vendor/github.com/alecthomas/chroma/.goreleaser.yml +++ b/vendor/github.com/alecthomas/chroma/.goreleaser.yml @@ -6,6 +6,8 @@ release: brews: - install: bin.install "chroma" +env: + - CGO_ENABLED=0 builds: - goos: - linux diff --git a/vendor/github.com/alecthomas/chroma/.travis.yml b/vendor/github.com/alecthomas/chroma/.travis.yml deleted file mode 100644 index 4850b0c..0000000 --- a/vendor/github.com/alecthomas/chroma/.travis.yml +++ /dev/null @@ -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.26.0 - - ./bin/golangci-lint run - - git clean -fdx . -after_success: - curl -sL https://git.io/goreleaser | bash && goreleaser - diff --git a/vendor/github.com/alecthomas/chroma/README.md b/vendor/github.com/alecthomas/chroma/README.md index 490adea..42af02e 100644 --- a/vendor/github.com/alecthomas/chroma/README.md +++ b/vendor/github.com/alecthomas/chroma/README.md @@ -1,4 +1,4 @@ -# Chroma — A general purpose syntax highlighter in pure Go [![Golang Documentation](https://godoc.org/github.com/alecthomas/chroma?status.svg)](https://godoc.org/github.com/alecthomas/chroma) [![Build Status](https://travis-ci.org/alecthomas/chroma.svg)](https://travis-ci.org/alecthomas/chroma) [![Gitter chat](https://badges.gitter.im/alecthomas.svg)](https://gitter.im/alecthomas/Lobby) +# Chroma — A general purpose syntax highlighter in pure Go [![Golang Documentation](https://godoc.org/github.com/alecthomas/chroma?status.svg)](https://godoc.org/github.com/alecthomas/chroma) [![CircleCI](https://img.shields.io/circleci/project/github/alecthomas/chroma.svg)](https://circleci.com/gh/alecthomas/chroma) [![Go Report Card](https://goreportcard.com/badge/github.com/alecthomas/chroma)](https://goreportcard.com/report/github.com/alecthomas/chroma) [![Slack chat](https://img.shields.io/static/v1?logo=slack&style=flat&label=slack&color=green&message=gophers)](https://gophers.slack.com/messages/CN9DS8YF3) > **NOTE:** As Chroma has just been released, its API is still in flux. That said, the high-level interface should not change significantly. @@ -36,29 +36,30 @@ translators for Pygments lexers and styles. Prefix | Language :----: | -------- A | ABAP, ABNF, ActionScript, ActionScript 3, Ada, Angular2, ANTLR, ApacheConf, APL, AppleScript, Arduino, Awk -B | Ballerina, Base Makefile, Bash, Batchfile, BlitzBasic, BNF, Brainfuck -C | C, C#, C++, Cap'n Proto, Cassandra CQL, Ceylon, CFEngine3, cfstatement, ChaiScript, Cheetah, Clojure, CMake, COBOL, CoffeeScript, Common Lisp, Coq, Crystal, CSS, Cython +B | Ballerina, Base Makefile, Bash, Batchfile, BibTeX, BlitzBasic, BNF, Brainfuck +C | C, C#, C++, Caddyfile, Caddyfile Directives, Cap'n Proto, Cassandra CQL, Ceylon, CFEngine3, cfstatement, ChaiScript, Cheetah, Clojure, CMake, COBOL, CoffeeScript, Common Lisp, Coq, Crystal, CSS, Cython D | D, Dart, Diff, Django/Jinja, Docker, DTD E | EBNF, Elixir, Elm, EmacsLisp, Erlang F | Factor, Fish, Forth, Fortran, FSharp -G | GAS, GDScript, Genshi, Genshi HTML, Genshi Text, GLSL, Gnuplot, Go, Go HTML Template, Go Text Template, GraphQL, Groovy -H | Handlebars, Haskell, Haxe, HCL, Hexdump, HTML, HTTP, Hy -I | Idris, INI, Io +G | GAS, GDScript, Genshi, Genshi HTML, Genshi Text, Gherkin, GLSL, Gnuplot, Go, Go HTML Template, Go Text Template, GraphQL, Groovy +H | Handlebars, Haskell, Haxe, HCL, Hexdump, HLB, HTML, HTTP, Hy +I | Idris, Igor, INI, Io J | J, Java, JavaScript, JSON, Julia, Jungle K | Kotlin L | Lighttpd configuration file, LLVM, Lua M | Mako, markdown, Mason, Mathematica, Matlab, MiniZinc, MLIR, Modula-2, MonkeyC, MorrowindScript, Myghty, MySQL N | NASM, Newspeak, Nginx configuration file, Nim, Nix O | Objective-C, OCaml, Octave, OpenSCAD, Org Mode -P | PacmanConf, Perl, PHP, Pig, PkgConfig, PL/pgSQL, plaintext, PostgreSQL SQL dialect, PostScript, POVRay, PowerShell, Prolog, Protocol Buffer, Puppet, Python, Python 3 +P | PacmanConf, Perl, PHP, PHTML, Pig, PkgConfig, PL/pgSQL, plaintext, Pony, PostgreSQL SQL dialect, PostScript, POVRay, PowerShell, Prolog, PromQL, Protocol Buffer, Puppet, Python, Python 3 Q | QBasic -R | R, Racket, Ragel, react, reg, reStructuredText, Rexx, Ruby, Rust -S | Sass, Scala, Scheme, Scilab, SCSS, Smalltalk, Smarty, SML, Snobol, Solidity, SPARQL, SQL, SquidConf, Swift, SYSTEMD, systemverilog +R | R, Racket, Ragel, react, ReasonML, reg, reStructuredText, Rexx, Ruby, Rust +S | SAS, Sass, Scala, Scheme, Scilab, SCSS, Smalltalk, Smarty, Snobol, Solidity, SPARQL, SQL, SquidConf, Standard ML, Stylus, Swift, SYSTEMD, systemverilog T | TableGen, TASM, Tcl, Tcsh, Termcap, Terminfo, Terraform, TeX, Thrift, TOML, TradingView, Transact-SQL, Turing, Turtle, Twig, TypeScript, TypoScript, TypoScriptCssData, TypoScriptHtmlData V | VB.net, verilog, VHDL, VimL, vue W | WDTE X | XML, Xorg -Y | YAML +Y | YAML, YANG +Z | Zig _I will attempt to keep this section up to date, but an authoritative list can be @@ -183,7 +184,7 @@ following constructor options: - `ClassPrefix(prefix)` - prefix each generated CSS class. - `TabWidth(width)` - Set the rendered tab width, in characters. - `WithLineNumbers()` - Render line numbers (style with `LineNumbers`). -- `LinkableLineNumbers()` - Make the line numbers linkable. +- `LinkableLineNumbers()` - Make the line numbers linkable and be a link to themselves. - `HighlightLines(ranges)` - Highlight lines in these ranges (style with `LineHighlight`). - `LineNumbersInTable()` - Use a table for formatting line numbers and code, rather than spans. diff --git a/vendor/github.com/alecthomas/chroma/formatters/html/html.go b/vendor/github.com/alecthomas/chroma/formatters/html/html.go index ad48da1..a0854af 100644 --- a/vendor/github.com/alecthomas/chroma/formatters/html/html.go +++ b/vendor/github.com/alecthomas/chroma/formatters/html/html.go @@ -211,7 +211,7 @@ func (f *Formatter) writeHTML(w io.Writer, style *chroma.Style, tokens []chroma. fmt.Fprintf(w, "", f.styleAttr(css, chroma.LineHighlight)) } - fmt.Fprintf(w, "%*d\n", f.styleAttr(css, chroma.LineNumbersTable), f.lineIDAttribute(line), lineDigits, line) + fmt.Fprintf(w, "%s\n", f.styleAttr(css, chroma.LineNumbersTable), f.lineIDAttribute(line), f.lineTitleWithLinkIfNeeded(lineDigits, line)) if highlight { fmt.Fprintf(w, "") @@ -237,7 +237,7 @@ func (f *Formatter) writeHTML(w io.Writer, style *chroma.Style, tokens []chroma. } if f.lineNumbers && !wrapInTable { - fmt.Fprintf(w, "%*d", f.styleAttr(css, chroma.LineNumbers), f.lineIDAttribute(line), lineDigits, line) + fmt.Fprintf(w, "%s", f.styleAttr(css, chroma.LineNumbers), f.lineIDAttribute(line), f.lineTitleWithLinkIfNeeded(lineDigits, line)) } for _, token := range tokens { @@ -272,7 +272,19 @@ func (f *Formatter) lineIDAttribute(line int) string { if !f.linkableLineNumbers { return "" } - return fmt.Sprintf(" id=\"%s%d\"", f.lineNumbersIDPrefix, line) + return fmt.Sprintf(" id=\"%s\"", f.lineID(line)) +} + +func (f *Formatter) lineTitleWithLinkIfNeeded(lineDigits, line int) string { + title := fmt.Sprintf("%*d", lineDigits, line) + if !f.linkableLineNumbers { + return title + } + return fmt.Sprintf("%s", 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) { diff --git a/vendor/github.com/alecthomas/chroma/lexers/b/bash.go b/vendor/github.com/alecthomas/chroma/lexers/b/bash.go index 33f6cd8..7eac38e 100644 --- a/vendor/github.com/alecthomas/chroma/lexers/b/bash.go +++ b/vendor/github.com/alecthomas/chroma/lexers/b/bash.go @@ -14,7 +14,7 @@ var Bash = internal.Register(MustNewLexer( &Config{ Name: "Bash", Aliases: []string{"bash", "sh", "ksh", "zsh", "shell"}, - Filenames: []string{"*.sh", "*.ksh", "*.bash", "*.ebuild", "*.eclass", "*.exheres-0", "*.exlib", "*.zsh", "*.zshrc", ".bashrc", "bashrc", ".bash_*", "bash_*", "zshrc", ".zshrc", "PKGBUILD"}, + Filenames: []string{"*.sh", "*.ksh", "*.bash", "*.ebuild", "*.eclass", ".env", "*.env", "*.exheres-0", "*.exlib", "*.zsh", "*.zshrc", ".bashrc", "bashrc", ".bash_*", "bash_*", "zshrc", ".zshrc", "PKGBUILD"}, MimeTypes: []string{"application/x-sh", "application/x-shellscript"}, }, Rules{ diff --git a/vendor/github.com/alecthomas/chroma/lexers/g/go.go b/vendor/github.com/alecthomas/chroma/lexers/g/go.go index 33077e0..8eced07 100644 --- a/vendor/github.com/alecthomas/chroma/lexers/g/go.go +++ b/vendor/github.com/alecthomas/chroma/lexers/g/go.go @@ -60,13 +60,13 @@ var Go = internal.Register(MustNewLexer( var goTemplateRules = Rules{ "root": { + {`{{(- )?/\*(.|\n)*?\*/( -)?}}`, CommentMultiline, nil}, {`{{[-]?`, CommentPreproc, Push("template")}, {`[^{]+`, Other, nil}, {`{`, Other, nil}, }, "template": { {`[-]?}}`, CommentPreproc, Pop(1)}, - {`/\*.*?\*/`, Comment, nil}, {`(?=}})`, CommentPreproc, Pop(1)}, // Terminate the pipeline {`\(`, Operator, Push("subexpression")}, {`"(\\\\|\\"|[^"])*"`, LiteralString, nil}, @@ -80,19 +80,19 @@ var goTemplateRules = Rules{ {`\s+`, Whitespace, nil}, {`\(`, Operator, Push("subexpression")}, {`(range|if|else|while|with|template|end|true|false|nil|and|call|html|index|js|len|not|or|print|printf|println|urlquery|eq|ne|lt|le|gt|ge)\b`, Keyword, nil}, - {`\||:=`, Operator, nil}, + {`\||:?=|,`, Operator, nil}, {`[$]?[^\W\d]\w*`, NameOther, nil}, {`[$]?\.(?:[^\W\d]\w*)?`, NameAttribute, nil}, {`"(\\\\|\\"|[^"])*"`, LiteralString, nil}, - {`\d+i`, LiteralNumber, nil}, - {`\d+\.\d*([Ee][-+]\d+)?i`, LiteralNumber, nil}, + {`-?\d+i`, LiteralNumber, nil}, + {`-?\d+\.\d*([Ee][-+]\d+)?i`, LiteralNumber, nil}, {`\.\d+([Ee][-+]\d+)?i`, LiteralNumber, nil}, - {`\d+[Ee][-+]\d+i`, LiteralNumber, nil}, - {`\d+(\.\d+[eE][+\-]?\d+|\.\d*|[eE][+\-]?\d+)`, LiteralNumberFloat, nil}, - {`\.\d+([eE][+\-]?\d+)?`, LiteralNumberFloat, nil}, - {`0[0-7]+`, LiteralNumberOct, nil}, - {`0[xX][0-9a-fA-F]+`, LiteralNumberHex, nil}, - {`(0|[1-9][0-9]*)`, LiteralNumberInteger, nil}, + {`-?\d+[Ee][-+]\d+i`, LiteralNumber, nil}, + {`-?\d+(\.\d+[eE][+\-]?\d+|\.\d*|[eE][+\-]?\d+)`, LiteralNumberFloat, nil}, + {`-?\.\d+([eE][+\-]?\d+)?`, LiteralNumberFloat, nil}, + {`-?0[0-7]+`, LiteralNumberOct, nil}, + {`-?0[xX][0-9a-fA-F]+`, LiteralNumberHex, nil}, + {`-?(0|[1-9][0-9]*)`, LiteralNumberInteger, nil}, {`'(\\['"\\abfnrtv]|\\x[0-9a-fA-F]{2}|\\[0-7]{1,3}|\\u[0-9a-fA-F]{4}|\\U[0-9a-fA-F]{8}|[^\\])'`, LiteralStringChar, nil}, {"`[^`]*`", LiteralString, nil}, }, diff --git a/vendor/github.com/alecthomas/chroma/lexers/j/javascript.go b/vendor/github.com/alecthomas/chroma/lexers/j/javascript.go index a50cb24..ffa20c3 100644 --- a/vendor/github.com/alecthomas/chroma/lexers/j/javascript.go +++ b/vendor/github.com/alecthomas/chroma/lexers/j/javascript.go @@ -49,6 +49,7 @@ var JavascriptRules = Rules{ {"`", LiteralStringBacktick, Pop(1)}, {`\\\\`, LiteralStringBacktick, nil}, {"\\\\`", LiteralStringBacktick, nil}, + {"\\\\[^`\\\\]", LiteralStringBacktick, nil}, {`\$\{`, LiteralStringInterpol, Push("interp-inside")}, {`\$`, LiteralStringBacktick, nil}, {"[^`\\\\$]+", LiteralStringBacktick, nil}, diff --git a/vendor/github.com/alecthomas/chroma/lexers/p/promql.go b/vendor/github.com/alecthomas/chroma/lexers/p/promql.go new file mode 100644 index 0000000..38982e1 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/lexers/p/promql.go @@ -0,0 +1,55 @@ +package p + +import ( + . "github.com/alecthomas/chroma" // nolint + "github.com/alecthomas/chroma/lexers/internal" +) + +// Promql lexer. +var Promql = internal.Register(MustNewLexer( + &Config{ + Name: "PromQL", + Aliases: []string{"promql"}, + Filenames: []string{"*.promql"}, + MimeTypes: []string{}, + }, + Rules{ + "root": { + {`\n`, TextWhitespace, nil}, + {`\s+`, TextWhitespace, nil}, + {`,`, Punctuation, nil}, + {Words(``, `\b`, `bool`, `by`, `group_left`, `group_right`, `ignoring`, `offset`, `on`, `without`), Keyword, nil}, + {Words(``, `\b`, `sum`, `min`, `max`, `avg`, `group`, `stddev`, `stdvar`, `count`, `count_values`, `bottomk`, `topk`, `quantile`), Keyword, nil}, + {Words(``, `\b`, `abs`, `absent`, `absent_over_time`, `avg_over_time`, `ceil`, `changes`, `clamp_max`, `clamp_min`, `count_over_time`, `day_of_month`, `day_of_week`, `days_in_month`, `delta`, `deriv`, `exp`, `floor`, `histogram_quantile`, `holt_winters`, `hour`, `idelta`, `increase`, `irate`, `label_join`, `label_replace`, `ln`, `log10`, `log2`, `max_over_time`, `min_over_time`, `minute`, `month`, `predict_linear`, `quantile_over_time`, `rate`, `resets`, `round`, `scalar`, `sort`, `sort_desc`, `sqrt`, `stddev_over_time`, `stdvar_over_time`, `sum_over_time`, `time`, `timestamp`, `vector`, `year`), KeywordReserved, nil}, + {`[1-9][0-9]*[smhdwy]`, LiteralString, nil}, + {`-?[0-9]+\.[0-9]+`, LiteralNumberFloat, nil}, + {`-?[0-9]+`, LiteralNumberInteger, nil}, + {`#.*?$`, CommentSingle, nil}, + {`(\+|\-|\*|\/|\%|\^)`, Operator, nil}, + {`==|!=|>=|<=|<|>`, Operator, nil}, + {`and|or|unless`, OperatorWord, nil}, + {`[_a-zA-Z][a-zA-Z0-9_]+`, NameVariable, nil}, + {`(["\'])(.*?)(["\'])`, ByGroups(Punctuation, LiteralString, Punctuation), nil}, + {`\(`, Operator, Push("function")}, + {`\)`, Operator, nil}, + {`\{`, Punctuation, Push("labels")}, + {`\[`, Punctuation, Push("range")}, + }, + "labels": { + {`\}`, Punctuation, Pop(1)}, + {`\n`, TextWhitespace, nil}, + {`\s+`, TextWhitespace, nil}, + {`,`, Punctuation, nil}, + {`([_a-zA-Z][a-zA-Z0-9_]*?)(\s*?)(=~|!=|=|~!)(\s*?)(")(.*?)(")`, ByGroups(NameLabel, TextWhitespace, Operator, TextWhitespace, Punctuation, LiteralString, Punctuation), nil}, + }, + "range": { + {`\]`, Punctuation, Pop(1)}, + {`[1-9][0-9]*[smhdwy]`, LiteralString, nil}, + }, + "function": { + {`\)`, Operator, Pop(1)}, + {`\(`, Operator, Push()}, + Default(Pop(1)), + }, + }, +)) diff --git a/vendor/github.com/alecthomas/chroma/lexers/qml.go b/vendor/github.com/alecthomas/chroma/lexers/qml.go new file mode 100644 index 0000000..9d2f2fb --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/lexers/qml.go @@ -0,0 +1,54 @@ +package lexers + +import ( + . "github.com/alecthomas/chroma" // nolint + "github.com/alecthomas/chroma/lexers/internal" +) + +// Qml lexer. +var Qml = internal.Register(MustNewLexer( + &Config{ + Name: "QML", + Aliases: []string{"qml", "qbs"}, + Filenames: []string{"*.qml", "*.qbs"}, + MimeTypes: []string{"application/x-qml", "application/x-qt.qbs+qml"}, + DotAll: true, + }, + Rules{ + "commentsandwhitespace": { + {`\s+`, Text, nil}, + {`