Initial protocol check commit

This commit is contained in:
Kirill Bulatov 2023-05-30 16:41:57 +03:00
parent 1ae5261024
commit 8a3b515f56
4 changed files with 234 additions and 2 deletions

View file

@ -2151,6 +2151,10 @@ impl Editor {
} }
} }
if let Some(hints_task) = this.request_inlay_hints(cx) {
hints_task.detach_and_log_err(cx);
}
if had_active_copilot_suggestion { if had_active_copilot_suggestion {
this.refresh_copilot_suggestions(true, cx); this.refresh_copilot_suggestions(true, cx);
if !this.has_active_copilot_suggestion(cx) { if !this.has_active_copilot_suggestion(cx) {
@ -2577,6 +2581,27 @@ impl Editor {
} }
} }
// TODO kb proper inlay hints handling
fn request_inlay_hints(&self, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
let project = self.project.as_ref()?;
let position = self.selections.newest_anchor().head();
let (buffer, _) = self
.buffer
.read(cx)
.text_anchor_for_position(position.clone(), cx)?;
let end = buffer.read(cx).len();
let inlay_hints_task = project.update(cx, |project, cx| {
project.inlay_hints(buffer.clone(), 0..end, cx)
});
Some(cx.spawn(|_, _| async move {
let inlay_hints = inlay_hints_task.await?;
dbg!(inlay_hints);
Ok(())
}))
}
fn trigger_on_type_formatting( fn trigger_on_type_formatting(
&self, &self,
input: String, input: String,

View file

@ -388,6 +388,9 @@ impl LanguageServer {
resolve_support: None, resolve_support: None,
..WorkspaceSymbolClientCapabilities::default() ..WorkspaceSymbolClientCapabilities::default()
}), }),
inlay_hint: Some(InlayHintWorkspaceClientCapabilities {
refresh_support: Default::default(),
}),
..Default::default() ..Default::default()
}), }),
text_document: Some(TextDocumentClientCapabilities { text_document: Some(TextDocumentClientCapabilities {
@ -429,6 +432,11 @@ impl LanguageServer {
content_format: Some(vec![MarkupKind::Markdown]), content_format: Some(vec![MarkupKind::Markdown]),
..Default::default() ..Default::default()
}), }),
// TODO kb add the resolution at least
inlay_hint: Some(InlayHintClientCapabilities {
resolve_support: None,
dynamic_registration: Some(false),
}),
..Default::default() ..Default::default()
}), }),
experimental: Some(json!({ experimental: Some(json!({

View file

@ -1,6 +1,7 @@
use crate::{ use crate::{
DocumentHighlight, Hover, HoverBlock, HoverBlockKind, Location, LocationLink, Project, DocumentHighlight, Hover, HoverBlock, HoverBlockKind, InlayHint, InlayHintLabel,
ProjectTransaction, InlayHintLabelPart, InlayHintLabelPartTooltip, InlayHintTooltip, Location, LocationLink,
MarkupContent, Project, ProjectTransaction,
}; };
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use async_trait::async_trait; use async_trait::async_trait;
@ -126,6 +127,10 @@ pub(crate) struct OnTypeFormatting {
pub push_to_history: bool, pub push_to_history: bool,
} }
pub(crate) struct InlayHints {
pub range: Range<Anchor>,
}
pub(crate) struct FormattingOptions { pub(crate) struct FormattingOptions {
tab_size: u32, tab_size: u32,
} }
@ -1780,3 +1785,147 @@ impl LspCommand for OnTypeFormatting {
message.buffer_id message.buffer_id
} }
} }
#[async_trait(?Send)]
impl LspCommand for InlayHints {
type Response = Vec<InlayHint>;
type LspRequest = lsp::InlayHintRequest;
type ProtoRequest = proto::OnTypeFormatting;
fn check_capabilities(&self, server_capabilities: &lsp::ServerCapabilities) -> bool {
let Some(inlay_hint_provider) = &server_capabilities.inlay_hint_provider else { return false };
match inlay_hint_provider {
lsp::OneOf::Left(enabled) => *enabled,
lsp::OneOf::Right(inlay_hint_capabilities) => match inlay_hint_capabilities {
lsp::InlayHintServerCapabilities::Options(_) => true,
// TODO kb there could be dynamic registrations, resolve options
lsp::InlayHintServerCapabilities::RegistrationOptions(_) => false,
},
}
}
fn to_lsp(
&self,
path: &Path,
buffer: &Buffer,
_: &Arc<LanguageServer>,
_: &AppContext,
) -> lsp::InlayHintParams {
lsp::InlayHintParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::from_file_path(path).unwrap(),
},
range: range_to_lsp(self.range.to_point_utf16(buffer)),
work_done_progress_params: Default::default(),
}
}
async fn response_from_lsp(
self,
message: Option<Vec<lsp::InlayHint>>,
_: ModelHandle<Project>,
buffer: ModelHandle<Buffer>,
_: LanguageServerId,
cx: AsyncAppContext,
) -> Result<Vec<InlayHint>> {
cx.read(|cx| {
let origin_buffer = buffer.read(cx);
Ok(message
.unwrap_or_default()
.into_iter()
.map(|lsp_hint| InlayHint {
position: origin_buffer.anchor_after(
origin_buffer
.clip_point_utf16(point_from_lsp(lsp_hint.position), Bias::Left),
),
label: match lsp_hint.label {
lsp::InlayHintLabel::String(s) => InlayHintLabel::String(s),
lsp::InlayHintLabel::LabelParts(lsp_parts) => InlayHintLabel::LabelParts(
lsp_parts
.into_iter()
.map(|label_part| InlayHintLabelPart {
value: label_part.value,
tooltip: label_part.tooltip.map(|tooltip| match tooltip {
lsp::InlayHintLabelPartTooltip::String(s) => {
InlayHintLabelPartTooltip::String(s)
}
lsp::InlayHintLabelPartTooltip::MarkupContent(
markup_content,
) => InlayHintLabelPartTooltip::MarkupContent(
MarkupContent {
kind: format!("{:?}", markup_content.kind),
value: markup_content.value,
},
),
}),
location: label_part.location.map(|lsp_location| {
let target_start = origin_buffer.clip_point_utf16(
point_from_lsp(lsp_location.range.start),
Bias::Left,
);
let target_end = origin_buffer.clip_point_utf16(
point_from_lsp(lsp_location.range.end),
Bias::Left,
);
Location {
buffer: buffer.clone(),
range: origin_buffer.anchor_after(target_start)
..origin_buffer.anchor_before(target_end),
}
}),
})
.collect(),
),
},
kind: lsp_hint.kind.map(|kind| format!("{kind:?}")),
tooltip: lsp_hint.tooltip.map(|tooltip| match tooltip {
lsp::InlayHintTooltip::String(s) => InlayHintTooltip::String(s),
lsp::InlayHintTooltip::MarkupContent(markup_content) => {
InlayHintTooltip::MarkupContent(MarkupContent {
kind: format!("{:?}", markup_content.kind),
value: markup_content.value,
})
}
}),
})
.collect())
})
}
fn to_proto(&self, _: u64, _: &Buffer) -> proto::OnTypeFormatting {
todo!("TODO kb")
}
async fn from_proto(
_: proto::OnTypeFormatting,
_: ModelHandle<Project>,
_: ModelHandle<Buffer>,
_: AsyncAppContext,
) -> Result<Self> {
todo!("TODO kb")
}
fn response_to_proto(
_: Vec<InlayHint>,
_: &mut Project,
_: PeerId,
_: &clock::Global,
_: &mut AppContext,
) -> proto::OnTypeFormattingResponse {
todo!("TODO kb")
}
async fn response_from_proto(
self,
_: proto::OnTypeFormattingResponse,
_: ModelHandle<Project>,
_: ModelHandle<Buffer>,
_: AsyncAppContext,
) -> Result<Vec<InlayHint>> {
todo!("TODO kb")
}
fn buffer_id_from_proto(message: &proto::OnTypeFormatting) -> u64 {
message.buffer_id
}
}

