diff --git a/cmd/micro/action/actions.go b/cmd/micro/action/actions.go index cd9e944b..76ec9ecc 100644 --- a/cmd/micro/action/actions.go +++ b/cmd/micro/action/actions.go @@ -758,11 +758,64 @@ func (h *BufHandler) DeleteLine() bool { // MoveLinesUp moves up the current line or selected lines if any func (h *BufHandler) MoveLinesUp() bool { + if h.Cursor.HasSelection() { + if h.Cursor.CurSelection[0].Y == 0 { + InfoBar.Message("Can not move further up") + return true + } + start := h.Cursor.CurSelection[0].Y + end := h.Cursor.CurSelection[1].Y + if start > end { + end, start = start, end + } + + h.Buf.MoveLinesUp( + start, + end, + ) + h.Cursor.CurSelection[1].Y -= 1 + } else { + if h.Cursor.Loc.Y == 0 { + InfoBar.Message("Can not move further up") + return true + } + h.Buf.MoveLinesUp( + h.Cursor.Loc.Y, + h.Cursor.Loc.Y+1, + ) + } + return true } // MoveLinesDown moves down the current line or selected lines if any func (h *BufHandler) MoveLinesDown() bool { + if h.Cursor.HasSelection() { + if h.Cursor.CurSelection[1].Y >= h.Buf.LinesNum() { + InfoBar.Message("Can not move further down") + return true + } + start := h.Cursor.CurSelection[0].Y + end := h.Cursor.CurSelection[1].Y + if start > end { + end, start = start, end + } + + h.Buf.MoveLinesDown( + start, + end, + ) + } else { + if h.Cursor.Loc.Y >= h.Buf.LinesNum()-1 { + InfoBar.Message("Can not move further down") + return true + } + h.Buf.MoveLinesDown( + h.Cursor.Loc.Y, + h.Cursor.Loc.Y+1, + ) + } + return true } @@ -803,6 +856,14 @@ func (h *BufHandler) paste(clip string) { // JumpToMatchingBrace moves the cursor to the matching brace if it is // currently on a brace func (h *BufHandler) JumpToMatchingBrace() bool { + for _, bp := range buffer.BracePairs { + r := h.Cursor.RuneUnder(h.Cursor.X) + if r == bp[0] || r == bp[1] { + matchingBrace := h.Buf.FindMatchingBrace(bp, h.Cursor.Loc) + h.Cursor.GotoLoc(matchingBrace) + } + } + return true } diff --git a/cmd/micro/buffer/buffer.go b/cmd/micro/buffer/buffer.go index c5c0f4bb..cc5658ad 100644 --- a/cmd/micro/buffer/buffer.go +++ b/cmd/micro/buffer/buffer.go @@ -504,3 +504,100 @@ func (b *Buffer) ClearCursors() { b.curCursor = 0 b.GetActiveCursor().ResetSelection() } + +// MoveLinesUp moves the range of lines up one row +func (b *Buffer) MoveLinesUp(start int, end int) { + if start < 1 || start >= end || end > len(b.lines) { + return + } + if end == len(b.lines) { + b.Insert( + Loc{ + utf8.RuneCount(b.lines[end-1].data), + end - 1, + }, + append([]byte{'\n'}, b.LineBytes(start-1)...), + ) + } else { + b.Insert( + Loc{0, end}, + append(b.LineBytes(start-1), '\n'), + ) + } + b.Remove( + Loc{0, start - 1}, + Loc{0, start}, + ) +} + +// MoveLinesDown moves the range of lines down one row +func (b *Buffer) MoveLinesDown(start int, end int) { + if start < 0 || start >= end || end >= len(b.lines)-1 { + return + } + b.Insert( + Loc{0, start}, + append(b.LineBytes(end), '\n'), + ) + end++ + b.Remove( + Loc{0, end}, + Loc{0, end + 1}, + ) +} + +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 +// TODO: maybe can be more efficient with utf8 package +func (b *Buffer) FindMatchingBrace(braceType [2]rune, start Loc) Loc { + curLine := []rune(string(b.LineBytes(start.Y))) + startChar := curLine[start.X] + var i int + if startChar == braceType[0] { + for y := start.Y; y < b.LinesNum(); y++ { + l := []rune(string(b.LineBytes(y))) + 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 +}