From 9e8d76f2fa91463be660737d1de3bff61258c90d Mon Sep 17 00:00:00 2001 From: Zachary Yedidia Date: Thu, 27 Feb 2020 12:39:19 -0500 Subject: [PATCH] If stdout is a pipe, output to the pipe If you run micro as `micro | cat` for example, micro will disallow you from saving the file, and when you quit the buffer, the contents will be sent to the pipe. This allows one to use micro as part of an interactive unix pipeline. Closes #1524 --- cmd/micro/micro.go | 18 ++++++++++++++---- internal/buffer/buffer.go | 10 ++++++++++ internal/util/util.go | 5 +++++ 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/cmd/micro/micro.go b/cmd/micro/micro.go index 950e8888..966f252c 100644 --- a/cmd/micro/micro.go +++ b/cmd/micro/micro.go @@ -147,11 +147,16 @@ func LoadInput() []*buffer.Buffer { args := flag.Args() buffers := make([]*buffer.Buffer, 0, len(args)) + btype := buffer.BTDefault + if !isatty.IsTerminal(os.Stdout.Fd()) { + btype = buffer.BTStdout + } + if len(args) > 0 { // Option 1 // We go through each file and load it for i := 0; i < len(args); i++ { - buf, err := buffer.NewBufferFromFile(args[i], buffer.BTDefault) + buf, err := buffer.NewBufferFromFile(args[i], btype) if err != nil { screen.TermMessage(err) continue @@ -168,17 +173,22 @@ func LoadInput() []*buffer.Buffer { screen.TermMessage("Error reading from stdin: ", err) input = []byte{} } - buffers = append(buffers, buffer.NewBufferFromString(string(input), filename, buffer.BTDefault)) + buffers = append(buffers, buffer.NewBufferFromString(string(input), filename, btype)) } else { // Option 3, just open an empty buffer - buffers = append(buffers, buffer.NewBufferFromString(string(input), filename, buffer.BTDefault)) + buffers = append(buffers, buffer.NewBufferFromString(string(input), filename, btype)) } return buffers } func main() { - defer os.Exit(0) + defer func() { + if util.Stdout.Len() > 0 { + fmt.Fprint(os.Stdout, util.Stdout.String()) + } + os.Exit(0) + }() // runtime.SetCPUProfileRate(400) // f, _ := os.Create("micro.prof") diff --git a/internal/buffer/buffer.go b/internal/buffer/buffer.go index f08f5323..2093e94b 100644 --- a/internal/buffer/buffer.go +++ b/internal/buffer/buffer.go @@ -5,6 +5,7 @@ import ( "bytes" "crypto/md5" "errors" + "fmt" "io" "io/ioutil" "os" @@ -60,6 +61,9 @@ var ( BTRaw = BufType{4, false, true, false} // BTInfo is a buffer for inputting information BTInfo = BufType{5, false, true, false} + // BTStdout is a buffer that only writes to stdout + // when closed + BTStdout = BufType{6, false, true, true} // ErrFileTooLarge is returned when the file is too large to hash // (fastdirty is automatically enabled) @@ -82,6 +86,8 @@ type SharedBuffer struct { // Name of the buffer on the status line name string + toStdout bool + // Settings customized by the user Settings map[string]interface{} @@ -355,6 +361,10 @@ func (b *Buffer) Fini() { b.Serialize() } b.RemoveBackup() + + if b.Type == BTStdout { + fmt.Fprint(util.Stdout, string(b.Bytes())) + } } // GetName returns the name that should be displayed in the statusline diff --git a/internal/util/util.go b/internal/util/util.go index aebe8e17..70f1fd2a 100644 --- a/internal/util/util.go +++ b/internal/util/util.go @@ -1,6 +1,7 @@ package util import ( + "bytes" "errors" "fmt" "os" @@ -34,6 +35,9 @@ var ( // FakeCursor is used to disable the terminal cursor and have micro // draw its own (enabled for windows consoles where the cursor is slow) FakeCursor = false + + // Stdout is a buffer that is written to stdout when micro closes + Stdout *bytes.Buffer ) func init() { @@ -46,6 +50,7 @@ func init() { if runtime.GOOS == "windows" { FakeCursor = true } + Stdout = new(bytes.Buffer) } // SliceEnd returns a byte slice where the index is a rune index