├── .github ├── dependabot.yml └── workflows │ └── ci.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE.txt ├── README.md ├── Taskfile.yml ├── go.mod ├── go.sum ├── leg.go ├── leg_test.go └── staticcheck.conf /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "gomod" 4 | directory: "/" # Location of go.mod 5 | schedule: 6 | interval: "daily" 7 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | pull_request: 6 | 7 | name: CI 8 | 9 | jobs: 10 | test: 11 | name: Unit tests 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout repo 15 | uses: actions/checkout@v4 16 | - name: Install Go 17 | uses: actions/setup-go@v4 18 | with: 19 | go-version: "1.22.1" 20 | - name: Install Task 21 | uses: arduino/setup-task@v2 22 | - name: Install dependencies 23 | run: task dep 24 | - name: Lint 25 | run: task lint 26 | - name: Test 27 | run: task test 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Dependency directories (remove the comment below to include it) 18 | # vendor/ 19 | 20 | # Go workspace file 21 | go.work 22 | 23 | # Binary 24 | n2 25 | 26 | # Goreleaser 27 | dist/ 28 | 29 | # Vendoring 30 | vendor/ 31 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Developer Guide 2 | 3 | ## Dependencies 4 | 5 | - [Task](https://taskfile.dev/installation/) 6 | - Linters: 7 | 8 | ```sh 9 | task dep 10 | ``` 11 | 12 | ### Tests 13 | 14 | To be sure the new code makes the linters happy and the tests are not broken. 15 | 16 | ```sh 17 | task # Alias for the next ones. 18 | task lint 19 | task test 20 | task format 21 | ``` 22 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright Jesús Rubio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # leg 2 | 3 | **Archived**, now just using [slog](https://go.dev/blog/slog). 4 | 5 | *** 6 | 7 | Screenshot 2023-03-06 at 14 18 25 10 | 11 | [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] 12 | 13 | Tiny wrapper to beauty command line application prototypes with a minimal effort. 14 | 15 | - Prints to `stderr`. 16 | - Thanks to [color](https://github.com/fatih/color) library: 17 | - Cross platform. 18 | - Respects [NO_COLOR](https://no-color.org). 19 | 20 | ## Install 21 | 22 | ```sg 23 | go get -u github.com/jesusprubio/leg 24 | ``` 25 | 26 | ### Dependencies 27 | 28 | - [Go](https://go.dev/doc/install) stable version. 29 | 30 | ## Use 31 | 32 | Visit the [tests](leg_test.go) to check more details. 33 | 34 | ```golang 35 | leg.Head("mumu", "🐘", "0.1.0") 36 | leg.Info("Informational message", "") 37 | leg.Success("Successful operation", "") 38 | leg.Warn("Warn message", "") 39 | leg.Error("Error message", "") 40 | leg.Wait("Waiting for something", "") 41 | leg.Done("Something finished", "") 42 | 43 | leg.Info("Informational message with scope", "scope-0") 44 | 45 | fmt.Print("deleted line") 46 | leg.Remove() 47 | 48 | leg.Result("To standard output") 49 | ``` 50 | 51 | [doc-img]: https://pkg.go.dev/badge/github.com/jesusprubio/leg 52 | [doc]: https://pkg.go.dev/github.com/jesusprubio/leg 53 | [ci-img]: https://github.com/jesusprubio/leg/workflows/CI/badge.svg 54 | [ci]: https://github.com/jesusprubio/leg/workflows/go.yml 55 | -------------------------------------------------------------------------------- /Taskfile.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | tasks: 4 | default: task lint test fmt 5 | 6 | clean: 7 | cmds: 8 | - go clean 9 | 10 | dep: 11 | cmds: 12 | - go install honnef.co/go/tools/cmd/staticcheck@latest 13 | - go install github.com/segmentio/golines@latest 14 | - go install github.com/securego/gosec/v2/cmd/gosec@latest 15 | - go install github.com/alexkohler/nakedret/cmd/nakedret@latest 16 | 17 | fmt: 18 | cmds: 19 | - go fmt ./... 20 | - golines -m 80 --shorten-comments -w . 21 | 22 | lint: 23 | cmds: 24 | - go vet ./... 25 | - staticcheck ./... 26 | - gosec -fmt=golint -quiet ./... 27 | - nakedret ./... 28 | 29 | test: 30 | cmds: 31 | - go test -v ./... 32 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/jesusprubio/leg 2 | 3 | go 1.22 4 | 5 | require github.com/fatih/color v1.16.0 6 | 7 | require ( 8 | github.com/mattn/go-colorable v0.1.13 // indirect 9 | github.com/mattn/go-isatty v0.0.20 // indirect 10 | golang.org/x/sys v0.14.0 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= 2 | github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= 3 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 4 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 5 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 6 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 7 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 8 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 9 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 10 | golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= 11 | golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 12 | -------------------------------------------------------------------------------- /leg.go: -------------------------------------------------------------------------------- 1 | // Package leg provides helpers to print the most common type of messages 2 | // used in command line applications. 3 | // 4 | // For simplicity, parameters of the different functions are not validated. 5 | // It is not fun to check for errors when printing messages. The benefits would 6 | // not be worth it. 7 | package leg 8 | 9 | import ( 10 | "fmt" 11 | "os" 12 | 13 | "github.com/fatih/color" 14 | ) 15 | 16 | // Head prints a simple application header/title. 17 | // 18 | // - `name`: Name of the project. 19 | // - `icon`: Optional icon to display. 20 | // - `version`: Include also the version. 21 | func Head(name string, icon string, version string) { 22 | if version != "" { 23 | version = fmt.Sprintf("\t(v%s)", version) 24 | } 25 | fmt.Fprintf( 26 | os.Stderr, 27 | "\n\t%s %s\n%s\n\n", 28 | icon, 29 | color.New(color.Bold).SprintFunc()(name), 30 | color.New(color.Faint).SprintFunc()(version), 31 | ) 32 | } 33 | 34 | // Info prints generic data. 35 | // 36 | // - `message`: String to print. 37 | // - `scope`: Prefix to append. 38 | func Info(message string, scope string) { 39 | printLine(¶ms{ 40 | tag: "ℹ", 41 | color: color.FgHiBlue, 42 | message: message, 43 | scope: scope, 44 | }) 45 | } 46 | 47 | // Prints a line with custom format to stderr. 48 | func printLine(p *params) { 49 | if p.scope != "" { 50 | p.scope = fmt.Sprintf("[%s]", p.scope) 51 | } 52 | tagWithColor := color.New(p.color, color.Bold).SprintFunc()(p.tag) 53 | fmt.Fprintf(os.Stderr, "%s %s %s\n", p.scope, tagWithColor, p.message) 54 | } 55 | 56 | // Parameters for `printLine` function. 57 | type params struct { 58 | // String to use as prefix (after scope). 59 | tag string 60 | // Color to use for the tag. 61 | color color.Attribute 62 | // String to print. 63 | message string 64 | // Prefix to append, optional. 65 | scope string 66 | } 67 | 68 | // Success prints about a correct operation. 69 | // 70 | // - `message`: String to print. 71 | // - `scope`: Prefix to append. 72 | func Success(message string, scope string) { 73 | printLine(¶ms{ 74 | tag: "✔", 75 | color: color.FgHiGreen, 76 | message: message, 77 | scope: scope, 78 | }) 79 | } 80 | 81 | // Warn prints about a not completely correct operation. 82 | // 83 | // - `message`: String to print. 84 | // - `scope`: Prefix to append. 85 | func Warn(message string, scope string) { 86 | printLine(¶ms{ 87 | tag: "⚠", 88 | color: color.FgHiYellow, 89 | message: message, 90 | scope: scope, 91 | }) 92 | } 93 | 94 | // Error prints about an errored operation. 95 | // 96 | // - `message`: String to print. 97 | // - `scope`: Prefix to append. 98 | func Error(message string, scope string) { 99 | printLine(¶ms{ 100 | tag: "✖", 101 | color: color.FgHiRed, 102 | message: message, 103 | scope: scope, 104 | }) 105 | } 106 | 107 | // Wait indicates a delay. 108 | // 109 | // - `message`: String to print. 110 | // - `scope`: Prefix to append. 111 | func Wait(message string, scope string) { 112 | printLine(¶ms{ 113 | tag: "…", 114 | color: color.FgHiMagenta, 115 | message: message, 116 | scope: scope, 117 | }) 118 | } 119 | 120 | // Done indicates something finished. 121 | // 122 | // - `message`: String to print. 123 | // - `scope`: Prefix to append. 124 | func Done(message string, scope string) { 125 | printLine(¶ms{ 126 | tag: "☒", 127 | color: color.FgHiCyan, 128 | message: message, 129 | scope: scope, 130 | }) 131 | } 132 | 133 | // Remove deletes the actual line.. 134 | func Remove() error { 135 | _, err := os.Stderr.WriteString("\r") 136 | return err 137 | } 138 | 139 | // Result prints to the standard output. 140 | // 141 | // - `message`: String to print. 142 | func Result(message string) { 143 | fmt.Fprintln(os.Stderr, message+"\n") 144 | } 145 | -------------------------------------------------------------------------------- /leg_test.go: -------------------------------------------------------------------------------- 1 | package leg 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestHead(t *testing.T) { 9 | Head("mumu", "🐘", "0.1.0") 10 | } 11 | 12 | func TestInfo(t *testing.T) { 13 | Info("Informational message", "") 14 | Info("Informational message with scope", "scope-0") 15 | } 16 | 17 | func TestSuccess(t *testing.T) { 18 | Success("Successful operation", "") 19 | } 20 | 21 | func TestWarn(t *testing.T) { 22 | Warn("Warn message", "") 23 | } 24 | 25 | func TestError(t *testing.T) { 26 | Error("Error message", "") 27 | } 28 | 29 | func TestWait(t *testing.T) { 30 | Wait("Waiting for something", "") 31 | } 32 | 33 | func TestDone(t *testing.T) { 34 | Done("Something finished", "") 35 | } 36 | 37 | func TestRemove(t *testing.T) { 38 | fmt.Print("deleted line") 39 | Remove() 40 | } 41 | 42 | func TestResult(t *testing.T) { 43 | Result("To standard output") 44 | } 45 | -------------------------------------------------------------------------------- /staticcheck.conf: -------------------------------------------------------------------------------- 1 | checks = ["all"] --------------------------------------------------------------------------------