diff --git a/cmd/micro/buffer.go b/cmd/micro/buffer.go index c791deaa..fe2f9886 100644 --- a/cmd/micro/buffer.go +++ b/cmd/micro/buffer.go @@ -630,3 +630,58 @@ func (b *Buffer) clearCursors() { b.UpdateCursors() b.Cursor.ResetSelection() } + +var bracePairs = [][2]rune{ + [2]rune{'(', ')'}, + [2]rune{'{', '}'}, + [2]rune{'[', ']'}, +} + +// FindMatchingBrace returns the location in the buffer of the matching bracket +// It is given a brace type containing the open and closing character, (for example +// '{' and '}') as well as the location to match from +func (b *Buffer) FindMatchingBrace(braceType [2]rune, start Loc) Loc { + curLine := []rune(string(b.lines[start.Y].data)) + startChar := curLine[start.X] + var i int + if startChar == braceType[0] { + for y := start.Y; y < b.NumLines; y++ { + l := []rune(string(b.lines[y].data)) + xInit := 0 + if y == start.Y { + xInit = start.X + } + for x := xInit; x < len(l); x++ { + r := l[x] + if r == braceType[0] { + i++ + } else if r == braceType[1] { + i-- + if i == 0 { + return Loc{x, y} + } + } + } + } + } else if startChar == braceType[1] { + for y := start.Y; y >= 0; y-- { + l := []rune(string(b.lines[y].data)) + xInit := len(l) - 1 + if y == start.Y { + xInit = start.X + } + for x := xInit; x >= 0; x-- { + r := l[x] + if r == braceType[0] { + i-- + if i == 0 { + return Loc{x, y} + } + } else if r == braceType[1] { + i++ + } + } + } + } + return start +} diff --git a/cmd/micro/cellview.go b/cmd/micro/cellview.go index 1cab7691..3bdadb7c 100644 --- a/cmd/micro/cellview.go +++ b/cmd/micro/cellview.go @@ -69,6 +69,17 @@ func (c *CellView) Draw(buf *Buffer, top, height, left, width int) { return } + matchingBrace := Loc{-1, -1} + // bracePairs is defined in buffer.go + if buf.Settings["matchbrace"].(bool) { + for _, bp := range bracePairs { + r := buf.Cursor.RuneUnder(buf.Cursor.X) + if r == bp[0] || r == bp[1] { + matchingBrace = buf.FindMatchingBrace(bp, buf.Cursor.Loc) + } + } + } + tabsize := int(buf.Settings["tabsize"].(float64)) softwrap := buf.Settings["softwrap"].(bool) indentrunes := []rune(buf.Settings["indentchar"].(string)) @@ -137,7 +148,12 @@ func (c *CellView) Draw(buf *Buffer, top, height, left, width int) { char := line[colN] if viewCol >= 0 { - c.lines[viewLine][viewCol] = &Char{Loc{viewCol, viewLine}, Loc{colN, lineN}, char, char, curStyle, 1} + st := curStyle + if colN == matchingBrace.X && lineN == matchingBrace.Y { + messenger.Message(matchingBrace) + st = curStyle.Reverse(true) + } + c.lines[viewLine][viewCol] = &Char{Loc{viewCol, viewLine}, Loc{colN, lineN}, char, char, st, 1} } if char == '\t' { charWidth := tabsize - (viewCol+left)%tabsize diff --git a/cmd/micro/settings.go b/cmd/micro/settings.go index 9062d448..08d4adab 100644 --- a/cmd/micro/settings.go +++ b/cmd/micro/settings.go @@ -214,6 +214,7 @@ func DefaultGlobalSettings() map[string]interface{} { "infobar": true, "keepautoindent": false, "keymenu": false, + "matchbrace": false, "mouse": true, "pluginchannels": []string{"https://raw.githubusercontent.com/micro-editor/plugin-channel/master/channel.json"}, "pluginrepos": []string{}, @@ -255,6 +256,7 @@ func DefaultLocalSettings() map[string]interface{} { "ignorecase": false, "indentchar": " ", "keepautoindent": false, + "matchbrace": false, "rmtrailingws": false, "ruler": true, "savecursor": false,