From 24cdd59e123726cb2ab7fee0b60b7a2a0fc57273 Mon Sep 17 00:00:00 2001 From: Aki Kareha Date: Thu, 26 Mar 2026 11:50:27 +0900 Subject: [PATCH] Refactor --- internal/console/console.go | 46 +--------- internal/console/input.go | 95 ++++++++++++++++++++ internal/{util/util.go => console/output.go} | 2 +- internal/editor/editor.go | 60 ++++++------- internal/editor/keyboard.go | 61 ------------- internal/editor/screen.go | 15 ---- 6 files changed, 124 insertions(+), 155 deletions(-) create mode 100644 internal/console/input.go rename internal/{util/util.go => console/output.go} (98%) delete mode 100644 internal/editor/keyboard.go delete mode 100644 internal/editor/screen.go diff --git a/internal/console/console.go b/internal/console/console.go index 22fee89..6bc4d14 100644 --- a/internal/console/console.go +++ b/internal/console/console.go @@ -2,9 +2,7 @@ package console import ( "fmt" - "io" "os" - "unicode/utf8" "golang.org/x/term" ) @@ -25,7 +23,7 @@ func Raw() { func Cooked() { if state == nil { - panic("state is nil") + panic("invalid state") } term.Restore(int(os.Stdin.Fd()), state) } @@ -53,47 +51,7 @@ func ShowCursor() { func Size() (int, int) { w, h, err := term.GetSize(int(os.Stdout.Fd())) if err != nil { - panic(err) + return 80, 24 } return w, h } - -func runeSize(b byte) int { - switch { - case b&0x80 == 0: - return 1 - case b&0xe0 == 0xc0: - return 2 - case b&0xf0 == 0xe0: - return 3 - case b&0xf8 == 0xf0: - return 4 - default: - return -1 // invalid - } -} - -func ReadRune() rune { - buf := make([]byte, 1) - _, err := io.ReadFull(os.Stdin, buf) - if err != nil { - panic(err) - } - expected := runeSize(buf[0]) - if expected == -1 { - panic("Invalid UTF-8 head") - } - full := make([]byte, expected) - full[0] = buf[0] - if expected > 1 { - _, err := io.ReadFull(os.Stdin, full[1:]) - if err != nil { - panic(err) - } - } - r, size := utf8.DecodeRune(full) - if r == utf8.RuneError && size == 1 { - panic("Invalid UTF-8 body") - } - return r -} diff --git a/internal/console/input.go b/internal/console/input.go new file mode 100644 index 0000000..053e283 --- /dev/null +++ b/internal/console/input.go @@ -0,0 +1,95 @@ +package console + +import ( + "io" + "os" + "unicode/utf8" +) + +type Key int + +const ( + KeyNormal = iota + KeyUp + KeyDown + KeyRight + KeyLeft +) + +const RuneEscape rune = 0x1b +const RuneEnter rune = '\r' +const RuneBackspace rune = '\b' +const RuneDelete rune = 0x7f + +var buf []rune = make([]rune, 0) + +func runeSize(b byte) int { + switch { + case b&0x80 == 0: + return 1 + case b&0xe0 == 0xc0: + return 2 + case b&0xf0 == 0xe0: + return 3 + case b&0xf8 == 0xf0: + return 4 + default: + return -1 // invalid + } +} + +func readRune() rune { + buf := make([]byte, 1) + _, err := io.ReadFull(os.Stdin, buf) + if err != nil { + panic(err) + } + expected := runeSize(buf[0]) + if expected == -1 { + panic("Invalid UTF-8 head") + } + full := make([]byte, expected) + full[0] = buf[0] + if expected > 1 { + _, err := io.ReadFull(os.Stdin, full[1:]) + if err != nil { + panic(err) + } + } + r, size := utf8.DecodeRune(full) + if r == utf8.RuneError && size == 1 { + panic("Invalid UTF-8 body") + } + return r +} + +func ReadKey() (Key, rune) { + if len(buf) > 0 { + r := buf[0] + buf = buf[1:] + return KeyNormal, r + } + r := readRune() + if r != RuneEscape { + return KeyNormal, r + } + r2 := readRune() + if r2 != '[' { + buf = append(buf, r2) + return KeyNormal, r + } + r3 := readRune() + switch r3 { + case 'A': + return KeyUp, 0 + case 'B': + return KeyDown, 0 + case 'C': + return KeyRight, 0 + case 'D': + return KeyLeft, 0 + } + buf = append(buf, r2) + buf = append(buf, r3) + return KeyNormal, r +} diff --git a/internal/util/util.go b/internal/console/output.go similarity index 98% rename from internal/util/util.go rename to internal/console/output.go index 1493d22..9090e6b 100644 --- a/internal/util/util.go +++ b/internal/console/output.go @@ -1,4 +1,4 @@ -package util +package console import ( "fmt" diff --git a/internal/editor/editor.go b/internal/editor/editor.go index 5ac4210..b4448c0 100644 --- a/internal/editor/editor.go +++ b/internal/editor/editor.go @@ -7,7 +7,6 @@ import ( "unicode/utf8" "tea.kareha.org/lab/levi/internal/console" - "tea.kareha.org/lab/levi/internal/util" ) type mode int @@ -18,8 +17,6 @@ const ( ) type Editor struct { - scr *screen - kb *keyboard col, row int x, y int vrow int @@ -55,12 +52,7 @@ func Init(args []string) *Editor { console.Raw() - scr := newScreen() - kb := newKeyboard() - return &Editor{ - scr: &scr, - kb: &kb, col: 0, row: 0, x: 0, @@ -95,14 +87,14 @@ func (ed *Editor) runeCount() int { } func (ed *Editor) lineHeight(line string) int { - w, _ := ed.scr.size() + w, _ := console.Size() rc := utf8.RuneCountInString(line) - width := util.StringWidth(line, rc) + width := console.StringWidth(line, rc) return 1 + max(width-1, 0)/w } func (ed *Editor) drawBuffer() { - _, h := ed.scr.size() + _, h := console.Size() y := 0 for i := ed.vrow; i < len(ed.lines); i++ { @@ -114,7 +106,7 @@ func (ed *Editor) drawBuffer() { } console.MoveCursor(0, y) - util.Print(line) + console.Print(line) y += ed.lineHeight(line) if y >= h-1 { @@ -124,24 +116,24 @@ func (ed *Editor) drawBuffer() { for ; y < h-1; y++ { console.MoveCursor(0, y) - util.Print("~") + console.Print("~") } } func (ed *Editor) drawStatus() { - _, h := ed.scr.size() + _, h := console.Size() console.MoveCursor(0, h-1) switch ed.mode { case modeCommand: - util.Print("c") + console.Print("c") case modeInsert: - util.Print("i") + console.Print("i") } } func (ed *Editor) updateCursor() { - w, h := ed.scr.size() + w, h := console.Size() var dy int switch ed.mode { @@ -151,12 +143,12 @@ func (ed *Editor) updateCursor() { ed.col = min(ed.col, max(len-1, 0)) // XXX approximation - width := util.StringWidth(ed.lines[ed.row], ed.col) + width := console.StringWidth(ed.lines[ed.row], ed.col) ed.x = width % w dy = width / w case modeInsert: // XXX approximation - width := util.StringWidth(ed.head+ed.insert.String(), ed.col) + width := console.StringWidth(ed.head+ed.insert.String(), ed.col) ed.x = width % w dy = width / w } @@ -249,11 +241,11 @@ func (ed *Editor) Main() { for { ed.repaint() - k, r := ed.kb.readKey() + k, r := console.ReadKey() switch ed.mode { case modeCommand: switch k { - case keyNormal: + case console.KeyNormal: switch r { case 'q': return @@ -272,42 +264,42 @@ func (ed *Editor) Main() { case 'x': ed.deleteRune(1) } - case keyUp: + case console.KeyUp: ed.moveUp(1) - case keyDown: + case console.KeyDown: ed.moveDown(1) - case keyRight: + case console.KeyRight: ed.moveRight(1) - case keyLeft: + case console.KeyLeft: ed.moveLeft(1) default: // TODO ring } case modeInsert: switch k { - case keyNormal: + case console.KeyNormal: switch r { - case runeEscape: + case console.RuneEscape: ed.exitInsert() - case runeEnter: + case console.RuneEnter: ed.insertNewline() - case runeBackspace: + case console.RuneBackspace: ed.deleteBefore() - case runeDelete: + case console.RuneDelete: ed.deleteBefore() default: ed.insertRune(r) } - case keyUp: + case console.KeyUp: ed.exitInsert() ed.moveUp(1) - case keyDown: + case console.KeyDown: ed.exitInsert() ed.moveDown(1) - case keyRight: + case console.KeyRight: ed.exitInsert() ed.moveRight(1) - case keyLeft: + case console.KeyLeft: ed.exitInsert() ed.moveLeft(1) default: diff --git a/internal/editor/keyboard.go b/internal/editor/keyboard.go deleted file mode 100644 index 5476f57..0000000 --- a/internal/editor/keyboard.go +++ /dev/null @@ -1,61 +0,0 @@ -package editor - -import ( - "tea.kareha.org/lab/levi/internal/console" -) - -const runeEscape rune = 0x1b -const runeEnter rune = '\r' -const runeBackspace rune = '\b' -const runeDelete rune = 0x7f - -type key int - -const ( - keyNormal = iota - keyUp - keyDown - keyRight - keyLeft -) - -type keyboard struct { - buf []rune -} - -func newKeyboard() keyboard { - return keyboard{ - buf: make([]rune, 0), - } -} - -func (kb *keyboard) readKey() (key, rune) { - if len(kb.buf) > 0 { - r := kb.buf[0] - kb.buf = kb.buf[1:] - return keyNormal, r - } - r := console.ReadRune() - if r != runeEscape { - return keyNormal, r - } - r2 := console.ReadRune() - if r2 != '[' { - kb.buf = append(kb.buf, r2) - return keyNormal, r - } - r3 := console.ReadRune() - switch r3 { - case 'A': - return keyUp, 0 - case 'B': - return keyDown, 0 - case 'C': - return keyRight, 0 - case 'D': - return keyLeft, 0 - } - kb.buf = append(kb.buf, r2) - kb.buf = append(kb.buf, r3) - return keyNormal, r -} diff --git a/internal/editor/screen.go b/internal/editor/screen.go deleted file mode 100644 index c308e4c..0000000 --- a/internal/editor/screen.go +++ /dev/null @@ -1,15 +0,0 @@ -package editor - -import ( - "tea.kareha.org/lab/levi/internal/console" -) - -type screen struct{} - -func newScreen() screen { - return screen{} -} - -func (scr *screen) size() (int, int) { - return console.Size() -}