Regular Expressions 101

Save & Share

Flavor

  • PCRE2 (PHP >=7.3)
  • PCRE (PHP <7.3)
  • ECMAScript (JavaScript)
  • Python
  • Golang
  • Java 8
  • .NET 7.0 (C#)
  • Rust
  • Regex Flavor Guide

Function

  • Match
  • Substitution
  • List
  • Unit Tests

Tools

Sponsors
There are currently no sponsors. Become a sponsor today!
An explanation of your regex will be automatically generated as you type.
Detailed match information will be displayed here automatically.
  • All Tokens
  • Common Tokens
  • General Tokens
  • Anchors
  • Meta Sequences
  • Quantifiers
  • Group Constructs
  • Character Classes
  • Flags/Modifiers
  • Substitution
  • A single character of: a, b or c
    [abc]
  • A character except: a, b or c
    [^abc]
  • A character in the range: a-z
    [a-z]
  • A character not in the range: a-z
    [^a-z]
  • A character in the range: a-z or A-Z
    [a-zA-Z]
  • Any single character
    .
  • Alternate - match either a or b
    a|b
  • Any whitespace character
    \s
  • Any non-whitespace character
    \S
  • Any digit
    \d
  • Any non-digit
    \D
  • Any word character
    \w
  • Any non-word character
    \W
  • Non-capturing group
    (?:...)
  • Capturing group
    (...)
  • Zero or one of a
    a?
  • Zero or more of a
    a*
  • One or more of a
    a+
  • Exactly 3 of a
    a{3}
  • 3 or more of a
    a{3,}
  • Between 3 and 6 of a
    a{3,6}
  • Start of string
    ^
  • End of string
    $
  • A word boundary
    \b
  • Non-word boundary
    \B

Regular Expression

/
/
gm

Test String

Substitution

Processing...

Code Generator

Generated Code

# coding=utf8 # the above tag defines encoding for this document and is for Python 2.x compatibility import re regex = (r"(?x)\n\n" r"# Set intent level\n" r"(?(DEFINE)(?<indent>[[:space:]]{4}))\n\n" r"# Must start at new line\n" r"^\n" r"# Captures following statement's description comment lines if written\n" r"(?<statementDescComment> \n" r" (?: \n" r" # Repeat below until next line not comment\n" r" (?=(?P>indent)\/)\V*\v\n" r" )+\n" r")?\n" r"# Generic Statement Capture\n" r"(?<statement>\n" r"# Const declaration capture\n" r"(?<const>\n" r" (?P>indent)const[[:space:]]*\([[:space:]]*\n" r" \v\n" r" (?:\n" r" (?!(?P>indent)\))\V*\v\n" r" )*\n" r" (?P>indent)\)\n" r")\n" r"|\n" r"# Full function declaration capture\n" r"(?<func>\n" r" # Function declaration initialization\n" r" (?<funcDecLine>\n" r" (?P>indent)func\V+\n" r" )\v\n" r" # Repeat subcapture until line starting with close bracket\n" r" (?:\n" r" (?!(?P>indent)\})\V*\v\n" r" )*\n" r" # Closing bracket\n" r" (?<funcCloseBracket>(?P>indent)\})\n" r")\n" r"|\n" r"(?<type>\n" r" # Type Declaration\n\n" r" # Check before wasting time\n" r" (?=(?P>indent)type)\n\n" r" # Short Form\n" r" (?<typeDecShort>\n" r" (?P>indent)type\V+[^\{]\v\n" r" )\n" r" |\n" r" # Longer Form (Brackted)\n" r" (?<typeDecLong>\n" r" (?P>indent)type\V+\n" r" )\v\n" r" # Repeat subcapture until line starting with close bracket\n" r" (?:\n" r" (?!(?P>indent)\})\V*\v\n" r" )*\n" r" # Closing bracket\n" r" (?<typeCloseBracket>(?P>indent)\})\n" r" )\n" r")") test_str = (" 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" " }") subst = "--[[\\n${statementDescComment}${statement}\\n]]--" # You can manually specify the number of replacements by changing the 4th argument result = re.sub(regex, subst, test_str, 0, re.MULTILINE) if result: print (result) # Note: for Python 2.7 compatibility, use ur"" to prefix the regex and u"" to prefix the test string and substitution.

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 Python, please visit: https://docs.python.org/3/library/re.html