// Syntax highlighting matches
matches SyntaxMatches
- // The matches from the last frame
- lastMatches SyntaxMatches
splitNode *LeafNode
}
// 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
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++
}
}
+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
// 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" {
+ } else if char == 's' {
v.Save(true)
return true
}
v.leftCol = 0
v.Cursor.ResetSelection()
v.Relocate()
+ v.Center(false)
v.messages = make(map[string][]GutterMessage)
v.matches = Match(v)
// 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()
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
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)
}
}
}
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
} 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 {
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)
}
}
if relocate {
v.Relocate()
}
- if settings["syntax"].(bool) {
+ if v.Buf.Settings["syntax"].(bool) {
v.matches = Match(v)
}
}
// 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 {
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
}
}
}
- if settings["ruler"] == true {
+ if v.Buf.Settings["ruler"] == true {
// Write the line number
lineNumStyle := defStyle
if style, ok := colorscheme["line-number"]; ok {
lineNumStyle = style
}
if style, ok := colorscheme["current-line-number"]; ok {
- if curLineN == v.Cursor.Y {
+ if curLineN == v.Cursor.Y && tabs[curTab].curView == v.Num && !v.Cursor.HasSelection() {
lineNumStyle = style
}
}
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]
}
// 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)
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 {
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)
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++ {