Skip to content

Commit 1ef6459

Browse files
Adding showchars option
1 parent 532c315 commit 1ef6459

File tree

3 files changed

+81
-23
lines changed

3 files changed

+81
-23
lines changed

internal/config/settings.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ var defaultCommonSettings = map[string]interface{}{
7070
"hltrailingws": false,
7171
"ignorecase": true,
7272
"incsearch": true,
73-
"indentchar": " ",
73+
"indentchar": " ", // Deprecated
7474
"keepautoindent": false,
7575
"matchbrace": true,
7676
"matchbraceleft": true,
@@ -88,6 +88,7 @@ var defaultCommonSettings = map[string]interface{}{
8888
"scrollbar": false,
8989
"scrollmargin": float64(3),
9090
"scrollspeed": float64(2),
91+
"showchars": "",
9192
"smartpaste": true,
9293
"softwrap": false,
9394
"splitbottom": true,
@@ -210,6 +211,7 @@ func validateParsedSettings() error {
210211
}
211212
continue
212213
}
214+
213215
if _, ok := defaults[k]; ok {
214216
if e := verifySetting(k, v, defaults[k]); e != nil {
215217
err = e

internal/display/bufwindow.go

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package display
22

33
import (
44
"strconv"
5+
"strings"
56

67
runewidth "github.com/mattn/go-runewidth"
78
"github.com/micro-editor/tcell/v2"
@@ -450,6 +451,30 @@ func (w *BufWindow) displayBuffer() {
450451
cursors := b.GetCursors()
451452

452453
curStyle := config.DefStyle
454+
455+
// Parse showchars which is in the format of key1=val1,key2=val2,...
456+
spacechars := " "
457+
tabchars := b.Settings["indentchar"].(string)
458+
var indentspacechars string
459+
var indenttabchars string
460+
for _, entry := range strings.Split(b.Settings["showchars"].(string), ",") {
461+
split := strings.SplitN(entry, "=", 2)
462+
if len(split) < 2 {
463+
continue
464+
}
465+
key, val := split[0], split[1]
466+
switch key {
467+
case "space":
468+
spacechars = val
469+
case "tab":
470+
tabchars = val
471+
case "ispace":
472+
indentspacechars = val
473+
case "itab":
474+
indenttabchars = val
475+
}
476+
}
477+
453478
for ; vloc.Y < w.bufHeight; vloc.Y++ {
454479
vloc.X = 0
455480

@@ -495,7 +520,7 @@ func (w *BufWindow) displayBuffer() {
495520
bloc.X = bslice
496521

497522
// returns the rune to be drawn, style of it and if the bg should be preserved
498-
getRuneStyle := func(r rune, style tcell.Style, isplaceholder bool) (rune, tcell.Style, bool) {
523+
getRuneStyle := func(r rune, style tcell.Style, showoffset int, linex int, isplaceholder bool) (rune, tcell.Style, bool) {
499524
if nColsBeforeStart > 0 || vloc.Y < 0 || isplaceholder {
500525
return r, style, false
501526
}
@@ -518,21 +543,35 @@ func (w *BufWindow) displayBuffer() {
518543
return r, style, false
519544
}
520545

521-
var drawrune rune
522-
if r == '\t' {
523-
indentrunes := []rune(b.Settings["indentchar"].(string))
524-
// if empty indentchar settings, use space
525-
if len(indentrunes) == 0 {
526-
indentrunes = []rune{' '}
546+
var indentrunes []rune
547+
switch r {
548+
case '\t':
549+
if bloc.X < leadingwsEnd && indenttabchars != "" {
550+
indentrunes = []rune(indenttabchars)
551+
} else {
552+
indentrunes = []rune(tabchars)
527553
}
528-
529-
drawrune = indentrunes[0]
530-
if s, ok := config.Colorscheme["indent-char"]; ok {
531-
fg, _, _ := s.Decompose()
532-
style = style.Foreground(fg)
554+
case ' ':
555+
if linex%tabsize == 0 && bloc.X < leadingwsEnd && indentspacechars != "" {
556+
indentrunes = []rune(indentspacechars)
557+
} else {
558+
indentrunes = []rune(spacechars)
533559
}
534560
}
535561

562+
var drawrune rune
563+
if showoffset < len(indentrunes) {
564+
drawrune = indentrunes[showoffset]
565+
} else {
566+
// use space if no showchars or after we showed showchars
567+
drawrune = ' '
568+
}
569+
570+
if s, ok := config.Colorscheme["indent-char"]; ok {
571+
fg, _, _ := s.Decompose()
572+
style = style.Foreground(fg)
573+
}
574+
536575
preservebg := false
537576
if b.Settings["hltaberrors"].(bool) && bloc.X < leadingwsEnd {
538577
if s, ok := config.Colorscheme["tab-error"]; ok {
@@ -692,6 +731,7 @@ func (w *BufWindow) displayBuffer() {
692731

693732
width := 0
694733

734+
linex := totalwidth
695735
switch r {
696736
case '\t':
697737
ts := tabsize - (totalwidth % tabsize)
@@ -732,15 +772,15 @@ func (w *BufWindow) displayBuffer() {
732772
}
733773

734774
for _, r := range word {
735-
drawrune, drawstyle, preservebg := getRuneStyle(r.r, r.style, false)
775+
drawrune, drawstyle, preservebg := getRuneStyle(r.r, r.style, 0, linex, false)
736776
draw(drawrune, r.combc, drawstyle, true, true, preservebg)
737777

738778
// Draw extra characters for tabs or wide runes
739779
for i := 1; i < r.width; i++ {
740780
if r.r == '\t' {
741-
drawrune, drawstyle, preservebg = getRuneStyle('\t', r.style, false)
781+
drawrune, drawstyle, preservebg = getRuneStyle('\t', r.style, i, linex+i, false)
742782
} else {
743-
drawrune, drawstyle, preservebg = getRuneStyle(' ', r.style, true)
783+
drawrune, drawstyle, preservebg = getRuneStyle(' ', r.style, i, linex+i, true)
744784
}
745785
draw(drawrune, nil, drawstyle, true, false, preservebg)
746786
}
@@ -787,7 +827,7 @@ func (w *BufWindow) displayBuffer() {
787827

788828
if vloc.X != maxWidth {
789829
// Display newline within a selection
790-
drawrune, drawstyle, preservebg := getRuneStyle(' ', config.DefStyle, true)
830+
drawrune, drawstyle, preservebg := getRuneStyle(' ', config.DefStyle, 0, totalwidth, true)
791831
draw(drawrune, nil, drawstyle, true, true, preservebg)
792832
}
793833

runtime/help/options.md

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -203,12 +203,8 @@ Here are the available options:
203203

204204
default value: `true`
205205

206-
* `indentchar`: sets the indentation character. This will not be inserted into
207-
files; it is only a visual indicator that whitespace is present. If set to a
208-
printing character, it functions as a subset of the "show invisibles"
209-
setting available in many other text editors. The color of this character is
210-
determined by the `indent-char` field in the current theme rather than the
211-
default text color.
206+
* `indentchar`: sets the character to be shown to display tab characters.
207+
This option is **deprecated**, use the `tab` key in `showchars` option instead.
212208

213209
default value: ` ` (space)
214210

@@ -386,6 +382,25 @@ Here are the available options:
386382

387383
default value: `2`
388384

385+
* `showchars`: sets what characters to be shown to display various invisible
386+
characters in the file. The characters shown will not be inserted into files.
387+
This option is specified in the form of `key1=value1,key2=value2,...`.
388+
389+
Here are the list of keys:
390+
- `space`: space characters
391+
- `tab`: tab characters. If set, overrides the `indentchar` option.
392+
- `ispace`: space characters at indent position before the first visible
393+
character in a line. If this is not set, `space` will be shown
394+
instead.
395+
- `itab`: tab characters before the first visible character in a line.
396+
If this is not set, `tab` will be shown instead.
397+
An example of this option value could be `tab=>,space=.,itab=|>,ispace=|`
398+
399+
The color of the shown character is determined by the `indent-char`
400+
field in the current theme rather than the default text color.
401+
402+
default value: ``
403+
389404
* `smartpaste`: add leading whitespace when pasting multiple lines.
390405
This will attempt to preserve the current indentation level when pasting an
391406
unindented block.
@@ -577,6 +592,7 @@ so that you can see what the formatting should look like.
577592
"scrollbarchar": "|",
578593
"scrollmargin": 3,
579594
"scrollspeed": 2,
595+
"showchars": "",
580596
"smartpaste": true,
581597
"softwrap": false,
582598
"splitbottom": true,

0 commit comments

Comments
 (0)