Initial commit.
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
# Kong is a command-line parser for Go
|
||||
|
||||
It parses a command-line into a struct. eg.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import "github.com/alecthomas/kong"
|
||||
|
||||
var CLI struct {
|
||||
Rm struct {
|
||||
Force bool `help:"Force removal."`
|
||||
Recursive bool `help:"Recursively remove files."`
|
||||
|
||||
Paths []string `help:"Paths to remove." type:"path"`
|
||||
} `help:"Remove files."`
|
||||
|
||||
Ls struct {
|
||||
Paths []string `help:"Paths to list." type:"path"`
|
||||
} `help:"List paths."`
|
||||
}
|
||||
|
||||
func main() {
|
||||
kong.Parse(&CLI)
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import "github.com/alecthomas/kong"
|
||||
|
||||
var CLI struct {
|
||||
Rm struct {
|
||||
Force bool `help:"Force removal."`
|
||||
Recursive bool `help:"Recursively remove files."`
|
||||
|
||||
Paths []string `help:"Paths to remove." type:"path"`
|
||||
} `help:"Remove files."`
|
||||
|
||||
Ls struct {
|
||||
Paths []string `help:"Paths to list." type:"path"`
|
||||
} `help:"List paths."`
|
||||
}
|
||||
|
||||
func main() {
|
||||
kong.Parse(&CLI)
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package kong
|
||||
|
||||
// NOTE: This code is from https://github.com/fatih/camelcase. MIT license.
|
||||
|
||||
import (
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// Split splits the camelcase word and returns a list of words. It also
|
||||
// supports digits. Both lower camel case and upper camel case are supported.
|
||||
// For more info please check: http://en.wikipedia.org/wiki/CamelCase
|
||||
//
|
||||
// Examples
|
||||
//
|
||||
// "" => [""]
|
||||
// "lowercase" => ["lowercase"]
|
||||
// "Class" => ["Class"]
|
||||
// "MyClass" => ["My", "Class"]
|
||||
// "MyC" => ["My", "C"]
|
||||
// "HTML" => ["HTML"]
|
||||
// "PDFLoader" => ["PDF", "Loader"]
|
||||
// "AString" => ["A", "String"]
|
||||
// "SimpleXMLParser" => ["Simple", "XML", "Parser"]
|
||||
// "vimRPCPlugin" => ["vim", "RPC", "Plugin"]
|
||||
// "GL11Version" => ["GL", "11", "Version"]
|
||||
// "99Bottles" => ["99", "Bottles"]
|
||||
// "May5" => ["May", "5"]
|
||||
// "BFG9000" => ["BFG", "9000"]
|
||||
// "BöseÜberraschung" => ["Böse", "Überraschung"]
|
||||
// "Two spaces" => ["Two", " ", "spaces"]
|
||||
// "BadUTF8\xe2\xe2\xa1" => ["BadUTF8\xe2\xe2\xa1"]
|
||||
//
|
||||
// Splitting rules
|
||||
//
|
||||
// 1) If string is not valid UTF-8, return it without splitting as
|
||||
// single item array.
|
||||
// 2) Assign all unicode characters into one of 4 sets: lower case
|
||||
// letters, upper case letters, numbers, and all other characters.
|
||||
// 3) Iterate through characters of string, introducing splits
|
||||
// between adjacent characters that belong to different sets.
|
||||
// 4) Iterate through array of split strings, and if a given string
|
||||
// is upper case:
|
||||
// if subsequent string is lower case:
|
||||
// move last character of upper case string to beginning of
|
||||
// lower case string
|
||||
func camelCase(src string) (entries []string) {
|
||||
// don't split invalid utf8
|
||||
if !utf8.ValidString(src) {
|
||||
return []string{src}
|
||||
}
|
||||
entries = []string{}
|
||||
var runes [][]rune
|
||||
lastClass := 0
|
||||
// split into fields based on class of unicode character
|
||||
for _, r := range src {
|
||||
var class int
|
||||
switch true {
|
||||
case unicode.IsLower(r):
|
||||
class = 1
|
||||
case unicode.IsUpper(r):
|
||||
class = 2
|
||||
case unicode.IsDigit(r):
|
||||
class = 3
|
||||
default:
|
||||
class = 4
|
||||
}
|
||||
if class == lastClass {
|
||||
runes[len(runes)-1] = append(runes[len(runes)-1], r)
|
||||
} else {
|
||||
runes = append(runes, []rune{r})
|
||||
}
|
||||
lastClass = class
|
||||
}
|
||||
// handle upper case -> lower case sequences, e.g.
|
||||
// "PDFL", "oader" -> "PDF", "Loader"
|
||||
for i := 0; i < len(runes)-1; i++ {
|
||||
if unicode.IsUpper(runes[i][0]) && unicode.IsLower(runes[i+1][0]) {
|
||||
runes[i+1] = append([]rune{runes[i][len(runes[i])-1]}, runes[i+1]...)
|
||||
runes[i] = runes[i][:len(runes[i])-1]
|
||||
}
|
||||
}
|
||||
// construct []string from results
|
||||
for _, s := range runes {
|
||||
if len(s) > 0 {
|
||||
entries = append(entries, string(s))
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package kong
|
||||
|
||||
import "os"
|
||||
|
||||
func Parse(cli interface{}) {
|
||||
parser, err := New("", "", cli)
|
||||
parser.FatalIfErrorf(err)
|
||||
err = parser.Parse(os.Args[1:])
|
||||
parser.FatalIfErrorf(err)
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package kong
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type Kong struct {
|
||||
Model *ApplicationModel
|
||||
// Termination function (defaults to os.Exit)
|
||||
Terminate func(int)
|
||||
}
|
||||
|
||||
func New(name, description string, grammar interface{}) (*Kong, error) {
|
||||
if name == "" {
|
||||
name = filepath.Base(os.Args[0])
|
||||
}
|
||||
return &Kong{
|
||||
Model: &ApplicationModel{
|
||||
Name: name,
|
||||
Description: description,
|
||||
},
|
||||
Terminate: os.Exit,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Parse arguments into target.
|
||||
func (k *Kong) Parse(args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *Kong) Errorf(format string, args ...interface{}) {
|
||||
fmt.Fprintf(os.Stderr, k.Model.Name+": "+format, args...)
|
||||
}
|
||||
|
||||
func (k *Kong) FatalIfErrorf(err error, args ...interface{}) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
msg := err.Error()
|
||||
if len(args) == 0 {
|
||||
msg = fmt.Sprintf(args[0].(string), args...) + ": " + err.Error()
|
||||
}
|
||||
k.Errorf("%s", msg)
|
||||
k.Terminate(1)
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package kong
|
||||
|
||||
import "flag"
|
||||
|
||||
type Value = flag.Getter
|
||||
|
||||
type ApplicationModel struct {
|
||||
Name string
|
||||
Description string
|
||||
|
||||
NodeModel
|
||||
}
|
||||
|
||||
type NodeModel struct {
|
||||
Groups []*GroupModel
|
||||
// Positional arguments.
|
||||
Arguments []*ArgumentModel
|
||||
}
|
||||
|
||||
type GroupModel struct {
|
||||
// Flags.
|
||||
Flags []*FlagModel
|
||||
// Command hierarchy.
|
||||
Commands []*CommandModel
|
||||
}
|
||||
|
||||
type ValueModel struct {
|
||||
Name string
|
||||
Help string
|
||||
Value flag.Value
|
||||
}
|
||||
|
||||
type CommandModel struct {
|
||||
NodeModel
|
||||
}
|
||||
|
||||
type ArgumentModel struct {
|
||||
ValueModel
|
||||
}
|
||||
|
||||
type FlagModel struct {
|
||||
ValueModel
|
||||
Short rune
|
||||
}
|
||||
Reference in New Issue
Block a user