Add the ability to close splits and change splits using the mouse

This commits adds split navigation with the mouse and the ability to
close splits. You can now also open a file directly with the hsplit
and vsplit commands.
This commit is contained in:
Zachary Yedidia 2016-07-01 18:12:37 -04:00
parent d2b11c2f98
commit 4a15a1d3c8
4 changed files with 112 additions and 13 deletions

View file

@ -915,11 +915,13 @@ func (v *View) OpenFile() bool {
filename = strings.Replace(filename, "~", home, 1)
file, err := ioutil.ReadFile(filename)
var buf *Buffer
if err != nil {
messenger.Error(err.Error())
return false
// File does not exist -- create an empty buffer with that name
buf = NewBuffer([]byte{}, filename)
} else {
buf = NewBuffer(file, filename)
}
buf := NewBuffer(file, filename)
v.OpenBuffer(buf)
return true
}
@ -1090,7 +1092,27 @@ func (v *View) Quit() bool {
// Make sure not to quit if there are unsaved changes
if v.CanClose("Quit anyway? (yes, no, save) ") {
v.CloseBuffer()
if len(tabs) > 1 {
if len(tabs[curTab].views) > 1 {
var view *View
if v.splitChild != nil {
view = v.splitChild
view.splitParent = v.splitParent
} else if v.splitParent != nil {
view = v.splitParent
v.splitParent.splitChild = nil
}
view.x, view.y = view.splitOrigPos[0], view.splitOrigPos[1]
view.widthPercent, view.heightPercent = view.splitOrigDimensions[0], view.splitOrigDimensions[1]
view.Resize(screen.Size())
if settings["syntax"].(bool) {
view.matches = Match(view)
}
tabs[curTab].views = tabs[curTab].views[:v.Num+copy(tabs[curTab].views[v.Num:], tabs[curTab].views[v.Num+1:])]
for i, v := range tabs[curTab].views {
v.Num = i
}
tabs[curTab].curView = view.Num
} else if len(tabs) > 1 {
if len(tabs[v.TabNum].views) == 1 {
tabs = tabs[:v.TabNum+copy(tabs[v.TabNum:], tabs[v.TabNum+1:])]
for i, t := range tabs {

View file

@ -2,11 +2,14 @@ package main
import (
"bytes"
"io/ioutil"
"os"
"os/exec"
"os/signal"
"regexp"
"strings"
"github.com/mitchellh/go-homedir"
)
var commands map[string]func([]string)
@ -63,11 +66,48 @@ func DefaultCommands() map[string]string {
}
}
// VSplit opens a vertical split with file given in the first argument
// If no file is given, it opens an empty buffer in a new split
func VSplit(args []string) {
CurView().VSplit()
if len(args) == 0 {
CurView().VSplit(NewBuffer([]byte{}, ""))
} else {
filename := args[0]
home, _ := homedir.Dir()
filename = strings.Replace(filename, "~", home, 1)
file, err := ioutil.ReadFile(filename)
var buf *Buffer
if err != nil {
// File does not exist -- create an empty buffer with that name
buf = NewBuffer([]byte{}, filename)
} else {
buf = NewBuffer(file, filename)
}
CurView().VSplit(buf)
}
}
// HSplit opens a horizontal split with file given in the first argument
// If no file is given, it opens an empty buffer in a new split
func HSplit(args []string) {
CurView().HSplit()
if len(args) == 0 {
CurView().HSplit(NewBuffer([]byte{}, ""))
} else {
filename := args[0]
home, _ := homedir.Dir()
filename = strings.Replace(filename, "~", home, 1)
file, err := ioutil.ReadFile(filename)
var buf *Buffer
if err != nil {
// File does not exist -- create an empty buffer with that name
buf = NewBuffer([]byte{}, filename)
} else {
buf = NewBuffer(file, filename)
}
CurView().HSplit(buf)
}
}
// Set sets an option

View file

@ -281,11 +281,17 @@ func main() {
case *tcell.EventMouse:
if e.Buttons() == tcell.Button1 {
_, h := screen.Size()
_, y := e.Position()
x, y := e.Position()
if y == h-1 && messenger.message != "" {
clipboard.WriteAll(messenger.message)
continue
}
for _, v := range tabs[curTab].views {
if x >= v.x && x < v.x+v.width && y >= v.y && y < v.y+v.height {
tabs[curTab].curView = v.Num
}
}
}
}

View file

@ -87,6 +87,11 @@ type View struct {
matches SyntaxMatches
// The matches from the last frame
lastMatches SyntaxMatches
splitParent *View
splitChild *View
splitOrigDimensions [2]int
splitOrigPos [2]int
}
// NewView returns a new fullscreen view
@ -222,32 +227,56 @@ func (v *View) ReOpen() {
}
}
func (v *View) HSplit() bool {
// HSplit opens a horizontal split with the given buffer
func (v *View) HSplit(buf *Buffer) bool {
origDimensions := [2]int{v.widthPercent, v.heightPercent}
origPos := [2]int{v.x, v.y}
v.heightPercent /= 2
v.Resize(screen.Size())
newView := NewViewWidthHeight(NewBuffer([]byte{}, ""), v.widthPercent, v.heightPercent)
newView := NewViewWidthHeight(buf, v.widthPercent, v.heightPercent)
v.splitOrigDimensions = origDimensions
v.splitOrigPos = origPos
newView.splitOrigDimensions = origDimensions
newView.splitOrigPos = origPos
newView.TabNum = v.TabNum
newView.y = v.y + v.height + 1
newView.x = v.x
tab := tabs[v.TabNum]
tab.curView++
newView.Num = len(tab.views)
newView.splitParent = v
v.splitChild = newView
tab.views = append(tab.views, newView)
return false
}
func (v *View) VSplit() bool {
// VSplit opens a vertical split with the given buffer
func (v *View) VSplit(buf *Buffer) bool {
origDimensions := [2]int{v.widthPercent, v.heightPercent}
origPos := [2]int{v.x, v.y}
v.widthPercent /= 2
v.Resize(screen.Size())
newView := NewViewWidthHeight(NewBuffer([]byte{}, ""), v.widthPercent, v.heightPercent)
newView := NewViewWidthHeight(buf, v.widthPercent, v.heightPercent)
v.splitOrigDimensions = origDimensions
v.splitOrigPos = origPos
newView.splitOrigDimensions = origDimensions
newView.splitOrigPos = origPos
newView.TabNum = v.TabNum
newView.y = v.y
newView.x = v.x + v.width
tab := tabs[v.TabNum]
tab.curView++
newView.Num = len(tab.views)
newView.splitParent = v
v.splitChild = newView
tab.views = append(tab.views, newView)
return false
}
@ -638,7 +667,7 @@ func (v *View) DisplayView() {
lineStyle = highlightStyle
}
if settings["cursorline"].(bool) && !v.Cursor.HasSelection() && v.Cursor.Y == lineN+v.Topline {
if settings["cursorline"].(bool) && tabs[curTab].curView == v.Num && !v.Cursor.HasSelection() && v.Cursor.Y == lineN+v.Topline {
if style, ok := colorscheme["cursor-line"]; ok {
fg, _, _ := style.Decompose()
lineStyle = lineStyle.Background(fg)
@ -742,7 +771,9 @@ func (v *View) DisplayCursor() {
// Display renders the view, the cursor, and statusline
func (v *View) Display() {
v.DisplayView()
v.DisplayCursor()
if v.Num == tabs[curTab].curView {
v.DisplayCursor()
}
if settings["statusline"].(bool) {
v.sline.Display()
}