From d850e50003e93b21f762ce0bed34b85e646d2166 Mon Sep 17 00:00:00 2001
From: Kevin Lyda <kevin@lyda.ie>
Date: Tue, 6 May 2025 18:14:29 +0100
Subject: [PATCH] Some readline cleanup

---
 NOTES.md             |  5 ++++-
 accounts/accounts.go |  2 +-
 dclish/dclish.go     | 10 +++++-----
 repl/help.go         |  2 +-
 repl/misc.go         | 13 ++++---------
 repl/repl.go         | 21 +++++++++++++++++----
 6 files changed, 32 insertions(+), 21 deletions(-)

diff --git a/NOTES.md b/NOTES.md
index d33a485..4ef9374 100644
--- a/NOTES.md
+++ b/NOTES.md
@@ -16,11 +16,14 @@ Look up how godoc does references to other things.
 
 Look up how to run migrations on the db from embedded files.
 
+Figure out readline completion.  Case sensitive - issue?  Building from
+repl.commands?
+
 ## Things to do
 
   * Implement a better dclish parser.
   * Implement each command.
-    * Next: HELP - move some commands to a Help array.
+    * Next: ????
   * Decide on how the boards are managed.
 
 ## Module links
diff --git a/accounts/accounts.go b/accounts/accounts.go
index 11e68a4..acd5b25 100644
--- a/accounts/accounts.go
+++ b/accounts/accounts.go
@@ -51,7 +51,7 @@ func Open(acc string) error {
 	if err != nil {
 		return errors.New("account preference directory problem")
 	}
-	User.pref, err = sql.Open("sqlite", path.Join(prefdir, acc, ".db"))
+	User.pref, err = sql.Open("sqlite", path.Join(prefdir, fmt.Sprintf("%s.%s", acc, ".db")))
 	if err != nil {
 		return errors.New("account preference database problem")
 	}
diff --git a/dclish/dclish.go b/dclish/dclish.go
index 07d4a13..57aa8aa 100644
--- a/dclish/dclish.go
+++ b/dclish/dclish.go
@@ -22,11 +22,11 @@ type Flags map[string]*Flag
 
 // Command contains the definition of a command, it's flags and subcommands.
 type Command struct {
-	Flags Flags
-	// TODO: FlagOrder []string
-	Args []string
-	// TODO: MaxArgs int
-	// TODO: MinArgs int
+	Flags       Flags
+	FlagOrder   []string
+	Args        []string
+	MaxArgs     int
+	MinArgs     int
 	Commands    []*Command
 	Action      ActionFunc
 	Description string
diff --git a/repl/help.go b/repl/help.go
index b2beca9..490c80d 100644
--- a/repl/help.go
+++ b/repl/help.go
@@ -52,7 +52,7 @@ use is to create a folder for posting SYSTEM messages only meant for a
 certain UIC group.  This is done by creating a PRIVATE SYSTEM folder, and
 giving access to that UIC group.  Only users in that UIC group will see
 the messages in that folder when they log in.`,
-	"Ctrl-C": `Except for when BULLETIN is awaiting input from the terminal, a 
+	"CTRL-C": `Except for when BULLETIN is awaiting input from the terminal, a 
 CTRL-C will cause BULLETIN to abort the execution of any command.  If
 BULLETIN is waiting for terminal input, a CTRL-C will cause BULLETIN
 to return to the BULLETIN> prompt.  If for some reason the user wishes
diff --git a/repl/misc.go b/repl/misc.go
index f8bb289..a5b62f3 100644
--- a/repl/misc.go
+++ b/repl/misc.go
@@ -2,8 +2,7 @@
 package repl
 
 import (
-	"fmt"
-	"os"
+	"errors"
 
 	"git.lyda.ie/kevin/bulletin/accounts"
 	"git.lyda.ie/kevin/bulletin/dclish"
@@ -12,17 +11,13 @@ import (
 // ActionQuit handles the `QUIT` command.
 func ActionQuit(_ *dclish.Command) error {
 	accounts.User.Close()
-	fmt.Println("QUIT")
-	// TODO: IIRC, quit should not update unread data.  Check.
-	os.Exit(0)
-	return nil
+	// TODO: IIRC, quit should not update unread data.  Check old code to confirm.
+	return errors.New("QUIT")
 }
 
 // ActionExit handles the `EXIT` command.
 func ActionExit(_ *dclish.Command) error {
 	accounts.User.Close()
-	fmt.Println("EXIT")
 	// TODO: update unread data.
-	os.Exit(0)
-	return nil
+	return errors.New("EXIT")
 }
diff --git a/repl/repl.go b/repl/repl.go
index 9668360..0f35366 100644
--- a/repl/repl.go
+++ b/repl/repl.go
@@ -3,14 +3,24 @@ package repl
 
 import (
 	"fmt"
+	"path"
 
+	"github.com/adrg/xdg"
 	"github.com/chzyer/readline"
 )
 
 // Loop is the main event loop.
 func Loop(user string) error {
-	fmt.Printf("TODO: get config for user %s using xdg.", user)
-	rl, err := readline.New("BULLETIN> ")
+	fmt.Printf("TODO: get config for user %s using xdg.\n", user)
+	rl, err := readline.NewEx(
+		&readline.Config{
+			Prompt:      "BULLETIN> ",
+			HistoryFile: path.Join(xdg.ConfigHome, "BULLETIN", fmt.Sprintf("%s.history", user)),
+			// TODO: AutoComplete:    completer,
+			InterruptPrompt:   "^C",
+			EOFPrompt:         "EXIT",
+			HistorySearchFold: true,
+		})
 	if err != nil {
 		return err
 	}
@@ -19,6 +29,11 @@ func Loop(user string) error {
 	for {
 		line, err := rl.Readline()
 		if err != nil {
+			if err.Error() == "Interrupt" {
+				commands.ParseAndRun("QUIT")
+			} else if err.Error() == "EOF" {
+				commands.ParseAndRun("EXIT")
+			}
 			return err
 		}
 		if len(line) == 0 {
@@ -29,6 +44,4 @@ func Loop(user string) error {
 			return err
 		}
 	}
-
-	return nil
 }
-- 
GitLab