]> git.lizzy.rs Git - micro.git/blob - internal/buffer/backup.go
Merge pull request #1386 from jncraton/docfix
[micro.git] / internal / buffer / backup.go
1 package buffer
2
3 import (
4         "fmt"
5         "io"
6         "log"
7         "os"
8         "time"
9
10         "github.com/zyedidia/micro/internal/config"
11         "github.com/zyedidia/micro/internal/screen"
12         "github.com/zyedidia/micro/internal/util"
13         "golang.org/x/text/encoding"
14 )
15
16 const backupMsg = `A backup was detected for this file. This likely means that micro
17 crashed while editing this file, or another instance of micro is currently
18 editing this file.
19
20 The backup was created on %s, and the file is
21
22 %s
23
24 * 'recover' will apply the backup as unsaved changes to the current buffer.
25   When the buffer is closed, the backup will be removed.
26 * 'ignore' will ignore the backup, discarding its changes. The backup file
27   will be removed.
28
29 Options: [r]ecover, [i]gnore: `
30
31 // Backup saves the current buffer to ConfigDir/backups
32 func (b *Buffer) Backup(checkTime bool) error {
33         if !b.Settings["backup"].(bool) || b.Path == "" {
34                 return nil
35         }
36
37         if checkTime {
38                 sub := time.Now().Sub(b.lastbackup)
39                 if sub < time.Duration(backupTime)*time.Millisecond {
40                         log.Println("Backup event but not enough time has passed", sub)
41                         return nil
42                 }
43         }
44
45         b.lastbackup = time.Now()
46
47         backupdir := config.ConfigDir + "/backups/"
48         if _, err := os.Stat(backupdir); os.IsNotExist(err) {
49                 os.Mkdir(backupdir, os.ModePerm)
50                 log.Println("Creating backup dir")
51         }
52
53         name := backupdir + util.EscapePath(b.AbsPath)
54
55         log.Println("Backing up to", name)
56
57         err := overwriteFile(name, encoding.Nop, func(file io.Writer) (e error) {
58                 if len(b.lines) == 0 {
59                         return
60                 }
61
62                 // end of line
63                 eol := []byte{'\n'}
64
65                 // write lines
66                 if _, e = file.Write(b.lines[0].data); e != nil {
67                         return
68                 }
69
70                 for _, l := range b.lines[1:] {
71                         if _, e = file.Write(eol); e != nil {
72                                 return
73                         }
74                         if _, e = file.Write(l.data); e != nil {
75                                 return
76                         }
77                 }
78                 return
79         })
80
81         return err
82 }
83
84 // RemoveBackup removes any backup file associated with this buffer
85 func (b *Buffer) RemoveBackup() {
86         if !b.Settings["backup"].(bool) || b.Path == "" {
87                 return
88         }
89         f := config.ConfigDir + "/backups/" + util.EscapePath(b.AbsPath)
90         os.Remove(f)
91 }
92
93 // ApplyBackup applies the corresponding backup file to this buffer (if one exists)
94 // Returns true if a backup was applied
95 func (b *Buffer) ApplyBackup(fsize int64) bool {
96         if b.Settings["backup"].(bool) && len(b.Path) > 0 {
97                 backupfile := config.ConfigDir + "/backups/" + util.EscapePath(b.AbsPath)
98                 if info, err := os.Stat(backupfile); err == nil {
99                         backup, err := os.Open(backupfile)
100                         if err == nil {
101                                 defer backup.Close()
102                                 t := info.ModTime()
103                                 msg := fmt.Sprintf(backupMsg, t.Format("Mon Jan _2 at 15:04, 2006"), util.EscapePath(b.AbsPath))
104                                 choice := screen.TermPrompt(msg, []string{"r", "i", "recover", "ignore"}, true)
105
106                                 if choice%2 == 0 {
107                                         // recover
108                                         b.LineArray = NewLineArray(uint64(fsize), FFAuto, backup)
109                                         b.isModified = true
110                                         return true
111                                 } else if choice%2 == 1 {
112                                         // delete
113                                         os.Remove(backupfile)
114                                 }
115                         }
116                 }
117         }
118
119         return false
120 }