@@ -1173,86 +1173,187 @@ var BracePairs = [][2]rune{
11731173 {'[' , ']' },
11741174}
11751175
1176- func (b * Buffer ) findMatchingBrace (braceType [2 ]rune , start Loc , char rune ) (Loc , bool ) {
1177- var i int
1178- if char == braceType [0 ] {
1179- for y := start .Y ; y < b .LinesNum (); y ++ {
1180- l := []rune (string (b .LineBytes (y )))
1181- xInit := 0
1182- if y == start .Y {
1183- xInit = start .X
1176+ func (b * Buffer ) resolveBraceStartLoc (start Loc ) Loc {
1177+ var onbrace bool = false
1178+ // TODO: maybe can be more efficient with utf8 package
1179+ curLine := []rune (string (b .LineBytes (start .Y )))
1180+ // See if we are on any brace
1181+ if start .X >= 0 && start .X < len (curLine ) {
1182+ startChar := curLine [start .X ]
1183+ for _ , bp := range BracePairs {
1184+ if startChar == bp [0 ] || startChar == bp [1 ] {
1185+ return start
11841186 }
1185- for x := xInit ; x < len ( l ); x ++ {
1186- r := l [ x ]
1187- if r == braceType [ 0 ] {
1188- i ++
1189- } else if r == braceType [ 1 ] {
1190- i --
1191- if i == 0 {
1192- return Loc { x , y }, true
1193- }
1187+ }
1188+ }
1189+
1190+ if ! onbrace && b . Settings [ "matchbraceleft" ].( bool ) {
1191+ if start . X - 1 >= 0 && start . X - 1 < len ( curLine ) {
1192+ startChar := curLine [ start . X - 1 ]
1193+ for _ , bp := range BracePairs {
1194+ if startChar == bp [ 0 ] || startChar == bp [ 1 ] {
1195+ return Loc { start . X - 1 , start . Y }
11941196 }
11951197 }
11961198 }
1197- } else if char == braceType [1 ] {
1198- for y := start .Y ; y >= 0 ; y -- {
1199- l := []rune (string (b .lines [y ].data ))
1200- xInit := len (l ) - 1
1201- if y == start .Y {
1202- xInit = start .X
1199+ }
1200+ return start
1201+ }
1202+
1203+ func (b * Buffer ) findOpeningBrace (braceType [2 ]rune , start Loc ) (Loc , bool ) {
1204+ // Bound guard
1205+ start = clamp (start , b .LineArray )
1206+ if len (b .lines ) == 0 {
1207+ return start , false
1208+ }
1209+
1210+ i := 1
1211+ // If we are on a closing brace, let the counter be incremented below when we traverse
1212+ curLine := []rune (string (b .LineBytes (start .Y )))
1213+ if start .X >= 0 && start .X < len (curLine ) {
1214+ startChar := curLine [start .X ]
1215+ if startChar == braceType [1 ] {
1216+ i = 0
1217+ }
1218+ }
1219+
1220+ for y := start .Y ; y >= 0 ; y -- {
1221+ l := []rune (string (b .lines [y ].data ))
1222+ xInit := len (l ) - 1
1223+ if y == start .Y && start .X < len (curLine ) {
1224+ xInit = start .X
1225+ }
1226+ for x := xInit ; x >= 0 ; x -- {
1227+ r := l [x ]
1228+ if r == braceType [1 ] {
1229+ i ++
1230+ } else if r == braceType [0 ] {
1231+ i --
1232+ if i == 0 {
1233+ return Loc {x , y }, true
1234+ }
12031235 }
1204- for x := xInit ; x >= 0 ; x -- {
1205- r := l [x ]
1206- if r == braceType [1 ] {
1207- i ++
1208- } else if r == braceType [0 ] {
1209- i --
1210- if i == 0 {
1211- return Loc {x , y }, true
1212- }
1236+ }
1237+ }
1238+ return start , false
1239+ }
1240+
1241+ // Returns the opening brace in current brace scope starting at the start location and a boolean
1242+ // indicating if an opening brace is found
1243+ func (b * Buffer ) FindOpeningBrace (start Loc ) (Loc , bool ) {
1244+ currentDist := - 1
1245+ currentMb := Loc {- 1 , - 1 }
1246+ start = b .resolveBraceStartLoc (start )
1247+ for _ , bp := range BracePairs {
1248+ mb , found := b .findOpeningBrace (bp , start )
1249+ if found {
1250+ dist := DiffLA (start , mb , b .LineArray )
1251+ if currentDist < 0 || dist < currentDist {
1252+ currentMb = mb
1253+ currentDist = dist
1254+ }
1255+ }
1256+ }
1257+
1258+ if currentDist == - 1 {
1259+ return start , false
1260+ } else {
1261+ return currentMb , true
1262+ }
1263+ }
1264+
1265+ func (b * Buffer ) findClosingBrace (braceType [2 ]rune , start Loc ) (Loc , bool ) {
1266+ // Bound guard
1267+ start = clamp (start , b .LineArray )
1268+ if len (b .lines ) == 0 {
1269+ return start , false
1270+ }
1271+
1272+ i := 1
1273+ // If we are on an opening brace, let the counter be incremented below when we traverse
1274+ curLine := []rune (string (b .LineBytes (start .Y )))
1275+ if start .X >= 0 && start .X < len (curLine ) {
1276+ startChar := curLine [start .X ]
1277+ if startChar == braceType [0 ] {
1278+ i = 0
1279+ }
1280+ }
1281+
1282+ for y := start .Y ; y < b .LinesNum (); y ++ {
1283+ l := []rune (string (b .LineBytes (y )))
1284+ xInit := 0
1285+ if y == start .Y && start .X >= 0 {
1286+ xInit = start .X
1287+ }
1288+ for x := xInit ; x < len (l ); x ++ {
1289+ r := l [x ]
1290+ if r == braceType [0 ] {
1291+ i ++
1292+ } else if r == braceType [1 ] {
1293+ i --
1294+ if i == 0 {
1295+ return Loc {x , y }, true
12131296 }
12141297 }
12151298 }
12161299 }
12171300 return start , false
12181301}
12191302
1303+ // Returns the closing brace in current brace scope starting at the start location and a boolean
1304+ // indicating if an closing brace is found
1305+ func (b * Buffer ) FindClosingBrace (start Loc ) (Loc , bool ) {
1306+ currentDist := - 1
1307+ currentMb := Loc {- 1 , - 1 }
1308+ start = b .resolveBraceStartLoc (start )
1309+ for _ , bp := range BracePairs {
1310+ mb , found := b .findClosingBrace (bp , start )
1311+ if found {
1312+ dist := DiffLA (start , mb , b .LineArray )
1313+ if currentDist < 0 || dist < currentDist {
1314+ currentMb = mb
1315+ currentDist = dist
1316+ }
1317+ }
1318+ }
1319+
1320+ if currentDist == - 1 {
1321+ return start , false
1322+ } else {
1323+ return currentMb , true
1324+ }
1325+ }
1326+
1327+ func (b * Buffer ) findMatchingBrace (braceType [2 ]rune , start Loc , char rune ) (Loc , bool ) {
1328+ if char == braceType [0 ] {
1329+ return b .findClosingBrace (braceType , start )
1330+ } else if char == braceType [1 ] {
1331+ return b .findOpeningBrace (braceType , start )
1332+ }
1333+ return start , false
1334+ }
1335+
12201336// If there is a brace character (for example '{' or ']') at the given start location,
12211337// FindMatchingBrace returns the location of the matching brace for it (for example '}'
12221338// or '['). The second returned value is true if there was no matching brace found
12231339// for given starting location but it was found for the location one character left
12241340// of it. The third returned value is true if the matching brace was found at all.
12251341func (b * Buffer ) FindMatchingBrace (start Loc ) (Loc , bool , bool ) {
1226- // TODO: maybe can be more efficient with utf8 package
1342+ newstart := b .resolveBraceStartLoc (start )
1343+ var left bool = false
1344+ if start != newstart {
1345+ left = true
1346+ start = newstart
1347+ }
12271348 curLine := []rune (string (b .LineBytes (start .Y )))
12281349
1229- // first try to find matching brace for the given location (it has higher priority)
12301350 if start .X >= 0 && start .X < len (curLine ) {
12311351 startChar := curLine [start .X ]
1232-
12331352 for _ , bp := range BracePairs {
12341353 if startChar == bp [0 ] || startChar == bp [1 ] {
12351354 mb , found := b .findMatchingBrace (bp , start , startChar )
12361355 if found {
1237- return mb , false , true
1238- }
1239- }
1240- }
1241- }
1242-
1243- if b .Settings ["matchbraceleft" ].(bool ) {
1244- // failed to find matching brace for the given location, so try to find matching
1245- // brace for the location one character left of it
1246- if start .X - 1 >= 0 && start .X - 1 < len (curLine ) {
1247- leftChar := curLine [start .X - 1 ]
1248- left := Loc {start .X - 1 , start .Y }
1249-
1250- for _ , bp := range BracePairs {
1251- if leftChar == bp [0 ] || leftChar == bp [1 ] {
1252- mb , found := b .findMatchingBrace (bp , left , leftChar )
1253- if found {
1254- return mb , true , true
1255- }
1356+ return mb , left , true
12561357 }
12571358 }
12581359 }
0 commit comments