@@ -82,9 +82,33 @@ function trimSpans(spans: RenderSpan[], width: number) {
8282 } ;
8383}
8484
85- /** Render the left-edge hunk marker without changing row width. */
86- function marker ( selected : boolean ) {
87- return selected ? "▌" : " " ;
85+ /** Parse a hex color string into RGB components. */
86+ function hexToRgb ( hex : string ) {
87+ const n = parseInt ( hex . slice ( 1 ) , 16 ) ;
88+ return { r : ( n >> 16 ) & 0xff , g : ( n >> 8 ) & 0xff , b : n & 0xff } ;
89+ }
90+
91+ /** Blend a color toward a background at a given ratio (0 = bg, 1 = fg). */
92+ function blendHex ( fg : string , bg : string , ratio : number ) {
93+ const f = hexToRgb ( fg ) ;
94+ const b = hexToRgb ( bg ) ;
95+ const mix = ( a : number , z : number ) => Math . round ( z + ( a - z ) * ratio ) ;
96+ const r = mix ( f . r , b . r ) ;
97+ const g = mix ( f . g , b . g ) ;
98+ const bl = mix ( f . b , b . b ) ;
99+ return `#${ ( ( r << 16 ) | ( g << 8 ) | bl ) . toString ( 16 ) . padStart ( 6 , "0" ) } ` ;
100+ }
101+
102+ const INACTIVE_RAIL_BLEND = 0.35 ;
103+
104+ /** Dim a rail color for inactive hunks by blending toward the panel background. */
105+ function dimRailColor ( color : string , theme : AppTheme ) {
106+ return blendHex ( color , theme . panel , INACTIVE_RAIL_BLEND ) ;
107+ }
108+
109+ /** The rail marker is always visible. */
110+ function marker ( ) {
111+ return "▌" ;
88112}
89113
90114/** Return the neutral active-hunk rail color for the current theme. */
@@ -93,26 +117,30 @@ function neutralRailColor(theme: AppTheme) {
93117}
94118
95119/** Pick the stack-view rail color for one rendered row. */
96- function stackRailColor ( kind : StackLineCell [ "kind" ] , theme : AppTheme ) {
97- if ( kind === "addition" ) {
98- return theme . addedSignColor ;
99- }
120+ function stackRailColor ( kind : StackLineCell [ "kind" ] , theme : AppTheme , selected : boolean ) {
121+ let color : string ;
100122
101- if ( kind === "deletion" ) {
102- return theme . removedSignColor ;
123+ if ( kind === "addition" ) {
124+ color = theme . addedSignColor ;
125+ } else if ( kind === "deletion" ) {
126+ color = theme . removedSignColor ;
127+ } else {
128+ color = neutralRailColor ( theme ) ;
103129 }
104130
105- return neutralRailColor ( theme ) ;
131+ return selected ? color : dimRailColor ( color , theme ) ;
106132}
107133
108134/** Pick the left split-view rail color from the old-side cell state. */
109- function splitLeftRailColor ( kind : SplitLineCell [ "kind" ] , theme : AppTheme ) {
110- return kind === "deletion" ? theme . removedSignColor : neutralRailColor ( theme ) ;
135+ function splitLeftRailColor ( kind : SplitLineCell [ "kind" ] , theme : AppTheme , selected : boolean ) {
136+ const color = kind === "deletion" ? theme . removedSignColor : neutralRailColor ( theme ) ;
137+ return selected ? color : dimRailColor ( color , theme ) ;
111138}
112139
113140/** Pick the right split-view rail color from the new-side cell state. */
114- function splitRightRailColor ( kind : SplitLineCell [ "kind" ] , theme : AppTheme ) {
115- return kind === "addition" ? theme . addedSignColor : neutralRailColor ( theme ) ;
141+ function splitRightRailColor ( kind : SplitLineCell [ "kind" ] , theme : AppTheme , selected : boolean ) {
142+ const color = kind === "addition" ? theme . addedSignColor : neutralRailColor ( theme ) ;
143+ return selected ? color : dimRailColor ( color , theme ) ;
116144}
117145
118146/** Pick split-view colors from the semantic diff cell kind. */
@@ -510,8 +538,8 @@ function renderHeaderRow(
510538 } }
511539 >
512540 < text >
513- < span fg = { selected ? neutralRailColor ( theme ) : theme . panelAlt } bg = { theme . panelAlt } >
514- { marker ( selected ) }
541+ < span fg = { selected ? neutralRailColor ( theme ) : dimRailColor ( neutralRailColor ( theme ) , theme ) } bg = { theme . panelAlt } >
542+ { marker ( ) }
515543 </ span >
516544 < span fg = { row . type === "collapsed" ? theme . muted : theme . badgeNeutral } bg = { theme . panelAlt } >
517545 { label }
@@ -534,8 +562,8 @@ function renderHeaderRow(
534562 >
535563 < box style = { { width : Math . max ( 0 , width - badgeWidth ) , height : 1 } } >
536564 < text >
537- < span fg = { selected ? neutralRailColor ( theme ) : theme . panelAlt } bg = { theme . panelAlt } >
538- { marker ( selected ) }
565+ < span fg = { selected ? neutralRailColor ( theme ) : dimRailColor ( neutralRailColor ( theme ) , theme ) } bg = { theme . panelAlt } >
566+ { marker ( ) }
539567 </ span >
540568 < span fg = { row . type === "collapsed" ? theme . muted : theme . badgeNeutral } bg = { theme . panelAlt } >
541569 { label }
@@ -684,13 +712,13 @@ function renderRow(
684712 const leftWidth = Math . max ( 0 , markerWidth + Math . floor ( usableWidth / 2 ) ) ;
685713 const rightWidth = Math . max ( 0 , separatorWidth + usableWidth - Math . floor ( usableWidth / 2 ) ) ;
686714 const leftPrefix = {
687- text : marker ( selected ) ,
688- fg : selected ? splitLeftRailColor ( row . left . kind , theme ) : theme . panel ,
715+ text : marker ( ) ,
716+ fg : splitLeftRailColor ( row . left . kind , theme , selected ) ,
689717 bg : theme . panel ,
690718 } ;
691719 const rightPrefix = {
692- text : selected ? "▌" : "│ ",
693- fg : selected ? splitRightRailColor ( row . right . kind , theme ) : theme . border ,
720+ text : "▌ ",
721+ fg : splitRightRailColor ( row . right . kind , theme , selected ) ,
694722 bg : theme . panel ,
695723 } ;
696724
@@ -744,8 +772,8 @@ function renderRow(
744772 }
745773 } else if ( row . type === "stack-line" ) {
746774 const prefix = {
747- text : marker ( selected ) ,
748- fg : selected ? stackRailColor ( row . cell . kind , theme ) : theme . panel ,
775+ text : marker ( ) ,
776+ fg : stackRailColor ( row . cell . kind , theme , selected ) ,
749777 bg : theme . panel ,
750778 } ;
751779
0 commit comments