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