mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-02-09 13:47:11 +02:00
support unicode characters
This commit is contained in:
parent
145cba34a0
commit
8c2b8cfb51
6
Gopkg.lock
generated
6
Gopkg.lock
generated
@ -189,11 +189,11 @@
|
|||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:f774b11ae458cae2d10b94ef66ef00ba1c57f1971dd0e5534ac743cbe574f6d4"
|
digest = "1:acbcdae312c37a8019e0f573a9be26499058d5e1244243655373d2fd97714658"
|
||||||
name = "github.com/jesseduffield/gocui"
|
name = "github.com/jesseduffield/gocui"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = "NUT"
|
pruneopts = "NUT"
|
||||||
revision = "7818a0f93387d1037cbd06f69323d9f8d068af7c"
|
revision = "5d9e836837237cb3aadca51ecb37c7cf3345bfa4"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:ac6d01547ec4f7f673311b4663909269bfb8249952de3279799289467837c3cc"
|
digest = "1:ac6d01547ec4f7f673311b4663909269bfb8249952de3279799289467837c3cc"
|
||||||
@ -614,8 +614,8 @@
|
|||||||
"github.com/davecgh/go-spew/spew",
|
"github.com/davecgh/go-spew/spew",
|
||||||
"github.com/fatih/color",
|
"github.com/fatih/color",
|
||||||
"github.com/golang-collections/collections/stack",
|
"github.com/golang-collections/collections/stack",
|
||||||
"github.com/jesseduffield/go-getter",
|
|
||||||
"github.com/heroku/rollrus",
|
"github.com/heroku/rollrus",
|
||||||
|
"github.com/jesseduffield/go-getter",
|
||||||
"github.com/jesseduffield/gocui",
|
"github.com/jesseduffield/gocui",
|
||||||
"github.com/kardianos/osext",
|
"github.com/kardianos/osext",
|
||||||
"github.com/mgutz/str",
|
"github.com/mgutz/str",
|
||||||
|
@ -15,9 +15,8 @@ ZWJ https://en.wikipedia.org/wiki/Zero-width_joiner / https://unicode.org/
|
|||||||
UNICODE ☆ 🤓 え 术
|
UNICODE ☆ 🤓 え 术
|
||||||
EOT
|
EOT
|
||||||
git add charstest.txt
|
git add charstest.txt
|
||||||
git commit -m "Test chars Œ¥ƒ👶👨👦☆ 🤓 え 术 commit"
|
git commit -m "Test chars Œ¥ƒ👶👨👦☆ 🤓 え 术👩💻👩🏻💻👩🏽💻👩🏼💻👩🏾💻👩🏿💻👨💻👨🏻💻👨🏼💻👨🏽💻👨🏾💻👨🏿💻 commit"
|
||||||
echo "我喜歡編碼" >> charstest.txt
|
echo "我喜歡編碼" >> charstest.txt
|
||||||
echo "நான் குறியீடு விரும்புகிறேன்" >> charstest.txt
|
echo "நான் குறியீடு விரும்புகிறேன்" >> charstest.txt
|
||||||
git add charstest.txt
|
git add charstest.txt
|
||||||
git commit -m "Test chars 我喜歡編碼 நான் குறியீடு விரும்புகிறேன் commit"
|
git commit -m "Test chars 我喜歡編碼 நான் குறியீடு விரும்புகிறேன் commit"
|
||||||
|
|
||||||
|
111
vendor/github.com/jesseduffield/gocui/edit.go
generated
vendored
111
vendor/github.com/jesseduffield/gocui/edit.go
generated
vendored
@ -4,7 +4,11 @@
|
|||||||
|
|
||||||
package gocui
|
package gocui
|
||||||
|
|
||||||
import "errors"
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/mattn/go-runewidth"
|
||||||
|
)
|
||||||
|
|
||||||
const maxInt = int(^uint(0) >> 1)
|
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.
|
// EditWrite writes a rune at the cursor position.
|
||||||
func (v *View) EditWrite(ch rune) {
|
func (v *View) EditWrite(ch rune) {
|
||||||
|
w := runewidth.RuneWidth(ch)
|
||||||
v.writeRune(v.cx, v.cy, 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
|
// 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)
|
v.MoveCursor(-1, 0, true)
|
||||||
}
|
}
|
||||||
} else { // wrapped line
|
} else { // wrapped line
|
||||||
v.deleteRune(len(v.viewLines[y-1].line)-1, v.cy-1)
|
n, _ := v.deleteRune(len(v.viewLines[y-1].line)-1, v.cy-1)
|
||||||
v.MoveCursor(-1, 0, true)
|
v.MoveCursor(-n, 0, true)
|
||||||
}
|
}
|
||||||
} else { // middle/end of the line
|
} else { // middle/end of the line
|
||||||
v.deleteRune(v.cx-1, v.cy)
|
n, _ := v.deleteRune(v.cx-1, v.cy)
|
||||||
v.MoveCursor(-1, 0, true)
|
v.MoveCursor(-n, 0, true)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if x == len(v.viewLines[y].line) { // end of the line
|
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,
|
// MoveCursor moves the cursor taking into account the width of the line/view,
|
||||||
// displacing the origin if necessary.
|
// displacing the origin if necessary.
|
||||||
func (v *View) MoveCursor(dx, dy int, writeMode bool) {
|
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()
|
maxX, maxY := v.Size()
|
||||||
cx, cy := v.cx+dx, v.cy+dy
|
cx, cy := v.cx+dx, v.cy+dy
|
||||||
x, y := v.ox+cx, v.oy+cy
|
x, y := v.ox+cx, v.oy+cy
|
||||||
|
|
||||||
var curLineWidth, prevLineWidth int
|
var curLineWidth, prevLineWidth int
|
||||||
// get the width of the current line
|
// get the width of the current line
|
||||||
if writeMode {
|
curLineWidth = maxInt
|
||||||
if v.Wrap {
|
if v.Wrap {
|
||||||
curLineWidth = maxX - 1
|
curLineWidth = maxX - 1
|
||||||
} else {
|
}
|
||||||
curLineWidth = maxInt
|
|
||||||
}
|
if !writeMode {
|
||||||
} else {
|
curLineWidth = 0
|
||||||
if y >= 0 && y < len(v.viewLines) {
|
if y >= 0 && y < len(v.viewLines) {
|
||||||
curLineWidth = len(v.viewLines[y].line)
|
curLineWidth = lineWidth(v.viewLines[y].line)
|
||||||
if v.Wrap && curLineWidth >= maxX {
|
if v.Wrap && curLineWidth >= maxX {
|
||||||
curLineWidth = maxX - 1
|
curLineWidth = maxX - 1
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
curLineWidth = 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// get the width of the previous line
|
// get the width of the previous line
|
||||||
|
prevLineWidth = 0
|
||||||
if y-1 >= 0 && y-1 < len(v.viewLines) {
|
if y-1 >= 0 && y-1 < len(v.viewLines) {
|
||||||
prevLineWidth = len(v.viewLines[y-1].line)
|
prevLineWidth = lineWidth(v.viewLines[y-1].line)
|
||||||
} else {
|
|
||||||
prevLineWidth = 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// adjust cursor's x position and view's x origin
|
// adjust cursor's x position and view's x origin
|
||||||
if x > curLineWidth { // move to next line
|
if x > curLineWidth { // move to next line
|
||||||
if dx > 0 { // horizontal movement
|
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
|
if !v.Wrap { // set origin so the EOL is visible
|
||||||
nox := prevLineWidth - maxX + 1
|
nox := prevLineWidth - maxX + 1
|
||||||
if nox < 0 {
|
if nox < 0 {
|
||||||
v.ox = 0
|
nox = 0
|
||||||
} else {
|
|
||||||
v.ox = nox
|
|
||||||
}
|
}
|
||||||
|
v.ox = nox
|
||||||
}
|
}
|
||||||
v.cx = prevLineWidth
|
v.cx = prevLineWidth
|
||||||
} else {
|
} 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
|
// deleteRune removes a rune from the view's internal buffer, at the
|
||||||
// position corresponding to the point (x, y).
|
// 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
|
v.tainted = true
|
||||||
|
|
||||||
x, y, err := v.realPosition(x, y)
|
x, y, err := v.realPosition(x, y)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if x < 0 || y < 0 || y >= len(v.lines) || x >= len(v.lines[y]) {
|
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.
|
// mergeLines merges the lines "y" and "y+1" if possible.
|
||||||
|
88
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
88
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
@ -10,6 +10,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mattn/go-runewidth"
|
||||||
"github.com/nsf/termbox-go"
|
"github.com/nsf/termbox-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -312,24 +313,14 @@ func (v *View) draw() error {
|
|||||||
if v.tainted {
|
if v.tainted {
|
||||||
v.viewLines = nil
|
v.viewLines = nil
|
||||||
for i, line := range v.lines {
|
for i, line := range v.lines {
|
||||||
|
wrap := 0
|
||||||
if v.Wrap {
|
if v.Wrap {
|
||||||
if len(line) < maxX {
|
wrap = maxX
|
||||||
vline := viewLine{linesX: 0, linesY: i, line: line}
|
}
|
||||||
v.viewLines = append(v.viewLines, vline)
|
|
||||||
continue
|
ls := lineWrap(line, wrap)
|
||||||
} else {
|
for j := range ls {
|
||||||
for n := 0; n <= len(line); n += maxX {
|
vline := viewLine{linesX: j, linesY: i, line: ls[j]}
|
||||||
if len(line[n:]) <= maxX {
|
|
||||||
vline := viewLine{linesX: n, linesY: i, line: line[n:]}
|
|
||||||
v.viewLines = append(v.viewLines, vline)
|
|
||||||
} else {
|
|
||||||
vline := viewLine{linesX: n, linesY: i, line: line[n : n+maxX]}
|
|
||||||
v.viewLines = append(v.viewLines, vline)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
vline := viewLine{linesX: 0, linesY: i, line: line}
|
|
||||||
v.viewLines = append(v.viewLines, vline)
|
v.viewLines = append(v.viewLines, vline)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -368,7 +359,7 @@ func (v *View) draw() error {
|
|||||||
if err := v.setRune(x, y, c.chr, fgColor, bgColor); err != nil {
|
if err := v.setRune(x, y, c.chr, fgColor, bgColor); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
x++
|
x += runewidth.RuneWidth(c.chr)
|
||||||
}
|
}
|
||||||
y++
|
y++
|
||||||
}
|
}
|
||||||
@ -438,11 +429,7 @@ func (v *View) BufferLines() []string {
|
|||||||
// Buffer returns a string with the contents of the view's internal
|
// Buffer returns a string with the contents of the view's internal
|
||||||
// buffer.
|
// buffer.
|
||||||
func (v *View) Buffer() string {
|
func (v *View) Buffer() string {
|
||||||
str := ""
|
return linesToString(v.lines)
|
||||||
for _, l := range v.lines {
|
|
||||||
str += lineType(l).String() + "\n"
|
|
||||||
}
|
|
||||||
return strings.Replace(str, "\x00", " ", -1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ViewBufferLines returns the lines in the view's internal
|
// ViewBufferLines returns the lines in the view's internal
|
||||||
@ -460,11 +447,12 @@ func (v *View) ViewBufferLines() []string {
|
|||||||
// ViewBuffer returns a string with the contents of the view's buffer that is
|
// ViewBuffer returns a string with the contents of the view's buffer that is
|
||||||
// shown to the user.
|
// shown to the user.
|
||||||
func (v *View) ViewBuffer() string {
|
func (v *View) ViewBuffer() string {
|
||||||
str := ""
|
lines := make([][]cell, len(v.viewLines))
|
||||||
for _, l := range v.viewLines {
|
for i := range v.viewLines {
|
||||||
str += lineType(l.line).String() + "\n"
|
lines[i] = v.viewLines[i].line
|
||||||
}
|
}
|
||||||
return strings.Replace(str, "\x00", " ", -1)
|
|
||||||
|
return linesToString(lines)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
@ -516,3 +504,49 @@ func (v *View) Word(x, y int) (string, error) {
|
|||||||
func indexFunc(r rune) bool {
|
func indexFunc(r rune) bool {
|
||||||
return r == ' ' || r == 0
|
return r == ' ' || r == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func lineWidth(line []cell) (n int) {
|
||||||
|
for i := range line {
|
||||||
|
n += runewidth.RuneWidth(line[i].chr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func lineWrap(line []cell, columns int) [][]cell {
|
||||||
|
if columns == 0 {
|
||||||
|
return [][]cell{line}
|
||||||
|
}
|
||||||
|
|
||||||
|
var n int
|
||||||
|
var offset int
|
||||||
|
lines := make([][]cell, 0, 1)
|
||||||
|
for i := range line {
|
||||||
|
rw := runewidth.RuneWidth(line[i].chr)
|
||||||
|
n += rw
|
||||||
|
if n > columns {
|
||||||
|
n = rw
|
||||||
|
lines = append(lines, line[offset:i-1])
|
||||||
|
offset = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lines = append(lines, line[offset:])
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func linesToString(lines [][]cell) string {
|
||||||
|
str := make([]string, len(lines))
|
||||||
|
for i := range lines {
|
||||||
|
rns := make([]rune, 0, len(lines[i]))
|
||||||
|
line := lineType(lines[i]).String()
|
||||||
|
for _, c := range line {
|
||||||
|
if c != '\x00' {
|
||||||
|
rns = append(rns, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
str[i] = string(rns)
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(str, "\n")
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user