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