Skip to content

Commit cb54c9a

Browse files
Adding showchars option
1 parent 22a70a1 commit cb54c9a

File tree

3 files changed

+91
-28
lines changed

3 files changed

+91
-28
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: 63 additions & 21 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

@@ -494,7 +519,7 @@ func (w *BufWindow) displayBuffer() {
494519
}
495520
bloc.X = bslice
496521

497-
getRuneStyle := func(r rune, style tcell.Style, isplaceholder bool) (rune, tcell.Style, bool) {
522+
getRuneStyle := func(r rune, style tcell.Style, showoffset int, isplaceholder bool) (rune, tcell.Style, bool) {
498523
bgoverridable := true
499524
if nColsBeforeStart > 0 || vloc.Y < 0 || isplaceholder {
500525
return r, style, bgoverridable
@@ -514,28 +539,45 @@ func (w *BufWindow) displayBuffer() {
514539
}
515540
}
516541

517-
if r != '\t' && r != ' '{
542+
if r != '\t' && r != ' ' {
518543
return r, style, bgoverridable
519544
}
520545

521-
var returnrune 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 && !b.Settings["tabstospaces"].(bool) {
550+
if indenttabchars != "" {
551+
indentrunes = []rune(indenttabchars)
552+
} else {
553+
indentrunes = []rune(tabchars)
554+
}
555+
} else {
556+
indentrunes = []rune(tabchars)
527557
}
528-
529-
returnrune = indentrunes[0]
530-
if s, ok := config.Colorscheme["indent-char"]; ok && r != ' ' {
531-
fg, _, _ := s.Decompose()
532-
style = style.Foreground(fg)
558+
case ' ':
559+
if bloc.X%tabsize == 0 && bloc.X < leadingwsEnd && b.Settings["tabstospaces"].(bool) {
560+
if indentspacechars != "" {
561+
indentrunes = []rune(indentspacechars)
562+
} else {
563+
indentrunes = []rune(spacechars)
564+
}
565+
} else {
566+
indentrunes = []rune(spacechars)
533567
}
568+
}
534569

535-
if s, ok := config.Colorscheme["indent-char"]; ok {
536-
fg, _, _ := s.Decompose()
537-
style = style.Foreground(fg)
538-
}
570+
var returnrune rune
571+
if showoffset < len(indentrunes) {
572+
returnrune = indentrunes[showoffset]
573+
} else {
574+
// use space if no showchars or after we showed showchars
575+
returnrune = ' '
576+
}
577+
578+
if s, ok := config.Colorscheme["indent-char"]; ok {
579+
fg, _, _ := s.Decompose()
580+
style = style.Foreground(fg)
539581
}
540582

541583
if b.Settings["hltaberrors"].(bool) && bloc.X < leadingwsEnd {
@@ -736,15 +778,15 @@ func (w *BufWindow) displayBuffer() {
736778
}
737779

738780
for _, r := range word {
739-
drawrune, drawstyle, bgoverridable := getRuneStyle(r.r, r.style, false)
781+
drawrune, drawstyle, bgoverridable := getRuneStyle(r.r, r.style, 0, false)
740782
draw(drawrune, r.combc, drawstyle, true, true, bgoverridable)
741783

742784
// Draw extra characters for tabs or wide runes
743785
for i := 1; i < r.width; i++ {
744786
if r.r == '\t' {
745-
drawrune, drawstyle, bgoverridable = getRuneStyle('\t', r.style, false)
787+
drawrune, drawstyle, bgoverridable = getRuneStyle('\t', r.style, i, false)
746788
} else {
747-
drawrune, drawstyle, bgoverridable = getRuneStyle(' ', r.style, true)
789+
drawrune, drawstyle, bgoverridable = getRuneStyle(' ', r.style, i, true)
748790
}
749791
draw(drawrune, nil, drawstyle, true, false, bgoverridable)
750792
}
@@ -791,7 +833,7 @@ func (w *BufWindow) displayBuffer() {
791833

792834
if vloc.X != maxWidth {
793835
// Display newline within a selection
794-
drawrune, drawstyle, bgoverridable := getRuneStyle(' ', config.DefStyle, true)
836+
drawrune, drawstyle, bgoverridable := getRuneStyle(' ', config.DefStyle, 0, true)
795837
draw(drawrune, nil, drawstyle, true, true, bgoverridable)
796838
}
797839

runtime/help/options.md

Lines changed: 25 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 `showchars` option instead.
212208

213209
default value: ` ` (space)
214210

@@ -386,6 +382,28 @@ 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 overrides the `indentchar` option if that exists)
388+
This option is specified in the form of `key1=value1,key2=value2,...`.
389+
390+
Here are the list of keys:
391+
- `space`: space characters
392+
- `tab`: tab characters
393+
- `ispace`: space characters at indent position before the first visible
394+
character in a line. If this is not set, `space` will be shown
395+
instead.
396+
This is only shown when `tabstospaces` is true.
397+
- `itab`: tab characters before the first visible character in a line.
398+
If this is not set, `tab` will be shown instead.
399+
This is only shown when `tabstospaces` is false
400+
An example of this option value could be `tab=>,space=.,itab=|>,ispace=|`
401+
402+
The color of the shown character is determined by the `indent-char`
403+
field in the current theme rather than the default text color.
404+
405+
default value: ``
406+
389407
* `smartpaste`: add leading whitespace when pasting multiple lines.
390408
This will attempt to preserve the current indentation level when pasting an
391409
unindented block.
@@ -577,6 +595,7 @@ so that you can see what the formatting should look like.
577595
"scrollbarchar": "|",
578596
"scrollmargin": 3,
579597
"scrollspeed": 2,
598+
"showchars": "",
580599
"smartpaste": true,
581600
"softwrap": false,
582601
"splitbottom": true,

0 commit comments

Comments
 (0)