Preparse documentation markdown when resolving completion

This commit is contained in:
Julia 2023-10-03 10:58:08 -04:00
parent fe62423344
commit b8876f2b17
6 changed files with 144 additions and 91 deletions

View file

@ -119,12 +119,12 @@ pub const DOCUMENT_HIGHLIGHTS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis
pub const FORMAT_TIMEOUT: Duration = Duration::from_secs(2); pub const FORMAT_TIMEOUT: Duration = Duration::from_secs(2);
pub fn render_rendered_markdown( pub fn render_parsed_markdown(
md: &language::RenderedMarkdown, md: &language::ParsedMarkdown,
style: &EditorStyle, style: &EditorStyle,
cx: &mut ViewContext<Editor>, cx: &mut ViewContext<Editor>,
) -> Text { ) -> Text {
enum RenderedRenderedMarkdown {} enum RenderedMarkdown {}
let md = md.clone(); let md = md.clone();
let code_span_background_color = style.document_highlight_read_background; let code_span_background_color = style.document_highlight_read_background;
@ -141,7 +141,7 @@ pub fn render_rendered_markdown(
style: CursorStyle::PointingHand, style: CursorStyle::PointingHand,
}); });
scene.push_mouse_region( scene.push_mouse_region(
MouseRegion::new::<RenderedRenderedMarkdown>(view_id, region_id, bounds) MouseRegion::new::<RenderedMarkdown>(view_id, region_id, bounds)
.on_click::<Editor, _>(MouseButton::Left, move |_, _, cx| { .on_click::<Editor, _>(MouseButton::Left, move |_, _, cx| {
cx.platform().open_url(&url) cx.platform().open_url(&url)
}), }),
@ -831,11 +831,12 @@ impl ContextMenu {
fn select_first( fn select_first(
&mut self, &mut self,
project: Option<&ModelHandle<Project>>, project: Option<&ModelHandle<Project>>,
style: theme::Editor,
cx: &mut ViewContext<Editor>, cx: &mut ViewContext<Editor>,
) -> bool { ) -> bool {
if self.visible() { if self.visible() {
match self { match self {
ContextMenu::Completions(menu) => menu.select_first(project, cx), ContextMenu::Completions(menu) => menu.select_first(project, style, cx),
ContextMenu::CodeActions(menu) => menu.select_first(cx), ContextMenu::CodeActions(menu) => menu.select_first(cx),
} }
true true
@ -847,11 +848,12 @@ impl ContextMenu {
fn select_prev( fn select_prev(
&mut self, &mut self,
project: Option<&ModelHandle<Project>>, project: Option<&ModelHandle<Project>>,
style: theme::Editor,
cx: &mut ViewContext<Editor>, cx: &mut ViewContext<Editor>,
) -> bool { ) -> bool {
if self.visible() { if self.visible() {
match self { match self {
ContextMenu::Completions(menu) => menu.select_prev(project, cx), ContextMenu::Completions(menu) => menu.select_prev(project, style, cx),
ContextMenu::CodeActions(menu) => menu.select_prev(cx), ContextMenu::CodeActions(menu) => menu.select_prev(cx),
} }
true true
@ -863,11 +865,12 @@ impl ContextMenu {
fn select_next( fn select_next(
&mut self, &mut self,
project: Option<&ModelHandle<Project>>, project: Option<&ModelHandle<Project>>,
style: theme::Editor,
cx: &mut ViewContext<Editor>, cx: &mut ViewContext<Editor>,
) -> bool { ) -> bool {
if self.visible() { if self.visible() {
match self { match self {
ContextMenu::Completions(menu) => menu.select_next(project, cx), ContextMenu::Completions(menu) => menu.select_next(project, style, cx),
ContextMenu::CodeActions(menu) => menu.select_next(cx), ContextMenu::CodeActions(menu) => menu.select_next(cx),
} }
true true
@ -879,11 +882,12 @@ impl ContextMenu {
fn select_last( fn select_last(
&mut self, &mut self,
project: Option<&ModelHandle<Project>>, project: Option<&ModelHandle<Project>>,
style: theme::Editor,
cx: &mut ViewContext<Editor>, cx: &mut ViewContext<Editor>,
) -> bool { ) -> bool {
if self.visible() { if self.visible() {
match self { match self {
ContextMenu::Completions(menu) => menu.select_last(project, cx), ContextMenu::Completions(menu) => menu.select_last(project, style, cx),
ContextMenu::CodeActions(menu) => menu.select_last(cx), ContextMenu::CodeActions(menu) => menu.select_last(cx),
} }
true true
@ -928,60 +932,66 @@ impl CompletionsMenu {
fn select_first( fn select_first(
&mut self, &mut self,
project: Option<&ModelHandle<Project>>, project: Option<&ModelHandle<Project>>,
style: theme::Editor,
cx: &mut ViewContext<Editor>, cx: &mut ViewContext<Editor>,
) { ) {
self.selected_item = 0; self.selected_item = 0;
self.list.scroll_to(ScrollTarget::Show(self.selected_item)); self.list.scroll_to(ScrollTarget::Show(self.selected_item));
self.attempt_resolve_selected_completion(project, cx); self.attempt_resolve_selected_completion(project, style, cx);
cx.notify(); cx.notify();
} }
fn select_prev( fn select_prev(
&mut self, &mut self,
project: Option<&ModelHandle<Project>>, project: Option<&ModelHandle<Project>>,
style: theme::Editor,
cx: &mut ViewContext<Editor>, cx: &mut ViewContext<Editor>,
) { ) {
if self.selected_item > 0 { if self.selected_item > 0 {
self.selected_item -= 1; self.selected_item -= 1;
self.list.scroll_to(ScrollTarget::Show(self.selected_item)); self.list.scroll_to(ScrollTarget::Show(self.selected_item));
} }
self.attempt_resolve_selected_completion(project, cx); self.attempt_resolve_selected_completion(project, style, cx);
cx.notify(); cx.notify();
} }
fn select_next( fn select_next(
&mut self, &mut self,
project: Option<&ModelHandle<Project>>, project: Option<&ModelHandle<Project>>,
style: theme::Editor,
cx: &mut ViewContext<Editor>, cx: &mut ViewContext<Editor>,
) { ) {
if self.selected_item + 1 < self.matches.len() { if self.selected_item + 1 < self.matches.len() {
self.selected_item += 1; self.selected_item += 1;
self.list.scroll_to(ScrollTarget::Show(self.selected_item)); self.list.scroll_to(ScrollTarget::Show(self.selected_item));
} }
self.attempt_resolve_selected_completion(project, cx); self.attempt_resolve_selected_completion(project, style, cx);
cx.notify(); cx.notify();
} }
fn select_last( fn select_last(
&mut self, &mut self,
project: Option<&ModelHandle<Project>>, project: Option<&ModelHandle<Project>>,
style: theme::Editor,
cx: &mut ViewContext<Editor>, cx: &mut ViewContext<Editor>,
) { ) {
self.selected_item = self.matches.len() - 1; self.selected_item = self.matches.len() - 1;
self.list.scroll_to(ScrollTarget::Show(self.selected_item)); self.list.scroll_to(ScrollTarget::Show(self.selected_item));
self.attempt_resolve_selected_completion(project, cx); self.attempt_resolve_selected_completion(project, style, cx);
cx.notify(); cx.notify();
} }
fn attempt_resolve_selected_completion( fn attempt_resolve_selected_completion(
&mut self, &mut self,
project: Option<&ModelHandle<Project>>, project: Option<&ModelHandle<Project>>,
style: theme::Editor,
cx: &mut ViewContext<Editor>, cx: &mut ViewContext<Editor>,
) { ) {
let index = self.matches[self.selected_item].candidate_id; let index = self.matches[self.selected_item].candidate_id;
let Some(project) = project else { let Some(project) = project else {
return; return;
}; };
let language_registry = project.read(cx).languages().clone();
let completions = self.completions.clone(); let completions = self.completions.clone();
let completions_guard = completions.read(); let completions_guard = completions.read();
@ -1008,16 +1018,27 @@ impl CompletionsMenu {
return; return;
} }
// TODO: Do on background
cx.spawn(|this, mut cx| async move { cx.spawn(|this, mut cx| async move {
let request = server.request::<lsp::request::ResolveCompletionItem>(completion); let request = server.request::<lsp::request::ResolveCompletionItem>(completion);
let Some(completion_item) = request.await.log_err() else { let Some(completion_item) = request.await.log_err() else {
return; return;
}; };
if completion_item.documentation.is_some() { if let Some(lsp_documentation) = completion_item.documentation {
let documentation = language::prepare_completion_documentation(
&lsp_documentation,
&language_registry,
None, // TODO: Try to reasonably work out which language the completion is for
&style,
);
let mut completions = completions.write(); let mut completions = completions.write();
completions[index].lsp_completion.documentation = completion_item.documentation; let completion = &mut completions[index];
completion.documentation = documentation;
completion.lsp_completion.documentation = Some(lsp_documentation);
drop(completions); drop(completions);
_ = this.update(&mut cx, |_, cx| cx.notify()); _ = this.update(&mut cx, |_, cx| cx.notify());
} }
}) })
@ -1069,7 +1090,7 @@ impl CompletionsMenu {
let completions = completions.read(); let completions = completions.read();
for (ix, mat) in matches[range].iter().enumerate() { for (ix, mat) in matches[range].iter().enumerate() {
let completion = &completions[mat.candidate_id]; let completion = &completions[mat.candidate_id];
let documentation = &completion.lsp_completion.documentation; let documentation = &completion.documentation;
let item_ix = start_ix + ix; let item_ix = start_ix + ix;
items.push( items.push(
@ -1100,7 +1121,9 @@ impl CompletionsMenu {
), ),
); );
if let Some(lsp::Documentation::String(text)) = documentation { if let Some(language::Documentation::SingleLine(text)) =
documentation
{
Flex::row() Flex::row()
.with_child(completion_label) .with_child(completion_label)
.with_children((|| { .with_children((|| {
@ -1183,39 +1206,18 @@ impl CompletionsMenu {
let mat = &self.matches[selected_item]; let mat = &self.matches[selected_item];
let completions = self.completions.read(); let completions = self.completions.read();
let completion = &completions[mat.candidate_id]; let completion = &completions[mat.candidate_id];
let documentation = &completion.lsp_completion.documentation; let documentation = &completion.documentation;
if let Some(lsp::Documentation::MarkupContent(content)) = documentation { match documentation {
let registry = editor Some(language::Documentation::MultiLinePlainText(text)) => {
.project Some(Text::new(text.clone(), style.text.clone()))
.as_ref() }
.unwrap()
.read(cx)
.languages()
.clone();
let language = self.buffer.read(cx).language().map(Arc::clone);
enum CompletionDocsMarkdown {} Some(language::Documentation::MultiLineMarkdown(parsed)) => {
Some( Some(render_parsed_markdown(parsed, &style, cx))
Flex::column() }
.scrollable::<CompletionDocsMarkdown>(0, None, cx)
.with_child(render_rendered_markdown( _ => None,
&language::markdown::render_markdown(
&content.value,
&registry,
&language,
&style.theme,
),
&style,
cx,
))
.constrained()
.with_width(alongside_docs_width)
.contained()
.with_style(alongside_docs_container_style),
)
} else {
None
} }
}) })
.contained() .contained()
@ -3333,7 +3335,11 @@ impl Editor {
None None
} else { } else {
_ = this.update(&mut cx, |editor, cx| { _ = this.update(&mut cx, |editor, cx| {
menu.attempt_resolve_selected_completion(editor.project.as_ref(), cx); menu.attempt_resolve_selected_completion(
editor.project.as_ref(),
editor.style(cx).theme,
cx,
);
}); });
Some(menu) Some(menu)
} }
@ -5509,13 +5515,16 @@ impl Editor {
return; return;
} }
if self if self.context_menu.is_some() {
.context_menu let style = self.style(cx).theme;
.as_mut() if self
.map(|menu| menu.select_last(self.project.as_ref(), cx)) .context_menu
.unwrap_or(false) .as_mut()
{ .map(|menu| menu.select_last(self.project.as_ref(), style, cx))
return; .unwrap_or(false)
{
return;
}
} }
if matches!(self.mode, EditorMode::SingleLine) { if matches!(self.mode, EditorMode::SingleLine) {
@ -5555,26 +5564,30 @@ impl Editor {
} }
pub fn context_menu_first(&mut self, _: &ContextMenuFirst, cx: &mut ViewContext<Self>) { pub fn context_menu_first(&mut self, _: &ContextMenuFirst, cx: &mut ViewContext<Self>) {
let style = self.style(cx).theme;
if let Some(context_menu) = self.context_menu.as_mut() { if let Some(context_menu) = self.context_menu.as_mut() {
context_menu.select_first(self.project.as_ref(), cx); context_menu.select_first(self.project.as_ref(), style, cx);
} }
} }
pub fn context_menu_prev(&mut self, _: &ContextMenuPrev, cx: &mut ViewContext<Self>) { pub fn context_menu_prev(&mut self, _: &ContextMenuPrev, cx: &mut ViewContext<Self>) {
let style = self.style(cx).theme;
if let Some(context_menu) = self.context_menu.as_mut() { if let Some(context_menu) = self.context_menu.as_mut() {
context_menu.select_prev(self.project.as_ref(), cx); context_menu.select_prev(self.project.as_ref(), style, cx);
} }
} }
pub fn context_menu_next(&mut self, _: &ContextMenuNext, cx: &mut ViewContext<Self>) { pub fn context_menu_next(&mut self, _: &ContextMenuNext, cx: &mut ViewContext<Self>) {
let style = self.style(cx).theme;
if let Some(context_menu) = self.context_menu.as_mut() { if let Some(context_menu) = self.context_menu.as_mut() {
context_menu.select_next(self.project.as_ref(), cx); context_menu.select_next(self.project.as_ref(), style, cx);
} }
} }
pub fn context_menu_last(&mut self, _: &ContextMenuLast, cx: &mut ViewContext<Self>) { pub fn context_menu_last(&mut self, _: &ContextMenuLast, cx: &mut ViewContext<Self>) {
let style = self.style(cx).theme;
if let Some(context_menu) = self.context_menu.as_mut() { if let Some(context_menu) = self.context_menu.as_mut() {
context_menu.select_last(self.project.as_ref(), cx); context_menu.select_last(self.project.as_ref(), style, cx);
} }
} }

View file

@ -13,7 +13,7 @@ use gpui::{
AnyElement, AppContext, CursorRegion, Element, ModelHandle, MouseRegion, Task, ViewContext, AnyElement, AppContext, CursorRegion, Element, ModelHandle, MouseRegion, Task, ViewContext,
}; };
use language::{ use language::{
markdown::{self, RenderedRegion}, markdown::{self, ParsedRegion},
Bias, DiagnosticEntry, DiagnosticSeverity, Language, LanguageRegistry, Bias, DiagnosticEntry, DiagnosticSeverity, Language, LanguageRegistry,
}; };
use project::{HoverBlock, HoverBlockKind, InlayHintLabelPart, Project}; use project::{HoverBlock, HoverBlockKind, InlayHintLabelPart, Project};
@ -367,9 +367,9 @@ fn render_blocks(
theme_id: usize, theme_id: usize,
blocks: &[HoverBlock], blocks: &[HoverBlock],
language_registry: &Arc<LanguageRegistry>, language_registry: &Arc<LanguageRegistry>,
language: &Option<Arc<Language>>, language: Option<Arc<Language>>,
style: &EditorStyle, style: &EditorStyle,
) -> RenderedInfo { ) -> ParsedInfo {
let mut text = String::new(); let mut text = String::new();
let mut highlights = Vec::new(); let mut highlights = Vec::new();
let mut region_ranges = Vec::new(); let mut region_ranges = Vec::new();
@ -382,10 +382,10 @@ fn render_blocks(
text.push_str(&block.text); text.push_str(&block.text);
} }
HoverBlockKind::Markdown => markdown::render_markdown_block( HoverBlockKind::Markdown => markdown::parse_markdown_block(
&block.text, &block.text,
language_registry, language_registry,
language, language.clone(),
style, style,
&mut text, &mut text,
&mut highlights, &mut highlights,
@ -399,7 +399,7 @@ fn render_blocks(
.now_or_never() .now_or_never()
.and_then(Result::ok) .and_then(Result::ok)
{ {
markdown::render_code( markdown::highlight_code(
&mut text, &mut text,
&mut highlights, &mut highlights,
&block.text, &block.text,
@ -413,7 +413,7 @@ fn render_blocks(
} }
} }
RenderedInfo { ParsedInfo {
theme_id, theme_id,
text: text.trim().to_string(), text: text.trim().to_string(),
highlights, highlights,
@ -482,16 +482,16 @@ pub struct InfoPopover {
symbol_range: DocumentRange, symbol_range: DocumentRange,
pub blocks: Vec<HoverBlock>, pub blocks: Vec<HoverBlock>,
language: Option<Arc<Language>>, language: Option<Arc<Language>>,
rendered_content: Option<RenderedInfo>, rendered_content: Option<ParsedInfo>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct RenderedInfo { struct ParsedInfo {
theme_id: usize, theme_id: usize,
text: String, text: String,
highlights: Vec<(Range<usize>, HighlightStyle)>, highlights: Vec<(Range<usize>, HighlightStyle)>,
region_ranges: Vec<Range<usize>>, region_ranges: Vec<Range<usize>>,
regions: Vec<RenderedRegion>, regions: Vec<ParsedRegion>,
} }
impl InfoPopover { impl InfoPopover {
@ -511,7 +511,7 @@ impl InfoPopover {
style.theme_id, style.theme_id,
&self.blocks, &self.blocks,
self.project.read(cx).languages(), self.project.read(cx).languages(),
&self.language, self.language.clone(),
style, style,
) )
}); });
@ -877,7 +877,7 @@ mod tests {
); );
let style = editor.style(cx); let style = editor.style(cx);
let rendered = render_blocks(0, &blocks, &Default::default(), &None, &style); let rendered = render_blocks(0, &blocks, &Default::default(), None, &style);
assert_eq!( assert_eq!(
rendered.text, rendered.text,
code_str.trim(), code_str.trim(),
@ -1069,7 +1069,7 @@ mod tests {
expected_styles, expected_styles,
} in &rows[0..] } in &rows[0..]
{ {
let rendered = render_blocks(0, &blocks, &Default::default(), &None, &style); let rendered = render_blocks(0, &blocks, &Default::default(), None, &style);
let (expected_text, ranges) = marked_text_ranges(expected_marked_text, false); let (expected_text, ranges) = marked_text_ranges(expected_marked_text, false);
let expected_highlights = ranges let expected_highlights = ranges

View file

@ -1,12 +1,13 @@
pub use crate::{ pub use crate::{
diagnostic_set::DiagnosticSet, diagnostic_set::DiagnosticSet,
highlight_map::{HighlightId, HighlightMap}, highlight_map::{HighlightId, HighlightMap},
markdown::RenderedMarkdown, markdown::ParsedMarkdown,
proto, BracketPair, Grammar, Language, LanguageConfig, LanguageRegistry, PLAIN_TEXT, proto, BracketPair, Grammar, Language, LanguageConfig, LanguageRegistry, PLAIN_TEXT,
}; };
use crate::{ use crate::{
diagnostic_set::{DiagnosticEntry, DiagnosticGroup}, diagnostic_set::{DiagnosticEntry, DiagnosticGroup},
language_settings::{language_settings, LanguageSettings}, language_settings::{language_settings, LanguageSettings},
markdown,
outline::OutlineItem, outline::OutlineItem,
syntax_map::{ syntax_map::{
SyntaxLayerInfo, SyntaxMap, SyntaxMapCapture, SyntaxMapCaptures, SyntaxMapMatches, SyntaxLayerInfo, SyntaxMap, SyntaxMapCapture, SyntaxMapCaptures, SyntaxMapMatches,
@ -144,12 +145,51 @@ pub struct Diagnostic {
pub is_unnecessary: bool, pub is_unnecessary: bool,
} }
pub fn prepare_completion_documentation(
documentation: &lsp::Documentation,
language_registry: &Arc<LanguageRegistry>,
language: Option<Arc<Language>>,
style: &theme::Editor,
) -> Option<Documentation> {
match documentation {
lsp::Documentation::String(text) => {
if text.lines().count() <= 1 {
Some(Documentation::SingleLine(text.clone()))
} else {
Some(Documentation::MultiLinePlainText(text.clone()))
}
}
lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
lsp::MarkupKind::PlainText => {
if value.lines().count() <= 1 {
Some(Documentation::SingleLine(value.clone()))
} else {
Some(Documentation::MultiLinePlainText(value.clone()))
}
}
lsp::MarkupKind::Markdown => {
let parsed = markdown::parse_markdown(value, language_registry, language, style);
Some(Documentation::MultiLineMarkdown(parsed))
}
},
}
}
#[derive(Clone, Debug)]
pub enum Documentation {
SingleLine(String),
MultiLinePlainText(String),
MultiLineMarkdown(ParsedMarkdown),
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Completion { pub struct Completion {
pub old_range: Range<Anchor>, pub old_range: Range<Anchor>,
pub new_text: String, pub new_text: String,
pub label: CodeLabel, pub label: CodeLabel,
pub alongside_documentation: Option<RenderedMarkdown>, pub documentation: Option<Documentation>,
pub server_id: LanguageServerId, pub server_id: LanguageServerId,
pub lsp_completion: lsp::CompletionItem, pub lsp_completion: lsp::CompletionItem,
} }

View file

@ -7,31 +7,31 @@ use gpui::fonts::{HighlightStyle, Underline, Weight};
use pulldown_cmark::{CodeBlockKind, Event, Options, Parser, Tag}; use pulldown_cmark::{CodeBlockKind, Event, Options, Parser, Tag};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct RenderedMarkdown { pub struct ParsedMarkdown {
pub text: String, pub text: String,
pub highlights: Vec<(Range<usize>, HighlightStyle)>, pub highlights: Vec<(Range<usize>, HighlightStyle)>,
pub region_ranges: Vec<Range<usize>>, pub region_ranges: Vec<Range<usize>>,
pub regions: Vec<RenderedRegion>, pub regions: Vec<ParsedRegion>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct RenderedRegion { pub struct ParsedRegion {
pub code: bool, pub code: bool,
pub link_url: Option<String>, pub link_url: Option<String>,
} }
pub fn render_markdown( pub fn parse_markdown(
markdown: &str, markdown: &str,
language_registry: &Arc<LanguageRegistry>, language_registry: &Arc<LanguageRegistry>,
language: &Option<Arc<Language>>, language: Option<Arc<Language>>,
style: &theme::Editor, style: &theme::Editor,
) -> RenderedMarkdown { ) -> ParsedMarkdown {
let mut text = String::new(); let mut text = String::new();
let mut highlights = Vec::new(); let mut highlights = Vec::new();
let mut region_ranges = Vec::new(); let mut region_ranges = Vec::new();
let mut regions = Vec::new(); let mut regions = Vec::new();
render_markdown_block( parse_markdown_block(
markdown, markdown,
language_registry, language_registry,
language, language,
@ -42,7 +42,7 @@ pub fn render_markdown(
&mut regions, &mut regions,
); );
RenderedMarkdown { ParsedMarkdown {
text, text,
highlights, highlights,
region_ranges, region_ranges,
@ -50,15 +50,15 @@ pub fn render_markdown(
} }
} }
pub fn render_markdown_block( pub fn parse_markdown_block(
markdown: &str, markdown: &str,
language_registry: &Arc<LanguageRegistry>, language_registry: &Arc<LanguageRegistry>,
language: &Option<Arc<Language>>, language: Option<Arc<Language>>,
style: &theme::Editor, style: &theme::Editor,
text: &mut String, text: &mut String,
highlights: &mut Vec<(Range<usize>, HighlightStyle)>, highlights: &mut Vec<(Range<usize>, HighlightStyle)>,
region_ranges: &mut Vec<Range<usize>>, region_ranges: &mut Vec<Range<usize>>,
regions: &mut Vec<RenderedRegion>, regions: &mut Vec<ParsedRegion>,
) { ) {
let mut bold_depth = 0; let mut bold_depth = 0;
let mut italic_depth = 0; let mut italic_depth = 0;
@ -71,7 +71,7 @@ pub fn render_markdown_block(
match event { match event {
Event::Text(t) => { Event::Text(t) => {
if let Some(language) = &current_language { if let Some(language) = &current_language {
render_code(text, highlights, t.as_ref(), language, style); highlight_code(text, highlights, t.as_ref(), language, style);
} else { } else {
text.push_str(t.as_ref()); text.push_str(t.as_ref());
@ -84,7 +84,7 @@ pub fn render_markdown_block(
} }
if let Some(link_url) = link_url.clone() { if let Some(link_url) = link_url.clone() {
region_ranges.push(prev_len..text.len()); region_ranges.push(prev_len..text.len());
regions.push(RenderedRegion { regions.push(ParsedRegion {
link_url: Some(link_url), link_url: Some(link_url),
code: false, code: false,
}); });
@ -124,7 +124,7 @@ pub fn render_markdown_block(
}, },
)); ));
} }
regions.push(RenderedRegion { regions.push(ParsedRegion {
code: true, code: true,
link_url: link_url.clone(), link_url: link_url.clone(),
}); });
@ -202,7 +202,7 @@ pub fn render_markdown_block(
} }
} }
pub fn render_code( pub fn highlight_code(
text: &mut String, text: &mut String,
highlights: &mut Vec<(Range<usize>, HighlightStyle)>, highlights: &mut Vec<(Range<usize>, HighlightStyle)>,
content: &str, content: &str,

View file

@ -482,7 +482,7 @@ pub async fn deserialize_completion(
lsp_completion.filter_text.as_deref(), lsp_completion.filter_text.as_deref(),
) )
}), }),
alongside_documentation: None, documentation: None,
server_id: LanguageServerId(completion.server_id as usize), server_id: LanguageServerId(completion.server_id as usize),
lsp_completion, lsp_completion,
}) })

View file

@ -1470,7 +1470,7 @@ impl LspCommand for GetCompletions {
lsp_completion.filter_text.as_deref(), lsp_completion.filter_text.as_deref(),
) )
}), }),
alongside_documentation: None, documentation: None,
server_id, server_id,
lsp_completion, lsp_completion,
} }