summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Carr <[email protected]>2025-10-25 08:26:54 -0500
committerJeff Carr <[email protected]>2025-10-25 08:26:54 -0500
commitb95f2cab06e5de8fec71b0b991777f5d5cb1fa90 (patch)
tree821deba3f06e10e908a9f3990e434bf47b5da022
parent31e1d6afbe3ad9e39d0f0115b1ae3ddb0bb5de64 (diff)
isolate history handling
-rw-r--r--argv.Print.go25
-rw-r--r--argv.SendStrings.go1
-rw-r--r--argv.proto13
-rw-r--r--makeAutocompleteFiles.bash.go4
-rw-r--r--structs.go3
-rw-r--r--theMagicOfAutocomplete.go163
6 files changed, 121 insertions, 88 deletions
diff --git a/argv.Print.go b/argv.Print.go
index 368cf7b..bb1de4a 100644
--- a/argv.Print.go
+++ b/argv.Print.go
@@ -23,20 +23,17 @@ func Debugf(fmts string, parts ...any) {
}
// print out auto complete debugging info
-func (pb *Argv) PrintDebug() {
- pb.PrintDebugNew("ARGV")
+func (pb *Argv) PrintDebug(last string) {
+ pb.PrintDebugNew("ARGV", last)
}
-func (pb *Argv) PrintDebugNew(msg string) {
+func (pb *Argv) PrintDebugNew(msg string, last string) {
cmd := fmt.Sprintf("cmd='%s'", pb.GetCmd())
var arglast string
- if me.last == nil {
- arglast = fmt.Sprintf("last='%s'", "<nil>")
- } else {
- arglast = fmt.Sprintf("last='%s'", me.last.GetCmd())
- }
+ arglast = fmt.Sprintf("last='%s'", last)
partial := fmt.Sprintf("p='%s'", pb.Partial)
- dur := cobol.Duration(pb.Ctime)
+ age := cobol.Duration(pb.Ctime)
+ dur := cobol.Duration(pb.Duration)
var fast string
if pb.Fast {
fast = "fast=1," + pb.GetCmd()
@@ -44,12 +41,16 @@ func (pb *Argv) PrintDebugNew(msg string) {
fast = "fast=0," + pb.GetCmd()
}
sargv := fmt.Sprintf("argv(%v)", pb.Real)
- Debugf("%s: age=(%s) %-12.12s %-12.12s %-12.12s %s %s goargs='%v' len(%d)", msg, dur, cmd, arglast, partial, fast, sargv, pb.Goargs, me.all.Len())
+ top := fmt.Sprintf("age=(%s)dur(%s)%-4.4s %-12.12s %-12.12s", age, dur, pb.Uuid, cmd, arglast)
+ Debugf("%s: %s %-12.12s %s %s goargs='%v' len(%d)", msg, top, partial, fast, sargv, pb.Goargs, me.all.Len())
}
-func (all *Argvs) PrintHistory() {
+func (all *Argvs) PrintHistory(last string) {
+ counter := 0
for pb := range all.IterAll() {
- pb.PrintDebugNew("HIST")
+ counter += 1
+ hist := fmt.Sprintf("HIST(%d)", counter)
+ pb.PrintDebugNew(hist, last)
}
}
diff --git a/argv.SendStrings.go b/argv.SendStrings.go
index c890608..4e074e0 100644
--- a/argv.SendStrings.go
+++ b/argv.SendStrings.go
@@ -56,7 +56,6 @@ func (pb *Argv) SubCommand(cmd ...string) {
// me.pp.GetUsageForSubcommand(Stdout, Stderr, partial, cmd)
// me.pp.GetUsageForSubcommand(Stdout, nil, partial, cmd)
} else {
- // last working: f, _ := os.OpenFile("/tmp/outlook", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
// last working: me.writeHelpForAutocomplete(f, Stdout, partial, cmd...)
me.writeHelpForAutocompleteFunc(partial, cmd...)
}
diff --git a/argv.proto b/argv.proto
index a67a896..3cf85b9 100644
--- a/argv.proto
+++ b/argv.proto
@@ -14,11 +14,11 @@ message App {
}
message StructEntry {
- string structName = 2; // 'Force', 'Verbose', 'SortCmd'
- string structType = 3; // 'string', 'int', '[]string', '*FindCmd'
- string defaultVal = 4; // "true"
- string helpText = 5; // "This will help you"
- string matchText = 6; // "--help-me
+ string structName = 1; // 'Force', 'Verbose', 'SortCmd'
+ string structType = 2; // 'string', 'int', '[]string', '*FindCmd'
+ string defaultVal = 3; // "true"
+ string helpText = 4; // "This will help you"
+ string matchText = 5; // "--help-me
}
message ArgTree {
@@ -39,11 +39,12 @@ message Argv { // `autogenpb:marshal
string stdout = 10; // all output is loaded here before being sent to the shell
string stderr = 11; // all output is loaded here before being sent to the shell
int32 helpCounter = 12; // counter to track if the help text has been sent to Stderr
+ string uuid = 13; // all output is loaded here before being sent to the shell
}
message Argvs { // `autogenpb:marshal` `autogenpb:sort` `autogenpb:nomutex`
string uuid = 1; // `autogenpb:uuid:1e6e765c-0c77-4c81-a622-0d819bfcce9a`
- string version = 2; // `autogenpb:version:v0.0.3`
+ string version = 2; // `autogenpb:version:v0.0.4`
repeated Argv argvs = 3;
string filename = 4; // `autogenpb:save` -- this enables autogenerated pb.Load() and pb.Save()
}
diff --git a/makeAutocompleteFiles.bash.go b/makeAutocompleteFiles.bash.go
index 259d795..45be925 100644
--- a/makeAutocompleteFiles.bash.go
+++ b/makeAutocompleteFiles.bash.go
@@ -26,10 +26,10 @@ func MakeBashCompleteFiles(argname string) {
}
basedir, _ := filepath.Split(filename)
if !config.IsDir(basedir) {
- os.MkdirAll(basedir, os.ModePerm)
+ os.MkdirAll(basedir, 0755)
}
- if f, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err == nil {
+ if f, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644); err == nil {
f.Write([]byte(makeBashCompletionText2(argname)))
f.Close()
} else {
diff --git a/structs.go b/structs.go
index c406e8f..f43b154 100644
--- a/structs.go
+++ b/structs.go
@@ -6,7 +6,7 @@ var me *AutoArgs
// this is a work in progress
type AutoArgs struct {
pb *Argv // the protobuf for the current process
- all *Argvs // the protobuf for the current process
+ all *Argvs // the history of argv
last *Argv // the pb from the last time the user tried autocomplete
id int // should be unique
Argv func([]string) // the function for shell autocomplete
@@ -27,5 +27,4 @@ type AutoArgs struct {
debug bool // is dubugging on?
setupAuto bool // do shell autocomplete setup
isAuto bool // try to do autocomplete
-
}
diff --git a/theMagicOfAutocomplete.go b/theMagicOfAutocomplete.go
index 9c9010b..0e92af3 100644
--- a/theMagicOfAutocomplete.go
+++ b/theMagicOfAutocomplete.go
@@ -10,6 +10,7 @@ import (
"strings"
"time"
+ "github.com/google/uuid"
"go.wit.com/lib/cobol"
"go.wit.com/lib/config"
"go.wit.com/lib/env"
@@ -24,6 +25,7 @@ import (
func Autocomplete(dest any) *Argv {
me = new(AutoArgs) // todo: redo this
me.pb = new(Argv)
+ me.pb.Uuid = uuid.New().String()
// set the start time of the binary
now := time.Now()
@@ -42,28 +44,8 @@ func Autocomplete(dest any) *Argv {
// initializes the lib/env library
env.Init(me.pb.AppInfo.APPNAME, me.pb.AppInfo.VERSION, cobol.Time(me.pb.AppInfo.BUILDTIME), me.pb.Real, GoodExit, BadExit)
- // loads the argv autocomplete history file
- me.all = NewArgvs()
- me.Err = config.CreateCacheDirPB(me.all, "argv", me.pb.AppInfo.APPNAME)
- if me.Err == nil {
- me.all.PrintHistory()
- } else {
- // there is no history.
- // todo: initialize the history file
- // todo: check if this is automatically done already
- //
- // ALWAYS KEEP THESE LINES AND THE panic()
- //
- // They are needed to debug autocomplete.
- //
- // This code is only executed when the user is hitting tab in the shell,
- // so this panic() is safe and can never be triggered by normal program execution.
- //
- me.debug = true
- me.pb.Stderr += fmt.Sprintf("config.CreateCacheDirPB() err(%v)\n", me.Err)
- me.pb.PrintStderr()
- panic("argvpb.Load() history file failed")
- }
+ // open the argv cache history file to figure out the timing
+ examineArgvHistory()
// try to register bash args for go-args
// arg.Register(&ArgvBash)
@@ -79,10 +61,10 @@ func Autocomplete(dest any) *Argv {
// user is trying to setup bash or zsh autocomplete
// --bash or --zsh is the first os.Args
if me.setupAuto {
- savePB()
// --bash or --zsh was passed. try to configure bash-completion
MakeAutocompleteFiles(me.pb.AppInfo.APPNAME)
// never forget to exit here or you will hate yourself and the choices you have made
+ savePB()
saveAndExit()
}
@@ -97,64 +79,41 @@ func Autocomplete(dest any) *Argv {
// do autocomplete and exit
savePB()
doAutocomplete()
- // todo: this never gets here. fix that
+ panic("blah")
+ savePB()
saveAndExit()
}
// not autocompleting. return to the application
// save the pb & history
- me.all.Clone(me.pb)
- errors.Join(me.Err, me.all.Save())
-
+ savePB()
// me.pp = arg.MustParse(dest)
me.Err = errors.Join(me.Err, me.mustParseFunc())
return me.pb
}
-// prints what is needed to Stdout & Stderr, then exits
-// EVERYTHING PAST HERE IS FOR AUTOCOMPLETE
+// doAutocomplete(): print what is needed to Stdout & Stderr, then exit
+//
// everything sent to STDOUT and STDERR matters past this point
+// any "junk" output, hidden fmt(), print() or log() statements are bad
func doAutocomplete() {
- // set the duration since the last auto complete
- // find the last entry. this is dumb way to do it
- me.last = new(Argv)
- me.last.Ctime = timestamppb.New(time.Now().Add(-time.Second))
- for found := range me.all.IterAll() {
- me.last = found
+ if me.last.Fast {
+ // user is probably holding down the <TAB> key
+ me.debug = true
+ // me.fastcmd = me.pb.GetCmd()
+ if me.pb.GetCmd() != me.last.GetCmd() {
+ // do the smart something here
+ // probably debug == true && printStderr()
+ }
}
- dur := time.Since(me.last.Ctime.AsTime())
- me.pb.Duration = durationpb.New(dur)
if me.debug {
// dump debug info
- me.pb.PrintDebug()
- me.all.PrintHistory()
+ me.pb.PrintDebug(me.last.GetCmd())
+ // me.all.PrintHistory()
// me.pb.PrintStderr()
}
- // roll the autocomplete file
- if me.all.Len() > 15 {
- me.pb.Debugf("DEBUG: trim() history is over 100 len=%d vs new=%d", me.all.Len(), me.all.Len()-90)
- me.all.Argvs = me.all.Argvs[me.all.Len()-10:]
- // newall.Autos = me.all.Autos[0:10]
- // for _, found := range me.all.Autos[0:10] {
- // newall.Append(found)
- // }
- }
-
- // turn on debugging if duration < 200 milliseconds
- dur = me.pb.Duration.AsDuration()
- if dur < time.Millisecond*200 {
- me.debug = true
- me.pb.Fast = true
- // me.fastcmd = me.pb.GetCmd()
- if me.last.Fast {
- if me.pb.GetCmd() == me.last.GetCmd() {
- // do the smart something here
- }
- }
- }
-
flags := []string{}
for _, s := range me.pb.Real {
if s == "--autodebug" {
@@ -186,9 +145,10 @@ func doAutocomplete() {
me.pb.Debugf("DEBUG: real=(%v) found --gui", me.pb.Real)
me.pb.PrintStderr()
me.pb.SendString("andlabs gogui")
+ savePB()
saveAndExit()
} else {
- // me.pb.Debugf("DEBUG: NO MATCH last='%s' found key '%s' = %s", me.last, key, val)
+ // me.pb.Debugf("DEBUG: NO MATCH last='%s' found key '%s' = %s", last, key, val)
}
}
@@ -224,6 +184,7 @@ func doAutocomplete() {
if me.pb.HelpCounter < 3 {
me.pb.PrintStderr()
} else {
+ savePB()
saveAndExit()
}
} else {
@@ -249,16 +210,88 @@ func doAutocomplete() {
// if not, send "reset bash newline\n" to cause bash to redraw PS1 for the user
}
}
+ savePB()
saveAndExit()
}
func savePB() {
// save now. this is near the end probably
- me.all.Clone(me.pb)
+ me.all.Append(me.pb)
+ npb := new(Argv)
+ // npb.Uuid = uuid.New().String()
+ me.all.Append(npb)
errors.Join(me.Err, me.all.Save())
}
func saveAndExit() {
- savePB()
os.Exit(0)
}
+
+// sets me.last
+// computes me.pb.Duration
+func examineArgvHistory() {
+ me.all = NewArgvs()
+ // loads the argv autocomplete history file
+ me.Err = config.ForceCreateCacheDirPB(me.all, "argv", me.pb.AppInfo.APPNAME)
+ if me.Err != nil {
+ // there is no history.
+ // ALWAYS KEEP THESE LINES AND THE panic()
+ // They are needed to debug autocomplete.
+ //
+ // This code is only executed when the user is hitting tab in the shell,
+ // so this panic() is safe and can never be triggered by normal program execution.
+ //
+ me.debug = true
+ me.pb.Stderr += fmt.Sprintf("config.CreateCacheDirPB() err(%v)\n", me.Err)
+ me.pb.PrintStderr()
+ panic("argvpb.Load() history file failed")
+ }
+ me.all.PrintHistory("<?>")
+ if me.all.Len() > 0 {
+ last := me.all.Argvs[me.all.Len()-1]
+ me.pb.Debugf("DEBUG LAST %v", last)
+ }
+ // roll the autocomplete file
+ maxsize := 17
+ trim := 10
+ if me.all.Len() > maxsize {
+ me.pb.Debugf("DEBUG: trim() history is over 17 len=%d vs new=%d", me.all.Len(), me.all.Len()-trim)
+ me.pb.Debugf("DEBUG: trim() history is over 17 len=%d vs new=%d", me.all.Len(), me.all.Len()-trim)
+ me.pb.Debugf("DEBUG: trim() history is over 17 len=%d vs new=%d", me.all.Len(), me.all.Len()-trim)
+ me.all.Argvs = me.all.Argvs[me.all.Len()-trim:]
+ // newall.Autos = me.all.Autos[0:10]
+ }
+
+ counter := 0
+ for pb := range me.all.IterAll() {
+ counter += 1
+ if pb.Ctime == nil {
+ me.all.Delete(pb)
+ continue
+ }
+ hist := fmt.Sprintf("HISTNIL(%d)", counter)
+ pb.PrintDebugNew(hist, "jwc")
+ }
+ if me.all.Len() == 0 {
+ me.pb.PrintStderr()
+ // todo: make a blak entry here
+ panic("examineArgvHistory() couldn't find a valid last entry")
+ }
+ me.last = me.all.Argvs[me.all.Len()-1]
+
+ // compute the duration since the last time
+ dur := time.Since(me.last.Ctime.AsTime())
+ me.pb.Duration = durationpb.New(dur)
+
+ // turn on debugging if duration < 200 milliseconds
+ if me.pb.Duration.AsDuration() < time.Millisecond*200 {
+ me.debug = true
+ me.pb.Fast = true
+ // me.fastcmd = me.pb.GetCmd()
+ if me.last.Fast {
+ if me.pb.GetCmd() != me.last.GetCmd() {
+ // do the smart something here
+ }
+ }
+ }
+}