Cli now handles printing stuff
This commit is contained in:
parent
39f62a3d3f
commit
4987ed0b4d
88
cli/cli.go
88
cli/cli.go
@ -1,6 +1,7 @@
|
||||
package cli
|
||||
|
||||
import "os"
|
||||
import "io"
|
||||
import "fmt"
|
||||
import "sort"
|
||||
import "errors"
|
||||
@ -11,6 +12,8 @@ import "strconv"
|
||||
// possible to create multiple Cli's to have so many sub-commands in one
|
||||
// program.
|
||||
type Cli struct {
|
||||
Logger
|
||||
|
||||
// Description describes the application.
|
||||
Description string
|
||||
|
||||
@ -49,12 +52,13 @@ func New (description string, flags ...*Flag) *Cli {
|
||||
}
|
||||
|
||||
// AddSub adds a sub-command to this command. It automatically fills out the
|
||||
// sub-command's Super field.
|
||||
// sub-command's Super field, and alters the prefix of its Logger to match.
|
||||
func (this *Cli) AddSub (name string, sub *Cli) {
|
||||
super := this.Super
|
||||
if super != "" { super += " " }
|
||||
super += name
|
||||
sub.Super = super
|
||||
sub.Super = super
|
||||
sub.Prefix = os.Args[0] + " " + super
|
||||
this.Sub[name] = sub
|
||||
}
|
||||
|
||||
@ -67,7 +71,7 @@ func (this *Cli) AddSub (name string, sub *Cli) {
|
||||
// command that did the parsing.
|
||||
func (this *Cli) Parse (args []string) (*Cli, error) {
|
||||
// try to find a sub-command
|
||||
if this.Sub != nil && len(args) > 0 {
|
||||
if this.Sub != nil && len(args) > 1 {
|
||||
if sub, ok := this.Sub[args[1]]; ok {
|
||||
return sub.Parse(args[1:])
|
||||
}
|
||||
@ -153,7 +157,7 @@ func (this *Cli) Parse (args []string) (*Cli, error) {
|
||||
func (this *Cli) ParseOrExit (args []string) *Cli {
|
||||
command, err := this.Parse(args)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s: %v\n\n", os.Args[0], err)
|
||||
fmt.Fprintf(this, "%s: %v\n\n", os.Args[0], err)
|
||||
this.Usage()
|
||||
os.Exit(2)
|
||||
}
|
||||
@ -183,25 +187,25 @@ func (this *Cli) LongFlag (long string) (*Flag, bool) {
|
||||
// Usage prints out usage/help information.
|
||||
func (this *Cli) Usage () {
|
||||
// syntax
|
||||
fmt.Fprint(os.Stderr, "Usage:")
|
||||
fmt.Fprint(os.Stderr, " ", os.Args[0])
|
||||
fmt.Fprint(this, "Usage:")
|
||||
fmt.Fprint(this, " ", os.Args[0])
|
||||
if this.Super != "" {
|
||||
fmt.Fprint(os.Stderr, " ", this.Super)
|
||||
fmt.Fprint(this, " ", this.Super)
|
||||
}
|
||||
hasSubCommands := this.Sub != nil && len(this.Sub) > 0
|
||||
if hasSubCommands {
|
||||
fmt.Fprint(os.Stderr, " [COMMAND]")
|
||||
fmt.Fprint(this, " [COMMAND]")
|
||||
}
|
||||
if this.Syntax == "" {
|
||||
fmt.Fprint(os.Stderr, " [OPTION]...")
|
||||
fmt.Fprint(this, " [OPTION]...")
|
||||
} else {
|
||||
fmt.Fprint(os.Stderr, " ", this.Syntax)
|
||||
fmt.Fprint(this, " ", this.Syntax)
|
||||
}
|
||||
fmt.Fprint(os.Stderr, "\n\n")
|
||||
fmt.Fprint(this, "\n\n")
|
||||
|
||||
// description
|
||||
if this.Description != "" {
|
||||
fmt.Fprintf(os.Stderr, "%s\n\n", this.Description)
|
||||
fmt.Fprintf(this, "%s\n\n", this.Description)
|
||||
}
|
||||
|
||||
// fit the longest flag
|
||||
@ -228,12 +232,12 @@ func (this *Cli) Usage () {
|
||||
shortLong += "--" + flag.Long
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stderr, format, shortLong, flag.Help)
|
||||
fmt.Fprintf(this, format, shortLong, flag.Help)
|
||||
}
|
||||
|
||||
// commands
|
||||
if hasSubCommands {
|
||||
fmt.Fprint(os.Stderr, "\nCommands:\n\n")
|
||||
fmt.Fprint(this, "\nCommands:\n\n")
|
||||
names := sortMapKeys(this.Sub)
|
||||
|
||||
// fit the longest command
|
||||
@ -246,11 +250,65 @@ func (this *Cli) Usage () {
|
||||
format := fmt.Sprint("\t%-", longest + 2, "s%s\n")
|
||||
|
||||
for _, name := range names {
|
||||
fmt.Fprintf(os.Stderr, format, name, this.Sub[name].Description)
|
||||
fmt.Fprintf(this, format, name, this.Sub[name].Description)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Logger prints messages to an output writer.
|
||||
type Logger struct {
|
||||
// Writer specifies the writer to output to. If it is nil, the Logger
|
||||
// will output to os.Stderr. If you wish to silence the output, set it
|
||||
// to io.Discard.
|
||||
io.Writer
|
||||
|
||||
// Debug determines whether or not debug messages will be logged.
|
||||
Debug bool
|
||||
|
||||
// Prefix is printed before all messages. If this is an empty string,
|
||||
// os.Args[0] will be used.
|
||||
Prefix string
|
||||
}
|
||||
|
||||
// Println logs a normal message.
|
||||
func (this *Logger) Println (v ...any) {
|
||||
fmt.Fprintf(this, "%s: %s", this.prefix(), fmt.Sprintln(v...))
|
||||
}
|
||||
|
||||
// Errorln logs an error message.
|
||||
func (this *Logger) Errorln (v ...any) {
|
||||
fmt.Fprintf(this, "%s: %s", this.prefix(), fmt.Sprintln(v...))
|
||||
}
|
||||
|
||||
// Warnln logs a warning.
|
||||
func (this *Logger) Warnln (v ...any) {
|
||||
fmt.Fprintf(this, "%s: warning: %s", this.prefix(), fmt.Sprintln(v...))
|
||||
}
|
||||
|
||||
// Debugln logs debugging information. It will only print the message if the
|
||||
// Debug field is set to true.
|
||||
func (this *Logger) Debugln (v ...any) {
|
||||
if !this.Debug { return }
|
||||
fmt.Fprintf(this, "%s: debug: %s", this.prefix(), fmt.Sprintln(v...))
|
||||
}
|
||||
|
||||
func (this *Logger) prefix () string {
|
||||
if this.Prefix == "" {
|
||||
return os.Args[0]
|
||||
} else {
|
||||
return this.Prefix
|
||||
}
|
||||
}
|
||||
|
||||
// Write writes to the Logger's writer. If it is nil, it writes to os.Stderr.
|
||||
func (this *Logger) Write (data []byte) (n int, err error) {
|
||||
if this.Writer == nil {
|
||||
return os.Stderr.Write(data)
|
||||
} else {
|
||||
return this.Writer.Write(data)
|
||||
}
|
||||
}
|
||||
|
||||
// Flag is a command line option.
|
||||
type Flag struct {
|
||||
Short rune // The short form of the flag (-l)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import "os"
|
||||
import "io"
|
||||
import "path/filepath"
|
||||
import "git.tebibyte.media/fspl/fspl/cli"
|
||||
import "git.tebibyte.media/fspl/fspl/entity"
|
||||
@ -11,7 +12,7 @@ func main () {
|
||||
// instantiate the compiler
|
||||
// FIXME: perhaps we want different paths on Windows?
|
||||
comp := new(compiler.Compiler)
|
||||
comp.Stderr = os.Stderr
|
||||
comp.Writer = os.Stderr
|
||||
comp.Resolver = compiler.NewResolver (
|
||||
"/usr/local/src/fspl",
|
||||
"/usr/src/fspl",
|
||||
@ -68,7 +69,7 @@ func main () {
|
||||
comp.Optimization = optimization.Value
|
||||
comp.Format = format.Value
|
||||
comp.Debug = debug.Value != ""
|
||||
comp.Quiet = quiet.Value != ""
|
||||
if quiet.Value != "" { comp.Writer = io.Discard }
|
||||
|
||||
err = comp.CompileUnit(entity.Address(application.Args[0]))
|
||||
if err != nil {
|
||||
|
@ -1,6 +1,5 @@
|
||||
package compiler
|
||||
|
||||
import "io"
|
||||
import "os"
|
||||
import "fmt"
|
||||
import "sort"
|
||||
@ -8,6 +7,7 @@ import "errors"
|
||||
import "os/exec"
|
||||
import "path/filepath"
|
||||
import "github.com/google/uuid"
|
||||
import "git.tebibyte.media/fspl/fspl/cli"
|
||||
import "git.tebibyte.media/fspl/fspl/llvm"
|
||||
import "git.tebibyte.media/fspl/fspl/lexer"
|
||||
import "git.tebibyte.media/fspl/fspl/entity"
|
||||
@ -19,12 +19,11 @@ import "git.tebibyte.media/fspl/fspl/generator/native"
|
||||
|
||||
type Compiler struct {
|
||||
Resolver
|
||||
cli.Logger
|
||||
|
||||
Output string
|
||||
Optimization string
|
||||
Format string
|
||||
Stderr io.Writer
|
||||
Debug bool
|
||||
Quiet bool
|
||||
}
|
||||
|
||||
func (this *Compiler) CompileUnit (address entity.Address) error {
|
||||
@ -353,25 +352,6 @@ func (this *Compiler) FindBackend (filetype string) (string, []string, error) {
|
||||
"or 'clang' are accessable from your PATH")
|
||||
}
|
||||
|
||||
func (this *Compiler) Errorln (v ...any) {
|
||||
if this.Quiet { return }
|
||||
if this.Stderr == nil { return }
|
||||
fmt.Fprintf(this.Stderr, "%s: %s", os.Args[0], fmt.Sprintln(v...))
|
||||
}
|
||||
|
||||
func (this *Compiler) Warnln (v ...any) {
|
||||
if this.Quiet { return }
|
||||
if this.Stderr == nil { return }
|
||||
fmt.Fprintf(this.Stderr, "%s: warning: %s", os.Args[0], fmt.Sprintln(v...))
|
||||
}
|
||||
|
||||
func (this *Compiler) Debugln (v ...any) {
|
||||
if this.Quiet { return }
|
||||
if !this.Debug { return }
|
||||
if this.Stderr == nil { return }
|
||||
fmt.Fprintf(this.Stderr, "%s: debug: %s", os.Args[0], fmt.Sprintln(v...))
|
||||
}
|
||||
|
||||
func sortMapKeys[T any] (unsorted map[string] T) []string {
|
||||
keys := make([]string, len(unsorted))
|
||||
index := 0
|
||||
|
Loading…
Reference in New Issue
Block a user