]> git.lizzy.rs Git - micro.git/blob - cmd/micro/buffer/save.go
Fix serialization
[micro.git] / cmd / micro / buffer / save.go
1 package buffer
2
3 import (
4         "bytes"
5         "io"
6         "os"
7         "os/exec"
8         "os/signal"
9         "path/filepath"
10
11         . "github.com/zyedidia/micro/cmd/micro/util"
12
13         "github.com/zyedidia/micro/cmd/micro/config"
14 )
15
16 // Save saves the buffer to its default path
17 func (b *Buffer) Save() error {
18         return b.SaveAs(b.Path)
19 }
20
21 // SaveAs saves the buffer to a specified path (filename), creating the file if it does not exist
22 func (b *Buffer) SaveAs(filename string) error {
23         // TODO: rmtrailingws and updaterules
24         b.UpdateRules()
25         // if b.Settings["rmtrailingws"].(bool) {
26         //      for i, l := range b.lines {
27         //              pos := len(bytes.TrimRightFunc(l.data, unicode.IsSpace))
28         //
29         //              if pos < len(l.data) {
30         //                      b.deleteToEnd(Loc{pos, i})
31         //              }
32         //      }
33         //
34         //      b.Cursor.Relocate()
35         // }
36
37         if b.Settings["eofnewline"].(bool) {
38                 end := b.End()
39                 if b.RuneAt(Loc{end.X - 1, end.Y}) != '\n' {
40                         b.Insert(end, "\n")
41                 }
42         }
43
44         // Update the last time this file was updated after saving
45         defer func() {
46                 b.ModTime, _ = GetModTime(filename)
47         }()
48
49         // Removes any tilde and replaces with the absolute path to home
50         absFilename, _ := ReplaceHome(filename)
51
52         // TODO: save creates parent dirs
53         // // Get the leading path to the file | "." is returned if there's no leading path provided
54         // if dirname := filepath.Dir(absFilename); dirname != "." {
55         //      // Check if the parent dirs don't exist
56         //      if _, statErr := os.Stat(dirname); os.IsNotExist(statErr) {
57         //              // Prompt to make sure they want to create the dirs that are missing
58         //              if yes, canceled := messenger.YesNoPrompt("Parent folders \"" + dirname + "\" do not exist. Create them? (y,n)"); yes && !canceled {
59         //                      // Create all leading dir(s) since they don't exist
60         //                      if mkdirallErr := os.MkdirAll(dirname, os.ModePerm); mkdirallErr != nil {
61         //                              // If there was an error creating the dirs
62         //                              return mkdirallErr
63         //                      }
64         //              } else {
65         //                      // If they canceled the creation of leading dirs
66         //                      return errors.New("Save aborted")
67         //              }
68         //      }
69         // }
70
71         var fileSize int
72
73         err := overwriteFile(absFilename, func(file io.Writer) (e error) {
74                 if len(b.lines) == 0 {
75                         return
76                 }
77
78                 // end of line
79                 var eol []byte
80                 if b.Settings["fileformat"] == "dos" {
81                         eol = []byte{'\r', '\n'}
82                 } else {
83                         eol = []byte{'\n'}
84                 }
85
86                 // write lines
87                 if fileSize, e = file.Write(b.lines[0].data); e != nil {
88                         return
89                 }
90
91                 for _, l := range b.lines[1:] {
92                         if _, e = file.Write(eol); e != nil {
93                                 return
94                         }
95                         if _, e = file.Write(l.data); e != nil {
96                                 return
97                         }
98                         fileSize += len(eol) + len(l.data)
99                 }
100                 return
101         })
102
103         if err != nil {
104                 return err
105         }
106
107         if !b.Settings["fastdirty"].(bool) {
108                 if fileSize > LargeFileThreshold {
109                         // For large files 'fastdirty' needs to be on
110                         b.Settings["fastdirty"] = true
111                 } else {
112                         calcHash(b, &b.origHash)
113                 }
114         }
115
116         b.Path = filename
117         absPath, _ := filepath.Abs(filename)
118         b.AbsPath = absPath
119         b.isModified = false
120         return b.Serialize()
121 }
122
123 // SaveWithSudo saves the buffer to the default path with sudo
124 func (b *Buffer) SaveWithSudo() error {
125         return b.SaveAsWithSudo(b.Path)
126 }
127
128 // SaveAsWithSudo is the same as SaveAs except it uses a neat trick
129 // with tee to use sudo so the user doesn't have to reopen micro with sudo
130 func (b *Buffer) SaveAsWithSudo(filename string) error {
131         b.UpdateRules()
132         b.Path = filename
133         absPath, _ := filepath.Abs(filename)
134         b.AbsPath = absPath
135
136         // Set up everything for the command
137         cmd := exec.Command(config.GlobalSettings["sucmd"].(string), "tee", filename)
138         cmd.Stdin = bytes.NewBuffer(b.Bytes())
139
140         // This is a trap for Ctrl-C so that it doesn't kill micro
141         // Instead we trap Ctrl-C to kill the program we're running
142         c := make(chan os.Signal, 1)
143         signal.Notify(c, os.Interrupt)
144         go func() {
145                 for range c {
146                         cmd.Process.Kill()
147                 }
148         }()
149
150         // Start the command
151         cmd.Start()
152         err := cmd.Wait()
153
154         if err == nil {
155                 b.isModified = false
156                 b.ModTime, _ = GetModTime(filename)
157                 return b.Serialize()
158         }
159         return err
160 }