Refine insert mode and add insert after command
This commit is contained in:
@@ -39,7 +39,7 @@ func HomeCursor() {
|
||||
}
|
||||
|
||||
func MoveCursor(x, y int) {
|
||||
fmt.Printf("\x1b[%d;%dH", y + 1, x + 1)
|
||||
fmt.Printf("\x1b[%d;%dH", y+1, x+1)
|
||||
}
|
||||
|
||||
func HideCursor() {
|
||||
@@ -60,13 +60,13 @@ func Size() (int, int) {
|
||||
|
||||
func runeSize(b byte) int {
|
||||
switch {
|
||||
case b & 0x80 == 0:
|
||||
case b&0x80 == 0:
|
||||
return 1
|
||||
case b & 0xe0 == 0xc0:
|
||||
case b&0xe0 == 0xc0:
|
||||
return 2
|
||||
case b & 0xf0 == 0xe0:
|
||||
case b&0xf0 == 0xe0:
|
||||
return 3
|
||||
case b & 0xf8 == 0xf0:
|
||||
case b&0xf8 == 0xf0:
|
||||
return 4
|
||||
default:
|
||||
return -1 // invalid
|
||||
|
||||
@@ -2,6 +2,7 @@ package editor
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"tea.kareha.org/lab/levi/internal/console"
|
||||
"tea.kareha.org/lab/levi/internal/util"
|
||||
@@ -15,11 +16,13 @@ const (
|
||||
)
|
||||
|
||||
type Editor struct {
|
||||
scr *Screen
|
||||
kb *Keyboard
|
||||
x, y int
|
||||
line *strings.Builder
|
||||
mode mode
|
||||
scr *Screen
|
||||
kb *Keyboard
|
||||
col, row int
|
||||
x, y int
|
||||
head, tail string
|
||||
insert *strings.Builder
|
||||
mode mode
|
||||
}
|
||||
|
||||
func New() *Editor {
|
||||
@@ -27,33 +30,54 @@ func New() *Editor {
|
||||
kb := NewKeyboard()
|
||||
|
||||
return &Editor{
|
||||
scr: &scr,
|
||||
kb: &kb,
|
||||
x: 0,
|
||||
y: 0,
|
||||
line: new(strings.Builder),
|
||||
mode: modeCommand,
|
||||
scr: &scr,
|
||||
kb: &kb,
|
||||
col: 0,
|
||||
row: 0,
|
||||
x: 0,
|
||||
y: 0,
|
||||
head: "",
|
||||
tail: "",
|
||||
insert: new(strings.Builder),
|
||||
mode: modeCommand,
|
||||
}
|
||||
}
|
||||
|
||||
func (ed *Editor) addRune(r rune) {
|
||||
ed.line.WriteRune(r)
|
||||
ed.insert.WriteRune(r)
|
||||
}
|
||||
|
||||
func (ed *Editor) drawBuffer() {
|
||||
switch ed.mode {
|
||||
case modeCommand:
|
||||
console.Print(ed.head)
|
||||
case modeInsert:
|
||||
console.Print(ed.head)
|
||||
console.Print(ed.insert.String())
|
||||
console.Print(ed.tail)
|
||||
}
|
||||
}
|
||||
|
||||
func (ed *Editor) drawStatus() {
|
||||
_, h := console.Size()
|
||||
|
||||
console.MoveCursor(0, h - 2)
|
||||
console.MoveCursor(0, h-2)
|
||||
switch ed.mode {
|
||||
case modeCommand:
|
||||
console.Print("-- [command] q: quit, i: insert --")
|
||||
console.Print("-- [command] q: quit, i: insert, a: insert after --")
|
||||
case modeInsert:
|
||||
console.Print("-- [insert] Esc: command mode --")
|
||||
}
|
||||
}
|
||||
|
||||
func (ed *Editor) drawBuffer() {
|
||||
console.Print(ed.line.String())
|
||||
func (ed *Editor) updateCursor() {
|
||||
switch ed.mode {
|
||||
case modeCommand:
|
||||
ed.x = util.StringWidth(ed.head, ed.col)
|
||||
case modeInsert:
|
||||
ed.x = util.StringWidth(ed.head+ed.insert.String(), ed.col)
|
||||
}
|
||||
ed.y = ed.row
|
||||
}
|
||||
|
||||
func (ed *Editor) repaint() {
|
||||
@@ -65,11 +89,39 @@ func (ed *Editor) repaint() {
|
||||
ed.drawBuffer()
|
||||
ed.drawStatus()
|
||||
|
||||
ed.updateCursor()
|
||||
console.MoveCursor(ed.x, ed.y)
|
||||
|
||||
console.ShowCursor()
|
||||
}
|
||||
|
||||
func (ed *Editor) enterInsert() {
|
||||
rs := []rune(ed.head)
|
||||
ed.head = string(rs[:ed.col])
|
||||
ed.tail = string(rs[ed.col:])
|
||||
ed.mode = modeInsert
|
||||
}
|
||||
|
||||
func (ed *Editor) enterInsertAfter() {
|
||||
len := utf8.RuneCountInString(ed.head)
|
||||
if ed.col < len-1 {
|
||||
ed.moveRight(1)
|
||||
ed.enterInsert()
|
||||
return
|
||||
} else {
|
||||
ed.col++
|
||||
ed.mode = modeInsert
|
||||
}
|
||||
}
|
||||
|
||||
func (ed *Editor) moveLeft(n int) {
|
||||
ed.col = max(ed.col-n, 0)
|
||||
}
|
||||
|
||||
func (ed *Editor) moveRight(n int) {
|
||||
ed.col = min(ed.col+n, max(utf8.RuneCountInString(ed.head)-1, 0))
|
||||
}
|
||||
|
||||
func (ed *Editor) Main() {
|
||||
for {
|
||||
ed.repaint()
|
||||
@@ -81,15 +133,25 @@ func (ed *Editor) Main() {
|
||||
case 'q':
|
||||
return
|
||||
case 'i':
|
||||
ed.mode = modeInsert
|
||||
ed.enterInsert()
|
||||
case 'a':
|
||||
ed.enterInsertAfter()
|
||||
case 'h':
|
||||
ed.moveLeft(1)
|
||||
case 'l':
|
||||
ed.moveRight(1)
|
||||
}
|
||||
case modeInsert:
|
||||
switch r {
|
||||
case Esc:
|
||||
ed.head = ed.head + ed.insert.String() + ed.tail
|
||||
ed.tail = ""
|
||||
ed.insert = new(strings.Builder)
|
||||
ed.mode = modeCommand
|
||||
ed.moveLeft(1)
|
||||
default:
|
||||
ed.addRune(r)
|
||||
ed.x += util.RuneWidth(r)
|
||||
ed.col++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
const Esc rune = 0x1b
|
||||
|
||||
type Keyboard struct {}
|
||||
type Keyboard struct{}
|
||||
|
||||
func NewKeyboard() Keyboard {
|
||||
return Keyboard{}
|
||||
|
||||
@@ -5,8 +5,7 @@ import (
|
||||
)
|
||||
|
||||
func isWide(r rune) bool {
|
||||
return r >= 0x1100 && (
|
||||
r <= 0x115f || // Hangul Jamo
|
||||
return r >= 0x1100 && (r <= 0x115f || // Hangul Jamo
|
||||
r == 0x2329 || r == 0x232a ||
|
||||
(r >= 0x2e80 && r <= 0xa4cf) ||
|
||||
(r >= 0xac00 && r <= 0xd7a3) ||
|
||||
@@ -47,3 +46,16 @@ func RuneWidth(r rune) int {
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
func StringWidth(s string, col int) int {
|
||||
sum := 0
|
||||
i := 0
|
||||
for _, r := range s {
|
||||
if i >= col {
|
||||
break
|
||||
}
|
||||
sum += RuneWidth(r)
|
||||
i++
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user