View file

@ -325,6 +325,45 @@ pub struct Location {
pub range: Range<language::Anchor>, pub range: Range<language::Anchor>,
} }
#[derive(Debug)]
pub struct InlayHint {
pub position: Anchor,
pub label: InlayHintLabel,
pub kind: Option<String>,
pub tooltip: Option<InlayHintTooltip>,
}
#[derive(Debug)]
pub enum InlayHintLabel {
String(String),
LabelParts(Vec<InlayHintLabelPart>),
}
#[derive(Debug)]
pub struct InlayHintLabelPart {
pub value: String,
pub tooltip: Option<InlayHintLabelPartTooltip>,
pub location: Option<Location>,
}
#[derive(Debug)]
pub enum InlayHintTooltip {
String(String),
MarkupContent(MarkupContent),
}
#[derive(Debug)]
pub enum InlayHintLabelPartTooltip {
String(String),
MarkupContent(MarkupContent),
}
#[derive(Debug)]
pub struct MarkupContent {
pub kind: String,
pub value: String,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct LocationLink { pub struct LocationLink {
pub origin: Option<Location>, pub origin: Option<Location>,
@ -4837,6 +4876,17 @@ impl Project {
) )
} }
pub fn inlay_hints<T: ToOffset>(
&self,
buffer_handle: ModelHandle<Buffer>,
range: Range<T>,
cx: &mut ModelContext<Self>,
) -> Task<Result<Vec<InlayHint>>> {
let buffer = buffer_handle.read(cx);
let range = buffer.anchor_before(range.start)..buffer.anchor_before(range.end);
self.request_lsp(buffer_handle, InlayHints { range }, cx)
}
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn search( pub fn search(
&self, &self,