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