Options struct moved to options.go and dev-expr commands moved to commands.go
This commit is contained in:
parent
e30d90befb
commit
f8d83ee5b7
@ -1 +1 @@
|
|||||||
1.11.0 41
|
1.12.0 15
|
||||||
|
234
commands.go
Normal file
234
commands.go
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// commands.go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.portale-stac.it/go-pkg/expr"
|
||||||
|
"git.portale-stac.it/go-pkg/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type commandFunction func(opt *Options, ctx expr.ExprContext, args []string) (err error)
|
||||||
|
|
||||||
|
type command struct {
|
||||||
|
name string
|
||||||
|
description string
|
||||||
|
code commandFunction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *command) exec(opt *Options, ctx expr.ExprContext, args []string) (err error) {
|
||||||
|
return cmd.code(opt, ctx, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
type commandHandler struct {
|
||||||
|
cmdIndex []string
|
||||||
|
commands map[string]*command
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCommandHandler() *commandHandler {
|
||||||
|
return &commandHandler{
|
||||||
|
cmdIndex: make([]string, 0, 20),
|
||||||
|
commands: make(map[string]*command),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// func (h *commandHandler) setContext(ctx expr.ExprContext) {
|
||||||
|
// h.ctx = ctx
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (h *commandHandler) add(name, description string, f commandFunction) {
|
||||||
|
h.cmdIndex = append(h.cmdIndex, name)
|
||||||
|
h.commands[name] = &command{name: name, description: description, code: f}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *commandHandler) get(cmdLine string) (cmd *command, args []string) {
|
||||||
|
if len(cmdLine) > 0 {
|
||||||
|
tokens := strings.Split(cmdLine, " ")
|
||||||
|
name := tokens[0]
|
||||||
|
args = make([]string, 0, len(tokens)-1)
|
||||||
|
if cmd = h.commands[name]; cmd != nil && len(tokens) > 1 {
|
||||||
|
for _, tk := range tokens[1:] {
|
||||||
|
if tk != "" {
|
||||||
|
args = append(args, tk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------
|
||||||
|
var cmdHandler *commandHandler
|
||||||
|
|
||||||
|
func (h *commandHandler) help() {
|
||||||
|
fmt.Fprintln(os.Stderr, `--- REPL commands:`)
|
||||||
|
for _, name := range h.cmdIndex {
|
||||||
|
cmd := h.commands[name]
|
||||||
|
fmt.Fprintf(os.Stderr, "%12s -- %s\n", cmd.name, cmd.description)
|
||||||
|
}
|
||||||
|
fmt.Fprint(os.Stderr, `
|
||||||
|
--- Command line options:
|
||||||
|
-b <builtin> Import builtin modules.
|
||||||
|
<builtin> can be a list of module names or a glob-pattern.
|
||||||
|
Use the special value 'all' or the pattern '*' to import all modules.
|
||||||
|
-e <expression> Evaluate <expression> instead of standard-input
|
||||||
|
-i Force REPL operation when all -e occurences have been processed
|
||||||
|
-h, --help, help Show this help menu
|
||||||
|
-m, --modules List all builtin modules
|
||||||
|
--noout Disable printing of expression results
|
||||||
|
-p Print prefix form
|
||||||
|
-t Print tree form
|
||||||
|
-v, --version Show program version
|
||||||
|
`)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------
|
||||||
|
|
||||||
|
func cmdExit(opt *Options, ctx expr.ExprContext, args []string) (err error) {
|
||||||
|
return io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
func cmdHelp(opt *Options, ctx expr.ExprContext, args []string) (err error) {
|
||||||
|
cmdHandler.help()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func cmdMultiLine(opt *Options, ctx expr.ExprContext, args []string) (err error) {
|
||||||
|
if opt.formOpt&expr.MultiLine == 0 {
|
||||||
|
opt.formOpt |= expr.MultiLine
|
||||||
|
} else {
|
||||||
|
opt.formOpt &= ^expr.MultiLine
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func cmdTty(opt *Options, ctx expr.ExprContext, args []string) (err error) {
|
||||||
|
if opt.formOpt&expr.TTY == 0 {
|
||||||
|
opt.formOpt |= expr.TTY
|
||||||
|
} else {
|
||||||
|
opt.formOpt &= ^expr.TTY
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func execFile(opt *Options, ctx expr.ExprContext, fileName string) (err error) {
|
||||||
|
var fh *os.File
|
||||||
|
if fh, err = os.Open(fileName); err == nil {
|
||||||
|
goBatch(opt, ctx, fh)
|
||||||
|
fh.Close()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func cmdSource(opt *Options, ctx expr.ExprContext, args []string) (err error) {
|
||||||
|
var target string
|
||||||
|
for _, arg := range args {
|
||||||
|
if len(arg) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// TODO migliorare questa parte: eventualmente valutare un'espressione
|
||||||
|
if target, err = checkStringLiteral(arg); err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if target, err = utils.ExpandPath(target); err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if isPattern(target) {
|
||||||
|
var fileNames []string
|
||||||
|
if fileNames, err = matchPathPattern(target); err == nil {
|
||||||
|
for _, fileName := range fileNames {
|
||||||
|
if err = execFile(opt, ctx, fileName); err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = execFile(opt, ctx, target)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func cmdModules(opt *Options, ctx expr.ExprContext, args []string) (err error) {
|
||||||
|
expr.IterateBuiltinModules(func(name, description string, imported bool) bool {
|
||||||
|
var check rune = ' '
|
||||||
|
if imported {
|
||||||
|
check = '*'
|
||||||
|
}
|
||||||
|
fmt.Printf("%c %20q: %s\n", check, name, description)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func cmdBase(opt *Options, ctx expr.ExprContext, args []string) (err error) {
|
||||||
|
if len(args) == 0 {
|
||||||
|
fmt.Println(opt.base)
|
||||||
|
} else if args[0] == "2" {
|
||||||
|
opt.baseVerb = "0b%b"
|
||||||
|
opt.base = 2
|
||||||
|
} else if args[0] == "8" {
|
||||||
|
opt.baseVerb = "0o%o"
|
||||||
|
opt.base = 8
|
||||||
|
} else if args[0] == "10" {
|
||||||
|
opt.baseVerb = "%d"
|
||||||
|
opt.base = 10
|
||||||
|
} else if args[0] == "16" {
|
||||||
|
opt.baseVerb = "0x%x"
|
||||||
|
opt.base = 16
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("invalid number base %s", args[0])
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func cmdOutput(opt *Options, ctx expr.ExprContext, args []string) (err error) {
|
||||||
|
var outputArg string
|
||||||
|
if len(args) == 0 {
|
||||||
|
outputArg = "status"
|
||||||
|
} else {
|
||||||
|
outputArg = strings.ToLower(args[0])
|
||||||
|
}
|
||||||
|
switch outputArg {
|
||||||
|
case "on":
|
||||||
|
opt.output = true
|
||||||
|
case "off":
|
||||||
|
opt.output = false
|
||||||
|
case "status":
|
||||||
|
if opt.output {
|
||||||
|
fmt.Println("on")
|
||||||
|
} else {
|
||||||
|
fmt.Println("off")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("output: unknown option %q", outputArg)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------
|
||||||
|
|
||||||
|
func setupCommands() {
|
||||||
|
cmdHandler = NewCommandHandler()
|
||||||
|
cmdHandler.add("base", "Set the integer output base: 2, 8, 10, or 16", cmdBase)
|
||||||
|
cmdHandler.add("exit", "Exit the program", cmdExit)
|
||||||
|
cmdHandler.add("help", "Show command list", cmdHelp)
|
||||||
|
cmdHandler.add("ml", "Enable/Disable multi-line output", cmdMultiLine)
|
||||||
|
cmdHandler.add("mods", "List builtin modules", cmdModules)
|
||||||
|
cmdHandler.add("output", "Enable/Disable printing expression results. Options 'on', 'off', 'status'", cmdOutput)
|
||||||
|
cmdHandler.add("source", "Load a file as input", cmdSource)
|
||||||
|
cmdHandler.add("tty", "Enable/Disable ansi output", cmdTty)
|
||||||
|
}
|
347
main.go
347
main.go
@ -30,80 +30,8 @@ const (
|
|||||||
historyFile = "~/.expr_history"
|
historyFile = "~/.expr_history"
|
||||||
)
|
)
|
||||||
|
|
||||||
type commandFunction func(ctx expr.ExprContext, args []string) (err error)
|
|
||||||
|
|
||||||
type command struct {
|
|
||||||
name string
|
|
||||||
description string
|
|
||||||
code commandFunction
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cmd *command) exec(ctx expr.ExprContext, args []string) (err error) {
|
|
||||||
return cmd.code(ctx, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
type commandHandler struct {
|
|
||||||
commands map[string]*command
|
|
||||||
// ctx expr.ExprContext
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCommandHandler() *commandHandler {
|
|
||||||
return &commandHandler{
|
|
||||||
commands: make(map[string]*command),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// func (h *commandHandler) setContext(ctx expr.ExprContext) {
|
|
||||||
// h.ctx = ctx
|
|
||||||
// }
|
|
||||||
|
|
||||||
func (h *commandHandler) add(name, description string, f commandFunction) {
|
|
||||||
h.commands[name] = &command{name: name, description: description, code: f}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *commandHandler) get(cmdLine string) (cmd *command, args []string) {
|
|
||||||
if len(cmdLine) > 0 {
|
|
||||||
tokens := strings.Split(cmdLine, " ")
|
|
||||||
name := tokens[0]
|
|
||||||
args = make([]string, 0, len(tokens)-1)
|
|
||||||
if cmd = h.commands[name]; cmd != nil && len(tokens) > 1 {
|
|
||||||
for _, tk := range tokens[1:] {
|
|
||||||
if tk != "" {
|
|
||||||
args = append(args, tk)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------
|
// ------
|
||||||
|
|
||||||
type Options struct {
|
|
||||||
printTree bool
|
|
||||||
printPrefix bool
|
|
||||||
forceInteractive bool
|
|
||||||
builtin []any
|
|
||||||
expressions []io.Reader
|
|
||||||
formOpt expr.FmtOpt
|
|
||||||
baseVerb string
|
|
||||||
base int
|
|
||||||
output bool
|
|
||||||
rcCount int
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewOptions() *Options {
|
|
||||||
return &Options{
|
|
||||||
expressions: make([]io.Reader, 0),
|
|
||||||
builtin: make([]any, 0),
|
|
||||||
formOpt: expr.Base10,
|
|
||||||
baseVerb: "%d",
|
|
||||||
base: 10,
|
|
||||||
output: true,
|
|
||||||
rcCount: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func errOptValueRequired(opt string) error {
|
func errOptValueRequired(opt string) error {
|
||||||
return fmt.Errorf("option %q requires a value", opt)
|
return fmt.Errorf("option %q requires a value", opt)
|
||||||
}
|
}
|
||||||
@ -112,104 +40,6 @@ func about() string {
|
|||||||
return PROGNAME + " -- " + VERSION + "; Expr package " + EXPR_VERSION
|
return PROGNAME + " -- " + VERSION + "; Expr package " + EXPR_VERSION
|
||||||
}
|
}
|
||||||
|
|
||||||
func (opt *Options) loadRc() {
|
|
||||||
var rcPath string
|
|
||||||
var fh *os.File
|
|
||||||
var err error
|
|
||||||
if rcPath, err = utils.ExpandPath("~/.dev-expr.rc"); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if fh, err = os.Open(rcPath); err == nil {
|
|
||||||
opt.expressions = append(opt.expressions, fh)
|
|
||||||
opt.rcCount++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (opt *Options) parseArgs() (err error) {
|
|
||||||
for i := 1; i < len(os.Args) && err == nil; i++ {
|
|
||||||
arg := os.Args[i]
|
|
||||||
switch arg {
|
|
||||||
case "-i":
|
|
||||||
opt.forceInteractive = true
|
|
||||||
case "-t":
|
|
||||||
opt.printTree = true
|
|
||||||
case "-p":
|
|
||||||
opt.printPrefix = true
|
|
||||||
case "-e":
|
|
||||||
if i+1 < len(os.Args) {
|
|
||||||
i++
|
|
||||||
spec := os.Args[i]
|
|
||||||
if strings.HasPrefix(spec, "@") {
|
|
||||||
var f *os.File
|
|
||||||
if f, err = os.Open(spec[1:]); err == nil {
|
|
||||||
opt.expressions = append(opt.expressions, f)
|
|
||||||
} else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
opt.expressions = append(opt.expressions, strings.NewReader(spec))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err = errOptValueRequired(arg)
|
|
||||||
}
|
|
||||||
case "-b":
|
|
||||||
if i+1 < len(os.Args) {
|
|
||||||
i++
|
|
||||||
specs := strings.Split(os.Args[i], ",")
|
|
||||||
if len(specs) == 1 {
|
|
||||||
opt.builtin = append(opt.builtin, specs[0])
|
|
||||||
} else {
|
|
||||||
opt.builtin = append(opt.builtin, specs)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err = errOptValueRequired(arg)
|
|
||||||
}
|
|
||||||
case "-m", "--modules":
|
|
||||||
expr.IterateBuiltinModules(func(name, description string, _ bool) bool {
|
|
||||||
fmt.Printf("%20q: %s\n", name, description)
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
os.Exit(0)
|
|
||||||
case "--noout":
|
|
||||||
opt.output = false
|
|
||||||
case "-h", "--help", "help":
|
|
||||||
cmdHandler.help()
|
|
||||||
os.Exit(0)
|
|
||||||
case "-v", "--version", "version", "about":
|
|
||||||
fmt.Println(about())
|
|
||||||
os.Exit(0)
|
|
||||||
default:
|
|
||||||
err = fmt.Errorf("invalid option nr %d %q", i+1, arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------
|
|
||||||
var cmdHandler *commandHandler
|
|
||||||
|
|
||||||
func (h *commandHandler) help() {
|
|
||||||
fmt.Fprintln(os.Stderr, `--- REPL commands:`)
|
|
||||||
for _, cmd := range h.commands {
|
|
||||||
fmt.Fprintf(os.Stderr, "%12s -- %s\n", cmd.name, cmd.description)
|
|
||||||
}
|
|
||||||
fmt.Fprint(os.Stderr, `
|
|
||||||
--- Command line options:
|
|
||||||
-b <builtin> Import builtin modules.
|
|
||||||
<builtin> can be a list of module names or a glob-pattern.
|
|
||||||
Use the special value 'all' or the pattern '*' to import all modules.
|
|
||||||
-e <expression> Evaluate <expression> instead of standard-input
|
|
||||||
-i Force REPL operation when all -e occurences have been processed
|
|
||||||
-h, --help, help Show this help menu
|
|
||||||
-m, --modules List all builtin modules
|
|
||||||
--noout Disable printing of expression results
|
|
||||||
-p Print prefix form
|
|
||||||
-t Print tree form
|
|
||||||
-v, --version Show program version
|
|
||||||
`)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func importBuiltins(opt *Options) (err error) {
|
func importBuiltins(opt *Options) (err error) {
|
||||||
for _, spec := range opt.builtin {
|
for _, spec := range opt.builtin {
|
||||||
if moduleSpec, ok := spec.(string); ok {
|
if moduleSpec, ok := spec.(string); ok {
|
||||||
@ -266,7 +96,7 @@ func goInteractiveReadline(opt *Options, ctx expr.ExprContext, r io.Reader) {
|
|||||||
if source != "" && !strings.HasPrefix(source, "//") {
|
if source != "" && !strings.HasPrefix(source, "//") {
|
||||||
if cmd, args := cmdHandler.get(source); cmd != nil {
|
if cmd, args := cmdHandler.get(source); cmd != nil {
|
||||||
rl.SaveToHistory(source)
|
rl.SaveToHistory(source)
|
||||||
if err = cmd.exec(ctx, args); err != nil {
|
if err = cmd.exec(opt, ctx, args); err != nil {
|
||||||
fmt.Fprintln(os.Stderr, "Eval Error:", err)
|
fmt.Fprintln(os.Stderr, "Eval Error:", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -296,7 +126,7 @@ func goInteractive(opt *Options, ctx expr.ExprContext, r io.Reader) {
|
|||||||
// fmt.Printf("source=%q\n", source)
|
// fmt.Printf("source=%q\n", source)
|
||||||
if source != "" && !strings.HasPrefix(source, "//") {
|
if source != "" && !strings.HasPrefix(source, "//") {
|
||||||
if cmd, args := cmdHandler.get(source); cmd != nil {
|
if cmd, args := cmdHandler.get(source); cmd != nil {
|
||||||
if err = cmd.exec(ctx, args); err != nil {
|
if err = cmd.exec(opt, ctx, args); err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -323,7 +153,7 @@ func goBatch(opt *Options, ctx expr.ExprContext, r io.Reader) {
|
|||||||
// fmt.Printf("source=%q\n", source)
|
// fmt.Printf("source=%q\n", source)
|
||||||
if source != "" && !strings.HasPrefix(source, "//") {
|
if source != "" && !strings.HasPrefix(source, "//") {
|
||||||
if cmd, args := cmdHandler.get(source); cmd != nil {
|
if cmd, args := cmdHandler.get(source); cmd != nil {
|
||||||
if err = cmd.exec(ctx, args); err != nil {
|
if err = cmd.exec(opt, ctx, args); err != nil {
|
||||||
fmt.Fprintln(os.Stderr, "Eval Error:", err)
|
fmt.Fprintln(os.Stderr, "Eval Error:", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -456,10 +286,9 @@ func registerLocalFunctions(ctx expr.ExprContext) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var opt *Options
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
opt = NewOptions()
|
setupCommands()
|
||||||
|
opt := NewOptions()
|
||||||
opt.loadRc()
|
opt.loadRc()
|
||||||
if err := opt.parseArgs(); err != nil {
|
if err := opt.parseArgs(); err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, err)
|
||||||
@ -492,169 +321,3 @@ func main() {
|
|||||||
printResult(opt, ctx.GetLast())
|
printResult(opt, ctx.GetLast())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------
|
|
||||||
|
|
||||||
func cmdExit(ctx expr.ExprContext, args []string) (err error) {
|
|
||||||
return io.EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdHelp(ctx expr.ExprContext, args []string) (err error) {
|
|
||||||
cmdHandler.help()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdMultiLine(ctx expr.ExprContext, args []string) (err error) {
|
|
||||||
if opt.formOpt&expr.MultiLine == 0 {
|
|
||||||
opt.formOpt |= expr.MultiLine
|
|
||||||
} else {
|
|
||||||
opt.formOpt &= ^expr.MultiLine
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdTty(ctx expr.ExprContext, args []string) (err error) {
|
|
||||||
if opt.formOpt&expr.TTY == 0 {
|
|
||||||
opt.formOpt |= expr.TTY
|
|
||||||
} else {
|
|
||||||
opt.formOpt &= ^expr.TTY
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func execFile(ctx expr.ExprContext, fileName string) (err error) {
|
|
||||||
var fh *os.File
|
|
||||||
if fh, err = os.Open(fileName); err == nil {
|
|
||||||
goBatch(opt, ctx, fh)
|
|
||||||
fh.Close()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdSource(ctx expr.ExprContext, args []string) (err error) {
|
|
||||||
var target string
|
|
||||||
for _, arg := range args {
|
|
||||||
if len(arg) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// TODO migliorare questa parte: eventualmente valutare un'espressione
|
|
||||||
if target, err = checkStringLiteral(arg); err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if target, err = utils.ExpandPath(target); err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if isPattern(target) {
|
|
||||||
var fileNames []string
|
|
||||||
if fileNames, err = matchPathPattern(target); err == nil {
|
|
||||||
for _, fileName := range fileNames {
|
|
||||||
if err = execFile(ctx, fileName); err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err = execFile(ctx, target)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func _cmdSource(ctx expr.ExprContext, args []string) (err error) {
|
|
||||||
var fh *os.File
|
|
||||||
for _, arg := range args {
|
|
||||||
length := len(arg)
|
|
||||||
if length == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if length >= 2 {
|
|
||||||
if (arg[0] == '"' && arg[length-1] == '"') || arg[0] == '\'' && arg[length-1] == '\'' {
|
|
||||||
arg = arg[1 : length-1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if fh, err = os.Open(arg); err == nil {
|
|
||||||
goBatch(opt, ctx, fh)
|
|
||||||
fh.Close()
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdModules(ctx expr.ExprContext, args []string) (err error) {
|
|
||||||
expr.IterateBuiltinModules(func(name, description string, imported bool) bool {
|
|
||||||
var check rune = ' '
|
|
||||||
if imported {
|
|
||||||
check = '*'
|
|
||||||
}
|
|
||||||
fmt.Printf("%c %20q: %s\n", check, name, description)
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdBase(ctx expr.ExprContext, args []string) (err error) {
|
|
||||||
if len(args) == 0 {
|
|
||||||
fmt.Println(opt.base)
|
|
||||||
} else if args[0] == "2" {
|
|
||||||
opt.baseVerb = "0b%b"
|
|
||||||
opt.base = 2
|
|
||||||
} else if args[0] == "8" {
|
|
||||||
opt.baseVerb = "0o%o"
|
|
||||||
opt.base = 8
|
|
||||||
} else if args[0] == "10" {
|
|
||||||
opt.baseVerb = "%d"
|
|
||||||
opt.base = 10
|
|
||||||
} else if args[0] == "16" {
|
|
||||||
opt.baseVerb = "0x%x"
|
|
||||||
opt.base = 16
|
|
||||||
} else {
|
|
||||||
err = fmt.Errorf("invalid number base %s", args[0])
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdOutput(ctx expr.ExprContext, args []string) (err error) {
|
|
||||||
var outputArg string
|
|
||||||
if len(args) == 0 {
|
|
||||||
outputArg = "status"
|
|
||||||
} else {
|
|
||||||
outputArg = strings.ToLower(args[0])
|
|
||||||
}
|
|
||||||
switch outputArg {
|
|
||||||
case "on":
|
|
||||||
opt.output = true
|
|
||||||
case "off":
|
|
||||||
opt.output = false
|
|
||||||
case "status":
|
|
||||||
if opt.output {
|
|
||||||
fmt.Println("on")
|
|
||||||
} else {
|
|
||||||
fmt.Println("off")
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
err = fmt.Errorf("output: unknown option %q", outputArg)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
cmdHandler = NewCommandHandler()
|
|
||||||
cmdHandler.add("base", "Set the integer output base: 2, 8, 10, or 16", cmdBase)
|
|
||||||
cmdHandler.add("exit", "Exit the program", cmdExit)
|
|
||||||
cmdHandler.add("help", "Show command list", cmdHelp)
|
|
||||||
cmdHandler.add("ml", "Enable/Disable multi-line output", cmdMultiLine)
|
|
||||||
cmdHandler.add("mods", "List builtin modules", cmdModules)
|
|
||||||
cmdHandler.add("output", "Enable/Disable printing expression results. Options 'on', 'off', 'status'", cmdOutput)
|
|
||||||
cmdHandler.add("source", "Load a file as input", cmdSource)
|
|
||||||
cmdHandler.add("tty", "Enable/Disable ansi output", cmdTty)
|
|
||||||
}
|
|
||||||
|
113
options.go
Normal file
113
options.go
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// options.go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.portale-stac.it/go-pkg/expr"
|
||||||
|
"git.portale-stac.it/go-pkg/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Options struct {
|
||||||
|
printTree bool
|
||||||
|
printPrefix bool
|
||||||
|
forceInteractive bool
|
||||||
|
builtin []any
|
||||||
|
expressions []io.Reader
|
||||||
|
formOpt expr.FmtOpt
|
||||||
|
baseVerb string
|
||||||
|
base int
|
||||||
|
output bool
|
||||||
|
rcCount int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOptions() *Options {
|
||||||
|
return &Options{
|
||||||
|
expressions: make([]io.Reader, 0),
|
||||||
|
builtin: make([]any, 0),
|
||||||
|
formOpt: expr.Base10,
|
||||||
|
baseVerb: "%d",
|
||||||
|
base: 10,
|
||||||
|
output: true,
|
||||||
|
rcCount: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opt *Options) loadRc() {
|
||||||
|
var rcPath string
|
||||||
|
var fh *os.File
|
||||||
|
var err error
|
||||||
|
if rcPath, err = utils.ExpandPath("~/.dev-expr.rc"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if fh, err = os.Open(rcPath); err == nil {
|
||||||
|
opt.expressions = append(opt.expressions, fh)
|
||||||
|
opt.rcCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opt *Options) parseArgs() (err error) {
|
||||||
|
for i := 1; i < len(os.Args) && err == nil; i++ {
|
||||||
|
arg := os.Args[i]
|
||||||
|
switch arg {
|
||||||
|
case "-i":
|
||||||
|
opt.forceInteractive = true
|
||||||
|
case "-t":
|
||||||
|
opt.printTree = true
|
||||||
|
case "-p":
|
||||||
|
opt.printPrefix = true
|
||||||
|
case "-e":
|
||||||
|
if i+1 < len(os.Args) {
|
||||||
|
i++
|
||||||
|
spec := os.Args[i]
|
||||||
|
if strings.HasPrefix(spec, "@") {
|
||||||
|
var f *os.File
|
||||||
|
if f, err = os.Open(spec[1:]); err == nil {
|
||||||
|
opt.expressions = append(opt.expressions, f)
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
opt.expressions = append(opt.expressions, strings.NewReader(spec))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = errOptValueRequired(arg)
|
||||||
|
}
|
||||||
|
case "-b":
|
||||||
|
if i+1 < len(os.Args) {
|
||||||
|
i++
|
||||||
|
specs := strings.Split(os.Args[i], ",")
|
||||||
|
if len(specs) == 1 {
|
||||||
|
opt.builtin = append(opt.builtin, specs[0])
|
||||||
|
} else {
|
||||||
|
opt.builtin = append(opt.builtin, specs)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = errOptValueRequired(arg)
|
||||||
|
}
|
||||||
|
case "-m", "--modules":
|
||||||
|
expr.IterateBuiltinModules(func(name, description string, _ bool) bool {
|
||||||
|
fmt.Printf("%20q: %s\n", name, description)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
os.Exit(0)
|
||||||
|
case "--noout":
|
||||||
|
opt.output = false
|
||||||
|
case "-h", "--help", "help":
|
||||||
|
cmdHandler.help()
|
||||||
|
os.Exit(0)
|
||||||
|
case "-v", "--version", "version", "about":
|
||||||
|
fmt.Println(about())
|
||||||
|
os.Exit(0)
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("invalid option nr %d %q", i+1, arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
@ -1 +1 @@
|
|||||||
1.11.0
|
1.12.0
|
||||||
|
Loading…
Reference in New Issue
Block a user