]> git.lizzy.rs Git - micro.git/commitdiff
Improved save with sudo
authorZachary Yedidia <zyedidia@gmail.com>
Sun, 22 Dec 2019 22:24:00 +0000 (17:24 -0500)
committerZachary Yedidia <zyedidia@gmail.com>
Wed, 25 Dec 2019 22:05:11 +0000 (17:05 -0500)
internal/buffer/save.go
internal/display/bufwindow.go

index fde6cf96098e1065fbd6d280b119667d49c7651d..240526e8ed5e7577426c965c1e16e0621e22a63b 100644 (file)
@@ -12,6 +12,7 @@ import (
        "unicode/utf8"
 
        "github.com/zyedidia/micro/internal/config"
+       "github.com/zyedidia/micro/internal/screen"
        . "github.com/zyedidia/micro/internal/util"
        "golang.org/x/text/encoding"
        "golang.org/x/text/encoding/htmlindex"
@@ -49,6 +50,48 @@ func overwriteFile(name string, enc encoding.Encoding, fn func(io.Writer) error)
        return
 }
 
+// overwriteFileAsRoot executes dd as root and then calls the supplied function
+// with dd's standard input as an io.Writer object. Dd opens the given file for writing,
+// truncating it if it exists, and writes what it receives on its standard input to the file.
+func overwriteFileAsRoot(name string, enc encoding.Encoding, fn func(io.Writer) error) (err error) {
+       cmd := exec.Command(config.GlobalSettings["sucmd"].(string), "dd", "status=none", "bs=4K", "of="+name)
+       var stdin io.WriteCloser
+
+       screenb := screen.TempFini()
+
+       // This is a trap for Ctrl-C so that it doesn't kill micro
+       // Instead we trap Ctrl-C to kill the program we're running
+       c := make(chan os.Signal, 1)
+       signal.Notify(c, os.Interrupt)
+       go func() {
+               for range c {
+                       cmd.Process.Kill()
+               }
+       }()
+
+       if stdin, err = cmd.StdinPipe(); err != nil {
+               return
+       }
+
+       if err = cmd.Start(); err != nil {
+               return
+       }
+
+       e := fn(stdin)
+
+       if err = stdin.Close(); err != nil {
+               return
+       }
+
+       if err = cmd.Wait(); err != nil {
+               return
+       }
+
+       screen.TempStart(screenb)
+
+       return e
+}
+
 // Save saves the buffer to its default path
 func (b *Buffer) Save() error {
        return b.SaveAs(b.Path)
@@ -56,6 +99,18 @@ func (b *Buffer) Save() error {
 
 // SaveAs saves the buffer to a specified path (filename), creating the file if it does not exist
 func (b *Buffer) SaveAs(filename string) error {
+       return b.saveToFile(filename, false)
+}
+
+func (b *Buffer) SaveWithSudo() error {
+       return b.SaveAsWithSudo(b.Path)
+}
+
+func (b *Buffer) SaveAsWithSudo(filename string) error {
+       return b.saveToFile(filename, true)
+}
+
+func (b *Buffer) saveToFile(filename string, withSudo bool) error {
        var err error
        if b.Type.Readonly {
                return errors.New("Cannot save readonly buffer")
@@ -116,7 +171,7 @@ func (b *Buffer) SaveAs(filename string) error {
                return err
        }
 
-       err = overwriteFile(absFilename, enc, func(file io.Writer) (e error) {
+       fwriter := func(file io.Writer) (e error) {
                if len(b.lines) == 0 {
                        return
                }
@@ -144,7 +199,13 @@ func (b *Buffer) SaveAs(filename string) error {
                        fileSize += len(eol) + len(l.data)
                }
                return
-       })
+       }
+
+       if withSudo {
+               err = overwriteFileAsRoot(absFilename, enc, fwriter)
+       } else {
+               err = overwriteFile(absFilename, enc, fwriter)
+       }
 
        if err != nil {
                return err
@@ -165,46 +226,3 @@ func (b *Buffer) SaveAs(filename string) error {
        b.isModified = false
        return err
 }
-
-// SaveWithSudo saves the buffer to the default path with sudo
-func (b *Buffer) SaveWithSudo() error {
-       return b.SaveAsWithSudo(b.Path)
-}
-
-// SaveAsWithSudo is the same as SaveAs except it uses a neat trick
-// with tee to use sudo so the user doesn't have to reopen micro with sudo
-func (b *Buffer) SaveAsWithSudo(filename string) error {
-       if b.Type.Scratch {
-               return errors.New("Cannot save scratch buffer")
-       }
-
-       b.UpdateRules()
-       b.Path = filename
-       absPath, _ := filepath.Abs(filename)
-       b.AbsPath = absPath
-
-       // Set up everything for the command
-       cmd := exec.Command(config.GlobalSettings["sucmd"].(string), "tee", filename)
-       cmd.Stdin = bytes.NewBuffer(b.Bytes())
-
-       // This is a trap for Ctrl-C so that it doesn't kill micro
-       // Instead we trap Ctrl-C to kill the program we're running
-       c := make(chan os.Signal, 1)
-       signal.Notify(c, os.Interrupt)
-       go func() {
-               for range c {
-                       cmd.Process.Kill()
-               }
-       }()
-
-       // Start the command
-       cmd.Start()
-       err := cmd.Wait()
-
-       if err == nil {
-               b.isModified = false
-               b.ModTime, _ = GetModTime(filename)
-               return b.Serialize()
-       }
-       return err
-}
index 65b0917b9ac4526c271a9e717fc41c6850bca3d1..b69673290339efd5d6967d3fc27661a6bf46c280 100644 (file)
@@ -118,12 +118,12 @@ func (w *BufWindow) Clear() {
 // but if softwrap is enabled things get complicated since one buffer
 // line can take up multiple lines in the view
 func (w *BufWindow) Bottomline() int {
-       // b := w.Buf
+       b := w.Buf
 
        // TODO: possible non-softwrap optimization
-       // if !b.Settings["softwrap"].(bool) {
-       //      return w.StartLine + w.Height
-       // }
+       if !b.Settings["softwrap"].(bool) || !w.hasCalcHeight {
+               return w.StartLine + w.Height
+       }
 
        prev := 0
        for _, l := range w.lineHeight {