Fix edit mode when View.Wrap is enabled

This commit is contained in:
Roi Martin 2015-02-04 01:59:03 +01:00
parent b1d190d0d7
commit 708261503b
2 changed files with 58 additions and 18 deletions

View File

@ -33,7 +33,7 @@ func (v *View) editDelete(back bool) error {
// editLine inserts a new line under the cursor. // editLine inserts a new line under the cursor.
func (v *View) editLine() error { func (v *View) editLine() error {
v.addLine(v.cy + 1) v.addLine(v.cy)
if err := v.SetCursor(v.cx, v.cy+1); err != nil { if err := v.SetCursor(v.cx, v.cy+1); err != nil {
if err := v.SetOrigin(v.ox, v.oy+1); err != nil { if err := v.SetOrigin(v.ox, v.oy+1); err != nil {
return err return err

74
view.go
View File

@ -61,8 +61,8 @@ type View struct {
} }
type viewLine struct { type viewLine struct {
linesX, linesY int linesX, linesY int // coordinates relative to v.lines
wrapped bool offset int // len(v.WrapPrefix) or 0
line []rune line []rune
} }
@ -171,8 +171,7 @@ func (v *View) Write(p []byte) (n int, err error) {
if nl > 0 { if nl > 0 {
v.lines[nl-1] = append(v.lines[nl-1], ch) v.lines[nl-1] = append(v.lines[nl-1], ch)
} else { } else {
v.lines = make([][]rune, 1) v.lines = append(v.lines, []rune{ch})
v.lines[0] = append(v.lines[0], ch)
} }
} }
} }
@ -204,9 +203,10 @@ func (v *View) Rewind() {
// draw re-draws the view's contents. // draw re-draws the view's contents.
func (v *View) draw() error { func (v *View) draw() error {
maxX, maxY := v.Size() maxX, maxY := v.Size()
lenPfx := len(v.WrapPrefix)
if v.Wrap { if v.Wrap {
if len(v.WrapPrefix) >= maxX { if lenPfx >= maxX {
return errors.New("WrapPrefix bigger or equal to X size") return errors.New("WrapPrefix bigger or equal to X size")
} }
v.ox = 0 v.ox = 0
@ -225,13 +225,17 @@ func (v *View) draw() error {
v.viewLines = append(v.viewLines, vline) v.viewLines = append(v.viewLines, vline)
} }
// Append remaining lines with WrapPrefix // Append remaining lines with WrapPrefix
for n := maxX; n < len(line); n += maxX - len(v.WrapPrefix) { for n := maxX; n < len(line); n += maxX - lenPfx {
wrappedLine := append(append([]rune(v.WrapPrefix), line[n:]...)) wrappedLine := append(append([]rune(v.WrapPrefix), line[n:]...))
if len(wrappedLine) <= maxX { if len(wrappedLine) <= maxX {
vline := viewLine{linesX: n, linesY: i, wrapped: true, line: wrappedLine} vline := viewLine{linesX: n, linesY: i,
offset: lenPfx,
line: wrappedLine}
v.viewLines = append(v.viewLines, vline) v.viewLines = append(v.viewLines, vline)
} else { } else {
vline := viewLine{linesX: n, linesY: i, wrapped: true, line: wrappedLine[:maxX]} vline := viewLine{linesX: n, linesY: i,
offset: lenPfx,
line: wrappedLine[:maxX]}
v.viewLines = append(v.viewLines, vline) v.viewLines = append(v.viewLines, vline)
} }
} }
@ -272,6 +276,29 @@ func (v *View) draw() error {
return nil return nil
} }
// realPosition returns the position in the internal buffer corresponding to the
// point (x, y) of the view.
func (v *View) realPosition(vx, vy int) (x, y int, err error) {
vx = v.ox + vx
vy = v.oy + vy
if vx < 0 || vy < 0 {
return 0, 0, errors.New("invalid point")
}
if vy < len(v.viewLines) {
vline := v.viewLines[vy]
x = vline.linesX + vline.offset + vx
y = vline.linesY
} else {
vline := v.viewLines[len(v.viewLines)-1]
x = vx
y = vline.linesY + vy - len(v.viewLines) + 1
}
return x, y, nil
}
// Clear empties the view's internal buffer. // Clear empties the view's internal buffer.
func (v *View) Clear() { func (v *View) Clear() {
v.tainted = true v.tainted = true
@ -298,8 +325,10 @@ func (v *View) clearRunes() {
func (v *View) writeRune(x, y int, ch rune) error { func (v *View) writeRune(x, y int, ch rune) error {
v.tainted = true v.tainted = true
x = v.ox + x x, y, err := v.realPosition(x, y)
y = v.oy + y if err != nil {
return err
}
if x < 0 || y < 0 { if x < 0 || y < 0 {
return errors.New("invalid point") return errors.New("invalid point")
@ -338,8 +367,10 @@ func (v *View) writeRune(x, y int, ch rune) error {
func (v *View) deleteRune(x, y int) error { func (v *View) deleteRune(x, y int) error {
v.tainted = true v.tainted = true
x = v.ox + x x, y, err := v.realPosition(x, y)
y = v.oy + y if err != nil {
return err
}
if x < 0 || y < 0 || y >= len(v.lines) || v.lines[y] == nil || x >= len(v.lines[y]) { if x < 0 || y < 0 || y >= len(v.lines) || v.lines[y] == nil || x >= len(v.lines[y]) {
return errors.New("invalid point") return errors.New("invalid point")
@ -349,12 +380,16 @@ func (v *View) deleteRune(x, y int) error {
return nil return nil
} }
// addLine adds a line into the view's internal buffer at the position // addLine adds a line into the view's internal buffer under the position
// corresponding to the point (x, y). // corresponding to the point (x, y).
func (v *View) addLine(y int) error { func (v *View) addLine(y int) error {
v.tainted = true v.tainted = true
y = v.oy + y _, y, err := v.realPosition(0, y)
if err != nil {
return err
}
y = y + 1 // the line must be added under (x, y)
if y < 0 || y >= len(v.lines) { if y < 0 || y >= len(v.lines) {
return errors.New("invalid point") return errors.New("invalid point")
@ -378,7 +413,10 @@ func (v *View) Buffer() string {
// Line returns a string with the line of the view's internal buffer // Line returns a string with the line of the view's internal buffer
// at the position corresponding to the point (x, y). // at the position corresponding to the point (x, y).
func (v *View) Line(y int) (string, error) { func (v *View) Line(y int) (string, error) {
y = v.oy + y _, y, err := v.realPosition(0, y)
if err != nil {
return "", err
}
if y < 0 || y >= len(v.lines) { if y < 0 || y >= len(v.lines) {
return "", errors.New("invalid point") return "", errors.New("invalid point")
@ -389,8 +427,10 @@ func (v *View) Line(y int) (string, error) {
// Word returns a string with the word of the view's internal buffer // Word returns a string with the word of the view's internal buffer
// at the position corresponding to the point (x, y). // at the position corresponding to the point (x, y).
func (v *View) Word(x, y int) (string, error) { func (v *View) Word(x, y int) (string, error) {
x = v.ox + x x, y, err := v.realPosition(x, y)
y = v.oy + y if err != nil {
return "", err
}
if y < 0 || y >= len(v.lines) || x >= len(v.lines[y]) { if y < 0 || y >= len(v.lines) || x >= len(v.lines[y]) {
return "", errors.New("invalid point") return "", errors.New("invalid point")