import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Example {
public static void main(String[] args) {
final String regex = "(?x)\n\n"
+ "# Set intent level\n"
+ "(?(DEFINE)(?<indent>[[:space:]]{4}))\n\n"
+ "# Must start at new line\n"
+ "^\n"
+ "# Captures following statement's description comment lines if written\n"
+ "(?<statementDescComment> \n"
+ " (?: \n"
+ " # Repeat below until next line not comment\n"
+ " (?=(?P>indent)\\/)\\V*\\v\n"
+ " )+\n"
+ ")?\n"
+ "# Generic Statement Capture\n"
+ "(?<statement>\n"
+ "# Const declaration capture\n"
+ "(?<const>\n"
+ " (?P>indent)const[[:space:]]*\\([[:space:]]*\n"
+ " \\v\n"
+ " (?:\n"
+ " (?!(?P>indent)\\))\\V*\\v\n"
+ " )*\n"
+ " (?P>indent)\\)\n"
+ ")\n"
+ "|\n"
+ "# Full function declaration capture\n"
+ "(?<func>\n"
+ " # Function declaration initialization\n"
+ " (?<funcDecLine>\n"
+ " (?P>indent)func\\V+\n"
+ " )\\v\n"
+ " # Repeat subcapture until line starting with close bracket\n"
+ " (?:\n"
+ " (?!(?P>indent)\\})\\V*\\v\n"
+ " )*\n"
+ " # Closing bracket\n"
+ " (?<funcCloseBracket>(?P>indent)\\})\n"
+ ")\n"
+ "|\n"
+ "(?<type>\n"
+ " # Type Declaration\n\n"
+ " # Check before wasting time\n"
+ " (?=(?P>indent)type)\n\n"
+ " # Short Form\n"
+ " (?<typeDecShort>\n"
+ " (?P>indent)type\\V+[^\\{]\\v\n"
+ " )\n"
+ " |\n"
+ " # Longer Form (Brackted)\n"
+ " (?<typeDecLong>\n"
+ " (?P>indent)type\\V+\n"
+ " )\\v\n"
+ " # Repeat subcapture until line starting with close bracket\n"
+ " (?:\n"
+ " (?!(?P>indent)\\})\\V*\\v\n"
+ " )*\n"
+ " # Closing bracket\n"
+ " (?<typeCloseBracket>(?P>indent)\\})\n"
+ " )\n"
+ ")";
final String string = " package main\n\n"
+ " import (\n"
+ " \"fmt\"\n"
+ " \"os\"\n"
+ " \"regexp\"\n"
+ " \"strconv\"\n"
+ " \"strings\"\n"
+ " \"time\"\n"
+ " \"unicode/utf8\"\n\n"
+ " \"github.com/yuin/gopher-lua\"\n"
+ " \"github.com/zyedidia/clipboard\"\n"
+ " \"github.com/zyedidia/micro/cmd/micro/shellwords\"\n"
+ " \"github.com/zyedidia/tcell\"\n"
+ " )\n\n"
+ " // PreActionCall executes the lua pre callback if possible\n"
+ " func PreActionCall(funcName string, view *View, args ...interface{}) bool {\n"
+ " executeAction := true\n"
+ " for pl := range loadedPlugins {\n"
+ " ret, err := Call(pl+\".pre\"+funcName, append([]interface{}{view}, args...)...)\n"
+ " if err != nil && !strings.HasPrefix(err.Error(), \"function does not exist\") {\n"
+ " TermMessage(err)\n"
+ " continue\n"
+ " }\n"
+ " if ret == lua.LFalse {\n"
+ " executeAction = false\n"
+ " }\n"
+ " }\n"
+ " return executeAction\n"
+ " }\n\n"
+ " // PostActionCall executes the lua plugin callback if possible\n"
+ " func PostActionCall(funcName string, view *View, args ...interface{}) bool {\n"
+ " relocate := true\n"
+ " for pl := range loadedPlugins {\n"
+ " ret, err := Call(pl+\".on\"+funcName, append([]interface{}{view}, args...)...)\n"
+ " if err != nil && !strings.HasPrefix(err.Error(), \"function does not exist\") {\n"
+ " TermMessage(err)\n"
+ " continue\n"
+ " }\n"
+ " if ret == lua.LFalse {\n"
+ " relocate = false\n"
+ " }\n"
+ " }\n"
+ " return relocate\n"
+ " }\n\n"
+ " func (v *View) deselect(index int) bool {\n"
+ " if v.Cursor.HasSelection() {\n"
+ " v.Cursor.Loc = v.Cursor.CurSelection[index]\n"
+ " v.Cursor.ResetSelection()\n"
+ " v.Cursor.StoreVisualX()\n"
+ " return true\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // MousePress is the event that should happen when a normal click happens\n"
+ " // This is almost always bound to left click\n"
+ " func (v *View) MousePress(usePlugin bool, e *tcell.EventMouse) bool {\n"
+ " if usePlugin && !PreActionCall(\"MousePress\", v, e) {\n"
+ " return false\n"
+ " }\n\n"
+ " x, y := e.Position()\n"
+ " x -= v.lineNumOffset - v.leftCol + v.x\n"
+ " y += v.Topline - v.y\n\n"
+ " // This is usually bound to left click\n"
+ " v.MoveToMouseClick(x, y)\n"
+ " if v.mouseReleased {\n"
+ " if len(v.Buf.cursors) > 1 {\n"
+ " for i := 1; i < len(v.Buf.cursors); i++ {\n"
+ " v.Buf.cursors[i] = nil\n"
+ " }\n"
+ " v.Buf.cursors = v.Buf.cursors[:1]\n"
+ " v.Buf.UpdateCursors()\n"
+ " v.Cursor.ResetSelection()\n"
+ " v.Relocate()\n"
+ " }\n"
+ " if time.Since(v.lastClickTime)/time.Millisecond < doubleClickThreshold && (x == v.lastLoc.X && y == v.lastLoc.Y) {\n"
+ " if v.doubleClick {\n"
+ " // Triple click\n"
+ " v.lastClickTime = time.Now()\n\n"
+ " v.tripleClick = true\n"
+ " v.doubleClick = false\n\n"
+ " v.Cursor.SelectLine()\n"
+ " v.Cursor.CopySelection(\"primary\")\n"
+ " } else {\n"
+ " // Double click\n"
+ " v.lastClickTime = time.Now()\n\n"
+ " v.doubleClick = true\n"
+ " v.tripleClick = false\n\n"
+ " v.Cursor.SelectWord()\n"
+ " v.Cursor.CopySelection(\"primary\")\n"
+ " }\n"
+ " } else {\n"
+ " v.doubleClick = false\n"
+ " v.tripleClick = false\n"
+ " v.lastClickTime = time.Now()\n\n"
+ " v.Cursor.OrigSelection[0] = v.Cursor.Loc\n"
+ " v.Cursor.CurSelection[0] = v.Cursor.Loc\n"
+ " v.Cursor.CurSelection[1] = v.Cursor.Loc\n"
+ " }\n"
+ " v.mouseReleased = false\n"
+ " } else if !v.mouseReleased {\n"
+ " if v.tripleClick {\n"
+ " v.Cursor.AddLineToSelection()\n"
+ " } else if v.doubleClick {\n"
+ " v.Cursor.AddWordToSelection()\n"
+ " } else {\n"
+ " v.Cursor.SetSelectionEnd(v.Cursor.Loc)\n"
+ " v.Cursor.CopySelection(\"primary\")\n"
+ " }\n"
+ " }\n\n"
+ " v.lastLoc = Loc{x, y}\n\n"
+ " if usePlugin {\n"
+ " PostActionCall(\"MousePress\", v, e)\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // ScrollUpAction scrolls the view up\n"
+ " func (v *View) ScrollUpAction(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"ScrollUp\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " scrollspeed := int(v.Buf.Settings[\"scrollspeed\"].(float64))\n"
+ " v.ScrollUp(scrollspeed)\n\n"
+ " if usePlugin {\n"
+ " PostActionCall(\"ScrollUp\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // ScrollDownAction scrolls the view up\n"
+ " func (v *View) ScrollDownAction(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"ScrollDown\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " scrollspeed := int(v.Buf.Settings[\"scrollspeed\"].(float64))\n"
+ " v.ScrollDown(scrollspeed)\n\n"
+ " if usePlugin {\n"
+ " PostActionCall(\"ScrollDown\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // Center centers the view on the cursor\n"
+ " func (v *View) Center(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"Center\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " v.Topline = v.Cursor.Y - v.Height/2\n"
+ " if v.Topline+v.Height > v.Buf.NumLines {\n"
+ " v.Topline = v.Buf.NumLines - v.Height\n"
+ " }\n"
+ " if v.Topline < 0 {\n"
+ " v.Topline = 0\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"Center\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // CursorUp moves the cursor up\n"
+ " func (v *View) CursorUp(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"CursorUp\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " v.deselect(0)\n"
+ " v.Cursor.Up()\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"CursorUp\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // CursorDown moves the cursor down\n"
+ " func (v *View) CursorDown(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"CursorDown\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " v.deselect(1)\n"
+ " v.Cursor.Down()\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"CursorDown\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // CursorLeft moves the cursor left\n"
+ " func (v *View) CursorLeft(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"CursorLeft\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Cursor.HasSelection() {\n"
+ " v.Cursor.Loc = v.Cursor.CurSelection[0]\n"
+ " v.Cursor.ResetSelection()\n"
+ " v.Cursor.StoreVisualX()\n"
+ " } else {\n"
+ " tabstospaces := v.Buf.Settings[\"tabstospaces\"].(bool)\n"
+ " tabmovement := v.Buf.Settings[\"tabmovement\"].(bool)\n"
+ " if tabstospaces && tabmovement {\n"
+ " tabsize := int(v.Buf.Settings[\"tabsize\"].(float64))\n"
+ " line := v.Buf.Line(v.Cursor.Y)\n"
+ " if v.Cursor.X-tabsize >= 0 && line[v.Cursor.X-tabsize:v.Cursor.X] == Spaces(tabsize) && IsStrWhitespace(line[0:v.Cursor.X-tabsize]) {\n"
+ " for i := 0; i < tabsize; i++ {\n"
+ " v.Cursor.Left()\n"
+ " }\n"
+ " } else {\n"
+ " v.Cursor.Left()\n"
+ " }\n"
+ " } else {\n"
+ " v.Cursor.Left()\n"
+ " }\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"CursorLeft\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // CursorRight moves the cursor right\n"
+ " func (v *View) CursorRight(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"CursorRight\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Cursor.HasSelection() {\n"
+ " v.Cursor.Loc = v.Cursor.CurSelection[1]\n"
+ " v.Cursor.ResetSelection()\n"
+ " v.Cursor.StoreVisualX()\n"
+ " } else {\n"
+ " tabstospaces := v.Buf.Settings[\"tabstospaces\"].(bool)\n"
+ " tabmovement := v.Buf.Settings[\"tabmovement\"].(bool)\n"
+ " if tabstospaces && tabmovement {\n"
+ " tabsize := int(v.Buf.Settings[\"tabsize\"].(float64))\n"
+ " line := v.Buf.Line(v.Cursor.Y)\n"
+ " if v.Cursor.X+tabsize < Count(line) && line[v.Cursor.X:v.Cursor.X+tabsize] == Spaces(tabsize) && IsStrWhitespace(line[0:v.Cursor.X]) {\n"
+ " for i := 0; i < tabsize; i++ {\n"
+ " v.Cursor.Right()\n"
+ " }\n"
+ " } else {\n"
+ " v.Cursor.Right()\n"
+ " }\n"
+ " } else {\n"
+ " v.Cursor.Right()\n"
+ " }\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"CursorRight\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // WordRight moves the cursor one word to the right\n"
+ " func (v *View) WordRight(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"WordRight\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " v.Cursor.WordRight()\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"WordRight\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // WordLeft moves the cursor one word to the left\n"
+ " func (v *View) WordLeft(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"WordLeft\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " v.Cursor.WordLeft()\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"WordLeft\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // SelectUp selects up one line\n"
+ " func (v *View) SelectUp(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"SelectUp\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if !v.Cursor.HasSelection() {\n"
+ " v.Cursor.OrigSelection[0] = v.Cursor.Loc\n"
+ " }\n"
+ " v.Cursor.Up()\n"
+ " v.Cursor.SelectTo(v.Cursor.Loc)\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"SelectUp\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // SelectDown selects down one line\n"
+ " func (v *View) SelectDown(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"SelectDown\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if !v.Cursor.HasSelection() {\n"
+ " v.Cursor.OrigSelection[0] = v.Cursor.Loc\n"
+ " }\n"
+ " v.Cursor.Down()\n"
+ " v.Cursor.SelectTo(v.Cursor.Loc)\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"SelectDown\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // SelectLeft selects the character to the left of the cursor\n"
+ " func (v *View) SelectLeft(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"SelectLeft\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " loc := v.Cursor.Loc\n"
+ " count := v.Buf.End()\n"
+ " if loc.GreaterThan(count) {\n"
+ " loc = count\n"
+ " }\n"
+ " if !v.Cursor.HasSelection() {\n"
+ " v.Cursor.OrigSelection[0] = loc\n"
+ " }\n"
+ " v.Cursor.Left()\n"
+ " v.Cursor.SelectTo(v.Cursor.Loc)\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"SelectLeft\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // SelectRight selects the character to the right of the cursor\n"
+ " func (v *View) SelectRight(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"SelectRight\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " loc := v.Cursor.Loc\n"
+ " count := v.Buf.End()\n"
+ " if loc.GreaterThan(count) {\n"
+ " loc = count\n"
+ " }\n"
+ " if !v.Cursor.HasSelection() {\n"
+ " v.Cursor.OrigSelection[0] = loc\n"
+ " }\n"
+ " v.Cursor.Right()\n"
+ " v.Cursor.SelectTo(v.Cursor.Loc)\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"SelectRight\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // SelectWordRight selects the word to the right of the cursor\n"
+ " func (v *View) SelectWordRight(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"SelectWordRight\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if !v.Cursor.HasSelection() {\n"
+ " v.Cursor.OrigSelection[0] = v.Cursor.Loc\n"
+ " }\n"
+ " v.Cursor.WordRight()\n"
+ " v.Cursor.SelectTo(v.Cursor.Loc)\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"SelectWordRight\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // SelectWordLeft selects the word to the left of the cursor\n"
+ " func (v *View) SelectWordLeft(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"SelectWordLeft\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if !v.Cursor.HasSelection() {\n"
+ " v.Cursor.OrigSelection[0] = v.Cursor.Loc\n"
+ " }\n"
+ " v.Cursor.WordLeft()\n"
+ " v.Cursor.SelectTo(v.Cursor.Loc)\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"SelectWordLeft\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // StartOfLine moves the cursor to the start of the line\n"
+ " func (v *View) StartOfLine(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"StartOfLine\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " v.deselect(0)\n\n"
+ " if v.Cursor.X != 0 {\n"
+ " v.Cursor.Start()\n"
+ " } else {\n"
+ " v.Cursor.StartOfText()\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"StartOfLine\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // EndOfLine moves the cursor to the end of the line\n"
+ " func (v *View) EndOfLine(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"EndOfLine\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " v.deselect(0)\n\n"
+ " v.Cursor.End()\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"EndOfLine\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // SelectLine selects the entire current line\n"
+ " func (v *View) SelectLine(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"SelectLine\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " v.Cursor.SelectLine()\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"SelectLine\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // SelectToStartOfLine selects to the start of the current line\n"
+ " func (v *View) SelectToStartOfLine(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"SelectToStartOfLine\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if !v.Cursor.HasSelection() {\n"
+ " v.Cursor.OrigSelection[0] = v.Cursor.Loc\n"
+ " }\n"
+ " v.Cursor.Start()\n"
+ " v.Cursor.SelectTo(v.Cursor.Loc)\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"SelectToStartOfLine\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // SelectToEndOfLine selects to the end of the current line\n"
+ " func (v *View) SelectToEndOfLine(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"SelectToEndOfLine\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if !v.Cursor.HasSelection() {\n"
+ " v.Cursor.OrigSelection[0] = v.Cursor.Loc\n"
+ " }\n"
+ " v.Cursor.End()\n"
+ " v.Cursor.SelectTo(v.Cursor.Loc)\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"SelectToEndOfLine\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // ParagraphPrevious moves the cursor to the previous empty line, or beginning of the buffer if there's none\n"
+ " func (v *View) ParagraphPrevious(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"ParagraphPrevious\", v) {\n"
+ " return false\n"
+ " }\n"
+ " var line int\n"
+ " for line = v.Cursor.Y; line > 0; line-- {\n"
+ " if len(v.Buf.lines[line].data) == 0 && line != v.Cursor.Y {\n"
+ " v.Cursor.X = 0\n"
+ " v.Cursor.Y = line\n"
+ " break\n"
+ " }\n"
+ " }\n"
+ " // If no empty line found. move cursor to end of buffer\n"
+ " if line == 0 {\n"
+ " v.Cursor.Loc = v.Buf.Start()\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"ParagraphPrevious\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // ParagraphNext moves the cursor to the next empty line, or end of the buffer if there's none\n"
+ " func (v *View) ParagraphNext(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"ParagraphNext\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " var line int\n"
+ " for line = v.Cursor.Y; line < len(v.Buf.lines); line++ {\n"
+ " if len(v.Buf.lines[line].data) == 0 && line != v.Cursor.Y {\n"
+ " v.Cursor.X = 0\n"
+ " v.Cursor.Y = line\n"
+ " break\n"
+ " }\n"
+ " }\n"
+ " // If no empty line found. move cursor to end of buffer\n"
+ " if line == len(v.Buf.lines) {\n"
+ " v.Cursor.Loc = v.Buf.End()\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"ParagraphNext\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // Retab changes all tabs to spaces or all spaces to tabs depending\n"
+ " // on the user's settings\n"
+ " func (v *View) Retab(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"Retab\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " toSpaces := v.Buf.Settings[\"tabstospaces\"].(bool)\n"
+ " tabsize := int(v.Buf.Settings[\"tabsize\"].(float64))\n"
+ " dirty := false\n\n"
+ " for i := 0; i < v.Buf.NumLines; i++ {\n"
+ " l := v.Buf.Line(i)\n\n"
+ " ws := GetLeadingWhitespace(l)\n"
+ " if ws != \"\" {\n"
+ " if toSpaces {\n"
+ " ws = strings.Replace(ws, \"\\t\", Spaces(tabsize), -1)\n"
+ " } else {\n"
+ " ws = strings.Replace(ws, Spaces(tabsize), \"\\t\", -1)\n"
+ " }\n"
+ " }\n\n"
+ " l = strings.TrimLeft(l, \" \\t\")\n"
+ " v.Buf.lines[i].data = []byte(ws + l)\n"
+ " dirty = true\n"
+ " }\n\n"
+ " v.Buf.IsModified = dirty\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"Retab\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // CursorStart moves the cursor to the start of the buffer\n"
+ " func (v *View) CursorStart(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"CursorStart\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " v.deselect(0)\n\n"
+ " v.Cursor.X = 0\n"
+ " v.Cursor.Y = 0\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"CursorStart\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // CursorEnd moves the cursor to the end of the buffer\n"
+ " func (v *View) CursorEnd(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"CursorEnd\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " v.deselect(0)\n\n"
+ " v.Cursor.Loc = v.Buf.End()\n"
+ " v.Cursor.StoreVisualX()\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"CursorEnd\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // SelectToStart selects the text from the cursor to the start of the buffer\n"
+ " func (v *View) SelectToStart(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"SelectToStart\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if !v.Cursor.HasSelection() {\n"
+ " v.Cursor.OrigSelection[0] = v.Cursor.Loc\n"
+ " }\n"
+ " v.CursorStart(false)\n"
+ " v.Cursor.SelectTo(v.Buf.Start())\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"SelectToStart\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // SelectToEnd selects the text from the cursor to the end of the buffer\n"
+ " func (v *View) SelectToEnd(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"SelectToEnd\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if !v.Cursor.HasSelection() {\n"
+ " v.Cursor.OrigSelection[0] = v.Cursor.Loc\n"
+ " }\n"
+ " v.CursorEnd(false)\n"
+ " v.Cursor.SelectTo(v.Buf.End())\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"SelectToEnd\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // InsertSpace inserts a space\n"
+ " func (v *View) InsertSpace(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"InsertSpace\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Cursor.HasSelection() {\n"
+ " v.Cursor.DeleteSelection()\n"
+ " v.Cursor.ResetSelection()\n"
+ " }\n"
+ " v.Buf.Insert(v.Cursor.Loc, \" \")\n"
+ " // v.Cursor.Right()\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"InsertSpace\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // InsertNewline inserts a newline plus possible some whitespace if autoindent is on\n"
+ " func (v *View) InsertNewline(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"InsertNewline\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " // Insert a newline\n"
+ " if v.Cursor.HasSelection() {\n"
+ " v.Cursor.DeleteSelection()\n"
+ " v.Cursor.ResetSelection()\n"
+ " }\n\n"
+ " ws := GetLeadingWhitespace(v.Buf.Line(v.Cursor.Y))\n"
+ " cx := v.Cursor.X\n"
+ " v.Buf.Insert(v.Cursor.Loc, \"\\n\")\n"
+ " // v.Cursor.Right()\n\n"
+ " if v.Buf.Settings[\"autoindent\"].(bool) {\n"
+ " if cx < len(ws) {\n"
+ " ws = ws[0:cx]\n"
+ " }\n"
+ " v.Buf.Insert(v.Cursor.Loc, ws)\n"
+ " // for i := 0; i < len(ws); i++ {\n"
+ " // v.Cursor.Right()\n"
+ " // }\n\n"
+ " // Remove the whitespaces if keepautoindent setting is off\n"
+ " if IsSpacesOrTabs(v.Buf.Line(v.Cursor.Y-1)) && !v.Buf.Settings[\"keepautoindent\"].(bool) {\n"
+ " line := v.Buf.Line(v.Cursor.Y - 1)\n"
+ " v.Buf.Remove(Loc{0, v.Cursor.Y - 1}, Loc{Count(line), v.Cursor.Y - 1})\n"
+ " }\n"
+ " }\n"
+ " v.Cursor.LastVisualX = v.Cursor.GetVisualX()\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"InsertNewline\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // Backspace deletes the previous character\n"
+ " func (v *View) Backspace(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"Backspace\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " // Delete a character\n"
+ " if v.Cursor.HasSelection() {\n"
+ " v.Cursor.DeleteSelection()\n"
+ " v.Cursor.ResetSelection()\n"
+ " } else if v.Cursor.Loc.GreaterThan(v.Buf.Start()) {\n"
+ " // We have to do something a bit hacky here because we want to\n"
+ " // delete the line by first moving left and then deleting backwards\n"
+ " // but the undo redo would place the cursor in the wrong place\n"
+ " // So instead we move left, save the position, move back, delete\n"
+ " // and restore the position\n\n"
+ " // If the user is using spaces instead of tabs and they are deleting\n"
+ " // whitespace at the start of the line, we should delete as if it's a\n"
+ " // tab (tabSize number of spaces)\n"
+ " lineStart := sliceEnd(v.Buf.LineBytes(v.Cursor.Y), v.Cursor.X)\n"
+ " tabSize := int(v.Buf.Settings[\"tabsize\"].(float64))\n"
+ " if v.Buf.Settings[\"tabstospaces\"].(bool) && IsSpaces(lineStart) && utf8.RuneCount(lineStart) != 0 && utf8.RuneCount(lineStart)%tabSize == 0 {\n"
+ " loc := v.Cursor.Loc\n"
+ " v.Buf.Remove(loc.Move(-tabSize, v.Buf), loc)\n"
+ " } else {\n"
+ " loc := v.Cursor.Loc\n"
+ " v.Buf.Remove(loc.Move(-1, v.Buf), loc)\n"
+ " }\n"
+ " }\n"
+ " v.Cursor.LastVisualX = v.Cursor.GetVisualX()\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"Backspace\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // DeleteWordRight deletes the word to the right of the cursor\n"
+ " func (v *View) DeleteWordRight(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"DeleteWordRight\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " v.SelectWordRight(false)\n"
+ " if v.Cursor.HasSelection() {\n"
+ " v.Cursor.DeleteSelection()\n"
+ " v.Cursor.ResetSelection()\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"DeleteWordRight\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // DeleteWordLeft deletes the word to the left of the cursor\n"
+ " func (v *View) DeleteWordLeft(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"DeleteWordLeft\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " v.SelectWordLeft(false)\n"
+ " if v.Cursor.HasSelection() {\n"
+ " v.Cursor.DeleteSelection()\n"
+ " v.Cursor.ResetSelection()\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"DeleteWordLeft\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // Delete deletes the next character\n"
+ " func (v *View) Delete(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"Delete\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Cursor.HasSelection() {\n"
+ " v.Cursor.DeleteSelection()\n"
+ " v.Cursor.ResetSelection()\n"
+ " } else {\n"
+ " loc := v.Cursor.Loc\n"
+ " if loc.LessThan(v.Buf.End()) {\n"
+ " v.Buf.Remove(loc, loc.Move(1, v.Buf))\n"
+ " }\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"Delete\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // IndentSelection indents the current selection\n"
+ " func (v *View) IndentSelection(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"IndentSelection\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Cursor.HasSelection() {\n"
+ " start := v.Cursor.CurSelection[0]\n"
+ " end := v.Cursor.CurSelection[1]\n"
+ " if end.Y < start.Y {\n"
+ " start, end = end, start\n"
+ " v.Cursor.SetSelectionStart(start)\n"
+ " v.Cursor.SetSelectionEnd(end)\n"
+ " }\n\n"
+ " startY := start.Y\n"
+ " endY := end.Move(-1, v.Buf).Y\n"
+ " endX := end.Move(-1, v.Buf).X\n"
+ " tabsize := len(v.Buf.IndentString())\n"
+ " for y := startY; y <= endY; y++ {\n"
+ " v.Buf.Insert(Loc{0, y}, v.Buf.IndentString())\n"
+ " if y == startY && start.X > 0 {\n"
+ " v.Cursor.SetSelectionStart(start.Move(tabsize, v.Buf))\n"
+ " }\n"
+ " if y == endY {\n"
+ " v.Cursor.SetSelectionEnd(Loc{endX + tabsize + 1, endY})\n"
+ " }\n"
+ " }\n"
+ " v.Cursor.Relocate()\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"IndentSelection\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // OutdentLine moves the current line back one indentation\n"
+ " func (v *View) OutdentLine(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"OutdentLine\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Cursor.HasSelection() {\n"
+ " return false\n"
+ " }\n\n"
+ " for x := 0; x < len(v.Buf.IndentString()); x++ {\n"
+ " if len(GetLeadingWhitespace(v.Buf.Line(v.Cursor.Y))) == 0 {\n"
+ " break\n"
+ " }\n"
+ " v.Buf.Remove(Loc{0, v.Cursor.Y}, Loc{1, v.Cursor.Y})\n"
+ " }\n"
+ " v.Cursor.Relocate()\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"OutdentLine\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // OutdentSelection takes the current selection and moves it back one indent level\n"
+ " func (v *View) OutdentSelection(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"OutdentSelection\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Cursor.HasSelection() {\n"
+ " start := v.Cursor.CurSelection[0]\n"
+ " end := v.Cursor.CurSelection[1]\n"
+ " if end.Y < start.Y {\n"
+ " start, end = end, start\n"
+ " v.Cursor.SetSelectionStart(start)\n"
+ " v.Cursor.SetSelectionEnd(end)\n"
+ " }\n\n"
+ " startY := start.Y\n"
+ " endY := end.Move(-1, v.Buf).Y\n"
+ " for y := startY; y <= endY; y++ {\n"
+ " for x := 0; x < len(v.Buf.IndentString()); x++ {\n"
+ " if len(GetLeadingWhitespace(v.Buf.Line(y))) == 0 {\n"
+ " break\n"
+ " }\n"
+ " v.Buf.Remove(Loc{0, y}, Loc{1, y})\n"
+ " }\n"
+ " }\n"
+ " v.Cursor.Relocate()\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"OutdentSelection\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // InsertTab inserts a tab or spaces\n"
+ " func (v *View) InsertTab(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"InsertTab\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Cursor.HasSelection() {\n"
+ " return false\n"
+ " }\n\n"
+ " tabBytes := len(v.Buf.IndentString())\n"
+ " bytesUntilIndent := tabBytes - (v.Cursor.GetVisualX() % tabBytes)\n"
+ " v.Buf.Insert(v.Cursor.Loc, v.Buf.IndentString()[:bytesUntilIndent])\n"
+ " // for i := 0; i < bytesUntilIndent; i++ {\n"
+ " // v.Cursor.Right()\n"
+ " // }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"InsertTab\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // SaveAll saves all open buffers\n"
+ " func (v *View) SaveAll(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"SaveAll\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " for _, t := range tabs {\n"
+ " for _, v := range t.Views {\n"
+ " v.Save(false)\n"
+ " }\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"SaveAll\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // Save the buffer to disk\n"
+ " func (v *View) Save(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"Save\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Type.Scratch == true {\n"
+ " // We can't save any view type with scratch set. eg help and log text\n"
+ " return false\n"
+ " }\n"
+ " // If this is an empty buffer, ask for a filename\n"
+ " if v.Buf.Path == \"\" {\n"
+ " v.SaveAs(false)\n"
+ " } else {\n"
+ " v.saveToFile(v.Buf.Path)\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"Save\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // This function saves the buffer to `filename` and changes the buffer's path and name\n"
+ " // to `filename` if the save is successful\n"
+ " func (v *View) saveToFile(filename string) {\n"
+ " err := v.Buf.SaveAs(filename)\n"
+ " if err != nil {\n"
+ " if strings.HasSuffix(err.Error(), \"permission denied\") {\n"
+ " choice, _ := messenger.YesNoPrompt(\"Permission denied. Do you want to save this file using sudo? (y,n)\")\n"
+ " if choice {\n"
+ " err = v.Buf.SaveAsWithSudo(filename)\n"
+ " if err != nil {\n"
+ " messenger.Error(err.Error())\n"
+ " } else {\n"
+ " v.Buf.Path = filename\n"
+ " v.Buf.name = filename\n"
+ " messenger.Message(\"Saved \" + filename)\n"
+ " }\n"
+ " }\n"
+ " messenger.Reset()\n"
+ " messenger.Clear()\n"
+ " } else {\n"
+ " messenger.Error(err.Error())\n"
+ " }\n"
+ " } else {\n"
+ " v.Buf.Path = filename\n"
+ " v.Buf.name = filename\n"
+ " messenger.Message(\"Saved \" + filename)\n"
+ " }\n"
+ " }\n\n"
+ " // SaveAs saves the buffer to disk with the given name\n"
+ " func (v *View) SaveAs(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"SaveAs\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " filename, canceled := messenger.Prompt(\"Filename: \", \"\", \"Save\", NoCompletion)\n"
+ " if !canceled {\n"
+ " // the filename might or might not be quoted, so unquote first then join the strings.\n"
+ " args, err := shellwords.Split(filename)\n"
+ " filename = strings.Join(args, \" \")\n"
+ " if err != nil {\n"
+ " messenger.Error(\"Error parsing arguments: \", err)\n"
+ " return false\n"
+ " }\n"
+ " v.saveToFile(filename)\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " PostActionCall(\"SaveAs\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // Find opens a prompt and searches forward for the input\n"
+ " func (v *View) Find(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"Find\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " searchStr := \"\"\n"
+ " if v.Cursor.HasSelection() {\n"
+ " searchStart = v.Cursor.CurSelection[1]\n"
+ " searchStart = v.Cursor.CurSelection[1]\n"
+ " searchStr = v.Cursor.GetSelection()\n"
+ " } else {\n"
+ " searchStart = v.Cursor.Loc\n"
+ " }\n"
+ " BeginSearch(searchStr)\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"Find\", v)\n"
+ " }\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // FindNext searches forwards for the last used search term\n"
+ " func (v *View) FindNext(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"FindNext\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Cursor.HasSelection() {\n"
+ " searchStart = v.Cursor.CurSelection[1]\n"
+ " // lastSearch = v.Cursor.GetSelection()\n"
+ " } else {\n"
+ " searchStart = v.Cursor.Loc\n"
+ " }\n"
+ " if lastSearch == \"\" {\n"
+ " return true\n"
+ " }\n"
+ " messenger.Message(\"Finding: \" + lastSearch)\n"
+ " Search(lastSearch, v, true)\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"FindNext\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // FindPrevious searches backwards for the last used search term\n"
+ " func (v *View) FindPrevious(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"FindPrevious\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Cursor.HasSelection() {\n"
+ " searchStart = v.Cursor.CurSelection[0]\n"
+ " } else {\n"
+ " searchStart = v.Cursor.Loc\n"
+ " }\n"
+ " messenger.Message(\"Finding: \" + lastSearch)\n"
+ " Search(lastSearch, v, false)\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"FindPrevious\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // Undo undoes the last action\n"
+ " func (v *View) Undo(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"Undo\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Buf.curCursor == 0 {\n"
+ " v.Buf.clearCursors()\n"
+ " }\n\n"
+ " v.Buf.Undo()\n"
+ " messenger.Message(\"Undid action\")\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"Undo\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // Redo redoes the last action\n"
+ " func (v *View) Redo(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"Redo\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Buf.curCursor == 0 {\n"
+ " v.Buf.clearCursors()\n"
+ " }\n\n"
+ " v.Buf.Redo()\n"
+ " messenger.Message(\"Redid action\")\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"Redo\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // Copy the selection to the system clipboard\n"
+ " func (v *View) Copy(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"Copy\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Cursor.HasSelection() {\n"
+ " v.Cursor.CopySelection(\"clipboard\")\n"
+ " v.freshClip = true\n"
+ " messenger.Message(\"Copied selection\")\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"Copy\", v)\n"
+ " }\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // CutLine cuts the current line to the clipboard\n"
+ " func (v *View) CutLine(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"CutLine\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " v.Cursor.SelectLine()\n"
+ " if !v.Cursor.HasSelection() {\n"
+ " return false\n"
+ " }\n"
+ " if v.freshClip == true {\n"
+ " if v.Cursor.HasSelection() {\n"
+ " if clip, err := clipboard.ReadAll(\"clipboard\"); err != nil {\n"
+ " messenger.Error(err)\n"
+ " } else {\n"
+ " clipboard.WriteAll(clip+v.Cursor.GetSelection(), \"clipboard\")\n"
+ " }\n"
+ " }\n"
+ " } else if time.Since(v.lastCutTime)/time.Second > 10*time.Second || v.freshClip == false {\n"
+ " v.Copy(true)\n"
+ " }\n"
+ " v.freshClip = true\n"
+ " v.lastCutTime = time.Now()\n"
+ " v.Cursor.DeleteSelection()\n"
+ " v.Cursor.ResetSelection()\n"
+ " messenger.Message(\"Cut line\")\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"CutLine\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // Cut the selection to the system clipboard\n"
+ " func (v *View) Cut(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"Cut\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Cursor.HasSelection() {\n"
+ " v.Cursor.CopySelection(\"clipboard\")\n"
+ " v.Cursor.DeleteSelection()\n"
+ " v.Cursor.ResetSelection()\n"
+ " v.freshClip = true\n"
+ " messenger.Message(\"Cut selection\")\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"Cut\", v)\n"
+ " }\n"
+ " return true\n"
+ " } else {\n"
+ " return v.CutLine(usePlugin)\n"
+ " }\n"
+ " }\n\n"
+ " // DuplicateLine duplicates the current line or selection\n"
+ " func (v *View) DuplicateLine(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"DuplicateLine\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Cursor.HasSelection() {\n"
+ " v.Buf.Insert(v.Cursor.CurSelection[1], v.Cursor.GetSelection())\n"
+ " } else {\n"
+ " v.Cursor.End()\n"
+ " v.Buf.Insert(v.Cursor.Loc, \"\\n\"+v.Buf.Line(v.Cursor.Y))\n"
+ " // v.Cursor.Right()\n"
+ " }\n\n"
+ " messenger.Message(\"Duplicated line\")\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"DuplicateLine\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // DeleteLine deletes the current line\n"
+ " func (v *View) DeleteLine(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"DeleteLine\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " v.Cursor.SelectLine()\n"
+ " if !v.Cursor.HasSelection() {\n"
+ " return false\n"
+ " }\n"
+ " v.Cursor.DeleteSelection()\n"
+ " v.Cursor.ResetSelection()\n"
+ " messenger.Message(\"Deleted line\")\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"DeleteLine\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // MoveLinesUp moves up the current line or selected lines if any\n"
+ " func (v *View) MoveLinesUp(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"MoveLinesUp\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Cursor.HasSelection() {\n"
+ " if v.Cursor.CurSelection[0].Y == 0 {\n"
+ " messenger.Message(\"Can not move further up\")\n"
+ " return true\n"
+ " }\n"
+ " start := v.Cursor.CurSelection[0].Y\n"
+ " end := v.Cursor.CurSelection[1].Y\n"
+ " if start > end {\n"
+ " end, start = start, end\n"
+ " }\n\n"
+ " v.Buf.MoveLinesUp(\n"
+ " start,\n"
+ " end,\n"
+ " )\n"
+ " v.Cursor.CurSelection[1].Y -= 1\n"
+ " messenger.Message(\"Moved up selected line(s)\")\n"
+ " } else {\n"
+ " if v.Cursor.Loc.Y == 0 {\n"
+ " messenger.Message(\"Can not move further up\")\n"
+ " return true\n"
+ " }\n"
+ " v.Buf.MoveLinesUp(\n"
+ " v.Cursor.Loc.Y,\n"
+ " v.Cursor.Loc.Y+1,\n"
+ " )\n"
+ " messenger.Message(\"Moved up current line\")\n"
+ " }\n"
+ " v.Buf.IsModified = true\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"MoveLinesUp\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // MoveLinesDown moves down the current line or selected lines if any\n"
+ " func (v *View) MoveLinesDown(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"MoveLinesDown\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Cursor.HasSelection() {\n"
+ " if v.Cursor.CurSelection[1].Y >= len(v.Buf.lines) {\n"
+ " messenger.Message(\"Can not move further down\")\n"
+ " return true\n"
+ " }\n"
+ " start := v.Cursor.CurSelection[0].Y\n"
+ " end := v.Cursor.CurSelection[1].Y\n"
+ " if start > end {\n"
+ " end, start = start, end\n"
+ " }\n\n"
+ " v.Buf.MoveLinesDown(\n"
+ " start,\n"
+ " end,\n"
+ " )\n"
+ " messenger.Message(\"Moved down selected line(s)\")\n"
+ " } else {\n"
+ " if v.Cursor.Loc.Y >= len(v.Buf.lines)-1 {\n"
+ " messenger.Message(\"Can not move further down\")\n"
+ " return true\n"
+ " }\n"
+ " v.Buf.MoveLinesDown(\n"
+ " v.Cursor.Loc.Y,\n"
+ " v.Cursor.Loc.Y+1,\n"
+ " )\n"
+ " messenger.Message(\"Moved down current line\")\n"
+ " }\n"
+ " v.Buf.IsModified = true\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"MoveLinesDown\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // Paste whatever is in the system clipboard into the buffer\n"
+ " // Delete and paste if the user has a selection\n"
+ " func (v *View) Paste(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"Paste\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " clip, _ := clipboard.ReadAll(\"clipboard\")\n"
+ " v.paste(clip)\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"Paste\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // PastePrimary pastes from the primary clipboard (only use on linux)\n"
+ " func (v *View) PastePrimary(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"Paste\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " clip, _ := clipboard.ReadAll(\"primary\")\n"
+ " v.paste(clip)\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"Paste\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // JumpToMatchingBrace moves the cursor to the matching brace if it is\n"
+ " // currently on a brace\n"
+ " func (v *View) JumpToMatchingBrace(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"JumpToMatchingBrace\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " for _, bp := range bracePairs {\n"
+ " r := v.Cursor.RuneUnder(v.Cursor.X)\n"
+ " if r == bp[0] || r == bp[1] {\n"
+ " matchingBrace := v.Buf.FindMatchingBrace(bp, v.Cursor.Loc)\n"
+ " v.Cursor.GotoLoc(matchingBrace)\n"
+ " }\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"JumpToMatchingBrace\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // SelectAll selects the entire buffer\n"
+ " func (v *View) SelectAll(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"SelectAll\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " v.Cursor.SetSelectionStart(v.Buf.Start())\n"
+ " v.Cursor.SetSelectionEnd(v.Buf.End())\n"
+ " // Put the cursor at the beginning\n"
+ " v.Cursor.X = 0\n"
+ " v.Cursor.Y = 0\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"SelectAll\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // OpenFile opens a new file in the buffer\n"
+ " func (v *View) OpenFile(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"OpenFile\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.CanClose() {\n"
+ " input, canceled := messenger.Prompt(\"> \", \"open \", \"Open\", CommandCompletion)\n"
+ " if !canceled {\n"
+ " HandleCommand(input)\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"OpenFile\", v)\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // Start moves the viewport to the start of the buffer\n"
+ " func (v *View) Start(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"Start\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " v.Topline = 0\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"Start\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // End moves the viewport to the end of the buffer\n"
+ " func (v *View) End(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"End\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Height > v.Buf.NumLines {\n"
+ " v.Topline = 0\n"
+ " } else {\n"
+ " v.Topline = v.Buf.NumLines - v.Height\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"End\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // PageUp scrolls the view up a page\n"
+ " func (v *View) PageUp(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"PageUp\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Topline > v.Height {\n"
+ " v.ScrollUp(v.Height)\n"
+ " } else {\n"
+ " v.Topline = 0\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"PageUp\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // PageDown scrolls the view down a page\n"
+ " func (v *View) PageDown(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"PageDown\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Buf.NumLines-(v.Topline+v.Height) > v.Height {\n"
+ " v.ScrollDown(v.Height)\n"
+ " } else if v.Buf.NumLines >= v.Height {\n"
+ " v.Topline = v.Buf.NumLines - v.Height\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"PageDown\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // SelectPageUp selects up one page\n"
+ " func (v *View) SelectPageUp(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"SelectPageUp\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if !v.Cursor.HasSelection() {\n"
+ " v.Cursor.OrigSelection[0] = v.Cursor.Loc\n"
+ " }\n"
+ " v.Cursor.UpN(v.Height)\n"
+ " v.Cursor.SelectTo(v.Cursor.Loc)\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"SelectPageUp\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // SelectPageDown selects down one page\n"
+ " func (v *View) SelectPageDown(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"SelectPageDown\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if !v.Cursor.HasSelection() {\n"
+ " v.Cursor.OrigSelection[0] = v.Cursor.Loc\n"
+ " }\n"
+ " v.Cursor.DownN(v.Height)\n"
+ " v.Cursor.SelectTo(v.Cursor.Loc)\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"SelectPageDown\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // CursorPageUp places the cursor a page up\n"
+ " func (v *View) CursorPageUp(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"CursorPageUp\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " v.deselect(0)\n\n"
+ " if v.Cursor.HasSelection() {\n"
+ " v.Cursor.Loc = v.Cursor.CurSelection[0]\n"
+ " v.Cursor.ResetSelection()\n"
+ " v.Cursor.StoreVisualX()\n"
+ " }\n"
+ " v.Cursor.UpN(v.Height)\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"CursorPageUp\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // CursorPageDown places the cursor a page up\n"
+ " func (v *View) CursorPageDown(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"CursorPageDown\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " v.deselect(0)\n\n"
+ " if v.Cursor.HasSelection() {\n"
+ " v.Cursor.Loc = v.Cursor.CurSelection[1]\n"
+ " v.Cursor.ResetSelection()\n"
+ " v.Cursor.StoreVisualX()\n"
+ " }\n"
+ " v.Cursor.DownN(v.Height)\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"CursorPageDown\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // HalfPageUp scrolls the view up half a page\n"
+ " func (v *View) HalfPageUp(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"HalfPageUp\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Topline > v.Height/2 {\n"
+ " v.ScrollUp(v.Height / 2)\n"
+ " } else {\n"
+ " v.Topline = 0\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"HalfPageUp\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // HalfPageDown scrolls the view down half a page\n"
+ " func (v *View) HalfPageDown(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"HalfPageDown\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Buf.NumLines-(v.Topline+v.Height) > v.Height/2 {\n"
+ " v.ScrollDown(v.Height / 2)\n"
+ " } else {\n"
+ " if v.Buf.NumLines >= v.Height {\n"
+ " v.Topline = v.Buf.NumLines - v.Height\n"
+ " }\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"HalfPageDown\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // ToggleRuler turns line numbers off and on\n"
+ " func (v *View) ToggleRuler(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"ToggleRuler\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Buf.Settings[\"ruler\"] == false {\n"
+ " v.Buf.Settings[\"ruler\"] = true\n"
+ " messenger.Message(\"Enabled ruler\")\n"
+ " } else {\n"
+ " v.Buf.Settings[\"ruler\"] = false\n"
+ " messenger.Message(\"Disabled ruler\")\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"ToggleRuler\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // JumpLine jumps to a line and moves the view accordingly.\n"
+ " func (v *View) JumpLine(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"JumpLine\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " // Prompt for line number\n"
+ " message := fmt.Sprintf(\"Jump to line:col (1 - %v) # \", v.Buf.NumLines)\n"
+ " input, canceled := messenger.Prompt(message, \"\", \"LineNumber\", NoCompletion)\n"
+ " if canceled {\n"
+ " return false\n"
+ " }\n"
+ " var lineInt int\n"
+ " var colInt int\n"
+ " var err error\n"
+ " if strings.Contains(input, \":\") {\n"
+ " split := strings.Split(input, \":\")\n"
+ " lineInt, err = strconv.Atoi(split[0])\n"
+ " if err != nil {\n"
+ " messenger.Message(\"Invalid line number\")\n"
+ " return false\n"
+ " }\n"
+ " colInt, err = strconv.Atoi(split[1])\n"
+ " if err != nil {\n"
+ " messenger.Message(\"Invalid column number\")\n"
+ " return false\n"
+ " }\n"
+ " } else {\n"
+ " lineInt, err = strconv.Atoi(input)\n"
+ " if err != nil {\n"
+ " messenger.Message(\"Invalid line number\")\n"
+ " return false\n"
+ " }\n"
+ " }\n"
+ " lineInt--\n"
+ " // Move cursor and view if possible.\n"
+ " if lineInt < v.Buf.NumLines && lineInt >= 0 {\n"
+ " v.Cursor.X = colInt\n"
+ " v.Cursor.Y = lineInt\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"JumpLine\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n"
+ " messenger.Error(\"Only \", v.Buf.NumLines, \" lines to jump\")\n"
+ " return false\n"
+ " }\n\n"
+ " // ClearStatus clears the messenger bar\n"
+ " func (v *View) ClearStatus(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"ClearStatus\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " messenger.Message(\"\")\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"ClearStatus\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // ToggleHelp toggles the help screen\n"
+ " func (v *View) ToggleHelp(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"ToggleHelp\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if v.Type != vtHelp {\n"
+ " // Open the default help\n"
+ " v.openHelp(\"help\")\n"
+ " } else {\n"
+ " v.Quit(true)\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"ToggleHelp\", v)\n"
+ " }\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // ToggleKeyMenu toggles the keymenu option and resizes all tabs\n"
+ " func (v *View) ToggleKeyMenu(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"ToggleBindings\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " globalSettings[\"keymenu\"] = !globalSettings[\"keymenu\"].(bool)\n"
+ " for _, tab := range tabs {\n"
+ " tab.Resize()\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"ToggleBindings\", v)\n"
+ " }\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // ShellMode opens a terminal to run a shell command\n"
+ " func (v *View) ShellMode(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"ShellMode\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " input, canceled := messenger.Prompt(\"$ \", \"\", \"Shell\", NoCompletion)\n"
+ " if !canceled {\n"
+ " // The true here is for openTerm to make the command interactive\n"
+ " HandleShellCommand(input, true, true)\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"ShellMode\", v)\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // CommandMode lets the user enter a command\n"
+ " func (v *View) CommandMode(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"CommandMode\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " input, canceled := messenger.Prompt(\"> \", \"\", \"Command\", CommandCompletion)\n"
+ " if !canceled {\n"
+ " HandleCommand(input)\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"CommandMode\", v)\n"
+ " }\n"
+ " }\n"
+ " }\n\n"
+ " return false\n"
+ " }\n\n"
+ " // ToggleOverwriteMode lets the user toggle the text overwrite mode\n"
+ " func (v *View) ToggleOverwriteMode(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"ToggleOverwriteMode\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " v.isOverwriteMode = !v.isOverwriteMode\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"ToggleOverwriteMode\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // Escape leaves current mode\n"
+ " func (v *View) Escape(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " // check if user is searching, or the last search is still active\n"
+ " if searching || lastSearch != \"\" {\n"
+ " ExitSearch(v)\n"
+ " return true\n"
+ " }\n"
+ " // check if a prompt is shown, hide it and don't quit\n"
+ " if messenger.hasPrompt {\n"
+ " messenger.Reset() // FIXME\n"
+ " return true\n"
+ " }\n"
+ " }\n\n"
+ " return false\n"
+ " }\n\n"
+ " // Quit this will close the current tab or view that is open\n"
+ " func (v *View) Quit(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"Quit\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " // Make sure not to quit if there are unsaved changes\n"
+ " if v.CanClose() {\n"
+ " v.CloseBuffer()\n"
+ " if len(tabs[curTab].Views) > 1 {\n"
+ " v.splitNode.Delete()\n"
+ " tabs[v.TabNum].Cleanup()\n"
+ " tabs[v.TabNum].Resize()\n"
+ " } else if len(tabs) > 1 {\n"
+ " if len(tabs[v.TabNum].Views) == 1 {\n"
+ " tabs = tabs[:v.TabNum+copy(tabs[v.TabNum:], tabs[v.TabNum+1:])]\n"
+ " for i, t := range tabs {\n"
+ " t.SetNum(i)\n"
+ " }\n"
+ " if curTab >= len(tabs) {\n"
+ " curTab--\n"
+ " }\n"
+ " if curTab == 0 {\n"
+ " CurView().ToggleTabbar()\n"
+ " }\n"
+ " }\n"
+ " } else {\n"
+ " if usePlugin {\n"
+ " PostActionCall(\"Quit\", v)\n"
+ " }\n\n"
+ " screen.Fini()\n"
+ " messenger.SaveHistory()\n"
+ " os.Exit(0)\n"
+ " }\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"Quit\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // QuitAll quits the whole editor; all splits and tabs\n"
+ " func (v *View) QuitAll(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"QuitAll\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " closeAll := true\n"
+ " for _, tab := range tabs {\n"
+ " for _, v := range tab.Views {\n"
+ " if !v.CanClose() {\n"
+ " closeAll = false\n"
+ " }\n"
+ " }\n"
+ " }\n\n"
+ " if closeAll {\n"
+ " // only quit if all of the buffers can be closed and the user confirms that they actually want to quit everything\n"
+ " shouldQuit, _ := messenger.YesNoPrompt(\"Do you want to quit micro (all open files will be closed)?\")\n\n"
+ " if shouldQuit {\n"
+ " for _, tab := range tabs {\n"
+ " for _, v := range tab.Views {\n"
+ " v.CloseBuffer()\n"
+ " }\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " PostActionCall(\"QuitAll\", v)\n"
+ " }\n\n"
+ " screen.Fini()\n"
+ " messenger.SaveHistory()\n"
+ " os.Exit(0)\n"
+ " }\n"
+ " }\n"
+ " }\n\n"
+ " return false\n"
+ " }\n\n"
+ " // AddTab adds a new tab with an empty buffer\n"
+ " func (v *View) AddTab(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"AddTab\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " tab := NewTabFromView(NewView(NewBufferFromString(\"\", \"\")))\n"
+ " tab.SetNum(len(tabs))\n"
+ " tabs = append(tabs, tab)\n"
+ " curTab = len(tabs) - 1\n"
+ " if len(tabs) == 2 {\n"
+ " for _, t := range tabs {\n"
+ " for _, v := range t.Views {\n"
+ " v.ToggleTabbar()\n"
+ " }\n"
+ " }\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"AddTab\", v)\n"
+ " }\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // PreviousTab switches to the previous tab in the tab list\n"
+ " func (v *View) PreviousTab(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"PreviousTab\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if curTab > 0 {\n"
+ " curTab--\n"
+ " } else if curTab == 0 {\n"
+ " curTab = len(tabs) - 1\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"PreviousTab\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // NextTab switches to the next tab in the tab list\n"
+ " func (v *View) NextTab(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"NextTab\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if curTab < len(tabs)-1 {\n"
+ " curTab++\n"
+ " } else if curTab == len(tabs)-1 {\n"
+ " curTab = 0\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"NextTab\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // VSplitBinding opens an empty vertical split\n"
+ " func (v *View) VSplitBinding(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"VSplit\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " v.VSplit(NewBufferFromString(\"\", \"\"))\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"VSplit\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // HSplitBinding opens an empty horizontal split\n"
+ " func (v *View) HSplitBinding(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"HSplit\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " v.HSplit(NewBufferFromString(\"\", \"\"))\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"HSplit\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // Unsplit closes all splits in the current tab except the active one\n"
+ " func (v *View) Unsplit(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"Unsplit\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " curView := tabs[curTab].CurView\n"
+ " for i := len(tabs[curTab].Views) - 1; i >= 0; i-- {\n"
+ " view := tabs[curTab].Views[i]\n"
+ " if view != nil && view.Num != curView {\n"
+ " view.Quit(true)\n"
+ " // messenger.Message(\"Quit \", view.Buf.Path)\n"
+ " }\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"Unsplit\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // NextSplit changes the view to the next split\n"
+ " func (v *View) NextSplit(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"NextSplit\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " tab := tabs[curTab]\n"
+ " if tab.CurView < len(tab.Views)-1 {\n"
+ " tab.CurView++\n"
+ " } else {\n"
+ " tab.CurView = 0\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"NextSplit\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // PreviousSplit changes the view to the previous split\n"
+ " func (v *View) PreviousSplit(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"PreviousSplit\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " tab := tabs[curTab]\n"
+ " if tab.CurView > 0 {\n"
+ " tab.CurView--\n"
+ " } else {\n"
+ " tab.CurView = len(tab.Views) - 1\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"PreviousSplit\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " var curMacro []interface{}\n"
+ " var recordingMacro bool\n\n"
+ " // ToggleMacro toggles recording of a macro\n"
+ " func (v *View) ToggleMacro(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"ToggleMacro\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " recordingMacro = !recordingMacro\n\n"
+ " if recordingMacro {\n"
+ " curMacro = []interface{}{}\n"
+ " messenger.Message(\"Recording\")\n"
+ " } else {\n"
+ " messenger.Message(\"Stopped recording\")\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"ToggleMacro\", v)\n"
+ " }\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // PlayMacro plays back the most recently recorded macro\n"
+ " func (v *View) PlayMacro(usePlugin bool) bool {\n"
+ " if usePlugin && !PreActionCall(\"PlayMacro\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " for _, action := range curMacro {\n"
+ " switch t := action.(type) {\n"
+ " case rune:\n"
+ " // Insert a character\n"
+ " if v.Cursor.HasSelection() {\n"
+ " v.Cursor.DeleteSelection()\n"
+ " v.Cursor.ResetSelection()\n"
+ " }\n"
+ " v.Buf.Insert(v.Cursor.Loc, string(t))\n"
+ " // v.Cursor.Right()\n\n"
+ " for pl := range loadedPlugins {\n"
+ " _, err := Call(pl+\".onRune\", string(t), v)\n"
+ " if err != nil && !strings.HasPrefix(err.Error(), \"function does not exist\") {\n"
+ " TermMessage(err)\n"
+ " }\n"
+ " }\n"
+ " case func(*View, bool) bool:\n"
+ " t(v, true)\n"
+ " }\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"PlayMacro\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n\n"
+ " // SpawnMultiCursor creates a new multiple cursor at the next occurrence of the current selection or current word\n"
+ " func (v *View) SpawnMultiCursor(usePlugin bool) bool {\n"
+ " spawner := v.Buf.cursors[len(v.Buf.cursors)-1]\n"
+ " // You can only spawn a cursor from the main cursor\n"
+ " if v.Cursor == spawner {\n"
+ " if usePlugin && !PreActionCall(\"SpawnMultiCursor\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " if !spawner.HasSelection() {\n"
+ " spawner.SelectWord()\n"
+ " } else {\n"
+ " c := &Cursor{\n"
+ " buf: v.Buf,\n"
+ " }\n\n"
+ " sel := spawner.GetSelection()\n\n"
+ " searchStart = spawner.CurSelection[1]\n"
+ " v.Cursor = c\n"
+ " Search(regexp.QuoteMeta(sel), v, true)\n\n"
+ " for _, cur := range v.Buf.cursors {\n"
+ " if c.Loc == cur.Loc {\n"
+ " return false\n"
+ " }\n"
+ " }\n"
+ " v.Buf.cursors = append(v.Buf.cursors, c)\n"
+ " v.Buf.UpdateCursors()\n"
+ " v.Relocate()\n"
+ " v.Cursor = spawner\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " PostActionCall(\"SpawnMultiCursor\", v)\n"
+ " }\n"
+ " }\n\n"
+ " return false\n"
+ " }\n\n"
+ " // SpawnMultiCursorSelect adds a cursor at the beginning of each line of a selection\n"
+ " func (v *View) SpawnMultiCursorSelect(usePlugin bool) bool {\n"
+ " if v.Cursor == &v.Buf.Cursor {\n"
+ " if usePlugin && !PreActionCall(\"SpawnMultiCursorSelect\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " // Avoid cases where multiple cursors already exist, that would create problems\n"
+ " if len(v.Buf.cursors) > 1 {\n"
+ " return false\n"
+ " }\n\n"
+ " var startLine int\n"
+ " var endLine int\n\n"
+ " a, b := v.Cursor.CurSelection[0].Y, v.Cursor.CurSelection[1].Y\n"
+ " if a > b {\n"
+ " startLine, endLine = b, a\n"
+ " } else {\n"
+ " startLine, endLine = a, b\n"
+ " }\n\n"
+ " if v.Cursor.HasSelection() {\n"
+ " v.Cursor.ResetSelection()\n"
+ " v.Cursor.GotoLoc(Loc{0, startLine})\n\n"
+ " for i := startLine; i <= endLine; i++ {\n"
+ " c := &Cursor{\n"
+ " buf: v.Buf,\n"
+ " }\n"
+ " c.GotoLoc(Loc{0, i})\n"
+ " v.Buf.cursors = append(v.Buf.cursors, c)\n"
+ " }\n"
+ " v.Buf.MergeCursors()\n"
+ " v.Buf.UpdateCursors()\n"
+ " } else {\n"
+ " return false\n"
+ " }\n\n"
+ " if usePlugin {\n"
+ " PostActionCall(\"SpawnMultiCursorSelect\", v)\n"
+ " }\n\n"
+ " messenger.Message(\"Added cursors from selection\")\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // MouseMultiCursor is a mouse action which puts a new cursor at the mouse position\n"
+ " func (v *View) MouseMultiCursor(usePlugin bool, e *tcell.EventMouse) bool {\n"
+ " if v.Cursor == &v.Buf.Cursor {\n"
+ " if usePlugin && !PreActionCall(\"SpawnMultiCursorAtMouse\", v, e) {\n"
+ " return false\n"
+ " }\n"
+ " x, y := e.Position()\n"
+ " x -= v.lineNumOffset - v.leftCol + v.x\n"
+ " y += v.Topline - v.y\n\n"
+ " c := &Cursor{\n"
+ " buf: v.Buf,\n"
+ " }\n"
+ " v.Cursor = c\n"
+ " v.MoveToMouseClick(x, y)\n"
+ " v.Relocate()\n"
+ " v.Cursor = &v.Buf.Cursor\n\n"
+ " v.Buf.cursors = append(v.Buf.cursors, c)\n"
+ " v.Buf.MergeCursors()\n"
+ " v.Buf.UpdateCursors()\n\n"
+ " if usePlugin {\n"
+ " PostActionCall(\"SpawnMultiCursorAtMouse\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // SkipMultiCursor moves the current multiple cursor to the next available position\n"
+ " func (v *View) SkipMultiCursor(usePlugin bool) bool {\n"
+ " cursor := v.Buf.cursors[len(v.Buf.cursors)-1]\n\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"SkipMultiCursor\", v) {\n"
+ " return false\n"
+ " }\n"
+ " sel := cursor.GetSelection()\n\n"
+ " searchStart = cursor.CurSelection[1]\n"
+ " v.Cursor = cursor\n"
+ " Search(regexp.QuoteMeta(sel), v, true)\n"
+ " v.Relocate()\n"
+ " v.Cursor = cursor\n\n"
+ " if usePlugin {\n"
+ " PostActionCall(\"SkipMultiCursor\", v)\n"
+ " }\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // RemoveMultiCursor removes the latest multiple cursor\n"
+ " func (v *View) RemoveMultiCursor(usePlugin bool) bool {\n"
+ " end := len(v.Buf.cursors)\n"
+ " if end > 1 {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"RemoveMultiCursor\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " v.Buf.cursors[end-1] = nil\n"
+ " v.Buf.cursors = v.Buf.cursors[:end-1]\n"
+ " v.Buf.UpdateCursors()\n"
+ " v.Relocate()\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"RemoveMultiCursor\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n"
+ " } else {\n"
+ " v.RemoveAllMultiCursors(usePlugin)\n"
+ " }\n"
+ " return false\n"
+ " }\n\n"
+ " // RemoveAllMultiCursors removes all cursors except the base cursor\n"
+ " func (v *View) RemoveAllMultiCursors(usePlugin bool) bool {\n"
+ " if v.mainCursor() {\n"
+ " if usePlugin && !PreActionCall(\"RemoveAllMultiCursors\", v) {\n"
+ " return false\n"
+ " }\n\n"
+ " v.Buf.clearCursors()\n"
+ " v.Relocate()\n\n"
+ " if usePlugin {\n"
+ " return PostActionCall(\"RemoveAllMultiCursors\", v)\n"
+ " }\n"
+ " return true\n"
+ " }\n"
+ " return false\n"
+ " }";
final String subst = "--[[\\n${statementDescComment}${statement}\\n]]--";
final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
final Matcher matcher = pattern.matcher(string);
// The substituted value will be contained in the result variable
final String result = matcher.replaceAll(subst);
System.out.println("Substitution result: " + result);
}
}
Please keep in mind that these code samples are automatically generated and are not guaranteed to work. If you find any syntax errors, feel free to submit a bug report. For a full regex reference for Java, please visit: https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html