mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-07-05 00:59:19 +02:00
fix editor
This commit is contained in:
committed by
github-actions[bot]
parent
7564e506b5
commit
345c90ac05
473
vendor/github.com/jesseduffield/gocui/edit.go
generated
vendored
473
vendor/github.com/jesseduffield/gocui/edit.go
generated
vendored
@ -6,14 +6,8 @@ package gocui
|
||||
|
||||
import (
|
||||
"unicode"
|
||||
|
||||
"github.com/go-errors/errors"
|
||||
|
||||
"github.com/mattn/go-runewidth"
|
||||
)
|
||||
|
||||
const maxInt = int(^uint(0) >> 1)
|
||||
|
||||
// Editor interface must be satisfied by gocui editors.
|
||||
type Editor interface {
|
||||
Edit(v *View, key Key, ch rune, mod Modifier) bool
|
||||
@ -34,467 +28,40 @@ var DefaultEditor Editor = EditorFunc(simpleEditor)
|
||||
|
||||
// simpleEditor is used as the default gocui editor.
|
||||
func simpleEditor(v *View, key Key, ch rune, mod Modifier) bool {
|
||||
matched := true
|
||||
|
||||
switch {
|
||||
case ch != 0 && mod == 0:
|
||||
v.EditWrite(ch)
|
||||
case key == KeySpace:
|
||||
v.EditWrite(' ')
|
||||
case key == KeyBackspace || key == KeyBackspace2:
|
||||
v.EditDelete(true)
|
||||
v.TextArea.BackSpaceChar()
|
||||
case key == KeyCtrlD || key == KeyDelete:
|
||||
v.EditDelete(false)
|
||||
case key == KeyInsert:
|
||||
v.Overwrite = !v.Overwrite
|
||||
v.TextArea.DeleteChar()
|
||||
case key == KeyArrowDown:
|
||||
v.MoveCursor(0, 1, false)
|
||||
v.TextArea.MoveCursorDown()
|
||||
case key == KeyArrowUp:
|
||||
v.MoveCursor(0, -1, false)
|
||||
v.TextArea.MoveCursorUp()
|
||||
case key == KeyArrowLeft:
|
||||
v.MoveCursor(-1, 0, false)
|
||||
v.TextArea.MoveCursorLeft()
|
||||
case key == KeyArrowRight:
|
||||
v.MoveCursor(1, 0, false)
|
||||
v.TextArea.MoveCursorRight()
|
||||
case key == KeyEnter:
|
||||
v.EditNewLine()
|
||||
v.TextArea.TypeRune('\n')
|
||||
case key == KeySpace:
|
||||
v.TextArea.TypeRune(' ')
|
||||
case key == KeyInsert:
|
||||
v.TextArea.ToggleOverwrite()
|
||||
case key == KeyCtrlU:
|
||||
v.EditDeleteToStartOfLine()
|
||||
v.TextArea.DeleteToStartOfLine()
|
||||
case key == KeyCtrlA:
|
||||
v.EditGotoToStartOfLine()
|
||||
v.TextArea.GoToStartOfLine()
|
||||
case key == KeyCtrlE:
|
||||
v.EditGotoToEndOfLine()
|
||||
matched = true
|
||||
v.TextArea.GoToEndOfLine()
|
||||
|
||||
// TODO: see if we need all three of these conditions: maybe the final one is sufficient
|
||||
// TODO: see if we need all three of these conditions: maybe the final one is sufficient
|
||||
case ch != 0 && mod == 0 && unicode.IsPrint(ch):
|
||||
v.EditWrite(ch)
|
||||
v.TextArea.TypeRune(ch)
|
||||
default:
|
||||
matched = false
|
||||
return false
|
||||
}
|
||||
|
||||
return matched
|
||||
}
|
||||
|
||||
// EditWrite writes a rune at the cursor position.
|
||||
func (v *View) EditWrite(ch rune) {
|
||||
w := runewidth.RuneWidth(ch)
|
||||
if w == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
v.writeRune(v.cx, v.cy, ch)
|
||||
v.moveCursor(w, 0, true)
|
||||
}
|
||||
|
||||
func (v *View) EditWriteString(str string) {
|
||||
for _, ch := range str {
|
||||
v.EditWrite(ch)
|
||||
}
|
||||
}
|
||||
|
||||
func (v *View) SetEditorContent(content string) error {
|
||||
v.Clear()
|
||||
if err := v.SetOrigin(0, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v.SetCursor(0, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
v.EditWriteString(content)
|
||||
return nil
|
||||
}
|
||||
|
||||
// EditDeleteToStartOfLine is the equivalent of pressing ctrl+U in your terminal, it deletes to the start of the line. Or if you are already at the start of the line, it deletes the newline character
|
||||
func (v *View) EditDeleteToStartOfLine() {
|
||||
x, _ := v.Cursor()
|
||||
if x == 0 {
|
||||
v.EditDelete(true)
|
||||
} else {
|
||||
// delete characters until we are the start of the line
|
||||
for x > 0 {
|
||||
v.EditDelete(true)
|
||||
x, _ = v.Cursor()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// EditGotoToStartOfLine takes you to the start of the current line
|
||||
func (v *View) EditGotoToStartOfLine() {
|
||||
x, _ := v.Cursor()
|
||||
for x > 0 {
|
||||
v.MoveCursor(-1, 0, false)
|
||||
x, _ = v.Cursor()
|
||||
}
|
||||
}
|
||||
|
||||
// EditGotoToEndOfLine takes you to the end of the line
|
||||
func (v *View) EditGotoToEndOfLine() {
|
||||
_, y := v.Cursor()
|
||||
_ = v.SetCursor(0, y+1)
|
||||
x, newY := v.Cursor()
|
||||
if newY == y {
|
||||
// we must be on the last line, so lets move to the very end
|
||||
prevX := -1
|
||||
for prevX != x {
|
||||
prevX = x
|
||||
v.MoveCursor(1, 0, false)
|
||||
x, _ = v.Cursor()
|
||||
}
|
||||
} else {
|
||||
// most left so now we're at the end of the original line
|
||||
v.MoveCursor(-1, 0, false)
|
||||
}
|
||||
}
|
||||
|
||||
// EditDelete deletes a rune at the cursor position. back determines the
|
||||
// direction.
|
||||
func (v *View) EditDelete(back bool) {
|
||||
v.writeMutex.Lock()
|
||||
defer v.writeMutex.Unlock()
|
||||
|
||||
x, y := v.ox+v.cx, v.oy+v.cy
|
||||
if y < 0 {
|
||||
return
|
||||
} else if y >= len(v.viewLines) {
|
||||
v.MoveCursor(-1, 0, true)
|
||||
return
|
||||
}
|
||||
|
||||
maxX, _ := v.Size()
|
||||
if back {
|
||||
if x == 0 { // start of the line
|
||||
if y < 1 {
|
||||
return
|
||||
}
|
||||
|
||||
var maxPrevWidth int
|
||||
if v.Wrap {
|
||||
maxPrevWidth = maxX
|
||||
} else {
|
||||
maxPrevWidth = maxInt
|
||||
}
|
||||
|
||||
if v.viewLines[y].linesX == 0 { // regular line
|
||||
v.mergeLines(v.cy - 1)
|
||||
if len(v.viewLines[y-1].line) < maxPrevWidth {
|
||||
v.MoveCursor(-1, 0, true)
|
||||
}
|
||||
} else { // wrapped line
|
||||
n, _ := v.deleteRune(len(v.viewLines[y-1].line)-1, v.cy-1)
|
||||
v.MoveCursor(-n, 0, true)
|
||||
}
|
||||
} else { // middle/end of the line
|
||||
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
|
||||
v.mergeLines(v.cy)
|
||||
} else { // start/middle of the line
|
||||
v.deleteRune(v.cx, v.cy)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// EditNewLine inserts a new line under the cursor.
|
||||
func (v *View) EditNewLine() {
|
||||
v.writeMutex.Lock()
|
||||
defer v.writeMutex.Unlock()
|
||||
|
||||
v.breakLine(v.cx, v.cy)
|
||||
v.ox = 0
|
||||
v.cy = v.cy + 1
|
||||
v.cx = 0
|
||||
}
|
||||
|
||||
// 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
|
||||
curLineWidth = maxInt
|
||||
if v.Wrap {
|
||||
curLineWidth = maxX - 1
|
||||
}
|
||||
|
||||
if !writeMode {
|
||||
curLineWidth = 0
|
||||
if y >= 0 && y < len(v.viewLines) {
|
||||
curLineWidth = lineWidth(v.viewLines[y].line)
|
||||
if v.Wrap && curLineWidth >= maxX {
|
||||
curLineWidth = maxX - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
// get the width of the previous line
|
||||
prevLineWidth = 0
|
||||
if y-1 >= 0 && y-1 < len(v.viewLines) {
|
||||
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
|
||||
cy++
|
||||
if writeMode || v.oy+cy < len(v.viewLines) {
|
||||
if !v.Wrap {
|
||||
v.ox = 0
|
||||
}
|
||||
v.cx = 0
|
||||
}
|
||||
} else { // vertical movement
|
||||
if curLineWidth > 0 { // move cursor to the EOL
|
||||
if v.Wrap {
|
||||
v.cx = curLineWidth
|
||||
} else {
|
||||
ncx := curLineWidth - v.ox
|
||||
if ncx < 0 {
|
||||
v.ox += ncx
|
||||
if v.ox < 0 {
|
||||
v.ox = 0
|
||||
}
|
||||
v.cx = 0
|
||||
} else {
|
||||
v.cx = ncx
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if writeMode || v.oy+cy < len(v.viewLines) {
|
||||
if !v.Wrap {
|
||||
v.ox = 0
|
||||
}
|
||||
v.cx = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if cx < 0 {
|
||||
if !v.Wrap && v.ox > 0 { // move origin to the left
|
||||
v.ox += cx
|
||||
v.cx = 0
|
||||
} else { // move to previous line
|
||||
cy--
|
||||
if prevLineWidth > 0 {
|
||||
if !v.Wrap { // set origin so the EOL is visible
|
||||
nox := prevLineWidth - maxX + 1
|
||||
if nox < 0 {
|
||||
nox = 0
|
||||
}
|
||||
v.ox = nox
|
||||
}
|
||||
v.cx = prevLineWidth
|
||||
} else {
|
||||
if !v.Wrap {
|
||||
v.ox = 0
|
||||
}
|
||||
v.cx = 0
|
||||
}
|
||||
}
|
||||
} else { // stay on the same line
|
||||
if v.Wrap {
|
||||
v.cx = cx
|
||||
} else {
|
||||
if cx >= maxX {
|
||||
v.ox += cx - maxX + 1
|
||||
v.cx = maxX
|
||||
} else {
|
||||
v.cx = cx
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// adjust cursor's y position and view's y origin
|
||||
if cy < 0 {
|
||||
if v.oy > 0 {
|
||||
v.oy--
|
||||
}
|
||||
} else if writeMode || v.oy+cy < len(v.viewLines) {
|
||||
if cy >= maxY {
|
||||
v.oy++
|
||||
} else {
|
||||
v.cy = cy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// writeRune writes a rune into the view's internal buffer, at the
|
||||
// position corresponding to the point (x, y). The length of the internal
|
||||
// buffer is increased if the point is out of bounds. Overwrite mode is
|
||||
// governed by the value of View.overwrite.
|
||||
func (v *View) writeRune(x, y int, ch rune) error {
|
||||
v.writeMutex.Lock()
|
||||
defer v.writeMutex.Unlock()
|
||||
|
||||
v.tainted = true
|
||||
|
||||
x, y, err := v.realPosition(x, y)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if x < 0 || y < 0 {
|
||||
return errors.New("invalid point")
|
||||
}
|
||||
|
||||
if y >= len(v.lines) {
|
||||
s := make([][]cell, y-len(v.lines)+1)
|
||||
v.lines = append(v.lines, s...)
|
||||
}
|
||||
|
||||
olen := len(v.lines[y])
|
||||
w := runewidth.RuneWidth(ch)
|
||||
|
||||
var s []cell
|
||||
if x >= len(v.lines[y]) {
|
||||
s = make([]cell, x-len(v.lines[y])+w)
|
||||
} else if !v.Overwrite {
|
||||
s = make([]cell, w)
|
||||
}
|
||||
v.lines[y] = append(v.lines[y], s...)
|
||||
|
||||
if !v.Overwrite || (v.Overwrite && x >= olen-w) {
|
||||
copy(v.lines[y][x+w:], v.lines[y][x:])
|
||||
}
|
||||
v.lines[y][x] = cell{
|
||||
fgColor: v.FgColor,
|
||||
bgColor: v.BgColor,
|
||||
chr: ch,
|
||||
}
|
||||
|
||||
for i := 1; i < w; i++ {
|
||||
v.lines[y][x+i] = cell{
|
||||
fgColor: v.FgColor,
|
||||
bgColor: v.BgColor,
|
||||
chr: '\x00',
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// deleteRune removes a rune from the view's internal buffer, at the
|
||||
// position corresponding to the point (x, y).
|
||||
// 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 0, err
|
||||
}
|
||||
|
||||
if x < 0 || y < 0 || y >= len(v.lines) || x >= len(v.lines[y]) {
|
||||
return 0, errors.New("invalid point")
|
||||
}
|
||||
|
||||
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+w:]...)
|
||||
return w, nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// mergeLines merges the lines "y" and "y+1" if possible.
|
||||
func (v *View) mergeLines(y int) error {
|
||||
v.clearViewLines()
|
||||
|
||||
_, y, err := v.realPosition(0, y)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if y < 0 || y >= len(v.lines) {
|
||||
return errors.New("invalid point")
|
||||
}
|
||||
|
||||
if y < len(v.lines)-1 { // otherwise we don't need to merge anything
|
||||
v.lines[y] = append(v.lines[y], v.lines[y+1]...)
|
||||
v.lines = append(v.lines[:y+1], v.lines[y+2:]...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// breakLine breaks a line of the internal buffer at the position corresponding
|
||||
// to the point (x, y).
|
||||
func (v *View) breakLine(x, y int) error {
|
||||
v.tainted = true
|
||||
|
||||
x, y, err := v.realPosition(x, y)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if y < 0 || y >= len(v.lines) {
|
||||
return errors.New("invalid point")
|
||||
}
|
||||
|
||||
var left, right []cell
|
||||
if x < len(v.lines[y]) { // break line
|
||||
left = make([]cell, len(v.lines[y][:x]))
|
||||
copy(left, v.lines[y][:x])
|
||||
right = make([]cell, len(v.lines[y][x:]))
|
||||
copy(right, v.lines[y][x:])
|
||||
} else { // new empty line
|
||||
left = v.lines[y]
|
||||
}
|
||||
|
||||
lines := make([][]cell, len(v.lines)+1)
|
||||
lines[y] = left
|
||||
lines[y+1] = right
|
||||
copy(lines, v.lines[:y])
|
||||
copy(lines[y+2:], v.lines[y+1:])
|
||||
v.lines = lines
|
||||
return nil
|
||||
v.RenderTextArea()
|
||||
|
||||
return true
|
||||
}
|
||||
|
5
vendor/github.com/jesseduffield/gocui/go.mod
generated
vendored
5
vendor/github.com/jesseduffield/gocui/go.mod
generated
vendored
@ -3,7 +3,8 @@ module github.com/jesseduffield/gocui
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/gdamore/tcell/v2 v2.0.0
|
||||
github.com/gdamore/tcell/v2 v2.4.0
|
||||
github.com/go-errors/errors v1.0.2
|
||||
github.com/mattn/go-runewidth v0.0.9
|
||||
github.com/mattn/go-runewidth v0.0.10
|
||||
github.com/stretchr/testify v1.7.0
|
||||
)
|
||||
|
28
vendor/github.com/jesseduffield/gocui/go.sum
generated
vendored
28
vendor/github.com/jesseduffield/gocui/go.sum
generated
vendored
@ -1,15 +1,29 @@
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
|
||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||
github.com/gdamore/tcell/v2 v2.0.0 h1:GRWG8aLfWAlekj9Q6W29bVvkHENc6hp79XOqG4AWDOs=
|
||||
github.com/gdamore/tcell/v2 v2.0.0/go.mod h1:vSVL/GV5mCSlPC6thFP5kfOFdM9MGZcalipmpTxTgQA=
|
||||
github.com/gdamore/tcell/v2 v2.4.0 h1:W6dxJEmaxYvhICFoTY3WrLLEXsQ11SaFnKGVEXW57KM=
|
||||
github.com/gdamore/tcell/v2 v2.4.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU=
|
||||
github.com/go-errors/errors v1.0.2 h1:xMxH9j2fNg/L4hLn/4y3M0IUsn0M6Wbu/Uh9QlOfBh4=
|
||||
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756 h1:9nuHUbU8dRnRRfj9KjWUVrJeoexdbeMjttk6Oh1rD10=
|
||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg=
|
||||
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M=
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
209
vendor/github.com/jesseduffield/gocui/text_area.go
generated
vendored
Normal file
209
vendor/github.com/jesseduffield/gocui/text_area.go
generated
vendored
Normal file
@ -0,0 +1,209 @@
|
||||
package gocui
|
||||
|
||||
import "github.com/mattn/go-runewidth"
|
||||
|
||||
type TextArea struct {
|
||||
content []rune
|
||||
cursor int
|
||||
overwrite bool
|
||||
}
|
||||
|
||||
func (self *TextArea) TypeRune(r rune) {
|
||||
if self.overwrite && !self.atEnd() {
|
||||
self.content[self.cursor] = r
|
||||
} else {
|
||||
self.content = append(
|
||||
self.content[:self.cursor],
|
||||
append([]rune{r}, self.content[self.cursor:]...)...,
|
||||
)
|
||||
}
|
||||
|
||||
self.cursor++
|
||||
}
|
||||
|
||||
func (self *TextArea) BackSpaceChar() {
|
||||
if self.cursor == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
self.content = append(self.content[:self.cursor-1], self.content[self.cursor:]...)
|
||||
self.cursor--
|
||||
}
|
||||
|
||||
func (self *TextArea) DeleteChar() {
|
||||
if self.atEnd() {
|
||||
return
|
||||
}
|
||||
|
||||
self.content = append(self.content[:self.cursor], self.content[self.cursor+1:]...)
|
||||
}
|
||||
|
||||
func (self *TextArea) MoveCursorLeft() {
|
||||
if self.cursor == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
self.cursor--
|
||||
}
|
||||
|
||||
func (self *TextArea) MoveCursorRight() {
|
||||
if self.cursor == len(self.content) {
|
||||
return
|
||||
}
|
||||
|
||||
self.cursor++
|
||||
}
|
||||
|
||||
func (self *TextArea) MoveCursorUp() {
|
||||
x, y := self.GetCursorXY()
|
||||
self.SetCursor2D(x, y-1)
|
||||
}
|
||||
|
||||
func (self *TextArea) MoveCursorDown() {
|
||||
x, y := self.GetCursorXY()
|
||||
self.SetCursor2D(x, y+1)
|
||||
}
|
||||
|
||||
func (self *TextArea) GetContent() string {
|
||||
return string(self.content)
|
||||
}
|
||||
|
||||
func (self *TextArea) ToggleOverwrite() {
|
||||
self.overwrite = !self.overwrite
|
||||
}
|
||||
|
||||
func (self *TextArea) atEnd() bool {
|
||||
return self.cursor == len(self.content)
|
||||
}
|
||||
|
||||
func (self *TextArea) DeleteToStartOfLine() {
|
||||
// copying vim's logic: if you're at the start of the line, you delete the newline
|
||||
// character and go to the end of the previous line
|
||||
if self.atLineStart() {
|
||||
if self.cursor == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
self.content = append(self.content[:self.cursor-1], self.content[self.cursor:]...)
|
||||
self.cursor--
|
||||
return
|
||||
}
|
||||
|
||||
// otherwise, you delete everything up to the start of the current line, without
|
||||
// deleting the newline character
|
||||
newlineIndex := self.closestNewlineOnLeft()
|
||||
self.content = append(self.content[:newlineIndex+1], self.content[self.cursor:]...)
|
||||
self.cursor = newlineIndex + 1
|
||||
}
|
||||
|
||||
func (self *TextArea) GoToStartOfLine() {
|
||||
if self.atLineStart() {
|
||||
return
|
||||
}
|
||||
|
||||
// otherwise, you delete everything up to the start of the current line, without
|
||||
// deleting the newline character
|
||||
newlineIndex := self.closestNewlineOnLeft()
|
||||
self.cursor = newlineIndex + 1
|
||||
}
|
||||
|
||||
func (self *TextArea) closestNewlineOnLeft() int {
|
||||
newlineIndex := -1
|
||||
|
||||
for i, r := range self.content[0:self.cursor] {
|
||||
if r == '\n' {
|
||||
newlineIndex = i
|
||||
}
|
||||
}
|
||||
|
||||
return newlineIndex
|
||||
}
|
||||
|
||||
func (self *TextArea) GoToEndOfLine() {
|
||||
if self.atEnd() {
|
||||
return
|
||||
}
|
||||
|
||||
self.cursor = self.closestNewlineOnRight()
|
||||
}
|
||||
|
||||
func (self *TextArea) closestNewlineOnRight() int {
|
||||
for i, r := range self.content[self.cursor:] {
|
||||
if r == '\n' {
|
||||
return self.cursor + i
|
||||
}
|
||||
}
|
||||
|
||||
return len(self.content)
|
||||
}
|
||||
|
||||
func (self *TextArea) atLineStart() bool {
|
||||
return self.cursor == 0 ||
|
||||
(len(self.content) > self.cursor-1 && self.content[self.cursor-1] == '\n')
|
||||
}
|
||||
|
||||
func (self *TextArea) GetCursorXY() (int, int) {
|
||||
cursorX := 0
|
||||
cursorY := 0
|
||||
for _, r := range self.content[0:self.cursor] {
|
||||
if r == '\n' {
|
||||
cursorY++
|
||||
cursorX = 0
|
||||
} else {
|
||||
chWidth := runewidth.RuneWidth(r)
|
||||
cursorX += chWidth
|
||||
}
|
||||
}
|
||||
|
||||
return cursorX, cursorY
|
||||
}
|
||||
|
||||
// takes an x,y position and maps it to a 1D cursor position
|
||||
func (self *TextArea) SetCursor2D(x int, y int) {
|
||||
if y < 0 {
|
||||
y = 0
|
||||
}
|
||||
if x < 0 {
|
||||
x = 0
|
||||
}
|
||||
|
||||
newCursor := 0
|
||||
for _, r := range self.content {
|
||||
if x <= 0 && y == 0 {
|
||||
self.cursor = newCursor
|
||||
return
|
||||
}
|
||||
|
||||
if r == '\n' {
|
||||
if y == 0 {
|
||||
self.cursor = newCursor
|
||||
return
|
||||
}
|
||||
y--
|
||||
} else if y == 0 {
|
||||
chWidth := runewidth.RuneWidth(r)
|
||||
x -= chWidth
|
||||
}
|
||||
|
||||
newCursor++
|
||||
}
|
||||
|
||||
// if we weren't able to run-down our arg, the user is trying to move out of
|
||||
// bounds so we'll just return
|
||||
if y > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
self.cursor = newCursor
|
||||
}
|
||||
|
||||
func (self *TextArea) Clear() {
|
||||
self.content = []rune{}
|
||||
self.cursor = 0
|
||||
}
|
||||
|
||||
func (self *TextArea) TypeString(str string) {
|
||||
for _, r := range str {
|
||||
self.TypeRune(r)
|
||||
}
|
||||
}
|
44
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
44
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
@ -6,6 +6,7 @@ package gocui
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -158,6 +159,8 @@ type View struct {
|
||||
// KeybindOnEdit should be set to true when you want to execute keybindings even when the view is editable
|
||||
// (this is usually not the case)
|
||||
KeybindOnEdit bool
|
||||
|
||||
TextArea *TextArea
|
||||
}
|
||||
|
||||
// call this in the event of a view resize, or if you want to render new content
|
||||
@ -340,6 +343,7 @@ func newView(name string, x0, y0, x1, y1 int, mode OutputMode) *View {
|
||||
outMode: mode,
|
||||
ei: newEscapeInterpreter(mode),
|
||||
searcher: &searcher{},
|
||||
TextArea: &TextArea{},
|
||||
}
|
||||
|
||||
v.FgColor, v.BgColor = ColorDefault, ColorDefault
|
||||
@ -1119,3 +1123,43 @@ func (v *View) SelectedPoint() (int, int) {
|
||||
ox, oy := v.Origin()
|
||||
return cx + ox, cy + oy
|
||||
}
|
||||
|
||||
func (v *View) RenderTextArea() {
|
||||
v.Clear()
|
||||
fmt.Fprint(v, v.TextArea.GetContent())
|
||||
cursorX, cursorY := v.TextArea.GetCursorXY()
|
||||
prevOriginX, prevOriginY := v.Origin()
|
||||
width, height := v.Size()
|
||||
|
||||
frameAdjustment := 0
|
||||
if v.Frame {
|
||||
frameAdjustment = -1
|
||||
}
|
||||
newViewCursorX, newOriginX := updatedCursorAndOrigin(prevOriginX, width+frameAdjustment, cursorX)
|
||||
newViewCursorY, newOriginY := updatedCursorAndOrigin(prevOriginY, height+frameAdjustment, cursorY)
|
||||
|
||||
_ = v.SetCursor(newViewCursorX, newViewCursorY)
|
||||
_ = v.SetOrigin(newOriginX, newOriginY)
|
||||
}
|
||||
|
||||
func updatedCursorAndOrigin(prevOrigin int, size int, cursor int) (int, int) {
|
||||
var newViewCursor int
|
||||
newOrigin := prevOrigin
|
||||
|
||||
if cursor > prevOrigin+size {
|
||||
newOrigin = cursor - size
|
||||
newViewCursor = size
|
||||
} else if cursor < prevOrigin {
|
||||
newOrigin = cursor
|
||||
newViewCursor = 0
|
||||
} else {
|
||||
newViewCursor = cursor - prevOrigin
|
||||
}
|
||||
|
||||
return newViewCursor, newOrigin
|
||||
}
|
||||
|
||||
func (v *View) ClearTextArea() {
|
||||
v.TextArea.Clear()
|
||||
v.Clear()
|
||||
}
|
||||
|
Reference in New Issue
Block a user