Merge branch 'master' into fix/file-detection

This commit is contained in:
Dmytro Maluka
2024-03-14 04:32:09 +01:00
committed by GitHub
65 changed files with 1114 additions and 363 deletions

View File

@@ -64,7 +64,7 @@ func (b *Buffer) CycleAutocomplete(forward bool) {
// GetWord gets the most recent word separated by any separator
// (whitespace, punctuation, any non alphanumeric character)
func GetWord(b *Buffer) ([]byte, int) {
func (b *Buffer) GetWord() ([]byte, int) {
c := b.GetActiveCursor()
l := b.LineBytes(c.Y)
l = util.SliceStart(l, c.X)
@@ -83,7 +83,7 @@ func GetWord(b *Buffer) ([]byte, int) {
}
// GetArg gets the most recent word (separated by ' ' only)
func GetArg(b *Buffer) (string, int) {
func (b *Buffer) GetArg() (string, int) {
c := b.GetActiveCursor()
l := b.LineBytes(c.Y)
l = util.SliceStart(l, c.X)
@@ -104,7 +104,7 @@ func GetArg(b *Buffer) (string, int) {
// FileComplete autocompletes filenames
func FileComplete(b *Buffer) ([]string, []string) {
c := b.GetActiveCursor()
input, argstart := GetArg(b)
input, argstart := b.GetArg()
sep := string(os.PathSeparator)
dirs := strings.Split(input, sep)
@@ -153,7 +153,7 @@ func FileComplete(b *Buffer) ([]string, []string) {
// BufferComplete autocompletes based on previous words in the buffer
func BufferComplete(b *Buffer) ([]string, []string) {
c := b.GetActiveCursor()
input, argstart := GetWord(b)
input, argstart := b.GetWord()
if argstart == -1 {
return []string{}, []string{}

View File

@@ -568,6 +568,13 @@ func (b *Buffer) RelocateCursors() {
}
}
// DeselectCursors removes selection from all cursors
func (b *Buffer) DeselectCursors() {
for _, c := range b.cursors {
c.Deselect(true)
}
}
// RuneAt returns the rune at a given location in the buffer
func (b *Buffer) RuneAt(loc Loc) rune {
line := b.LineBytes(loc.Y)
@@ -1056,7 +1063,7 @@ func (b *Buffer) FindMatchingBrace(braceType [2]rune, start Loc) (Loc, bool, boo
leftChar = curLine[start.X-1]
}
var i int
if startChar == braceType[0] || leftChar == braceType[0] {
if startChar == braceType[0] || (leftChar == braceType[0] && startChar != braceType[1]) {
for y := start.Y; y < b.LinesNum(); y++ {
l := []rune(string(b.LineBytes(y)))
xInit := 0
@@ -1087,24 +1094,24 @@ func (b *Buffer) FindMatchingBrace(braceType [2]rune, start Loc) (Loc, bool, boo
l := []rune(string(b.lines[y].data))
xInit := len(l) - 1
if y == start.Y {
if leftChar == braceType[1] {
xInit = start.X - 1
} else {
if startChar == braceType[1] {
xInit = start.X
} else {
xInit = start.X - 1
}
}
for x := xInit; x >= 0; x-- {
r := l[x]
if r == braceType[0] {
if r == braceType[1] {
i++
} else if r == braceType[0] {
i--
if i == 0 {
if leftChar == braceType[1] {
return Loc{x, y}, true, true
if startChar == braceType[1] {
return Loc{x, y}, false, true
}
return Loc{x, y}, false, true
return Loc{x, y}, true, true
}
} else if r == braceType[1] {
i++
}
}
}

View File

@@ -30,6 +30,11 @@ type Cursor struct {
// to know what the original selection was
OrigSelection [2]Loc
// The line number where a new trailing whitespace has been added
// or -1 if there is no new trailing whitespace at this cursor.
// This is used for checking if a trailing whitespace should be highlighted
NewTrailingWsY int
// Which cursor index is this (for multiple cursors)
Num int
}
@@ -38,6 +43,8 @@ func NewCursor(b *Buffer, l Loc) *Cursor {
c := &Cursor{
buf: b,
Loc: l,
NewTrailingWsY: -1,
}
c.StoreVisualX()
return c

View File

@@ -106,6 +106,10 @@ func (eh *EventHandler) DoTextEvent(t *TextEvent, useUndo bool) {
c.Relocate()
c.LastVisualX = c.GetVisualX()
}
if useUndo {
eh.updateTrailingWs(t)
}
}
// ExecuteTextEvent runs a text event
@@ -290,6 +294,7 @@ func (eh *EventHandler) UndoOneEvent() {
if teCursor.Num >= 0 && teCursor.Num < len(eh.cursors) {
t.C = *eh.cursors[teCursor.Num]
eh.cursors[teCursor.Num].Goto(teCursor)
eh.cursors[teCursor.Num].NewTrailingWsY = teCursor.NewTrailingWsY
} else {
teCursor.Num = -1
}
@@ -333,6 +338,7 @@ func (eh *EventHandler) RedoOneEvent() {
if teCursor.Num >= 0 && teCursor.Num < len(eh.cursors) {
t.C = *eh.cursors[teCursor.Num]
eh.cursors[teCursor.Num].Goto(teCursor)
eh.cursors[teCursor.Num].NewTrailingWsY = teCursor.NewTrailingWsY
} else {
teCursor.Num = -1
}
@@ -342,3 +348,58 @@ func (eh *EventHandler) RedoOneEvent() {
eh.UndoStack.Push(t)
}
// updateTrailingWs updates the cursor's trailing whitespace status after a text event
func (eh *EventHandler) updateTrailingWs(t *TextEvent) {
if len(t.Deltas) != 1 {
return
}
text := t.Deltas[0].Text
start := t.Deltas[0].Start
end := t.Deltas[0].End
c := eh.cursors[eh.active]
isEol := func(loc Loc) bool {
return loc.X == util.CharacterCount(eh.buf.LineBytes(loc.Y))
}
if t.EventType == TextEventInsert && c.Loc == end && isEol(end) {
var addedTrailingWs bool
addedAfterWs := false
addedWsOnly := false
if start.Y == end.Y {
addedTrailingWs = util.HasTrailingWhitespace(text)
addedWsOnly = util.IsBytesWhitespace(text)
addedAfterWs = start.X > 0 && util.IsWhitespace(c.buf.RuneAt(Loc{start.X - 1, start.Y}))
} else {
lastnl := bytes.LastIndex(text, []byte{'\n'})
addedTrailingWs = util.HasTrailingWhitespace(text[lastnl+1:])
}
if addedTrailingWs && !(addedAfterWs && addedWsOnly) {
c.NewTrailingWsY = c.Y
} else if !addedTrailingWs {
c.NewTrailingWsY = -1
}
} else if t.EventType == TextEventRemove && c.Loc == start && isEol(start) {
removedAfterWs := util.HasTrailingWhitespace(eh.buf.LineBytes(start.Y))
var removedWsOnly bool
if start.Y == end.Y {
removedWsOnly = util.IsBytesWhitespace(text)
} else {
firstnl := bytes.Index(text, []byte{'\n'})
removedWsOnly = util.IsBytesWhitespace(text[:firstnl])
}
if removedAfterWs && !removedWsOnly {
c.NewTrailingWsY = c.Y
} else if !removedAfterWs {
c.NewTrailingWsY = -1
}
} else if c.NewTrailingWsY != -1 && start.Y != end.Y && c.Loc.GreaterThan(start) &&
((t.EventType == TextEventInsert && c.Y == c.NewTrailingWsY+(end.Y-start.Y)) ||
(t.EventType == TextEventRemove && c.Y == c.NewTrailingWsY-(end.Y-start.Y))) {
// The cursor still has its new trailingws
// but its line number was shifted by insert or remove of lines above
c.NewTrailingWsY = c.Y
}
}

View File

@@ -54,7 +54,7 @@ func overwriteFile(name string, enc encoding.Encoding, fn func(io.Writer) error,
screen.TempStart(screenb)
return err
}
} else if writeCloser, err = os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644); err != nil {
} else if writeCloser, err = os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666); err != nil {
return
}