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/lineArray.go b/cmd/micro/lineArray.go index 87f7395a..54af5858 100644 --- a/cmd/micro/lineArray.go +++ b/cmd/micro/lineArray.go @@ -132,6 +132,31 @@ func (la *LineArray) DeleteByte(pos Loc) { la.lines[pos.Y] = la.lines[pos.Y][:pos.X+copy(la.lines[pos.Y][pos.X:], la.lines[pos.Y][pos.X+1:])] } +func (la *LineArray) MoveLinesUp(y0 int, y1 int) { + // 0 < y0 < y1 <= len(la.lines) + if y0 < 1 || y0 >= y1 || y1 > len(la.lines) { + return // what to do? FIXME + } + before := la.lines[y0-1] + for y := y0 ; y < y1 ; y ++ { + la.lines[y-1] = la.lines[y] + } + la.lines[y1-1] = before +} + +func (la *LineArray) MoveLinesDown(y0 int, y1 int) { + // 0 <= y0 < y1 < len(la.lines) + if y0 < 0 || y0 >= y1 || y1 >= len(la.lines) { + return // what to do? FIXME + } + after := la.lines[y1] + for y := y1-1 ; y >= y0 ; y -- { + la.lines[y+1] = la.lines[y] + } + la.lines[y0] = after +} + + // Substr returns the string representation between two locations func (la *LineArray) Substr(start, end Loc) string { startX := runeToByteIndex(start.X, la.lines[start.Y])