Add better matchbrace

This commit is contained in:
Zachary Yedidia 2019-08-04 15:11:09 -07:00
parent f39a916e5f
commit d1e713ce08
6 changed files with 73 additions and 23 deletions

View File

@ -933,9 +933,14 @@ func (h *BufPane) paste(clip string) {
func (h *BufPane) JumpToMatchingBrace() bool { func (h *BufPane) JumpToMatchingBrace() bool {
for _, bp := range buffer.BracePairs { for _, bp := range buffer.BracePairs {
r := h.Cursor.RuneUnder(h.Cursor.X) r := h.Cursor.RuneUnder(h.Cursor.X)
if r == bp[0] || r == bp[1] { rl := h.Cursor.RuneUnder(h.Cursor.X - 1)
matchingBrace := h.Buf.FindMatchingBrace(bp, h.Cursor.Loc) if r == bp[0] || r == bp[1] || rl == bp[0] || rl == bp[1] {
h.Cursor.GotoLoc(matchingBrace) matchingBrace, left := h.Buf.FindMatchingBrace(bp, h.Cursor.Loc)
if left {
h.Cursor.GotoLoc(matchingBrace)
} else {
h.Cursor.GotoLoc(matchingBrace.Move(1, h.Buf))
}
} }
} }

View File

@ -651,16 +651,30 @@ var BracePairs = [][2]rune{
// It is given a brace type containing the open and closing character, (for example // It is given a brace type containing the open and closing character, (for example
// '{' and '}') as well as the location to match from // '{' and '}') as well as the location to match from
// TODO: maybe can be more efficient with utf8 package // TODO: maybe can be more efficient with utf8 package
func (b *Buffer) FindMatchingBrace(braceType [2]rune, start Loc) Loc { // returns the location of the matching brace
// if the boolean returned is true then the original matching brace is one character left
// of the starting location
func (b *Buffer) FindMatchingBrace(braceType [2]rune, start Loc) (Loc, bool) {
curLine := []rune(string(b.LineBytes(start.Y))) curLine := []rune(string(b.LineBytes(start.Y)))
startChar := curLine[start.X] startChar := ' '
if start.X >= 0 && start.X < len(curLine) {
startChar = curLine[start.X]
}
leftChar := ' '
if start.X-1 >= 0 && start.X-1 < len(curLine) {
leftChar = curLine[start.X-1]
}
var i int var i int
if startChar == braceType[0] { if startChar == braceType[0] || leftChar == braceType[0] {
for y := start.Y; y < b.LinesNum(); y++ { for y := start.Y; y < b.LinesNum(); y++ {
l := []rune(string(b.LineBytes(y))) l := []rune(string(b.LineBytes(y)))
xInit := 0 xInit := 0
if y == start.Y { if y == start.Y {
xInit = start.X if startChar == braceType[0] {
xInit = start.X
} else {
xInit = start.X - 1
}
} }
for x := xInit; x < len(l); x++ { for x := xInit; x < len(l); x++ {
r := l[x] r := l[x]
@ -669,24 +683,34 @@ func (b *Buffer) FindMatchingBrace(braceType [2]rune, start Loc) Loc {
} else if r == braceType[1] { } else if r == braceType[1] {
i-- i--
if i == 0 { if i == 0 {
return Loc{x, y} if startChar == braceType[0] {
return Loc{x, y}, false
}
return Loc{x, y}, true
} }
} }
} }
} }
} else if startChar == braceType[1] { } else if startChar == braceType[1] || leftChar == braceType[1] {
for y := start.Y; y >= 0; y-- { for y := start.Y; y >= 0; y-- {
l := []rune(string(b.lines[y].data)) l := []rune(string(b.lines[y].data))
xInit := len(l) - 1 xInit := len(l) - 1
if y == start.Y { if y == start.Y {
xInit = start.X if leftChar == braceType[1] {
xInit = start.X - 1
} else {
xInit = start.X
}
} }
for x := xInit; x >= 0; x-- { for x := xInit; x >= 0; x-- {
r := l[x] r := l[x]
if r == braceType[0] { if r == braceType[0] {
i-- i--
if i == 0 { if i == 0 {
return Loc{x, y} if leftChar == braceType[1] {
return Loc{x, y}, true
}
return Loc{x, y}, false
} }
} else if r == braceType[1] { } else if r == braceType[1] {
i++ i++
@ -694,7 +718,7 @@ func (b *Buffer) FindMatchingBrace(braceType [2]rune, start Loc) Loc {
} }
} }
} }
return start return start, true
} }
// Retab changes all tabs to spaces or vice versa // Retab changes all tabs to spaces or vice versa

File diff suppressed because one or more lines are too long

View File

@ -162,8 +162,7 @@ var defaultCommonSettings = map[string]interface{}{
"ignorecase": false, "ignorecase": false,
"indentchar": " ", "indentchar": " ",
"keepautoindent": false, "keepautoindent": false,
"matchbrace": false, "matchbrace": true,
"matchbraceleft": false,
"mkparents": false, "mkparents": false,
"readonly": false, "readonly": false,
"rmtrailingws": false, "rmtrailingws": false,

View File

@ -381,6 +381,27 @@ func (w *BufWindow) displayBuffer() {
b.Highlighter.HighlightMatches(b, w.StartLine, w.StartLine+bufHeight) b.Highlighter.HighlightMatches(b, w.StartLine, w.StartLine+bufHeight)
} }
var matchingBraces []buffer.Loc
// bracePairs is defined in buffer.go
if b.Settings["matchbrace"].(bool) {
for _, bp := range buffer.BracePairs {
for _, c := range b.GetCursors() {
if c.HasSelection() {
continue
}
curX := c.X
curLoc := c.Loc
r := c.RuneUnder(curX)
rl := c.RuneUnder(curX - 1)
if r == bp[0] || r == bp[1] || rl == bp[0] || rl == bp[1] {
mb, _ := b.FindMatchingBrace(bp, curLoc)
matchingBraces = append(matchingBraces, mb)
}
}
}
}
lineNumStyle := config.DefStyle lineNumStyle := config.DefStyle
if style, ok := config.Colorscheme["line-number"]; ok { if style, ok := config.Colorscheme["line-number"]; ok {
lineNumStyle = style lineNumStyle = style
@ -477,6 +498,12 @@ func (w *BufWindow) displayBuffer() {
} }
} }
for _, mb := range matchingBraces {
if mb.X == bloc.X && mb.Y == bloc.Y {
style = style.Underline(true)
}
}
screen.Screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, r, nil, style) screen.Screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, r, nil, style)
if showcursor { if showcursor {

View File

@ -115,15 +115,10 @@ Here are the options that you can set:
default value: `false` default value: `false`
* `matchbrace`: highlight matching braces for '()', '{}', '[]' * `matchbrace`: underline matching braces for '()', '{}', '[]' when the cursor
is on a brace character.
default value: `false` default value: `true`
* `matchbraceleft`: when matching a closing brace, should matching match the
brace directly under the cursor, or the character to the left? only matters
if `matchbrace` is true
default value: `false`
* `mkparents`: if a file is opened on a path that does not exist, the file cannot * `mkparents`: if a file is opened on a path that does not exist, the file cannot
be saved because the parent directories don't exist. This option lets micro be saved because the parent directories don't exist. This option lets micro