diff --git a/cmd/micro/action/actions.go b/cmd/micro/action/actions.go index 782962c3..d66991e4 100644 --- a/cmd/micro/action/actions.go +++ b/cmd/micro/action/actions.go @@ -18,7 +18,7 @@ import ( ) // ScrollUp is not an action -func (h *BufHandler) ScrollUp(n int) { +func (h *BufPane) ScrollUp(n int) { v := h.GetView() if v.StartLine >= n { v.StartLine -= n @@ -27,7 +27,7 @@ func (h *BufHandler) ScrollUp(n int) { } // ScrollDown is not an action -func (h *BufHandler) ScrollDown(n int) { +func (h *BufPane) ScrollDown(n int) { v := h.GetView() if v.StartLine <= h.Buf.LinesNum()-1-n { v.StartLine += n @@ -37,7 +37,7 @@ func (h *BufHandler) ScrollDown(n int) { // MousePress is the event that should happen when a normal click happens // This is almost always bound to left click -func (h *BufHandler) MousePress(e *tcell.EventMouse) bool { +func (h *BufPane) MousePress(e *tcell.EventMouse) bool { b := h.Buf mx, my := e.Position() mouseLoc := h.GetMouseLoc(buffer.Loc{mx, my}) @@ -93,19 +93,19 @@ func (h *BufHandler) MousePress(e *tcell.EventMouse) bool { } // ScrollUpAction scrolls the view up -func (h *BufHandler) ScrollUpAction() bool { +func (h *BufPane) ScrollUpAction() bool { h.ScrollUp(util.IntOpt(h.Buf.Settings["scrollspeed"])) return false } // ScrollDownAction scrolls the view up -func (h *BufHandler) ScrollDownAction() bool { +func (h *BufPane) ScrollDownAction() bool { h.ScrollDown(util.IntOpt(h.Buf.Settings["scrollspeed"])) return false } // Center centers the view on the cursor -func (h *BufHandler) Center() bool { +func (h *BufPane) Center() bool { v := h.GetView() v.StartLine = h.Cursor.Y - v.Height/2 if v.StartLine+v.Height > h.Buf.LinesNum() { @@ -119,49 +119,49 @@ func (h *BufHandler) Center() bool { } // CursorUp moves the cursor up -func (h *BufHandler) CursorUp() bool { +func (h *BufPane) CursorUp() bool { h.Cursor.Deselect(true) h.Cursor.Up() return true } // CursorDown moves the cursor down -func (h *BufHandler) CursorDown() bool { +func (h *BufPane) CursorDown() bool { h.Cursor.Deselect(true) h.Cursor.Down() return true } // CursorLeft moves the cursor left -func (h *BufHandler) CursorLeft() bool { +func (h *BufPane) CursorLeft() bool { h.Cursor.Deselect(true) h.Cursor.Left() return true } // CursorRight moves the cursor right -func (h *BufHandler) CursorRight() bool { +func (h *BufPane) CursorRight() bool { h.Cursor.Deselect(false) h.Cursor.Right() return true } // WordRight moves the cursor one word to the right -func (h *BufHandler) WordRight() bool { +func (h *BufPane) WordRight() bool { h.Cursor.Deselect(false) h.Cursor.WordRight() return true } // WordLeft moves the cursor one word to the left -func (h *BufHandler) WordLeft() bool { +func (h *BufPane) WordLeft() bool { h.Cursor.Deselect(true) h.Cursor.WordLeft() return true } // SelectUp selects up one line -func (h *BufHandler) SelectUp() bool { +func (h *BufPane) SelectUp() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } @@ -171,7 +171,7 @@ func (h *BufHandler) SelectUp() bool { } // SelectDown selects down one line -func (h *BufHandler) SelectDown() bool { +func (h *BufPane) SelectDown() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } @@ -181,7 +181,7 @@ func (h *BufHandler) SelectDown() bool { } // SelectLeft selects the character to the left of the cursor -func (h *BufHandler) SelectLeft() bool { +func (h *BufPane) SelectLeft() bool { loc := h.Cursor.Loc count := h.Buf.End() if loc.GreaterThan(count) { @@ -196,7 +196,7 @@ func (h *BufHandler) SelectLeft() bool { } // SelectRight selects the character to the right of the cursor -func (h *BufHandler) SelectRight() bool { +func (h *BufPane) SelectRight() bool { loc := h.Cursor.Loc count := h.Buf.End() if loc.GreaterThan(count) { @@ -211,7 +211,7 @@ func (h *BufHandler) SelectRight() bool { } // SelectWordRight selects the word to the right of the cursor -func (h *BufHandler) SelectWordRight() bool { +func (h *BufPane) SelectWordRight() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } @@ -221,7 +221,7 @@ func (h *BufHandler) SelectWordRight() bool { } // SelectWordLeft selects the word to the left of the cursor -func (h *BufHandler) SelectWordLeft() bool { +func (h *BufPane) SelectWordLeft() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } @@ -231,7 +231,7 @@ func (h *BufHandler) SelectWordLeft() bool { } // StartOfLine moves the cursor to the start of the line -func (h *BufHandler) StartOfLine() bool { +func (h *BufPane) StartOfLine() bool { h.Cursor.Deselect(true) if h.Cursor.X != 0 { h.Cursor.Start() @@ -242,20 +242,20 @@ func (h *BufHandler) StartOfLine() bool { } // EndOfLine moves the cursor to the end of the line -func (h *BufHandler) EndOfLine() bool { +func (h *BufPane) EndOfLine() bool { h.Cursor.Deselect(true) h.Cursor.End() return true } // SelectLine selects the entire current line -func (h *BufHandler) SelectLine() bool { +func (h *BufPane) SelectLine() bool { h.Cursor.SelectLine() return true } // SelectToStartOfLine selects to the start of the current line -func (h *BufHandler) SelectToStartOfLine() bool { +func (h *BufPane) SelectToStartOfLine() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } @@ -265,7 +265,7 @@ func (h *BufHandler) SelectToStartOfLine() bool { } // SelectToEndOfLine selects to the end of the current line -func (h *BufHandler) SelectToEndOfLine() bool { +func (h *BufPane) SelectToEndOfLine() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } @@ -275,7 +275,7 @@ func (h *BufHandler) SelectToEndOfLine() bool { } // ParagraphPrevious moves the cursor to the previous empty line, or beginning of the buffer if there's none -func (h *BufHandler) ParagraphPrevious() bool { +func (h *BufPane) ParagraphPrevious() bool { var line int for line = h.Cursor.Y; line > 0; line-- { if len(h.Buf.LineBytes(line)) == 0 && line != h.Cursor.Y { @@ -292,7 +292,7 @@ func (h *BufHandler) ParagraphPrevious() bool { } // ParagraphNext moves the cursor to the next empty line, or end of the buffer if there's none -func (h *BufHandler) ParagraphNext() bool { +func (h *BufPane) ParagraphNext() bool { var line int for line = h.Cursor.Y; line < h.Buf.LinesNum(); line++ { if len(h.Buf.LineBytes(line)) == 0 && line != h.Cursor.Y { @@ -310,13 +310,13 @@ func (h *BufHandler) ParagraphNext() bool { // Retab changes all tabs to spaces or all spaces to tabs depending // on the user's settings -func (h *BufHandler) Retab() bool { +func (h *BufPane) Retab() bool { h.Buf.Retab() return true } // CursorStart moves the cursor to the start of the buffer -func (h *BufHandler) CursorStart() bool { +func (h *BufPane) CursorStart() bool { h.Cursor.Deselect(true) h.Cursor.X = 0 h.Cursor.Y = 0 @@ -324,7 +324,7 @@ func (h *BufHandler) CursorStart() bool { } // CursorEnd moves the cursor to the end of the buffer -func (h *BufHandler) CursorEnd() bool { +func (h *BufPane) CursorEnd() bool { h.Cursor.Deselect(true) h.Cursor.Loc = h.Buf.End() h.Cursor.StoreVisualX() @@ -332,7 +332,7 @@ func (h *BufHandler) CursorEnd() bool { } // SelectToStart selects the text from the cursor to the start of the buffer -func (h *BufHandler) SelectToStart() bool { +func (h *BufPane) SelectToStart() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } @@ -342,7 +342,7 @@ func (h *BufHandler) SelectToStart() bool { } // SelectToEnd selects the text from the cursor to the end of the buffer -func (h *BufHandler) SelectToEnd() bool { +func (h *BufPane) SelectToEnd() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } @@ -352,7 +352,7 @@ func (h *BufHandler) SelectToEnd() bool { } // InsertNewline inserts a newline plus possible some whitespace if autoindent is on -func (h *BufHandler) InsertNewline() bool { +func (h *BufPane) InsertNewline() bool { // Insert a newline if h.Cursor.HasSelection() { h.Cursor.DeleteSelection() @@ -384,7 +384,7 @@ func (h *BufHandler) InsertNewline() bool { } // Backspace deletes the previous character -func (h *BufHandler) Backspace() bool { +func (h *BufPane) Backspace() bool { if h.Cursor.HasSelection() { h.Cursor.DeleteSelection() h.Cursor.ResetSelection() @@ -413,7 +413,7 @@ func (h *BufHandler) Backspace() bool { } // DeleteWordRight deletes the word to the right of the cursor -func (h *BufHandler) DeleteWordRight() bool { +func (h *BufPane) DeleteWordRight() bool { h.SelectWordRight() if h.Cursor.HasSelection() { h.Cursor.DeleteSelection() @@ -423,7 +423,7 @@ func (h *BufHandler) DeleteWordRight() bool { } // DeleteWordLeft deletes the word to the left of the cursor -func (h *BufHandler) DeleteWordLeft() bool { +func (h *BufPane) DeleteWordLeft() bool { h.SelectWordLeft() if h.Cursor.HasSelection() { h.Cursor.DeleteSelection() @@ -433,7 +433,7 @@ func (h *BufHandler) DeleteWordLeft() bool { } // Delete deletes the next character -func (h *BufHandler) Delete() bool { +func (h *BufPane) Delete() bool { if h.Cursor.HasSelection() { h.Cursor.DeleteSelection() h.Cursor.ResetSelection() @@ -447,7 +447,7 @@ func (h *BufHandler) Delete() bool { } // IndentSelection indents the current selection -func (h *BufHandler) IndentSelection() bool { +func (h *BufPane) IndentSelection() bool { if h.Cursor.HasSelection() { start := h.Cursor.CurSelection[0] end := h.Cursor.CurSelection[1] @@ -479,7 +479,7 @@ func (h *BufHandler) IndentSelection() bool { } // OutdentLine moves the current line back one indentation -func (h *BufHandler) OutdentLine() bool { +func (h *BufPane) OutdentLine() bool { if h.Cursor.HasSelection() { return false } @@ -495,7 +495,7 @@ func (h *BufHandler) OutdentLine() bool { } // OutdentSelection takes the current selection and moves it back one indent level -func (h *BufHandler) OutdentSelection() bool { +func (h *BufPane) OutdentSelection() bool { if h.Cursor.HasSelection() { start := h.Cursor.CurSelection[0] end := h.Cursor.CurSelection[1] @@ -523,7 +523,7 @@ func (h *BufHandler) OutdentSelection() bool { } // InsertTab inserts a tab or spaces -func (h *BufHandler) InsertTab() bool { +func (h *BufPane) InsertTab() bool { indent := h.Buf.IndentString(util.IntOpt(h.Buf.Settings["tabsize"])) tabBytes := len(indent) bytesUntilIndent := tabBytes - (h.Cursor.GetVisualX() % tabBytes) @@ -532,7 +532,7 @@ func (h *BufHandler) InsertTab() bool { } // SaveAll saves all open buffers -func (h *BufHandler) SaveAll() bool { +func (h *BufPane) SaveAll() bool { for _, b := range buffer.OpenBuffers { b.Save() } @@ -540,7 +540,7 @@ func (h *BufHandler) SaveAll() bool { } // Save the buffer to disk -func (h *BufHandler) Save() bool { +func (h *BufPane) Save() bool { // If this is an empty buffer, ask for a filename if h.Buf.Path == "" { h.SaveAs() @@ -552,7 +552,7 @@ func (h *BufHandler) Save() bool { } // SaveAs saves the buffer to disk with the given name -func (h *BufHandler) SaveAs() bool { +func (h *BufPane) SaveAs() bool { InfoBar.Prompt("Filename: ", "", "Save", nil, func(resp string, canceled bool) { if !canceled { // the filename might or might not be quoted, so unquote first then join the strings. @@ -571,7 +571,7 @@ func (h *BufHandler) SaveAs() bool { // This function saves the buffer to `filename` and changes the buffer's path and name // to `filename` if the save is successful -func (h *BufHandler) saveBufToFile(filename string) { +func (h *BufPane) saveBufToFile(filename string) { err := h.Buf.SaveAs(filename) if err != nil { if strings.HasSuffix(err.Error(), "permission denied") { @@ -598,7 +598,7 @@ func (h *BufHandler) saveBufToFile(filename string) { } // Find opens a prompt and searches forward for the input -func (h *BufHandler) Find() bool { +func (h *BufPane) Find() bool { InfoBar.Prompt("Find: ", "", "Find", func(resp string) { // Event callback match, found, _ := h.Buf.FindNext(resp, h.Buf.Start(), h.Buf.End(), h.Cursor.Loc, true, true) @@ -637,7 +637,7 @@ func (h *BufHandler) Find() bool { } // FindNext searches forwards for the last used search term -func (h *BufHandler) FindNext() bool { +func (h *BufPane) FindNext() bool { // If the cursor is at the start of a selection and we search we want // to search from the end of the selection in the case that // the selection is a search result in which case we wouldn't move at @@ -663,7 +663,7 @@ func (h *BufHandler) FindNext() bool { } // FindPrevious searches backwards for the last used search term -func (h *BufHandler) FindPrevious() bool { +func (h *BufPane) FindPrevious() bool { // If the cursor is at the end of a selection and we search we want // to search from the beginning of the selection in the case that // the selection is a search result in which case we wouldn't move at @@ -689,21 +689,21 @@ func (h *BufHandler) FindPrevious() bool { } // Undo undoes the last action -func (h *BufHandler) Undo() bool { +func (h *BufPane) Undo() bool { h.Buf.Undo() InfoBar.Message("Undid action") return true } // Redo redoes the last action -func (h *BufHandler) Redo() bool { +func (h *BufPane) Redo() bool { h.Buf.Redo() InfoBar.Message("Redid action") return true } // Copy the selection to the system clipboard -func (h *BufHandler) Copy() bool { +func (h *BufPane) Copy() bool { if h.Cursor.HasSelection() { h.Cursor.CopySelection("clipboard") h.freshClip = true @@ -713,7 +713,7 @@ func (h *BufHandler) Copy() bool { } // CutLine cuts the current line to the clipboard -func (h *BufHandler) CutLine() bool { +func (h *BufPane) CutLine() bool { h.Cursor.SelectLine() if !h.Cursor.HasSelection() { return false @@ -738,7 +738,7 @@ func (h *BufHandler) CutLine() bool { } // Cut the selection to the system clipboard -func (h *BufHandler) Cut() bool { +func (h *BufPane) Cut() bool { if h.Cursor.HasSelection() { h.Cursor.CopySelection("clipboard") h.Cursor.DeleteSelection() @@ -753,7 +753,7 @@ func (h *BufHandler) Cut() bool { } // DuplicateLine duplicates the current line or selection -func (h *BufHandler) DuplicateLine() bool { +func (h *BufPane) DuplicateLine() bool { if h.Cursor.HasSelection() { h.Buf.Insert(h.Cursor.CurSelection[1], string(h.Cursor.GetSelection())) } else { @@ -767,7 +767,7 @@ func (h *BufHandler) DuplicateLine() bool { } // DeleteLine deletes the current line -func (h *BufHandler) DeleteLine() bool { +func (h *BufPane) DeleteLine() bool { h.Cursor.SelectLine() if !h.Cursor.HasSelection() { return false @@ -779,7 +779,7 @@ func (h *BufHandler) DeleteLine() bool { } // MoveLinesUp moves up the current line or selected lines if any -func (h *BufHandler) MoveLinesUp() bool { +func (h *BufPane) MoveLinesUp() bool { if h.Cursor.HasSelection() { if h.Cursor.CurSelection[0].Y == 0 { InfoBar.Message("Can not move further up") @@ -811,7 +811,7 @@ func (h *BufHandler) MoveLinesUp() bool { } // MoveLinesDown moves down the current line or selected lines if any -func (h *BufHandler) MoveLinesDown() bool { +func (h *BufPane) MoveLinesDown() bool { if h.Cursor.HasSelection() { if h.Cursor.CurSelection[1].Y >= h.Buf.LinesNum() { InfoBar.Message("Can not move further down") @@ -843,20 +843,20 @@ func (h *BufHandler) MoveLinesDown() bool { // Paste whatever is in the system clipboard into the buffer // Delete and paste if the user has a selection -func (h *BufHandler) Paste() bool { +func (h *BufPane) Paste() bool { clip, _ := clipboard.ReadAll("clipboard") h.paste(clip) return true } // PastePrimary pastes from the primary clipboard (only use on linux) -func (h *BufHandler) PastePrimary() bool { +func (h *BufPane) PastePrimary() bool { clip, _ := clipboard.ReadAll("primary") h.paste(clip) return true } -func (h *BufHandler) paste(clip string) { +func (h *BufPane) paste(clip string) { if h.Buf.Settings["smartpaste"].(bool) { if h.Cursor.X > 0 && len(util.GetLeadingWhitespace([]byte(strings.TrimLeft(clip, "\r\n")))) == 0 { leadingWS := util.GetLeadingWhitespace(h.Buf.LineBytes(h.Cursor.Y)) @@ -877,7 +877,7 @@ func (h *BufHandler) paste(clip string) { // JumpToMatchingBrace moves the cursor to the matching brace if it is // currently on a brace -func (h *BufHandler) JumpToMatchingBrace() bool { +func (h *BufPane) JumpToMatchingBrace() bool { for _, bp := range buffer.BracePairs { r := h.Cursor.RuneUnder(h.Cursor.X) if r == bp[0] || r == bp[1] { @@ -890,7 +890,7 @@ func (h *BufHandler) JumpToMatchingBrace() bool { } // SelectAll selects the entire buffer -func (h *BufHandler) SelectAll() bool { +func (h *BufPane) SelectAll() bool { h.Cursor.SetSelectionStart(h.Buf.Start()) h.Cursor.SetSelectionEnd(h.Buf.End()) // Put the cursor at the beginning @@ -900,7 +900,7 @@ func (h *BufHandler) SelectAll() bool { } // OpenFile opens a new file in the buffer -func (h *BufHandler) OpenFile() bool { +func (h *BufPane) OpenFile() bool { InfoBar.Prompt("> ", "open ", "Open", nil, func(resp string, canceled bool) { if !canceled { h.HandleCommand(resp) @@ -910,7 +910,7 @@ func (h *BufHandler) OpenFile() bool { } // Start moves the viewport to the start of the buffer -func (h *BufHandler) Start() bool { +func (h *BufPane) Start() bool { v := h.GetView() v.StartLine = 0 h.SetView(v) @@ -918,7 +918,7 @@ func (h *BufHandler) Start() bool { } // End moves the viewport to the end of the buffer -func (h *BufHandler) End() bool { +func (h *BufPane) End() bool { // TODO: softwrap problems? v := h.GetView() if v.Height > h.Buf.LinesNum() { @@ -931,7 +931,7 @@ func (h *BufHandler) End() bool { } // PageUp scrolls the view up a page -func (h *BufHandler) PageUp() bool { +func (h *BufPane) PageUp() bool { v := h.GetView() if v.StartLine > v.Height { h.ScrollUp(v.Height) @@ -943,7 +943,7 @@ func (h *BufHandler) PageUp() bool { } // PageDown scrolls the view down a page -func (h *BufHandler) PageDown() bool { +func (h *BufPane) PageDown() bool { v := h.GetView() if h.Buf.LinesNum()-(v.StartLine+v.Height) > v.Height { h.ScrollDown(v.Height) @@ -954,7 +954,7 @@ func (h *BufHandler) PageDown() bool { } // SelectPageUp selects up one page -func (h *BufHandler) SelectPageUp() bool { +func (h *BufPane) SelectPageUp() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } @@ -964,7 +964,7 @@ func (h *BufHandler) SelectPageUp() bool { } // SelectPageDown selects down one page -func (h *BufHandler) SelectPageDown() bool { +func (h *BufPane) SelectPageDown() bool { if !h.Cursor.HasSelection() { h.Cursor.OrigSelection[0] = h.Cursor.Loc } @@ -974,7 +974,7 @@ func (h *BufHandler) SelectPageDown() bool { } // CursorPageUp places the cursor a page up -func (h *BufHandler) CursorPageUp() bool { +func (h *BufPane) CursorPageUp() bool { h.Cursor.Deselect(true) if h.Cursor.HasSelection() { @@ -987,7 +987,7 @@ func (h *BufHandler) CursorPageUp() bool { } // CursorPageDown places the cursor a page up -func (h *BufHandler) CursorPageDown() bool { +func (h *BufPane) CursorPageDown() bool { h.Cursor.Deselect(false) if h.Cursor.HasSelection() { @@ -1000,7 +1000,7 @@ func (h *BufHandler) CursorPageDown() bool { } // HalfPageUp scrolls the view up half a page -func (h *BufHandler) HalfPageUp() bool { +func (h *BufPane) HalfPageUp() bool { v := h.GetView() if v.StartLine > v.Height/2 { h.ScrollUp(v.Height / 2) @@ -1012,7 +1012,7 @@ func (h *BufHandler) HalfPageUp() bool { } // HalfPageDown scrolls the view down half a page -func (h *BufHandler) HalfPageDown() bool { +func (h *BufPane) HalfPageDown() bool { v := h.GetView() if h.Buf.LinesNum()-(v.StartLine+v.Height) > v.Height/2 { h.ScrollDown(v.Height / 2) @@ -1026,7 +1026,7 @@ func (h *BufHandler) HalfPageDown() bool { } // ToggleRuler turns line numbers off and on -func (h *BufHandler) ToggleRuler() bool { +func (h *BufPane) ToggleRuler() bool { if !h.Buf.Settings["ruler"].(bool) { h.Buf.Settings["ruler"] = true InfoBar.Message("Enabled ruler") @@ -1038,18 +1038,18 @@ func (h *BufHandler) ToggleRuler() bool { } // JumpLine jumps to a line and moves the view accordingly. -func (h *BufHandler) JumpLine() bool { +func (h *BufPane) JumpLine() bool { return false } // ClearStatus clears the messenger bar -func (h *BufHandler) ClearStatus() bool { +func (h *BufPane) ClearStatus() bool { InfoBar.Message("") return false } // ToggleHelp toggles the help screen -func (h *BufHandler) ToggleHelp() bool { +func (h *BufPane) ToggleHelp() bool { if h.Buf.Type == buffer.BTHelp { h.Quit() } else { @@ -1059,14 +1059,14 @@ func (h *BufHandler) ToggleHelp() bool { } // ToggleKeyMenu toggles the keymenu option and resizes all tabs -func (h *BufHandler) ToggleKeyMenu() bool { +func (h *BufPane) ToggleKeyMenu() bool { config.GlobalSettings["keymenu"] = !config.GetGlobalOption("keymenu").(bool) Tabs.Resize() return false } // ShellMode opens a terminal to run a shell command -func (h *BufHandler) ShellMode() bool { +func (h *BufPane) ShellMode() bool { InfoBar.Prompt("$ ", "", "Shell", nil, func(resp string, canceled bool) { if !canceled { // The true here is for openTerm to make the command interactive @@ -1078,7 +1078,7 @@ func (h *BufHandler) ShellMode() bool { } // CommandMode lets the user enter a command -func (h *BufHandler) CommandMode() bool { +func (h *BufPane) CommandMode() bool { InfoBar.Prompt("> ", "", "Command", nil, func(resp string, canceled bool) { if !canceled { h.HandleCommand(resp) @@ -1088,18 +1088,18 @@ func (h *BufHandler) CommandMode() bool { } // ToggleOverwriteMode lets the user toggle the text overwrite mode -func (h *BufHandler) ToggleOverwriteMode() bool { +func (h *BufPane) ToggleOverwriteMode() bool { h.isOverwriteMode = !h.isOverwriteMode return false } // Escape leaves current mode -func (h *BufHandler) Escape() bool { +func (h *BufPane) Escape() bool { return false } // Quit this will close the current tab or view that is open -func (h *BufHandler) Quit() bool { +func (h *BufPane) Quit() bool { quit := func() { h.Buf.Close() if len(MainTab().Panes) > 1 { @@ -1128,12 +1128,12 @@ func (h *BufHandler) Quit() bool { } // QuitAll quits the whole editor; all splits and tabs -func (h *BufHandler) QuitAll() bool { +func (h *BufPane) QuitAll() bool { return false } // AddTab adds a new tab with an empty buffer -func (h *BufHandler) AddTab() bool { +func (h *BufPane) AddTab() bool { width, height := screen.Screen.Size() iOffset := config.GetInfoBarOffset() b := buffer.NewBufferFromString("", "", buffer.BTDefault) @@ -1145,7 +1145,7 @@ func (h *BufHandler) AddTab() bool { } // PreviousTab switches to the previous tab in the tab list -func (h *BufHandler) PreviousTab() bool { +func (h *BufPane) PreviousTab() bool { a := Tabs.Active() Tabs.SetActive(util.Clamp(a-1, 0, len(Tabs.List)-1)) @@ -1153,28 +1153,28 @@ func (h *BufHandler) PreviousTab() bool { } // NextTab switches to the next tab in the tab list -func (h *BufHandler) NextTab() bool { +func (h *BufPane) NextTab() bool { a := Tabs.Active() Tabs.SetActive(util.Clamp(a+1, 0, len(Tabs.List)-1)) return false } // VSplitAction opens an empty vertical split -func (h *BufHandler) VSplitAction() bool { +func (h *BufPane) VSplitAction() bool { h.VSplitBuf(buffer.NewBufferFromString("", "", buffer.BTDefault)) return false } // HSplitAction opens an empty horizontal split -func (h *BufHandler) HSplitAction() bool { +func (h *BufPane) HSplitAction() bool { h.HSplitBuf(buffer.NewBufferFromString("", "", buffer.BTDefault)) return false } // Unsplit closes all splits in the current tab except the active one -func (h *BufHandler) Unsplit() bool { +func (h *BufPane) Unsplit() bool { n := MainTab().GetNode(h.splitID) n.Unsplit() @@ -1185,7 +1185,7 @@ func (h *BufHandler) Unsplit() bool { } // NextSplit changes the view to the next split -func (h *BufHandler) NextSplit() bool { +func (h *BufPane) NextSplit() bool { a := MainTab().active if a < len(MainTab().Panes)-1 { a++ @@ -1199,7 +1199,7 @@ func (h *BufHandler) NextSplit() bool { } // PreviousSplit changes the view to the previous split -func (h *BufHandler) PreviousSplit() bool { +func (h *BufPane) PreviousSplit() bool { a := MainTab().active if a > 0 { a-- @@ -1215,17 +1215,17 @@ var curMacro []interface{} var recordingMacro bool // ToggleMacro toggles recording of a macro -func (h *BufHandler) ToggleMacro() bool { +func (h *BufPane) ToggleMacro() bool { return true } // PlayMacro plays back the most recently recorded macro -func (h *BufHandler) PlayMacro() bool { +func (h *BufPane) PlayMacro() bool { return true } // SpawnMultiCursor creates a new multiple cursor at the next occurrence of the current selection or current word -func (h *BufHandler) SpawnMultiCursor() bool { +func (h *BufPane) SpawnMultiCursor() bool { spawner := h.Buf.GetCursor(h.Buf.NumCursors() - 1) if !spawner.HasSelection() { spawner.SelectWord() @@ -1264,7 +1264,7 @@ func (h *BufHandler) SpawnMultiCursor() bool { } // SpawnMultiCursorSelect adds a cursor at the beginning of each line of a selection -func (h *BufHandler) SpawnMultiCursorSelect() bool { +func (h *BufPane) SpawnMultiCursorSelect() bool { // Avoid cases where multiple cursors already exist, that would create problems if h.Buf.NumCursors() > 1 { return false @@ -1298,7 +1298,7 @@ func (h *BufHandler) SpawnMultiCursorSelect() bool { } // MouseMultiCursor is a mouse action which puts a new cursor at the mouse position -func (h *BufHandler) MouseMultiCursor(e *tcell.EventMouse) bool { +func (h *BufPane) MouseMultiCursor(e *tcell.EventMouse) bool { b := h.Buf mx, my := e.Position() mouseLoc := h.GetMouseLoc(buffer.Loc{X: mx, Y: my}) @@ -1310,7 +1310,7 @@ func (h *BufHandler) MouseMultiCursor(e *tcell.EventMouse) bool { } // SkipMultiCursor moves the current multiple cursor to the next available position -func (h *BufHandler) SkipMultiCursor() bool { +func (h *BufPane) SkipMultiCursor() bool { lastC := h.Buf.GetCursor(h.Buf.NumCursors() - 1) sel := lastC.GetSelection() searchStart := lastC.CurSelection[1] @@ -1341,7 +1341,7 @@ func (h *BufHandler) SkipMultiCursor() bool { } // RemoveMultiCursor removes the latest multiple cursor -func (h *BufHandler) RemoveMultiCursor() bool { +func (h *BufPane) RemoveMultiCursor() bool { if h.Buf.NumCursors() > 1 { h.Buf.RemoveCursor(h.Buf.NumCursors() - 1) h.Buf.SetCurCursor(h.Buf.NumCursors() - 1) @@ -1353,7 +1353,7 @@ func (h *BufHandler) RemoveMultiCursor() bool { } // RemoveAllMultiCursors removes all cursors except the base cursor -func (h *BufHandler) RemoveAllMultiCursors() bool { +func (h *BufPane) RemoveAllMultiCursors() bool { h.Buf.ClearCursors() h.multiWord = false return true diff --git a/cmd/micro/action/actions_other.go b/cmd/micro/action/actions_other.go index 52e94376..6d62581b 100644 --- a/cmd/micro/action/actions_other.go +++ b/cmd/micro/action/actions_other.go @@ -2,7 +2,7 @@ package action -func (*BufHandler) Suspend() bool { +func (*BufPane) Suspend() bool { InfoBar.Error("Suspend is only supported on BSD/Linux") return false } diff --git a/cmd/micro/action/actions_posix.go b/cmd/micro/action/actions_posix.go index c6ac2b0d..98609bbe 100644 --- a/cmd/micro/action/actions_posix.go +++ b/cmd/micro/action/actions_posix.go @@ -11,7 +11,7 @@ import ( // 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 code was adapted from the suspend code in nsf/godit -func (*BufHandler) Suspend() bool { +func (*BufPane) Suspend() bool { screenb := screen.TempFini() // suspend the process diff --git a/cmd/micro/action/bufhandler.go b/cmd/micro/action/bufpane.go similarity index 58% rename from cmd/micro/action/bufhandler.go rename to cmd/micro/action/bufpane.go index c072a522..71baf6b5 100644 --- a/cmd/micro/action/bufhandler.go +++ b/cmd/micro/action/bufpane.go @@ -9,8 +9,8 @@ import ( "github.com/zyedidia/tcell" ) -type BufKeyAction func(*BufHandler) bool -type BufMouseAction func(*BufHandler, *tcell.EventMouse) bool +type BufKeyAction func(*BufPane) bool +type BufMouseAction func(*BufPane, *tcell.EventMouse) bool var BufKeyBindings map[Event]BufKeyAction var BufKeyStrings map[Event]string @@ -47,12 +47,12 @@ func BufMapMouse(k MouseEvent, action string) { } } -// The BufHandler connects the buffer and the window +// The BufPane 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 { +type BufPane struct { display.BWindow Buf *buffer.Buffer @@ -98,8 +98,8 @@ type BufHandler struct { splitID uint64 } -func NewBufHandler(buf *buffer.Buffer, win display.BWindow) *BufHandler { - h := new(BufHandler) +func NewBufPane(buf *buffer.Buffer, win display.BWindow) *BufPane { + h := new(BufPane) h.Buf = buf h.BWindow = win @@ -109,7 +109,12 @@ func NewBufHandler(buf *buffer.Buffer, win display.BWindow) *BufHandler { return h } -func (h *BufHandler) OpenBuffer(b *buffer.Buffer) { +func NewBufPaneFromBuf(buf *buffer.Buffer) *BufPane { + w := display.NewBufWindow(0, 0, 0, 0, buf) + return NewBufPane(buf, w) +} + +func (h *BufPane) OpenBuffer(b *buffer.Buffer) { h.Buf.Close() h.Buf = b h.BWindow.SetBuffer(b) @@ -126,17 +131,21 @@ func (h *BufHandler) OpenBuffer(b *buffer.Buffer) { h.lastClickTime = time.Time{} } -func (h *BufHandler) ID() uint64 { +func (h *BufPane) ID() uint64 { return h.splitID } -func (h *BufHandler) Name() string { +func (h *BufPane) SetID(i uint64) { + h.splitID = i +} + +func (h *BufPane) Name() string { return h.Buf.GetName() } // HandleEvent executes the tcell event properly // TODO: multiple actions bound to one key -func (h *BufHandler) HandleEvent(event tcell.Event) { +func (h *BufPane) HandleEvent(event tcell.Event) { switch e := event.(type) { case *tcell.EventRaw: re := RawEvent{ @@ -204,7 +213,7 @@ func (h *BufHandler) HandleEvent(event tcell.Event) { // DoKeyEvent executes a key event by finding the action it is bound // to and executing it (possibly multiple times for multiple cursors) -func (h *BufHandler) DoKeyEvent(e Event) bool { +func (h *BufPane) DoKeyEvent(e Event) bool { if action, ok := BufKeyBindings[e]; ok { estr := BufKeyStrings[e] for _, s := range MultiActions { @@ -228,14 +237,14 @@ func (h *BufHandler) DoKeyEvent(e Event) bool { return false } -func (h *BufHandler) HasKeyEvent(e Event) bool { +func (h *BufPane) HasKeyEvent(e Event) bool { _, ok := BufKeyBindings[e] return ok } // DoMouseEvent executes a mouse event by finding the action it is bound // to and executing it -func (h *BufHandler) DoMouseEvent(e MouseEvent, te *tcell.EventMouse) bool { +func (h *BufPane) DoMouseEvent(e MouseEvent, te *tcell.EventMouse) bool { if action, ok := BufMouseBindings[e]; ok { if action(h, te) { h.Relocate() @@ -249,7 +258,7 @@ func (h *BufHandler) DoMouseEvent(e MouseEvent, te *tcell.EventMouse) bool { // DoRuneInsert inserts a given rune into the current buffer // (possibly multiple times for multiple cursors) -func (h *BufHandler) DoRuneInsert(r rune) { +func (h *BufPane) DoRuneInsert(r rune) { cursors := h.Buf.GetCursors() for _, c := range cursors { // Insert a character @@ -269,127 +278,127 @@ func (h *BufHandler) DoRuneInsert(r rune) { } } -func (h *BufHandler) VSplitBuf(buf *buffer.Buffer) { - e := NewBufEditPane(0, 0, 0, 0, buf) +func (h *BufPane) VSplitBuf(buf *buffer.Buffer) { + e := NewBufPaneFromBuf(buf) e.splitID = MainTab().GetNode(h.splitID).VSplit(h.Buf.Settings["splitright"].(bool)) MainTab().Panes = append(MainTab().Panes, e) MainTab().Resize() MainTab().SetActive(len(MainTab().Panes) - 1) } -func (h *BufHandler) HSplitBuf(buf *buffer.Buffer) { - e := NewBufEditPane(0, 0, 0, 0, buf) +func (h *BufPane) HSplitBuf(buf *buffer.Buffer) { + e := NewBufPaneFromBuf(buf) e.splitID = MainTab().GetNode(h.splitID).HSplit(h.Buf.Settings["splitbottom"].(bool)) MainTab().Panes = append(MainTab().Panes, e) MainTab().Resize() MainTab().SetActive(len(MainTab().Panes) - 1) } -func (h *BufHandler) Close() { +func (h *BufPane) Close() { h.Buf.Close() } // BufKeyActions contains the list of all possible key actions the bufhandler could execute 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, - "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).VSplitAction, - "HSplit": (*BufHandler).HSplitAction, - "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, + "CursorUp": (*BufPane).CursorUp, + "CursorDown": (*BufPane).CursorDown, + "CursorPageUp": (*BufPane).CursorPageUp, + "CursorPageDown": (*BufPane).CursorPageDown, + "CursorLeft": (*BufPane).CursorLeft, + "CursorRight": (*BufPane).CursorRight, + "CursorStart": (*BufPane).CursorStart, + "CursorEnd": (*BufPane).CursorEnd, + "SelectToStart": (*BufPane).SelectToStart, + "SelectToEnd": (*BufPane).SelectToEnd, + "SelectUp": (*BufPane).SelectUp, + "SelectDown": (*BufPane).SelectDown, + "SelectLeft": (*BufPane).SelectLeft, + "SelectRight": (*BufPane).SelectRight, + "WordRight": (*BufPane).WordRight, + "WordLeft": (*BufPane).WordLeft, + "SelectWordRight": (*BufPane).SelectWordRight, + "SelectWordLeft": (*BufPane).SelectWordLeft, + "DeleteWordRight": (*BufPane).DeleteWordRight, + "DeleteWordLeft": (*BufPane).DeleteWordLeft, + "SelectLine": (*BufPane).SelectLine, + "SelectToStartOfLine": (*BufPane).SelectToStartOfLine, + "SelectToEndOfLine": (*BufPane).SelectToEndOfLine, + "ParagraphPrevious": (*BufPane).ParagraphPrevious, + "ParagraphNext": (*BufPane).ParagraphNext, + "InsertNewline": (*BufPane).InsertNewline, + "Backspace": (*BufPane).Backspace, + "Delete": (*BufPane).Delete, + "InsertTab": (*BufPane).InsertTab, + "Save": (*BufPane).Save, + "SaveAll": (*BufPane).SaveAll, + "SaveAs": (*BufPane).SaveAs, + "Find": (*BufPane).Find, + "FindNext": (*BufPane).FindNext, + "FindPrevious": (*BufPane).FindPrevious, + "Center": (*BufPane).Center, + "Undo": (*BufPane).Undo, + "Redo": (*BufPane).Redo, + "Copy": (*BufPane).Copy, + "Cut": (*BufPane).Cut, + "CutLine": (*BufPane).CutLine, + "DuplicateLine": (*BufPane).DuplicateLine, + "DeleteLine": (*BufPane).DeleteLine, + "MoveLinesUp": (*BufPane).MoveLinesUp, + "MoveLinesDown": (*BufPane).MoveLinesDown, + "IndentSelection": (*BufPane).IndentSelection, + "OutdentSelection": (*BufPane).OutdentSelection, + "OutdentLine": (*BufPane).OutdentLine, + "Paste": (*BufPane).Paste, + "PastePrimary": (*BufPane).PastePrimary, + "SelectAll": (*BufPane).SelectAll, + "OpenFile": (*BufPane).OpenFile, + "Start": (*BufPane).Start, + "End": (*BufPane).End, + "PageUp": (*BufPane).PageUp, + "PageDown": (*BufPane).PageDown, + "SelectPageUp": (*BufPane).SelectPageUp, + "SelectPageDown": (*BufPane).SelectPageDown, + "HalfPageUp": (*BufPane).HalfPageUp, + "HalfPageDown": (*BufPane).HalfPageDown, + "StartOfLine": (*BufPane).StartOfLine, + "EndOfLine": (*BufPane).EndOfLine, + "ToggleHelp": (*BufPane).ToggleHelp, + "ToggleKeyMenu": (*BufPane).ToggleKeyMenu, + "ToggleRuler": (*BufPane).ToggleRuler, + "JumpLine": (*BufPane).JumpLine, + "ClearStatus": (*BufPane).ClearStatus, + "ShellMode": (*BufPane).ShellMode, + "CommandMode": (*BufPane).CommandMode, + "ToggleOverwriteMode": (*BufPane).ToggleOverwriteMode, + "Escape": (*BufPane).Escape, + "Quit": (*BufPane).Quit, + "QuitAll": (*BufPane).QuitAll, + "AddTab": (*BufPane).AddTab, + "PreviousTab": (*BufPane).PreviousTab, + "NextTab": (*BufPane).NextTab, + "NextSplit": (*BufPane).NextSplit, + "PreviousSplit": (*BufPane).PreviousSplit, + "Unsplit": (*BufPane).Unsplit, + "VSplit": (*BufPane).VSplitAction, + "HSplit": (*BufPane).HSplitAction, + "ToggleMacro": (*BufPane).ToggleMacro, + "PlayMacro": (*BufPane).PlayMacro, + "Suspend": (*BufPane).Suspend, + "ScrollUp": (*BufPane).ScrollUpAction, + "ScrollDown": (*BufPane).ScrollDownAction, + "SpawnMultiCursor": (*BufPane).SpawnMultiCursor, + "SpawnMultiCursorSelect": (*BufPane).SpawnMultiCursorSelect, + "RemoveMultiCursor": (*BufPane).RemoveMultiCursor, + "RemoveAllMultiCursors": (*BufPane).RemoveAllMultiCursors, + "SkipMultiCursor": (*BufPane).SkipMultiCursor, + "JumpToMatchingBrace": (*BufPane).JumpToMatchingBrace, // This was changed to InsertNewline but I don't want to break backwards compatibility - "InsertEnter": (*BufHandler).InsertNewline, + "InsertEnter": (*BufPane).InsertNewline, } // BufMouseActions contains the list of all possible mouse actions the bufhandler could execute var BufMouseActions = map[string]BufMouseAction{ - "MousePress": (*BufHandler).MousePress, - "MouseMultiCursor": (*BufHandler).MouseMultiCursor, + "MousePress": (*BufPane).MousePress, + "MouseMultiCursor": (*BufPane).MouseMultiCursor, } // MultiActions is a list of actions that should be executed multiple diff --git a/cmd/micro/action/command.go b/cmd/micro/action/command.go index f0503e90..9330b2de 100644 --- a/cmd/micro/action/command.go +++ b/cmd/micro/action/command.go @@ -20,7 +20,7 @@ import ( // A Command contains an action (a function to call) as well as information about how to autocomplete the command type Command struct { - action func(*BufHandler, []string) + action func(*BufPane, []string) completions []Completion } @@ -32,34 +32,34 @@ type StrCommand struct { var commands map[string]Command -var commandActions = map[string]func(*BufHandler, []string){ - "Set": (*BufHandler).SetCmd, - "SetLocal": (*BufHandler).SetLocalCmd, - "Show": (*BufHandler).ShowCmd, - "ShowKey": (*BufHandler).ShowKeyCmd, - "Run": (*BufHandler).RunCmd, - "Bind": (*BufHandler).BindCmd, - "Unbind": (*BufHandler).UnbindCmd, - "Quit": (*BufHandler).QuitCmd, - "Save": (*BufHandler).SaveCmd, - "Replace": (*BufHandler).ReplaceCmd, - "ReplaceAll": (*BufHandler).ReplaceAllCmd, - "VSplit": (*BufHandler).VSplitCmd, - "HSplit": (*BufHandler).HSplitCmd, - "Tab": (*BufHandler).NewTabCmd, - "Help": (*BufHandler).HelpCmd, - "Eval": (*BufHandler).EvalCmd, - "ToggleLog": (*BufHandler).ToggleLogCmd, - "Plugin": (*BufHandler).PluginCmd, - "Reload": (*BufHandler).ReloadCmd, - "Cd": (*BufHandler).CdCmd, - "Pwd": (*BufHandler).PwdCmd, - "Open": (*BufHandler).OpenCmd, - "TabSwitch": (*BufHandler).TabSwitchCmd, - "Term": (*BufHandler).TermCmd, - "MemUsage": (*BufHandler).MemUsageCmd, - "Retab": (*BufHandler).RetabCmd, - "Raw": (*BufHandler).RawCmd, +var commandActions = map[string]func(*BufPane, []string){ + "Set": (*BufPane).SetCmd, + "SetLocal": (*BufPane).SetLocalCmd, + "Show": (*BufPane).ShowCmd, + "ShowKey": (*BufPane).ShowKeyCmd, + "Run": (*BufPane).RunCmd, + "Bind": (*BufPane).BindCmd, + "Unbind": (*BufPane).UnbindCmd, + "Quit": (*BufPane).QuitCmd, + "Save": (*BufPane).SaveCmd, + "Replace": (*BufPane).ReplaceCmd, + "ReplaceAll": (*BufPane).ReplaceAllCmd, + "VSplit": (*BufPane).VSplitCmd, + "HSplit": (*BufPane).HSplitCmd, + "Tab": (*BufPane).NewTabCmd, + "Help": (*BufPane).HelpCmd, + "Eval": (*BufPane).EvalCmd, + "ToggleLog": (*BufPane).ToggleLogCmd, + "Plugin": (*BufPane).PluginCmd, + "Reload": (*BufPane).ReloadCmd, + "Cd": (*BufPane).CdCmd, + "Pwd": (*BufPane).PwdCmd, + "Open": (*BufPane).OpenCmd, + "TabSwitch": (*BufPane).TabSwitchCmd, + "Term": (*BufPane).TermCmd, + "MemUsage": (*BufPane).MemUsageCmd, + "Retab": (*BufPane).RetabCmd, + "Raw": (*BufPane).RawCmd, } // InitCommands initializes the default commands @@ -126,7 +126,7 @@ func DefaultCommands() map[string]StrCommand { // the given string and executes the command when the user presses // enter func CommandEditAction(prompt string) BufKeyAction { - return func(h *BufHandler) bool { + return func(h *BufPane) bool { InfoBar.Prompt("> ", prompt, "Command", nil, func(resp string, canceled bool) { if !canceled { MainTab().CurPane().HandleCommand(resp) @@ -139,29 +139,34 @@ func CommandEditAction(prompt string) BufKeyAction { // CommandAction returns a bindable function which executes the // given command func CommandAction(cmd string) BufKeyAction { - return func(h *BufHandler) bool { + return func(h *BufPane) bool { MainTab().CurPane().HandleCommand(cmd) return false } } // PluginCmd installs, removes, updates, lists, or searches for given plugins -func (h *BufHandler) PluginCmd(args []string) { +func (h *BufPane) PluginCmd(args []string) { } // RetabCmd changes all spaces to tabs or all tabs to spaces // depending on the user's settings -func (h *BufHandler) RetabCmd(args []string) { +func (h *BufPane) RetabCmd(args []string) { h.Buf.Retab() } // RawCmd opens a new raw view which displays the escape sequences micro // is receiving in real-time -func (h *BufHandler) RawCmd(args []string) { +func (h *BufPane) RawCmd(args []string) { + width, height := screen.Screen.Size() + iOffset := config.GetInfoBarOffset() + tp := NewTabFromPane(0, 0, width, height-iOffset, NewRawPane()) + Tabs.AddTab(tp) + Tabs.SetActive(len(Tabs.List) - 1) } // TabSwitchCmd switches to a given tab either by name or by number -func (h *BufHandler) TabSwitchCmd(args []string) { +func (h *BufPane) TabSwitchCmd(args []string) { if len(args) > 0 { num, err := strconv.Atoi(args[0]) if err != nil { @@ -189,7 +194,7 @@ func (h *BufHandler) TabSwitchCmd(args []string) { } // CdCmd changes the current working directory -func (h *BufHandler) CdCmd(args []string) { +func (h *BufPane) CdCmd(args []string) { if len(args) > 0 { path, err := util.ReplaceHome(args[0]) if err != nil { @@ -220,12 +225,12 @@ func (h *BufHandler) CdCmd(args []string) { // Note that Go commonly reserves more memory from the OS than is currently in-use/required // Additionally, even if Go returns memory to the OS, the OS does not always claim it because // there may be plenty of memory to spare -func (h *BufHandler) MemUsageCmd(args []string) { +func (h *BufPane) MemUsageCmd(args []string) { InfoBar.Message(util.GetMemStats()) } // PwdCmd prints the current working directory -func (h *BufHandler) PwdCmd(args []string) { +func (h *BufPane) PwdCmd(args []string) { wd, err := os.Getwd() if err != nil { InfoBar.Message(err.Error()) @@ -235,7 +240,7 @@ func (h *BufHandler) PwdCmd(args []string) { } // OpenCmd opens a new buffer with a given filename -func (h *BufHandler) OpenCmd(args []string) { +func (h *BufPane) OpenCmd(args []string) { if len(args) > 0 { filename := args[0] // the filename might or might not be quoted, so unquote first then join the strings. @@ -272,14 +277,14 @@ func (h *BufHandler) OpenCmd(args []string) { } // ToggleLogCmd toggles the log view -func (h *BufHandler) ToggleLogCmd(args []string) { +func (h *BufPane) ToggleLogCmd(args []string) { } // ReloadCmd reloads all files (syntax files, colorschemes...) -func (h *BufHandler) ReloadCmd(args []string) { +func (h *BufPane) ReloadCmd(args []string) { } -func (h *BufHandler) openHelp(page string) error { +func (h *BufPane) openHelp(page string) error { if data, err := config.FindRuntimeFile(config.RTHelp, page).Data(); err != nil { return errors.New(fmt.Sprint("Unable to load help text", page, "\n", err)) } else { @@ -296,7 +301,7 @@ func (h *BufHandler) openHelp(page string) error { } // HelpCmd tries to open the given help page in a horizontal split -func (h *BufHandler) HelpCmd(args []string) { +func (h *BufPane) HelpCmd(args []string) { if len(args) < 1 { // Open the default help if the user just typed "> help" h.openHelp("help") @@ -314,7 +319,7 @@ func (h *BufHandler) HelpCmd(args []string) { // VSplitCmd opens a vertical split with file given in the first argument // If no file is given, it opens an empty buffer in a new split -func (h *BufHandler) VSplitCmd(args []string) { +func (h *BufPane) VSplitCmd(args []string) { if len(args) == 0 { // Open an empty vertical split h.VSplitAction() @@ -332,7 +337,7 @@ func (h *BufHandler) VSplitCmd(args []string) { // HSplitCmd opens a horizontal split with file given in the first argument // If no file is given, it opens an empty buffer in a new split -func (h *BufHandler) HSplitCmd(args []string) { +func (h *BufPane) HSplitCmd(args []string) { if len(args) == 0 { // Open an empty horizontal split h.HSplitAction() @@ -349,11 +354,11 @@ func (h *BufHandler) HSplitCmd(args []string) { } // EvalCmd evaluates a lua expression -func (h *BufHandler) EvalCmd(args []string) { +func (h *BufPane) EvalCmd(args []string) { } // NewTabCmd opens the given file in a new tab -func (h *BufHandler) NewTabCmd(args []string) { +func (h *BufPane) NewTabCmd(args []string) { width, height := screen.Screen.Size() iOffset := config.GetInfoBarOffset() if len(args) > 0 { @@ -417,7 +422,7 @@ func SetGlobalOption(option, value string) error { } // SetCmd sets an option -func (h *BufHandler) SetCmd(args []string) { +func (h *BufPane) SetCmd(args []string) { if len(args) < 2 { InfoBar.Error("Not enough arguments") return @@ -438,7 +443,7 @@ func (h *BufHandler) SetCmd(args []string) { } // SetLocalCmd sets an option local to the buffer -func (h *BufHandler) SetLocalCmd(args []string) { +func (h *BufPane) SetLocalCmd(args []string) { if len(args) < 2 { InfoBar.Error("Not enough arguments") return @@ -455,7 +460,7 @@ func (h *BufHandler) SetLocalCmd(args []string) { } // ShowCmd shows the value of the given option -func (h *BufHandler) ShowCmd(args []string) { +func (h *BufPane) ShowCmd(args []string) { if len(args) < 1 { InfoBar.Error("Please provide an option to show") return @@ -477,7 +482,7 @@ func (h *BufHandler) ShowCmd(args []string) { } // ShowKeyCmd displays the action that a key is bound to -func (h *BufHandler) ShowKeyCmd(args []string) { +func (h *BufPane) ShowKeyCmd(args []string) { if len(args) < 1 { InfoBar.Error("Please provide a key to show") return @@ -491,7 +496,7 @@ func (h *BufHandler) ShowKeyCmd(args []string) { } // BindCmd creates a new keybinding -func (h *BufHandler) BindCmd(args []string) { +func (h *BufPane) BindCmd(args []string) { if len(args) < 2 { InfoBar.Error("Not enough arguments") return @@ -504,7 +509,7 @@ func (h *BufHandler) BindCmd(args []string) { } // UnbindCmd binds a key to its default action -func (h *BufHandler) UnbindCmd(args []string) { +func (h *BufPane) UnbindCmd(args []string) { if len(args) < 1 { InfoBar.Error("Not enough arguements") return @@ -517,7 +522,7 @@ func (h *BufHandler) UnbindCmd(args []string) { } // RunCmd runs a shell command in the background -func (h *BufHandler) RunCmd(args []string) { +func (h *BufPane) RunCmd(args []string) { runf, err := shell.RunBackgroundShell(shellwords.Join(args...)) if err != nil { InfoBar.Error(err) @@ -530,17 +535,17 @@ func (h *BufHandler) RunCmd(args []string) { } // QuitCmd closes the main view -func (h *BufHandler) QuitCmd(args []string) { +func (h *BufPane) QuitCmd(args []string) { h.Quit() } // SaveCmd saves the buffer in the main view -func (h *BufHandler) SaveCmd(args []string) { +func (h *BufPane) SaveCmd(args []string) { h.Save() } // ReplaceCmd runs search and replace -func (h *BufHandler) ReplaceCmd(args []string) { +func (h *BufPane) ReplaceCmd(args []string) { if len(args) < 2 || len(args) > 4 { // We need to find both a search and replace expression InfoBar.Error("Invalid replace statement: " + strings.Join(args, " ")) @@ -654,11 +659,11 @@ func (h *BufHandler) ReplaceCmd(args []string) { } // ReplaceAllCmd replaces search term all at once -func (h *BufHandler) ReplaceAllCmd(args []string) { +func (h *BufPane) ReplaceAllCmd(args []string) { } // TermCmd opens a terminal in the current view -func (h *BufHandler) TermCmd(args []string) { +func (h *BufPane) TermCmd(args []string) { ps := MainTab().Panes if len(args) == 0 { @@ -685,7 +690,7 @@ func (h *BufHandler) TermCmd(args []string) { } v := h.GetView() - MainTab().Panes[i] = NewTermHandler(v.X, v.Y, v.Width, v.Height, t, id) + MainTab().Panes[i] = NewTermPane(v.X, v.Y, v.Width, v.Height, t, id) MainTab().SetActive(i) } @@ -716,7 +721,7 @@ func (h *BufHandler) TermCmd(args []string) { } // HandleCommand handles input from the user -func (h *BufHandler) HandleCommand(input string) { +func (h *BufPane) HandleCommand(input string) { args, err := shellwords.Split(input) if err != nil { InfoBar.Error("Error parsing args ", err) diff --git a/cmd/micro/action/infohandler.go b/cmd/micro/action/infopane.go similarity index 68% rename from cmd/micro/action/infohandler.go rename to cmd/micro/action/infopane.go index 5c432295..d71371c3 100644 --- a/cmd/micro/action/infohandler.go +++ b/cmd/micro/action/infopane.go @@ -6,22 +6,33 @@ import ( "github.com/zyedidia/tcell" ) -type InfoKeyAction func(*InfoHandler) +type InfoKeyAction func(*InfoPane) -type InfoHandler struct { - *BufHandler +type InfoPane struct { + *BufPane *info.InfoBuf } -func NewInfoHandler(ib *info.InfoBuf, w display.BWindow) *InfoHandler { - ih := new(InfoHandler) - ih.InfoBuf = ib - ih.BufHandler = NewBufHandler(ib.Buffer, w) +func NewInfoPane(ib *info.InfoBuf, w display.BWindow) *InfoPane { + ip := new(InfoPane) + ip.InfoBuf = ib + ip.BufPane = NewBufPane(ib.Buffer, w) - return ih + return ip } -func (h *InfoHandler) HandleEvent(event tcell.Event) { +func NewInfoBar() *InfoPane { + ib := info.NewBuffer() + w := display.NewInfoWindow(ib) + return NewInfoPane(ib, w) +} + +func (h *InfoPane) Close() { + h.InfoBuf.Close() + h.BufPane.Close() +} + +func (h *InfoPane) HandleEvent(event tcell.Event) { switch e := event.(type) { case *tcell.EventKey: ke := KeyEvent{ @@ -54,11 +65,11 @@ func (h *InfoHandler) HandleEvent(event tcell.Event) { } } case *tcell.EventMouse: - h.BufHandler.HandleEvent(event) + h.BufPane.HandleEvent(event) } } -func (h *InfoHandler) DoKeyEvent(e KeyEvent) bool { +func (h *InfoPane) DoKeyEvent(e KeyEvent) bool { done := false if action, ok := BufKeyBindings[e]; ok { estr := BufKeyStrings[e] @@ -75,7 +86,7 @@ func (h *InfoHandler) DoKeyEvent(e KeyEvent) bool { } } if !done { - done = action(h.BufHandler) + done = action(h.BufPane) } } return done @@ -133,35 +144,35 @@ var InfoNones = []string{ // InfoOverrides is the list of actions which have been overriden // by the infohandler var InfoOverrides = map[string]InfoKeyAction{ - "CursorUp": (*InfoHandler).CursorUp, - "CursorDown": (*InfoHandler).CursorDown, - "InsertNewline": (*InfoHandler).InsertNewline, - "InsertTab": (*InfoHandler).InsertTab, - "Escape": (*InfoHandler).Escape, - "Quit": (*InfoHandler).Quit, - "QuitAll": (*InfoHandler).QuitAll, + "CursorUp": (*InfoPane).CursorUp, + "CursorDown": (*InfoPane).CursorDown, + "InsertNewline": (*InfoPane).InsertNewline, + "InsertTab": (*InfoPane).InsertTab, + "Escape": (*InfoPane).Escape, + "Quit": (*InfoPane).Quit, + "QuitAll": (*InfoPane).QuitAll, } -func (h *InfoHandler) CursorUp() { +func (h *InfoPane) CursorUp() { h.UpHistory(h.History[h.PromptType]) } -func (h *InfoHandler) CursorDown() { +func (h *InfoPane) CursorDown() { h.DownHistory(h.History[h.PromptType]) } -func (h *InfoHandler) InsertTab() { +func (h *InfoPane) InsertTab() { // TODO: autocomplete } -func (h *InfoHandler) InsertNewline() { +func (h *InfoPane) InsertNewline() { if !h.HasYN { h.DonePrompt(false) } } -func (h *InfoHandler) Quit() { +func (h *InfoPane) Quit() { h.DonePrompt(true) } -func (h *InfoHandler) QuitAll() { +func (h *InfoPane) QuitAll() { h.DonePrompt(true) } -func (h *InfoHandler) Escape() { +func (h *InfoPane) Escape() { h.DonePrompt(true) } diff --git a/cmd/micro/action/pane.go b/cmd/micro/action/pane.go index 8da64e5e..0a4f2f6e 100644 --- a/cmd/micro/action/pane.go +++ b/cmd/micro/action/pane.go @@ -1,47 +1,14 @@ package action import ( - "github.com/zyedidia/micro/cmd/micro/buffer" "github.com/zyedidia/micro/cmd/micro/display" - "github.com/zyedidia/micro/cmd/micro/info" ) type Pane interface { Handler display.Window ID() uint64 + SetID(i uint64) Name() string Close() } - -type EditPane struct { - display.BWindow - *BufHandler -} - -type InfoPane struct { - display.BWindow - *InfoHandler - *info.InfoBuf -} - -func NewBufEditPane(x, y, width, height int, b *buffer.Buffer) *EditPane { - e := new(EditPane) - // TODO: can probably replace editpane with bufhandler entirely - w := display.NewBufWindow(x, y, width, height, b) - e.BWindow = w - e.BufHandler = NewBufHandler(b, w) - - return e -} - -func NewInfoBar() *InfoPane { - e := new(InfoPane) - ib := info.NewBuffer() - w := display.NewInfoWindow(ib) - e.BWindow = w - e.InfoHandler = NewInfoHandler(ib, w) - e.InfoBuf = ib - - return e -} diff --git a/cmd/micro/action/rawpane.go b/cmd/micro/action/rawpane.go new file mode 100644 index 00000000..113c938c --- /dev/null +++ b/cmd/micro/action/rawpane.go @@ -0,0 +1,40 @@ +package action + +import ( + "fmt" + "reflect" + + "github.com/zyedidia/micro/cmd/micro/buffer" + "github.com/zyedidia/micro/cmd/micro/display" + "github.com/zyedidia/tcell" +) + +type RawPane struct { + *BufPane +} + +func NewRawPaneFromWin(b *buffer.Buffer, win display.BWindow) *RawPane { + rh := new(RawPane) + rh.BufPane = NewBufPane(b, win) + + return rh +} + +func NewRawPane() *RawPane { + b := buffer.NewBufferFromString("", "", buffer.BTRaw) + w := display.NewBufWindow(0, 0, 0, 0, b) + return NewRawPaneFromWin(b, w) +} + +func (h *RawPane) HandleEvent(event tcell.Event) { + switch e := event.(type) { + case *tcell.EventKey: + if e.Key() == tcell.KeyCtrlQ { + h.Quit() + } + } + + h.Buf.Insert(h.Cursor.Loc, reflect.TypeOf(event).String()[7:]) + h.Buf.Insert(h.Cursor.Loc, fmt.Sprintf(": %q\n", event.EscSeq())) + h.Relocate() +} diff --git a/cmd/micro/action/tab.go b/cmd/micro/action/tab.go index 6b8773e4..2c6ce8ac 100644 --- a/cmd/micro/action/tab.go +++ b/cmd/micro/action/tab.go @@ -160,13 +160,24 @@ func NewTabFromBuffer(x, y, width, height int, b *buffer.Buffer) *Tab { t.Node = views.NewRoot(x, y, width, height) t.UIWindow = display.NewUIWindow(t.Node) - e := NewBufEditPane(x, y, width, height, b) - e.splitID = t.ID() + e := NewBufPaneFromBuf(b) + e.SetID(t.ID()) t.Panes = append(t.Panes, e) return t } +func NewTabFromPane(x, y, width, height int, pane Pane) *Tab { + t := new(Tab) + t.Node = views.NewRoot(x, y, width, height) + t.UIWindow = display.NewUIWindow(t.Node) + + pane.SetID(t.ID()) + + t.Panes = append(t.Panes, pane) + return t +} + // HandleEvent takes a tcell event and usually dispatches it to the current // active pane. However if the event is a resize or a mouse event where the user // is interacting with the UI (resizing splits) then the event is consumed here diff --git a/cmd/micro/action/termhandler.go b/cmd/micro/action/termpane.go similarity index 84% rename from cmd/micro/action/termhandler.go rename to cmd/micro/action/termpane.go index 388377ab..2340b3ae 100644 --- a/cmd/micro/action/termhandler.go +++ b/cmd/micro/action/termpane.go @@ -11,7 +11,7 @@ import ( "github.com/zyedidia/terminal" ) -type TermHandler struct { +type TermPane struct { *shell.Terminal display.Window @@ -19,8 +19,8 @@ type TermHandler struct { id uint64 } -func NewTermHandler(x, y, w, h int, t *shell.Terminal, id uint64) *TermHandler { - th := new(TermHandler) +func NewTermPane(x, y, w, h int, t *shell.Terminal, id uint64) *TermPane { + th := new(TermPane) th.Terminal = t th.id = id th.mouseReleased = true @@ -28,13 +28,17 @@ func NewTermHandler(x, y, w, h int, t *shell.Terminal, id uint64) *TermHandler { return th } -func (t *TermHandler) ID() uint64 { +func (t *TermPane) ID() uint64 { return t.id } -func (t *TermHandler) Close() {} +func (t *TermPane) SetID(i uint64) { + t.id = i +} -func (t *TermHandler) Quit() { +func (t *TermPane) Close() {} + +func (t *TermPane) Quit() { t.Close() if len(MainTab().Panes) > 1 { t.Unsplit() @@ -47,7 +51,7 @@ func (t *TermHandler) Quit() { } } -func (t *TermHandler) Unsplit() { +func (t *TermPane) Unsplit() { n := MainTab().GetNode(t.id) n.Unsplit() @@ -60,7 +64,7 @@ func (t *TermHandler) Unsplit() { // If the event is a mouse event and the program running in the emulator // does not have mouse support, the emulator will support selections and // copy-paste -func (t *TermHandler) HandleEvent(event tcell.Event) { +func (t *TermPane) HandleEvent(event tcell.Event) { if e, ok := event.(*tcell.EventKey); ok { if t.Status == shell.TTDone { switch e.Key() { @@ -107,6 +111,6 @@ func (t *TermHandler) HandleEvent(event tcell.Event) { } } -func (t *TermHandler) HandleCommand(input string) { +func (t *TermPane) HandleCommand(input string) { InfoBar.Error("Commands are unsupported in term for now") } diff --git a/cmd/micro/buffer/buffer.go b/cmd/micro/buffer/buffer.go index d02a6191..3c8672dc 100644 --- a/cmd/micro/buffer/buffer.go +++ b/cmd/micro/buffer/buffer.go @@ -23,8 +23,8 @@ var OpenBuffers []*Buffer // The BufType defines what kind of buffer this is type BufType struct { Kind int - Readonly bool // The file cannot be edited - Scratch bool // The file cannot be saved + Readonly bool // The buffer cannot be edited + Scratch bool // The buffer cannot be saved Syntax bool // Syntax highlighting is enabled } @@ -33,7 +33,7 @@ var ( BTHelp = BufType{1, true, true, true} BTLog = BufType{2, true, true, false} BTScratch = BufType{3, false, true, false} - BTRaw = BufType{4, true, true, false} + BTRaw = BufType{4, false, true, false} BTInfo = BufType{5, false, true, false} ErrFileTooLarge = errors.New("File is too large to hash") @@ -241,15 +241,19 @@ func (b *Buffer) SetName(s string) { } func (b *Buffer) Insert(start Loc, text string) { - b.EventHandler.cursors = b.cursors - b.EventHandler.active = b.curCursor - b.EventHandler.Insert(start, text) + if !b.Type.Readonly { + b.EventHandler.cursors = b.cursors + b.EventHandler.active = b.curCursor + b.EventHandler.Insert(start, text) + } } func (b *Buffer) Remove(start, end Loc) { - b.EventHandler.cursors = b.cursors - b.EventHandler.active = b.curCursor - b.EventHandler.Remove(start, end) + if !b.Type.Readonly { + b.EventHandler.cursors = b.cursors + b.EventHandler.active = b.curCursor + b.EventHandler.Remove(start, end) + } } // FileType returns the buffer's filetype @@ -296,6 +300,10 @@ func (b *Buffer) RuneAt(loc Loc) rune { // Modified returns if this buffer has been modified since // being opened func (b *Buffer) Modified() bool { + if b.Type.Scratch { + return false + } + if b.Settings["fastdirty"].(bool) { return b.isModified } diff --git a/cmd/micro/buffer/save.go b/cmd/micro/buffer/save.go index 4acf484e..1d62818e 100644 --- a/cmd/micro/buffer/save.go +++ b/cmd/micro/buffer/save.go @@ -3,6 +3,7 @@ package buffer import ( "bufio" "bytes" + "errors" "io" "os" "os/exec" @@ -50,6 +51,10 @@ func (b *Buffer) Save() error { // SaveAs saves the buffer to a specified path (filename), creating the file if it does not exist func (b *Buffer) SaveAs(filename string) error { + if b.Type.Scratch { + return errors.New("Cannot save scratch buffer") + } + // TODO: rmtrailingws and updaterules b.UpdateRules() // if b.Settings["rmtrailingws"].(bool) { @@ -158,6 +163,10 @@ func (b *Buffer) SaveWithSudo() error { // 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 { + if b.Type.Scratch { + return errors.New("Cannot save scratch buffer") + } + b.UpdateRules() b.Path = filename absPath, _ := filepath.Abs(filename)