]> git.lizzy.rs Git - micro.git/blob - cmd/micro/buffer.go
Remove unused syntax highlighting code and optimize IsDirty()
[micro.git] / cmd / micro / buffer.go
1 package main
2
3 import (
4         "github.com/vinzmay/go-rope"
5         "io/ioutil"
6         "strings"
7 )
8
9 // Buffer stores the text for files that are loaded into the text editor
10 // It uses a rope to efficiently store the string and contains some
11 // simple functions for saving and wrapper functions for modifying the rope
12 type Buffer struct {
13         // Stores the text of the buffer
14         r *rope.Rope
15
16         // Path to the file on disk
17         path string
18         // Name of the buffer on the status line
19         name string
20
21         // This is the text stored every time the buffer is saved to check if the buffer is modified
22         savedText           string
23         netInsertions       int
24         dirtySinceLastCheck bool
25
26         // Provide efficient and easy access to text and lines so the rope String does not
27         // need to be constantly recalculated
28         // These variables are updated in the update() function
29         text  string
30         lines []string
31
32         // Syntax highlighting rules
33         rules []SyntaxRule
34         // The buffer's filetype
35         filetype string
36 }
37
38 // NewBuffer creates a new buffer from `txt` with path and name `path`
39 func NewBuffer(txt, path string) *Buffer {
40         b := new(Buffer)
41         if txt == "" {
42                 b.r = new(rope.Rope)
43         } else {
44                 b.r = rope.New(txt)
45         }
46         b.path = path
47         b.name = path
48         b.savedText = txt
49
50         b.Update()
51         b.UpdateRules()
52
53         return b
54 }
55
56 // UpdateRules updates the syntax rules and filetype for this buffer
57 // This is called when the colorscheme changes
58 func (b *Buffer) UpdateRules() {
59         b.rules, b.filetype = GetRules(b)
60 }
61
62 // Update fetches the string from the rope and updates the `text` and `lines` in the buffer
63 func (b *Buffer) Update() {
64         if b.r.Len() == 0 {
65                 b.text = ""
66         } else {
67                 b.text = b.r.String()
68         }
69         b.lines = strings.Split(b.text, "\n")
70 }
71
72 // Save saves the buffer to its default path
73 func (b *Buffer) Save() error {
74         return b.SaveAs(b.path)
75 }
76
77 // SaveAs saves the buffer to a specified path (filename), creating the file if it does not exist
78 func (b *Buffer) SaveAs(filename string) error {
79         b.UpdateRules()
80         err := ioutil.WriteFile(filename, []byte(b.text), 0644)
81         if err == nil {
82                 b.savedText = b.text
83                 b.netInsertions = 0
84         }
85         return err
86 }
87
88 // IsDirty returns whether or not the buffer has been modified compared to the one on disk
89 func (b *Buffer) IsDirty() bool {
90         if !b.dirtySinceLastCheck {
91                 return false
92         }
93         if b.netInsertions == 0 {
94                 isDirty := b.savedText != b.text
95                 b.dirtySinceLastCheck = isDirty
96                 return isDirty
97         }
98         return true
99 }
100
101 // Insert a string into the rope
102 func (b *Buffer) Insert(idx int, value string) {
103         b.dirtySinceLastCheck = true
104         b.netInsertions += len(value)
105         b.r = b.r.Insert(idx, value)
106         b.Update()
107 }
108
109 // Remove a slice of the rope from start to end (exclusive)
110 // Returns the string that was removed
111 func (b *Buffer) Remove(start, end int) string {
112         b.dirtySinceLastCheck = true
113         b.netInsertions -= end - start
114         if start < 0 {
115                 start = 0
116         }
117         if end > b.Len() {
118                 end = b.Len()
119         }
120         removed := b.text[start:end]
121         // The rope implenentation I am using wants indicies starting at 1 instead of 0
122         start++
123         end++
124         b.r = b.r.Delete(start, end-start)
125         b.Update()
126         return removed
127 }
128
129 // Len gives the length of the buffer
130 func (b *Buffer) Len() int {
131         return b.r.Len()
132 }