From 64370b70d6d6bcf46be424ec78bdb85aa591d6e5 Mon Sep 17 00:00:00 2001 From: Dmitry Maluka Date: Tue, 20 Oct 2020 22:10:41 +0200 Subject: [PATCH 1/8] Highlighting tab errors Added option `hltaberrors` which helps to spot sloppy whitespace errors with tabs used instead of spaces or vice versa. It uses the value of `tabstospaces` option as a criterion whether a tab or space character is an error or not. If `tabstospaces` is on, we probably expect that the file should contain no tab characters, so any tab character is highlighted as an error. If `tabstospaces` is off, we probably expect that the file uses indentation with tabs, so space characters in the initial indent part of lines are highlighted as errors. --- internal/config/settings.go | 1 + internal/display/bufwindow.go | 14 ++++++++++++++ runtime/help/options.md | 7 +++++++ 3 files changed, 22 insertions(+) diff --git a/internal/config/settings.go b/internal/config/settings.go index 3b9bfaef..40e271b7 100644 --- a/internal/config/settings.go +++ b/internal/config/settings.go @@ -289,6 +289,7 @@ var defaultCommonSettings = map[string]interface{}{ "fileformat": defaultFileFormat(), "filetype": "unknown", "hlsearch": false, + "hltaberrors": false, "incsearch": true, "ignorecase": true, "indentchar": " ", diff --git a/internal/display/bufwindow.go b/internal/display/bufwindow.go index 6e67f845..8d4645e0 100644 --- a/internal/display/bufwindow.go +++ b/internal/display/bufwindow.go @@ -495,6 +495,8 @@ func (w *BufWindow) displayBuffer() { vloc.X = w.gutterOffset } + leadingwsEnd := len(util.GetLeadingWhitespace(b.LineBytes(bloc.Y))) + line, nColsBeforeStart, bslice, startStyle := w.getStartInfo(w.StartCol, bloc.Y) if startStyle != nil { curStyle = *startStyle @@ -518,6 +520,18 @@ func (w *BufWindow) displayBuffer() { // over cursor-line and color-column dontOverrideBackground := origBg != defBg + if b.Settings["hltaberrors"].(bool) { + if s, ok := config.Colorscheme["tab-error"]; ok { + isTab := (r == '\t') || (r == ' ' && !showcursor) + if (b.Settings["tabstospaces"].(bool) && isTab) || + (!b.Settings["tabstospaces"].(bool) && bloc.X < leadingwsEnd && r == ' ' && !isTab) { + fg, _, _ := s.Decompose() + style = style.Background(fg) + dontOverrideBackground = true + } + } + } + for _, c := range cursors { if c.HasSelection() && (bloc.GreaterEqual(c.CurSelection[0]) && bloc.LessThan(c.CurSelection[1]) || diff --git a/runtime/help/options.md b/runtime/help/options.md index a492bc44..3826f27b 100644 --- a/runtime/help/options.md +++ b/runtime/help/options.md @@ -174,6 +174,13 @@ Here are the available options: default value: `false` +* `hltaberrors`: highlight tabs when spaces are expected, and spaces when tabs + are expected. More precisely: if `tabstospaces` option is on, highlight + all tab characters; if `tabstospaces` is off, highlight space characters + in the initial indent part of the line. + + default value: `false` + * `incsearch`: enable incremental search in "Find" prompt (matching as you type). default value: `true` From 104caf08dd9ee1bd4be324ff9867b629aca3a08a Mon Sep 17 00:00:00 2001 From: Dmitry Maluka Date: Tue, 20 Oct 2020 22:52:49 +0200 Subject: [PATCH 2/8] Highlighting trailing whitespaces Added option `hltrailingws` for highlighting trailing whitespaces at the end of lines. Note that it behaves in a "smart" way. It doesn't highlight newly added (transient) trailing whitespaces that naturally occur while typing text. It would be annoying to see transient highlighting every time we enter a space at the end of a line while typing. So a newly added trailing whitespace starts being highlighting only after the cursor moves to another line. Thus the highlighting serves its purpose: it draws our attention to annoying sloppy forgotten trailing whitespaces. --- internal/action/bufpane.go | 7 +++++ internal/buffer/cursor.go | 7 +++++ internal/buffer/eventhandler.go | 51 +++++++++++++++++++++++++++++++++ internal/config/settings.go | 1 + internal/display/bufwindow.go | 25 +++++++++++++++- internal/util/util.go | 23 +++++++++++++++ runtime/help/options.md | 6 ++++ 7 files changed, 119 insertions(+), 1 deletion(-) diff --git a/internal/action/bufpane.go b/internal/action/bufpane.go index dea7b906..89d174c7 100644 --- a/internal/action/bufpane.go +++ b/internal/action/bufpane.go @@ -509,6 +509,13 @@ func (h *BufPane) HandleEvent(event tcell.Event) { InfoBar.ClearGutter() } } + + cursors := h.Buf.GetCursors() + for _, c := range cursors { + if c.NewTrailingWsY != c.Y { + c.NewTrailingWsY = -1 + } + } } // Bindings returns the current bindings tree for this buffer. diff --git a/internal/buffer/cursor.go b/internal/buffer/cursor.go index 12fc5db2..bd3ae068 100644 --- a/internal/buffer/cursor.go +++ b/internal/buffer/cursor.go @@ -30,6 +30,11 @@ type Cursor struct { // to know what the original selection was OrigSelection [2]Loc + // The line number where a new trailing whitespace has been added + // or -1 if there is no new trailing whitespace at this cursor. + // This is used for checking if a trailing whitespace should be highlighted + NewTrailingWsY int + // Which cursor index is this (for multiple cursors) Num int } @@ -38,6 +43,8 @@ func NewCursor(b *Buffer, l Loc) *Cursor { c := &Cursor{ buf: b, Loc: l, + + NewTrailingWsY: -1, } c.StoreVisualX() return c diff --git a/internal/buffer/eventhandler.go b/internal/buffer/eventhandler.go index 6be34bce..66c44dba 100644 --- a/internal/buffer/eventhandler.go +++ b/internal/buffer/eventhandler.go @@ -106,6 +106,8 @@ func (eh *EventHandler) DoTextEvent(t *TextEvent, useUndo bool) { c.Relocate() c.LastVisualX = c.GetVisualX() } + + eh.updateTrailingWs(t) } // ExecuteTextEvent runs a text event @@ -342,3 +344,52 @@ func (eh *EventHandler) RedoOneEvent() { eh.UndoStack.Push(t) } + +// updateTrailingWs updates the cursor's trailing whitespace status after a text event +func (eh *EventHandler) updateTrailingWs(t *TextEvent) { + if len(t.Deltas) != 1 { + return + } + text := t.Deltas[0].Text + start := t.Deltas[0].Start + end := t.Deltas[0].End + + c := eh.cursors[eh.active] + isEol := func(loc Loc) bool { + return loc.X == util.CharacterCount(eh.buf.LineBytes(loc.Y)) + } + if t.EventType == TextEventInsert && c.Loc == end && isEol(end) { + var addedTrailingWs bool + addedAfterWs := false + addedWsOnly := false + if start.Y == end.Y { + addedTrailingWs = util.HasTrailingWhitespace(text) + addedWsOnly = util.IsBytesWhitespace(text) + addedAfterWs = start.X > 0 && util.IsWhitespace(c.buf.RuneAt(Loc{start.X - 1, start.Y})) + } else { + lastnl := bytes.LastIndex(text, []byte{'\n'}) + addedTrailingWs = util.HasTrailingWhitespace(text[lastnl+1:]) + } + + if addedTrailingWs && !(addedAfterWs && addedWsOnly) { + c.NewTrailingWsY = c.Y + } else if !addedTrailingWs { + c.NewTrailingWsY = -1 + } + } else if t.EventType == TextEventRemove && c.Loc == start && isEol(start) { + removedAfterWs := util.HasTrailingWhitespace(eh.buf.LineBytes(start.Y)) + var removedWsOnly bool + if start.Y == end.Y { + removedWsOnly = util.IsBytesWhitespace(text) + } else { + firstnl := bytes.Index(text, []byte{'\n'}) + removedWsOnly = util.IsBytesWhitespace(text[:firstnl]) + } + + if removedAfterWs && !removedWsOnly { + c.NewTrailingWsY = c.Y + } else if !removedAfterWs { + c.NewTrailingWsY = -1 + } + } +} diff --git a/internal/config/settings.go b/internal/config/settings.go index 40e271b7..bfb1061f 100644 --- a/internal/config/settings.go +++ b/internal/config/settings.go @@ -290,6 +290,7 @@ var defaultCommonSettings = map[string]interface{}{ "filetype": "unknown", "hlsearch": false, "hltaberrors": false, + "hltrailingws": false, "incsearch": true, "ignorecase": true, "indentchar": " ", diff --git a/internal/display/bufwindow.go b/internal/display/bufwindow.go index 8d4645e0..942dd167 100644 --- a/internal/display/bufwindow.go +++ b/internal/display/bufwindow.go @@ -495,7 +495,11 @@ func (w *BufWindow) displayBuffer() { vloc.X = w.gutterOffset } - leadingwsEnd := len(util.GetLeadingWhitespace(b.LineBytes(bloc.Y))) + bline := b.LineBytes(bloc.Y) + blineLen := util.CharacterCount(bline) + + leadingwsEnd := len(util.GetLeadingWhitespace(bline)) + trailingwsStart := blineLen - util.CharacterCount(util.GetTrailingWhitespace(bline)) line, nColsBeforeStart, bslice, startStyle := w.getStartInfo(w.StartCol, bloc.Y) if startStyle != nil { @@ -532,6 +536,25 @@ func (w *BufWindow) displayBuffer() { } } + if b.Settings["hltrailingws"].(bool) { + if s, ok := config.Colorscheme["trailingws"]; ok { + if bloc.X >= trailingwsStart && bloc.X < blineLen { + hl := true + for _, c := range cursors { + if c.NewTrailingWsY == bloc.Y { + hl = false + break + } + } + if hl { + fg, _, _ := s.Decompose() + style = style.Background(fg) + dontOverrideBackground = true + } + } + } + } + for _, c := range cursors { if c.HasSelection() && (bloc.GreaterEqual(c.CurSelection[0]) && bloc.LessThan(c.CurSelection[1]) || diff --git a/internal/util/util.go b/internal/util/util.go index fb21c487..bebd949b 100644 --- a/internal/util/util.go +++ b/internal/util/util.go @@ -16,6 +16,7 @@ import ( "strings" "time" "unicode" + "unicode/utf8" "github.com/blang/semver" runewidth "github.com/mattn/go-runewidth" @@ -363,6 +364,28 @@ func GetLeadingWhitespace(b []byte) []byte { return ws } +// GetTrailingWhitespace returns the trailing whitespace of the given byte array +func GetTrailingWhitespace(b []byte) []byte { + ws := []byte{} + for len(b) > 0 { + r, size := utf8.DecodeLastRune(b) + if IsWhitespace(r) { + ws = append([]byte(string(r)), ws...) + } else { + break + } + + b = b[:len(b)-size] + } + return ws +} + +// HasTrailingWhitespace returns true if the given byte array ends with a whitespace +func HasTrailingWhitespace(b []byte) bool { + r, _ := utf8.DecodeLastRune(b) + return IsWhitespace(r) +} + // IntOpt turns a float64 setting to an int func IntOpt(opt interface{}) int { return int(opt.(float64)) diff --git a/runtime/help/options.md b/runtime/help/options.md index 3826f27b..72075820 100644 --- a/runtime/help/options.md +++ b/runtime/help/options.md @@ -181,6 +181,12 @@ Here are the available options: default value: `false` +* `hltrailingws`: highlight trailing whitespaces at ends of lines. Note that + it doesn't highlight newly added trailing whitespaces that naturally occur + while typing text. It highlights only nasty forgotten trailing whitespaces. + + default value: `false` + * `incsearch`: enable incremental search in "Find" prompt (matching as you type). default value: `true` From c52ccad14b3736b2975835351cdba31e9f7c6ea1 Mon Sep 17 00:00:00 2001 From: Dmitry Maluka Date: Tue, 20 Oct 2020 23:46:55 +0200 Subject: [PATCH 3/8] hltrailingws: adjust autoclose plugin implementation Fix unwanted highlighting of whitespace in the new line when inserting a newline after a bracket (when hltrailingws is on). To fix it, change the order of operations: insert the new empty line after all other things, to avoid moving the cursor between lines after that. --- runtime/plugins/autoclose/autoclose.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/plugins/autoclose/autoclose.lua b/runtime/plugins/autoclose/autoclose.lua index 531b7601..f1fc2fad 100644 --- a/runtime/plugins/autoclose/autoclose.lua +++ b/runtime/plugins/autoclose/autoclose.lua @@ -50,11 +50,11 @@ function preInsertNewline(bp) for i = 1, #autoNewlinePairs do if curRune == charAt(autoNewlinePairs[i], 1) then if nextRune == charAt(autoNewlinePairs[i], 2) then - bp:InsertNewline() - bp:InsertTab() bp.Buf:Insert(-bp.Cursor.Loc, "\n" .. ws) bp:StartOfLine() bp:CursorLeft() + bp:InsertNewline() + bp:InsertTab() return false end end From b824e767d6f04fa633f341e46a61e692a1c36a79 Mon Sep 17 00:00:00 2001 From: Dmitry Maluka Date: Wed, 21 Oct 2020 00:33:18 +0200 Subject: [PATCH 4/8] Add tab-error and trailingws colors to colorschemes --- runtime/colorschemes/atom-dark.micro | 2 ++ runtime/colorschemes/bubblegum.micro | 2 ++ runtime/colorschemes/cmc-16.micro | 2 ++ runtime/colorschemes/cmc-tc.micro | 2 ++ runtime/colorschemes/darcula.micro | 2 ++ runtime/colorschemes/default.micro | 2 ++ runtime/colorschemes/dracula-tc.micro | 3 +++ runtime/colorschemes/dukedark-tc.micro | 2 ++ runtime/colorschemes/dukelight-tc.micro | 2 ++ runtime/colorschemes/dukeubuntu-tc.micro | 2 ++ runtime/colorschemes/geany.micro | 2 ++ runtime/colorschemes/gotham.micro | 2 ++ runtime/colorschemes/gruvbox-tc.micro | 2 ++ runtime/colorschemes/gruvbox.micro | 2 ++ runtime/colorschemes/material-tc.micro | 2 ++ runtime/colorschemes/monokai-dark.micro | 2 ++ runtime/colorschemes/monokai.micro | 2 ++ runtime/colorschemes/one-dark.micro | 2 ++ runtime/colorschemes/railscast.micro | 2 ++ runtime/colorschemes/simple.micro | 2 ++ runtime/colorschemes/solarized-tc.micro | 2 ++ runtime/colorschemes/solarized.micro | 2 ++ runtime/colorschemes/sunny-day.micro | 2 ++ runtime/colorschemes/twilight.micro | 2 ++ runtime/colorschemes/zenburn.micro | 2 ++ 25 files changed, 51 insertions(+) diff --git a/runtime/colorschemes/atom-dark.micro b/runtime/colorschemes/atom-dark.micro index d7f8eff6..0f462995 100644 --- a/runtime/colorschemes/atom-dark.micro +++ b/runtime/colorschemes/atom-dark.micro @@ -29,3 +29,5 @@ color-link color-column "#2D2F31" #color-link type.extended "default" #Plain brackets color-link match-brace "#1D1F21,#62B1FE" +color-link tab-error "#D75F5F" +color-link trailingws "#D75F5F" diff --git a/runtime/colorschemes/bubblegum.micro b/runtime/colorschemes/bubblegum.micro index 4c039d4d..dcc2276d 100644 --- a/runtime/colorschemes/bubblegum.micro +++ b/runtime/colorschemes/bubblegum.micro @@ -27,3 +27,5 @@ color-link color-column "254" color-link type.extended "241,231" color-link symbol.brackets "241,231" color-link match-brace "231,28" +color-link tab-error "210" +color-link trailingws "210" diff --git a/runtime/colorschemes/cmc-16.micro b/runtime/colorschemes/cmc-16.micro index 09ad6eaf..0a50096c 100644 --- a/runtime/colorschemes/cmc-16.micro +++ b/runtime/colorschemes/cmc-16.micro @@ -43,3 +43,5 @@ color-link color-column "cyan" color-link underlined.url "underline blue, white" color-link divider "blue" color-link match-brace "black,cyan" +color-link tab-error "brightred" +color-link trailingws "brightred" diff --git a/runtime/colorschemes/cmc-tc.micro b/runtime/colorschemes/cmc-tc.micro index f142210e..b0502c6f 100644 --- a/runtime/colorschemes/cmc-tc.micro +++ b/runtime/colorschemes/cmc-tc.micro @@ -39,3 +39,5 @@ color-link constant.bool "bold #55ffff" color-link constant.bool.true "bold #85ff85" color-link constant.bool.false "bold #ff8585" color-link match-brace "#1e2124,#55ffff" +color-link tab-error "#d75f5f" +color-link trailingws "#d75f5f" diff --git a/runtime/colorschemes/darcula.micro b/runtime/colorschemes/darcula.micro index 560ab585..7103e842 100644 --- a/runtime/colorschemes/darcula.micro +++ b/runtime/colorschemes/darcula.micro @@ -30,3 +30,5 @@ color-link type.extended "default" #color-link symbol.brackets "default" color-link symbol.tag "#AE81FF,#242424" color-link match-brace "#242424,#7A9EC2" +color-link tab-error "#D75F5F" +color-link trailingws "#D75F5F" diff --git a/runtime/colorschemes/default.micro b/runtime/colorschemes/default.micro index 1c3b5eab..9ae5bfd6 100644 --- a/runtime/colorschemes/default.micro +++ b/runtime/colorschemes/default.micro @@ -30,3 +30,5 @@ color-link type.extended "default" #color-link symbol.brackets "default" color-link symbol.tag "#AE81FF,#282828" color-link match-brace "#282828,#AE81FF" +color-link tab-error "#D75F5F" +color-link trailingws "#D75F5F" diff --git a/runtime/colorschemes/dracula-tc.micro b/runtime/colorschemes/dracula-tc.micro index b242eb6c..af0509c7 100644 --- a/runtime/colorschemes/dracula-tc.micro +++ b/runtime/colorschemes/dracula-tc.micro @@ -44,3 +44,6 @@ color-link color-column "#44475A" color-link type.extended "default" color-link match-brace "#282A36,#FF79C6" + +color-link tab-error "#D75F5F" +color-link trailingws "#D75F5F" diff --git a/runtime/colorschemes/dukedark-tc.micro b/runtime/colorschemes/dukedark-tc.micro index 54afff60..52ec8476 100644 --- a/runtime/colorschemes/dukedark-tc.micro +++ b/runtime/colorschemes/dukedark-tc.micro @@ -34,3 +34,5 @@ color-link type.keyword "bold #5aaae6,#001e28" color-link type.extended "#ffffff,#001e28" color-link underlined "#608b4e,#001e28" color-link match-brace "#001e28,#5aaae6" +color-link tab-error "#d75f5f" +color-link trailingws "#d75f5f" diff --git a/runtime/colorschemes/dukelight-tc.micro b/runtime/colorschemes/dukelight-tc.micro index c381f2b1..c694ffb6 100644 --- a/runtime/colorschemes/dukelight-tc.micro +++ b/runtime/colorschemes/dukelight-tc.micro @@ -34,3 +34,5 @@ color-link type.keyword "bold #780050,#f0f0f0" color-link type.extended "#000000,#f0f0f0" color-link underlined "#3f7f5f,#f0f0f0" color-link match-brace "#f0f0f0,#780050" +color-link tab-error "#ff8787" +color-link trailingws "#ff8787" diff --git a/runtime/colorschemes/dukeubuntu-tc.micro b/runtime/colorschemes/dukeubuntu-tc.micro index 7c9f7afb..b34cc2c4 100644 --- a/runtime/colorschemes/dukeubuntu-tc.micro +++ b/runtime/colorschemes/dukeubuntu-tc.micro @@ -34,3 +34,5 @@ color-link type.keyword "bold #5aaae6,#2d0023" color-link type.extended "#ffffff,#2d0023" color-link underlined "#886484,#2d0023" color-link match-brace "#2d0023,#5aaae6" +color-link tab-error "#d75f5f" +color-link trailingws "#d75f5f" diff --git a/runtime/colorschemes/geany.micro b/runtime/colorschemes/geany.micro index 7333a2a2..43ced31a 100644 --- a/runtime/colorschemes/geany.micro +++ b/runtime/colorschemes/geany.micro @@ -25,3 +25,5 @@ color-link diff-deleted "red" color-link gutter-error ",red" color-link gutter-warning "red" color-link match-brace "black,cyan" +color-link tab-error "brightred" +color-link trailingws "brightred" diff --git a/runtime/colorschemes/gotham.micro b/runtime/colorschemes/gotham.micro index 600822b6..d067a81c 100644 --- a/runtime/colorschemes/gotham.micro +++ b/runtime/colorschemes/gotham.micro @@ -25,3 +25,5 @@ color-link cursor-line "#091F2E" color-link color-column "#11151C" color-link symbol "#99D1CE,#0C1014" color-link match-brace "#0C1014,#D26937" +color-link tab-error "#D75F5F" +color-link trailingws "#D75F5F" diff --git a/runtime/colorschemes/gruvbox-tc.micro b/runtime/colorschemes/gruvbox-tc.micro index e6301e67..65d72b15 100644 --- a/runtime/colorschemes/gruvbox-tc.micro +++ b/runtime/colorschemes/gruvbox-tc.micro @@ -25,3 +25,5 @@ color-link color-column "#79740e" color-link statusline "#ebdbb2,#665c54" color-link tabbar "#ebdbb2,#665c54" color-link match-brace "#282828,#d3869b" +color-link tab-error "#d75f5f" +color-link trailingws "#d75f5f" diff --git a/runtime/colorschemes/gruvbox.micro b/runtime/colorschemes/gruvbox.micro index a59e99ef..46cc09cf 100644 --- a/runtime/colorschemes/gruvbox.micro +++ b/runtime/colorschemes/gruvbox.micro @@ -22,3 +22,5 @@ color-link color-column "237" color-link statusline "223,237" color-link tabbar "223,237" color-link match-brace "235,72" +color-link tab-error "167" +color-link trailingws "167" diff --git a/runtime/colorschemes/material-tc.micro b/runtime/colorschemes/material-tc.micro index 561cf81c..5a7f9c89 100644 --- a/runtime/colorschemes/material-tc.micro +++ b/runtime/colorschemes/material-tc.micro @@ -31,3 +31,5 @@ color-link todo "bold #C792EA,#263238" color-link type "#FFCB6B,#263238" color-link underlined "underline #EEFFFF,#263238" color-link match-brace "#263238,#C792EA" +color-link tab-error "#D75F5F" +color-link trailingws "#D75F5F" diff --git a/runtime/colorschemes/monokai-dark.micro b/runtime/colorschemes/monokai-dark.micro index 51174309..3a1e89c4 100644 --- a/runtime/colorschemes/monokai-dark.micro +++ b/runtime/colorschemes/monokai-dark.micro @@ -24,3 +24,5 @@ color-link gutter-warning "#E6DB74" color-link cursor-line "#323232" color-link color-column "#323232" color-link match-brace "#1D0000,#AE81FF" +color-link tab-error "#D75F5F" +color-link trailingws "#D75F5F" diff --git a/runtime/colorschemes/monokai.micro b/runtime/colorschemes/monokai.micro index e33cf830..13c44b74 100644 --- a/runtime/colorschemes/monokai.micro +++ b/runtime/colorschemes/monokai.micro @@ -30,3 +30,5 @@ color-link type.extended "default" #color-link symbol.brackets "default" color-link symbol.tag "#AE81FF,#282828" color-link match-brace "#282828,#AE81FF" +color-link tab-error "#D75F5F" +color-link trailingws "#D75F5F" diff --git a/runtime/colorschemes/one-dark.micro b/runtime/colorschemes/one-dark.micro index b6c96954..ed994321 100644 --- a/runtime/colorschemes/one-dark.micro +++ b/runtime/colorschemes/one-dark.micro @@ -35,3 +35,5 @@ color-link type "#66D9EF" color-link type.keyword "#C678DD" color-link underlined "#8996A8" color-link match-brace "#21252C,#C678DD" +color-link tab-error "#D75F5F" +color-link trailingws "#D75F5F" diff --git a/runtime/colorschemes/railscast.micro b/runtime/colorschemes/railscast.micro index 61934b94..01c0055d 100644 --- a/runtime/colorschemes/railscast.micro +++ b/runtime/colorschemes/railscast.micro @@ -28,6 +28,8 @@ color-link tabbar "bold #b1b1b1,#232323" color-link cursor-line "#353535" color-link color-column "#353535" color-link space "underline #e6e1dc,#2b2b2b" +color-link tab-error "#d75f5f" +color-link trailingws "#d75f5f" #the Python syntax definition are wrong. This is not how you should do decorators! color-link brightgreen "#edb753,#2b2b2b" diff --git a/runtime/colorschemes/simple.micro b/runtime/colorschemes/simple.micro index 74c71e02..707c04cb 100644 --- a/runtime/colorschemes/simple.micro +++ b/runtime/colorschemes/simple.micro @@ -29,3 +29,5 @@ color-link symbol.brackets "default" #Color shebangs the comment color color-link preproc.shebang "comment" color-link match-brace ",magenta" +color-link tab-error "brightred" +color-link trailingws "brightred" diff --git a/runtime/colorschemes/solarized-tc.micro b/runtime/colorschemes/solarized-tc.micro index d68a024a..8eae0391 100644 --- a/runtime/colorschemes/solarized-tc.micro +++ b/runtime/colorschemes/solarized-tc.micro @@ -27,3 +27,5 @@ color-link color-column "#003541" color-link type.extended "#839496,#002833" color-link symbol.brackets "#839496,#002833" color-link match-brace "#002833,#268BD2" +color-link tab-error "#D75F5F" +color-link trailingws "#D75F5F" diff --git a/runtime/colorschemes/solarized.micro b/runtime/colorschemes/solarized.micro index 745b46ea..4d3923ad 100644 --- a/runtime/colorschemes/solarized.micro +++ b/runtime/colorschemes/solarized.micro @@ -26,3 +26,5 @@ color-link color-column "black" color-link type.extended "default" color-link symbol.brackets "default" color-link match-brace ",blue" +color-link tab-error "brightred" +color-link trailingws "brightred" diff --git a/runtime/colorschemes/sunny-day.micro b/runtime/colorschemes/sunny-day.micro index 82e4b8f4..c4161bce 100644 --- a/runtime/colorschemes/sunny-day.micro +++ b/runtime/colorschemes/sunny-day.micro @@ -25,3 +25,5 @@ color-link cursor-line "229" #color-link color-column "196" color-link current-line-number "246" color-line match-brace "230,22" +color-link tab-error "210" +color-link trailingws "210" diff --git a/runtime/colorschemes/twilight.micro b/runtime/colorschemes/twilight.micro index 224fb7fd..8135bb80 100644 --- a/runtime/colorschemes/twilight.micro +++ b/runtime/colorschemes/twilight.micro @@ -36,3 +36,5 @@ color-link type "#F9EE98" color-link type.keyword "#CDA869" color-link underlined "#8996A8" color-link match-brace "#141414,#E0C589" +color-link tab-error "#D75F5F" +color-link trailingws "#D75F5F" diff --git a/runtime/colorschemes/zenburn.micro b/runtime/colorschemes/zenburn.micro index e4f91175..acbd83fb 100644 --- a/runtime/colorschemes/zenburn.micro +++ b/runtime/colorschemes/zenburn.micro @@ -26,3 +26,5 @@ color-link cursor-line "238" color-link color-column "238" color-link current-line-number "188,237" color-link match-brace "237,223" +color-link tab-error "167" +color-link trailingws "167" From f108c906434b0c5eb3e2159f877d39a97853f078 Mon Sep 17 00:00:00 2001 From: Dmitry Maluka Date: Thu, 22 Oct 2020 22:29:16 +0200 Subject: [PATCH 5/8] hltrailingws: improve updateTrailingWs logic Handle the case when the cursor itself hasn't really moved to another line, but its line number has changed due to insert or remove of some lines above. In this case, if the cursor is still at its new trailingws, we should not reset NewTrailingWsY to -1 but update it to the new line number. A scenario exemplifying this issue: Bind some key, e.g. Alt-r, to such a lua function: function insertNewlineAbove(bp) bp.Buf:Insert(buffer.Loc(0, bp.Cursor.Y), "\n") end Then in a file containing these lines: aaa bbb ccc insert a space at the end of bbb line, and then press Alt-r. bbb and ccc are moved one line down, but also the trailing space after bbb becomes highlighted, which isn't what we expect. This commit fixes that. --- internal/buffer/eventhandler.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/internal/buffer/eventhandler.go b/internal/buffer/eventhandler.go index 66c44dba..6dfb32a0 100644 --- a/internal/buffer/eventhandler.go +++ b/internal/buffer/eventhandler.go @@ -391,5 +391,11 @@ func (eh *EventHandler) updateTrailingWs(t *TextEvent) { } else if !removedAfterWs { c.NewTrailingWsY = -1 } + } else if c.NewTrailingWsY != -1 && start.Y != end.Y && c.Loc.GreaterThan(start) && + ((t.EventType == TextEventInsert && c.Y == c.NewTrailingWsY+(end.Y-start.Y)) || + (t.EventType == TextEventRemove && c.Y == c.NewTrailingWsY-(end.Y-start.Y))) { + // The cursor still has its new trailingws + // but its line number was shifted by insert or remove of lines above + c.NewTrailingWsY = c.Y } } From 53efce72fa4bb883e9892d64be3eaab2a1e54d9e Mon Sep 17 00:00:00 2001 From: Dmitry Maluka Date: Thu, 22 Oct 2020 22:54:46 +0200 Subject: [PATCH 6/8] hltrailingws: improve behavior with selection Improve user experience: if we are at a line with a new (i.e. not highlighted yet) trailingws and we begin selecting text, don't highlight the trailingws until we are done with selection, even if we moved the cursor to another line while selecting. --- internal/action/bufpane.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/action/bufpane.go b/internal/action/bufpane.go index 89d174c7..2baf6739 100644 --- a/internal/action/bufpane.go +++ b/internal/action/bufpane.go @@ -512,7 +512,8 @@ func (h *BufPane) HandleEvent(event tcell.Event) { cursors := h.Buf.GetCursors() for _, c := range cursors { - if c.NewTrailingWsY != c.Y { + if c.NewTrailingWsY != c.Y && (!c.HasSelection() || + (c.NewTrailingWsY != c.CurSelection[0].Y && c.NewTrailingWsY != c.CurSelection[1].Y)) { c.NewTrailingWsY = -1 } } From 13d1407f60a12b2c450074887bc821f64350a635 Mon Sep 17 00:00:00 2001 From: Dmitry Maluka Date: Fri, 23 Oct 2020 00:17:22 +0200 Subject: [PATCH 7/8] hltrailingws: simpler and better undo/redo handling --- internal/buffer/eventhandler.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/internal/buffer/eventhandler.go b/internal/buffer/eventhandler.go index 6dfb32a0..53f64025 100644 --- a/internal/buffer/eventhandler.go +++ b/internal/buffer/eventhandler.go @@ -107,7 +107,9 @@ func (eh *EventHandler) DoTextEvent(t *TextEvent, useUndo bool) { c.LastVisualX = c.GetVisualX() } - eh.updateTrailingWs(t) + if useUndo { + eh.updateTrailingWs(t) + } } // ExecuteTextEvent runs a text event @@ -292,6 +294,7 @@ func (eh *EventHandler) UndoOneEvent() { if teCursor.Num >= 0 && teCursor.Num < len(eh.cursors) { t.C = *eh.cursors[teCursor.Num] eh.cursors[teCursor.Num].Goto(teCursor) + eh.cursors[teCursor.Num].NewTrailingWsY = teCursor.NewTrailingWsY } else { teCursor.Num = -1 } @@ -335,6 +338,7 @@ func (eh *EventHandler) RedoOneEvent() { if teCursor.Num >= 0 && teCursor.Num < len(eh.cursors) { t.C = *eh.cursors[teCursor.Num] eh.cursors[teCursor.Num].Goto(teCursor) + eh.cursors[teCursor.Num].NewTrailingWsY = teCursor.NewTrailingWsY } else { teCursor.Num = -1 } From 6dc3df646b57207a28e18213261a864543f18056 Mon Sep 17 00:00:00 2001 From: Dmitry Maluka Date: Sun, 27 Nov 2022 21:30:16 +0100 Subject: [PATCH 8/8] readme: Mention hltrailingws/hltaberrors feature --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6d4a8579..3be5f9b3 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ You can also check out the website for Micro at https://micro-editor.github.io. - Small and simple. - Easily configurable. - Macros. +- Smart highlighting of trailing whitespace and tab vs space errors. - Common editor features such as undo/redo, line numbers, Unicode support, soft wrapping, … ## Installation