mirror of
https://github.com/agresdominik/cheat_sheet.git
synced 2026-07-21 16:10:54 +00:00
Compare commits
4 Commits
4b21757e16
...
v0.1.3
| Author | SHA1 | Date | |
|---|---|---|---|
| 648412d550 | |||
| f0056b9722 | |||
| 11541d532f | |||
| 39361150a5 |
@@ -8,7 +8,7 @@ name: CI
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [main]
|
branches: ['**'] # CI on every branch
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
|
|
||||||
|
|||||||
@@ -92,9 +92,9 @@ jobs:
|
|||||||
|
|
||||||
- name: Patch cheatsh formula
|
- name: Patch cheatsh formula
|
||||||
run: |
|
run: |
|
||||||
|
# version is inferred by Homebrew from the URL tag, so only url + sha256 are patched.
|
||||||
FORMULA="tap/Formula/cheatsh.rb"
|
FORMULA="tap/Formula/cheatsh.rb"
|
||||||
sed -i "s|url .*|url \"${{ steps.sha.outputs.url }}\"|" "$FORMULA"
|
sed -i "s|url .*|url \"${{ steps.sha.outputs.url }}\"|" "$FORMULA"
|
||||||
sed -i "s|version .*|version \"${{ inputs.version }}\"|" "$FORMULA"
|
|
||||||
sed -i "s|sha256 .*|sha256 \"${{ steps.sha.outputs.sha }}\"|" "$FORMULA"
|
sed -i "s|sha256 .*|sha256 \"${{ steps.sha.outputs.sha }}\"|" "$FORMULA"
|
||||||
|
|
||||||
- name: Commit and push tap update
|
- name: Commit and push tap update
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
EXECUTABLE = cheatsh
|
EXECUTABLE = cheatsh
|
||||||
PACKAGES = ./src/.
|
PACKAGES = ./src/.
|
||||||
BINDIR = bin
|
BINDIR = bin
|
||||||
SYSCONFDIR = $(HOME)/.config/cheatsh
|
|
||||||
PREFIX ?= $(HOME)/.local
|
PREFIX ?= $(HOME)/.local
|
||||||
|
DATADIR = $(PREFIX)/share/cheatsh
|
||||||
|
|
||||||
all: build
|
all: build
|
||||||
|
|
||||||
@@ -12,16 +12,16 @@ build:
|
|||||||
|
|
||||||
install: build
|
install: build
|
||||||
|
|
||||||
@echo "Installing binary in $(PREFIX)"
|
@echo "Installing binary in $(PREFIX)/bin"
|
||||||
install -Dm755 bin/$(EXECUTABLE) $(PREFIX)/bin/$(EXECUTABLE)
|
install -Dm755 bin/$(EXECUTABLE) $(PREFIX)/bin/$(EXECUTABLE)
|
||||||
|
|
||||||
@echo "Copying config files to $(SYSCONFDIR)"
|
@echo "Installing command lists in $(DATADIR)"
|
||||||
install -Dm644 data/commands.json $(SYSCONFDIR)/commands.json
|
install -Dm644 data/commands.json $(DATADIR)/commands.json
|
||||||
install -Dm644 data/commands_template.json $(SYSCONFDIR)/commands_template.json
|
install -Dm644 data/commands_template.json $(DATADIR)/commands_template.json
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -f $(PREFIX)/bin/$(EXECUTABLE)
|
rm -f $(PREFIX)/bin/$(EXECUTABLE)
|
||||||
rm -rf $(SYSCONFDIR)
|
rm -rf $(DATADIR)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf bin/
|
rm -rf bin/
|
||||||
|
|||||||
@@ -1,15 +1,89 @@
|
|||||||
# Cheat Sheet
|
# Cheat Sheet
|
||||||
|
|
||||||
A small TUI Tool which displays a pre-configured json file content in a menu and lets the user search for commands and select them. Once selected these are printed in the terminal for easy access.
|
A small TUI tool that displays a pre-configured set of commands in a searchable
|
||||||
|
menu. Pick one and it's copied to your system clipboard — paste it where you
|
||||||
|
need it and edit before running.
|
||||||
|
|
||||||
I wrote this to simplify my search for commands I use often enough to need them multiple times but not often enoigh to remember alway exactly how they are called.
|
I wrote this to look up commands I use often enough to need repeatedly, but not
|
||||||
|
often enough to remember exactly. Written in Go with [bubbletea](https://github.com/charmbracelet/bubbletea).
|
||||||
|
|
||||||
Written in go + used bubbletea for the TUI part of the application.
|
## Install
|
||||||
|
|
||||||
|
### Homebrew (recommended)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install agresdominik/repo/cheatsh
|
||||||
|
```
|
||||||
|
|
||||||
|
### From source
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/agresdominik/cheat_sheet
|
||||||
|
cd cheat_sheet
|
||||||
|
make install # builds and installs to ~/.local/bin
|
||||||
|
```
|
||||||
|
|
||||||
|
Make sure `~/.local/bin` is in your `PATH` (or change `PREFIX` in the `Makefile`).
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
cheatsh ships with a maintained command list and uses it by default. It lives
|
||||||
|
next to the binary and is **replaced on `brew upgrade`**, so updating the list
|
||||||
|
in this repo and releasing is all it takes to get the new commands on your
|
||||||
|
machines:
|
||||||
|
|
||||||
|
```
|
||||||
|
<prefix>/share/cheatsh/commands.json # Homebrew, e.g. /opt/homebrew/...
|
||||||
|
~/.local/share/cheatsh/commands.json # make install
|
||||||
|
data/commands.json # running from a source checkout
|
||||||
|
```
|
||||||
|
|
||||||
|
To maintain the default list, edit `data/commands.json` and release. The format
|
||||||
|
is a map of categories to command lists:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"git": [
|
||||||
|
{ "command": "git reset --soft HEAD~1", "desc": "Undo last commit, keep changes" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom list
|
||||||
|
|
||||||
|
If you'd rather keep your own list (one that survives upgrades untouched), copy
|
||||||
|
the template and pass it explicitly — `--config` always wins over the bundled
|
||||||
|
default:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp "$(brew --prefix)/share/cheatsh/commands_template.json" ~/my-commands.json
|
||||||
|
cheatsh --config ~/my-commands.json
|
||||||
|
```
|
||||||
|
|
||||||
|
## Clipboard dependency
|
||||||
|
|
||||||
|
Copying to the clipboard needs a backend:
|
||||||
|
|
||||||
|
- **macOS** — works out of the box (`pbcopy`).
|
||||||
|
- **Linux/Wayland** — `wl-clipboard`.
|
||||||
|
- **Linux/X11** — `xsel` or `xclip`.
|
||||||
|
|
||||||
|
If no backend is found, cheatsh prints the command to stdout instead.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Use the commands in the given makefile to run, build, test in a docker container or install the application on your device. Beforehand define your own commands.json based on the `commands_template.json` in the `data/` folder.
|
```bash
|
||||||
|
cheatsh # browse and select; selection is copied to clipboard
|
||||||
|
cheatsh --config FILE # use a specific config file
|
||||||
|
cheatsh --help
|
||||||
|
```
|
||||||
|
|
||||||
Once installed just run `cheatsh` in the terminal. If it's not found, make sure `~/.local/bin/` is in your `PATH` or change the path under the `PREFIX` variable in the `Makefile`.
|
In the TUI: `/` to filter, `enter` to descend / select, `b` to go back, `q` to quit.
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make build # build to bin/cheatsh
|
||||||
|
make local # build and run against data/commands.json
|
||||||
|
go test ./src/...
|
||||||
|
```
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ module github.com/dominikagres/cheat_sheet
|
|||||||
go 1.24.1
|
go 1.24.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/atotto/clipboard v0.1.4
|
||||||
github.com/charmbracelet/bubbles v0.21.0
|
github.com/charmbracelet/bubbles v0.21.0
|
||||||
github.com/charmbracelet/bubbletea v1.3.10
|
github.com/charmbracelet/bubbletea v1.3.10
|
||||||
github.com/charmbracelet/lipgloss v1.1.0
|
github.com/charmbracelet/lipgloss v1.1.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/atotto/clipboard v0.1.4 // indirect
|
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
|
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
|
||||||
github.com/charmbracelet/x/ansi v0.10.1 // indirect
|
github.com/charmbracelet/x/ansi v0.10.1 // indirect
|
||||||
|
|||||||
+36
-38
@@ -40,56 +40,54 @@ func main() {
|
|||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
var configFile string
|
|
||||||
|
|
||||||
home, err := os.UserHomeDir()
|
|
||||||
if err == nil {
|
|
||||||
userConf := filepath.Join(home, ".config", "cheatsh")
|
|
||||||
if info, err := os.Stat(userConf); err == nil && info.IsDir() {
|
|
||||||
configFile = filepath.Join(userConf, "commands.json")
|
|
||||||
} else {
|
|
||||||
configFile = "/etc/cheatsh/commands.json"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var commands CmdList
|
|
||||||
|
|
||||||
if *configFlag != "" {
|
|
||||||
commands, err = loadCommands(*configFlag)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Cannot load commands file: %v", err)
|
|
||||||
}
|
|
||||||
StartTui(commands)
|
|
||||||
return
|
|
||||||
} else if len(os.Args) == 1 {
|
|
||||||
commands, err = loadCommands(configFile)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Cannot load commands file: %v", err)
|
|
||||||
}
|
|
||||||
StartTui(commands)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
|
||||||
case *helpFlag:
|
case *helpFlag:
|
||||||
printHelp()
|
printHelp()
|
||||||
|
return
|
||||||
case *newFlag:
|
case *newFlag:
|
||||||
HandleInput()
|
HandleInput()
|
||||||
|
return
|
||||||
default:
|
|
||||||
printHelp()
|
|
||||||
os.Exit(1)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configFile := *configFlag
|
||||||
|
if configFile == "" {
|
||||||
|
configFile = defaultConfigPath()
|
||||||
|
}
|
||||||
|
|
||||||
|
commands, err := loadCommands(configFile)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
log.Fatalf("No config found at %s\nPass a config explicitly with --config <file>.", configFile)
|
||||||
|
}
|
||||||
|
log.Fatalf("Cannot load commands file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
StartTui(commands)
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultConfigPath returns the bundled command list installed next to the
|
||||||
|
// binary (<prefix>/share/cheatsh/commands.json, replaced on upgrade). When
|
||||||
|
// running from a source checkout that file doesn't exist, so it falls back to
|
||||||
|
// data/commands.json relative to the working directory.
|
||||||
|
func defaultConfigPath() string {
|
||||||
|
if exe, err := os.Executable(); err == nil {
|
||||||
|
if real, err := filepath.EvalSymlinks(exe); err == nil {
|
||||||
|
exe = real
|
||||||
|
}
|
||||||
|
p := filepath.Join(filepath.Dir(exe), "..", "share", "cheatsh", "commands.json")
|
||||||
|
if _, err := os.Stat(p); err == nil {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filepath.Join("data", "commands.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
func printHelp() {
|
func printHelp() {
|
||||||
fmt.Println(`Usage: cheatsh [options]
|
fmt.Println(`Usage: cheatsh [options]
|
||||||
|
Select a command to copy it to the system clipboard.
|
||||||
|
Without --config the bundled command list is used; pass --config to use your own.
|
||||||
Options:
|
Options:
|
||||||
--config <file> Specify a config file
|
--config <file> Use a custom config file
|
||||||
--help Show this help message
|
--help Show this help message
|
||||||
--new Add a new command to the config file`)
|
--new Add a new command to the config file`)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/atotto/clipboard"
|
||||||
"github.com/charmbracelet/bubbles/key"
|
"github.com/charmbracelet/bubbles/key"
|
||||||
"github.com/charmbracelet/bubbles/list"
|
"github.com/charmbracelet/bubbles/list"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
@@ -128,7 +129,12 @@ func StartTui(commands CmdList) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if m, ok := finalModel.(model); ok && m.selectedCmd != "" {
|
if m, ok := finalModel.(model); ok && m.selectedCmd != "" {
|
||||||
|
if err := clipboard.WriteAll(m.selectedCmd); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, "Could not copy to clipboard:", err)
|
||||||
fmt.Println(m.selectedCmd)
|
fmt.Println(m.selectedCmd)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println("Copied to clipboard:", m.selectedCmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user