@@ -19,8 +19,8 @@ pub(crate) struct GenericDisplayRow {
1919 pub name : String ,
2020 pub display_shortcut : Option < KeyBinding > ,
2121 pub match_indices : Option < Vec < usize > > , // indices to bold (char positions)
22- pub is_current : bool ,
23- pub description : Option < String > , // optional grey text after the name
22+ pub description : Option < String > , // optional grey text after the name
23+ pub wrap_indent : Option < usize > , // optional indent for wrapped lines
2424}
2525
2626/// Compute a shared description-column start based on the widest visible name
@@ -47,13 +47,30 @@ fn compute_desc_col(
4747 desc_col
4848}
4949
50+ /// Determine how many spaces to indent wrapped lines for a row.
51+ fn wrap_indent ( row : & GenericDisplayRow , desc_col : usize , max_width : u16 ) -> usize {
52+ let max_indent = max_width. saturating_sub ( 1 ) as usize ;
53+ let indent = row. wrap_indent . unwrap_or_else ( || {
54+ if row. description . is_some ( ) {
55+ desc_col
56+ } else {
57+ 0
58+ }
59+ } ) ;
60+ indent. min ( max_indent)
61+ }
62+
5063/// Build the full display line for a row with the description padded to start
5164/// at `desc_col`. Applies fuzzy-match bolding when indices are present and
5265/// dims the description.
5366fn build_full_line ( row : & GenericDisplayRow , desc_col : usize ) -> Line < ' static > {
5467 // Enforce single-line name: allow at most desc_col - 2 cells for name,
5568 // reserving two spaces before the description column.
56- let name_limit = desc_col. saturating_sub ( 2 ) ;
69+ let name_limit = row
70+ . description
71+ . as_ref ( )
72+ . map ( |_| desc_col. saturating_sub ( 2 ) )
73+ . unwrap_or ( usize:: MAX ) ;
5774
5875 let mut name_spans: Vec < Span > = Vec :: with_capacity ( row. name . len ( ) ) ;
5976 let mut used_width = 0usize ;
@@ -63,11 +80,12 @@ fn build_full_line(row: &GenericDisplayRow, desc_col: usize) -> Line<'static> {
6380 let mut idx_iter = idxs. iter ( ) . peekable ( ) ;
6481 for ( char_idx, ch) in row. name . chars ( ) . enumerate ( ) {
6582 let ch_w = UnicodeWidthChar :: width ( ch) . unwrap_or ( 0 ) ;
66- if used_width + ch_w > name_limit {
83+ let next_width = used_width. saturating_add ( ch_w) ;
84+ if next_width > name_limit {
6785 truncated = true ;
6886 break ;
6987 }
70- used_width += ch_w ;
88+ used_width = next_width ;
7189
7290 if idx_iter. peek ( ) . is_some_and ( |next| * * next == char_idx) {
7391 idx_iter. next ( ) ;
@@ -79,11 +97,12 @@ fn build_full_line(row: &GenericDisplayRow, desc_col: usize) -> Line<'static> {
7997 } else {
8098 for ch in row. name . chars ( ) {
8199 let ch_w = UnicodeWidthChar :: width ( ch) . unwrap_or ( 0 ) ;
82- if used_width + ch_w > name_limit {
100+ let next_width = used_width. saturating_add ( ch_w) ;
101+ if next_width > name_limit {
83102 truncated = true ;
84103 break ;
85104 }
86- used_width += ch_w ;
105+ used_width = next_width ;
87106 name_spans. push ( ch. to_string ( ) . into ( ) ) ;
88107 }
89108 }
@@ -161,24 +180,7 @@ pub(crate) fn render_rows(
161180 break ;
162181 }
163182
164- let GenericDisplayRow {
165- name,
166- match_indices,
167- display_shortcut,
168- is_current : _is_current,
169- description,
170- } = row;
171-
172- let mut full_line = build_full_line (
173- & GenericDisplayRow {
174- name : name. clone ( ) ,
175- match_indices : match_indices. clone ( ) ,
176- display_shortcut : * display_shortcut,
177- is_current : * _is_current,
178- description : description. clone ( ) ,
179- } ,
180- desc_col,
181- ) ;
183+ let mut full_line = build_full_line ( row, desc_col) ;
182184 if Some ( i) == state. selected_idx {
183185 // Match previous behavior: cyan + bold for the selected row.
184186 // Reset the style first to avoid inheriting dim from keyboard shortcuts.
@@ -190,9 +192,10 @@ pub(crate) fn render_rows(
190192 // Wrap with subsequent indent aligned to the description column.
191193 use crate :: wrapping:: RtOptions ;
192194 use crate :: wrapping:: word_wrap_line;
195+ let continuation_indent = wrap_indent ( row, desc_col, area. width ) ;
193196 let options = RtOptions :: new ( area. width as usize )
194197 . initial_indent ( Line :: from ( "" ) )
195- . subsequent_indent ( Line :: from ( " " . repeat ( desc_col ) ) ) ;
198+ . subsequent_indent ( Line :: from ( " " . repeat ( continuation_indent ) ) ) ;
196199 let wrapped = word_wrap_line ( & full_line, options) ;
197200
198201 // Render the wrapped lines.
@@ -256,9 +259,10 @@ pub(crate) fn measure_rows_height(
256259 . map ( |( _, r) | r)
257260 {
258261 let full_line = build_full_line ( row, desc_col) ;
262+ let continuation_indent = wrap_indent ( row, desc_col, content_width) ;
259263 let opts = RtOptions :: new ( content_width as usize )
260264 . initial_indent ( Line :: from ( "" ) )
261- . subsequent_indent ( Line :: from ( " " . repeat ( desc_col ) ) ) ;
265+ . subsequent_indent ( Line :: from ( " " . repeat ( continuation_indent ) ) ) ;
262266 total = total. saturating_add ( word_wrap_line ( & full_line, opts) . len ( ) as u16 ) ;
263267 }
264268 total. max ( 1 )
0 commit comments