mirror of
https://github.com/zyedidia/micro.git
synced 2026-03-15 21:37:09 +09:00
Action subpackage
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package action
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
@@ -9,450 +9,450 @@ import (
|
|||||||
|
|
||||||
// MousePress is the event that should happen when a normal click happens
|
// MousePress is the event that should happen when a normal click happens
|
||||||
// This is almost always bound to left click
|
// This is almost always bound to left click
|
||||||
func (a *BufActionHandler) MousePress(e *tcell.EventMouse) bool {
|
func (a *BufHandler) MousePress(e *tcell.EventMouse) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScrollUpAction scrolls the view up
|
// ScrollUpAction scrolls the view up
|
||||||
func (a *BufActionHandler) ScrollUpAction() bool {
|
func (a *BufHandler) ScrollUpAction() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScrollDownAction scrolls the view up
|
// ScrollDownAction scrolls the view up
|
||||||
func (a *BufActionHandler) ScrollDownAction() bool {
|
func (a *BufHandler) ScrollDownAction() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Center centers the view on the cursor
|
// Center centers the view on the cursor
|
||||||
func (a *BufActionHandler) Center() bool {
|
func (a *BufHandler) Center() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// CursorUp moves the cursor up
|
// CursorUp moves the cursor up
|
||||||
func (a *BufActionHandler) CursorUp() bool {
|
func (a *BufHandler) CursorUp() bool {
|
||||||
a.Cursor.Deselect(true)
|
a.Cursor.Deselect(true)
|
||||||
a.Cursor.Up()
|
a.Cursor.Up()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// CursorDown moves the cursor down
|
// CursorDown moves the cursor down
|
||||||
func (a *BufActionHandler) CursorDown() bool {
|
func (a *BufHandler) CursorDown() bool {
|
||||||
a.Cursor.Deselect(true)
|
a.Cursor.Deselect(true)
|
||||||
a.Cursor.Down()
|
a.Cursor.Down()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// CursorLeft moves the cursor left
|
// CursorLeft moves the cursor left
|
||||||
func (a *BufActionHandler) CursorLeft() bool {
|
func (a *BufHandler) CursorLeft() bool {
|
||||||
a.Cursor.Deselect(true)
|
a.Cursor.Deselect(true)
|
||||||
a.Cursor.Left()
|
a.Cursor.Left()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// CursorRight moves the cursor right
|
// CursorRight moves the cursor right
|
||||||
func (a *BufActionHandler) CursorRight() bool {
|
func (a *BufHandler) CursorRight() bool {
|
||||||
a.Cursor.Deselect(true)
|
a.Cursor.Deselect(true)
|
||||||
a.Cursor.Right()
|
a.Cursor.Right()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// WordRight moves the cursor one word to the right
|
// WordRight moves the cursor one word to the right
|
||||||
func (a *BufActionHandler) WordRight() bool {
|
func (a *BufHandler) WordRight() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// WordLeft moves the cursor one word to the left
|
// WordLeft moves the cursor one word to the left
|
||||||
func (a *BufActionHandler) WordLeft() bool {
|
func (a *BufHandler) WordLeft() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectUp selects up one line
|
// SelectUp selects up one line
|
||||||
func (a *BufActionHandler) SelectUp() bool {
|
func (a *BufHandler) SelectUp() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectDown selects down one line
|
// SelectDown selects down one line
|
||||||
func (a *BufActionHandler) SelectDown() bool {
|
func (a *BufHandler) SelectDown() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectLeft selects the character to the left of the cursor
|
// SelectLeft selects the character to the left of the cursor
|
||||||
func (a *BufActionHandler) SelectLeft() bool {
|
func (a *BufHandler) SelectLeft() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectRight selects the character to the right of the cursor
|
// SelectRight selects the character to the right of the cursor
|
||||||
func (a *BufActionHandler) SelectRight() bool {
|
func (a *BufHandler) SelectRight() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectWordRight selects the word to the right of the cursor
|
// SelectWordRight selects the word to the right of the cursor
|
||||||
func (a *BufActionHandler) SelectWordRight() bool {
|
func (a *BufHandler) SelectWordRight() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectWordLeft selects the word to the left of the cursor
|
// SelectWordLeft selects the word to the left of the cursor
|
||||||
func (a *BufActionHandler) SelectWordLeft() bool {
|
func (a *BufHandler) SelectWordLeft() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartOfLine moves the cursor to the start of the line
|
// StartOfLine moves the cursor to the start of the line
|
||||||
func (a *BufActionHandler) StartOfLine() bool {
|
func (a *BufHandler) StartOfLine() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// EndOfLine moves the cursor to the end of the line
|
// EndOfLine moves the cursor to the end of the line
|
||||||
func (a *BufActionHandler) EndOfLine() bool {
|
func (a *BufHandler) EndOfLine() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectLine selects the entire current line
|
// SelectLine selects the entire current line
|
||||||
func (a *BufActionHandler) SelectLine() bool {
|
func (a *BufHandler) SelectLine() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectToStartOfLine selects to the start of the current line
|
// SelectToStartOfLine selects to the start of the current line
|
||||||
func (a *BufActionHandler) SelectToStartOfLine() bool {
|
func (a *BufHandler) SelectToStartOfLine() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectToEndOfLine selects to the end of the current line
|
// SelectToEndOfLine selects to the end of the current line
|
||||||
func (a *BufActionHandler) SelectToEndOfLine() bool {
|
func (a *BufHandler) SelectToEndOfLine() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParagraphPrevious moves the cursor to the previous empty line, or beginning of the buffer if there's none
|
// ParagraphPrevious moves the cursor to the previous empty line, or beginning of the buffer if there's none
|
||||||
func (a *BufActionHandler) ParagraphPrevious() bool {
|
func (a *BufHandler) ParagraphPrevious() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParagraphNext moves the cursor to the next empty line, or end of the buffer if there's none
|
// ParagraphNext moves the cursor to the next empty line, or end of the buffer if there's none
|
||||||
func (a *BufActionHandler) ParagraphNext() bool {
|
func (a *BufHandler) ParagraphNext() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retab changes all tabs to spaces or all spaces to tabs depending
|
// Retab changes all tabs to spaces or all spaces to tabs depending
|
||||||
// on the user's settings
|
// on the user's settings
|
||||||
func (a *BufActionHandler) Retab() bool {
|
func (a *BufHandler) Retab() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// CursorStart moves the cursor to the start of the buffer
|
// CursorStart moves the cursor to the start of the buffer
|
||||||
func (a *BufActionHandler) CursorStart() bool {
|
func (a *BufHandler) CursorStart() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// CursorEnd moves the cursor to the end of the buffer
|
// CursorEnd moves the cursor to the end of the buffer
|
||||||
func (a *BufActionHandler) CursorEnd() bool {
|
func (a *BufHandler) CursorEnd() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectToStart selects the text from the cursor to the start of the buffer
|
// SelectToStart selects the text from the cursor to the start of the buffer
|
||||||
func (a *BufActionHandler) SelectToStart() bool {
|
func (a *BufHandler) SelectToStart() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectToEnd selects the text from the cursor to the end of the buffer
|
// SelectToEnd selects the text from the cursor to the end of the buffer
|
||||||
func (a *BufActionHandler) SelectToEnd() bool {
|
func (a *BufHandler) SelectToEnd() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertSpace inserts a space
|
// InsertSpace inserts a space
|
||||||
func (a *BufActionHandler) InsertSpace() bool {
|
func (a *BufHandler) InsertSpace() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertNewline inserts a newline plus possible some whitespace if autoindent is on
|
// InsertNewline inserts a newline plus possible some whitespace if autoindent is on
|
||||||
func (a *BufActionHandler) InsertNewline() bool {
|
func (a *BufHandler) InsertNewline() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backspace deletes the previous character
|
// Backspace deletes the previous character
|
||||||
func (a *BufActionHandler) Backspace() bool {
|
func (a *BufHandler) Backspace() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteWordRight deletes the word to the right of the cursor
|
// DeleteWordRight deletes the word to the right of the cursor
|
||||||
func (a *BufActionHandler) DeleteWordRight() bool {
|
func (a *BufHandler) DeleteWordRight() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteWordLeft deletes the word to the left of the cursor
|
// DeleteWordLeft deletes the word to the left of the cursor
|
||||||
func (a *BufActionHandler) DeleteWordLeft() bool {
|
func (a *BufHandler) DeleteWordLeft() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete deletes the next character
|
// Delete deletes the next character
|
||||||
func (a *BufActionHandler) Delete() bool {
|
func (a *BufHandler) Delete() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// IndentSelection indents the current selection
|
// IndentSelection indents the current selection
|
||||||
func (a *BufActionHandler) IndentSelection() bool {
|
func (a *BufHandler) IndentSelection() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// OutdentLine moves the current line back one indentation
|
// OutdentLine moves the current line back one indentation
|
||||||
func (a *BufActionHandler) OutdentLine() bool {
|
func (a *BufHandler) OutdentLine() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// OutdentSelection takes the current selection and moves it back one indent level
|
// OutdentSelection takes the current selection and moves it back one indent level
|
||||||
func (a *BufActionHandler) OutdentSelection() bool {
|
func (a *BufHandler) OutdentSelection() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertTab inserts a tab or spaces
|
// InsertTab inserts a tab or spaces
|
||||||
func (a *BufActionHandler) InsertTab() bool {
|
func (a *BufHandler) InsertTab() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveAll saves all open buffers
|
// SaveAll saves all open buffers
|
||||||
func (a *BufActionHandler) SaveAll() bool {
|
func (a *BufHandler) SaveAll() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the buffer to disk
|
// Save the buffer to disk
|
||||||
func (a *BufActionHandler) Save() bool {
|
func (a *BufHandler) Save() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveAs saves the buffer to disk with the given name
|
// SaveAs saves the buffer to disk with the given name
|
||||||
func (a *BufActionHandler) SaveAs() bool {
|
func (a *BufHandler) SaveAs() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find opens a prompt and searches forward for the input
|
// Find opens a prompt and searches forward for the input
|
||||||
func (a *BufActionHandler) Find() bool {
|
func (a *BufHandler) Find() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindNext searches forwards for the last used search term
|
// FindNext searches forwards for the last used search term
|
||||||
func (a *BufActionHandler) FindNext() bool {
|
func (a *BufHandler) FindNext() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindPrevious searches backwards for the last used search term
|
// FindPrevious searches backwards for the last used search term
|
||||||
func (a *BufActionHandler) FindPrevious() bool {
|
func (a *BufHandler) FindPrevious() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Undo undoes the last action
|
// Undo undoes the last action
|
||||||
func (a *BufActionHandler) Undo() bool {
|
func (a *BufHandler) Undo() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redo redoes the last action
|
// Redo redoes the last action
|
||||||
func (a *BufActionHandler) Redo() bool {
|
func (a *BufHandler) Redo() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the selection to the system clipboard
|
// Copy the selection to the system clipboard
|
||||||
func (a *BufActionHandler) Copy() bool {
|
func (a *BufHandler) Copy() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// CutLine cuts the current line to the clipboard
|
// CutLine cuts the current line to the clipboard
|
||||||
func (a *BufActionHandler) CutLine() bool {
|
func (a *BufHandler) CutLine() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cut the selection to the system clipboard
|
// Cut the selection to the system clipboard
|
||||||
func (a *BufActionHandler) Cut() bool {
|
func (a *BufHandler) Cut() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// DuplicateLine duplicates the current line or selection
|
// DuplicateLine duplicates the current line or selection
|
||||||
func (a *BufActionHandler) DuplicateLine() bool {
|
func (a *BufHandler) DuplicateLine() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteLine deletes the current line
|
// DeleteLine deletes the current line
|
||||||
func (a *BufActionHandler) DeleteLine() bool {
|
func (a *BufHandler) DeleteLine() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// MoveLinesUp moves up the current line or selected lines if any
|
// MoveLinesUp moves up the current line or selected lines if any
|
||||||
func (a *BufActionHandler) MoveLinesUp() bool {
|
func (a *BufHandler) MoveLinesUp() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// MoveLinesDown moves down the current line or selected lines if any
|
// MoveLinesDown moves down the current line or selected lines if any
|
||||||
func (a *BufActionHandler) MoveLinesDown() bool {
|
func (a *BufHandler) MoveLinesDown() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paste whatever is in the system clipboard into the buffer
|
// Paste whatever is in the system clipboard into the buffer
|
||||||
// Delete and paste if the user has a selection
|
// Delete and paste if the user has a selection
|
||||||
func (a *BufActionHandler) Paste() bool {
|
func (a *BufHandler) Paste() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// PastePrimary pastes from the primary clipboard (only use on linux)
|
// PastePrimary pastes from the primary clipboard (only use on linux)
|
||||||
func (a *BufActionHandler) PastePrimary() bool {
|
func (a *BufHandler) PastePrimary() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// JumpToMatchingBrace moves the cursor to the matching brace if it is
|
// JumpToMatchingBrace moves the cursor to the matching brace if it is
|
||||||
// currently on a brace
|
// currently on a brace
|
||||||
func (a *BufActionHandler) JumpToMatchingBrace() bool {
|
func (a *BufHandler) JumpToMatchingBrace() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectAll selects the entire buffer
|
// SelectAll selects the entire buffer
|
||||||
func (a *BufActionHandler) SelectAll() bool {
|
func (a *BufHandler) SelectAll() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenFile opens a new file in the buffer
|
// OpenFile opens a new file in the buffer
|
||||||
func (a *BufActionHandler) OpenFile() bool {
|
func (a *BufHandler) OpenFile() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start moves the viewport to the start of the buffer
|
// Start moves the viewport to the start of the buffer
|
||||||
func (a *BufActionHandler) Start() bool {
|
func (a *BufHandler) Start() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// End moves the viewport to the end of the buffer
|
// End moves the viewport to the end of the buffer
|
||||||
func (a *BufActionHandler) End() bool {
|
func (a *BufHandler) End() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// PageUp scrolls the view up a page
|
// PageUp scrolls the view up a page
|
||||||
func (a *BufActionHandler) PageUp() bool {
|
func (a *BufHandler) PageUp() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// PageDown scrolls the view down a page
|
// PageDown scrolls the view down a page
|
||||||
func (a *BufActionHandler) PageDown() bool {
|
func (a *BufHandler) PageDown() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectPageUp selects up one page
|
// SelectPageUp selects up one page
|
||||||
func (a *BufActionHandler) SelectPageUp() bool {
|
func (a *BufHandler) SelectPageUp() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectPageDown selects down one page
|
// SelectPageDown selects down one page
|
||||||
func (a *BufActionHandler) SelectPageDown() bool {
|
func (a *BufHandler) SelectPageDown() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// CursorPageUp places the cursor a page up
|
// CursorPageUp places the cursor a page up
|
||||||
func (a *BufActionHandler) CursorPageUp() bool {
|
func (a *BufHandler) CursorPageUp() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// CursorPageDown places the cursor a page up
|
// CursorPageDown places the cursor a page up
|
||||||
func (a *BufActionHandler) CursorPageDown() bool {
|
func (a *BufHandler) CursorPageDown() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// HalfPageUp scrolls the view up half a page
|
// HalfPageUp scrolls the view up half a page
|
||||||
func (a *BufActionHandler) HalfPageUp() bool {
|
func (a *BufHandler) HalfPageUp() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// HalfPageDown scrolls the view down half a page
|
// HalfPageDown scrolls the view down half a page
|
||||||
func (a *BufActionHandler) HalfPageDown() bool {
|
func (a *BufHandler) HalfPageDown() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToggleRuler turns line numbers off and on
|
// ToggleRuler turns line numbers off and on
|
||||||
func (a *BufActionHandler) ToggleRuler() bool {
|
func (a *BufHandler) ToggleRuler() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// JumpLine jumps to a line and moves the view accordingly.
|
// JumpLine jumps to a line and moves the view accordingly.
|
||||||
func (a *BufActionHandler) JumpLine() bool {
|
func (a *BufHandler) JumpLine() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearStatus clears the messenger bar
|
// ClearStatus clears the messenger bar
|
||||||
func (a *BufActionHandler) ClearStatus() bool {
|
func (a *BufHandler) ClearStatus() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToggleHelp toggles the help screen
|
// ToggleHelp toggles the help screen
|
||||||
func (a *BufActionHandler) ToggleHelp() bool {
|
func (a *BufHandler) ToggleHelp() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToggleKeyMenu toggles the keymenu option and resizes all tabs
|
// ToggleKeyMenu toggles the keymenu option and resizes all tabs
|
||||||
func (a *BufActionHandler) ToggleKeyMenu() bool {
|
func (a *BufHandler) ToggleKeyMenu() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShellMode opens a terminal to run a shell command
|
// ShellMode opens a terminal to run a shell command
|
||||||
func (a *BufActionHandler) ShellMode() bool {
|
func (a *BufHandler) ShellMode() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommandMode lets the user enter a command
|
// CommandMode lets the user enter a command
|
||||||
func (a *BufActionHandler) CommandMode() bool {
|
func (a *BufHandler) CommandMode() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToggleOverwriteMode lets the user toggle the text overwrite mode
|
// ToggleOverwriteMode lets the user toggle the text overwrite mode
|
||||||
func (a *BufActionHandler) ToggleOverwriteMode() bool {
|
func (a *BufHandler) ToggleOverwriteMode() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Escape leaves current mode
|
// Escape leaves current mode
|
||||||
func (a *BufActionHandler) Escape() bool {
|
func (a *BufHandler) Escape() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quit this will close the current tab or view that is open
|
// Quit this will close the current tab or view that is open
|
||||||
func (a *BufActionHandler) Quit() bool {
|
func (a *BufHandler) Quit() bool {
|
||||||
screen.Screen.Fini()
|
screen.Screen.Fini()
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// QuitAll quits the whole editor; all splits and tabs
|
// QuitAll quits the whole editor; all splits and tabs
|
||||||
func (a *BufActionHandler) QuitAll() bool {
|
func (a *BufHandler) QuitAll() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddTab adds a new tab with an empty buffer
|
// AddTab adds a new tab with an empty buffer
|
||||||
func (a *BufActionHandler) AddTab() bool {
|
func (a *BufHandler) AddTab() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// PreviousTab switches to the previous tab in the tab list
|
// PreviousTab switches to the previous tab in the tab list
|
||||||
func (a *BufActionHandler) PreviousTab() bool {
|
func (a *BufHandler) PreviousTab() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// NextTab switches to the next tab in the tab list
|
// NextTab switches to the next tab in the tab list
|
||||||
func (a *BufActionHandler) NextTab() bool {
|
func (a *BufHandler) NextTab() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// VSplitBinding opens an empty vertical split
|
// VSplitBinding opens an empty vertical split
|
||||||
func (a *BufActionHandler) VSplitBinding() bool {
|
func (a *BufHandler) VSplitBinding() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// HSplitBinding opens an empty horizontal split
|
// HSplitBinding opens an empty horizontal split
|
||||||
func (a *BufActionHandler) HSplitBinding() bool {
|
func (a *BufHandler) HSplitBinding() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unsplit closes all splits in the current tab except the active one
|
// Unsplit closes all splits in the current tab except the active one
|
||||||
func (a *BufActionHandler) Unsplit() bool {
|
func (a *BufHandler) Unsplit() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// NextSplit changes the view to the next split
|
// NextSplit changes the view to the next split
|
||||||
func (a *BufActionHandler) NextSplit() bool {
|
func (a *BufHandler) NextSplit() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// PreviousSplit changes the view to the previous split
|
// PreviousSplit changes the view to the previous split
|
||||||
func (a *BufActionHandler) PreviousSplit() bool {
|
func (a *BufHandler) PreviousSplit() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,41 +460,41 @@ var curMacro []interface{}
|
|||||||
var recordingMacro bool
|
var recordingMacro bool
|
||||||
|
|
||||||
// ToggleMacro toggles recording of a macro
|
// ToggleMacro toggles recording of a macro
|
||||||
func (a *BufActionHandler) ToggleMacro() bool {
|
func (a *BufHandler) ToggleMacro() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// PlayMacro plays back the most recently recorded macro
|
// PlayMacro plays back the most recently recorded macro
|
||||||
func (a *BufActionHandler) PlayMacro() bool {
|
func (a *BufHandler) PlayMacro() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SpawnMultiCursor creates a new multiple cursor at the next occurrence of the current selection or current word
|
// SpawnMultiCursor creates a new multiple cursor at the next occurrence of the current selection or current word
|
||||||
func (a *BufActionHandler) SpawnMultiCursor() bool {
|
func (a *BufHandler) SpawnMultiCursor() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// SpawnMultiCursorSelect adds a cursor at the beginning of each line of a selection
|
// SpawnMultiCursorSelect adds a cursor at the beginning of each line of a selection
|
||||||
func (a *BufActionHandler) SpawnMultiCursorSelect() bool {
|
func (a *BufHandler) SpawnMultiCursorSelect() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// MouseMultiCursor is a mouse action which puts a new cursor at the mouse position
|
// MouseMultiCursor is a mouse action which puts a new cursor at the mouse position
|
||||||
func (a *BufActionHandler) MouseMultiCursor(e *tcell.EventMouse) bool {
|
func (a *BufHandler) MouseMultiCursor(e *tcell.EventMouse) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// SkipMultiCursor moves the current multiple cursor to the next available position
|
// SkipMultiCursor moves the current multiple cursor to the next available position
|
||||||
func (a *BufActionHandler) SkipMultiCursor() bool {
|
func (a *BufHandler) SkipMultiCursor() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveMultiCursor removes the latest multiple cursor
|
// RemoveMultiCursor removes the latest multiple cursor
|
||||||
func (a *BufActionHandler) RemoveMultiCursor() bool {
|
func (a *BufHandler) RemoveMultiCursor() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveAllMultiCursors removes all cursors except the base cursor
|
// RemoveAllMultiCursors removes all cursors except the base cursor
|
||||||
func (a *BufActionHandler) RemoveAllMultiCursors() bool {
|
func (a *BufHandler) RemoveAllMultiCursors() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
// +build plan9 nacl windows
|
// +build plan9 nacl windows
|
||||||
|
|
||||||
package main
|
package action
|
||||||
|
|
||||||
func (*BufActionHandler) Suspend() bool {
|
func (*BufHandler) Suspend() bool {
|
||||||
// TODO: error message
|
// TODO: error message
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// +build linux darwin dragonfly solaris openbsd netbsd freebsd
|
// +build linux darwin dragonfly solaris openbsd netbsd freebsd
|
||||||
|
|
||||||
package main
|
package action
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"syscall"
|
"syscall"
|
||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
// Suspend sends micro to the background. This is the same as pressing CtrlZ in most unix programs.
|
// Suspend sends micro to the background. This is the same as pressing CtrlZ in most unix programs.
|
||||||
// This only works on linux and has no default binding.
|
// This only works on linux and has no default binding.
|
||||||
// This code was adapted from the suspend code in nsf/godit
|
// This code was adapted from the suspend code in nsf/godit
|
||||||
func (*BufActionHandler) Suspend() bool {
|
func (*BufHandler) Suspend() bool {
|
||||||
screenWasNil := screen.Screen == nil
|
screenWasNil := screen.Screen == nil
|
||||||
|
|
||||||
if !screenWasNil {
|
if !screenWasNil {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package action
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -14,7 +14,7 @@ import (
|
|||||||
"github.com/zyedidia/tcell"
|
"github.com/zyedidia/tcell"
|
||||||
)
|
)
|
||||||
|
|
||||||
var bindings = DefaultBindings()
|
var Bindings = DefaultBindings()
|
||||||
|
|
||||||
func InitBindings() {
|
func InitBindings() {
|
||||||
var parsed map[string]string
|
var parsed map[string]string
|
||||||
@@ -57,7 +57,7 @@ func BindKey(k, v string) {
|
|||||||
util.TermMessage("Raw events not supported yet")
|
util.TermMessage("Raw events not supported yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
bindings[k] = v
|
Bindings[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
// findKeyEvent will find binding Key 'b' using string 'k'
|
// findKeyEvent will find binding Key 'b' using string 'k'
|
||||||
206
cmd/micro/action/bufhandler.go
Normal file
206
cmd/micro/action/bufhandler.go
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
package action
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/zyedidia/micro/cmd/micro/buffer"
|
||||||
|
"github.com/zyedidia/tcell"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BufKeyAction func(*BufHandler) bool
|
||||||
|
type BufMouseAction func(*BufHandler, *tcell.EventMouse) bool
|
||||||
|
|
||||||
|
var BufKeyBindings map[KeyEvent]BufKeyAction
|
||||||
|
var BufMouseBindings map[MouseEvent]BufMouseAction
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
BufKeyBindings = make(map[KeyEvent]BufKeyAction)
|
||||||
|
BufMouseBindings = make(map[MouseEvent]BufMouseAction)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BufMapKey(k KeyEvent, action string) {
|
||||||
|
BufKeyBindings[k] = BufKeyActions[action]
|
||||||
|
}
|
||||||
|
func BufMapMouse(k MouseEvent, action string) {
|
||||||
|
BufMouseBindings[k] = BufMouseActions[action]
|
||||||
|
}
|
||||||
|
|
||||||
|
// The BufHandler connects the buffer and the window
|
||||||
|
// It provides a cursor (or multiple) and defines a set of actions
|
||||||
|
// that can be taken on the buffer
|
||||||
|
// The ActionHandler can access the window for necessary info about
|
||||||
|
// visual positions for mouse clicks and scrolling
|
||||||
|
type BufHandler struct {
|
||||||
|
Buf *buffer.Buffer
|
||||||
|
|
||||||
|
cursors []*buffer.Cursor
|
||||||
|
Cursor *buffer.Cursor // the active cursor
|
||||||
|
|
||||||
|
// Since tcell doesn't differentiate between a mouse release event
|
||||||
|
// and a mouse move event with no keys pressed, we need to keep
|
||||||
|
// track of whether or not the mouse was pressed (or not released) last event to determine
|
||||||
|
// mouse release events
|
||||||
|
mouseReleased bool
|
||||||
|
|
||||||
|
// We need to keep track of insert key press toggle
|
||||||
|
isOverwriteMode bool
|
||||||
|
// This stores when the last click was
|
||||||
|
// This is useful for detecting double and triple clicks
|
||||||
|
lastClickTime time.Time
|
||||||
|
lastLoc buffer.Loc
|
||||||
|
|
||||||
|
// lastCutTime stores when the last ctrl+k was issued.
|
||||||
|
// It is used for clearing the clipboard to replace it with fresh cut lines.
|
||||||
|
lastCutTime time.Time
|
||||||
|
|
||||||
|
// freshClip returns true if the clipboard has never been pasted.
|
||||||
|
freshClip bool
|
||||||
|
|
||||||
|
// Was the last mouse event actually a double click?
|
||||||
|
// Useful for detecting triple clicks -- if a double click is detected
|
||||||
|
// but the last mouse event was actually a double click, it's a triple click
|
||||||
|
doubleClick bool
|
||||||
|
// Same here, just to keep track for mouse move events
|
||||||
|
tripleClick bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBufHandler(buf *buffer.Buffer) *BufHandler {
|
||||||
|
a := new(BufHandler)
|
||||||
|
a.Buf = buf
|
||||||
|
|
||||||
|
a.cursors = []*buffer.Cursor{&buffer.Cursor{
|
||||||
|
Buf: buf,
|
||||||
|
Loc: buf.StartCursor,
|
||||||
|
}}
|
||||||
|
a.Cursor = a.cursors[0]
|
||||||
|
|
||||||
|
buf.SetCursors(a.cursors)
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleEvent executes the tcell event properly
|
||||||
|
// TODO: multiple actions bound to one key
|
||||||
|
func (a *BufHandler) HandleEvent(event tcell.Event) {
|
||||||
|
switch e := event.(type) {
|
||||||
|
case *tcell.EventKey:
|
||||||
|
ke := KeyEvent{
|
||||||
|
code: e.Key(),
|
||||||
|
mod: e.Modifiers(),
|
||||||
|
r: e.Rune(),
|
||||||
|
}
|
||||||
|
if action, ok := BufKeyBindings[ke]; ok {
|
||||||
|
action(a)
|
||||||
|
}
|
||||||
|
case *tcell.EventMouse:
|
||||||
|
me := MouseEvent{
|
||||||
|
btn: e.Buttons(),
|
||||||
|
mod: e.Modifiers(),
|
||||||
|
}
|
||||||
|
if action, ok := BufMouseBindings[me]; ok {
|
||||||
|
action(a, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var BufKeyActions = map[string]BufKeyAction{
|
||||||
|
"CursorUp": (*BufHandler).CursorUp,
|
||||||
|
"CursorDown": (*BufHandler).CursorDown,
|
||||||
|
"CursorPageUp": (*BufHandler).CursorPageUp,
|
||||||
|
"CursorPageDown": (*BufHandler).CursorPageDown,
|
||||||
|
"CursorLeft": (*BufHandler).CursorLeft,
|
||||||
|
"CursorRight": (*BufHandler).CursorRight,
|
||||||
|
"CursorStart": (*BufHandler).CursorStart,
|
||||||
|
"CursorEnd": (*BufHandler).CursorEnd,
|
||||||
|
"SelectToStart": (*BufHandler).SelectToStart,
|
||||||
|
"SelectToEnd": (*BufHandler).SelectToEnd,
|
||||||
|
"SelectUp": (*BufHandler).SelectUp,
|
||||||
|
"SelectDown": (*BufHandler).SelectDown,
|
||||||
|
"SelectLeft": (*BufHandler).SelectLeft,
|
||||||
|
"SelectRight": (*BufHandler).SelectRight,
|
||||||
|
"WordRight": (*BufHandler).WordRight,
|
||||||
|
"WordLeft": (*BufHandler).WordLeft,
|
||||||
|
"SelectWordRight": (*BufHandler).SelectWordRight,
|
||||||
|
"SelectWordLeft": (*BufHandler).SelectWordLeft,
|
||||||
|
"DeleteWordRight": (*BufHandler).DeleteWordRight,
|
||||||
|
"DeleteWordLeft": (*BufHandler).DeleteWordLeft,
|
||||||
|
"SelectLine": (*BufHandler).SelectLine,
|
||||||
|
"SelectToStartOfLine": (*BufHandler).SelectToStartOfLine,
|
||||||
|
"SelectToEndOfLine": (*BufHandler).SelectToEndOfLine,
|
||||||
|
"ParagraphPrevious": (*BufHandler).ParagraphPrevious,
|
||||||
|
"ParagraphNext": (*BufHandler).ParagraphNext,
|
||||||
|
"InsertNewline": (*BufHandler).InsertNewline,
|
||||||
|
"InsertSpace": (*BufHandler).InsertSpace,
|
||||||
|
"Backspace": (*BufHandler).Backspace,
|
||||||
|
"Delete": (*BufHandler).Delete,
|
||||||
|
"InsertTab": (*BufHandler).InsertTab,
|
||||||
|
"Save": (*BufHandler).Save,
|
||||||
|
"SaveAll": (*BufHandler).SaveAll,
|
||||||
|
"SaveAs": (*BufHandler).SaveAs,
|
||||||
|
"Find": (*BufHandler).Find,
|
||||||
|
"FindNext": (*BufHandler).FindNext,
|
||||||
|
"FindPrevious": (*BufHandler).FindPrevious,
|
||||||
|
"Center": (*BufHandler).Center,
|
||||||
|
"Undo": (*BufHandler).Undo,
|
||||||
|
"Redo": (*BufHandler).Redo,
|
||||||
|
"Copy": (*BufHandler).Copy,
|
||||||
|
"Cut": (*BufHandler).Cut,
|
||||||
|
"CutLine": (*BufHandler).CutLine,
|
||||||
|
"DuplicateLine": (*BufHandler).DuplicateLine,
|
||||||
|
"DeleteLine": (*BufHandler).DeleteLine,
|
||||||
|
"MoveLinesUp": (*BufHandler).MoveLinesUp,
|
||||||
|
"MoveLinesDown": (*BufHandler).MoveLinesDown,
|
||||||
|
"IndentSelection": (*BufHandler).IndentSelection,
|
||||||
|
"OutdentSelection": (*BufHandler).OutdentSelection,
|
||||||
|
"OutdentLine": (*BufHandler).OutdentLine,
|
||||||
|
"Paste": (*BufHandler).Paste,
|
||||||
|
"PastePrimary": (*BufHandler).PastePrimary,
|
||||||
|
"SelectAll": (*BufHandler).SelectAll,
|
||||||
|
"OpenFile": (*BufHandler).OpenFile,
|
||||||
|
"Start": (*BufHandler).Start,
|
||||||
|
"End": (*BufHandler).End,
|
||||||
|
"PageUp": (*BufHandler).PageUp,
|
||||||
|
"PageDown": (*BufHandler).PageDown,
|
||||||
|
"SelectPageUp": (*BufHandler).SelectPageUp,
|
||||||
|
"SelectPageDown": (*BufHandler).SelectPageDown,
|
||||||
|
"HalfPageUp": (*BufHandler).HalfPageUp,
|
||||||
|
"HalfPageDown": (*BufHandler).HalfPageDown,
|
||||||
|
"StartOfLine": (*BufHandler).StartOfLine,
|
||||||
|
"EndOfLine": (*BufHandler).EndOfLine,
|
||||||
|
"ToggleHelp": (*BufHandler).ToggleHelp,
|
||||||
|
"ToggleKeyMenu": (*BufHandler).ToggleKeyMenu,
|
||||||
|
"ToggleRuler": (*BufHandler).ToggleRuler,
|
||||||
|
"JumpLine": (*BufHandler).JumpLine,
|
||||||
|
"ClearStatus": (*BufHandler).ClearStatus,
|
||||||
|
"ShellMode": (*BufHandler).ShellMode,
|
||||||
|
"CommandMode": (*BufHandler).CommandMode,
|
||||||
|
"ToggleOverwriteMode": (*BufHandler).ToggleOverwriteMode,
|
||||||
|
"Escape": (*BufHandler).Escape,
|
||||||
|
"Quit": (*BufHandler).Quit,
|
||||||
|
"QuitAll": (*BufHandler).QuitAll,
|
||||||
|
"AddTab": (*BufHandler).AddTab,
|
||||||
|
"PreviousTab": (*BufHandler).PreviousTab,
|
||||||
|
"NextTab": (*BufHandler).NextTab,
|
||||||
|
"NextSplit": (*BufHandler).NextSplit,
|
||||||
|
"PreviousSplit": (*BufHandler).PreviousSplit,
|
||||||
|
"Unsplit": (*BufHandler).Unsplit,
|
||||||
|
"VSplit": (*BufHandler).VSplitBinding,
|
||||||
|
"HSplit": (*BufHandler).HSplitBinding,
|
||||||
|
"ToggleMacro": (*BufHandler).ToggleMacro,
|
||||||
|
"PlayMacro": (*BufHandler).PlayMacro,
|
||||||
|
"Suspend": (*BufHandler).Suspend,
|
||||||
|
"ScrollUp": (*BufHandler).ScrollUpAction,
|
||||||
|
"ScrollDown": (*BufHandler).ScrollDownAction,
|
||||||
|
"SpawnMultiCursor": (*BufHandler).SpawnMultiCursor,
|
||||||
|
"SpawnMultiCursorSelect": (*BufHandler).SpawnMultiCursorSelect,
|
||||||
|
"RemoveMultiCursor": (*BufHandler).RemoveMultiCursor,
|
||||||
|
"RemoveAllMultiCursors": (*BufHandler).RemoveAllMultiCursors,
|
||||||
|
"SkipMultiCursor": (*BufHandler).SkipMultiCursor,
|
||||||
|
"JumpToMatchingBrace": (*BufHandler).JumpToMatchingBrace,
|
||||||
|
|
||||||
|
// This was changed to InsertNewline but I don't want to break backwards compatibility
|
||||||
|
"InsertEnter": (*BufHandler).InsertNewline,
|
||||||
|
}
|
||||||
|
var BufMouseActions = map[string]BufMouseAction{
|
||||||
|
"MousePress": (*BufHandler).MousePress,
|
||||||
|
"MouseMultiCursor": (*BufHandler).MouseMultiCursor,
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package action
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/zyedidia/tcell"
|
"github.com/zyedidia/tcell"
|
||||||
@@ -31,8 +31,8 @@ type MouseEvent struct {
|
|||||||
mod tcell.ModMask
|
mod tcell.ModMask
|
||||||
}
|
}
|
||||||
|
|
||||||
// An ActionHandler will take a tcell event and execute it
|
// A Handler will take a tcell event and execute it
|
||||||
// appropriately
|
// appropriately
|
||||||
type ActionHandler interface {
|
type Handler interface {
|
||||||
HandleEvent(tcell.Event)
|
HandleEvent(tcell.Event)
|
||||||
}
|
}
|
||||||
@@ -1,208 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/zyedidia/micro/cmd/micro/buffer"
|
|
||||||
"github.com/zyedidia/tcell"
|
|
||||||
)
|
|
||||||
|
|
||||||
type BufKeyAction func(*BufActionHandler) bool
|
|
||||||
type BufMouseAction func(*BufActionHandler, *tcell.EventMouse) bool
|
|
||||||
|
|
||||||
var BufKeyBindings map[KeyEvent]BufKeyAction
|
|
||||||
var BufMouseBindings map[MouseEvent]BufMouseAction
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
BufKeyBindings = make(map[KeyEvent]BufKeyAction)
|
|
||||||
BufMouseBindings = make(map[MouseEvent]BufMouseAction)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BufMapKey(k KeyEvent, action string) {
|
|
||||||
BufKeyBindings[k] = BufKeyActions[action]
|
|
||||||
}
|
|
||||||
func BufMapMouse(k MouseEvent, action string) {
|
|
||||||
BufMouseBindings[k] = BufMouseActions[action]
|
|
||||||
}
|
|
||||||
|
|
||||||
// The BufActionHandler connects the buffer and the window
|
|
||||||
// It provides a cursor (or multiple) and defines a set of actions
|
|
||||||
// that can be taken on the buffer
|
|
||||||
// The ActionHandler can access the window for necessary info about
|
|
||||||
// visual positions for mouse clicks and scrolling
|
|
||||||
type BufActionHandler struct {
|
|
||||||
Buf *buffer.Buffer
|
|
||||||
Win *Window
|
|
||||||
|
|
||||||
cursors []*buffer.Cursor
|
|
||||||
Cursor *buffer.Cursor // the active cursor
|
|
||||||
|
|
||||||
// Since tcell doesn't differentiate between a mouse release event
|
|
||||||
// and a mouse move event with no keys pressed, we need to keep
|
|
||||||
// track of whether or not the mouse was pressed (or not released) last event to determine
|
|
||||||
// mouse release events
|
|
||||||
mouseReleased bool
|
|
||||||
|
|
||||||
// We need to keep track of insert key press toggle
|
|
||||||
isOverwriteMode bool
|
|
||||||
// This stores when the last click was
|
|
||||||
// This is useful for detecting double and triple clicks
|
|
||||||
lastClickTime time.Time
|
|
||||||
lastLoc buffer.Loc
|
|
||||||
|
|
||||||
// lastCutTime stores when the last ctrl+k was issued.
|
|
||||||
// It is used for clearing the clipboard to replace it with fresh cut lines.
|
|
||||||
lastCutTime time.Time
|
|
||||||
|
|
||||||
// freshClip returns true if the clipboard has never been pasted.
|
|
||||||
freshClip bool
|
|
||||||
|
|
||||||
// Was the last mouse event actually a double click?
|
|
||||||
// Useful for detecting triple clicks -- if a double click is detected
|
|
||||||
// but the last mouse event was actually a double click, it's a triple click
|
|
||||||
doubleClick bool
|
|
||||||
// Same here, just to keep track for mouse move events
|
|
||||||
tripleClick bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewBufActionHandler(buf *buffer.Buffer, win *Window) *BufActionHandler {
|
|
||||||
a := new(BufActionHandler)
|
|
||||||
a.Buf = buf
|
|
||||||
a.Win = win
|
|
||||||
|
|
||||||
a.cursors = []*buffer.Cursor{&buffer.Cursor{
|
|
||||||
Buf: buf,
|
|
||||||
Loc: buf.StartCursor,
|
|
||||||
}}
|
|
||||||
a.Cursor = a.cursors[0]
|
|
||||||
|
|
||||||
buf.SetCursors(a.cursors)
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandleEvent executes the tcell event properly
|
|
||||||
// TODO: multiple actions bound to one key
|
|
||||||
func (a *BufActionHandler) HandleEvent(event tcell.Event) {
|
|
||||||
switch e := event.(type) {
|
|
||||||
case *tcell.EventKey:
|
|
||||||
ke := KeyEvent{
|
|
||||||
code: e.Key(),
|
|
||||||
mod: e.Modifiers(),
|
|
||||||
r: e.Rune(),
|
|
||||||
}
|
|
||||||
if action, ok := BufKeyBindings[ke]; ok {
|
|
||||||
action(a)
|
|
||||||
}
|
|
||||||
case *tcell.EventMouse:
|
|
||||||
me := MouseEvent{
|
|
||||||
btn: e.Buttons(),
|
|
||||||
mod: e.Modifiers(),
|
|
||||||
}
|
|
||||||
if action, ok := BufMouseBindings[me]; ok {
|
|
||||||
action(a, e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var BufKeyActions = map[string]BufKeyAction{
|
|
||||||
"CursorUp": (*BufActionHandler).CursorUp,
|
|
||||||
"CursorDown": (*BufActionHandler).CursorDown,
|
|
||||||
"CursorPageUp": (*BufActionHandler).CursorPageUp,
|
|
||||||
"CursorPageDown": (*BufActionHandler).CursorPageDown,
|
|
||||||
"CursorLeft": (*BufActionHandler).CursorLeft,
|
|
||||||
"CursorRight": (*BufActionHandler).CursorRight,
|
|
||||||
"CursorStart": (*BufActionHandler).CursorStart,
|
|
||||||
"CursorEnd": (*BufActionHandler).CursorEnd,
|
|
||||||
"SelectToStart": (*BufActionHandler).SelectToStart,
|
|
||||||
"SelectToEnd": (*BufActionHandler).SelectToEnd,
|
|
||||||
"SelectUp": (*BufActionHandler).SelectUp,
|
|
||||||
"SelectDown": (*BufActionHandler).SelectDown,
|
|
||||||
"SelectLeft": (*BufActionHandler).SelectLeft,
|
|
||||||
"SelectRight": (*BufActionHandler).SelectRight,
|
|
||||||
"WordRight": (*BufActionHandler).WordRight,
|
|
||||||
"WordLeft": (*BufActionHandler).WordLeft,
|
|
||||||
"SelectWordRight": (*BufActionHandler).SelectWordRight,
|
|
||||||
"SelectWordLeft": (*BufActionHandler).SelectWordLeft,
|
|
||||||
"DeleteWordRight": (*BufActionHandler).DeleteWordRight,
|
|
||||||
"DeleteWordLeft": (*BufActionHandler).DeleteWordLeft,
|
|
||||||
"SelectLine": (*BufActionHandler).SelectLine,
|
|
||||||
"SelectToStartOfLine": (*BufActionHandler).SelectToStartOfLine,
|
|
||||||
"SelectToEndOfLine": (*BufActionHandler).SelectToEndOfLine,
|
|
||||||
"ParagraphPrevious": (*BufActionHandler).ParagraphPrevious,
|
|
||||||
"ParagraphNext": (*BufActionHandler).ParagraphNext,
|
|
||||||
"InsertNewline": (*BufActionHandler).InsertNewline,
|
|
||||||
"InsertSpace": (*BufActionHandler).InsertSpace,
|
|
||||||
"Backspace": (*BufActionHandler).Backspace,
|
|
||||||
"Delete": (*BufActionHandler).Delete,
|
|
||||||
"InsertTab": (*BufActionHandler).InsertTab,
|
|
||||||
"Save": (*BufActionHandler).Save,
|
|
||||||
"SaveAll": (*BufActionHandler).SaveAll,
|
|
||||||
"SaveAs": (*BufActionHandler).SaveAs,
|
|
||||||
"Find": (*BufActionHandler).Find,
|
|
||||||
"FindNext": (*BufActionHandler).FindNext,
|
|
||||||
"FindPrevious": (*BufActionHandler).FindPrevious,
|
|
||||||
"Center": (*BufActionHandler).Center,
|
|
||||||
"Undo": (*BufActionHandler).Undo,
|
|
||||||
"Redo": (*BufActionHandler).Redo,
|
|
||||||
"Copy": (*BufActionHandler).Copy,
|
|
||||||
"Cut": (*BufActionHandler).Cut,
|
|
||||||
"CutLine": (*BufActionHandler).CutLine,
|
|
||||||
"DuplicateLine": (*BufActionHandler).DuplicateLine,
|
|
||||||
"DeleteLine": (*BufActionHandler).DeleteLine,
|
|
||||||
"MoveLinesUp": (*BufActionHandler).MoveLinesUp,
|
|
||||||
"MoveLinesDown": (*BufActionHandler).MoveLinesDown,
|
|
||||||
"IndentSelection": (*BufActionHandler).IndentSelection,
|
|
||||||
"OutdentSelection": (*BufActionHandler).OutdentSelection,
|
|
||||||
"OutdentLine": (*BufActionHandler).OutdentLine,
|
|
||||||
"Paste": (*BufActionHandler).Paste,
|
|
||||||
"PastePrimary": (*BufActionHandler).PastePrimary,
|
|
||||||
"SelectAll": (*BufActionHandler).SelectAll,
|
|
||||||
"OpenFile": (*BufActionHandler).OpenFile,
|
|
||||||
"Start": (*BufActionHandler).Start,
|
|
||||||
"End": (*BufActionHandler).End,
|
|
||||||
"PageUp": (*BufActionHandler).PageUp,
|
|
||||||
"PageDown": (*BufActionHandler).PageDown,
|
|
||||||
"SelectPageUp": (*BufActionHandler).SelectPageUp,
|
|
||||||
"SelectPageDown": (*BufActionHandler).SelectPageDown,
|
|
||||||
"HalfPageUp": (*BufActionHandler).HalfPageUp,
|
|
||||||
"HalfPageDown": (*BufActionHandler).HalfPageDown,
|
|
||||||
"StartOfLine": (*BufActionHandler).StartOfLine,
|
|
||||||
"EndOfLine": (*BufActionHandler).EndOfLine,
|
|
||||||
"ToggleHelp": (*BufActionHandler).ToggleHelp,
|
|
||||||
"ToggleKeyMenu": (*BufActionHandler).ToggleKeyMenu,
|
|
||||||
"ToggleRuler": (*BufActionHandler).ToggleRuler,
|
|
||||||
"JumpLine": (*BufActionHandler).JumpLine,
|
|
||||||
"ClearStatus": (*BufActionHandler).ClearStatus,
|
|
||||||
"ShellMode": (*BufActionHandler).ShellMode,
|
|
||||||
"CommandMode": (*BufActionHandler).CommandMode,
|
|
||||||
"ToggleOverwriteMode": (*BufActionHandler).ToggleOverwriteMode,
|
|
||||||
"Escape": (*BufActionHandler).Escape,
|
|
||||||
"Quit": (*BufActionHandler).Quit,
|
|
||||||
"QuitAll": (*BufActionHandler).QuitAll,
|
|
||||||
"AddTab": (*BufActionHandler).AddTab,
|
|
||||||
"PreviousTab": (*BufActionHandler).PreviousTab,
|
|
||||||
"NextTab": (*BufActionHandler).NextTab,
|
|
||||||
"NextSplit": (*BufActionHandler).NextSplit,
|
|
||||||
"PreviousSplit": (*BufActionHandler).PreviousSplit,
|
|
||||||
"Unsplit": (*BufActionHandler).Unsplit,
|
|
||||||
"VSplit": (*BufActionHandler).VSplitBinding,
|
|
||||||
"HSplit": (*BufActionHandler).HSplitBinding,
|
|
||||||
"ToggleMacro": (*BufActionHandler).ToggleMacro,
|
|
||||||
"PlayMacro": (*BufActionHandler).PlayMacro,
|
|
||||||
"Suspend": (*BufActionHandler).Suspend,
|
|
||||||
"ScrollUp": (*BufActionHandler).ScrollUpAction,
|
|
||||||
"ScrollDown": (*BufActionHandler).ScrollDownAction,
|
|
||||||
"SpawnMultiCursor": (*BufActionHandler).SpawnMultiCursor,
|
|
||||||
"SpawnMultiCursorSelect": (*BufActionHandler).SpawnMultiCursorSelect,
|
|
||||||
"RemoveMultiCursor": (*BufActionHandler).RemoveMultiCursor,
|
|
||||||
"RemoveAllMultiCursors": (*BufActionHandler).RemoveAllMultiCursors,
|
|
||||||
"SkipMultiCursor": (*BufActionHandler).SkipMultiCursor,
|
|
||||||
"JumpToMatchingBrace": (*BufActionHandler).JumpToMatchingBrace,
|
|
||||||
|
|
||||||
// This was changed to InsertNewline but I don't want to break backwards compatibility
|
|
||||||
"InsertEnter": (*BufActionHandler).InsertNewline,
|
|
||||||
}
|
|
||||||
var BufMouseActions = map[string]BufMouseAction{
|
|
||||||
"MousePress": (*BufActionHandler).MousePress,
|
|
||||||
"MouseMultiCursor": (*BufActionHandler).MouseMultiCursor,
|
|
||||||
}
|
|
||||||
@@ -2,15 +2,11 @@ package buffer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/gob"
|
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"os/signal"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -236,154 +232,6 @@ func (b *Buffer) ReOpen() error {
|
|||||||
// b.Cursor.Relocate()
|
// b.Cursor.Relocate()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Saving
|
|
||||||
|
|
||||||
// Save saves the buffer to its default path
|
|
||||||
func (b *Buffer) Save() error {
|
|
||||||
return b.SaveAs(b.Path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SaveAs saves the buffer to a specified path (filename), creating the file if it does not exist
|
|
||||||
func (b *Buffer) SaveAs(filename string) error {
|
|
||||||
// TODO: rmtrailingws and updaterules
|
|
||||||
b.UpdateRules()
|
|
||||||
// if b.Settings["rmtrailingws"].(bool) {
|
|
||||||
// for i, l := range b.lines {
|
|
||||||
// pos := len(bytes.TrimRightFunc(l.data, unicode.IsSpace))
|
|
||||||
//
|
|
||||||
// if pos < len(l.data) {
|
|
||||||
// b.deleteToEnd(Loc{pos, i})
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// b.Cursor.Relocate()
|
|
||||||
// }
|
|
||||||
|
|
||||||
if b.Settings["eofnewline"].(bool) {
|
|
||||||
end := b.End()
|
|
||||||
if b.RuneAt(Loc{end.X - 1, end.Y}) != '\n' {
|
|
||||||
b.Insert(end, "\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the last time this file was updated after saving
|
|
||||||
defer func() {
|
|
||||||
b.ModTime, _ = GetModTime(filename)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Removes any tilde and replaces with the absolute path to home
|
|
||||||
absFilename, _ := ReplaceHome(filename)
|
|
||||||
|
|
||||||
// TODO: save creates parent dirs
|
|
||||||
// // Get the leading path to the file | "." is returned if there's no leading path provided
|
|
||||||
// if dirname := filepath.Dir(absFilename); dirname != "." {
|
|
||||||
// // Check if the parent dirs don't exist
|
|
||||||
// if _, statErr := os.Stat(dirname); os.IsNotExist(statErr) {
|
|
||||||
// // Prompt to make sure they want to create the dirs that are missing
|
|
||||||
// if yes, canceled := messenger.YesNoPrompt("Parent folders \"" + dirname + "\" do not exist. Create them? (y,n)"); yes && !canceled {
|
|
||||||
// // Create all leading dir(s) since they don't exist
|
|
||||||
// if mkdirallErr := os.MkdirAll(dirname, os.ModePerm); mkdirallErr != nil {
|
|
||||||
// // If there was an error creating the dirs
|
|
||||||
// return mkdirallErr
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// // If they canceled the creation of leading dirs
|
|
||||||
// return errors.New("Save aborted")
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
var fileSize int
|
|
||||||
|
|
||||||
err := overwriteFile(absFilename, func(file io.Writer) (e error) {
|
|
||||||
if len(b.lines) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// end of line
|
|
||||||
var eol []byte
|
|
||||||
if b.Settings["fileformat"] == "dos" {
|
|
||||||
eol = []byte{'\r', '\n'}
|
|
||||||
} else {
|
|
||||||
eol = []byte{'\n'}
|
|
||||||
}
|
|
||||||
|
|
||||||
// write lines
|
|
||||||
if fileSize, e = file.Write(b.lines[0].data); e != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, l := range b.lines[1:] {
|
|
||||||
if _, e = file.Write(eol); e != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if _, e = file.Write(l.data); e != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fileSize += len(eol) + len(l.data)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !b.Settings["fastdirty"].(bool) {
|
|
||||||
if fileSize > LargeFileThreshold {
|
|
||||||
// For large files 'fastdirty' needs to be on
|
|
||||||
b.Settings["fastdirty"] = true
|
|
||||||
} else {
|
|
||||||
calcHash(b, &b.origHash)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b.Path = filename
|
|
||||||
absPath, _ := filepath.Abs(filename)
|
|
||||||
b.AbsPath = absPath
|
|
||||||
b.isModified = false
|
|
||||||
return b.Serialize()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SaveWithSudo saves the buffer to the default path with sudo
|
|
||||||
func (b *Buffer) SaveWithSudo() error {
|
|
||||||
return b.SaveAsWithSudo(b.Path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SaveAsWithSudo is the same as SaveAs except it uses a neat trick
|
|
||||||
// with tee to use sudo so the user doesn't have to reopen micro with sudo
|
|
||||||
func (b *Buffer) SaveAsWithSudo(filename string) error {
|
|
||||||
b.UpdateRules()
|
|
||||||
b.Path = filename
|
|
||||||
absPath, _ := filepath.Abs(filename)
|
|
||||||
b.AbsPath = absPath
|
|
||||||
|
|
||||||
// Set up everything for the command
|
|
||||||
cmd := exec.Command(config.GlobalSettings["sucmd"].(string), "tee", filename)
|
|
||||||
cmd.Stdin = bytes.NewBuffer(b.Bytes())
|
|
||||||
|
|
||||||
// This is a trap for Ctrl-C so that it doesn't kill micro
|
|
||||||
// Instead we trap Ctrl-C to kill the program we're running
|
|
||||||
c := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(c, os.Interrupt)
|
|
||||||
go func() {
|
|
||||||
for range c {
|
|
||||||
cmd.Process.Kill()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Start the command
|
|
||||||
cmd.Start()
|
|
||||||
err := cmd.Wait()
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
b.isModified = false
|
|
||||||
b.ModTime, _ = GetModTime(filename)
|
|
||||||
return b.Serialize()
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Buffer) SetCursors(c []*Cursor) {
|
func (b *Buffer) SetCursors(c []*Cursor) {
|
||||||
b.cursors = c
|
b.cursors = c
|
||||||
}
|
}
|
||||||
@@ -472,56 +320,6 @@ func calcHash(b *Buffer, out *[md5.Size]byte) {
|
|||||||
h.Sum((*out)[:0])
|
h.Sum((*out)[:0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
|
||||||
gob.Register(TextEvent{})
|
|
||||||
gob.Register(SerializedBuffer{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Serialize serializes the buffer to config.ConfigDir/buffers
|
|
||||||
func (b *Buffer) Serialize() error {
|
|
||||||
if !b.Settings["savecursor"].(bool) && !b.Settings["saveundo"].(bool) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
name := config.ConfigDir + "/buffers/" + EscapePath(b.AbsPath)
|
|
||||||
|
|
||||||
return overwriteFile(name, func(file io.Writer) error {
|
|
||||||
return gob.NewEncoder(file).Encode(SerializedBuffer{
|
|
||||||
b.EventHandler,
|
|
||||||
b.GetActiveCursor().Loc,
|
|
||||||
b.ModTime,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Buffer) Unserialize() error {
|
|
||||||
// If either savecursor or saveundo is turned on, we need to load the serialized information
|
|
||||||
// from ~/.config/micro/buffers
|
|
||||||
file, err := os.Open(config.ConfigDir + "/buffers/" + EscapePath(b.AbsPath))
|
|
||||||
defer file.Close()
|
|
||||||
if err == nil {
|
|
||||||
var buffer SerializedBuffer
|
|
||||||
decoder := gob.NewDecoder(file)
|
|
||||||
gob.Register(TextEvent{})
|
|
||||||
err = decoder.Decode(&buffer)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(err.Error() + "\nYou may want to remove the files in ~/.config/micro/buffers (these files store the information for the 'saveundo' and 'savecursor' options) if this problem persists.")
|
|
||||||
}
|
|
||||||
if b.Settings["savecursor"].(bool) {
|
|
||||||
b.StartCursor = buffer.Cursor
|
|
||||||
}
|
|
||||||
|
|
||||||
if b.Settings["saveundo"].(bool) {
|
|
||||||
// We should only use last time's eventhandler if the file wasn't modified by someone else in the meantime
|
|
||||||
if b.ModTime == buffer.ModTime {
|
|
||||||
b.EventHandler = buffer.EventHandler
|
|
||||||
b.EventHandler.buf = b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateRules updates the syntax rules and filetype for this buffer
|
// UpdateRules updates the syntax rules and filetype for this buffer
|
||||||
// This is called when the colorscheme changes
|
// This is called when the colorscheme changes
|
||||||
func (b *Buffer) UpdateRules() {
|
func (b *Buffer) UpdateRules() {
|
||||||
|
|||||||
160
cmd/micro/buffer/save.go
Normal file
160
cmd/micro/buffer/save.go
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
package buffer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"os/signal"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
. "github.com/zyedidia/micro/cmd/micro/util"
|
||||||
|
|
||||||
|
"github.com/zyedidia/micro/cmd/micro/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Save saves the buffer to its default path
|
||||||
|
func (b *Buffer) Save() error {
|
||||||
|
return b.SaveAs(b.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveAs saves the buffer to a specified path (filename), creating the file if it does not exist
|
||||||
|
func (b *Buffer) SaveAs(filename string) error {
|
||||||
|
// TODO: rmtrailingws and updaterules
|
||||||
|
b.UpdateRules()
|
||||||
|
// if b.Settings["rmtrailingws"].(bool) {
|
||||||
|
// for i, l := range b.lines {
|
||||||
|
// pos := len(bytes.TrimRightFunc(l.data, unicode.IsSpace))
|
||||||
|
//
|
||||||
|
// if pos < len(l.data) {
|
||||||
|
// b.deleteToEnd(Loc{pos, i})
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// b.Cursor.Relocate()
|
||||||
|
// }
|
||||||
|
|
||||||
|
if b.Settings["eofnewline"].(bool) {
|
||||||
|
end := b.End()
|
||||||
|
if b.RuneAt(Loc{end.X - 1, end.Y}) != '\n' {
|
||||||
|
b.Insert(end, "\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the last time this file was updated after saving
|
||||||
|
defer func() {
|
||||||
|
b.ModTime, _ = GetModTime(filename)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Removes any tilde and replaces with the absolute path to home
|
||||||
|
absFilename, _ := ReplaceHome(filename)
|
||||||
|
|
||||||
|
// TODO: save creates parent dirs
|
||||||
|
// // Get the leading path to the file | "." is returned if there's no leading path provided
|
||||||
|
// if dirname := filepath.Dir(absFilename); dirname != "." {
|
||||||
|
// // Check if the parent dirs don't exist
|
||||||
|
// if _, statErr := os.Stat(dirname); os.IsNotExist(statErr) {
|
||||||
|
// // Prompt to make sure they want to create the dirs that are missing
|
||||||
|
// if yes, canceled := messenger.YesNoPrompt("Parent folders \"" + dirname + "\" do not exist. Create them? (y,n)"); yes && !canceled {
|
||||||
|
// // Create all leading dir(s) since they don't exist
|
||||||
|
// if mkdirallErr := os.MkdirAll(dirname, os.ModePerm); mkdirallErr != nil {
|
||||||
|
// // If there was an error creating the dirs
|
||||||
|
// return mkdirallErr
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// // If they canceled the creation of leading dirs
|
||||||
|
// return errors.New("Save aborted")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
var fileSize int
|
||||||
|
|
||||||
|
err := overwriteFile(absFilename, func(file io.Writer) (e error) {
|
||||||
|
if len(b.lines) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// end of line
|
||||||
|
var eol []byte
|
||||||
|
if b.Settings["fileformat"] == "dos" {
|
||||||
|
eol = []byte{'\r', '\n'}
|
||||||
|
} else {
|
||||||
|
eol = []byte{'\n'}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write lines
|
||||||
|
if fileSize, e = file.Write(b.lines[0].data); e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, l := range b.lines[1:] {
|
||||||
|
if _, e = file.Write(eol); e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, e = file.Write(l.data); e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fileSize += len(eol) + len(l.data)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !b.Settings["fastdirty"].(bool) {
|
||||||
|
if fileSize > LargeFileThreshold {
|
||||||
|
// For large files 'fastdirty' needs to be on
|
||||||
|
b.Settings["fastdirty"] = true
|
||||||
|
} else {
|
||||||
|
calcHash(b, &b.origHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Path = filename
|
||||||
|
absPath, _ := filepath.Abs(filename)
|
||||||
|
b.AbsPath = absPath
|
||||||
|
b.isModified = false
|
||||||
|
return b.Serialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveWithSudo saves the buffer to the default path with sudo
|
||||||
|
func (b *Buffer) SaveWithSudo() error {
|
||||||
|
return b.SaveAsWithSudo(b.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveAsWithSudo is the same as SaveAs except it uses a neat trick
|
||||||
|
// with tee to use sudo so the user doesn't have to reopen micro with sudo
|
||||||
|
func (b *Buffer) SaveAsWithSudo(filename string) error {
|
||||||
|
b.UpdateRules()
|
||||||
|
b.Path = filename
|
||||||
|
absPath, _ := filepath.Abs(filename)
|
||||||
|
b.AbsPath = absPath
|
||||||
|
|
||||||
|
// Set up everything for the command
|
||||||
|
cmd := exec.Command(config.GlobalSettings["sucmd"].(string), "tee", filename)
|
||||||
|
cmd.Stdin = bytes.NewBuffer(b.Bytes())
|
||||||
|
|
||||||
|
// This is a trap for Ctrl-C so that it doesn't kill micro
|
||||||
|
// Instead we trap Ctrl-C to kill the program we're running
|
||||||
|
c := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(c, os.Interrupt)
|
||||||
|
go func() {
|
||||||
|
for range c {
|
||||||
|
cmd.Process.Kill()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Start the command
|
||||||
|
cmd.Start()
|
||||||
|
err := cmd.Wait()
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
b.isModified = false
|
||||||
|
b.ModTime, _ = GetModTime(filename)
|
||||||
|
return b.Serialize()
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
61
cmd/micro/buffer/serialize.go
Normal file
61
cmd/micro/buffer/serialize.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package buffer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/gob"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/zyedidia/micro/cmd/micro/config"
|
||||||
|
. "github.com/zyedidia/micro/cmd/micro/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
gob.Register(TextEvent{})
|
||||||
|
gob.Register(SerializedBuffer{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialize serializes the buffer to config.ConfigDir/buffers
|
||||||
|
func (b *Buffer) Serialize() error {
|
||||||
|
if !b.Settings["savecursor"].(bool) && !b.Settings["saveundo"].(bool) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
name := config.ConfigDir + "/buffers/" + EscapePath(b.AbsPath)
|
||||||
|
|
||||||
|
return overwriteFile(name, func(file io.Writer) error {
|
||||||
|
return gob.NewEncoder(file).Encode(SerializedBuffer{
|
||||||
|
b.EventHandler,
|
||||||
|
b.GetActiveCursor().Loc,
|
||||||
|
b.ModTime,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Buffer) Unserialize() error {
|
||||||
|
// If either savecursor or saveundo is turned on, we need to load the serialized information
|
||||||
|
// from ~/.config/micro/buffers
|
||||||
|
file, err := os.Open(config.ConfigDir + "/buffers/" + EscapePath(b.AbsPath))
|
||||||
|
defer file.Close()
|
||||||
|
if err == nil {
|
||||||
|
var buffer SerializedBuffer
|
||||||
|
decoder := gob.NewDecoder(file)
|
||||||
|
gob.Register(TextEvent{})
|
||||||
|
err = decoder.Decode(&buffer)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(err.Error() + "\nYou may want to remove the files in ~/.config/micro/buffers (these files store the information for the 'saveundo' and 'savecursor' options) if this problem persists.")
|
||||||
|
}
|
||||||
|
if b.Settings["savecursor"].(bool) {
|
||||||
|
b.StartCursor = buffer.Cursor
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.Settings["saveundo"].(bool) {
|
||||||
|
// We should only use last time's eventhandler if the file wasn't modified by someone else in the meantime
|
||||||
|
if b.ModTime == buffer.ModTime {
|
||||||
|
b.EventHandler = buffer.EventHandler
|
||||||
|
b.EventHandler.buf = b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
|
"github.com/zyedidia/micro/cmd/micro/action"
|
||||||
"github.com/zyedidia/micro/cmd/micro/buffer"
|
"github.com/zyedidia/micro/cmd/micro/buffer"
|
||||||
"github.com/zyedidia/micro/cmd/micro/config"
|
"github.com/zyedidia/micro/cmd/micro/config"
|
||||||
"github.com/zyedidia/micro/cmd/micro/screen"
|
"github.com/zyedidia/micro/cmd/micro/screen"
|
||||||
@@ -105,7 +106,7 @@ func main() {
|
|||||||
util.TermMessage(err)
|
util.TermMessage(err)
|
||||||
}
|
}
|
||||||
config.InitGlobalSettings()
|
config.InitGlobalSettings()
|
||||||
InitBindings()
|
action.InitBindings()
|
||||||
err = config.InitColorscheme()
|
err = config.InitColorscheme()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.TermMessage(err)
|
util.TermMessage(err)
|
||||||
@@ -126,7 +127,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
TryBindKey("Ctrl-z", "Undo", true)
|
action.TryBindKey("Ctrl-z", "Undo", true)
|
||||||
|
|
||||||
b, err := buffer.NewBufferFromFile(os.Args[1])
|
b, err := buffer.NewBufferFromFile(os.Args[1])
|
||||||
|
|
||||||
@@ -137,7 +138,7 @@ func main() {
|
|||||||
width, height := screen.Screen.Size()
|
width, height := screen.Screen.Size()
|
||||||
w := NewWindow(0, 0, width, height-1, b)
|
w := NewWindow(0, 0, width, height-1, b)
|
||||||
|
|
||||||
a := NewBufActionHandler(b, w)
|
a := action.NewBufHandler(b)
|
||||||
|
|
||||||
// Here is the event loop which runs in a separate thread
|
// Here is the event loop which runs in a separate thread
|
||||||
go func() {
|
go func() {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/zyedidia/micro/cmd/micro/action"
|
||||||
"github.com/zyedidia/micro/cmd/micro/buffer"
|
"github.com/zyedidia/micro/cmd/micro/buffer"
|
||||||
"github.com/zyedidia/micro/cmd/micro/config"
|
"github.com/zyedidia/micro/cmd/micro/config"
|
||||||
"github.com/zyedidia/micro/cmd/micro/screen"
|
"github.com/zyedidia/micro/cmd/micro/screen"
|
||||||
@@ -84,7 +85,7 @@ func (s *StatusLine) Display() {
|
|||||||
return []byte(fmt.Sprint(s.FindOpt(string(option))))
|
return []byte(fmt.Sprint(s.FindOpt(string(option))))
|
||||||
} else if bytes.HasPrefix(name, []byte("bind")) {
|
} else if bytes.HasPrefix(name, []byte("bind")) {
|
||||||
binding := string(name[5:])
|
binding := string(name[5:])
|
||||||
for k, v := range bindings {
|
for k, v := range action.Bindings {
|
||||||
if v == binding {
|
if v == binding {
|
||||||
return []byte(k)
|
return []byte(k)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user