Skip to content

Commit

Permalink
Proper support for double width characters
Browse files Browse the repository at this point in the history
Fixes #99
  • Loading branch information
zyedidia committed Jun 4, 2016
1 parent 852bd2c commit d6307b2
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 12 deletions.
19 changes: 7 additions & 12 deletions cmd/micro/cursor.go
Original file line number Diff line number Diff line change
@@ -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)
Expand Down Expand Up @@ -357,22 +353,21 @@ 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
}

// 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
Expand Down
24 changes: 24 additions & 0 deletions cmd/micro/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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])
}
11 changes: 11 additions & 0 deletions cmd/micro/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strings"
"time"

"github.com/mattn/go-runewidth"
"github.com/zyedidia/tcell"
)

Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit d6307b2

Please sign in to comment.