Cli now handles printing stuff

This commit is contained in:
Sasha Koshka 2024-02-22 21:24:07 -05:00
parent 39f62a3d3f
commit 4987ed0b4d
3 changed files with 79 additions and 40 deletions

View File

@ -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)

View File

@ -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 {

View File

@ -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