10 "github.com/mitchellh/go-homedir"
11 "github.com/yuin/gopher-lua"
12 "github.com/zyedidia/clipboard"
15 // PreActionCall executes the lua pre callback if possible
16 func PreActionCall(funcName string) bool {
18 for _, pl := range loadedPlugins {
19 ret, err := Call(pl+".pre"+funcName, nil)
20 if err != nil && !strings.HasPrefix(err.Error(), "function does not exist") {
24 if ret == lua.LFalse {
31 // PostActionCall executes the lua plugin callback if possible
32 func PostActionCall(funcName string) {
33 for _, pl := range loadedPlugins {
34 _, err := Call(pl+".on"+funcName, nil)
35 if err != nil && !strings.HasPrefix(err.Error(), "function does not exist") {
42 // CursorUp moves the cursor up
43 func (v *View) CursorUp(usePlugin bool) bool {
44 if usePlugin && !PreActionCall("CursorUp") {
48 if v.Cursor.HasSelection() {
49 v.Cursor.Loc = v.Cursor.CurSelection[0]
50 v.Cursor.ResetSelection()
55 PostActionCall("CursorUp")
60 // CursorDown moves the cursor down
61 func (v *View) CursorDown(usePlugin bool) bool {
62 if usePlugin && !PreActionCall("CursorDown") {
66 if v.Cursor.HasSelection() {
67 v.Cursor.Loc = v.Cursor.CurSelection[1]
68 v.Cursor.ResetSelection()
73 PostActionCall("CursorDown")
78 // CursorLeft moves the cursor left
79 func (v *View) CursorLeft(usePlugin bool) bool {
80 if usePlugin && !PreActionCall("CursorLeft") {
84 if v.Cursor.HasSelection() {
85 v.Cursor.Loc = v.Cursor.CurSelection[0]
86 v.Cursor.ResetSelection()
92 PostActionCall("CursorLeft")
97 // CursorRight moves the cursor right
98 func (v *View) CursorRight(usePlugin bool) bool {
99 if usePlugin && !PreActionCall("CursorRight") {
103 if v.Cursor.HasSelection() {
104 v.Cursor.Loc = v.Cursor.CurSelection[1].Move(-1, v.Buf)
105 v.Cursor.ResetSelection()
111 PostActionCall("CursorRight")
116 // WordRight moves the cursor one word to the right
117 func (v *View) WordRight(usePlugin bool) bool {
118 if usePlugin && !PreActionCall("WordRight") {
125 PostActionCall("WordRight")
130 // WordLeft moves the cursor one word to the left
131 func (v *View) WordLeft(usePlugin bool) bool {
132 if usePlugin && !PreActionCall("WordLeft") {
139 PostActionCall("WordLeft")
144 // SelectUp selects up one line
145 func (v *View) SelectUp(usePlugin bool) bool {
146 if usePlugin && !PreActionCall("SelectUp") {
150 if !v.Cursor.HasSelection() {
151 v.Cursor.OrigSelection[0] = v.Cursor.Loc
154 v.Cursor.SelectTo(v.Cursor.Loc)
157 PostActionCall("SelectUp")
162 // SelectDown selects down one line
163 func (v *View) SelectDown(usePlugin bool) bool {
164 if usePlugin && !PreActionCall("SelectDown") {
168 if !v.Cursor.HasSelection() {
169 v.Cursor.OrigSelection[0] = v.Cursor.Loc
172 v.Cursor.SelectTo(v.Cursor.Loc)
175 PostActionCall("SelectDown")
180 // SelectLeft selects the character to the left of the cursor
181 func (v *View) SelectLeft(usePlugin bool) bool {
182 if usePlugin && !PreActionCall("SelectLeft") {
187 count := v.Buf.End().Move(-1, v.Buf)
188 if loc.GreaterThan(count) {
191 if !v.Cursor.HasSelection() {
192 v.Cursor.OrigSelection[0] = loc
195 v.Cursor.SelectTo(v.Cursor.Loc)
198 PostActionCall("SelectLeft")
203 // SelectRight selects the character to the right of the cursor
204 func (v *View) SelectRight(usePlugin bool) bool {
205 if usePlugin && !PreActionCall("SelectRight") {
210 count := v.Buf.End().Move(-1, v.Buf)
211 if loc.GreaterThan(count) {
214 if !v.Cursor.HasSelection() {
215 v.Cursor.OrigSelection[0] = loc
218 v.Cursor.SelectTo(v.Cursor.Loc)
221 PostActionCall("SelectRight")
226 // SelectWordRight selects the word to the right of the cursor
227 func (v *View) SelectWordRight(usePlugin bool) bool {
228 if usePlugin && !PreActionCall("SelectWordRight") {
232 if !v.Cursor.HasSelection() {
233 v.Cursor.OrigSelection[0] = v.Cursor.Loc
236 v.Cursor.SelectTo(v.Cursor.Loc)
239 PostActionCall("SelectWordRight")
244 // SelectWordLeft selects the word to the left of the cursor
245 func (v *View) SelectWordLeft(usePlugin bool) bool {
246 if usePlugin && !PreActionCall("SelectWordLeft") {
250 if !v.Cursor.HasSelection() {
251 v.Cursor.OrigSelection[0] = v.Cursor.Loc
254 v.Cursor.SelectTo(v.Cursor.Loc)
257 PostActionCall("SelectWordLeft")
262 // StartOfLine moves the cursor to the start of the line
263 func (v *View) StartOfLine(usePlugin bool) bool {
264 if usePlugin && !PreActionCall("StartOfLine") {
271 PostActionCall("StartOfLine")
276 // EndOfLine moves the cursor to the end of the line
277 func (v *View) EndOfLine(usePlugin bool) bool {
278 if usePlugin && !PreActionCall("EndOfLine") {
285 PostActionCall("EndOfLine")
290 // SelectToStartOfLine selects to the start of the current line
291 func (v *View) SelectToStartOfLine(usePlugin bool) bool {
292 if usePlugin && !PreActionCall("SelectToStartOfLine") {
296 if !v.Cursor.HasSelection() {
297 v.Cursor.OrigSelection[0] = v.Cursor.Loc
300 v.Cursor.SelectTo(v.Cursor.Loc)
303 PostActionCall("SelectToStartOfLine")
308 // SelectToEndOfLine selects to the end of the current line
309 func (v *View) SelectToEndOfLine(usePlugin bool) bool {
310 if usePlugin && !PreActionCall("SelectToEndOfLine") {
314 if !v.Cursor.HasSelection() {
315 v.Cursor.OrigSelection[0] = v.Cursor.Loc
318 v.Cursor.SelectTo(v.Cursor.Loc)
321 PostActionCall("SelectToEndOfLine")
326 // CursorStart moves the cursor to the start of the buffer
327 func (v *View) CursorStart(usePlugin bool) bool {
328 if usePlugin && !PreActionCall("CursorStart") {
336 PostActionCall("CursorStart")
341 // CursorEnd moves the cursor to the end of the buffer
342 func (v *View) CursorEnd(usePlugin bool) bool {
343 if usePlugin && !PreActionCall("CursorEnd") {
347 v.Cursor.Loc = v.Buf.End()
350 PostActionCall("CursorEnd")
355 // SelectToStart selects the text from the cursor to the start of the buffer
356 func (v *View) SelectToStart(usePlugin bool) bool {
357 if usePlugin && !PreActionCall("SelectToStart") {
361 if !v.Cursor.HasSelection() {
362 v.Cursor.OrigSelection[0] = v.Cursor.Loc
365 v.Cursor.SelectTo(v.Buf.Start())
368 PostActionCall("SelectToStart")
373 // SelectToEnd selects the text from the cursor to the end of the buffer
374 func (v *View) SelectToEnd(usePlugin bool) bool {
375 if usePlugin && !PreActionCall("SelectToEnd") {
379 if !v.Cursor.HasSelection() {
380 v.Cursor.OrigSelection[0] = v.Cursor.Loc
383 v.Cursor.SelectTo(v.Buf.End())
386 PostActionCall("SelectToEnd")
391 // InsertSpace inserts a space
392 func (v *View) InsertSpace(usePlugin bool) bool {
393 if usePlugin && !PreActionCall("InsertSpace") {
397 if v.Cursor.HasSelection() {
398 v.Cursor.DeleteSelection()
399 v.Cursor.ResetSelection()
401 v.Buf.Insert(v.Cursor.Loc, " ")
405 PostActionCall("InsertSpace")
410 // InsertNewline inserts a newline plus possible some whitespace if autoindent is on
411 func (v *View) InsertNewline(usePlugin bool) bool {
412 if usePlugin && !PreActionCall("InsertNewline") {
417 if v.Cursor.HasSelection() {
418 v.Cursor.DeleteSelection()
419 v.Cursor.ResetSelection()
422 v.Buf.Insert(v.Cursor.Loc, "\n")
423 ws := GetLeadingWhitespace(v.Buf.Line(v.Cursor.Y))
426 if settings["autoindent"].(bool) {
427 v.Buf.Insert(v.Cursor.Loc, ws)
428 for i := 0; i < len(ws); i++ {
432 v.Cursor.LastVisualX = v.Cursor.GetVisualX()
435 PostActionCall("InsertNewline")
440 // Backspace deletes the previous character
441 func (v *View) Backspace(usePlugin bool) bool {
442 if usePlugin && !PreActionCall("Backspace") {
446 // Delete a character
447 if v.Cursor.HasSelection() {
448 v.Cursor.DeleteSelection()
449 v.Cursor.ResetSelection()
450 } else if v.Cursor.Loc.GreaterThan(v.Buf.Start()) {
451 // We have to do something a bit hacky here because we want to
452 // delete the line by first moving left and then deleting backwards
453 // but the undo redo would place the cursor in the wrong place
454 // So instead we move left, save the position, move back, delete
455 // and restore the position
457 // If the user is using spaces instead of tabs and they are deleting
458 // whitespace at the start of the line, we should delete as if its a
459 // tab (tabSize number of spaces)
460 lineStart := v.Buf.Line(v.Cursor.Y)[:v.Cursor.X]
461 tabSize := int(settings["tabsize"].(float64))
462 if settings["tabstospaces"].(bool) && IsSpaces(lineStart) && len(lineStart) != 0 && len(lineStart)%tabSize == 0 {
464 v.Cursor.Loc = loc.Move(-tabSize, v.Buf)
465 cx, cy := v.Cursor.X, v.Cursor.Y
467 v.Buf.Remove(loc.Move(-tabSize, v.Buf), loc)
468 v.Cursor.X, v.Cursor.Y = cx, cy
471 cx, cy := v.Cursor.X, v.Cursor.Y
474 v.Buf.Remove(loc.Move(-1, v.Buf), loc)
475 v.Cursor.X, v.Cursor.Y = cx, cy
478 v.Cursor.LastVisualX = v.Cursor.GetVisualX()
481 PostActionCall("Backspace")
486 // DeleteWordRight deletes the word to the right of the cursor
487 func (v *View) DeleteWordRight(usePlugin bool) bool {
488 if usePlugin && !PreActionCall("DeleteWordRight") {
492 v.SelectWordRight(false)
493 if v.Cursor.HasSelection() {
494 v.Cursor.DeleteSelection()
495 v.Cursor.ResetSelection()
499 PostActionCall("DeleteWordRight")
504 // DeleteWordLeft deletes the word to the left of the cursor
505 func (v *View) DeleteWordLeft(usePlugin bool) bool {
506 if usePlugin && !PreActionCall("DeleteWordLeft") {
510 v.SelectWordLeft(false)
511 if v.Cursor.HasSelection() {
512 v.Cursor.DeleteSelection()
513 v.Cursor.ResetSelection()
517 PostActionCall("DeleteWordLeft")
522 // Delete deletes the next character
523 func (v *View) Delete(usePlugin bool) bool {
524 if usePlugin && !PreActionCall("Delete") {
528 if v.Cursor.HasSelection() {
529 v.Cursor.DeleteSelection()
530 v.Cursor.ResetSelection()
533 if loc.LessThan(v.Buf.End()) {
534 v.Buf.Remove(loc, loc.Move(1, v.Buf))
539 PostActionCall("Delete")
544 // IndentSelection indents the current selection
545 func (v *View) IndentSelection(usePlugin bool) bool {
546 if usePlugin && !PreActionCall("IndentSelection") {
550 if v.Cursor.HasSelection() {
551 start := v.Cursor.CurSelection[0].Y
552 end := v.Cursor.CurSelection[1].Move(-1, v.Buf).Y
553 endX := v.Cursor.CurSelection[1].Move(-1, v.Buf).X
554 for i := start; i <= end; i++ {
555 if settings["tabstospaces"].(bool) {
556 tabsize := int(settings["tabsize"].(float64))
557 v.Buf.Insert(Loc{0, i}, Spaces(tabsize))
559 if v.Cursor.CurSelection[0].X > 0 {
560 v.Cursor.CurSelection[0] = v.Cursor.CurSelection[0].Move(tabsize, v.Buf)
564 v.Cursor.CurSelection[1] = Loc{endX + tabsize + 1, end}
567 v.Buf.Insert(Loc{0, i}, "\t")
569 if v.Cursor.CurSelection[0].X > 0 {
570 v.Cursor.CurSelection[0] = v.Cursor.CurSelection[0].Move(1, v.Buf)
574 v.Cursor.CurSelection[1] = Loc{endX + 2, end}
581 PostActionCall("IndentSelection")
588 // OutdentSelection takes the current selection and moves it back one indent level
589 func (v *View) OutdentSelection(usePlugin bool) bool {
590 if usePlugin && !PreActionCall("OutdentSelection") {
594 if v.Cursor.HasSelection() {
595 start := v.Cursor.CurSelection[0].Y
596 end := v.Cursor.CurSelection[1].Move(-1, v.Buf).Y
597 endX := v.Cursor.CurSelection[1].Move(-1, v.Buf).X
598 for i := start; i <= end; i++ {
599 if len(GetLeadingWhitespace(v.Buf.Line(i))) > 0 {
600 if settings["tabstospaces"].(bool) {
601 tabsize := int(settings["tabsize"].(float64))
602 for j := 0; j < tabsize; j++ {
603 if len(GetLeadingWhitespace(v.Buf.Line(i))) == 0 {
606 v.Buf.Remove(Loc{0, i}, Loc{1, i})
608 if v.Cursor.CurSelection[0].X > 0 {
609 v.Cursor.CurSelection[0] = v.Cursor.CurSelection[0].Move(-1, v.Buf)
613 v.Cursor.CurSelection[1] = Loc{endX - j, end}
617 v.Buf.Remove(Loc{0, i}, Loc{1, i})
619 if v.Cursor.CurSelection[0].X > 0 {
620 v.Cursor.CurSelection[0] = v.Cursor.CurSelection[0].Move(-1, v.Buf)
624 v.Cursor.CurSelection[1] = Loc{endX, end}
632 PostActionCall("OutdentSelection")
639 // InsertTab inserts a tab or spaces
640 func (v *View) InsertTab(usePlugin bool) bool {
641 if usePlugin && !PreActionCall("InsertTab") {
645 if v.Cursor.HasSelection() {
649 if settings["tabstospaces"].(bool) {
650 tabSize := int(settings["tabsize"].(float64))
651 v.Buf.Insert(v.Cursor.Loc, Spaces(tabSize))
652 for i := 0; i < tabSize; i++ {
656 v.Buf.Insert(v.Cursor.Loc, "\t")
661 PostActionCall("InsertTab")
666 // Save the buffer to disk
667 func (v *View) Save(usePlugin bool) bool {
668 if usePlugin && !PreActionCall("Save") {
673 // We can't save the help text
676 // If this is an empty buffer, ask for a filename
677 if v.Buf.Path == "" {
678 filename, canceled := messenger.Prompt("Filename: ", "Save", NoCompletion)
680 v.Buf.Path = filename
681 v.Buf.Name = filename
688 if strings.HasSuffix(err.Error(), "permission denied") {
689 choice, _ := messenger.YesNoPrompt("Permission denied. Do you want to save this file using sudo? (y,n)")
691 err = v.Buf.SaveWithSudo()
693 messenger.Error(err.Error())
696 messenger.Message("Saved " + v.Buf.Path)
701 messenger.Error(err.Error())
704 messenger.Message("Saved " + v.Buf.Path)
708 PostActionCall("Save")
713 // Find opens a prompt and searches forward for the input
714 func (v *View) Find(usePlugin bool) bool {
715 if usePlugin && !PreActionCall("Find") {
719 if v.Cursor.HasSelection() {
720 searchStart = ToCharPos(v.Cursor.CurSelection[1], v.Buf)
722 searchStart = ToCharPos(v.Cursor.Loc, v.Buf)
727 PostActionCall("Find")
732 // FindNext searches forwards for the last used search term
733 func (v *View) FindNext(usePlugin bool) bool {
734 if usePlugin && !PreActionCall("FindNext") {
738 if v.Cursor.HasSelection() {
739 searchStart = ToCharPos(v.Cursor.CurSelection[1], v.Buf)
741 searchStart = ToCharPos(v.Cursor.Loc, v.Buf)
743 messenger.Message("Finding: " + lastSearch)
744 Search(lastSearch, v, true)
747 PostActionCall("FindNext")
752 // FindPrevious searches backwards for the last used search term
753 func (v *View) FindPrevious(usePlugin bool) bool {
754 if usePlugin && !PreActionCall("FindPrevious") {
758 if v.Cursor.HasSelection() {
759 searchStart = ToCharPos(v.Cursor.CurSelection[0], v.Buf)
761 searchStart = ToCharPos(v.Cursor.Loc, v.Buf)
763 messenger.Message("Finding: " + lastSearch)
764 Search(lastSearch, v, false)
767 PostActionCall("FindPrevious")
772 // Undo undoes the last action
773 func (v *View) Undo(usePlugin bool) bool {
774 if usePlugin && !PreActionCall("Undo") {
779 messenger.Message("Undid action")
782 PostActionCall("Undo")
787 // Redo redoes the last action
788 func (v *View) Redo(usePlugin bool) bool {
789 if usePlugin && !PreActionCall("Redo") {
794 messenger.Message("Redid action")
797 PostActionCall("Redo")
802 // Copy the selection to the system clipboard
803 func (v *View) Copy(usePlugin bool) bool {
804 if usePlugin && !PreActionCall("Copy") {
808 if v.Cursor.HasSelection() {
809 clipboard.WriteAll(v.Cursor.GetSelection())
811 messenger.Message("Copied selection")
815 PostActionCall("Copy")
820 // CutLine cuts the current line to the clipboard
821 func (v *View) CutLine(usePlugin bool) bool {
822 if usePlugin && !PreActionCall("CutLine") {
826 v.Cursor.SelectLine()
827 if !v.Cursor.HasSelection() {
830 if v.freshClip == true {
831 if v.Cursor.HasSelection() {
832 if clip, err := clipboard.ReadAll(); err != nil {
835 clipboard.WriteAll(clip + v.Cursor.GetSelection())
838 } else if time.Since(v.lastCutTime)/time.Second > 10*time.Second || v.freshClip == false {
842 v.lastCutTime = time.Now()
843 v.Cursor.DeleteSelection()
844 v.Cursor.ResetSelection()
845 messenger.Message("Cut line")
848 PostActionCall("CutLine")
853 // Cut the selection to the system clipboard
854 func (v *View) Cut(usePlugin bool) bool {
855 if usePlugin && !PreActionCall("Cut") {
859 if v.Cursor.HasSelection() {
860 clipboard.WriteAll(v.Cursor.GetSelection())
861 v.Cursor.DeleteSelection()
862 v.Cursor.ResetSelection()
864 messenger.Message("Cut selection")
867 PostActionCall("Cut")
875 // DuplicateLine duplicates the current line
876 func (v *View) DuplicateLine(usePlugin bool) bool {
877 if usePlugin && !PreActionCall("DuplicateLine") {
882 v.Buf.Insert(v.Cursor.Loc, "\n"+v.Buf.Line(v.Cursor.Y))
884 messenger.Message("Duplicated line")
887 PostActionCall("DuplicateLine")
892 // DeleteLine deletes the current line
893 func (v *View) DeleteLine(usePlugin bool) bool {
894 if usePlugin && !PreActionCall("DeleteLine") {
898 v.Cursor.SelectLine()
899 if !v.Cursor.HasSelection() {
902 v.Cursor.DeleteSelection()
903 v.Cursor.ResetSelection()
904 messenger.Message("Deleted line")
907 PostActionCall("DeleteLine")
912 // Paste whatever is in the system clipboard into the buffer
913 // Delete and paste if the user has a selection
914 func (v *View) Paste(usePlugin bool) bool {
915 if usePlugin && !PreActionCall("Paste") {
919 if v.Cursor.HasSelection() {
920 v.Cursor.DeleteSelection()
921 v.Cursor.ResetSelection()
923 clip, _ := clipboard.ReadAll()
924 v.Buf.Insert(v.Cursor.Loc, clip)
925 v.Cursor.Loc = v.Cursor.Loc.Move(Count(clip), v.Buf)
927 messenger.Message("Pasted clipboard")
930 PostActionCall("Paste")
935 // SelectAll selects the entire buffer
936 func (v *View) SelectAll(usePlugin bool) bool {
937 if usePlugin && !PreActionCall("SelectAll") {
941 v.Cursor.CurSelection[0] = v.Buf.Start()
942 v.Cursor.CurSelection[1] = v.Buf.End()
943 // Put the cursor at the beginning
948 PostActionCall("SelectAll")
953 // OpenFile opens a new file in the buffer
954 func (v *View) OpenFile(usePlugin bool) bool {
955 if usePlugin && !PreActionCall("OpenFile") {
959 if v.CanClose("Continue? (yes, no, save) ") {
960 filename, canceled := messenger.Prompt("File to open: ", "Open", FileCompletion)
964 home, _ := homedir.Dir()
965 filename = strings.Replace(filename, "~", home, 1)
966 file, err := ioutil.ReadFile(filename)
970 // File does not exist -- create an empty buffer with that name
971 buf = NewBuffer([]byte{}, filename)
973 buf = NewBuffer(file, filename)
978 PostActionCall("OpenFile")
985 // Start moves the viewport to the start of the buffer
986 func (v *View) Start(usePlugin bool) bool {
987 if usePlugin && !PreActionCall("Start") {
994 PostActionCall("Start")
999 // End moves the viewport to the end of the buffer
1000 func (v *View) End(usePlugin bool) bool {
1001 if usePlugin && !PreActionCall("End") {
1005 if v.height > v.Buf.NumLines {
1008 v.Topline = v.Buf.NumLines - v.height
1012 PostActionCall("End")
1017 // PageUp scrolls the view up a page
1018 func (v *View) PageUp(usePlugin bool) bool {
1019 if usePlugin && !PreActionCall("PageUp") {
1023 if v.Topline > v.height {
1024 v.ScrollUp(v.height)
1030 PostActionCall("PageUp")
1035 // PageDown scrolls the view down a page
1036 func (v *View) PageDown(usePlugin bool) bool {
1037 if usePlugin && !PreActionCall("PageDown") {
1041 if v.Buf.NumLines-(v.Topline+v.height) > v.height {
1042 v.ScrollDown(v.height)
1043 } else if v.Buf.NumLines >= v.height {
1044 v.Topline = v.Buf.NumLines - v.height
1048 PostActionCall("PageDown")
1053 // CursorPageUp places the cursor a page up
1054 func (v *View) CursorPageUp(usePlugin bool) bool {
1055 if usePlugin && !PreActionCall("CursorPageUp") {
1059 if v.Cursor.HasSelection() {
1060 v.Cursor.Loc = v.Cursor.CurSelection[0]
1061 v.Cursor.ResetSelection()
1063 v.Cursor.UpN(v.height)
1066 PostActionCall("CursorPageUp")
1071 // CursorPageDown places the cursor a page up
1072 func (v *View) CursorPageDown(usePlugin bool) bool {
1073 if usePlugin && !PreActionCall("CursorPageDown") {
1077 if v.Cursor.HasSelection() {
1078 v.Cursor.Loc = v.Cursor.CurSelection[1]
1079 v.Cursor.ResetSelection()
1081 v.Cursor.DownN(v.height)
1084 PostActionCall("CursorPageDown")
1089 // HalfPageUp scrolls the view up half a page
1090 func (v *View) HalfPageUp(usePlugin bool) bool {
1091 if usePlugin && !PreActionCall("HalfPageUp") {
1095 if v.Topline > v.height/2 {
1096 v.ScrollUp(v.height / 2)
1102 PostActionCall("HalfPageUp")
1107 // HalfPageDown scrolls the view down half a page
1108 func (v *View) HalfPageDown(usePlugin bool) bool {
1109 if usePlugin && !PreActionCall("HalfPageDown") {
1113 if v.Buf.NumLines-(v.Topline+v.height) > v.height/2 {
1114 v.ScrollDown(v.height / 2)
1116 if v.Buf.NumLines >= v.height {
1117 v.Topline = v.Buf.NumLines - v.height
1122 PostActionCall("HalfPageDown")
1127 // ToggleRuler turns line numbers off and on
1128 func (v *View) ToggleRuler(usePlugin bool) bool {
1129 if usePlugin && !PreActionCall("ToggleRuler") {
1133 if settings["ruler"] == false {
1134 settings["ruler"] = true
1135 messenger.Message("Enabled ruler")
1137 settings["ruler"] = false
1138 messenger.Message("Disabled ruler")
1142 PostActionCall("ToggleRuler")
1147 // JumpLine jumps to a line and moves the view accordingly.
1148 func (v *View) JumpLine(usePlugin bool) bool {
1149 if usePlugin && !PreActionCall("JumpLine") {
1153 // Prompt for line number
1154 linestring, canceled := messenger.Prompt("Jump to line # ", "LineNumber", NoCompletion)
1158 lineint, err := strconv.Atoi(linestring)
1159 lineint = lineint - 1 // fix offset
1161 messenger.Error(err) // return errors
1164 // Move cursor and view if possible.
1165 if lineint < v.Buf.NumLines && lineint >= 0 {
1167 v.Cursor.Y = lineint
1170 PostActionCall("JumpLine")
1174 messenger.Error("Only ", v.Buf.NumLines, " lines to jump")
1178 // ClearStatus clears the messenger bar
1179 func (v *View) ClearStatus(usePlugin bool) bool {
1180 if usePlugin && !PreActionCall("ClearStatus") {
1184 messenger.Message("")
1187 PostActionCall("ClearStatus")
1192 // ToggleHelp toggles the help screen
1193 func (v *View) ToggleHelp(usePlugin bool) bool {
1194 if usePlugin && !PreActionCall("ToggleHelp") {
1199 // Open the default help
1206 PostActionCall("ToggleHelp")
1211 // ShellMode opens a terminal to run a shell command
1212 func (v *View) ShellMode(usePlugin bool) bool {
1213 if usePlugin && !PreActionCall("ShellMode") {
1217 input, canceled := messenger.Prompt("$ ", "Shell", NoCompletion)
1219 // The true here is for openTerm to make the command interactive
1220 HandleShellCommand(input, true)
1222 PostActionCall("ShellMode")
1228 // CommandMode lets the user enter a command
1229 func (v *View) CommandMode(usePlugin bool) bool {
1230 if usePlugin && !PreActionCall("CommandMode") {
1234 input, canceled := messenger.Prompt("> ", "Command", CommandCompletion)
1236 HandleCommand(input)
1238 PostActionCall("CommandMode")
1245 // Quit quits the editor
1246 // This behavior needs to be changed and should really only quit the editor if this
1248 // However, since micro only supports one view for now, it doesn't really matter
1249 func (v *View) Quit(usePlugin bool) bool {
1250 if usePlugin && !PreActionCall("Quit") {
1254 // Make sure not to quit if there are unsaved changes
1255 if v.CanClose("Quit anyway? (yes, no, save) ") {
1257 if len(tabs[curTab].views) > 1 {
1258 v.splitNode.Delete()
1259 tabs[v.TabNum].Cleanup()
1260 tabs[v.TabNum].Resize()
1261 } else if len(tabs) > 1 {
1262 if len(tabs[v.TabNum].views) == 1 {
1263 tabs = tabs[:v.TabNum+copy(tabs[v.TabNum:], tabs[v.TabNum+1:])]
1264 for i, t := range tabs {
1267 if curTab >= len(tabs) {
1271 // CurView().Resize(screen.Size())
1272 CurView().ToggleTabbar()
1273 CurView().matches = Match(CurView())
1278 PostActionCall("Quit")
1287 PostActionCall("Quit")
1292 // AddTab adds a new tab with an empty buffer
1293 func (v *View) AddTab(usePlugin bool) bool {
1294 if usePlugin && !PreActionCall("AddTab") {
1298 tab := NewTabFromView(NewView(NewBuffer([]byte{}, "")))
1299 tab.SetNum(len(tabs))
1300 tabs = append(tabs, tab)
1303 for _, t := range tabs {
1304 for _, v := range t.views {
1311 PostActionCall("AddTab")
1316 // PreviousTab switches to the previous tab in the tab list
1317 func (v *View) PreviousTab(usePlugin bool) bool {
1318 if usePlugin && !PreActionCall("PreviousTab") {
1324 } else if curTab == 0 {
1325 curTab = len(tabs) - 1
1329 PostActionCall("PreviousTab")
1334 // NextTab switches to the next tab in the tab list
1335 func (v *View) NextTab(usePlugin bool) bool {
1336 if usePlugin && !PreActionCall("NextTab") {
1340 if curTab < len(tabs)-1 {
1342 } else if curTab == len(tabs)-1 {
1347 PostActionCall("NextTab")
1352 // NextSplit changes the view to the next split
1353 func (v *View) NextSplit(usePlugin bool) bool {
1354 if usePlugin && !PreActionCall("NextSplit") {
1359 if tab.curView < len(tab.views)-1 {
1366 PostActionCall("NextSplit")
1371 // PreviousSplit changes the view to the previous split
1372 func (v *View) PreviousSplit(usePlugin bool) bool {
1373 if usePlugin && !PreActionCall("PreviousSplit") {
1378 if tab.curView > 0 {
1381 tab.curView = len(tab.views) - 1
1385 PostActionCall("PreviousSplit")
1390 // None is no action
1392 if !PreActionCall("None") {
1396 PostActionCall("None")