mirror of
https://github.com/cheat/cheat.git
synced 2024-11-14 08:01:09 +01:00
commit
73f80bde48
23 changed files with 55 additions and 90 deletions
|
@ -9,13 +9,13 @@ On Unix-like systems, you may simply paste the following snippet into your termi
|
|||
|
||||
```sh
|
||||
cd /tmp \
|
||||
&& wget https://github.com/cheat/cheat/releases/download/4.2.5/cheat-linux-amd64.gz \
|
||||
&& wget https://github.com/cheat/cheat/releases/download/4.2.7/cheat-linux-amd64.gz \
|
||||
&& gunzip cheat-linux-amd64.gz \
|
||||
&& chmod +x cheat-linux-amd64 \
|
||||
&& sudo mv cheat-linux-amd64 /usr/local/bin/cheat
|
||||
```
|
||||
|
||||
You may need to need to change the version number (`4.2.5`) and the archive
|
||||
You may need to need to change the version number (`4.2.7`) and the archive
|
||||
(`cheat-linux-amd64.gz`) depending on your platform.
|
||||
|
||||
See the [releases page][releases] for a list of supported platforms.
|
||||
|
|
|
@ -18,11 +18,7 @@ func cmdDirectories(opts map[string]interface{}, conf config.Config) {
|
|||
|
||||
// generate sorted, columnized output
|
||||
for _, path := range conf.Cheatpaths {
|
||||
fmt.Fprintln(w, fmt.Sprintf(
|
||||
"%s:\t%s",
|
||||
path.Name,
|
||||
path.Path,
|
||||
))
|
||||
fmt.Fprintf(w, "%s:\t%s\n", path.Name, path.Path)
|
||||
}
|
||||
|
||||
// write columnized output to stdout
|
||||
|
|
|
@ -20,7 +20,7 @@ func cmdEdit(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))
|
||||
fmt.Fprintf(os.Stderr, "failed to list cheatsheets: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ func cmdList(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))
|
||||
fmt.Fprintf(os.Stderr, "failed to list cheatsheets: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
@ -63,10 +63,7 @@ func cmdList(opts map[string]interface{}, conf config.Config) {
|
|||
// 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),
|
||||
)
|
||||
fmt.Fprintf(os.Stderr, "failed to compile regexp: %s, %v\n", pattern, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
@ -95,12 +92,7 @@ func cmdList(opts map[string]interface{}, conf config.Config) {
|
|||
|
||||
// generate sorted, columnized output
|
||||
for _, sheet := range flattened {
|
||||
fmt.Fprintln(w, fmt.Sprintf(
|
||||
"%s\t%s\t%s",
|
||||
sheet.Title,
|
||||
sheet.Path,
|
||||
strings.Join(sheet.Tags, ","),
|
||||
))
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\n", sheet.Title, sheet.Path, strings.Join(sheet.Tags, ","))
|
||||
}
|
||||
|
||||
// write columnized output to stdout
|
||||
|
|
|
@ -17,7 +17,7 @@ func cmdRemove(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))
|
||||
fmt.Fprintf(os.Stderr, "failed to list cheatsheets: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
@ -37,19 +37,19 @@ func cmdRemove(opts map[string]interface{}, conf config.Config) {
|
|||
// 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))
|
||||
fmt.Fprintf(os.Stderr, "No cheatsheet found for '%s'.\n", cheatsheet)
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
// fail early if the sheet is read-only
|
||||
if sheet.ReadOnly {
|
||||
fmt.Fprintln(os.Stderr, fmt.Sprintf("cheatsheet '%s' is read-only.", cheatsheet))
|
||||
fmt.Fprintf(os.Stderr, "cheatsheet '%s' is read-only.\n", 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))
|
||||
fmt.Fprintf(os.Stderr, "failed to delete sheet: %s, %v\n", sheet.Title, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ func cmdSearch(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))
|
||||
fmt.Fprintf(os.Stderr, "failed to list cheatsheets: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
@ -55,13 +55,13 @@ func cmdSearch(opts map[string]interface{}, conf config.Config) {
|
|||
// 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))
|
||||
fmt.Fprintf(os.Stderr, "failed to compile regexp: %s, %v\n", pattern, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// `Search` will return text entries that match the search terms. We're
|
||||
// using it here to overwrite the prior cheatsheet Text, filtering it to
|
||||
// only what is relevant
|
||||
// `Search` will return text entries that match the search terms.
|
||||
// We're using it here to overwrite the prior cheatsheet Text,
|
||||
// filtering it to only what is relevant.
|
||||
sheet.Text = sheet.Search(reg)
|
||||
|
||||
// if the sheet did not match the search, ignore it and move on
|
||||
|
@ -74,14 +74,16 @@ func cmdSearch(opts map[string]interface{}, conf config.Config) {
|
|||
sheet.Colorize(conf)
|
||||
}
|
||||
|
||||
// display the cheatsheet title and path
|
||||
out += fmt.Sprintf("%s %s\n",
|
||||
display.Underline(sheet.Title),
|
||||
// display the cheatsheet body
|
||||
out += fmt.Sprintf(
|
||||
"%s %s\n%s\n",
|
||||
// append the cheatsheet title
|
||||
sheet.Title,
|
||||
// append the cheatsheet path
|
||||
display.Faint(fmt.Sprintf("(%s)", sheet.CheatPath), conf),
|
||||
// indent each line of content
|
||||
display.Indent(sheet.Text),
|
||||
)
|
||||
|
||||
// indent each line of content
|
||||
out += display.Indent(sheet.Text) + "\n"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,7 +91,7 @@ func cmdSearch(opts map[string]interface{}, conf config.Config) {
|
|||
out = strings.TrimSpace(out)
|
||||
|
||||
// display the output
|
||||
// NB: resist the temptation to call `display.Display` multiple times in
|
||||
// the loop above. That will not play nicely with the paginator.
|
||||
// NB: resist the temptation to call `display.Write` multiple times in the
|
||||
// loop above. That will not play nicely with the paginator.
|
||||
display.Write(out, conf)
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ 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))
|
||||
fmt.Fprintf(os.Stderr, "failed to list cheatsheets: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ func cmdView(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))
|
||||
fmt.Fprintf(os.Stderr, "failed to list cheatsheets: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ func cmdView(opts map[string]interface{}, conf config.Config) {
|
|||
|
||||
// identify the matching cheatsheet
|
||||
out += fmt.Sprintf("%s %s\n",
|
||||
display.Underline(sheet.Title),
|
||||
sheet.Title,
|
||||
display.Faint(fmt.Sprintf("(%s)", sheet.CheatPath), conf),
|
||||
)
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ import (
|
|||
"github.com/cheat/cheat/internal/installer"
|
||||
)
|
||||
|
||||
const version = "4.2.6"
|
||||
const version = "4.2.7"
|
||||
|
||||
func main() {
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ func TestFilterFailure(t *testing.T) {
|
|||
}
|
||||
|
||||
// filter the paths
|
||||
paths, err := Filter(paths, "qux")
|
||||
_, err := Filter(paths, "qux")
|
||||
if err == nil {
|
||||
t.Errorf("failed to return an error on non-existent cheatpath")
|
||||
}
|
||||
|
|
|
@ -11,12 +11,10 @@ func Writeable(cheatpaths []Cheatpath) (Cheatpath, error) {
|
|||
// NB: we're going backwards because we assume that the most "local"
|
||||
// cheatpath will be specified last in the configs
|
||||
for i := len(cheatpaths) - 1; i >= 0; i-- {
|
||||
|
||||
// if the cheatpath is not read-only, it is writeable, and thus returned
|
||||
if cheatpaths[i].ReadOnly == false {
|
||||
if !cheatpaths[i].ReadOnly {
|
||||
return cheatpaths[i], nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// otherwise, return an error
|
||||
|
|
|
@ -2,7 +2,6 @@ package config
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
@ -29,7 +28,7 @@ type Config struct {
|
|||
func New(opts map[string]interface{}, confPath string, resolve bool) (Config, error) {
|
||||
|
||||
// read the config file
|
||||
buf, err := ioutil.ReadFile(confPath)
|
||||
buf, err := os.ReadFile(confPath)
|
||||
if err != nil {
|
||||
return Config{}, fmt.Errorf("could not read config file: %v", err)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package config
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
@ -16,7 +15,7 @@ func Init(confpath string, configs string) error {
|
|||
}
|
||||
|
||||
// write the config file
|
||||
if err := ioutil.WriteFile(confpath, []byte(configs), 0644); err != nil {
|
||||
if err := os.WriteFile(confpath, []byte(configs), 0644); err != nil {
|
||||
return fmt.Errorf("failed to create file: %v", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
@ -10,7 +9,7 @@ import (
|
|||
func TestInit(t *testing.T) {
|
||||
|
||||
// initialize a temporary config file
|
||||
confFile, err := ioutil.TempFile("", "cheat-test")
|
||||
confFile, err := os.CreateTemp("", "cheat-test")
|
||||
if err != nil {
|
||||
t.Errorf("failed to create temp file: %v", err)
|
||||
}
|
||||
|
@ -25,7 +24,7 @@ func TestInit(t *testing.T) {
|
|||
}
|
||||
|
||||
// read back the config file contents
|
||||
bytes, err := ioutil.ReadFile(confFile.Name())
|
||||
bytes, err := os.ReadFile(confFile.Name())
|
||||
if err != nil {
|
||||
t.Errorf("failed to read config file: %v", err)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
@ -24,7 +23,7 @@ func TestPathConfigNotExists(t *testing.T) {
|
|||
func TestPathConfigExists(t *testing.T) {
|
||||
|
||||
// initialize a temporary config file
|
||||
confFile, err := ioutil.TempFile("", "cheat-test")
|
||||
confFile, err := os.CreateTemp("", "cheat-test")
|
||||
if err != nil {
|
||||
t.Errorf("failed to create temp file: %v", err)
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
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))
|
||||
return fmt.Sprintf("\033[2m%s\033[0m", str)
|
||||
}
|
||||
|
||||
// otherwise, return the string unmodified
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
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))
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
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)
|
||||
}
|
||||
}
|
|
@ -23,15 +23,14 @@ func Write(out string, conf config.Config) {
|
|||
pager := parts[0]
|
||||
args := parts[1:]
|
||||
|
||||
// run the pager
|
||||
// configure the pager
|
||||
cmd := exec.Command(pager, args...)
|
||||
cmd.Stdin = strings.NewReader(out)
|
||||
cmd.Stdout = os.Stdout
|
||||
|
||||
// handle errors
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, fmt.Sprintf("failed to write to pager: %v", err))
|
||||
// run the pager and handle errors
|
||||
if err := cmd.Run(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to write to pager: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ func Prompt(prompt string, def bool) (bool, error) {
|
|||
reader := bufio.NewReader(os.Stdin)
|
||||
|
||||
// display the prompt
|
||||
fmt.Print(fmt.Sprintf("%s: ", prompt))
|
||||
fmt.Printf("%s: ", prompt)
|
||||
|
||||
// read the answer
|
||||
ans, err := reader.ReadString('\n')
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package sheet
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
|
@ -13,7 +12,7 @@ func TestCopyFlat(t *testing.T) {
|
|||
|
||||
// mock a cheatsheet file
|
||||
text := "this is the cheatsheet text"
|
||||
src, err := ioutil.TempFile("", "foo-src")
|
||||
src, err := os.CreateTemp("", "foo-src")
|
||||
if err != nil {
|
||||
t.Errorf("failed to mock cheatsheet: %v", err)
|
||||
}
|
||||
|
@ -41,7 +40,7 @@ func TestCopyFlat(t *testing.T) {
|
|||
}
|
||||
|
||||
// assert that the destination file contains the correct text
|
||||
got, err := ioutil.ReadFile(outpath)
|
||||
got, err := os.ReadFile(outpath)
|
||||
if err != nil {
|
||||
t.Errorf("failed to read destination file: %v", err)
|
||||
}
|
||||
|
@ -60,7 +59,7 @@ func TestCopyDeep(t *testing.T) {
|
|||
|
||||
// mock a cheatsheet file
|
||||
text := "this is the cheatsheet text"
|
||||
src, err := ioutil.TempFile("", "foo-src")
|
||||
src, err := os.CreateTemp("", "foo-src")
|
||||
if err != nil {
|
||||
t.Errorf("failed to mock cheatsheet: %v", err)
|
||||
}
|
||||
|
@ -94,7 +93,7 @@ func TestCopyDeep(t *testing.T) {
|
|||
}
|
||||
|
||||
// assert that the destination file contains the correct text
|
||||
got, err := ioutil.ReadFile(outpath)
|
||||
got, err := os.ReadFile(outpath)
|
||||
if err != nil {
|
||||
t.Errorf("failed to read destination file: %v", err)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package sheet
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"github.com/cheat/cheat/internal/frontmatter"
|
||||
|
@ -29,7 +29,7 @@ func New(
|
|||
) (Sheet, error) {
|
||||
|
||||
// read the cheatsheet file
|
||||
markdown, err := ioutil.ReadFile(path)
|
||||
markdown, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return Sheet{}, fmt.Errorf("failed to read file: %s, %v", path, err)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package sheets
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
@ -55,7 +56,11 @@ func Load(cheatpaths []cp.Cheatpath) ([]map[string]sheet.Sheet, error) {
|
|||
// contained within hidden directories in the middle of a path, though
|
||||
// that should not realistically occur.
|
||||
if strings.HasPrefix(title, ".") || strings.HasPrefix(info.Name(), ".") {
|
||||
return nil
|
||||
// Do not walk hidden directories. This is important,
|
||||
// because it's common for cheatsheets to be stored in
|
||||
// version-control, and a `.git` directory can easily
|
||||
// contain thousands of files.
|
||||
return fs.SkipDir
|
||||
}
|
||||
|
||||
// parse the cheatsheet file into a `sheet` struct
|
||||
|
|
Loading…
Reference in a new issue