@@ -453,28 +453,26 @@ func (w *BufWindow) displayBuffer() {
453453
454454 curStyle := config .DefStyle
455455
456- // Parse showchars which is in the format of option1 =val1,option2 =val2,...
456+ // Parse showchars which is in the format of key1 =val1,key2 =val2,...
457457 spacechars := " "
458458 tabchars := b .Settings ["indentchar" ].(string )
459- indentspacechars := " "
460- indenttabchars := b .Settings ["indentchar" ].(string )
461-
462- charsentries := strings .Split (b .Settings ["showchars" ].(string ), "," )
463- for _ , entry := range charsentries {
464- if ! strings .Contains (entry , "=" ) {
459+ var indentspacechars string
460+ var indenttabchars string
461+ for _ , entry := range strings .Split (b .Settings ["showchars" ].(string ), "," ) {
462+ split := strings .SplitN (entry , "=" , 2 )
463+ if len (split ) < 2 {
465464 continue
466465 }
467- entrykey := strings .Split (entry , "=" )[0 ]
468- entryval := strings .Split (entry , "=" )[1 ]
469- switch entrykey {
466+ key , val := split [0 ], split [1 ]
467+ switch key {
470468 case "space" :
471- spacechars = entryval
469+ spacechars = val
472470 case "tab" :
473- tabchars = entryval
471+ tabchars = val
474472 case "ispace" :
475- indentspacechars = entryval
473+ indentspacechars = val
476474 case "itab" :
477- indenttabchars = entryval
475+ indenttabchars = val
478476 }
479477 }
480478
@@ -522,149 +520,171 @@ func (w *BufWindow) displayBuffer() {
522520 }
523521 bloc .X = bslice
524522
525- draw := func (r rune , showoffset int , combc []rune , isplaceholder bool , style tcell.Style , highlight bool , showcursor bool ) {
526- if nColsBeforeStart <= 0 && vloc .Y >= 0 {
527- if highlight {
528- if w .Buf .HighlightSearch && w .Buf .SearchMatch (bloc ) {
529- style = config .DefStyle .Reverse (true )
530- if s , ok := config .Colorscheme ["hlsearch" ]; ok {
531- style = s
523+ // returns the rune to be drawn, style of it and if the bg should be preserved
524+ getRuneStyle := func (r rune , style tcell.Style , showoffset int , linex int , isplaceholder bool ) (rune , tcell.Style , bool ) {
525+ if nColsBeforeStart > 0 || vloc .Y < 0 || isplaceholder {
526+ return r , style , false
527+ }
528+
529+ for _ , mb := range matchingBraces {
530+ if mb .X == bloc .X && mb .Y == bloc .Y {
531+ if b .Settings ["matchbracestyle" ].(string ) == "highlight" {
532+ if s , ok := config .Colorscheme ["match-brace" ]; ok {
533+ return r , s , false
534+ } else {
535+ return r , style .Reverse (true ), false
532536 }
537+ } else {
538+ return r , style .Underline (true ), false
533539 }
540+ }
541+ }
534542
535- _ , origBg , _ := style .Decompose ()
536- _ , defBg , _ := config .DefStyle .Decompose ()
537-
538- // syntax or hlsearch highlighting with non-default background takes precedence
539- // over cursor-line and color-column
540- dontOverrideBackground := origBg != defBg
541-
542- if b .Settings ["hltaberrors" ].(bool ) {
543- if s , ok := config .Colorscheme ["tab-error" ]; ok {
544- isTab := (r == '\t' ) || (r == ' ' && ! showcursor )
545- if (b .Settings ["tabstospaces" ].(bool ) && isTab ) ||
546- (! b .Settings ["tabstospaces" ].(bool ) && bloc .X < leadingwsEnd && r == ' ' && ! isTab ) {
547- fg , _ , _ := s .Decompose ()
548- style = style .Background (fg )
549- dontOverrideBackground = true
550- }
551- }
543+ if r != '\t' && r != ' ' {
544+ return r , style , false
545+ }
546+
547+ var indentrunes []rune
548+ switch r {
549+ case '\t' :
550+ if bloc .X < leadingwsEnd && indenttabchars != "" {
551+ indentrunes = []rune (indenttabchars )
552+ } else {
553+ indentrunes = []rune (tabchars )
554+ }
555+ case ' ' :
556+ if linex % tabsize == 0 && bloc .X < leadingwsEnd && indentspacechars != "" {
557+ indentrunes = []rune (indentspacechars )
558+ } else {
559+ indentrunes = []rune (spacechars )
560+ }
561+ }
562+
563+ var drawrune rune
564+ if showoffset < len (indentrunes ) {
565+ drawrune = indentrunes [showoffset ]
566+ } else {
567+ // use space if no showchars or after we showed showchars
568+ drawrune = ' '
569+ }
570+
571+ if s , ok := config .Colorscheme ["indent-char" ]; ok {
572+ fg , _ , _ := s .Decompose ()
573+ style = style .Foreground (fg )
574+ }
575+
576+ preservebg := false
577+ if b .Settings ["hltaberrors" ].(bool ) && bloc .X < leadingwsEnd {
578+ if s , ok := config .Colorscheme ["tab-error" ]; ok {
579+ if b .Settings ["tabstospaces" ].(bool ) && r == '\t' {
580+ fg , _ , _ := s .Decompose ()
581+ style = style .Background (fg )
582+ preservebg = true
583+ } else if ! b .Settings ["tabstospaces" ].(bool ) && r == ' ' {
584+ fg , _ , _ := s .Decompose ()
585+ style = style .Background (fg )
586+ preservebg = true
552587 }
588+ }
589+ }
553590
554- if b .Settings ["hltrailingws" ].(bool ) {
555- if s , ok := config .Colorscheme ["trailingws" ]; ok {
556- if bloc .X >= trailingwsStart && bloc .X < blineLen {
557- hl := true
558- for _ , c := range cursors {
559- if c .NewTrailingWsY == bloc .Y {
560- hl = false
561- break
562- }
563- }
564- if hl {
565- fg , _ , _ := s .Decompose ()
566- style = style .Background (fg )
567- dontOverrideBackground = true
568- }
591+ if b .Settings ["hltrailingws" ].(bool ) {
592+ if s , ok := config .Colorscheme ["trailingws" ]; ok {
593+ if bloc .X >= trailingwsStart && bloc .X < blineLen {
594+ hl := true
595+ for _ , c := range cursors {
596+ if c .NewTrailingWsY == bloc .Y {
597+ hl = false
598+ break
569599 }
570600 }
601+ if hl {
602+ fg , _ , _ := s .Decompose ()
603+ style = style .Background (fg )
604+ preservebg = true
605+ }
571606 }
607+ }
608+ }
572609
573- for _ , c := range cursors {
574- if c .HasSelection () &&
575- (bloc .GreaterEqual (c .CurSelection [0 ]) && bloc .LessThan (c .CurSelection [1 ]) ||
576- bloc .LessThan (c .CurSelection [0 ]) && bloc .GreaterEqual (c .CurSelection [1 ])) {
577- // The current character is selected
578- style = config .DefStyle .Reverse (true )
610+ return drawrune , style , preservebg
611+ }
579612
580- if s , ok := config .Colorscheme ["selection" ]; ok {
581- style = s
582- }
583- }
613+ draw := func (r rune , combc []rune , style tcell.Style , highlight bool , showcursor bool , preservebg bool ) {
614+ defer func () {
615+ if nColsBeforeStart <= 0 {
616+ vloc .X ++
617+ }
618+ nColsBeforeStart --
619+ }()
584620
585- if b .Settings ["cursorline" ].(bool ) && w .active && ! dontOverrideBackground &&
586- ! c .HasSelection () && c .Y == bloc .Y {
587- if s , ok := config .Colorscheme ["cursor-line" ]; ok {
588- fg , _ , _ := s .Decompose ()
589- style = style .Background (fg )
590- }
591- }
592- }
621+ if nColsBeforeStart > 0 || vloc .Y < 0 {
622+ return
623+ }
593624
594- for _ , m := range b .Messages {
595- if bloc .GreaterEqual (m .Start ) && bloc .LessThan (m .End ) ||
596- bloc .LessThan (m .End ) && bloc .GreaterEqual (m .Start ) {
597- style = style .Underline (true )
598- break
599- }
625+ if highlight {
626+ if w .Buf .HighlightSearch && w .Buf .SearchMatch (bloc ) {
627+ style = config .DefStyle .Reverse (true )
628+ if s , ok := config .Colorscheme ["hlsearch" ]; ok {
629+ style = s
600630 }
631+ }
601632
602- if (r == '\t' || r == ' ' ) && ! isplaceholder {
603- var indentrunes []rune
604- switch r {
605- case '\t' :
606- if bloc .X < leadingwsEnd && ! b .Settings ["tabstospaces" ].(bool ) {
607- indentrunes = []rune (indenttabchars )
608- } else {
609- indentrunes = []rune (tabchars )
610- }
611- case ' ' :
612- if bloc .X % tabsize == 0 && bloc .X < leadingwsEnd && b .Settings ["tabstospaces" ].(bool ) {
613- indentrunes = []rune (indentspacechars )
614- } else {
615- indentrunes = []rune (spacechars )
616- }
617- }
633+ _ , origBg , _ := style .Decompose ()
634+ _ , defBg , _ := config .DefStyle .Decompose ()
618635
619- if showoffset < len (indentrunes ) {
620- r = indentrunes [showoffset ]
621- } else {
622- // use space if no showchars or after we showed showchars
623- r = ' '
624- }
636+ // syntax or hlsearch highlighting with non-default background takes precedence
637+ // over cursor-line and color-column
638+ if ! preservebg && origBg != defBg {
639+ preservebg = true
640+ }
625641
626- if s , ok := config .Colorscheme ["indent-char" ]; ok && r != ' ' {
627- fg , _ , _ := s .Decompose ()
628- style = style .Foreground (fg )
642+ for _ , c := range cursors {
643+ if c .HasSelection () &&
644+ (bloc .GreaterEqual (c .CurSelection [0 ]) && bloc .LessThan (c .CurSelection [1 ]) ||
645+ bloc .LessThan (c .CurSelection [0 ]) && bloc .GreaterEqual (c .CurSelection [1 ])) {
646+ // The current character is selected
647+ style = config .DefStyle .Reverse (true )
648+
649+ if s , ok := config .Colorscheme ["selection" ]; ok {
650+ style = s
629651 }
630652 }
631653
632- if s , ok := config .Colorscheme ["color-column" ]; ok {
633- if colorcolumn != 0 && vloc .X - w .gutterOffset + w .StartCol == colorcolumn && ! dontOverrideBackground {
654+ if b .Settings ["cursorline" ].(bool ) && w .active && ! preservebg &&
655+ ! c .HasSelection () && c .Y == bloc .Y {
656+ if s , ok := config .Colorscheme ["cursor-line" ]; ok {
634657 fg , _ , _ := s .Decompose ()
635658 style = style .Background (fg )
636659 }
637660 }
661+ }
638662
639- for _ , mb := range matchingBraces {
640- if mb .X == bloc .X && mb .Y == bloc .Y {
641- if b .Settings ["matchbracestyle" ].(string ) == "highlight" {
642- if s , ok := config .Colorscheme ["match-brace" ]; ok {
643- style = s
644- } else {
645- style = style .Reverse (true )
646- }
647- } else {
648- style = style .Underline (true )
649- }
650- }
663+ for _ , m := range b .Messages {
664+ if bloc .GreaterEqual (m .Start ) && bloc .LessThan (m .End ) ||
665+ bloc .LessThan (m .End ) && bloc .GreaterEqual (m .Start ) {
666+ style = style .Underline (true )
667+ break
651668 }
652669 }
653670
654- screen .SetContent (w .X + vloc .X , w .Y + vloc .Y , r , combc , style )
655-
656- if showcursor {
657- for _ , c := range cursors {
658- if c .X == bloc .X && c .Y == bloc .Y && ! c .HasSelection () {
659- w .showCursor (w .X + vloc .X , w .Y + vloc .Y , c .Num == 0 )
660- }
671+ if s , ok := config .Colorscheme ["color-column" ]; ok {
672+ if colorcolumn != 0 && vloc .X - w .gutterOffset + w .StartCol == colorcolumn && ! preservebg {
673+ fg , _ , _ := s .Decompose ()
674+ style = style .Background (fg )
661675 }
662676 }
663677 }
664- if nColsBeforeStart <= 0 {
665- vloc .X ++
678+
679+ screen .SetContent (w .X + vloc .X , w .Y + vloc .Y , r , combc , style )
680+
681+ if showcursor {
682+ for _ , c := range cursors {
683+ if c .X == bloc .X && c .Y == bloc .Y && ! c .HasSelection () {
684+ w .showCursor (w .X + vloc .X , w .Y + vloc .Y , c .Num == 0 )
685+ }
686+ }
666687 }
667- nColsBeforeStart --
668688 }
669689
670690 wrap := func () {
@@ -712,6 +732,7 @@ func (w *BufWindow) displayBuffer() {
712732
713733 width := 0
714734
735+ linex := totalwidth
715736 switch r {
716737 case '\t' :
717738 ts := tabsize - (totalwidth % tabsize )
@@ -736,7 +757,7 @@ func (w *BufWindow) displayBuffer() {
736757 // If a word (or just a wide rune) does not fit in the window
737758 if vloc .X + wordwidth > maxWidth && vloc .X > w .gutterOffset {
738759 for vloc .X < maxWidth {
739- draw (' ' , 0 , nil , true , config .DefStyle , false , false )
760+ draw (' ' , nil , config .DefStyle , false , false , true )
740761 }
741762
742763 // We either stop or we wrap to draw the word in the next line
@@ -760,15 +781,17 @@ func (w *BufWindow) displayBuffer() {
760781 }
761782
762783 for _ , r := range word {
763- draw (r .r , 0 , r .combc , false , r .style , true , true )
784+ drawrune , drawstyle , preservebg := getRuneStyle (r .r , r .style , 0 , linex , false )
785+ draw (drawrune , r .combc , drawstyle , true , true , preservebg )
764786
765- // Draw any extra characters for tabs
787+ // Draw extra characters for tabs or wide runes
766788 for i := 1 ; i < r .width ; i ++ {
767- if r .r ! = '\t' {
768- draw ( ' ' , i , nil , true , r .style , true , false )
789+ if r .r = = '\t' {
790+ drawrune , drawstyle , preservebg = getRuneStyle ( '\t' , r .style , i , linex + i , false )
769791 } else {
770- draw ( '\t' , i , nil , false , r .style , true , false )
792+ drawrune , drawstyle , preservebg = getRuneStyle ( ' ' , r .style , i , linex + i , true )
771793 }
794+ draw (drawrune , nil , drawstyle , true , false , preservebg )
772795 }
773796 bloc .X ++
774797 }
@@ -821,7 +844,8 @@ func (w *BufWindow) displayBuffer() {
821844
822845 if vloc .X != maxWidth {
823846 // Display newline within a selection
824- draw (' ' , 0 , nil , true , config .DefStyle , true , true )
847+ drawrune , drawstyle , preservebg := getRuneStyle (' ' , config .DefStyle , 0 , totalwidth , true )
848+ draw (drawrune , nil , drawstyle , true , true , preservebg )
825849 }
826850
827851 bloc .X = w .StartCol
0 commit comments