diff --git a/cmd/micro/actions.go b/cmd/micro/actions.go index 94177dca..68f71952 100644 --- a/cmd/micro/actions.go +++ b/cmd/micro/actions.go @@ -968,6 +968,85 @@ func (v *View) DeleteLine(usePlugin bool) bool { return true } +// MoveLinesUp moves up the current line or selected lines if any +func (v *View) MoveLinesUp(usePlugin bool) bool { + if usePlugin && !PreActionCall("MoveLinesUp", v) { + return false + } + + if v.Cursor.HasSelection() { + if v.Cursor.CurSelection[0].Y == 0 { + messenger.Message("Can not move further up") + return true + } + v.Buf.MoveLinesUp( + v.Cursor.CurSelection[0].Y, + v.Cursor.CurSelection[1].Y, + ) + v.Cursor.UpN(1) + v.Cursor.CurSelection[0].Y -= 1 + v.Cursor.CurSelection[1].Y -= 1 + messenger.Message("Moved up selected line(s)") + } else { + if v.Cursor.Loc.Y == 0 { + messenger.Message("Can not move further up") + return true + } + v.Buf.MoveLinesUp( + v.Cursor.Loc.Y, + v.Cursor.Loc.Y + 1, + ) + v.Cursor.UpN(1) + messenger.Message("Moved up current line") + } + v.Buf.IsModified = true + + if usePlugin { + return PostActionCall("MoveLinesUp", v) + } + return true +} + +// MoveLinesDown moves down the current line or selected lines if any +func (v *View) MoveLinesDown(usePlugin bool) bool { + if usePlugin && !PreActionCall("MoveLinesDown", v) { + return false + } + + if v.Cursor.HasSelection() { + if v.Cursor.CurSelection[1].Y >= len(v.Buf.lines) { + messenger.Message("Can not move further down") + return true + } + v.Buf.MoveLinesDown( + v.Cursor.CurSelection[0].Y, + v.Cursor.CurSelection[1].Y, + ) + v.Cursor.DownN(1) + v.Cursor.CurSelection[0].Y += 1 + v.Cursor.CurSelection[1].Y += 1 + messenger.Message("Moved down selected line(s)") + } else { + if v.Cursor.Loc.Y >= len(v.Buf.lines)-1 { + messenger.Message("Can not move further down") + return true + } + v.Buf.MoveLinesDown( + v.Cursor.Loc.Y, + v.Cursor.Loc.Y + 1, + ) + v.Cursor.DownN(1) + messenger.Message("Moved down current line") + } + v.Buf.IsModified = true + + if usePlugin { + return PostActionCall("MoveLinesDown", v) + } + return true +} + + // Paste whatever is in the system clipboard into the buffer // Delete and paste if the user has a selection func (v *View) Paste(usePlugin bool) bool { diff --git a/cmd/micro/bindings.go b/cmd/micro/bindings.go index b1d00c24..f2c21568 100644 --- a/cmd/micro/bindings.go +++ b/cmd/micro/bindings.go @@ -52,6 +52,8 @@ var bindingActions = map[string]func(*View, bool) bool{ "CutLine": (*View).CutLine, "DuplicateLine": (*View).DuplicateLine, "DeleteLine": (*View).DeleteLine, + "MoveLinesUp": (*View).MoveLinesUp, + "MoveLinesDown": (*View).MoveLinesDown, "IndentSelection": (*View).IndentSelection, "OutdentSelection": (*View).OutdentSelection, "Paste": (*View).Paste, @@ -364,6 +366,8 @@ func DefaultBindings() map[string]string { "ShiftRight": "SelectRight", "AltLeft": "WordLeft", "AltRight": "WordRight", + "AltUp": "MoveLinesUp", + "AltDown": "MoveLinesDown", "AltShiftRight": "SelectWordRight", "AltShiftLeft": "SelectWordLeft", "CtrlLeft": "StartOfLine", diff --git a/cmd/micro/buffer.go b/cmd/micro/buffer.go index 0d893fda..f3f1f742 100644 --- a/cmd/micro/buffer.go +++ b/cmd/micro/buffer.go @@ -363,3 +363,41 @@ func (b *Buffer) Lines(start, end int) []string { func (b *Buffer) Len() int { return Count(b.String()) } + +func (b *Buffer) MoveLinesUp(start int, end int) { + // 0 < start < end <= len(b.lines) + if start < 1 || start >= end || end > len(b.lines) { + return // what to do? FIXME + } + b.Insert( + Loc{0, end}, + b.Line(start - 1) + "\n", + ) + b.Remove( + Loc{0, start - 1}, + Loc{0, start}, + ) +} + +func (b *Buffer) MoveLinesDown(start int, end int) { + // 0 <= start < end < len(b.lines) + if start < 0 || start >= end || end >= len(b.lines) { + return // what to do? FIXME + } + b.Insert( + Loc{0, start}, + b.Line(end) + "\n", + ) + end += 1 + rmEndLoc := Loc{0, end + 1} + if end >= len(b.lines)-1 { + rmEndLoc = Loc{ + utf8.RuneCount(b.lines[end]) - 1, + end, + } + } + b.Remove( + Loc{0, end}, + rmEndLoc, + ) +} diff --git a/runtime/help/keybindings.md b/runtime/help/keybindings.md index 63bfc525..a34ed57b 100644 --- a/runtime/help/keybindings.md +++ b/runtime/help/keybindings.md @@ -17,6 +17,8 @@ you can rebind them to your liking. "AltRight": "WordRight", "AltShiftRight": "SelectWordRight", "AltShiftLeft": "SelectWordLeft", + "AltUp" "MoveLinesUp", + "AltDown" "MoveLinesDown", "CtrlLeft": "StartOfLine", "CtrlRight": "EndOfLine", "CtrlShiftLeft": "SelectToStartOfLine", @@ -140,6 +142,8 @@ WordRight WordLeft SelectWordRight SelectWordLeft +MoveLinesUp +MoveLinesDown DeleteWordRight DeleteWordLeft SelectToStartOfLine