diff --git a/helix-term/src/ui/lsp/signature_help.rs b/helix-term/src/ui/lsp/signature_help.rs index 87a3eb95f..8df525aff 100644 --- a/helix-term/src/ui/lsp/signature_help.rs +++ b/helix-term/src/ui/lsp/signature_help.rs @@ -94,7 +94,8 @@ impl Component for SignatureHelp { } fn render(&mut self, area: Rect, surface: &mut Buffer, cx: &mut Context) { - let margin = Margin::horizontal(1); + let margin = Margin::all(1); + let area = area.inner(margin); let signature = self .signatures @@ -127,13 +128,15 @@ impl Component for SignatureHelp { let signature_index = self.signature_index(); let text = Text::from(signature_index); let paragraph = Paragraph::new(&text).alignment(Alignment::Right); - paragraph.render(area.clip_top(1).with_height(1).clip_right(1), surface); + paragraph.render(area.with_height(1).clip_right(1), surface); } - let (_, sig_text_height) = crate::ui::text::required_size(&sig_text, area.width); - let sig_text_area = area.clip_top(1).with_height(sig_text_height); - let sig_text_area = sig_text_area.inner(margin).intersection(surface.area); - let sig_text_para = Paragraph::new(&sig_text).wrap(Wrap { trim: false }); + let sig_text_para = Paragraph::new(&sig_text) + .wrap(Wrap { trim: false }) + .scroll((cx.scroll.unwrap_or_default() as u16, 0)); + let (_, sig_text_height) = sig_text_para.required_size(area.width); + let sig_text_area = area.with_height(sig_text_height.min(area.height)); + let sig_text_area = sig_text_area.intersection(surface.area); sig_text_para.render(sig_text_area, surface); if signature.signature_doc.is_none() { @@ -159,7 +162,7 @@ impl Component for SignatureHelp { let sig_doc_para = Paragraph::new(&sig_doc) .wrap(Wrap { trim: false }) .scroll((cx.scroll.unwrap_or_default() as u16, 0)); - sig_doc_para.render(sig_doc_area.inner(margin), surface); + sig_doc_para.render(sig_doc_area, surface); } fn required_size(&mut self, viewport: (u16, u16)) -> Option<(u16, u16)> { @@ -180,8 +183,8 @@ impl Component for SignatureHelp { &self.config_loader.load(), None, ); - let (sig_width, sig_height) = - crate::ui::text::required_size(&signature_text, max_text_width); + let sig_text_para = Paragraph::new(&signature_text).wrap(Wrap { trim: false }); + let (sig_width, sig_height) = sig_text_para.required_size(max_text_width); let (width, height) = match signature.signature_doc { Some(ref doc) => { diff --git a/helix-tui/src/widgets/paragraph.rs b/helix-tui/src/widgets/paragraph.rs index 73153a077..2b4ccfbd1 100644 --- a/helix-tui/src/widgets/paragraph.rs +++ b/helix-tui/src/widgets/paragraph.rs @@ -127,6 +127,38 @@ impl<'a> Paragraph<'a> { self.alignment = alignment; self } + + pub fn required_size(&self, max_text_width: u16) -> (u16, u16) { + let style = self.style; + let mut styled = self.text.lines.iter().flat_map(|spans| { + spans + .0 + .iter() + .flat_map(|span| span.styled_graphemes(style)) + // Required given the way composers work but might be refactored out if we change + // composers to operate on lines instead of a stream of graphemes. + .chain(iter::once(StyledGrapheme { + symbol: "\n", + style: self.style, + })) + }); + let mut line_composer: Box = if let Some(Wrap { trim }) = self.wrap { + Box::new(WordWrapper::new(&mut styled, max_text_width, trim)) + } else { + let mut line_composer = Box::new(LineTruncator::new(&mut styled, max_text_width)); + if self.alignment == Alignment::Left { + line_composer.set_horizontal_offset(self.scroll.1); + } + line_composer + }; + let mut text_width = 0; + let mut text_height = 0; + while let Some((_, line_width)) = line_composer.next_line() { + text_width = line_width.max(text_width); + text_height += 1; + } + (text_width, text_height) + } } impl Widget for Paragraph<'_> {