diff options
Diffstat (limited to 'vendor/github.com/jesseduffield/gocui/edit.go')
-rw-r--r-- | vendor/github.com/jesseduffield/gocui/edit.go | 111 |
1 files changed, 83 insertions, 28 deletions
diff --git a/vendor/github.com/jesseduffield/gocui/edit.go b/vendor/github.com/jesseduffield/gocui/edit.go index e1b19c20b..a5e6f690b 100644 --- a/vendor/github.com/jesseduffield/gocui/edit.go +++ b/vendor/github.com/jesseduffield/gocui/edit.go @@ -4,7 +4,11 @@ package gocui -import "errors" +import ( + "errors" + + "github.com/mattn/go-runewidth" +) const maxInt = int(^uint(0) >> 1) @@ -54,8 +58,9 @@ func simpleEditor(v *View, key Key, ch rune, mod Modifier) { // EditWrite writes a rune at the cursor position. func (v *View) EditWrite(ch rune) { + w := runewidth.RuneWidth(ch) v.writeRune(v.cx, v.cy, ch) - v.MoveCursor(1, 0, true) + v.moveCursor(w, 0, true) } // EditDelete deletes a rune at the cursor position. back determines the @@ -89,12 +94,12 @@ func (v *View) EditDelete(back bool) { v.MoveCursor(-1, 0, true) } } else { // wrapped line - v.deleteRune(len(v.viewLines[y-1].line)-1, v.cy-1) - v.MoveCursor(-1, 0, true) + n, _ := v.deleteRune(len(v.viewLines[y-1].line)-1, v.cy-1) + v.MoveCursor(-n, 0, true) } } else { // middle/end of the line - v.deleteRune(v.cx-1, v.cy) - v.MoveCursor(-1, 0, true) + n, _ := v.deleteRune(v.cx-1, v.cy) + v.MoveCursor(-n, 0, true) } } else { if x == len(v.viewLines[y].line) { // end of the line @@ -116,35 +121,74 @@ func (v *View) EditNewLine() { // MoveCursor moves the cursor taking into account the width of the line/view, // displacing the origin if necessary. func (v *View) MoveCursor(dx, dy int, writeMode bool) { + ox, oy := v.cx+v.ox, v.cy+v.oy + x, y := ox+dx, oy+dy + + if y < 0 || y >= len(v.viewLines) { + v.moveCursor(dx, dy, writeMode) + return + } + + // Removing newline. + if x < 0 { + var prevLen int + if y-1 >= 0 && y-1 < len(v.viewLines) { + prevLen = lineWidth(v.viewLines[y-1].line) + } + + v.MoveCursor(prevLen, -1, writeMode) + return + } + + line := v.viewLines[y].line + var col int + var prevCol int + for i := range line { + prevCol = col + col += runewidth.RuneWidth(line[i].chr) + if dx > 0 { + if x <= col { + x = col + break + } + continue + } + + if x < col { + x = prevCol + break + } + } + + v.moveCursor(x-ox, y-oy, writeMode) +} + +func (v *View) moveCursor(dx, dy int, writeMode bool) { maxX, maxY := v.Size() cx, cy := v.cx+dx, v.cy+dy x, y := v.ox+cx, v.oy+cy var curLineWidth, prevLineWidth int // get the width of the current line - if writeMode { - if v.Wrap { - curLineWidth = maxX - 1 - } else { - curLineWidth = maxInt - } - } else { + curLineWidth = maxInt + if v.Wrap { + curLineWidth = maxX - 1 + } + + if !writeMode { + curLineWidth = 0 if y >= 0 && y < len(v.viewLines) { - curLineWidth = len(v.viewLines[y].line) + curLineWidth = lineWidth(v.viewLines[y].line) if v.Wrap && curLineWidth >= maxX { curLineWidth = maxX - 1 } - } else { - curLineWidth = 0 } } // get the width of the previous line + prevLineWidth = 0 if y-1 >= 0 && y-1 < len(v.viewLines) { - prevLineWidth = len(v.viewLines[y-1].line) - } else { - prevLineWidth = 0 + prevLineWidth = lineWidth(v.viewLines[y-1].line) } - // adjust cursor's x position and view's x origin if x > curLineWidth { // move to next line if dx > 0 { // horizontal movement @@ -190,10 +234,9 @@ func (v *View) MoveCursor(dx, dy int, writeMode bool) { if !v.Wrap { // set origin so the EOL is visible nox := prevLineWidth - maxX + 1 if nox < 0 { - v.ox = 0 - } else { - v.ox = nox + nox = 0 } + v.ox = nox } v.cx = prevLineWidth } else { @@ -275,19 +318,31 @@ func (v *View) writeRune(x, y int, ch rune) error { // deleteRune removes a rune from the view's internal buffer, at the // position corresponding to the point (x, y). -func (v *View) deleteRune(x, y int) error { +// returns the amount of columns that where removed. +func (v *View) deleteRune(x, y int) (int, error) { v.tainted = true x, y, err := v.realPosition(x, y) if err != nil { - return err + return 0, err } if x < 0 || y < 0 || y >= len(v.lines) || x >= len(v.lines[y]) { - return errors.New("invalid point") + return 0, errors.New("invalid point") } - v.lines[y] = append(v.lines[y][:x], v.lines[y][x+1:]...) - return nil + + var tw int + for i := range v.lines[y] { + w := runewidth.RuneWidth(v.lines[y][i].chr) + tw += w + if tw > x { + v.lines[y] = append(v.lines[y][:i], v.lines[y][i+1:]...) + return w, nil + } + + } + + return 0, nil } // mergeLines merges the lines "y" and "y+1" if possible. |