Skip to content

Commit 9eb8782

Browse files
authored
Rework FindMatchingBrace() interface and implementation (zyedidia#3319)
Instead of passing a single brace pair to FindMatchingBrace(), make it traverse all brace pairs in buffer.BracePairs on its own. This has the following advantages: 1. Makes FindMatchingBrace() easier to use, in particular much easier to use from Lua. 2. Lets FindMatchingBrace() ensure that we use just one matching brace - the higher-priority one. This fixes the following issues: ([foo]bar) ^ when the cursor is on `[`: - Both `[]` and `()` pairs are highlighted, whereas the expected behavior is that only one pair is highlighted - the one that the JumpToMatchingBrace action would jump to. - JumpToMatchingBrace action incorrectly jumps to `)` instead of `]` (which should take higher priority in this case). In contrast, with `((foo)bar)` it works correctly.
1 parent 46e55c8 commit 9eb8782

File tree

3 files changed

+71
-73
lines changed

3 files changed

+71
-73
lines changed

internal/action/actions.go

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,21 +1394,15 @@ func (h *BufPane) paste(clip string) {
13941394
// JumpToMatchingBrace moves the cursor to the matching brace if it is
13951395
// currently on a brace
13961396
func (h *BufPane) JumpToMatchingBrace() bool {
1397-
for _, bp := range buffer.BracePairs {
1398-
r := h.Cursor.RuneUnder(h.Cursor.X)
1399-
rl := h.Cursor.RuneUnder(h.Cursor.X - 1)
1400-
if r == bp[0] || r == bp[1] || rl == bp[0] || rl == bp[1] {
1401-
matchingBrace, left, found := h.Buf.FindMatchingBrace(bp, h.Cursor.Loc)
1402-
if found {
1403-
if left {
1404-
h.Cursor.GotoLoc(matchingBrace)
1405-
} else {
1406-
h.Cursor.GotoLoc(matchingBrace.Move(1, h.Buf))
1407-
}
1408-
h.Relocate()
1409-
return true
1410-
}
1397+
matchingBrace, left, found := h.Buf.FindMatchingBrace(h.Cursor.Loc)
1398+
if found {
1399+
if left {
1400+
h.Cursor.GotoLoc(matchingBrace)
1401+
} else {
1402+
h.Cursor.GotoLoc(matchingBrace.Move(1, h.Buf))
14111403
}
1404+
h.Relocate()
1405+
return true
14121406
}
14131407
return false
14141408
}

internal/buffer/buffer.go

Lines changed: 50 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,34 +1140,14 @@ var BracePairs = [][2]rune{
11401140
{'[', ']'},
11411141
}
11421142

1143-
// FindMatchingBrace returns the location in the buffer of the matching bracket
1144-
// It is given a brace type containing the open and closing character, (for example
1145-
// '{' and '}') as well as the location to match from
1146-
// TODO: maybe can be more efficient with utf8 package
1147-
// returns the location of the matching brace
1148-
// if the boolean returned is true then the original matching brace is one character left
1149-
// of the starting location
1150-
func (b *Buffer) FindMatchingBrace(braceType [2]rune, start Loc) (Loc, bool, bool) {
1151-
curLine := []rune(string(b.LineBytes(start.Y)))
1152-
startChar := ' '
1153-
if start.X >= 0 && start.X < len(curLine) {
1154-
startChar = curLine[start.X]
1155-
}
1156-
leftChar := ' '
1157-
if start.X-1 >= 0 && start.X-1 < len(curLine) {
1158-
leftChar = curLine[start.X-1]
1159-
}
1143+
func (b *Buffer) findMatchingBrace(braceType [2]rune, start Loc, char rune) (Loc, bool) {
11601144
var i int
1161-
if startChar == braceType[0] || (leftChar == braceType[0] && startChar != braceType[1]) {
1145+
if char == braceType[0] {
11621146
for y := start.Y; y < b.LinesNum(); y++ {
11631147
l := []rune(string(b.LineBytes(y)))
11641148
xInit := 0
11651149
if y == start.Y {
1166-
if startChar == braceType[0] {
1167-
xInit = start.X
1168-
} else {
1169-
xInit = start.X - 1
1170-
}
1150+
xInit = start.X
11711151
}
11721152
for x := xInit; x < len(l); x++ {
11731153
r := l[x]
@@ -1176,24 +1156,17 @@ func (b *Buffer) FindMatchingBrace(braceType [2]rune, start Loc) (Loc, bool, boo
11761156
} else if r == braceType[1] {
11771157
i--
11781158
if i == 0 {
1179-
if startChar == braceType[0] {
1180-
return Loc{x, y}, false, true
1181-
}
1182-
return Loc{x, y}, true, true
1159+
return Loc{x, y}, true
11831160
}
11841161
}
11851162
}
11861163
}
1187-
} else if startChar == braceType[1] || leftChar == braceType[1] {
1164+
} else if char == braceType[1] {
11881165
for y := start.Y; y >= 0; y-- {
11891166
l := []rune(string(b.lines[y].data))
11901167
xInit := len(l) - 1
11911168
if y == start.Y {
1192-
if startChar == braceType[1] {
1193-
xInit = start.X
1194-
} else {
1195-
xInit = start.X - 1
1196-
}
1169+
xInit = start.X
11971170
}
11981171
for x := xInit; x >= 0; x-- {
11991172
r := l[x]
@@ -1202,16 +1175,55 @@ func (b *Buffer) FindMatchingBrace(braceType [2]rune, start Loc) (Loc, bool, boo
12021175
} else if r == braceType[0] {
12031176
i--
12041177
if i == 0 {
1205-
if startChar == braceType[1] {
1206-
return Loc{x, y}, false, true
1207-
}
1208-
return Loc{x, y}, true, true
1178+
return Loc{x, y}, true
12091179
}
12101180
}
12111181
}
12121182
}
12131183
}
1214-
return start, true, false
1184+
return start, false
1185+
}
1186+
1187+
// If there is a brace character (for example '{' or ']') at the given start location,
1188+
// FindMatchingBrace returns the location of the matching brace for it (for example '}'
1189+
// or '['). The second returned value is true if there was no matching brace found
1190+
// for given starting location but it was found for the location one character left
1191+
// of it. The third returned value is true if the matching brace was found at all.
1192+
func (b *Buffer) FindMatchingBrace(start Loc) (Loc, bool, bool) {
1193+
// TODO: maybe can be more efficient with utf8 package
1194+
curLine := []rune(string(b.LineBytes(start.Y)))
1195+
1196+
// first try to find matching brace for the given location (it has higher priority)
1197+
if start.X >= 0 && start.X < len(curLine) {
1198+
startChar := curLine[start.X]
1199+
1200+
for _, bp := range BracePairs {
1201+
if startChar == bp[0] || startChar == bp[1] {
1202+
mb, found := b.findMatchingBrace(bp, start, startChar)
1203+
if found {
1204+
return mb, false, true
1205+
}
1206+
}
1207+
}
1208+
}
1209+
1210+
// failed to find matching brace for the given location, so try to find matching
1211+
// brace for the location one character left of it
1212+
if start.X-1 >= 0 && start.X-1 < len(curLine) {
1213+
leftChar := curLine[start.X-1]
1214+
left := Loc{start.X - 1, start.Y}
1215+
1216+
for _, bp := range BracePairs {
1217+
if leftChar == bp[0] || leftChar == bp[1] {
1218+
mb, found := b.findMatchingBrace(bp, left, leftChar)
1219+
if found {
1220+
return mb, true, true
1221+
}
1222+
}
1223+
}
1224+
}
1225+
1226+
return start, false, false
12151227
}
12161228

12171229
// Retab changes all tabs to spaces or vice versa

internal/display/bufwindow.go

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -392,28 +392,20 @@ func (w *BufWindow) displayBuffer() {
392392
var matchingBraces []buffer.Loc
393393
// bracePairs is defined in buffer.go
394394
if b.Settings["matchbrace"].(bool) {
395-
for _, bp := range buffer.BracePairs {
396-
for _, c := range b.GetCursors() {
397-
if c.HasSelection() {
398-
continue
399-
}
400-
curX := c.X
401-
curLoc := c.Loc
402-
403-
r := c.RuneUnder(curX)
404-
rl := c.RuneUnder(curX - 1)
405-
if r == bp[0] || r == bp[1] || rl == bp[0] || rl == bp[1] {
406-
mb, left, found := b.FindMatchingBrace(bp, curLoc)
407-
if found {
408-
matchingBraces = append(matchingBraces, mb)
409-
if !left {
410-
if b.Settings["matchbracestyle"].(string) != "highlight" {
411-
matchingBraces = append(matchingBraces, curLoc)
412-
}
413-
} else {
414-
matchingBraces = append(matchingBraces, curLoc.Move(-1, b))
415-
}
395+
for _, c := range b.GetCursors() {
396+
if c.HasSelection() {
397+
continue
398+
}
399+
400+
mb, left, found := b.FindMatchingBrace(c.Loc)
401+
if found {
402+
matchingBraces = append(matchingBraces, mb)
403+
if !left {
404+
if b.Settings["matchbracestyle"].(string) != "highlight" {
405+
matchingBraces = append(matchingBraces, c.Loc)
416406
}
407+
} else {
408+
matchingBraces = append(matchingBraces, c.Loc.Move(-1, b))
417409
}
418410
}
419411
}

0 commit comments

Comments
 (0)