@@ -100,6 +100,7 @@ export function renderTail(
100100 const outputLines : string [ ] = [ ] ;
101101 const theme = themeManager . getTheme ( ) ;
102102 const indent = ' ' . repeat ( state . prefixIndent ) ;
103+ const borderColor = chalk . dim . hex ( theme . colors . border . light ) ;
103104
104105 // 隐藏行提示
105106 if ( hiddenLines > 0 ) {
@@ -108,27 +109,74 @@ export function renderTail(
108109 ) ;
109110 }
110111
112+ // 代码块模式:从 lines 中分离 fence 行和实际代码
113+ const isCodeMode = mode === 'code' ;
114+ const isDiffMode = mode === 'diff' ;
115+ let codeLang = '' ;
116+ let contentLines = lines ;
117+
118+ if ( isCodeMode && lines . length > 0 ) {
119+ // 第一行是 fence(如 "```typescript"),解析语言并跳过
120+ const fenceMatch = lines [ 0 ] . match ( / ^ ` ` ` ( \w + ) ? / ) ;
121+ codeLang = fenceMatch ?. [ 1 ] || '' ;
122+ contentLines = lines . slice ( 1 ) ;
123+ } else if ( isDiffMode && lines . length > 0 && lines [ 0 ] === '<<<DIFF>>>' ) {
124+ contentLines = lines . slice ( 1 ) ;
125+ }
126+
127+ const visibleLines = contentLines . slice ( - maxDisplayLines ) ;
128+
129+ // 代码块:渲染顶部边框 + 语言标签
130+ if ( isCodeMode && hiddenLines === 0 ) {
131+ const langLabel = codeLang
132+ ? ` ${ chalk . hex ( theme . colors . text . secondary ) ( codeLang ) } `
133+ : '' ;
134+ outputLines . push ( `${ indent } ${ borderColor ( '╭─' ) } ${ langLabel } ` ) ;
135+ }
136+
111137 // 内容行
112- const visibleLines = lines . slice ( - maxDisplayLines ) ;
113138 for ( let i = 0 ; i < visibleLines . length ; i ++ ) {
114139 const line = visibleLines [ i ] ;
115140 let prefix = indent ;
116141
117- // 首行前缀
118- if ( i === 0 && ! hidePrefix && state . isFirstRender ) {
142+ // 首行前缀(仅 text 模式使用 bullet)
143+ if ( i === 0 && ! hidePrefix && state . isFirstRender && ! isCodeMode && ! isDiffMode ) {
119144 prefix = chalk . bold . hex ( theme . colors . success ) ( '• ' ) + ' ' ;
120145 state . isFirstRender = false ;
121146 }
122147
123148 // 截断超宽行
124- const maxContentWidth = state . terminalWidth - state . prefixIndent - 2 ;
149+ const borderExtra = isCodeMode ? 4 : 0 ; // "│ " 占 2 字符 + 2 边距
150+ const maxContentWidth = state . terminalWidth - state . prefixIndent - 2 - borderExtra ;
125151 let displayLine = line ;
126152 if ( stringWidth ( line ) > maxContentWidth ) {
127153 // 简单截断(不处理 ANSI,因为 tail 是纯文本)
128154 displayLine = line . slice ( 0 , maxContentWidth ) ;
129155 }
130156
131- outputLines . push ( `${ prefix } ${ displayLine } ` ) ;
157+ if ( isCodeMode ) {
158+ // 代码块行:添加左边框
159+ outputLines . push ( `${ indent } ${ borderColor ( '│' ) } ${ displayLine } ` ) ;
160+ } else if ( isDiffMode ) {
161+ // Diff 行:按前缀着色
162+ const trimmed = displayLine ;
163+ if ( trimmed . startsWith ( '+' ) ) {
164+ outputLines . push ( `${ prefix } ${ chalk . green ( displayLine ) } ` ) ;
165+ } else if ( trimmed . startsWith ( '-' ) ) {
166+ outputLines . push ( `${ prefix } ${ chalk . red ( displayLine ) } ` ) ;
167+ } else if ( trimmed . startsWith ( '@@' ) ) {
168+ outputLines . push ( `${ prefix } ${ chalk . dim ( displayLine ) } ` ) ;
169+ } else {
170+ outputLines . push ( `${ prefix } ${ displayLine } ` ) ;
171+ }
172+ } else {
173+ outputLines . push ( `${ prefix } ${ displayLine } ` ) ;
174+ }
175+
176+ // 首次渲染标记(代码块和 diff 模式在首行已输出边框,此处仍需标记)
177+ if ( i === 0 && ! hidePrefix && state . isFirstRender ) {
178+ state . isFirstRender = false ;
179+ }
132180 }
133181
134182 // 差量渲染:对比上一帧,只更新变化的行
0 commit comments