mirror of
https://github.com/zyedidia/micro
synced 2024-11-05 17:41:24 +00:00
Add savecursor
option
This adds the `savecursor` option which will remember where the cursor was when the file was closed and put it back when the file is opened again. The option is off by default so that people aren't confused as to why the cursor isn't at the start of a file when they open it. This commit also adds a more general ability to serialize a buffer so various components can be saved (which could also be useful for persistent undo). Fixes #107
This commit is contained in:
parent
96c7bc67c0
commit
a92a7dc4e6
11 changed files with 352 additions and 270 deletions
|
@ -336,7 +336,7 @@ func DefaultBindings() map[string]string {
|
|||
// CursorUp moves the cursor up
|
||||
func (v *View) CursorUp() bool {
|
||||
if v.Cursor.HasSelection() {
|
||||
v.Cursor.SetLoc(v.Cursor.curSelection[0])
|
||||
v.Cursor.SetLoc(v.Cursor.CurSelection[0])
|
||||
v.Cursor.ResetSelection()
|
||||
}
|
||||
v.Cursor.Up()
|
||||
|
@ -346,7 +346,7 @@ func (v *View) CursorUp() bool {
|
|||
// CursorDown moves the cursor down
|
||||
func (v *View) CursorDown() bool {
|
||||
if v.Cursor.HasSelection() {
|
||||
v.Cursor.SetLoc(v.Cursor.curSelection[1])
|
||||
v.Cursor.SetLoc(v.Cursor.CurSelection[1])
|
||||
v.Cursor.ResetSelection()
|
||||
}
|
||||
v.Cursor.Down()
|
||||
|
@ -356,7 +356,7 @@ func (v *View) CursorDown() bool {
|
|||
// CursorLeft moves the cursor left
|
||||
func (v *View) CursorLeft() bool {
|
||||
if v.Cursor.HasSelection() {
|
||||
v.Cursor.SetLoc(v.Cursor.curSelection[0])
|
||||
v.Cursor.SetLoc(v.Cursor.CurSelection[0])
|
||||
v.Cursor.ResetSelection()
|
||||
} else {
|
||||
v.Cursor.Left()
|
||||
|
@ -367,7 +367,7 @@ func (v *View) CursorLeft() bool {
|
|||
// CursorRight moves the cursor right
|
||||
func (v *View) CursorRight() bool {
|
||||
if v.Cursor.HasSelection() {
|
||||
v.Cursor.SetLoc(v.Cursor.curSelection[1] - 1)
|
||||
v.Cursor.SetLoc(v.Cursor.CurSelection[1] - 1)
|
||||
v.Cursor.ResetSelection()
|
||||
} else {
|
||||
v.Cursor.Right()
|
||||
|
@ -391,7 +391,7 @@ func (v *View) WordLeft() bool {
|
|||
func (v *View) SelectUp() bool {
|
||||
loc := v.Cursor.Loc()
|
||||
if !v.Cursor.HasSelection() {
|
||||
v.Cursor.origSelection[0] = loc
|
||||
v.Cursor.OrigSelection[0] = loc
|
||||
}
|
||||
v.Cursor.Up()
|
||||
v.Cursor.SelectTo(v.Cursor.Loc())
|
||||
|
@ -402,7 +402,7 @@ func (v *View) SelectUp() bool {
|
|||
func (v *View) SelectDown() bool {
|
||||
loc := v.Cursor.Loc()
|
||||
if !v.Cursor.HasSelection() {
|
||||
v.Cursor.origSelection[0] = loc
|
||||
v.Cursor.OrigSelection[0] = loc
|
||||
}
|
||||
v.Cursor.Down()
|
||||
v.Cursor.SelectTo(v.Cursor.Loc())
|
||||
|
@ -417,7 +417,7 @@ func (v *View) SelectLeft() bool {
|
|||
loc = count
|
||||
}
|
||||
if !v.Cursor.HasSelection() {
|
||||
v.Cursor.origSelection[0] = loc
|
||||
v.Cursor.OrigSelection[0] = loc
|
||||
}
|
||||
v.Cursor.Left()
|
||||
v.Cursor.SelectTo(v.Cursor.Loc())
|
||||
|
@ -432,7 +432,7 @@ func (v *View) SelectRight() bool {
|
|||
loc = count
|
||||
}
|
||||
if !v.Cursor.HasSelection() {
|
||||
v.Cursor.origSelection[0] = loc
|
||||
v.Cursor.OrigSelection[0] = loc
|
||||
}
|
||||
v.Cursor.Right()
|
||||
v.Cursor.SelectTo(v.Cursor.Loc())
|
||||
|
@ -443,7 +443,7 @@ func (v *View) SelectRight() bool {
|
|||
func (v *View) SelectWordRight() bool {
|
||||
loc := v.Cursor.Loc()
|
||||
if !v.Cursor.HasSelection() {
|
||||
v.Cursor.origSelection[0] = loc
|
||||
v.Cursor.OrigSelection[0] = loc
|
||||
}
|
||||
v.Cursor.WordRight()
|
||||
v.Cursor.SelectTo(v.Cursor.Loc())
|
||||
|
@ -454,7 +454,7 @@ func (v *View) SelectWordRight() bool {
|
|||
func (v *View) SelectWordLeft() bool {
|
||||
loc := v.Cursor.Loc()
|
||||
if !v.Cursor.HasSelection() {
|
||||
v.Cursor.origSelection[0] = loc
|
||||
v.Cursor.OrigSelection[0] = loc
|
||||
}
|
||||
v.Cursor.WordLeft()
|
||||
v.Cursor.SelectTo(v.Cursor.Loc())
|
||||
|
@ -477,7 +477,7 @@ func (v *View) EndOfLine() bool {
|
|||
func (v *View) SelectToStartOfLine() bool {
|
||||
loc := v.Cursor.Loc()
|
||||
if !v.Cursor.HasSelection() {
|
||||
v.Cursor.origSelection[0] = loc
|
||||
v.Cursor.OrigSelection[0] = loc
|
||||
}
|
||||
v.Cursor.Start()
|
||||
v.Cursor.SelectTo(v.Cursor.Loc())
|
||||
|
@ -488,7 +488,7 @@ func (v *View) SelectToStartOfLine() bool {
|
|||
func (v *View) SelectToEndOfLine() bool {
|
||||
loc := v.Cursor.Loc()
|
||||
if !v.Cursor.HasSelection() {
|
||||
v.Cursor.origSelection[0] = loc
|
||||
v.Cursor.OrigSelection[0] = loc
|
||||
}
|
||||
v.Cursor.End()
|
||||
v.Cursor.SelectTo(v.Cursor.Loc())
|
||||
|
@ -497,8 +497,8 @@ func (v *View) SelectToEndOfLine() bool {
|
|||
|
||||
// CursorStart moves the cursor to the start of the buffer
|
||||
func (v *View) CursorStart() bool {
|
||||
v.Cursor.x = 0
|
||||
v.Cursor.y = 0
|
||||
v.Cursor.X = 0
|
||||
v.Cursor.Y = 0
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -512,7 +512,7 @@ func (v *View) CursorEnd() bool {
|
|||
func (v *View) SelectToStart() bool {
|
||||
loc := v.Cursor.Loc()
|
||||
if !v.Cursor.HasSelection() {
|
||||
v.Cursor.origSelection[0] = loc
|
||||
v.Cursor.OrigSelection[0] = loc
|
||||
}
|
||||
v.CursorStart()
|
||||
v.Cursor.SelectTo(0)
|
||||
|
@ -523,7 +523,7 @@ func (v *View) SelectToStart() bool {
|
|||
func (v *View) SelectToEnd() bool {
|
||||
loc := v.Cursor.Loc()
|
||||
if !v.Cursor.HasSelection() {
|
||||
v.Cursor.origSelection[0] = loc
|
||||
v.Cursor.OrigSelection[0] = loc
|
||||
}
|
||||
v.CursorEnd()
|
||||
v.Cursor.SelectTo(v.Buf.Len())
|
||||
|
@ -550,7 +550,7 @@ func (v *View) InsertEnter() bool {
|
|||
}
|
||||
|
||||
v.Buf.Insert(v.Cursor.Loc(), "\n")
|
||||
ws := GetLeadingWhitespace(v.Buf.Lines[v.Cursor.y])
|
||||
ws := GetLeadingWhitespace(v.Buf.Lines[v.Cursor.Y])
|
||||
v.Cursor.Right()
|
||||
|
||||
if settings["autoindent"].(bool) {
|
||||
|
@ -559,7 +559,7 @@ func (v *View) InsertEnter() bool {
|
|||
v.Cursor.Right()
|
||||
}
|
||||
}
|
||||
v.Cursor.lastVisualX = v.Cursor.GetVisualX()
|
||||
v.Cursor.LastVisualX = v.Cursor.GetVisualX()
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -579,25 +579,25 @@ func (v *View) Backspace() bool {
|
|||
// If the user is using spaces instead of tabs and they are deleting
|
||||
// whitespace at the start of the line, we should delete as if its a
|
||||
// tab (tabSize number of spaces)
|
||||
lineStart := v.Buf.Lines[v.Cursor.y][:v.Cursor.x]
|
||||
lineStart := v.Buf.Lines[v.Cursor.Y][:v.Cursor.X]
|
||||
tabSize := int(settings["tabsize"].(float64))
|
||||
if settings["tabstospaces"].(bool) && IsSpaces(lineStart) && len(lineStart) != 0 && len(lineStart)%tabSize == 0 {
|
||||
loc := v.Cursor.Loc()
|
||||
v.Cursor.SetLoc(loc - tabSize)
|
||||
cx, cy := v.Cursor.x, v.Cursor.y
|
||||
cx, cy := v.Cursor.X, v.Cursor.Y
|
||||
v.Cursor.SetLoc(loc)
|
||||
v.Buf.Remove(loc-tabSize, loc)
|
||||
v.Cursor.x, v.Cursor.y = cx, cy
|
||||
v.Cursor.X, v.Cursor.Y = cx, cy
|
||||
} else {
|
||||
v.Cursor.Left()
|
||||
cx, cy := v.Cursor.x, v.Cursor.y
|
||||
cx, cy := v.Cursor.X, v.Cursor.Y
|
||||
v.Cursor.Right()
|
||||
loc := v.Cursor.Loc()
|
||||
v.Buf.Remove(loc-1, loc)
|
||||
v.Cursor.x, v.Cursor.y = cx, cy
|
||||
v.Cursor.X, v.Cursor.Y = cx, cy
|
||||
}
|
||||
}
|
||||
v.Cursor.lastVisualX = v.Cursor.GetVisualX()
|
||||
v.Cursor.LastVisualX = v.Cursor.GetVisualX()
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -663,9 +663,9 @@ func (v *View) Save() bool {
|
|||
// Find opens a prompt and searches forward for the input
|
||||
func (v *View) Find() bool {
|
||||
if v.Cursor.HasSelection() {
|
||||
searchStart = v.Cursor.curSelection[1]
|
||||
searchStart = v.Cursor.CurSelection[1]
|
||||
} else {
|
||||
searchStart = ToCharPos(v.Cursor.x, v.Cursor.y, v.Buf)
|
||||
searchStart = ToCharPos(v.Cursor.X, v.Cursor.Y, v.Buf)
|
||||
}
|
||||
BeginSearch()
|
||||
return true
|
||||
|
@ -674,9 +674,9 @@ func (v *View) Find() bool {
|
|||
// FindNext searches forwards for the last used search term
|
||||
func (v *View) FindNext() bool {
|
||||
if v.Cursor.HasSelection() {
|
||||
searchStart = v.Cursor.curSelection[1]
|
||||
searchStart = v.Cursor.CurSelection[1]
|
||||
} else {
|
||||
searchStart = ToCharPos(v.Cursor.x, v.Cursor.y, v.Buf)
|
||||
searchStart = ToCharPos(v.Cursor.X, v.Cursor.Y, v.Buf)
|
||||
}
|
||||
messenger.Message("Finding: " + lastSearch)
|
||||
Search(lastSearch, v, true)
|
||||
|
@ -686,9 +686,9 @@ func (v *View) FindNext() bool {
|
|||
// FindPrevious searches backwards for the last used search term
|
||||
func (v *View) FindPrevious() bool {
|
||||
if v.Cursor.HasSelection() {
|
||||
searchStart = v.Cursor.curSelection[0]
|
||||
searchStart = v.Cursor.CurSelection[0]
|
||||
} else {
|
||||
searchStart = ToCharPos(v.Cursor.x, v.Cursor.y, v.Buf)
|
||||
searchStart = ToCharPos(v.Cursor.X, v.Cursor.Y, v.Buf)
|
||||
}
|
||||
messenger.Message("Finding: " + lastSearch)
|
||||
Search(lastSearch, v, false)
|
||||
|
@ -759,7 +759,7 @@ func (v *View) Cut() bool {
|
|||
// DuplicateLine duplicates the current line
|
||||
func (v *View) DuplicateLine() bool {
|
||||
v.Cursor.End()
|
||||
v.Buf.Insert(v.Cursor.Loc(), "\n"+v.Buf.Lines[v.Cursor.y])
|
||||
v.Buf.Insert(v.Cursor.Loc(), "\n"+v.Buf.Lines[v.Cursor.Y])
|
||||
v.Cursor.Right()
|
||||
messenger.Message("Duplicated line")
|
||||
return true
|
||||
|
@ -782,11 +782,11 @@ func (v *View) Paste() bool {
|
|||
|
||||
// SelectAll selects the entire buffer
|
||||
func (v *View) SelectAll() bool {
|
||||
v.Cursor.curSelection[0] = 0
|
||||
v.Cursor.curSelection[1] = v.Buf.Len()
|
||||
v.Cursor.CurSelection[0] = 0
|
||||
v.Cursor.CurSelection[1] = v.Buf.Len()
|
||||
// Put the cursor at the beginning
|
||||
v.Cursor.x = 0
|
||||
v.Cursor.y = 0
|
||||
v.Cursor.X = 0
|
||||
v.Cursor.Y = 0
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -896,8 +896,8 @@ func (v *View) JumpLine() bool {
|
|||
}
|
||||
// Move cursor and view if possible.
|
||||
if lineint < v.Buf.NumLines {
|
||||
v.Cursor.x = 0
|
||||
v.Cursor.y = lineint
|
||||
v.Cursor.X = 0
|
||||
v.Cursor.Y = lineint
|
||||
return true
|
||||
}
|
||||
messenger.Error("Only ", v.Buf.NumLines, " lines to jump")
|
||||
|
@ -954,6 +954,7 @@ func (v *View) Quit() bool {
|
|||
}
|
||||
// Make sure not to quit if there are unsaved changes
|
||||
if views[mainView].CanClose("Quit anyway? (yes, no, save) ") {
|
||||
views[mainView].CloseBuffer()
|
||||
screen.Fini()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/vinzmay/go-rope"
|
||||
"encoding/gob"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/vinzmay/go-rope"
|
||||
)
|
||||
|
||||
// Buffer stores the text for files that are loaded into the text editor
|
||||
|
@ -48,18 +52,46 @@ func NewBuffer(txt, path string) *Buffer {
|
|||
b.Path = path
|
||||
b.Name = path
|
||||
|
||||
// Put the cursor at the first spot
|
||||
b.Cursor = Cursor{
|
||||
x: 0,
|
||||
y: 0,
|
||||
Buf: b,
|
||||
}
|
||||
|
||||
b.EventHandler = NewEventHandler(b)
|
||||
|
||||
b.Update()
|
||||
b.UpdateRules()
|
||||
|
||||
if _, err := os.Stat(configDir + "/buffers/"); os.IsNotExist(err) {
|
||||
os.Mkdir(configDir+"/buffers/", os.ModePerm)
|
||||
}
|
||||
|
||||
if settings["savecursor"].(bool) {
|
||||
absPath, _ := filepath.Abs(b.Path)
|
||||
file, err := os.Open(configDir + "/buffers/" + EscapePath(absPath))
|
||||
if err == nil {
|
||||
var cursor Cursor
|
||||
decoder := gob.NewDecoder(file)
|
||||
err = decoder.Decode(&cursor)
|
||||
if err != nil {
|
||||
TermMessage(err.Error())
|
||||
}
|
||||
b.Cursor = cursor
|
||||
b.Cursor.buf = b
|
||||
b.Cursor.Clamp()
|
||||
} else {
|
||||
// Put the cursor at the first spot
|
||||
b.Cursor = Cursor{
|
||||
X: 0,
|
||||
Y: 0,
|
||||
buf: b,
|
||||
}
|
||||
}
|
||||
file.Close()
|
||||
} else {
|
||||
// Put the cursor at the first spot
|
||||
b.Cursor = Cursor{
|
||||
X: 0,
|
||||
Y: 0,
|
||||
buf: b,
|
||||
}
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
|
@ -87,6 +119,21 @@ func (b *Buffer) Save() error {
|
|||
return b.SaveAs(b.Path)
|
||||
}
|
||||
|
||||
// Serialize serializes the buffer to configDir/buffers
|
||||
func (b *Buffer) Serialize() error {
|
||||
if settings["savecursor"].(bool) {
|
||||
absPath, _ := filepath.Abs(b.Path)
|
||||
file, err := os.Create(configDir + "/buffers/" + EscapePath(absPath))
|
||||
if err == nil {
|
||||
enc := gob.NewEncoder(file)
|
||||
err = enc.Encode(b.Cursor)
|
||||
}
|
||||
file.Close()
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SaveAs saves the buffer to a specified path (filename), creating the file if it does not exist
|
||||
func (b *Buffer) SaveAs(filename string) error {
|
||||
b.UpdateRules()
|
||||
|
@ -94,6 +141,7 @@ func (b *Buffer) SaveAs(filename string) error {
|
|||
err := ioutil.WriteFile(filename, data, 0644)
|
||||
if err == nil {
|
||||
b.IsModified = false
|
||||
err = b.Serialize()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -172,7 +172,7 @@ func HandleCommand(input string) {
|
|||
choice, canceled := messenger.YesNoPrompt("Perform replacement? (y,n)")
|
||||
if canceled {
|
||||
if view.Cursor.HasSelection() {
|
||||
view.Cursor.SetLoc(view.Cursor.curSelection[0])
|
||||
view.Cursor.SetLoc(view.Cursor.CurSelection[0])
|
||||
view.Cursor.ResetSelection()
|
||||
}
|
||||
messenger.Reset()
|
||||
|
@ -185,9 +185,9 @@ func HandleCommand(input string) {
|
|||
messenger.Reset()
|
||||
} else {
|
||||
if view.Cursor.HasSelection() {
|
||||
searchStart = view.Cursor.curSelection[1]
|
||||
searchStart = view.Cursor.CurSelection[1]
|
||||
} else {
|
||||
searchStart = ToCharPos(view.Cursor.x, view.Cursor.y, view.Buf)
|
||||
searchStart = ToCharPos(view.Cursor.X, view.Cursor.Y, view.Buf)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -46,192 +46,203 @@ func ToCharPos(x, y int, buf *Buffer) int {
|
|||
// is also simpler to use character indicies for other tasks such as
|
||||
// selection.
|
||||
type Cursor struct {
|
||||
Buf *Buffer
|
||||
buf *Buffer
|
||||
|
||||
// The cursor display location
|
||||
x int
|
||||
y int
|
||||
X int
|
||||
Y int
|
||||
|
||||
// Last cursor x position
|
||||
lastVisualX int
|
||||
LastVisualX int
|
||||
|
||||
// The current selection as a range of character numbers (inclusive)
|
||||
curSelection [2]int
|
||||
CurSelection [2]int
|
||||
// The original selection as a range of character numbers
|
||||
// This is used for line and word selection where it is necessary
|
||||
// to know what the original selection was
|
||||
origSelection [2]int
|
||||
OrigSelection [2]int
|
||||
}
|
||||
|
||||
// Clamp makes sure that the cursor is in the bounds of the buffer
|
||||
// It cannot be less than 0 or greater than the buffer length
|
||||
func (c *Cursor) Clamp() {
|
||||
loc := c.Loc()
|
||||
if loc < 0 {
|
||||
c.SetLoc(0)
|
||||
} else if loc > c.buf.Len() {
|
||||
c.SetLoc(c.buf.Len())
|
||||
}
|
||||
}
|
||||
|
||||
// SetLoc sets the location of the cursor in terms of character number
|
||||
// and not x, y location
|
||||
// It's just a simple wrapper of FromCharPos
|
||||
func (c *Cursor) SetLoc(loc int) {
|
||||
c.x, c.y = FromCharPos(loc, c.Buf)
|
||||
c.lastVisualX = c.GetVisualX()
|
||||
c.X, c.Y = FromCharPos(loc, c.buf)
|
||||
c.LastVisualX = c.GetVisualX()
|
||||
}
|
||||
|
||||
// Loc gets the cursor location in terms of character number instead
|
||||
// of x, y location
|
||||
// It's just a simple wrapper of ToCharPos
|
||||
func (c *Cursor) Loc() int {
|
||||
return ToCharPos(c.x, c.y, c.Buf)
|
||||
return ToCharPos(c.X, c.Y, c.buf)
|
||||
}
|
||||
|
||||
// ResetSelection resets the user's selection
|
||||
func (c *Cursor) ResetSelection() {
|
||||
c.curSelection[0] = 0
|
||||
c.curSelection[1] = 0
|
||||
c.CurSelection[0] = 0
|
||||
c.CurSelection[1] = 0
|
||||
}
|
||||
|
||||
// HasSelection returns whether or not the user has selected anything
|
||||
func (c *Cursor) HasSelection() bool {
|
||||
return c.curSelection[0] != c.curSelection[1]
|
||||
return c.CurSelection[0] != c.CurSelection[1]
|
||||
}
|
||||
|
||||
// DeleteSelection deletes the currently selected text
|
||||
func (c *Cursor) DeleteSelection() {
|
||||
if c.curSelection[0] > c.curSelection[1] {
|
||||
c.Buf.Remove(c.curSelection[1], c.curSelection[0])
|
||||
c.SetLoc(c.curSelection[1])
|
||||
if c.CurSelection[0] > c.CurSelection[1] {
|
||||
c.buf.Remove(c.CurSelection[1], c.CurSelection[0])
|
||||
c.SetLoc(c.CurSelection[1])
|
||||
} else if c.GetSelection() == "" {
|
||||
return
|
||||
} else {
|
||||
c.Buf.Remove(c.curSelection[0], c.curSelection[1])
|
||||
c.SetLoc(c.curSelection[0])
|
||||
c.buf.Remove(c.CurSelection[0], c.CurSelection[1])
|
||||
c.SetLoc(c.CurSelection[0])
|
||||
}
|
||||
}
|
||||
|
||||
// GetSelection returns the cursor's selection
|
||||
func (c *Cursor) GetSelection() string {
|
||||
if c.curSelection[0] > c.curSelection[1] {
|
||||
return c.Buf.Substr(c.curSelection[1], c.curSelection[0])
|
||||
if c.CurSelection[0] > c.CurSelection[1] {
|
||||
return c.buf.Substr(c.CurSelection[1], c.CurSelection[0])
|
||||
}
|
||||
return c.Buf.Substr(c.curSelection[0], c.curSelection[1])
|
||||
return c.buf.Substr(c.CurSelection[0], c.CurSelection[1])
|
||||
}
|
||||
|
||||
// SelectLine selects the current line
|
||||
func (c *Cursor) SelectLine() {
|
||||
c.Start()
|
||||
c.curSelection[0] = c.Loc()
|
||||
c.CurSelection[0] = c.Loc()
|
||||
c.End()
|
||||
if c.Buf.NumLines-1 > c.y {
|
||||
c.curSelection[1] = c.Loc() + 1
|
||||
if c.buf.NumLines-1 > c.Y {
|
||||
c.CurSelection[1] = c.Loc() + 1
|
||||
} else {
|
||||
c.curSelection[1] = c.Loc()
|
||||
c.CurSelection[1] = c.Loc()
|
||||
}
|
||||
|
||||
c.origSelection = c.curSelection
|
||||
c.OrigSelection = c.CurSelection
|
||||
}
|
||||
|
||||
// AddLineToSelection adds the current line to the selection
|
||||
func (c *Cursor) AddLineToSelection() {
|
||||
loc := c.Loc()
|
||||
|
||||
if loc < c.origSelection[0] {
|
||||
if loc < c.OrigSelection[0] {
|
||||
c.Start()
|
||||
c.curSelection[0] = c.Loc()
|
||||
c.curSelection[1] = c.origSelection[1]
|
||||
c.CurSelection[0] = c.Loc()
|
||||
c.CurSelection[1] = c.OrigSelection[1]
|
||||
}
|
||||
if loc > c.origSelection[1] {
|
||||
if loc > c.OrigSelection[1] {
|
||||
c.End()
|
||||
c.curSelection[1] = c.Loc()
|
||||
c.curSelection[0] = c.origSelection[0]
|
||||
c.CurSelection[1] = c.Loc()
|
||||
c.CurSelection[0] = c.OrigSelection[0]
|
||||
}
|
||||
|
||||
if loc < c.origSelection[1] && loc > c.origSelection[0] {
|
||||
c.curSelection = c.origSelection
|
||||
if loc < c.OrigSelection[1] && loc > c.OrigSelection[0] {
|
||||
c.CurSelection = c.OrigSelection
|
||||
}
|
||||
}
|
||||
|
||||
// SelectWord selects the word the cursor is currently on
|
||||
func (c *Cursor) SelectWord() {
|
||||
if len(c.Buf.Lines[c.y]) == 0 {
|
||||
if len(c.buf.Lines[c.Y]) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if !IsWordChar(string(c.RuneUnder(c.x))) {
|
||||
if !IsWordChar(string(c.RuneUnder(c.X))) {
|
||||
loc := c.Loc()
|
||||
c.curSelection[0] = loc
|
||||
c.curSelection[1] = loc + 1
|
||||
c.origSelection = c.curSelection
|
||||
c.CurSelection[0] = loc
|
||||
c.CurSelection[1] = loc + 1
|
||||
c.OrigSelection = c.CurSelection
|
||||
return
|
||||
}
|
||||
|
||||
forward, backward := c.x, c.x
|
||||
forward, backward := c.X, c.X
|
||||
|
||||
for backward > 0 && IsWordChar(string(c.RuneUnder(backward-1))) {
|
||||
backward--
|
||||
}
|
||||
|
||||
c.curSelection[0] = ToCharPos(backward, c.y, c.Buf)
|
||||
c.origSelection[0] = c.curSelection[0]
|
||||
c.CurSelection[0] = ToCharPos(backward, c.Y, c.buf)
|
||||
c.OrigSelection[0] = c.CurSelection[0]
|
||||
|
||||
for forward < Count(c.Buf.Lines[c.y])-1 && IsWordChar(string(c.RuneUnder(forward+1))) {
|
||||
for forward < Count(c.buf.Lines[c.Y])-1 && IsWordChar(string(c.RuneUnder(forward+1))) {
|
||||
forward++
|
||||
}
|
||||
|
||||
c.curSelection[1] = ToCharPos(forward, c.y, c.Buf) + 1
|
||||
c.origSelection[1] = c.curSelection[1]
|
||||
c.SetLoc(c.curSelection[1])
|
||||
c.CurSelection[1] = ToCharPos(forward, c.Y, c.buf) + 1
|
||||
c.OrigSelection[1] = c.CurSelection[1]
|
||||
c.SetLoc(c.CurSelection[1])
|
||||
}
|
||||
|
||||
// AddWordToSelection adds the word the cursor is currently on to the selection
|
||||
func (c *Cursor) AddWordToSelection() {
|
||||
loc := c.Loc()
|
||||
|
||||
if loc > c.origSelection[0] && loc < c.origSelection[1] {
|
||||
c.curSelection = c.origSelection
|
||||
if loc > c.OrigSelection[0] && loc < c.OrigSelection[1] {
|
||||
c.CurSelection = c.OrigSelection
|
||||
return
|
||||
}
|
||||
|
||||
if loc < c.origSelection[0] {
|
||||
backward := c.x
|
||||
if loc < c.OrigSelection[0] {
|
||||
backward := c.X
|
||||
|
||||
for backward > 0 && IsWordChar(string(c.RuneUnder(backward-1))) {
|
||||
backward--
|
||||
}
|
||||
|
||||
c.curSelection[0] = ToCharPos(backward, c.y, c.Buf)
|
||||
c.curSelection[1] = c.origSelection[1]
|
||||
c.CurSelection[0] = ToCharPos(backward, c.Y, c.buf)
|
||||
c.CurSelection[1] = c.OrigSelection[1]
|
||||
}
|
||||
|
||||
if loc > c.origSelection[1] {
|
||||
forward := c.x
|
||||
if loc > c.OrigSelection[1] {
|
||||
forward := c.X
|
||||
|
||||
for forward < Count(c.Buf.Lines[c.y])-1 && IsWordChar(string(c.RuneUnder(forward+1))) {
|
||||
for forward < Count(c.buf.Lines[c.Y])-1 && IsWordChar(string(c.RuneUnder(forward+1))) {
|
||||
forward++
|
||||
}
|
||||
|
||||
c.curSelection[1] = ToCharPos(forward, c.y, c.Buf) + 1
|
||||
c.curSelection[0] = c.origSelection[0]
|
||||
c.CurSelection[1] = ToCharPos(forward, c.Y, c.buf) + 1
|
||||
c.CurSelection[0] = c.OrigSelection[0]
|
||||
}
|
||||
|
||||
c.SetLoc(c.curSelection[1])
|
||||
c.SetLoc(c.CurSelection[1])
|
||||
}
|
||||
|
||||
// SelectTo selects from the current cursor location to the given location
|
||||
func (c *Cursor) SelectTo(loc int) {
|
||||
if loc > c.origSelection[0] {
|
||||
c.curSelection[0] = c.origSelection[0]
|
||||
c.curSelection[1] = loc
|
||||
if loc > c.OrigSelection[0] {
|
||||
c.CurSelection[0] = c.OrigSelection[0]
|
||||
c.CurSelection[1] = loc
|
||||
} else {
|
||||
c.curSelection[0] = loc
|
||||
c.curSelection[1] = c.origSelection[0]
|
||||
c.CurSelection[0] = loc
|
||||
c.CurSelection[1] = c.OrigSelection[0]
|
||||
}
|
||||
}
|
||||
|
||||
// WordRight moves the cursor one word to the right
|
||||
func (c *Cursor) WordRight() {
|
||||
c.Right()
|
||||
for IsWhitespace(c.RuneUnder(c.x)) {
|
||||
if c.x == Count(c.Buf.Lines[c.y]) {
|
||||
for IsWhitespace(c.RuneUnder(c.X)) {
|
||||
if c.X == Count(c.buf.Lines[c.Y]) {
|
||||
return
|
||||
}
|
||||
c.Right()
|
||||
}
|
||||
for !IsWhitespace(c.RuneUnder(c.x)) {
|
||||
if c.x == Count(c.Buf.Lines[c.y]) {
|
||||
for !IsWhitespace(c.RuneUnder(c.X)) {
|
||||
if c.X == Count(c.buf.Lines[c.Y]) {
|
||||
return
|
||||
}
|
||||
c.Right()
|
||||
|
@ -241,14 +252,14 @@ func (c *Cursor) WordRight() {
|
|||
// WordLeft moves the cursor one word to the left
|
||||
func (c *Cursor) WordLeft() {
|
||||
c.Left()
|
||||
for IsWhitespace(c.RuneUnder(c.x)) {
|
||||
if c.x == 0 {
|
||||
for IsWhitespace(c.RuneUnder(c.X)) {
|
||||
if c.X == 0 {
|
||||
return
|
||||
}
|
||||
c.Left()
|
||||
}
|
||||
for !IsWhitespace(c.RuneUnder(c.x)) {
|
||||
if c.x == 0 {
|
||||
for !IsWhitespace(c.RuneUnder(c.X)) {
|
||||
if c.X == 0 {
|
||||
return
|
||||
}
|
||||
c.Left()
|
||||
|
@ -258,7 +269,7 @@ func (c *Cursor) WordLeft() {
|
|||
|
||||
// RuneUnder returns the rune under the given x position
|
||||
func (c *Cursor) RuneUnder(x int) rune {
|
||||
line := []rune(c.Buf.Lines[c.y])
|
||||
line := []rune(c.buf.Lines[c.Y])
|
||||
if len(line) == 0 {
|
||||
return '\n'
|
||||
}
|
||||
|
@ -272,26 +283,26 @@ func (c *Cursor) RuneUnder(x int) rune {
|
|||
|
||||
// Up moves the cursor up one line (if possible)
|
||||
func (c *Cursor) Up() {
|
||||
if c.y > 0 {
|
||||
c.y--
|
||||
if c.Y > 0 {
|
||||
c.Y--
|
||||
|
||||
runes := []rune(c.Buf.Lines[c.y])
|
||||
c.x = c.GetCharPosInLine(c.y, c.lastVisualX)
|
||||
if c.x > len(runes) {
|
||||
c.x = len(runes)
|
||||
runes := []rune(c.buf.Lines[c.Y])
|
||||
c.X = c.GetCharPosInLine(c.Y, c.LastVisualX)
|
||||
if c.X > len(runes) {
|
||||
c.X = len(runes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Down moves the cursor down one line (if possible)
|
||||
func (c *Cursor) Down() {
|
||||
if c.y < c.Buf.NumLines-1 {
|
||||
c.y++
|
||||
if c.Y < c.buf.NumLines-1 {
|
||||
c.Y++
|
||||
|
||||
runes := []rune(c.Buf.Lines[c.y])
|
||||
c.x = c.GetCharPosInLine(c.y, c.lastVisualX)
|
||||
if c.x > len(runes) {
|
||||
c.x = len(runes)
|
||||
runes := []rune(c.buf.Lines[c.Y])
|
||||
c.X = c.GetCharPosInLine(c.Y, c.LastVisualX)
|
||||
if c.X > len(runes) {
|
||||
c.X = len(runes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -301,39 +312,39 @@ func (c *Cursor) Left() {
|
|||
if c.Loc() == 0 {
|
||||
return
|
||||
}
|
||||
if c.x > 0 {
|
||||
c.x--
|
||||
if c.X > 0 {
|
||||
c.X--
|
||||
} else {
|
||||
c.Up()
|
||||
c.End()
|
||||
}
|
||||
c.lastVisualX = c.GetVisualX()
|
||||
c.LastVisualX = c.GetVisualX()
|
||||
}
|
||||
|
||||
// Right moves the cursor right one cell (if possible) or to the next line if it is at the end
|
||||
func (c *Cursor) Right() {
|
||||
if c.Loc() == c.Buf.Len() {
|
||||
if c.Loc() == c.buf.Len() {
|
||||
return
|
||||
}
|
||||
if c.x < Count(c.Buf.Lines[c.y]) {
|
||||
c.x++
|
||||
if c.X < Count(c.buf.Lines[c.Y]) {
|
||||
c.X++
|
||||
} else {
|
||||
c.Down()
|
||||
c.Start()
|
||||
}
|
||||
c.lastVisualX = c.GetVisualX()
|
||||
c.LastVisualX = c.GetVisualX()
|
||||
}
|
||||
|
||||
// End moves the cursor to the end of the line it is on
|
||||
func (c *Cursor) End() {
|
||||
c.x = Count(c.Buf.Lines[c.y])
|
||||
c.lastVisualX = c.GetVisualX()
|
||||
c.X = Count(c.buf.Lines[c.Y])
|
||||
c.LastVisualX = c.GetVisualX()
|
||||
}
|
||||
|
||||
// Start moves the cursor to the start of the line it is on
|
||||
func (c *Cursor) Start() {
|
||||
c.x = 0
|
||||
c.lastVisualX = c.GetVisualX()
|
||||
c.X = 0
|
||||
c.LastVisualX = c.GetVisualX()
|
||||
}
|
||||
|
||||
// GetCharPosInLine gets the char position of a visual x y coordinate (this is necessary because tabs are 1 char but 4 visual spaces)
|
||||
|
@ -341,7 +352,7 @@ func (c *Cursor) GetCharPosInLine(lineNum, visualPos int) int {
|
|||
// Get the tab size
|
||||
tabSize := int(settings["tabsize"].(float64))
|
||||
// This is the visual line -- every \t replaced with the correct number of spaces
|
||||
visualLine := strings.Replace(c.Buf.Lines[lineNum], "\t", "\t"+Spaces(tabSize-1), -1)
|
||||
visualLine := strings.Replace(c.buf.Lines[lineNum], "\t", "\t"+Spaces(tabSize-1), -1)
|
||||
if visualPos > Count(visualLine) {
|
||||
visualPos = Count(visualLine)
|
||||
}
|
||||
|
@ -354,23 +365,23 @@ func (c *Cursor) GetCharPosInLine(lineNum, visualPos int) int {
|
|||
|
||||
// GetVisualX returns the x value of the cursor in visual spaces
|
||||
func (c *Cursor) GetVisualX() int {
|
||||
runes := []rune(c.Buf.Lines[c.y])
|
||||
runes := []rune(c.buf.Lines[c.Y])
|
||||
tabSize := int(settings["tabsize"].(float64))
|
||||
return c.x + NumOccurences(string(runes[:c.x]), '\t')*(tabSize-1)
|
||||
return c.X + NumOccurences(string(runes[:c.X]), '\t')*(tabSize-1)
|
||||
}
|
||||
|
||||
// Relocate makes sure that the cursor is inside the bounds of the buffer
|
||||
// If it isn't, it moves it to be within the buffer's lines
|
||||
func (c *Cursor) Relocate() {
|
||||
if c.y < 0 {
|
||||
c.y = 0
|
||||
} else if c.y >= c.Buf.NumLines {
|
||||
c.y = c.Buf.NumLines - 1
|
||||
if c.Y < 0 {
|
||||
c.Y = 0
|
||||
} else if c.Y >= c.buf.NumLines {
|
||||
c.Y = c.buf.NumLines - 1
|
||||
}
|
||||
|
||||
if c.x < 0 {
|
||||
c.x = 0
|
||||
} else if c.x > Count(c.Buf.Lines[c.y]) {
|
||||
c.x = Count(c.Buf.Lines[c.y])
|
||||
if c.X < 0 {
|
||||
c.X = 0
|
||||
} else if c.X > Count(c.buf.Lines[c.Y]) {
|
||||
c.X = Count(c.buf.Lines[c.Y])
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -119,9 +119,9 @@ func Search(searchStr string, v *View, down bool) {
|
|||
return
|
||||
}
|
||||
|
||||
v.Cursor.curSelection[0] = charPos + runePos(match[0], str)
|
||||
v.Cursor.curSelection[1] = charPos + runePos(match[1], str)
|
||||
v.Cursor.x, v.Cursor.y = FromCharPos(charPos+match[1]-1, v.Buf)
|
||||
v.Cursor.CurSelection[0] = charPos + runePos(match[0], str)
|
||||
v.Cursor.CurSelection[1] = charPos + runePos(match[1], str)
|
||||
v.Cursor.X, v.Cursor.Y = FromCharPos(charPos+match[1]-1, v.Buf)
|
||||
if v.Relocate() {
|
||||
v.matches = Match(v)
|
||||
}
|
||||
|
|
|
@ -77,6 +77,7 @@ func DefaultSettings() map[string]interface{} {
|
|||
"ignorecase": false,
|
||||
"indentchar": " ",
|
||||
"ruler": true,
|
||||
"savecursor": false,
|
||||
"scrollspeed": float64(2),
|
||||
"scrollmargin": float64(3),
|
||||
"statusline": true,
|
||||
|
|
|
@ -33,7 +33,7 @@ func (sline *Statusline) Display() {
|
|||
// We use GetVisualX() here because otherwise we get the column number in runes
|
||||
// so a '\t' is only 1, when it should be tabSize
|
||||
columnNum := strconv.Itoa(sline.view.Cursor.GetVisualX() + 1)
|
||||
lineNum := strconv.Itoa(sline.view.Cursor.y + 1)
|
||||
lineNum := strconv.Itoa(sline.view.Cursor.Y + 1)
|
||||
|
||||
file += " (" + lineNum + "," + columnNum + ")"
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
|
@ -118,6 +120,12 @@ func ParseBool(str string) (bool, error) {
|
|||
return strconv.ParseBool(str)
|
||||
}
|
||||
|
||||
// EscapePath replaces every path separator in a given path with a %
|
||||
func EscapePath(path string) string {
|
||||
path = filepath.ToSlash(path)
|
||||
return strings.Replace(path, "/", "%", -1)
|
||||
}
|
||||
|
||||
func runePos(p int, str string) int {
|
||||
return utf8.RuneCountInString(str[:p])
|
||||
}
|
||||
|
|
|
@ -166,6 +166,7 @@ func (v *View) CanClose(msg string) bool {
|
|||
// OpenBuffer opens a new buffer in this view.
|
||||
// This resets the topline, event handler and cursor.
|
||||
func (v *View) OpenBuffer(buf *Buffer) {
|
||||
v.CloseBuffer()
|
||||
v.Buf = buf
|
||||
v.Cursor = &buf.Cursor
|
||||
v.Topline = 0
|
||||
|
@ -181,6 +182,13 @@ func (v *View) OpenBuffer(buf *Buffer) {
|
|||
v.lastClickTime = time.Time{}
|
||||
}
|
||||
|
||||
// CloseBuffer performs any closing functions on the buffer
|
||||
func (v *View) CloseBuffer() {
|
||||
if v.Buf != nil {
|
||||
v.Buf.Serialize()
|
||||
}
|
||||
}
|
||||
|
||||
// ReOpen reloads the current buffer
|
||||
func (v *View) ReOpen() {
|
||||
if v.CanClose("Continue? (yes, no, save) ") {
|
||||
|
@ -203,7 +211,7 @@ func (v *View) ReOpen() {
|
|||
// This is useful if the user has scrolled far away, and then starts typing
|
||||
func (v *View) Relocate() bool {
|
||||
ret := false
|
||||
cy := v.Cursor.y
|
||||
cy := v.Cursor.Y
|
||||
scrollmargin := int(settings["scrollmargin"].(float64))
|
||||
if cy < v.Topline+scrollmargin && cy > scrollmargin-1 {
|
||||
v.Topline = cy - scrollmargin
|
||||
|
@ -253,9 +261,9 @@ func (v *View) MoveToMouseClick(x, y int) {
|
|||
if x > Count(v.Buf.Lines[y]) {
|
||||
x = Count(v.Buf.Lines[y])
|
||||
}
|
||||
v.Cursor.x = x
|
||||
v.Cursor.y = y
|
||||
v.Cursor.lastVisualX = v.Cursor.GetVisualX()
|
||||
v.Cursor.X = x
|
||||
v.Cursor.Y = y
|
||||
v.Cursor.LastVisualX = v.Cursor.GetVisualX()
|
||||
}
|
||||
|
||||
// HandleEvent handles an event passed by the main loop
|
||||
|
@ -345,9 +353,9 @@ func (v *View) HandleEvent(event tcell.Event) {
|
|||
v.lastClickTime = time.Now()
|
||||
|
||||
loc := v.Cursor.Loc()
|
||||
v.Cursor.origSelection[0] = loc
|
||||
v.Cursor.curSelection[0] = loc
|
||||
v.Cursor.curSelection[1] = loc
|
||||
v.Cursor.OrigSelection[0] = loc
|
||||
v.Cursor.CurSelection[0] = loc
|
||||
v.Cursor.CurSelection[1] = loc
|
||||
}
|
||||
v.mouseReleased = false
|
||||
} else if !v.mouseReleased {
|
||||
|
@ -357,7 +365,7 @@ func (v *View) HandleEvent(event tcell.Event) {
|
|||
} else if v.doubleClick {
|
||||
v.Cursor.AddWordToSelection()
|
||||
} else {
|
||||
v.Cursor.curSelection[1] = v.Cursor.Loc()
|
||||
v.Cursor.CurSelection[1] = v.Cursor.Loc()
|
||||
}
|
||||
}
|
||||
case tcell.ButtonNone:
|
||||
|
@ -373,7 +381,7 @@ 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.CurSelection[1] = v.Cursor.Loc()
|
||||
}
|
||||
v.mouseReleased = true
|
||||
}
|
||||
|
@ -487,7 +495,7 @@ func (v *View) DisplayView() {
|
|||
x++
|
||||
screen.SetContent(x, lineN, '>', nil, gutterStyle)
|
||||
x++
|
||||
if v.Cursor.y == lineN+v.Topline {
|
||||
if v.Cursor.Y == lineN+v.Topline {
|
||||
messenger.Message(msg.msg)
|
||||
messenger.gutterMessage = true
|
||||
}
|
||||
|
@ -499,7 +507,7 @@ func (v *View) DisplayView() {
|
|||
x++
|
||||
screen.SetContent(x, lineN, ' ', nil, tcell.StyleDefault)
|
||||
x++
|
||||
if v.Cursor.y == lineN+v.Topline && messenger.gutterMessage {
|
||||
if v.Cursor.Y == lineN+v.Topline && messenger.gutterMessage {
|
||||
messenger.Reset()
|
||||
messenger.gutterMessage = false
|
||||
}
|
||||
|
@ -542,8 +550,8 @@ func (v *View) DisplayView() {
|
|||
}
|
||||
|
||||
if v.Cursor.HasSelection() &&
|
||||
(charNum >= v.Cursor.curSelection[0] && charNum < v.Cursor.curSelection[1] ||
|
||||
charNum < v.Cursor.curSelection[0] && charNum >= v.Cursor.curSelection[1]) {
|
||||
(charNum >= v.Cursor.CurSelection[0] && charNum < v.Cursor.CurSelection[1] ||
|
||||
charNum < v.Cursor.CurSelection[0] && charNum >= v.Cursor.CurSelection[1]) {
|
||||
|
||||
lineStyle = tcell.StyleDefault.Reverse(true)
|
||||
|
||||
|
@ -560,8 +568,8 @@ func (v *View) DisplayView() {
|
|||
lineIndentStyle = style
|
||||
}
|
||||
if v.Cursor.HasSelection() &&
|
||||
(charNum >= v.Cursor.curSelection[0] && charNum < v.Cursor.curSelection[1] ||
|
||||
charNum < v.Cursor.curSelection[0] && charNum >= v.Cursor.curSelection[1]) {
|
||||
(charNum >= v.Cursor.CurSelection[0] && charNum < v.Cursor.CurSelection[1] ||
|
||||
charNum < v.Cursor.CurSelection[0] && charNum >= v.Cursor.CurSelection[1]) {
|
||||
|
||||
lineIndentStyle = tcell.StyleDefault.Reverse(true)
|
||||
|
||||
|
@ -591,8 +599,8 @@ func (v *View) DisplayView() {
|
|||
// The newline may be selected, in which case we should draw the selection style
|
||||
// with a space to represent it
|
||||
if v.Cursor.HasSelection() &&
|
||||
(charNum >= v.Cursor.curSelection[0] && charNum < v.Cursor.curSelection[1] ||
|
||||
charNum < v.Cursor.curSelection[0] && charNum >= v.Cursor.curSelection[1]) {
|
||||
(charNum >= v.Cursor.CurSelection[0] && charNum < v.Cursor.CurSelection[1] ||
|
||||
charNum < v.Cursor.CurSelection[0] && charNum >= v.Cursor.CurSelection[1]) {
|
||||
|
||||
selectStyle := defStyle.Reverse(true)
|
||||
|
||||
|
@ -609,10 +617,10 @@ func (v *View) DisplayView() {
|
|||
// DisplayCursor draws the current buffer's cursor to the screen
|
||||
func (v *View) DisplayCursor() {
|
||||
// Don't draw the cursor if it is out of the viewport or if it has a selection
|
||||
if (v.Cursor.y-v.Topline < 0 || v.Cursor.y-v.Topline > v.height-1) || v.Cursor.HasSelection() {
|
||||
if (v.Cursor.Y-v.Topline < 0 || v.Cursor.Y-v.Topline > v.height-1) || v.Cursor.HasSelection() {
|
||||
screen.HideCursor()
|
||||
} else {
|
||||
screen.ShowCursor(v.Cursor.GetVisualX()+v.lineNumOffset-v.leftCol, v.Cursor.y-v.Topline)
|
||||
screen.ShowCursor(v.Cursor.GetVisualX()+v.lineNumOffset-v.leftCol, v.Cursor.Y-v.Topline)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -214,6 +214,11 @@ Here are the options that you can set:
|
|||
|
||||
default value: `on`
|
||||
|
||||
* `savecursor`: remember where the cursor was last time the file was opened and
|
||||
put it there when you open the file again
|
||||
|
||||
default value: `off`
|
||||
|
||||
* `scrollmargin`: amount of lines you would like to see above and below the cursor
|
||||
|
||||
default value: `3`
|
||||
|
|
Loading…
Reference in a new issue