micro/internal/buffer/backup.go

143 lines
3.3 KiB
Go
Raw Normal View History

2019-12-22 00:35:09 +03:00
package buffer
import (
2019-12-23 02:05:23 +03:00
"fmt"
2019-12-22 00:35:09 +03:00
"io"
2019-12-22 03:55:23 +03:00
"os"
2020-02-11 21:09:17 +03:00
"path/filepath"
2019-12-22 03:55:23 +03:00
"time"
2019-12-22 00:35:09 +03:00
2020-05-04 17:16:15 +03:00
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/v2/internal/util"
2019-12-22 00:35:09 +03:00
"golang.org/x/text/encoding"
)
2019-12-22 03:55:23 +03:00
const backupMsg = `A backup was detected for this file. This likely means that micro
crashed while editing this file, or another instance of micro is currently
editing this file.
The backup was created on %s, and the file is
%s
2019-12-22 03:55:23 +03:00
* 'recover' will apply the backup as unsaved changes to the current buffer.
When the buffer is closed, the backup will be removed.
* 'ignore' will ignore the backup, discarding its changes. The backup file
will be removed.
Options: [r]ecover, [i]gnore: `
var backupRequestChan chan *Buffer
func backupThread() {
for {
time.Sleep(time.Second * 8)
for len(backupRequestChan) > 0 {
b := <-backupRequestChan
b.Backup()
}
2019-12-22 00:35:09 +03:00
}
}
func init() {
backupRequestChan = make(chan *Buffer, 10)
go backupThread()
}
2019-12-22 00:35:09 +03:00
func (b *Buffer) RequestBackup() {
if !b.requestedBackup {
select {
case backupRequestChan <- b:
default:
// channel is full
2019-12-22 07:26:53 +03:00
}
b.requestedBackup = true
2019-12-22 03:55:23 +03:00
}
}
2019-12-22 03:55:23 +03:00
// Backup saves the current buffer to ConfigDir/backups
func (b *Buffer) Backup() error {
if !b.Settings["backup"].(bool) || b.Path == "" || b.Type != BTDefault {
return nil
}
2019-12-22 03:55:23 +03:00
backupdir, err := util.ReplaceHome(b.Settings["backupdir"].(string))
if len(backupdir) == 0 || err != nil {
backupdir = filepath.Join(config.ConfigDir, "backups")
}
2019-12-22 03:55:23 +03:00
if _, err := os.Stat(backupdir); os.IsNotExist(err) {
os.Mkdir(backupdir, os.ModePerm)
}
2020-02-11 21:09:17 +03:00
name := filepath.Join(backupdir, util.EscapePath(b.AbsPath))
2019-12-22 03:55:23 +03:00
err = overwriteFile(name, encoding.Nop, func(file io.Writer) (e error) {
2019-12-22 00:35:09 +03:00
if len(b.lines) == 0 {
return
}
// end of line
eol := []byte{'\n'}
// write lines
if _, e = file.Write(b.lines[0].data); e != nil {
return
}
for _, l := range b.lines[1:] {
if _, e = file.Write(eol); e != nil {
return
}
if _, e = file.Write(l.data); e != nil {
return
}
}
return
}, false)
2019-12-22 00:35:09 +03:00
b.requestedBackup = false
2019-12-22 00:35:09 +03:00
return err
}
2019-12-22 03:55:23 +03:00
// RemoveBackup removes any backup file associated with this buffer
func (b *Buffer) RemoveBackup() {
if !b.Settings["backup"].(bool) || b.Settings["permbackup"].(bool) || b.Path == "" || b.Type != BTDefault {
2019-12-22 03:55:23 +03:00
return
}
2020-02-11 21:09:17 +03:00
f := filepath.Join(config.ConfigDir, "backups", util.EscapePath(b.AbsPath))
2019-12-22 03:55:23 +03:00
os.Remove(f)
}
2019-12-22 00:35:09 +03:00
// ApplyBackup applies the corresponding backup file to this buffer (if one exists)
2019-12-23 02:05:23 +03:00
// Returns true if a backup was applied
func (b *Buffer) ApplyBackup(fsize int64) bool {
if b.Settings["backup"].(bool) && !b.Settings["permbackup"].(bool) && len(b.Path) > 0 && b.Type == BTDefault {
2020-02-11 21:09:17 +03:00
backupfile := filepath.Join(config.ConfigDir, "backups", util.EscapePath(b.AbsPath))
2019-12-23 02:05:23 +03:00
if info, err := os.Stat(backupfile); err == nil {
backup, err := os.Open(backupfile)
if err == nil {
defer backup.Close()
t := info.ModTime()
msg := fmt.Sprintf(backupMsg, t.Format("Mon Jan _2 at 15:04, 2006"), util.EscapePath(b.AbsPath))
2019-12-23 02:05:23 +03:00
choice := screen.TermPrompt(msg, []string{"r", "i", "recover", "ignore"}, true)
if choice%2 == 0 {
// recover
b.LineArray = NewLineArray(uint64(fsize), FFAuto, backup)
b.isModified = true
return true
} else if choice%2 == 1 {
// delete
os.Remove(backupfile)
}
}
}
}
return false
2019-12-22 00:35:09 +03:00
}