From a9120ce270c5374fcff4d83cc5c7d40ab36ff0e4 Mon Sep 17 00:00:00 2001 From: Zachary Yedidia Date: Wed, 19 Feb 2020 14:41:30 -0500 Subject: [PATCH] Share more buffer elements and fix rehighlight Fixes #1521 --- internal/buffer/buffer.go | 153 ++++++++++++++++++---------------- internal/display/bufwindow.go | 17 +--- 2 files changed, 82 insertions(+), 88 deletions(-) diff --git a/internal/buffer/buffer.go b/internal/buffer/buffer.go index c8ee1104..87bf8c01 100644 --- a/internal/buffer/buffer.go +++ b/internal/buffer/buffer.go @@ -75,6 +75,32 @@ type SharedBuffer struct { // Type of the buffer (e.g. help, raw, scratch etc..) Type BufType + // Path to the file on disk + Path string + // Absolute path to the file on disk + AbsPath string + // Name of the buffer on the status line + name string + + // Settings customized by the user + Settings map[string]interface{} + + Suggestions []string + Completions []string + CurSuggestion int + + Messages []*Message + + updateDiffTimer *time.Timer + diffBase []byte + diffBaseLineCount int + diffLock sync.RWMutex + diff map[int]DiffStatus + + // counts the number of edits + // resets every backupTime edits + lastbackup time.Time + // ReloadDisabled allows the user to disable reloads if they // are viewing a file that is constantly changing ReloadDisabled bool @@ -84,8 +110,13 @@ type SharedBuffer struct { // it changes based on how the buffer has changed HasSuggestions bool - // Modifications is the list of modified regions for syntax highlighting - Modifications []Loc + // The Highlighter struct actually performs the highlighting + Highlighter *highlight.Highlighter + // SyntaxDef represents the syntax highlighting definition being used + // This stores the highlighting rules and filetype detection info + SyntaxDef *highlight.Def + + ModifiedThisFrame bool // Hash of the original buffer -- empty if fastdirty is on origHash [md5.Size]byte @@ -96,17 +127,38 @@ func (b *SharedBuffer) insert(pos Loc, value []byte) { b.HasSuggestions = false b.LineArray.insert(pos, value) - // b.Modifications is cleared every screen redraw so it's - // ok to append duplicates - b.Modifications = append(b.Modifications, Loc{pos.Y, pos.Y + bytes.Count(value, []byte{'\n'})}) + inslines := bytes.Count(value, []byte{'\n'}) + log.Println("insert", string(value), pos.Y, pos.Y+inslines) + b.MarkModified(pos.Y, pos.Y+inslines) } func (b *SharedBuffer) remove(start, end Loc) []byte { b.isModified = true b.HasSuggestions = false - b.Modifications = append(b.Modifications, Loc{start.Y, start.Y}) + defer b.MarkModified(start.Y, end.Y) return b.LineArray.remove(start, end) } +// MarkModified marks the buffer as modified for this frame +// and performs rehighlighting if syntax highlighting is enabled +func (b *SharedBuffer) MarkModified(start, end int) { + b.ModifiedThisFrame = true + + if !b.Settings["syntax"].(bool) || b.SyntaxDef == nil { + return + } + + log.Println("Modified", start, end, len(b.lines)) + start = util.Clamp(start, 0, len(b.lines)) + end = util.Clamp(end, 0, len(b.lines)) + + l := -1 + log.Println("Modified", start, end) + for i := start; i <= end; i++ { + l = util.Max(b.Highlighter.ReHighlightStates(b, i), l) + } + b.Highlighter.HighlightMatches(b, start, l+1) +} + // DisableReload disables future reloads of this sharedbuffer func (b *SharedBuffer) DisableReload() { b.ReloadDisabled = true @@ -135,39 +187,6 @@ type Buffer struct { cursors []*Cursor curCursor int StartCursor Loc - - // Path to the file on disk - Path string - // Absolute path to the file on disk - AbsPath string - // Name of the buffer on the status line - name string - - // SyntaxDef represents the syntax highlighting definition being used - // This stores the highlighting rules and filetype detection info - SyntaxDef *highlight.Def - // The Highlighter struct actually performs the highlighting - Highlighter *highlight.Highlighter - HighlightLock sync.Mutex - - // Settings customized by the user - Settings map[string]interface{} - - Suggestions []string - Completions []string - CurSuggestion int - - Messages []*Message - - updateDiffTimer *time.Timer - diffBase []byte - diffBaseLineCount int - diffLock sync.RWMutex - diff map[int]DiffStatus - - // counts the number of edits - // resets every backupTime edits - lastbackup time.Time } // NewBufferFromFile opens a new buffer using the given path @@ -222,23 +241,6 @@ func NewBuffer(r io.Reader, size int64, path string, startcursor Loc, btype BufT b := new(Buffer) - b.Settings = config.DefaultCommonSettings() - for k, v := range config.GlobalSettings { - if _, ok := config.DefaultGlobalOnlySettings[k]; !ok { - // make sure setting is not global-only - b.Settings[k] = v - } - } - config.InitLocalSettings(b.Settings, path) - - enc, err := htmlindex.Get(b.Settings["encoding"].(string)) - if err != nil { - enc = unicode.UTF8 - b.Settings["encoding"] = "utf-8" - } - - reader := bufio.NewReader(transform.NewReader(r, enc.NewDecoder())) - found := false if len(path) > 0 { for _, buf := range OpenBuffers { @@ -250,16 +252,32 @@ func NewBuffer(r io.Reader, size int64, path string, startcursor Loc, btype BufT } } - b.Path = path - b.AbsPath = absPath - if !found { b.SharedBuffer = new(SharedBuffer) b.Type = btype + b.AbsPath = absPath + b.Path = path + + b.Settings = config.DefaultCommonSettings() + for k, v := range config.GlobalSettings { + if _, ok := config.DefaultGlobalOnlySettings[k]; !ok { + // make sure setting is not global-only + b.Settings[k] = v + } + } + config.InitLocalSettings(b.Settings, path) + + enc, err := htmlindex.Get(b.Settings["encoding"].(string)) + if err != nil { + enc = unicode.UTF8 + b.Settings["encoding"] = "utf-8" + } + hasBackup := b.ApplyBackup(size) if !hasBackup { + reader := bufio.NewReader(transform.NewReader(r, enc.NewDecoder())) b.LineArray = NewLineArray(uint64(size), FFAuto, reader) } b.EventHandler = NewEventHandler(b.SharedBuffer, b.cursors) @@ -280,6 +298,7 @@ func NewBuffer(r io.Reader, size int64, path string, startcursor Loc, btype BufT } b.UpdateRules() + // init local settings again now that we know the filetype config.InitLocalSettings(b.Settings, b.Path) if _, err := os.Stat(filepath.Join(config.ConfigDir, "buffers")); os.IsNotExist(err) { @@ -309,13 +328,11 @@ func NewBuffer(r io.Reader, size int64, path string, startcursor Loc, btype BufT } } - err = config.RunPluginFn("onBufferOpen", luar.New(ulua.L, b)) + err := config.RunPluginFn("onBufferOpen", luar.New(ulua.L, b)) if err != nil { screen.TermMessage(err) } - b.Modifications = make([]Loc, 0, 10) - OpenBuffers = append(OpenBuffers, b) return b @@ -382,16 +399,6 @@ func (b *Buffer) Remove(start, end Loc) { } } -// ClearModifications clears the list of modified lines in this buffer -// The list of modified lines is used for syntax highlighting so that -// we can selectively highlight only the necessary lines -// This function should be called every time this buffer is drawn to -// the screen -func (b *Buffer) ClearModifications() { - // clear slice without resetting the cap - b.Modifications = b.Modifications[:0] -} - // FileType returns the buffer's filetype func (b *Buffer) FileType() string { return b.Settings["filetype"].(string) @@ -922,7 +929,7 @@ func (b *Buffer) Retab() { l = bytes.TrimLeft(l, " \t") b.lines[i].data = append(ws, l...) - b.Modifications = append(b.Modifications, Loc{i, i}) + b.MarkModified(i, i) dirty = true } diff --git a/internal/display/bufwindow.go b/internal/display/bufwindow.go index 7ebdcf34..372b13dc 100644 --- a/internal/display/bufwindow.go +++ b/internal/display/bufwindow.go @@ -397,21 +397,7 @@ func (w *BufWindow) displayBuffer() { bufWidth-- } - if len(b.Modifications) > 0 { - if b.Settings["syntax"].(bool) && b.SyntaxDef != nil { - for _, r := range b.Modifications { - rx := util.Clamp(r.X, 0, b.LinesNum()) - ry := util.Clamp(r.Y, 0, b.LinesNum()) - final := -1 - for i := rx; i <= ry; i++ { - final = util.Max(b.Highlighter.ReHighlightStates(b, i), final) - } - b.Highlighter.HighlightMatches(b, rx, final+1) - } - } - - b.ClearModifications() - + if b.ModifiedThisFrame { if b.Settings["diffgutter"].(bool) { b.UpdateDiff(func(synchronous bool) { // If the diff was updated asynchronously, the outer call to @@ -426,6 +412,7 @@ func (w *BufWindow) displayBuffer() { } }) } + b.ModifiedThisFrame = false } var matchingBraces []buffer.Loc