mirror of
https://github.com/zyedidia/micro.git
synced 2026-02-04 22:20:20 +09:00
Merge pull request #3335 from dmaluka/line-actions-cleanup
Improve and unify `CopyLine`, `CutLine`, `DeleteLine`, `DuplicateLine` actions
This commit is contained in:
@@ -1238,101 +1238,179 @@ func (h *BufPane) Redo() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *BufPane) selectLines() int {
|
||||||
|
if h.Cursor.HasSelection() {
|
||||||
|
start := h.Cursor.CurSelection[0]
|
||||||
|
end := h.Cursor.CurSelection[1]
|
||||||
|
if start.GreaterThan(end) {
|
||||||
|
start, end = end, start
|
||||||
|
}
|
||||||
|
if end.X == 0 {
|
||||||
|
end = end.Move(-1, h.Buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Cursor.Deselect(true)
|
||||||
|
h.Cursor.SetSelectionStart(buffer.Loc{0, start.Y})
|
||||||
|
h.Cursor.SetSelectionEnd(buffer.Loc{0, end.Y + 1})
|
||||||
|
} else {
|
||||||
|
h.Cursor.SelectLine()
|
||||||
|
}
|
||||||
|
return h.Cursor.CurSelection[1].Y - h.Cursor.CurSelection[0].Y
|
||||||
|
}
|
||||||
|
|
||||||
// Copy the selection to the system clipboard
|
// Copy the selection to the system clipboard
|
||||||
func (h *BufPane) Copy() bool {
|
func (h *BufPane) Copy() bool {
|
||||||
if h.Cursor.HasSelection() {
|
|
||||||
h.Cursor.CopySelection(clipboard.ClipboardReg)
|
|
||||||
h.freshClip = true
|
|
||||||
InfoBar.Message("Copied selection")
|
|
||||||
}
|
|
||||||
h.Relocate()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopyLine copies the current line to the clipboard
|
|
||||||
func (h *BufPane) CopyLine() bool {
|
|
||||||
if h.Cursor.HasSelection() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
origLoc := h.Cursor.Loc
|
|
||||||
h.Cursor.SelectLine()
|
|
||||||
h.Cursor.CopySelection(clipboard.ClipboardReg)
|
|
||||||
h.freshClip = true
|
|
||||||
InfoBar.Message("Copied line")
|
|
||||||
|
|
||||||
h.Cursor.Deselect(true)
|
|
||||||
h.Cursor.Loc = origLoc
|
|
||||||
h.Relocate()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// CutLine cuts the current line to the clipboard
|
|
||||||
func (h *BufPane) CutLine() bool {
|
|
||||||
h.Cursor.SelectLine()
|
|
||||||
if !h.Cursor.HasSelection() {
|
if !h.Cursor.HasSelection() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if h.freshClip {
|
h.Cursor.CopySelection(clipboard.ClipboardReg)
|
||||||
if h.Cursor.HasSelection() {
|
h.freshClip = false
|
||||||
if clip, err := clipboard.Read(clipboard.ClipboardReg); err != nil {
|
InfoBar.Message("Copied selection")
|
||||||
InfoBar.Error(err)
|
h.Relocate()
|
||||||
} else {
|
return true
|
||||||
clipboard.WriteMulti(clip+string(h.Cursor.GetSelection()), clipboard.ClipboardReg, h.Cursor.Num, h.Buf.NumCursors())
|
}
|
||||||
}
|
|
||||||
}
|
// CopyLine copies the current line to the clipboard. If there is a selection,
|
||||||
} else if time.Since(h.lastCutTime)/time.Second > 10*time.Second || !h.freshClip {
|
// CopyLine copies all the lines that are (fully or partially) in the selection.
|
||||||
h.Copy()
|
func (h *BufPane) CopyLine() bool {
|
||||||
|
origLoc := h.Cursor.Loc
|
||||||
|
origLastVisualX := h.Cursor.LastVisualX
|
||||||
|
origSelection := h.Cursor.CurSelection
|
||||||
|
|
||||||
|
nlines := h.selectLines()
|
||||||
|
if nlines == 0 {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
h.freshClip = true
|
h.Cursor.CopySelection(clipboard.ClipboardReg)
|
||||||
h.lastCutTime = time.Now()
|
h.freshClip = false
|
||||||
h.Cursor.DeleteSelection()
|
if nlines > 1 {
|
||||||
h.Cursor.ResetSelection()
|
InfoBar.Message(fmt.Sprintf("Copied %d lines", nlines))
|
||||||
InfoBar.Message("Cut line")
|
} else {
|
||||||
|
InfoBar.Message("Copied line")
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Cursor.Loc = origLoc
|
||||||
|
h.Cursor.LastVisualX = origLastVisualX
|
||||||
|
h.Cursor.CurSelection = origSelection
|
||||||
h.Relocate()
|
h.Relocate()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cut the selection to the system clipboard
|
// Cut the selection to the system clipboard
|
||||||
func (h *BufPane) Cut() bool {
|
func (h *BufPane) Cut() bool {
|
||||||
if h.Cursor.HasSelection() {
|
if !h.Cursor.HasSelection() {
|
||||||
h.Cursor.CopySelection(clipboard.ClipboardReg)
|
return false
|
||||||
h.Cursor.DeleteSelection()
|
|
||||||
h.Cursor.ResetSelection()
|
|
||||||
h.freshClip = true
|
|
||||||
InfoBar.Message("Cut selection")
|
|
||||||
|
|
||||||
h.Relocate()
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
return h.CutLine()
|
h.Cursor.CopySelection(clipboard.ClipboardReg)
|
||||||
}
|
h.Cursor.DeleteSelection()
|
||||||
|
h.Cursor.ResetSelection()
|
||||||
|
h.freshClip = false
|
||||||
|
InfoBar.Message("Cut selection")
|
||||||
|
|
||||||
// DuplicateLine duplicates the current line or selection
|
|
||||||
func (h *BufPane) DuplicateLine() bool {
|
|
||||||
var infoMessage = "Duplicated line"
|
|
||||||
if h.Cursor.HasSelection() {
|
|
||||||
infoMessage = "Duplicated selection"
|
|
||||||
h.Buf.Insert(h.Cursor.CurSelection[1], string(h.Cursor.GetSelection()))
|
|
||||||
} else {
|
|
||||||
h.Cursor.End()
|
|
||||||
h.Buf.Insert(h.Cursor.Loc, "\n"+string(h.Buf.LineBytes(h.Cursor.Y)))
|
|
||||||
// h.Cursor.Right()
|
|
||||||
}
|
|
||||||
|
|
||||||
InfoBar.Message(infoMessage)
|
|
||||||
h.Relocate()
|
h.Relocate()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteLine deletes the current line
|
// CutLine cuts the current line to the clipboard. If there is a selection,
|
||||||
func (h *BufPane) DeleteLine() bool {
|
// CutLine cuts all the lines that are (fully or partially) in the selection.
|
||||||
h.Cursor.SelectLine()
|
func (h *BufPane) CutLine() bool {
|
||||||
|
nlines := h.selectLines()
|
||||||
|
if nlines == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
totalLines := nlines
|
||||||
|
if h.freshClip {
|
||||||
|
if clip, err := clipboard.Read(clipboard.ClipboardReg); err != nil {
|
||||||
|
InfoBar.Error(err)
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
clipboard.WriteMulti(clip+string(h.Cursor.GetSelection()), clipboard.ClipboardReg, h.Cursor.Num, h.Buf.NumCursors())
|
||||||
|
totalLines = strings.Count(clip, "\n") + nlines
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
h.Cursor.CopySelection(clipboard.ClipboardReg)
|
||||||
|
}
|
||||||
|
h.freshClip = true
|
||||||
|
h.Cursor.DeleteSelection()
|
||||||
|
h.Cursor.ResetSelection()
|
||||||
|
h.Cursor.StoreVisualX()
|
||||||
|
if totalLines > 1 {
|
||||||
|
InfoBar.Message(fmt.Sprintf("Cut %d lines", totalLines))
|
||||||
|
} else {
|
||||||
|
InfoBar.Message("Cut line")
|
||||||
|
}
|
||||||
|
h.Relocate()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duplicate the selection
|
||||||
|
func (h *BufPane) Duplicate() bool {
|
||||||
if !h.Cursor.HasSelection() {
|
if !h.Cursor.HasSelection() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
h.Buf.Insert(h.Cursor.CurSelection[1], string(h.Cursor.GetSelection()))
|
||||||
|
InfoBar.Message("Duplicated selection")
|
||||||
|
h.Relocate()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// DuplicateLine duplicates the current line. If there is a selection, DuplicateLine
|
||||||
|
// duplicates all the lines that are (fully or partially) in the selection.
|
||||||
|
func (h *BufPane) DuplicateLine() bool {
|
||||||
|
if h.Cursor.HasSelection() {
|
||||||
|
origLoc := h.Cursor.Loc
|
||||||
|
origLastVisualX := h.Cursor.LastVisualX
|
||||||
|
origSelection := h.Cursor.CurSelection
|
||||||
|
|
||||||
|
start := h.Cursor.CurSelection[0]
|
||||||
|
end := h.Cursor.CurSelection[1]
|
||||||
|
if start.GreaterThan(end) {
|
||||||
|
start, end = end, start
|
||||||
|
}
|
||||||
|
if end.X == 0 {
|
||||||
|
end = end.Move(-1, h.Buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Cursor.Deselect(true)
|
||||||
|
h.Cursor.Loc = end
|
||||||
|
h.Cursor.End()
|
||||||
|
for y := start.Y; y <= end.Y; y++ {
|
||||||
|
h.Buf.Insert(h.Cursor.Loc, "\n"+string(h.Buf.LineBytes(y)))
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Cursor.Loc = origLoc
|
||||||
|
h.Cursor.LastVisualX = origLastVisualX
|
||||||
|
h.Cursor.CurSelection = origSelection
|
||||||
|
|
||||||
|
if start.Y < end.Y {
|
||||||
|
InfoBar.Message(fmt.Sprintf("Duplicated %d lines", end.Y-start.Y+1))
|
||||||
|
} else {
|
||||||
|
InfoBar.Message("Duplicated line")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
h.Cursor.End()
|
||||||
|
h.Buf.Insert(h.Cursor.Loc, "\n"+string(h.Buf.LineBytes(h.Cursor.Y)))
|
||||||
|
InfoBar.Message("Duplicated line")
|
||||||
|
}
|
||||||
|
h.Relocate()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteLine deletes the current line. If there is a selection, DeleteLine
|
||||||
|
// deletes all the lines that are (fully or partially) in the selection.
|
||||||
|
func (h *BufPane) DeleteLine() bool {
|
||||||
|
nlines := h.selectLines()
|
||||||
|
if nlines == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
h.Cursor.DeleteSelection()
|
h.Cursor.DeleteSelection()
|
||||||
h.Cursor.ResetSelection()
|
h.Cursor.ResetSelection()
|
||||||
InfoBar.Message("Deleted line")
|
h.Cursor.StoreVisualX()
|
||||||
|
if nlines > 1 {
|
||||||
|
InfoBar.Message(fmt.Sprintf("Deleted %d lines", nlines))
|
||||||
|
} else {
|
||||||
|
InfoBar.Message("Deleted line")
|
||||||
|
}
|
||||||
h.Relocate()
|
h.Relocate()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -233,11 +233,8 @@ type BufPane struct {
|
|||||||
lastClickTime time.Time
|
lastClickTime time.Time
|
||||||
lastLoc buffer.Loc
|
lastLoc buffer.Loc
|
||||||
|
|
||||||
// lastCutTime stores when the last ctrl+k was issued.
|
// freshClip returns true if one or more lines have been cut to the clipboard
|
||||||
// It is used for clearing the clipboard to replace it with fresh cut lines.
|
// and have never been pasted yet.
|
||||||
lastCutTime time.Time
|
|
||||||
|
|
||||||
// freshClip returns true if the clipboard has never been pasted.
|
|
||||||
freshClip bool
|
freshClip bool
|
||||||
|
|
||||||
// Was the last mouse event actually a double click?
|
// Was the last mouse event actually a double click?
|
||||||
@@ -780,6 +777,7 @@ var BufKeyActions = map[string]BufKeyAction{
|
|||||||
"CopyLine": (*BufPane).CopyLine,
|
"CopyLine": (*BufPane).CopyLine,
|
||||||
"Cut": (*BufPane).Cut,
|
"Cut": (*BufPane).Cut,
|
||||||
"CutLine": (*BufPane).CutLine,
|
"CutLine": (*BufPane).CutLine,
|
||||||
|
"Duplicate": (*BufPane).Duplicate,
|
||||||
"DuplicateLine": (*BufPane).DuplicateLine,
|
"DuplicateLine": (*BufPane).DuplicateLine,
|
||||||
"DeleteLine": (*BufPane).DeleteLine,
|
"DeleteLine": (*BufPane).DeleteLine,
|
||||||
"MoveLinesUp": (*BufPane).MoveLinesUp,
|
"MoveLinesUp": (*BufPane).MoveLinesUp,
|
||||||
@@ -907,6 +905,7 @@ var MultiActions = map[string]bool{
|
|||||||
"Copy": true,
|
"Copy": true,
|
||||||
"Cut": true,
|
"Cut": true,
|
||||||
"CutLine": true,
|
"CutLine": true,
|
||||||
|
"Duplicate": true,
|
||||||
"DuplicateLine": true,
|
"DuplicateLine": true,
|
||||||
"DeleteLine": true,
|
"DeleteLine": true,
|
||||||
"MoveLinesUp": true,
|
"MoveLinesUp": true,
|
||||||
|
|||||||
@@ -45,10 +45,10 @@ var bufdefaults = map[string]string{
|
|||||||
"Alt-]": "DiffNext|CursorEnd",
|
"Alt-]": "DiffNext|CursorEnd",
|
||||||
"Ctrl-z": "Undo",
|
"Ctrl-z": "Undo",
|
||||||
"Ctrl-y": "Redo",
|
"Ctrl-y": "Redo",
|
||||||
"Ctrl-c": "CopyLine|Copy",
|
"Ctrl-c": "Copy|CopyLine",
|
||||||
"Ctrl-x": "Cut",
|
"Ctrl-x": "Cut|CutLine",
|
||||||
"Ctrl-k": "CutLine",
|
"Ctrl-k": "CutLine",
|
||||||
"Ctrl-d": "DuplicateLine",
|
"Ctrl-d": "Duplicate|DuplicateLine",
|
||||||
"Ctrl-v": "Paste",
|
"Ctrl-v": "Paste",
|
||||||
"Ctrl-a": "SelectAll",
|
"Ctrl-a": "SelectAll",
|
||||||
"Ctrl-t": "AddTab",
|
"Ctrl-t": "AddTab",
|
||||||
@@ -146,8 +146,8 @@ var infodefaults = map[string]string{
|
|||||||
"Backtab": "CycleAutocompleteBack",
|
"Backtab": "CycleAutocompleteBack",
|
||||||
"Ctrl-z": "Undo",
|
"Ctrl-z": "Undo",
|
||||||
"Ctrl-y": "Redo",
|
"Ctrl-y": "Redo",
|
||||||
"Ctrl-c": "CopyLine|Copy",
|
"Ctrl-c": "Copy|CopyLine",
|
||||||
"Ctrl-x": "Cut",
|
"Ctrl-x": "Cut|CutLine",
|
||||||
"Ctrl-k": "CutLine",
|
"Ctrl-k": "CutLine",
|
||||||
"Ctrl-v": "Paste",
|
"Ctrl-v": "Paste",
|
||||||
"Home": "StartOfTextToggle",
|
"Home": "StartOfTextToggle",
|
||||||
|
|||||||
@@ -48,10 +48,10 @@ var bufdefaults = map[string]string{
|
|||||||
"Alt-]": "DiffNext|CursorEnd",
|
"Alt-]": "DiffNext|CursorEnd",
|
||||||
"Ctrl-z": "Undo",
|
"Ctrl-z": "Undo",
|
||||||
"Ctrl-y": "Redo",
|
"Ctrl-y": "Redo",
|
||||||
"Ctrl-c": "CopyLine|Copy",
|
"Ctrl-c": "Copy|CopyLine",
|
||||||
"Ctrl-x": "Cut",
|
"Ctrl-x": "Cut|CutLine",
|
||||||
"Ctrl-k": "CutLine",
|
"Ctrl-k": "CutLine",
|
||||||
"Ctrl-d": "DuplicateLine",
|
"Ctrl-d": "Duplicate|DuplicateLine",
|
||||||
"Ctrl-v": "Paste",
|
"Ctrl-v": "Paste",
|
||||||
"Ctrl-a": "SelectAll",
|
"Ctrl-a": "SelectAll",
|
||||||
"Ctrl-t": "AddTab",
|
"Ctrl-t": "AddTab",
|
||||||
@@ -149,8 +149,8 @@ var infodefaults = map[string]string{
|
|||||||
"Backtab": "CycleAutocompleteBack",
|
"Backtab": "CycleAutocompleteBack",
|
||||||
"Ctrl-z": "Undo",
|
"Ctrl-z": "Undo",
|
||||||
"Ctrl-y": "Redo",
|
"Ctrl-y": "Redo",
|
||||||
"Ctrl-c": "CopyLine|Copy",
|
"Ctrl-c": "Copy|CopyLine",
|
||||||
"Ctrl-x": "Cut",
|
"Ctrl-x": "Cut|CutLine",
|
||||||
"Ctrl-k": "CutLine",
|
"Ctrl-k": "CutLine",
|
||||||
"Ctrl-v": "Paste",
|
"Ctrl-v": "Paste",
|
||||||
"Home": "StartOfTextToggle",
|
"Home": "StartOfTextToggle",
|
||||||
|
|||||||
@@ -278,6 +278,14 @@ Autocomplete
|
|||||||
The `StartOfTextToggle` and `SelectToStartOfTextToggle` actions toggle between
|
The `StartOfTextToggle` and `SelectToStartOfTextToggle` actions toggle between
|
||||||
jumping to the start of the text (first) and start of the line.
|
jumping to the start of the text (first) and start of the line.
|
||||||
|
|
||||||
|
The `CutLine` action cuts the current line and adds it to the previously cut
|
||||||
|
lines in the clipboard since the last paste (rather than just replaces the
|
||||||
|
clipboard contents with this line). So you can cut multiple, not necessarily
|
||||||
|
consecutive lines to the clipboard just by pressing `Ctrl-k` multiple times,
|
||||||
|
without selecting them. If you want the more traditional behavior i.e. just
|
||||||
|
rewrite the clipboard every time, you can use `CopyLine,DeleteLine` action
|
||||||
|
instead of `CutLine`.
|
||||||
|
|
||||||
You can also bind some mouse actions (these must be bound to mouse buttons)
|
You can also bind some mouse actions (these must be bound to mouse buttons)
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -495,10 +503,10 @@ conventions for text editing defaults.
|
|||||||
"Alt-]": "DiffNext|CursorEnd",
|
"Alt-]": "DiffNext|CursorEnd",
|
||||||
"Ctrl-z": "Undo",
|
"Ctrl-z": "Undo",
|
||||||
"Ctrl-y": "Redo",
|
"Ctrl-y": "Redo",
|
||||||
"Ctrl-c": "CopyLine|Copy",
|
"Ctrl-c": "Copy|CopyLine",
|
||||||
"Ctrl-x": "Cut",
|
"Ctrl-x": "Cut|CutLine",
|
||||||
"Ctrl-k": "CutLine",
|
"Ctrl-k": "CutLine",
|
||||||
"Ctrl-d": "DuplicateLine",
|
"Ctrl-d": "Duplicate|DuplicateLine",
|
||||||
"Ctrl-v": "Paste",
|
"Ctrl-v": "Paste",
|
||||||
"Ctrl-a": "SelectAll",
|
"Ctrl-a": "SelectAll",
|
||||||
"Ctrl-t": "AddTab",
|
"Ctrl-t": "AddTab",
|
||||||
@@ -621,8 +629,8 @@ are given below:
|
|||||||
"Backtab": "CycleAutocompleteBack",
|
"Backtab": "CycleAutocompleteBack",
|
||||||
"Ctrl-z": "Undo",
|
"Ctrl-z": "Undo",
|
||||||
"Ctrl-y": "Redo",
|
"Ctrl-y": "Redo",
|
||||||
"Ctrl-c": "CopyLine|Copy",
|
"Ctrl-c": "Copy|CopyLine",
|
||||||
"Ctrl-x": "Cut",
|
"Ctrl-x": "Cut|CutLine",
|
||||||
"Ctrl-k": "CutLine",
|
"Ctrl-k": "CutLine",
|
||||||
"Ctrl-v": "Paste",
|
"Ctrl-v": "Paste",
|
||||||
"Home": "StartOfTextToggle",
|
"Home": "StartOfTextToggle",
|
||||||
|
|||||||
Reference in New Issue
Block a user