totalwidth := w.StartCol - nColsBeforeStart
- if svloc.X <= vloc.X+w.X && vloc.Y+w.Y == svloc.Y {
- return bloc
- }
for len(line) > 0 {
- if vloc.X+w.X == svloc.X && vloc.Y+w.Y == svloc.Y {
- return bloc
- }
-
r, _, size := util.DecodeCharacter(line)
- draw()
+
width := 0
switch r {
case '\t':
ts := tabsize - (totalwidth % tabsize)
- width = ts
+ width = util.Min(ts, maxWidth-vloc.X)
+ totalwidth += ts
default:
width = runewidth.RuneWidth(r)
+ totalwidth += width
}
+ // If a wide rune does not fit in the window
+ if vloc.X+width > maxWidth && vloc.X > w.gutterOffset {
+ if vloc.Y+w.Y == svloc.Y {
+ return bloc
+ }
+
+ // We either stop or we wrap to draw the rune in the next line
+ if !softwrap {
+ break
+ } else {
+ vloc.Y++
+ if vloc.Y >= w.bufHeight {
+ break
+ }
+ vloc.X = w.gutterOffset
+ }
+ }
+
+ draw()
+
// Draw any extra characters either spaces for tabs or @ for incomplete wide runes
if width > 1 {
for i := 1; i < width; i++ {
- if vloc.X+w.X == svloc.X && vloc.Y+w.Y == svloc.Y {
- return bloc
- }
draw()
}
}
+
+ if svloc.X < vloc.X+w.X && vloc.Y+w.Y == svloc.Y {
+ return bloc
+ }
bloc.X++
line = line[size:]
- totalwidth += width
-
// If we reach the end of the window then we either stop or we wrap for softwrap
if vloc.X >= maxWidth {
if !softwrap {
nColsBeforeStart--
}
+ wrap := func() {
+ vloc.X = 0
+ if w.hasMessage {
+ w.drawGutter(&vloc, &bloc)
+ }
+ if b.Settings["diffgutter"].(bool) {
+ w.drawDiffGutter(lineNumStyle, true, &vloc, &bloc)
+ }
+
+ // This will draw an empty line number because the current line is wrapped
+ if b.Settings["ruler"].(bool) {
+ w.drawLineNum(lineNumStyle, true, &vloc, &bloc)
+ }
+ }
+
totalwidth := w.StartCol - nColsBeforeStart
for len(line) > 0 {
r, combc, size := util.DecodeCharacter(line)
curStyle, _ = w.getStyle(curStyle, bloc)
- draw(r, combc, curStyle, true)
-
width := 0
char := ' '
switch r {
case '\t':
ts := tabsize - (totalwidth % tabsize)
- width = ts
+ width = util.Min(ts, maxWidth-vloc.X)
+ totalwidth += ts
default:
width = runewidth.RuneWidth(r)
char = '@'
+ totalwidth += width
}
+ // If a wide rune does not fit in the window
+ if vloc.X+width > maxWidth && vloc.X > w.gutterOffset {
+ for vloc.X < maxWidth {
+ draw(' ', nil, config.DefStyle, false)
+ }
+
+ // We either stop or we wrap to draw the rune in the next line
+ if !softwrap {
+ break
+ } else {
+ vloc.Y++
+ if vloc.Y >= w.bufHeight {
+ break
+ }
+ wrap()
+ }
+ }
+
+ draw(r, combc, curStyle, true)
+
// Draw any extra characters either spaces for tabs or @ for incomplete wide runes
if width > 1 {
for i := 1; i < width; i++ {
bloc.X++
line = line[size:]
- totalwidth += width
-
// If we reach the end of the window then we either stop or we wrap for softwrap
if vloc.X >= maxWidth {
if !softwrap {
if vloc.Y >= w.bufHeight {
break
}
- vloc.X = 0
- if w.hasMessage {
- w.drawGutter(&vloc, &bloc)
- }
- if b.Settings["diffgutter"].(bool) {
- w.drawDiffGutter(lineNumStyle, true, &vloc, &bloc)
- }
-
- // This will draw an empty line number because the current line is wrapped
- if b.Settings["ruler"].(bool) {
- w.drawLineNum(lineNumStyle, true, &vloc, &bloc)
- }
+ wrap()
}
}
}
package display
import (
+ runewidth "github.com/mattn/go-runewidth"
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/v2/internal/util"
)
}
func (w *BufWindow) getRow(loc buffer.Loc) int {
+ if loc.X <= 0 {
+ return 0
+ }
+
if w.bufWidth <= 0 {
return 0
}
- // TODO: this doesn't work quite correctly if there is an incomplete tab
- // or wide character at the end of a row. See also issue #1979
- x := util.StringWidth(w.Buf.LineBytes(loc.Y), loc.X, util.IntOpt(w.Buf.Settings["tabsize"]))
- return x / w.bufWidth
+
+ tabsize := util.IntOpt(w.Buf.Settings["tabsize"])
+
+ line := w.Buf.LineBytes(loc.Y)
+ x := 0
+ visualx := 0
+ row := 0
+ totalwidth := 0
+
+ for len(line) > 0 {
+ r, _, size := util.DecodeCharacter(line)
+
+ width := 0
+ switch r {
+ case '\t':
+ ts := tabsize - (totalwidth % tabsize)
+ width = util.Min(ts, w.bufWidth-visualx)
+ totalwidth += ts
+ default:
+ width = runewidth.RuneWidth(r)
+ totalwidth += width
+ }
+
+ // If a wide rune does not fit in the window
+ if visualx+width > w.bufWidth && visualx > 0 {
+ row++
+ visualx = 0
+ }
+
+ if x == loc.X {
+ return row
+ }
+ x++
+ line = line[size:]
+
+ visualx += width
+ if visualx >= w.bufWidth {
+ row++
+ visualx = 0
+ }
+ }
+ return row
}
func (w *BufWindow) getRowCount(line int) int {