X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=cmd%2Fmicro%2Fview.go;h=996ac8bdd39cde4e67e443c5fbc07f2f34453485;hb=6721ec8e7dc04d074661882186d72652cd2e5c34;hp=055911bc318715c8d8314177581885112d015d8d;hpb=1e26aaed3cca321845b8a7ceb77e571fc40e275c;p=micro.git diff --git a/cmd/micro/view.go b/cmd/micro/view.go index 055911bc..996ac8bd 100644 --- a/cmd/micro/view.go +++ b/cmd/micro/view.go @@ -77,8 +77,6 @@ type View struct { // Syntax highlighting matches matches SyntaxMatches - // The matches from the last frame - lastMatches SyntaxMatches splitNode *LeafNode } @@ -86,11 +84,11 @@ type View struct { // NewView returns a new fullscreen view func NewView(buf *Buffer) *View { screenW, screenH := screen.Size() - return NewViewWidthHeight(buf, screenW, screenH-1) + return NewViewWidthHeight(buf, screenW, screenH) } -// NewViewWidthHeight returns a new view with the specified width and height percentages -// Note that w and h are percentages not actual values +// NewViewWidthHeight returns a new view with the specified width and height +// Note that w and h are raw column and row values func NewViewWidthHeight(buf *Buffer, w, h int) *View { v := new(View) @@ -109,15 +107,23 @@ func NewViewWidthHeight(buf *Buffer, w, h int) *View { view: v, } - if settings["statusline"].(bool) { + if v.Buf.Settings["statusline"].(bool) { v.height-- } + for _, pl := range loadedPlugins { + _, err := Call(pl+".onViewOpen", v) + if err != nil && !strings.HasPrefix(err.Error(), "function does not exist") { + TermMessage(err) + continue + } + } + return v } func (v *View) ToggleStatusLine() { - if settings["statusline"].(bool) { + if v.Buf.Settings["statusline"].(bool) { v.height-- } else { v.height++ @@ -139,6 +145,20 @@ func (v *View) ToggleTabbar() { } } +func (v *View) paste(clip string) { + leadingWS := GetLeadingWhitespace(v.Buf.Line(v.Cursor.Y)) + + if v.Cursor.HasSelection() { + v.Cursor.DeleteSelection() + v.Cursor.ResetSelection() + } + clip = strings.Replace(clip, "\n", "\n"+leadingWS, -1) + v.Buf.Insert(v.Cursor.Loc, clip) + v.Cursor.Loc = v.Cursor.Loc.Move(Count(clip), v.Buf) + v.freshClip = false + messenger.Message("Pasted clipboard") +} + // ScrollUp scrolls the view up n lines (if possible) func (v *View) ScrollUp(n int) { // Try to scroll by n but if it would overflow, scroll by 1 @@ -163,14 +183,14 @@ func (v *View) ScrollDown(n int) { // If there are unsaved changes, the user will be asked if the view can be closed // causing them to lose the unsaved changes // The message is what to print after saying "You have unsaved changes. " -func (v *View) CanClose(msg string) bool { +func (v *View) CanClose(msg string, responses ...rune) bool { if v.Buf.IsModified { - quit, canceled := messenger.Prompt("You have unsaved changes. "+msg, "Unsaved", NoCompletion) + char, canceled := messenger.LetterPrompt("You have unsaved changes. "+msg, responses...) if !canceled { - if strings.ToLower(quit) == "yes" || strings.ToLower(quit) == "y" { + if char == 'y' { return true - } else if strings.ToLower(quit) == "save" || strings.ToLower(quit) == "s" { - v.Save() + } else if char == 's' { + v.Save(true) return true } } @@ -191,6 +211,7 @@ func (v *View) OpenBuffer(buf *Buffer) { v.leftCol = 0 v.Cursor.ResetSelection() v.Relocate() + v.Center(false) v.messages = make(map[string][]GutterMessage) v.matches = Match(v) @@ -210,7 +231,7 @@ func (v *View) CloseBuffer() { // ReOpen reloads the current buffer func (v *View) ReOpen() { - if v.CanClose("Continue? (yes, no, save) ") { + if v.CanClose("Continue? (y,n,s) ", 'y', 'n', 's') { screen.Clear() v.Buf.ReOpen() v.Relocate() @@ -237,7 +258,7 @@ func (v *View) VSplit(buf *Buffer) bool { func (v *View) Relocate() bool { ret := false cy := v.Cursor.Y - scrollmargin := int(settings["scrollmargin"].(float64)) + scrollmargin := int(v.Buf.Settings["scrollmargin"].(float64)) if cy < v.Topline+scrollmargin && cy > scrollmargin-1 { v.Topline = cy - scrollmargin ret = true @@ -314,7 +335,7 @@ func (v *View) HandleEvent(event tcell.Event) { v.Cursor.Right() for _, pl := range loadedPlugins { - _, err := Call(pl+".onRune", []string{string(e.Rune())}) + _, err := Call(pl+".onRune", string(e.Rune()), v) if err != nil && !strings.HasPrefix(err.Error(), "function does not exist") { TermMessage(err) } @@ -330,21 +351,31 @@ func (v *View) HandleEvent(event tcell.Event) { if e.Modifiers() == key.modifiers { relocate = false for _, action := range actions { - relocate = action(v) || relocate + relocate = action(v, true) || relocate } } } } } case *tcell.EventPaste: + if !PreActionCall("Paste", v) { + break + } + + leadingWS := GetLeadingWhitespace(v.Buf.Line(v.Cursor.Y)) + if v.Cursor.HasSelection() { v.Cursor.DeleteSelection() v.Cursor.ResetSelection() } clip := e.Text() + clip = strings.Replace(clip, "\n", "\n"+leadingWS, -1) v.Buf.Insert(v.Cursor.Loc, clip) v.Cursor.Loc = v.Cursor.Loc.Move(Count(clip), v.Buf) v.freshClip = false + messenger.Message("Pasted clipboard") + + PostActionCall("Paste", v) case *tcell.EventMouse: x, y := e.Position() x -= v.lineNumOffset - v.leftCol + v.x @@ -383,8 +414,8 @@ func (v *View) HandleEvent(event tcell.Event) { v.lastClickTime = time.Now() v.Cursor.OrigSelection[0] = v.Cursor.Loc - v.Cursor.CurSelection[0] = v.Cursor.Loc - v.Cursor.CurSelection[1] = v.Cursor.Loc + v.Cursor.SetSelectionStart(v.Cursor.Loc) + v.Cursor.SetSelectionEnd(v.Cursor.Loc) } v.mouseReleased = false } else if !v.mouseReleased { @@ -394,9 +425,13 @@ func (v *View) HandleEvent(event tcell.Event) { } else if v.doubleClick { v.Cursor.AddWordToSelection() } else { - v.Cursor.CurSelection[1] = v.Cursor.Loc + v.Cursor.SetSelectionEnd(v.Cursor.Loc) } } + case tcell.Button2: + // Middle mouse button was clicked, + // We should paste primary + v.PastePrimary(true) case tcell.ButtonNone: // Mouse event with no click if !v.mouseReleased { @@ -410,17 +445,17 @@ func (v *View) HandleEvent(event tcell.Event) { if !v.doubleClick && !v.tripleClick { v.MoveToMouseClick(x, y) - v.Cursor.CurSelection[1] = v.Cursor.Loc + v.Cursor.SetSelectionEnd(v.Cursor.Loc) } v.mouseReleased = true } case tcell.WheelUp: // Scroll up - scrollspeed := int(settings["scrollspeed"].(float64)) + scrollspeed := int(v.Buf.Settings["scrollspeed"].(float64)) v.ScrollUp(scrollspeed) case tcell.WheelDown: // Scroll down - scrollspeed := int(settings["scrollspeed"].(float64)) + scrollspeed := int(v.Buf.Settings["scrollspeed"].(float64)) v.ScrollDown(scrollspeed) } } @@ -428,7 +463,7 @@ func (v *View) HandleEvent(event tcell.Event) { if relocate { v.Relocate() } - if settings["syntax"].(bool) { + if v.Buf.Settings["syntax"].(bool) { v.matches = Match(v) } } @@ -464,6 +499,20 @@ func (v *View) ClearAllGutterMessages() { } } +// Opens the given help page in a new horizontal split +func (v *View) openHelp(helpPage string) { + if v.Help { + helpBuffer := NewBuffer([]byte(helpPages[helpPage]), helpPage+".md") + helpBuffer.Name = "Help" + v.OpenBuffer(helpBuffer) + } else { + helpBuffer := NewBuffer([]byte(helpPages[helpPage]), helpPage+".md") + helpBuffer.Name = "Help" + v.HSplit(helpBuffer) + CurView().Help = true + } +} + func (v *View) drawCell(x, y int, ch rune, combc []rune, style tcell.Style) { if x >= v.x && x < v.x+v.width && y >= v.y && y < v.y+v.height { screen.SetContent(x, y, ch, combc, style) @@ -480,7 +529,7 @@ func (v *View) DisplayView() { // We are going to have to offset by that amount maxLineLength := len(strconv.Itoa(v.Buf.NumLines)) - if settings["ruler"] == true { + if v.Buf.Settings["ruler"] == true { // + 1 for the little space after the line number v.lineNumOffset = maxLineLength + 1 } else { @@ -559,7 +608,7 @@ func (v *View) DisplayView() { screenX++ v.drawCell(screenX, screenY, '>', nil, gutterStyle) screenX++ - if v.Cursor.Y == curLineN { + if v.Cursor.Y == curLineN && !messenger.hasPrompt { messenger.Message(msg.msg) messenger.gutterMessage = true } @@ -579,15 +628,16 @@ func (v *View) DisplayView() { } } - if settings["ruler"] == true { + if v.Buf.Settings["ruler"] == true { // Write the line number lineNumStyle := defStyle - curLineNumStyle := defStyle if style, ok := colorscheme["line-number"]; ok { lineNumStyle = style } if style, ok := colorscheme["current-line-number"]; ok { - curLineNumStyle = style + if curLineN == v.Cursor.Y && tabs[curTab].curView == v.Num && !v.Cursor.HasSelection() { + lineNumStyle = style + } } lineNum := strconv.Itoa(curLineN + 1) @@ -599,11 +649,7 @@ func (v *View) DisplayView() { } // Write the actual line number for _, ch := range lineNum { - if curLineN == v.Cursor.Y { - v.drawCell(screenX, screenY, ch, nil, curLineNumStyle) - } else { - v.drawCell(screenX, screenY, ch, nil, lineNumStyle) - } + v.drawCell(screenX, screenY, ch, nil, lineNumStyle) screenX++ } @@ -613,10 +659,11 @@ func (v *View) DisplayView() { } // Now we actually draw the line - for colN, ch := range line { + colN := 0 + for _, ch := range line { lineStyle := defStyle - if settings["syntax"].(bool) { + if v.Buf.Settings["syntax"].(bool) { // Syntax highlighting is enabled highlightStyle = v.matches[viewLine][colN] } @@ -636,7 +683,7 @@ func (v *View) DisplayView() { // We need to display the background of the linestyle with the correct color if cursorline is enabled // and this is the current view and there is no selection on this line and the cursor is on this line - if settings["cursorline"].(bool) && tabs[curTab].curView == v.Num && !v.Cursor.HasSelection() && v.Cursor.Y == curLineN { + if v.Buf.Settings["cursorline"].(bool) && tabs[curTab].curView == v.Num && !v.Cursor.HasSelection() && v.Cursor.Y == curLineN { if style, ok := colorscheme["cursor-line"]; ok { fg, _, _ := style.Decompose() lineStyle = lineStyle.Background(fg) @@ -662,19 +709,19 @@ func (v *View) DisplayView() { lineIndentStyle = style } } - if settings["cursorline"].(bool) && tabs[curTab].curView == v.Num && !v.Cursor.HasSelection() && v.Cursor.Y == curLineN { + if v.Buf.Settings["cursorline"].(bool) && tabs[curTab].curView == v.Num && !v.Cursor.HasSelection() && v.Cursor.Y == curLineN { if style, ok := colorscheme["cursor-line"]; ok { fg, _, _ := style.Decompose() lineIndentStyle = lineIndentStyle.Background(fg) } } // Here we get the indent char - indentChar := []rune(settings["indentchar"].(string)) + indentChar := []rune(v.Buf.Settings["indentchar"].(string)) if screenX-v.x-v.leftCol >= v.lineNumOffset { v.drawCell(screenX-v.leftCol, screenY, indentChar[0], nil, lineIndentStyle) } // Now the tab has to be displayed as a bunch of spaces - tabSize := int(settings["tabsize"].(float64)) + tabSize := int(v.Buf.Settings["tabsize"].(float64)) for i := 0; i < tabSize-1; i++ { screenX++ if screenX-v.x-v.leftCol >= v.lineNumOffset { @@ -698,6 +745,7 @@ func (v *View) DisplayView() { } charNum = charNum.Move(1, v.Buf) screenX++ + colN++ } // Here we are at a newline @@ -720,7 +768,7 @@ func (v *View) DisplayView() { for i := 0; i < v.width; i++ { lineStyle := defStyle - if settings["cursorline"].(bool) && tabs[curTab].curView == v.Num && !v.Cursor.HasSelection() && v.Cursor.Y == curLineN { + if v.Buf.Settings["cursorline"].(bool) && tabs[curTab].curView == v.Num && !v.Cursor.HasSelection() && v.Cursor.Y == curLineN { if style, ok := colorscheme["cursor-line"]; ok { fg, _, _ := style.Decompose() lineStyle = lineStyle.Background(fg) @@ -750,7 +798,7 @@ func (v *View) Display() { v.DisplayCursor() } _, screenH := screen.Size() - if settings["statusline"].(bool) { + if v.Buf.Settings["statusline"].(bool) { v.sline.Display() } else if (v.y + v.height) != screenH-1 { for x := 0; x < v.width; x++ {