diff --git a/internal/action/actions.go b/internal/action/actions.go index 2b36795a96..f47c838872 100644 --- a/internal/action/actions.go +++ b/internal/action/actions.go @@ -1293,19 +1293,24 @@ func (h *BufPane) paste(clip string) { // JumpToMatchingBrace moves the cursor to the matching brace if it is // currently on a brace func (h *BufPane) JumpToMatchingBrace() bool { - for _, bp := range buffer.BracePairs { - r := h.Cursor.RuneUnder(h.Cursor.X) - rl := h.Cursor.RuneUnder(h.Cursor.X - 1) - if r == bp[0] || r == bp[1] || rl == bp[0] || rl == bp[1] { - matchingBrace, left, found := h.Buf.FindMatchingBrace(bp, h.Cursor.Loc) - if found { - if left { - h.Cursor.GotoLoc(matchingBrace) - } else { - h.Cursor.GotoLoc(matchingBrace.Move(1, h.Buf)) + for _, pair := range h.Buf.Settings["bracepairs"].([]interface{}) { + strPair := pair.(string) + if util.CharacterCountInString(strPair) == 2 { + runes := []rune(strPair) + bp := [2]rune{runes[0], runes[1]} + r := h.Cursor.RuneUnder(h.Cursor.X) + rl := h.Cursor.RuneUnder(h.Cursor.X - 1) + if r == bp[0] || r == bp[1] || rl == bp[0] || rl == bp[1] { + matchingBrace, left, found := h.Buf.FindMatchingBrace(bp, h.Cursor.Loc) + if found { + if left { + h.Cursor.GotoLoc(matchingBrace) + } else { + h.Cursor.GotoLoc(matchingBrace.Move(1, h.Buf)) + } + h.Relocate() + return true } - h.Relocate() - return true } } } diff --git a/internal/buffer/buffer.go b/internal/buffer/buffer.go index 38461fbf0c..6a3c51d1e0 100644 --- a/internal/buffer/buffer.go +++ b/internal/buffer/buffer.go @@ -974,12 +974,6 @@ func (b *Buffer) MoveLinesDown(start int, end int) { ) } -var BracePairs = [][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 diff --git a/internal/config/settings.go b/internal/config/settings.go index 78db9427b0..dbe944c980 100644 --- a/internal/config/settings.go +++ b/internal/config/settings.go @@ -43,6 +43,7 @@ func init() { // Options with validators var optionValidators = map[string]optionValidator{ "autosave": validateNonNegativeValue, + "bracepairs": validateBracePairs, "clipboard": validateClipboard, "tabsize": validatePositiveValue, "scrollmargin": validateNonNegativeValue, @@ -89,7 +90,7 @@ func ReadSettings() error { func verifySetting(option string, value reflect.Type, def reflect.Type) bool { var interfaceArr []interface{} switch option { - case "pluginrepos", "pluginchannels": + case "bracepairs", "pluginrepos", "pluginchannels": return value.AssignableTo(reflect.TypeOf(interfaceArr)) default: return def.AssignableTo(value) @@ -277,6 +278,7 @@ var defaultCommonSettings = map[string]interface{}{ "backup": true, "backupdir": "", "basename": false, + "bracepairs": []interface{}{"()", "{}", "[]"}, "colorcolumn": float64(0), "cursorline": true, "diffgutter": false, @@ -413,6 +415,16 @@ func GetNativeValue(option string, realValue interface{}, value string) (interfa return nil, ErrInvalidValue } native = float64(i) + } else if kind == reflect.Slice { + var s []interface{} + parts := strings.Split(value, " ") + if len(parts) == 0 { + return nil, ErrInvalidValue + } + for _, pair := range parts { + s = append(s, pair) + } + native = s } else { return nil, ErrInvalidValue } @@ -462,6 +474,16 @@ func validateNonNegativeValue(option string, value interface{}) error { return nil } +func validateBracePairs(option string, value interface{}) error { + _, ok := value.([]interface{}) + + if !ok { + return errors.New("Expected slice of strings") + } + + return nil +} + func validateColorscheme(option string, value interface{}) error { colorscheme, ok := value.(string) diff --git a/internal/display/bufwindow.go b/internal/display/bufwindow.go index fde209695a..6a2ce251ff 100644 --- a/internal/display/bufwindow.go +++ b/internal/display/bufwindow.go @@ -390,26 +390,30 @@ func (w *BufWindow) displayBuffer() { } 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, left, found := b.FindMatchingBrace(bp, curLoc) - if found { - matchingBraces = append(matchingBraces, mb) - if !left { - matchingBraces = append(matchingBraces, curLoc) - } else { - matchingBraces = append(matchingBraces, curLoc.Move(-1, b)) + for _, pair := range b.Settings["bracepairs"].([]interface{}) { + strPair := pair.(string) + if util.CharacterCountInString(strPair) == 2 { + runes := []rune(strPair) + bp := [2]rune{runes[0], runes[1]} + 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, left, found := b.FindMatchingBrace(bp, curLoc) + if found { + matchingBraces = append(matchingBraces, mb) + if !left { + matchingBraces = append(matchingBraces, curLoc) + } else { + matchingBraces = append(matchingBraces, curLoc.Move(-1, b)) + } } } } diff --git a/runtime/help/options.md b/runtime/help/options.md index 791d52ff98..0d352bea55 100644 --- a/runtime/help/options.md +++ b/runtime/help/options.md @@ -54,6 +54,11 @@ Here are the available options: default value: `false` +* `bracepairs`: controls which characters shall be handled as start and end + of brace pairs. + + default value: `"()", "{}", "[]"` + * `clipboard`: specifies how micro should access the system clipboard. Possible values are: * `external`: accesses clipboard via an external tool, such as xclip/xsel