mirror of
https://github.com/cheat/cheat.git
synced 2025-09-01 17:48:30 +02:00
Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
e2920bd922 | |||
973a1f59ea | |||
3afea0972c | |||
f86633ca1c | |||
a01a3491a4 | |||
daa43d3867 | |||
e94a1e22df | |||
5046975a0f | |||
198156a299 | |||
a7067279df | |||
a8e6fdb18a | |||
bbfa4efdb7 | |||
741ad91389 | |||
573d43a7e6 | |||
879e8f2be4 | |||
eab3c14f1f | |||
9a6130b6b7 | |||
aeaf01e1de |
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
@ -45,6 +46,39 @@ func cmdList(opts map[string]interface{}, conf config.Config) {
|
|||||||
return flattened[i].Title < flattened[j].Title
|
return flattened[i].Title < flattened[j].Title
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// filter if <cheatsheet> was specified
|
||||||
|
// NB: our docopt specification is misleading here. When used in conjunction
|
||||||
|
// with `-l`, `<cheatsheet>` is really a pattern against which to filter
|
||||||
|
// sheet titles.
|
||||||
|
if opts["<cheatsheet>"] != nil {
|
||||||
|
|
||||||
|
// initialize a slice of filtered sheets
|
||||||
|
filtered := []sheet.Sheet{}
|
||||||
|
|
||||||
|
// initialize our filter pattern
|
||||||
|
pattern := "(?i)" + opts["<cheatsheet>"].(string)
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// iterate over each cheatsheet, and pass-through those which match the
|
||||||
|
// filter pattern
|
||||||
|
for _, s := range flattened {
|
||||||
|
if reg.MatchString(s.Title) {
|
||||||
|
filtered = append(filtered, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flattened = filtered
|
||||||
|
}
|
||||||
|
|
||||||
// exit early if no cheatsheets are available
|
// exit early if no cheatsheets are available
|
||||||
if len(flattened) == 0 {
|
if len(flattened) == 0 {
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
|
55
cmd/cheat/cmd_remove.go
Normal file
55
cmd/cheat/cmd_remove.go
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/cheat/cheat/internal/config"
|
||||||
|
"github.com/cheat/cheat/internal/sheets"
|
||||||
|
)
|
||||||
|
|
||||||
|
// cmdRemove opens a cheatsheet for editing (or creates it if it doesn't exist).
|
||||||
|
func cmdRemove(opts map[string]interface{}, conf config.Config) {
|
||||||
|
|
||||||
|
cheatsheet := opts["--rm"].(string)
|
||||||
|
|
||||||
|
// load the cheatsheets
|
||||||
|
cheatsheets, err := sheets.Load(conf.Cheatpaths)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, fmt.Sprintf("failed to list cheatsheets: %v", err))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// filter cheatcheats by tag if --tag was provided
|
||||||
|
if opts["--tag"] != nil {
|
||||||
|
cheatsheets = sheets.Filter(
|
||||||
|
cheatsheets,
|
||||||
|
strings.Split(opts["--tag"].(string), ","),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
sheet, ok := consolidated[cheatsheet]
|
||||||
|
if !ok {
|
||||||
|
fmt.Fprintln(os.Stderr, fmt.Sprintf("no cheatsheet found for '%s'.\n", cheatsheet))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// fail early if the sheet is read-only
|
||||||
|
if sheet.ReadOnly {
|
||||||
|
fmt.Fprintln(os.Stderr, fmt.Sprintf("cheatsheet '%s' is read-only.", cheatsheet))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, attempt to delete the sheet
|
||||||
|
if err := os.Remove(sheet.Path); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, fmt.Sprintf("failed to delete sheet: %s, %v", sheet.Title, err))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
@ -38,12 +38,6 @@ func cmdSearch(opts map[string]interface{}, conf config.Config) {
|
|||||||
// sort the cheatsheets alphabetically, and search for matches
|
// sort the cheatsheets alphabetically, and search for matches
|
||||||
for _, sheet := range sheets.Sort(consolidated) {
|
for _, sheet := range sheets.Sort(consolidated) {
|
||||||
|
|
||||||
// colorize output?
|
|
||||||
colorize := false
|
|
||||||
if conf.Colorize == true || opts["--colorize"] == true {
|
|
||||||
colorize = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// assume that we want to perform a case-insensitive search for <phrase>
|
// assume that we want to perform a case-insensitive search for <phrase>
|
||||||
pattern := "(?i)" + phrase
|
pattern := "(?i)" + phrase
|
||||||
|
|
||||||
@ -55,12 +49,12 @@ func cmdSearch(opts map[string]interface{}, conf config.Config) {
|
|||||||
// compile the regex
|
// compile the regex
|
||||||
reg, err := regexp.Compile(pattern)
|
reg, err := regexp.Compile(pattern)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Errorf("failed to compile regexp: %s, %v", pattern, err)
|
fmt.Fprintln(os.Stderr, fmt.Sprintf("failed to compile regexp: %s, %v", pattern, err))
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// search the sheet
|
// search the sheet
|
||||||
matches := sheet.Search(reg, colorize)
|
matches := sheet.Search(reg, conf.Color(opts))
|
||||||
|
|
||||||
// display the results
|
// display the results
|
||||||
if len(matches) > 0 {
|
if len(matches) > 0 {
|
||||||
|
25
cmd/cheat/cmd_tags.go
Normal file
25
cmd/cheat/cmd_tags.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/cheat/cheat/internal/config"
|
||||||
|
"github.com/cheat/cheat/internal/sheets"
|
||||||
|
)
|
||||||
|
|
||||||
|
// cmdTags lists all tags in use.
|
||||||
|
func cmdTags(opts map[string]interface{}, conf config.Config) {
|
||||||
|
|
||||||
|
// load the cheatsheets
|
||||||
|
cheatsheets, err := sheets.Load(conf.Cheatpaths)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, fmt.Sprintf("failed to list cheatsheets: %v", err))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// write sheet tags to stdout
|
||||||
|
for _, tag := range sheets.Tags(cheatsheets) {
|
||||||
|
fmt.Println(tag)
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/chroma/quick"
|
"github.com/alecthomas/chroma/quick"
|
||||||
"github.com/mattn/go-isatty"
|
|
||||||
|
|
||||||
"github.com/cheat/cheat/internal/config"
|
"github.com/cheat/cheat/internal/config"
|
||||||
"github.com/cheat/cheat/internal/sheets"
|
"github.com/cheat/cheat/internal/sheets"
|
||||||
@ -44,20 +43,7 @@ func cmdView(opts map[string]interface{}, conf config.Config) {
|
|||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply colorization if so configured ...
|
if !conf.Color(opts) {
|
||||||
colorize := conf.Colorize
|
|
||||||
|
|
||||||
// ... or if --colorized were passed ...
|
|
||||||
if opts["--colorize"] == true {
|
|
||||||
colorize = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// ... unless we're outputting to a non-TTY
|
|
||||||
if !isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd()) {
|
|
||||||
colorize = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if !colorize {
|
|
||||||
fmt.Print(sheet.Text)
|
fmt.Print(sheet.Text)
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,15 @@ Options:
|
|||||||
--init Write a default config file to stdout
|
--init Write a default config file to stdout
|
||||||
-c --colorize Colorize output
|
-c --colorize Colorize output
|
||||||
-d --directories List cheatsheet directories
|
-d --directories List cheatsheet directories
|
||||||
-e --edit=<sheet> Edit cheatsheet
|
-e --edit=<sheet> Edit <sheet>
|
||||||
-l --list List cheatsheets
|
-l --list List cheatsheets
|
||||||
-p --path=<name> Return only sheets found on path <name>
|
-p --path=<name> Return only sheets found on path <name>
|
||||||
-r --regex Treat search <phrase> as a regex
|
-r --regex Treat search <phrase> as a regex
|
||||||
-s --search=<phrase> Search cheatsheets for <phrase>
|
-s --search=<phrase> Search cheatsheets for <phrase>
|
||||||
-t --tag=<tag> Return only sheets matching <tag>
|
-t --tag=<tag> Return only sheets matching <tag>
|
||||||
|
-T --tags List all tags in use
|
||||||
-v --version Print the version number
|
-v --version Print the version number
|
||||||
|
--rm=<sheet> Remove (delete) <sheet>
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
@ -33,6 +35,12 @@ Examples:
|
|||||||
To list all available cheatsheets:
|
To list all available cheatsheets:
|
||||||
cheat -l
|
cheat -l
|
||||||
|
|
||||||
|
To list all cheatsheets whose titles match "apt":
|
||||||
|
cheat -l apt
|
||||||
|
|
||||||
|
To list all tags in use:
|
||||||
|
cheat -T
|
||||||
|
|
||||||
To list available cheatsheets that are tagged as "personal":
|
To list available cheatsheets that are tagged as "personal":
|
||||||
cheat -l -t personal
|
cheat -l -t personal
|
||||||
|
|
||||||
@ -41,3 +49,6 @@ Examples:
|
|||||||
|
|
||||||
To search (by regex) for cheatsheets that contain an IP address:
|
To search (by regex) for cheatsheets that contain an IP address:
|
||||||
cheat -c -r -s '(?:[0-9]{1,3}\.){3}[0-9]{1,3}'
|
cheat -c -r -s '(?:[0-9]{1,3}\.){3}[0-9]{1,3}'
|
||||||
|
|
||||||
|
To remove (delete) the foo/bar cheatsheet:
|
||||||
|
cheat --rm foo/bar
|
||||||
|
@ -13,7 +13,7 @@ import (
|
|||||||
"github.com/cheat/cheat/internal/config"
|
"github.com/cheat/cheat/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
const version = "3.0.7"
|
const version = "3.2.1"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
@ -76,9 +76,15 @@ func main() {
|
|||||||
case opts["--list"].(bool):
|
case opts["--list"].(bool):
|
||||||
cmd = cmdList
|
cmd = cmdList
|
||||||
|
|
||||||
|
case opts["--tags"].(bool):
|
||||||
|
cmd = cmdTags
|
||||||
|
|
||||||
case opts["--search"] != nil:
|
case opts["--search"] != nil:
|
||||||
cmd = cmdSearch
|
cmd = cmdSearch
|
||||||
|
|
||||||
|
case opts["--rm"] != nil:
|
||||||
|
cmd = cmdRemove
|
||||||
|
|
||||||
case opts["<cheatsheet>"] != nil:
|
case opts["<cheatsheet>"] != nil:
|
||||||
cmd = cmdView
|
cmd = cmdView
|
||||||
|
|
||||||
|
@ -14,13 +14,15 @@ Options:
|
|||||||
--init Write a default config file to stdout
|
--init Write a default config file to stdout
|
||||||
-c --colorize Colorize output
|
-c --colorize Colorize output
|
||||||
-d --directories List cheatsheet directories
|
-d --directories List cheatsheet directories
|
||||||
-e --edit=<sheet> Edit cheatsheet
|
-e --edit=<sheet> Edit <sheet>
|
||||||
-l --list List cheatsheets
|
-l --list List cheatsheets
|
||||||
-p --path=<name> Return only sheets found on path <name>
|
-p --path=<name> Return only sheets found on path <name>
|
||||||
-r --regex Treat search <phrase> as a regex
|
-r --regex Treat search <phrase> as a regex
|
||||||
-s --search=<phrase> Search cheatsheets for <phrase>
|
-s --search=<phrase> Search cheatsheets for <phrase>
|
||||||
-t --tag=<tag> Return only sheets matching <tag>
|
-t --tag=<tag> Return only sheets matching <tag>
|
||||||
|
-T --tags List all tags in use
|
||||||
-v --version Print the version number
|
-v --version Print the version number
|
||||||
|
--rm=<sheet> Remove (delete) <sheet>
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
@ -42,6 +44,12 @@ Examples:
|
|||||||
To list all available cheatsheets:
|
To list all available cheatsheets:
|
||||||
cheat -l
|
cheat -l
|
||||||
|
|
||||||
|
To list all cheatsheets whose titles match "apt":
|
||||||
|
cheat -l apt
|
||||||
|
|
||||||
|
To list all tags in use:
|
||||||
|
cheat -T
|
||||||
|
|
||||||
To list available cheatsheets that are tagged as "personal":
|
To list available cheatsheets that are tagged as "personal":
|
||||||
cheat -l -t personal
|
cheat -l -t personal
|
||||||
|
|
||||||
@ -50,5 +58,8 @@ Examples:
|
|||||||
|
|
||||||
To search (by regex) for cheatsheets that contain an IP address:
|
To search (by regex) for cheatsheets that contain an IP address:
|
||||||
cheat -c -r -s '(?:[0-9]{1,3}\.){3}[0-9]{1,3}'
|
cheat -c -r -s '(?:[0-9]{1,3}\.){3}[0-9]{1,3}'
|
||||||
|
|
||||||
|
To remove (delete) the foo/bar cheatsheet:
|
||||||
|
cheat --rm foo/bar
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
2
go.mod
2
go.mod
@ -10,5 +10,5 @@ require (
|
|||||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b
|
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0
|
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0
|
||||||
gopkg.in/yaml.v2 v2.2.5
|
gopkg.in/yaml.v2 v2.2.7
|
||||||
)
|
)
|
||||||
|
4
go.sum
4
go.sum
@ -60,5 +60,5 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+
|
|||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 h1:POO/ycCATvegFmVuPpQzZFJ+pGZeX22Ufu6fibxDVjU=
|
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 h1:POO/ycCATvegFmVuPpQzZFJ+pGZeX22Ufu6fibxDVjU=
|
||||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
|
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
|
||||||
gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
|
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
||||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
26
internal/config/color.go
Normal file
26
internal/config/color.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/mattn/go-isatty"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Color indicates whether colorization should be applied to the output
|
||||||
|
func (c *Config) Color(opts map[string]interface{}) bool {
|
||||||
|
|
||||||
|
// default to the colorization specified in the configs...
|
||||||
|
colorize := c.Colorize
|
||||||
|
|
||||||
|
// ... however, only apply colorization if we're writing to a tty...
|
||||||
|
if !isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd()) {
|
||||||
|
colorize = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... *unless* the --colorize flag was passed
|
||||||
|
if opts["--colorize"] == true {
|
||||||
|
colorize = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return colorize
|
||||||
|
}
|
@ -45,7 +45,7 @@ func Load(cheatpaths []cp.Cheatpath) ([]map[string]sheet.Sheet, error) {
|
|||||||
// accessed. Eg: `cheat tar` - `tar` is the title)
|
// accessed. Eg: `cheat tar` - `tar` is the title)
|
||||||
title := strings.TrimPrefix(
|
title := strings.TrimPrefix(
|
||||||
strings.TrimPrefix(path, cheatpath.Path),
|
strings.TrimPrefix(path, cheatpath.Path),
|
||||||
"/",
|
string(os.PathSeparator),
|
||||||
)
|
)
|
||||||
|
|
||||||
// ignore hidden files and directories. Otherwise, we'll likely load
|
// ignore hidden files and directories. Otherwise, we'll likely load
|
||||||
|
36
internal/sheets/tags.go
Normal file
36
internal/sheets/tags.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package sheets
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/cheat/cheat/internal/sheet"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Tags returns a slice of all tags in use in any sheet
|
||||||
|
func Tags(cheatpaths []map[string]sheet.Sheet) []string {
|
||||||
|
|
||||||
|
// create a map of all tags in use in any sheet
|
||||||
|
tags := make(map[string]bool)
|
||||||
|
|
||||||
|
// iterate over all tags on all sheets on all cheatpaths
|
||||||
|
for _, path := range cheatpaths {
|
||||||
|
for _, sheet := range path {
|
||||||
|
for _, tag := range sheet.Tags {
|
||||||
|
tags[tag] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// restructure the map into a slice
|
||||||
|
sorted := []string{}
|
||||||
|
for tag := range tags {
|
||||||
|
sorted = append(sorted, tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort the slice
|
||||||
|
sort.Slice(sorted, func(i, j int) bool {
|
||||||
|
return sorted[i] < sorted[j]
|
||||||
|
})
|
||||||
|
|
||||||
|
return sorted
|
||||||
|
}
|
51
internal/sheets/tags_test.go
Normal file
51
internal/sheets/tags_test.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package sheets
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
|
||||||
|
"github.com/cheat/cheat/internal/sheet"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestTags asserts that cheetsheet tags are properly returned
|
||||||
|
func TestTags(t *testing.T) {
|
||||||
|
|
||||||
|
// mock cheatsheets available on multiple cheatpaths
|
||||||
|
cheatpaths := []map[string]sheet.Sheet{
|
||||||
|
|
||||||
|
// mock community cheatsheets
|
||||||
|
map[string]sheet.Sheet{
|
||||||
|
"foo": sheet.Sheet{Title: "foo", Tags: []string{"alpha"}},
|
||||||
|
"bar": sheet.Sheet{Title: "bar", Tags: []string{"alpha", "bravo"}},
|
||||||
|
},
|
||||||
|
|
||||||
|
// mock local cheatsheets
|
||||||
|
map[string]sheet.Sheet{
|
||||||
|
"bar": sheet.Sheet{Title: "bar", Tags: []string{"bravo", "charlie"}},
|
||||||
|
"baz": sheet.Sheet{Title: "baz", Tags: []string{"delta"}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// consolidate the cheatsheets
|
||||||
|
tags := Tags(cheatpaths)
|
||||||
|
|
||||||
|
// specify the expected output
|
||||||
|
want := []string{
|
||||||
|
"alpha",
|
||||||
|
"bravo",
|
||||||
|
"charlie",
|
||||||
|
"delta",
|
||||||
|
}
|
||||||
|
|
||||||
|
// assert that the cheatsheets properly consolidated
|
||||||
|
if !reflect.DeepEqual(tags, want) {
|
||||||
|
t.Errorf(
|
||||||
|
"failed to return tags: want:\n%s, got:\n%s",
|
||||||
|
spew.Sdump(want),
|
||||||
|
spew.Sdump(tags),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -7,5 +7,7 @@ complete -c cheat -s l -l list -d "List cheatsheets"
|
|||||||
complete -c cheat -s p -l path -x -a "(cheat -d | cut -d ':' -f 1)" -d "Return only sheets found on given path"
|
complete -c cheat -s p -l path -x -a "(cheat -d | cut -d ':' -f 1)" -d "Return only sheets found on given path"
|
||||||
complete -c cheat -s r -l regex -d "Treat search phrase as a regex"
|
complete -c cheat -s r -l regex -d "Treat search phrase as a regex"
|
||||||
complete -c cheat -s s -l search -x -d "Search cheatsheets for given phrase"
|
complete -c cheat -s s -l search -x -d "Search cheatsheets for given phrase"
|
||||||
complete -c cheat -s t -l tag -x -a "(cheat -l | tail -n +2 | rev | cut -d ' ' -f 1 | rev | sed 's/,/\n/g;/^\$/d' | sort -u)" -d "Return only sheets matching the given tag"
|
complete -c cheat -s t -l tag -x -a "(cheat -T)" -d "Return only sheets matching the given tag"
|
||||||
|
complete -c cheat -s T -l tags -d "List all tags in use"
|
||||||
complete -c cheat -s v -l version -d "Print the version number"
|
complete -c cheat -s v -l version -d "Print the version number"
|
||||||
|
complete -c cheat -l rm -x -a "(cheat -l | tail -n +2 | cut -d ' ' -f 1)" -d "Remove (delete) cheatsheet"
|
||||||
|
18
vendor/gopkg.in/yaml.v2/.travis.yml
generated
vendored
18
vendor/gopkg.in/yaml.v2/.travis.yml
generated
vendored
@ -1,12 +1,16 @@
|
|||||||
language: go
|
language: go
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.4
|
- "1.4.x"
|
||||||
- 1.5
|
- "1.5.x"
|
||||||
- 1.6
|
- "1.6.x"
|
||||||
- 1.7
|
- "1.7.x"
|
||||||
- 1.8
|
- "1.8.x"
|
||||||
- 1.9
|
- "1.9.x"
|
||||||
- tip
|
- "1.10.x"
|
||||||
|
- "1.11.x"
|
||||||
|
- "1.12.x"
|
||||||
|
- "1.13.x"
|
||||||
|
- "tip"
|
||||||
|
|
||||||
go_import_path: gopkg.in/yaml.v2
|
go_import_path: gopkg.in/yaml.v2
|
||||||
|
62
vendor/gopkg.in/yaml.v2/scannerc.go
generated
vendored
62
vendor/gopkg.in/yaml.v2/scannerc.go
generated
vendored
@ -634,13 +634,14 @@ func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool {
|
|||||||
need_more_tokens = true
|
need_more_tokens = true
|
||||||
} else {
|
} else {
|
||||||
// Check if any potential simple key may occupy the head position.
|
// Check if any potential simple key may occupy the head position.
|
||||||
if !yaml_parser_stale_simple_keys(parser) {
|
for i := len(parser.simple_keys) - 1; i >= 0; i-- {
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range parser.simple_keys {
|
|
||||||
simple_key := &parser.simple_keys[i]
|
simple_key := &parser.simple_keys[i]
|
||||||
if simple_key.possible && simple_key.token_number == parser.tokens_parsed {
|
if simple_key.token_number < parser.tokens_parsed {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if valid, ok := yaml_simple_key_is_valid(parser, simple_key); !ok {
|
||||||
|
return false
|
||||||
|
} else if valid && simple_key.token_number == parser.tokens_parsed {
|
||||||
need_more_tokens = true
|
need_more_tokens = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -678,11 +679,6 @@ func yaml_parser_fetch_next_token(parser *yaml_parser_t) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove obsolete potential simple keys.
|
|
||||||
if !yaml_parser_stale_simple_keys(parser) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the indentation level against the current column.
|
// Check the indentation level against the current column.
|
||||||
if !yaml_parser_unroll_indent(parser, parser.mark.column) {
|
if !yaml_parser_unroll_indent(parser, parser.mark.column) {
|
||||||
return false
|
return false
|
||||||
@ -837,29 +833,30 @@ func yaml_parser_fetch_next_token(parser *yaml_parser_t) bool {
|
|||||||
"found character that cannot start any token")
|
"found character that cannot start any token")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the list of potential simple keys and remove the positions that
|
func yaml_simple_key_is_valid(parser *yaml_parser_t, simple_key *yaml_simple_key_t) (valid, ok bool) {
|
||||||
// cannot contain simple keys anymore.
|
if !simple_key.possible {
|
||||||
func yaml_parser_stale_simple_keys(parser *yaml_parser_t) bool {
|
return false, true
|
||||||
// Check for a potential simple key for each flow level.
|
}
|
||||||
for i := range parser.simple_keys {
|
|
||||||
simple_key := &parser.simple_keys[i]
|
|
||||||
|
|
||||||
// The specification requires that a simple key
|
// The 1.2 specification says:
|
||||||
//
|
//
|
||||||
// - is limited to a single line,
|
// "If the ? indicator is omitted, parsing needs to see past the
|
||||||
// - is shorter than 1024 characters.
|
// implicit key to recognize it as such. To limit the amount of
|
||||||
if simple_key.possible && (simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index) {
|
// lookahead required, the “:” indicator must appear at most 1024
|
||||||
|
// Unicode characters beyond the start of the key. In addition, the key
|
||||||
|
// is restricted to a single line."
|
||||||
|
//
|
||||||
|
if simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index {
|
||||||
// Check if the potential simple key to be removed is required.
|
// Check if the potential simple key to be removed is required.
|
||||||
if simple_key.required {
|
if simple_key.required {
|
||||||
return yaml_parser_set_scanner_error(parser,
|
return false, yaml_parser_set_scanner_error(parser,
|
||||||
"while scanning a simple key", simple_key.mark,
|
"while scanning a simple key", simple_key.mark,
|
||||||
"could not find expected ':'")
|
"could not find expected ':'")
|
||||||
}
|
}
|
||||||
simple_key.possible = false
|
simple_key.possible = false
|
||||||
|
return false, true
|
||||||
}
|
}
|
||||||
}
|
return true, true
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if a simple key may start at the current position and add it if
|
// Check if a simple key may start at the current position and add it if
|
||||||
@ -879,8 +876,8 @@ func yaml_parser_save_simple_key(parser *yaml_parser_t) bool {
|
|||||||
possible: true,
|
possible: true,
|
||||||
required: required,
|
required: required,
|
||||||
token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head),
|
token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head),
|
||||||
|
mark: parser.mark,
|
||||||
}
|
}
|
||||||
simple_key.mark = parser.mark
|
|
||||||
|
|
||||||
if !yaml_parser_remove_simple_key(parser) {
|
if !yaml_parser_remove_simple_key(parser) {
|
||||||
return false
|
return false
|
||||||
@ -912,7 +909,12 @@ const max_flow_level = 10000
|
|||||||
// Increase the flow level and resize the simple key list if needed.
|
// Increase the flow level and resize the simple key list if needed.
|
||||||
func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool {
|
func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool {
|
||||||
// Reset the simple key on the next level.
|
// Reset the simple key on the next level.
|
||||||
parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{})
|
parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{
|
||||||
|
possible: false,
|
||||||
|
required: false,
|
||||||
|
token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head),
|
||||||
|
mark: parser.mark,
|
||||||
|
})
|
||||||
|
|
||||||
// Increase the flow level.
|
// Increase the flow level.
|
||||||
parser.flow_level++
|
parser.flow_level++
|
||||||
@ -1286,7 +1288,11 @@ func yaml_parser_fetch_value(parser *yaml_parser_t) bool {
|
|||||||
simple_key := &parser.simple_keys[len(parser.simple_keys)-1]
|
simple_key := &parser.simple_keys[len(parser.simple_keys)-1]
|
||||||
|
|
||||||
// Have we found a simple key?
|
// Have we found a simple key?
|
||||||
if simple_key.possible {
|
if valid, ok := yaml_simple_key_is_valid(parser, simple_key); !ok {
|
||||||
|
return false
|
||||||
|
|
||||||
|
} else if valid {
|
||||||
|
|
||||||
// Create the KEY token and insert it into the queue.
|
// Create the KEY token and insert it into the queue.
|
||||||
token := yaml_token_t{
|
token := yaml_token_t{
|
||||||
typ: yaml_KEY_TOKEN,
|
typ: yaml_KEY_TOKEN,
|
||||||
|
2
vendor/gopkg.in/yaml.v2/yaml.go
generated
vendored
2
vendor/gopkg.in/yaml.v2/yaml.go
generated
vendored
@ -89,7 +89,7 @@ func UnmarshalStrict(in []byte, out interface{}) (err error) {
|
|||||||
return unmarshal(in, out, true)
|
return unmarshal(in, out, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Decorder reads and decodes YAML values from an input stream.
|
// A Decoder reads and decodes YAML values from an input stream.
|
||||||
type Decoder struct {
|
type Decoder struct {
|
||||||
strict bool
|
strict bool
|
||||||
parser *parser
|
parser *parser
|
||||||
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@ -53,5 +53,5 @@ github.com/mitchellh/go-homedir
|
|||||||
golang.org/x/sys/unix
|
golang.org/x/sys/unix
|
||||||
# gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0
|
# gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0
|
||||||
gopkg.in/yaml.v1
|
gopkg.in/yaml.v1
|
||||||
# gopkg.in/yaml.v2 v2.2.5
|
# gopkg.in/yaml.v2 v2.2.7
|
||||||
gopkg.in/yaml.v2
|
gopkg.in/yaml.v2
|
||||||
|
Reference in New Issue
Block a user