From c1dd403ab9a324ce376d5e9cd3f30c6ad45c3a1a Mon Sep 17 00:00:00 2001 From: Saeed Rasooli Date: Tue, 11 Oct 2016 23:05:41 +0330 Subject: [PATCH 1/3] Feature: add MoveLinesUp (Alt + Up) and MoveLinesDown (Alt + Down) actions --- cmd/micro/actions.go | 79 ++++++++++++++++++++++++++++++++++++++++++ cmd/micro/bindings.go | 4 +++ cmd/micro/lineArray.go | 25 +++++++++++++ 3 files changed, 108 insertions(+) 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]) From e4386d9398e4ddec531d7e2c0155eecd0ab45220 Mon Sep 17 00:00:00 2001 From: Saeed Rasooli Date: Wed, 12 Oct 2016 01:04:28 +0330 Subject: [PATCH 2/3] add help for MoveLinesUp and MoveLinesDown --- runtime/help/keybindings.md | 4 ++++ 1 file changed, 4 insertions(+) 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 From 0bf07eadcc18e172d718d4a19626af3a6785db55 Mon Sep 17 00:00:00 2001 From: Saeed Rasooli Date: Wed, 12 Oct 2016 08:14:49 +0330 Subject: [PATCH 3/3] Improvement: move MoveLinesUp and MoveLinesDown to Buffer enables Undo/Redo with EventHandler, #407 --- cmd/micro/buffer.go | 38 ++++++++++++++++++++++++++++++++++++++ cmd/micro/lineArray.go | 25 ------------------------- 2 files changed, 38 insertions(+), 25 deletions(-) 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/cmd/micro/lineArray.go b/cmd/micro/lineArray.go index 54af5858..87f7395a 100644 --- a/cmd/micro/lineArray.go +++ b/cmd/micro/lineArray.go @@ -132,31 +132,6 @@ 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])