From 4b3aca124e0aab537e94d4d1582a093fa5d24dcb Mon Sep 17 00:00:00 2001 From: raven Date: Sun, 22 Mar 2026 12:13:36 -0500 Subject: move console handling into its own file --- cmd/metronode/console.go | 104 +++++++++++++++++++++++++++++++++++++++++++++++ cmd/metronode/main.go | 97 ------------------------------------------- 2 files changed, 104 insertions(+), 97 deletions(-) create mode 100644 cmd/metronode/console.go diff --git a/cmd/metronode/console.go b/cmd/metronode/console.go new file mode 100644 index 0000000..f82da45 --- /dev/null +++ b/cmd/metronode/console.go @@ -0,0 +1,104 @@ +package main + +import ( + "io" + "os" + "strings" + "sync/atomic" + "golang.org/x/term" + "git.citrons.xyz/metronode/server" +) + +type console struct { + input atomic.Pointer[string] + termState *term.State +} + +func initConsole() (cons console, err error) { + var input string + cons.input.Store(&input) + cons.termState, err = term.MakeRaw(int(os.Stdin.Fd())) + if err != nil { + return + } + cons.showInput() + return +} + +func (c *console) Close() error { + c.input.Store(nil) + term.Restore(int(os.Stdin.Fd()), c.termState) + os.Stdout.Write([]byte("\n")) + return nil +} + +func (c *console) Read(p []byte) (n int, err error) { + input := c.input.Load() + if input == nil { + return 0, io.EOF + } + n, err = os.Stdin.Read(p) + if err != nil { + return + } + var sb strings.Builder + for _, c := range p[:n] { + if c == '\r' { + c = '\n' + } + if c >= 32 || c == '\n' { + sb.WriteByte(c) + } + } + s := sb.String() + newline := strings.LastIndex(s, "\n") + if newline != -1 { + s = s[newline + 1:] + c.input.Store(&s) + } else { + s = *input + s + c.input.Store(&s) + } + c.Write([]byte{}) + return +} + +func (c *console) showInput() { + input := c.input.Load() + if input == nil { + return + } + s := "\0337" // save cursor position + w, _, _ := term.GetSize(int(os.Stdout.Fd())) + s = s + strings.Repeat(" ", w) + s = s + "\0338" // restore + s = s + "\0337" // save + s = s + "> " + *input + os.Stdout.Write([]byte(s)) +} + +func (c *console) Write(p []byte) (n int, err error) { + s := "\0338" // restore cursor position + s = s + "\033[0J" // erase until end of screen + s = s + strings.Replace(string(p), "\n", "\r\n", -1) + n, err = os.Stdout.Write([]byte(s)) + n = max(0, n - (len(s) - len(p))) + c.showInput() + return +} + +func (c *console) OnCommandOutput(from *server.Server, output string) { + s := "\033[33m" // yellow + s = s + output + s = s + "\033[0m" // reset + s = s + "\r\n" + c.Write([]byte(s)) +} + +func (c *console) OnCommandError(from *server.Server, err string) { + s := "\033[31m" // red + s = s + err + s = s + "\033[0m" // reset + s = s + "\r\n" + c.Write([]byte(s)) +} \ No newline at end of file diff --git a/cmd/metronode/main.go b/cmd/metronode/main.go index bf1cc98..bae5a39 100644 --- a/cmd/metronode/main.go +++ b/cmd/metronode/main.go @@ -2,15 +2,11 @@ package main import ( "os" - "io" "net" "fmt" "log" "flag" "bufio" - "strings" - "sync/atomic" - "golang.org/x/term" "git.citrons.xyz/metronode/server" ) @@ -99,96 +95,3 @@ func readConsole(s *server.Server, cons *console) { } } -type console struct { - input atomic.Pointer[string] - termState *term.State -} - -func initConsole() (cons console, err error) { - var input string - cons.input.Store(&input) - cons.termState, err = term.MakeRaw(int(os.Stdin.Fd())) - if err != nil { - return - } - cons.showInput() - return -} - -func (c *console) Close() error { - c.input.Store(nil) - term.Restore(int(os.Stdin.Fd()), c.termState) - os.Stdout.Write([]byte("\n")) - return nil -} - -func (c *console) Read(p []byte) (n int, err error) { - input := c.input.Load() - if input == nil { - return 0, io.EOF - } - n, err = os.Stdin.Read(p) - if err != nil { - return - } - var sb strings.Builder - for _, c := range p[:n] { - if c == '\r' { - c = '\n' - } - if c >= 32 || c == '\n' { - sb.WriteByte(c) - } - } - s := sb.String() - newline := strings.LastIndex(s, "\n") - if newline != -1 { - s = s[newline + 1:] - c.input.Store(&s) - } else { - s = *input + s - c.input.Store(&s) - } - c.Write([]byte{}) - return -} - -func (c *console) showInput() { - input := c.input.Load() - if input == nil { - return - } - s := "\0337" // save cursor position - w, _, _ := term.GetSize(int(os.Stdout.Fd())) - s = s + strings.Repeat(" ", w) - s = s + "\0338" // restore - s = s + "\0337" // save - s = s + "> " + *input - os.Stdout.Write([]byte(s)) -} - -func (c *console) Write(p []byte) (n int, err error) { - s := "\0338" // restore cursor position - s = s + "\033[0J" // erase until end of screen - s = s + strings.Replace(string(p), "\n", "\r\n", -1) - n, err = os.Stdout.Write([]byte(s)) - n = max(0, n - (len(s) - len(p))) - c.showInput() - return -} - -func (c *console) OnCommandOutput(from *server.Server, output string) { - s := "\033[33m" // yellow - s = s + output - s = s + "\033[0m" // reset - s = s + "\r\n" - c.Write([]byte(s)) -} - -func (c *console) OnCommandError(from *server.Server, err string) { - s := "\033[31m" // red - s = s + err - s = s + "\033[0m" // reset - s = s + "\r\n" - c.Write([]byte(s)) -} -- cgit v1.2.3