3434from rich .table import Table
3535from rich .text import Text
3636
37- from pythinker_code .ui .shell .components .markdown import PythinkerMarkdown , pythinker_markdown
37+ from pythinker_code .ui .shell .components .markdown import pythinker_markdown , pythinker_report_markdown
38+ from pythinker_code .ui .shell .glyphs import REPORT_FILE_MARKER
3839from pythinker_code .ui .shell .spacing import REPORT_PANEL_PADDING
39- from pythinker_code .ui .theme import ThemeName , tui_rich_style
40+ from pythinker_code .ui .theme import ThemeName , get_tui_tokens , tui_rich_style
4041
4142_log = logging .getLogger (__name__ )
4243
5657_SEVERITY_ORDER : tuple [Severity , ...] = get_args (Severity )
5758_SEVERITY_SET = frozenset (_SEVERITY_ORDER )
5859
59- # severity -> (token name, bold). Muted theme tokens only; critical is the one
60- # emphasis (bold) so the eye lands on it without a brighter colour .
60+ # severity -> (token name, bold). Report panels keep body text regular weight;
61+ # only the panel title (H1 equivalent) uses bold .
6162_SEVERITY_TOKEN : dict [Severity , tuple [str , bool ]] = {
62- "critical" : ("error" , True ),
63+ "critical" : ("error" , False ),
6364 "high" : ("error" , False ),
6465 "medium" : ("warning" , False ),
6566 "low" : ("accent" , False ),
66- "info" : ("muted " , False ),
67+ "info" : ("activity_spinner " , False ),
6768}
6869
6970_DOT = "●"
@@ -251,19 +252,19 @@ def _render_report_prose(text: str, *, theme: ThemeName | None = None) -> Render
251252
252253 rows : list [RenderableType ] = []
253254 if report .preamble .strip ():
254- rows .append (pythinker_markdown (report .preamble ))
255+ rows .append (pythinker_report_markdown (report .preamble ))
255256
256257 body_style = tui_rich_style ("text" , theme = theme )
257258 for section in report .sections :
258259 if rows :
259260 rows .append (Text ("" ))
260- # Use a lower-level Markdown heading so inline code / links inside labels
261- # keep the standard muted-blue highlight without promoting every report
262- # subsection to the muted-yellow H1 treatment.
263- rows .append (PythinkerMarkdown (f"### { section .title } " ))
261+ rows .append (pythinker_report_markdown (f"# { section .title } " ))
264262 if section .body .strip ():
265263 rows .append (
266- Padding (PythinkerMarkdown (section .body .strip (), style = body_style ), (0 , 0 , 0 , 2 ))
264+ Padding (
265+ pythinker_report_markdown (section .body .strip (), style = body_style ),
266+ (0 , 0 , 0 , 2 ),
267+ )
267268 )
268269
269270 return Group (* rows )
@@ -282,24 +283,50 @@ def _severity_style(severity: Severity, theme: ThemeName | None) -> RichStyle:
282283 return style + RichStyle (bold = True ) if bold else style
283284
284285
286+ def _strong_style (theme : ThemeName | None ) -> RichStyle :
287+ return tui_rich_style ("tool_title" , theme = theme ) + RichStyle (bold = True )
288+
289+
290+ def _primary_style (theme : ThemeName | None ) -> RichStyle :
291+ return tui_rich_style ("text" , theme = theme )
292+
293+
294+ def _secondary_style (theme : ThemeName | None ) -> RichStyle :
295+ return tui_rich_style ("secondary" , theme = theme )
296+
297+
298+ def _muted_style (theme : ThemeName | None ) -> RichStyle :
299+ return tui_rich_style ("muted" , theme = theme )
300+
301+
285302def _summary_line (counts : dict [Severity , int ], theme : ThemeName | None ) -> Text :
286303 line = Text ()
304+ pill_bg = get_tui_tokens (theme ).tool_pending_bg
305+ bg = RichStyle (bgcolor = pill_bg )
287306 first = True
288307 for severity in _SEVERITY_ORDER :
289308 count = counts [severity ]
290309 if not count :
291310 continue
292311 if not first :
293- line .append (" " )
312+ line .append (" " )
294313 first = False
295- line .append (f"{ _DOT } " , style = _severity_style (severity , theme ))
296- line .append (f"{ count } { severity } " , style = tui_rich_style ( "text" , theme = theme ) )
314+ line .append (f" { _DOT } " , style = _severity_style (severity , theme ) + bg )
315+ line .append (f"{ count } { severity } " , style = _primary_style ( theme ) + bg )
297316 if not counts ["critical" ] and not counts ["high" ]:
298- prefix = " " if not first else ""
299- line .append (f"{ prefix } no critical or high" , style = tui_rich_style ( "muted" , theme = theme ))
317+ prefix = " " if not first else ""
318+ line .append (f"{ prefix } no critical or high" , style = _secondary_style ( theme ))
300319 return line
301320
302321
322+ def _render_section_header (severity : Severity , theme : ThemeName | None ) -> Group :
323+ border = tui_rich_style ("border" , theme = theme )
324+ return Group (
325+ Text (severity .capitalize (), style = tui_rich_style ("tool_title" , theme = theme )),
326+ Rule (style = border , characters = "─" ),
327+ )
328+
329+
303330def _render_finding (finding : ReportFinding , theme : ThemeName | None ) -> RenderableType :
304331 rows : list [RenderableType ] = []
305332
@@ -313,22 +340,29 @@ def _render_finding(finding: ReportFinding, theme: ThemeName | None) -> Renderab
313340 title .add_column (overflow = "fold" )
314341 title .add_row (
315342 Text (_DOT , style = _severity_style (finding .severity , theme )),
316- Text (finding .title , style = tui_rich_style ( "border" , theme = theme ) + RichStyle ( bold = True )),
343+ Text (finding .title , style = _primary_style ( theme )),
317344 )
318345 rows .append (title )
319346
320347 if finding .location :
321- # Keep wrapped file paths in the same hanging-indent column. A raw
322- # leading-space Text only indents the first physical line after Rich
323- # wraps, which makes long locations drift left inside wide reports.
324- rows .append (
325- Padding (Text (finding .location , style = tui_rich_style ("dim" , theme = theme )), (0 , 0 , 0 , 2 ))
348+ rows .append (Text ("" ))
349+ muted = _muted_style (theme )
350+ location = Table .grid (padding = 0 )
351+ location .add_column (width = 2 , no_wrap = True )
352+ location .add_column (overflow = "fold" )
353+ location .add_row (
354+ Text (REPORT_FILE_MARKER , style = muted ),
355+ Text (finding .location , style = muted ),
326356 )
357+ rows .append (location )
327358
328359 if finding .body .strip ():
329- body_style = tui_rich_style ( "text" , theme = theme )
360+ body_style = _primary_style ( theme )
330361 rows .append (
331- Padding (PythinkerMarkdown (finding .body .strip (), style = body_style ), (0 , 0 , 0 , 2 ))
362+ Padding (
363+ pythinker_report_markdown (finding .body .strip (), style = body_style ),
364+ (0 , 0 , 0 , 2 ),
365+ )
332366 )
333367
334368 return Group (* rows )
@@ -337,20 +371,20 @@ def _render_finding(finding: ReportFinding, theme: ThemeName | None) -> Renderab
337371def render_report (report : Report , * , theme : ThemeName | None = None ) -> RenderableType :
338372 """Render *report* as a padded, syntax-friendly Rich report panel."""
339373 counts = _counts (report .findings )
340- border = tui_rich_style ("border_muted " , theme = theme )
374+ border = tui_rich_style ("border " , theme = theme )
341375 blank = Text ("" )
342376
343377 rows : list [RenderableType ] = []
344378 if report .scope :
345- rows += [Text (report .scope , style = tui_rich_style ( "dim" , theme = theme )), blank ]
379+ rows += [Text (report .scope , style = _secondary_style ( theme )), blank ]
346380 rows .append (_summary_line (counts , theme ))
347381
348382 for severity in _SEVERITY_ORDER :
349383 group = [f for f in report .findings if f .severity == severity ]
350384 if not group :
351385 continue
352386 rows .append (blank )
353- rows .append (Rule ( f" { severity . capitalize () } " , align = "left" , style = border , characters = "─" ))
387+ rows .append (_render_section_header ( severity , theme ))
354388 for finding in group :
355389 rows .append (blank )
356390 rows .append (_render_finding (finding , theme ))
@@ -359,10 +393,10 @@ def render_report(report: Report, *, theme: ThemeName | None = None) -> Renderab
359393 rows += [
360394 blank ,
361395 Rule (style = border , characters = "─" ),
362- Text (report .note , style = tui_rich_style ( "muted" , theme = theme )),
396+ Text (report .note , style = _secondary_style ( theme )),
363397 ]
364398
365- title = Text (report .title , style = tui_rich_style ( "warning" , theme = theme ) + RichStyle ( bold = True ))
399+ title = Text (report .title , style = _strong_style ( theme ))
366400 return Panel (
367401 Group (* rows ),
368402 title = title ,
0 commit comments