Proper support for double width characters

Fixes #99
This commit is contained in:
Zachary Yedidia
2016-06-04 16:25:11 -04:00
parent 852bd2c904
commit d6307b2718
3 changed files with 42 additions and 12 deletions

View File

@@ -1,9 +1,5 @@
package main
import (
"strings"
)
// FromCharPos converts from a character position to an x, y position
func FromCharPos(loc int, buf *Buffer) (int, int) {
return FromCharPosStart(0, 0, 0, loc, buf)
@@ -357,13 +353,13 @@ func (c *Cursor) GetCharPosInLine(lineNum, visualPos int) int {
// Get the tab size
tabSize := int(settings["tabsize"].(float64))
// This is the visual line -- every \t replaced with the correct number of spaces
visualLine := strings.Replace(c.buf.Lines[lineNum], "\t", "\t"+Spaces(tabSize-1), -1)
if visualPos > Count(visualLine) {
visualPos = Count(visualLine)
visualLineLen := StringWidth(c.buf.Lines[lineNum])
if visualPos > visualLineLen {
visualPos = visualLineLen
}
numTabs := NumOccurences(visualLine[:visualPos], '\t')
if visualPos >= (tabSize-1)*numTabs {
return visualPos - (tabSize-1)*numTabs
width := WidthOfLargeRunes(c.buf.Lines[lineNum])
if visualPos >= width {
return visualPos - width
}
return visualPos / tabSize
}
@@ -371,8 +367,7 @@ func (c *Cursor) GetCharPosInLine(lineNum, visualPos int) int {
// GetVisualX returns the x value of the cursor in visual spaces
func (c *Cursor) GetVisualX() int {
runes := []rune(c.buf.Lines[c.Y])
tabSize := int(settings["tabsize"].(float64))
return c.X + NumOccurences(string(runes[:c.X]), '\t')*(tabSize-1)
return StringWidth(string(runes[:c.X]))
}
// Relocate makes sure that the cursor is inside the bounds of the buffer

View File

@@ -7,6 +7,8 @@ import (
"strings"
"time"
"unicode/utf8"
"github.com/mattn/go-runewidth"
)
// Util.go is a collection of utility functions that are used throughout
@@ -138,6 +140,28 @@ func GetModTime(path string) (time.Time, bool) {
return info.ModTime(), true
}
func StringWidth(str string) int {
sw := runewidth.StringWidth(str)
sw += NumOccurences(str, '\t') * (int(settings["tabsize"].(float64)) - 1)
return sw
}
func WidthOfLargeRunes(str string) int {
count := 0
for _, ch := range str {
var w int
if ch == '\t' {
w = int(settings["tabsize"].(float64))
} else {
w = runewidth.RuneWidth(ch)
}
if w > 1 {
count += (w - 1)
}
}
return count
}
func runePos(p int, str string) int {
return utf8.RuneCountInString(str[:p])
}

View File

@@ -7,6 +7,7 @@ import (
"strings"
"time"
"github.com/mattn/go-runewidth"
"github.com/zyedidia/tcell"
)
@@ -601,6 +602,16 @@ func (v *View) DisplayView() {
screen.SetContent(x-v.leftCol, lineN, ' ', nil, lineStyle)
}
}
} else if runewidth.RuneWidth(ch) > 1 {
if x-v.leftCol >= v.lineNumOffset {
screen.SetContent(x-v.leftCol, lineN, ch, nil, lineStyle)
}
for i := 0; i < runewidth.RuneWidth(ch)-1; i++ {
x++
if x-v.leftCol >= v.lineNumOffset {
screen.SetContent(x-v.leftCol, lineN, ' ', nil, lineStyle)
}
}
} else {
if x-v.leftCol >= v.lineNumOffset {
screen.SetContent(x-v.leftCol, lineN, ch, nil, lineStyle)