mirror of
https://github.com/zyedidia/micro
synced 2024-10-04 15:09:41 +00:00
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.
This commit is contained in:
parent
64370b70d6
commit
104caf08dd
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -290,6 +290,7 @@ var defaultCommonSettings = map[string]interface{}{
|
|||
"filetype": "unknown",
|
||||
"hlsearch": false,
|
||||
"hltaberrors": false,
|
||||
"hltrailingws": false,
|
||||
"incsearch": true,
|
||||
"ignorecase": true,
|
||||
"indentchar": " ",
|
||||
|
|
|
@ -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]) ||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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`
|
||||
|
|
Loading…
Reference in a new issue