From eeaac76f5f9c6aa47d3f4eb762d87066a8fdb9f8 Mon Sep 17 00:00:00 2001 From: Zachary Yedidia Date: Tue, 29 Nov 2016 13:44:30 -0500 Subject: [PATCH] Use io.Readers to read files more efficiently --- cmd/micro/actions.go | 6 +++--- cmd/micro/buffer.go | 14 +++++++++++--- cmd/micro/command.go | 18 ++++++++++-------- cmd/micro/lineArray.go | 25 ++++++++++++++++++------- cmd/micro/messenger.go | 3 ++- cmd/micro/micro.go | 12 ++++++++---- cmd/micro/statusline.go | 3 --- cmd/micro/tab.go | 2 -- cmd/micro/view.go | 9 +++++---- 9 files changed, 57 insertions(+), 35 deletions(-) diff --git a/cmd/micro/actions.go b/cmd/micro/actions.go index 2c37695b..8b31b0ab 100644 --- a/cmd/micro/actions.go +++ b/cmd/micro/actions.go @@ -1469,7 +1469,7 @@ func (v *View) AddTab(usePlugin bool) bool { return false } - tab := NewTabFromView(NewView(NewBuffer([]byte{}, ""))) + tab := NewTabFromView(NewView(NewBuffer(strings.NewReader(""), ""))) tab.SetNum(len(tabs)) tabs = append(tabs, tab) curTab++ @@ -1529,7 +1529,7 @@ func (v *View) VSplitBinding(usePlugin bool) bool { return false } - v.VSplit(NewBuffer([]byte{}, "")) + v.VSplit(NewBuffer(strings.NewReader(""), "")) if usePlugin { return PostActionCall("VSplit", v) @@ -1543,7 +1543,7 @@ func (v *View) HSplitBinding(usePlugin bool) bool { return false } - v.HSplit(NewBuffer([]byte{}, "")) + v.HSplit(NewBuffer(strings.NewReader(""), "")) if usePlugin { return PostActionCall("HSplit", v) diff --git a/cmd/micro/buffer.go b/cmd/micro/buffer.go index 9bdc1250..a3041473 100644 --- a/cmd/micro/buffer.go +++ b/cmd/micro/buffer.go @@ -3,6 +3,7 @@ package main import ( "bytes" "encoding/gob" + "io" "io/ioutil" "os" "os/exec" @@ -55,8 +56,12 @@ type SerializedBuffer struct { ModTime time.Time } -// NewBuffer creates a new buffer from `txt` with path and name `path` -func NewBuffer(txt []byte, path string) *Buffer { +func NewBufferFromString(text, path string) *Buffer { + return NewBuffer(strings.NewReader(text), path) +} + +// NewBuffer creates a new buffer from a given reader with a given path +func NewBuffer(reader io.Reader, path string) *Buffer { if path != "" { for _, tab := range tabs { for _, view := range tab.views { @@ -68,7 +73,7 @@ func NewBuffer(txt []byte, path string) *Buffer { } b := new(Buffer) - b.LineArray = NewLineArray(txt) + b.LineArray = NewLineArray(reader) b.Settings = DefaultLocalSettings() for k, v := range globalSettings { @@ -166,6 +171,9 @@ func NewBuffer(txt []byte, path string) *Buffer { func (b *Buffer) GetName() string { if b.name == "" { + if b.Path == "" { + return "No name" + } return b.Path } return b.name diff --git a/cmd/micro/command.go b/cmd/micro/command.go index a5208eeb..203212be 100644 --- a/cmd/micro/command.go +++ b/cmd/micro/command.go @@ -4,7 +4,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "os" "os/exec" "os/signal" @@ -266,17 +265,18 @@ func Help(args []string) { // If no file is given, it opens an empty buffer in a new split func VSplit(args []string) { if len(args) == 0 { - CurView().VSplit(NewBuffer([]byte{}, "")) + CurView().VSplit(NewBuffer(strings.NewReader(""), "")) } else { filename := args[0] home, _ := homedir.Dir() filename = strings.Replace(filename, "~", home, 1) - file, err := ioutil.ReadFile(filename) + file, err := os.Open(filename) + defer file.Close() var buf *Buffer if err != nil { // File does not exist -- create an empty buffer with that name - buf = NewBuffer([]byte{}, filename) + buf = NewBuffer(strings.NewReader(""), filename) } else { buf = NewBuffer(file, filename) } @@ -288,17 +288,18 @@ func VSplit(args []string) { // If no file is given, it opens an empty buffer in a new split func HSplit(args []string) { if len(args) == 0 { - CurView().HSplit(NewBuffer([]byte{}, "")) + CurView().HSplit(NewBuffer(strings.NewReader(""), "")) } else { filename := args[0] home, _ := homedir.Dir() filename = strings.Replace(filename, "~", home, 1) - file, err := ioutil.ReadFile(filename) + file, err := os.Open(filename) + defer file.Close() var buf *Buffer if err != nil { // File does not exist -- create an empty buffer with that name - buf = NewBuffer([]byte{}, filename) + buf = NewBuffer(strings.NewReader(""), filename) } else { buf = NewBuffer(file, filename) } @@ -326,7 +327,8 @@ func NewTab(args []string) { filename := args[0] home, _ := homedir.Dir() filename = strings.Replace(filename, "~", home, 1) - file, _ := ioutil.ReadFile(filename) + file, _ := os.Open(filename) + defer file.Close() tab := NewTabFromView(NewView(NewBuffer(file, filename))) tab.SetNum(len(tabs)) diff --git a/cmd/micro/lineArray.go b/cmd/micro/lineArray.go index 87f7395a..9583c04e 100644 --- a/cmd/micro/lineArray.go +++ b/cmd/micro/lineArray.go @@ -1,7 +1,9 @@ package main import ( + "bufio" "bytes" + "io" "unicode/utf8" ) @@ -33,14 +35,23 @@ type LineArray struct { } // NewLineArray returns a new line array from an array of bytes -func NewLineArray(text []byte) *LineArray { +func NewLineArray(reader io.Reader) *LineArray { la := new(LineArray) - // Split the bytes into lines - split := bytes.Split(text, []byte("\n")) - la.lines = make([][]byte, len(split)) - for i := range split { - la.lines[i] = make([]byte, len(split[i])) - copy(la.lines[i], split[i]) + br := bufio.NewReader(reader) + + i := 0 + for { + data, err := br.ReadBytes('\n') + if err != nil { + if err == io.EOF { + la.lines = append(la.lines, data[:len(data)]) + } + // Last line was read + break + } else { + la.lines = append(la.lines, data[:len(data)-1]) + } + i++ } return la diff --git a/cmd/micro/messenger.go b/cmd/micro/messenger.go index 5287832e..5cfdf1c2 100644 --- a/cmd/micro/messenger.go +++ b/cmd/micro/messenger.go @@ -6,6 +6,7 @@ import ( "fmt" "os" "strconv" + "strings" "github.com/zyedidia/clipboard" "github.com/zyedidia/tcell" @@ -78,7 +79,7 @@ func (m *Messenger) AddLog(msg string) { func (m *Messenger) getBuffer() *Buffer { if m.log == nil { - m.log = NewBuffer([]byte{}, "") + m.log = NewBuffer(strings.NewReader(""), "") m.log.name = "Log" } return m.log diff --git a/cmd/micro/micro.go b/cmd/micro/micro.go index 0fab44a6..e7dc2ef5 100644 --- a/cmd/micro/micro.go +++ b/cmd/micro/micro.go @@ -93,9 +93,11 @@ func LoadInput() []*Buffer { filename = flag.Args()[i] // Check that the file exists + var input *os.File if _, e := os.Stat(filename); e == nil { // If it exists we load it into a buffer - input, err = ioutil.ReadFile(filename) + input, err = os.Open(filename) + defer input.Close() if err != nil { TermMessage(err) continue @@ -103,6 +105,7 @@ func LoadInput() []*Buffer { } // If the file didn't exist, input will be empty, and we'll open an empty buffer buffers = append(buffers, NewBuffer(input, filename)) + fmt.Print("\a") } } else if !isatty.IsTerminal(os.Stdin.Fd()) { // Option 2 @@ -113,10 +116,10 @@ func LoadInput() []*Buffer { TermMessage("Error reading from stdin: ", err) input = []byte{} } - buffers = append(buffers, NewBuffer(input, filename)) + buffers = append(buffers, NewBuffer(strings.NewReader(string(input)), filename)) } else { // Option 3, just open an empty buffer - buffers = append(buffers, NewBuffer(input, filename)) + buffers = append(buffers, NewBuffer(strings.NewReader(string(input)), filename)) } return buffers @@ -335,7 +338,7 @@ func main() { L.SetGlobal("HandleShellCommand", luar.New(L, HandleShellCommand)) L.SetGlobal("GetLeadingWhitespace", luar.New(L, GetLeadingWhitespace)) L.SetGlobal("MakeCompletion", luar.New(L, MakeCompletion)) - L.SetGlobal("NewBuffer", luar.New(L, NewBuffer)) + L.SetGlobal("NewBuffer", luar.New(L, NewBufferFromString)) L.SetGlobal("RuneStr", luar.New(L, func(r rune) string { return string(r) })) @@ -404,6 +407,7 @@ func main() { }() for { + fmt.Print("\a") // Display everything RedrawAll() diff --git a/cmd/micro/statusline.go b/cmd/micro/statusline.go index 8614c8d8..7e646bfc 100644 --- a/cmd/micro/statusline.go +++ b/cmd/micro/statusline.go @@ -18,9 +18,6 @@ func (sline *Statusline) Display() { y := sline.view.Height + sline.view.y file := sline.view.Buf.GetName() - if file == "" { - file = "No name" - } // If the buffer is dirty (has been modified) write a little '+' if sline.view.Buf.IsModified { diff --git a/cmd/micro/tab.go b/cmd/micro/tab.go index b9940707..885867c2 100644 --- a/cmd/micro/tab.go +++ b/cmd/micro/tab.go @@ -13,8 +13,6 @@ type Tab struct { views []*View // This is the current view for this tab CurView int - // Generally this is the name of the current view's buffer - name string tree *SplitTree } diff --git a/cmd/micro/view.go b/cmd/micro/view.go index f10cc8ff..61b9b140 100644 --- a/cmd/micro/view.go +++ b/cmd/micro/view.go @@ -1,7 +1,7 @@ package main import ( - "io/ioutil" + "os" "strconv" "strings" "time" @@ -242,13 +242,14 @@ func (v *View) OpenBuffer(buf *Buffer) { func (v *View) Open(filename string) { home, _ := homedir.Dir() filename = strings.Replace(filename, "~", home, 1) - file, err := ioutil.ReadFile(filename) + file, err := os.Open(filename) + defer file.Close() var buf *Buffer if err != nil { messenger.Message(err.Error()) // File does not exist -- create an empty buffer with that name - buf = NewBuffer([]byte{}, filename) + buf = NewBuffer(strings.NewReader(""), filename) } else { buf = NewBuffer(file, filename) } @@ -630,7 +631,7 @@ func (v *View) openHelp(helpPage string) { if data, err := FindRuntimeFile(RTHelp, helpPage).Data(); err != nil { TermMessage("Unable to load help text", helpPage, "\n", err) } else { - helpBuffer := NewBuffer(data, helpPage+".md") + helpBuffer := NewBuffer(strings.NewReader(string(data)), helpPage+".md") helpBuffer.name = "Help" if v.Type == vtHelp {