]> git.lizzy.rs Git - micro.git/blobdiff - cmd/micro/buffer.go
Fix draw ordering
[micro.git] / cmd / micro / buffer.go
index a9451e9315c24f16112a957e8b9c56da68aeb395..9e40f55e35baa5ddc1572df5a790665ab1e5cc9b 100644 (file)
@@ -8,10 +8,8 @@ import (
        "os/exec"
        "os/signal"
        "path/filepath"
-       "strings"
        "time"
-
-       "github.com/vinzmay/go-rope"
+       "unicode/utf8"
 )
 
 // Buffer stores the text for files that are loaded into the text editor
@@ -20,9 +18,8 @@ import (
 type Buffer struct {
        // The eventhandler for undo/redo
        *EventHandler
-
-       // Stores the text of the buffer
-       r *rope.Rope
+       // This stores all the text in the buffer as an array of lines
+       *LineArray
 
        Cursor Cursor
 
@@ -31,15 +28,12 @@ type Buffer struct {
        // Name of the buffer on the status line
        Name string
 
+       // Whether or not the buffer has been modified since it was opened
        IsModified bool
 
        // Stores the last modification time of the file the buffer is pointing to
        ModTime time.Time
 
-       // Provide efficient and easy access to text and lines so the rope String does not
-       // need to be constantly recalculated
-       // These variables are updated in the update() function
-       Lines    []string
        NumLines int
 
        // Syntax highlighting rules
@@ -49,6 +43,7 @@ type Buffer struct {
 }
 
 // The SerializedBuffer holds the types that get serialized when a buffer is saved
+// These are used for the savecursor and saveundo options
 type SerializedBuffer struct {
        EventHandler *EventHandler
        Cursor       Cursor
@@ -56,16 +51,19 @@ type SerializedBuffer struct {
 }
 
 // NewBuffer creates a new buffer from `txt` with path and name `path`
-func NewBuffer(txt, path string) *Buffer {
+func NewBuffer(txt []byte, path string) *Buffer {
        b := new(Buffer)
-       if txt == "" {
-               b.r = new(rope.Rope)
-       } else {
-               b.r = rope.New(txt)
-       }
+       b.LineArray = NewLineArray(txt)
+
        b.Path = path
        b.Name = path
 
+       // If the file doesn't have a path to disk then we give it no name
+       if path == "" {
+               b.Name = "No name"
+       }
+
+       // The last time this file was modified
        b.ModTime, _ = GetModTime(b.Path)
 
        b.EventHandler = NewEventHandler(b)
@@ -79,12 +77,16 @@ func NewBuffer(txt, path string) *Buffer {
 
        // Put the cursor at the first spot
        b.Cursor = Cursor{
-               X:   0,
-               Y:   0,
+               Loc: Loc{
+                       X: 0,
+                       Y: 0,
+               },
                buf: b,
        }
 
        if settings["savecursor"].(bool) || settings["saveundo"].(bool) {
+               // If either savecursor or saveundo is turned on, we need to load the serialized information
+               // from ~/.config/micro/buffers
                absPath, _ := filepath.Abs(b.Path)
                file, err := os.Open(configDir + "/buffers/" + EscapePath(absPath))
                if err == nil {
@@ -93,7 +95,7 @@ func NewBuffer(txt, path string) *Buffer {
                        gob.Register(TextEvent{})
                        err = decoder.Decode(&buffer)
                        if err != nil {
-                               TermMessage(err.Error())
+                               TermMessage(err.Error(), "\n", "You may want to remove the files in ~/.config/micro/buffers (these files store the information for the 'saveundo' and 'savecursor' options) if this problem persists.")
                        }
                        if settings["savecursor"].(bool) {
                                b.Cursor = buffer.Cursor
@@ -121,13 +123,6 @@ func (b *Buffer) UpdateRules() {
        b.rules, b.FileType = GetRules(b)
 }
 
-func (b *Buffer) String() string {
-       if b.r.Len() != 0 {
-               return b.r.String()
-       }
-       return ""
-}
-
 // CheckModTime makes sure that the file this buffer points to hasn't been updated
 // by an external program since it was last read
 // If it has, we ask the user if they would like to reload the file
@@ -168,8 +163,7 @@ func (b *Buffer) ReOpen() {
 
 // Update fetches the string from the rope and updates the `text` and `lines` in the buffer
 func (b *Buffer) Update() {
-       b.Lines = strings.Split(b.String(), "\n")
-       b.NumLines = len(b.Lines)
+       b.NumLines = len(b.lines)
 }
 
 // Save saves the buffer to its default path
@@ -268,42 +262,44 @@ func (b *Buffer) SaveAsWithSudo(filename string) error {
        return err
 }
 
-// This directly inserts value at idx, bypassing all undo/redo
-func (b *Buffer) insert(idx int, value string) {
+func (b *Buffer) insert(pos Loc, value []byte) {
        b.IsModified = true
-       b.r = b.r.Insert(idx, value)
+       b.LineArray.insert(pos, value)
        b.Update()
 }
-
-// Remove a slice of the rope from start to end (exclusive)
-// Returns the string that was removed
-// This directly removes from start to end from the buffer, bypassing all undo/redo
-func (b *Buffer) remove(start, end int) string {
+func (b *Buffer) remove(start, end Loc) string {
        b.IsModified = true
-       if start < 0 {
-               start = 0
-       }
-       if end > b.Len() {
-               end = b.Len()
-       }
-       if start == end {
-               return ""
-       }
-       removed := b.Substr(start, end)
-       // The rope implenentation I am using wants indicies starting at 1 instead of 0
-       start++
-       end++
-       b.r = b.r.Delete(start, end-start)
+       sub := b.LineArray.remove(start, end)
        b.Update()
-       return removed
+       return sub
+}
+
+// Start returns the location of the first character in the buffer
+func (b *Buffer) Start() Loc {
+       return Loc{0, 0}
 }
 
-// Substr returns the substring of the rope from start to end
-func (b *Buffer) Substr(start, end int) string {
-       return b.r.Substr(start+1, end-start).String()
+// End returns the location of the last character in the buffer
+func (b *Buffer) End() Loc {
+       return Loc{utf8.RuneCount(b.lines[b.NumLines-1]), b.NumLines - 1}
+}
+
+// Line returns a single line
+func (b *Buffer) Line(n int) string {
+       return string(b.lines[n])
+}
+
+// Lines returns an array of strings containing the lines from start to end
+func (b *Buffer) Lines(start, end int) []string {
+       lines := b.lines[start:end]
+       var slice []string
+       for _, line := range lines {
+               slice = append(slice, string(line))
+       }
+       return slice
 }
 
 // Len gives the length of the buffer
 func (b *Buffer) Len() int {
-       return b.r.Len()
+       return Count(b.String())
 }