Add documentation to hovers
This commit is contained in:
parent
6dccab8b12
commit
dcb4e76a40
@ -193,6 +193,33 @@ impl AnalysisState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_documentation(&mut self, token_idx: usize, documentation: Option<String>) {
|
||||||
|
if let Some(documentation) = documentation {
|
||||||
|
if let Some(token) = self.map.get_mut(&token_idx) {
|
||||||
|
if let Some(hover) = &mut token.hover {
|
||||||
|
hover.documentation = Some(documentation);
|
||||||
|
} else {
|
||||||
|
token.hover = Some(Hover {
|
||||||
|
documentation: Some(documentation),
|
||||||
|
kind: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.map.insert(
|
||||||
|
token_idx,
|
||||||
|
SemanticToken {
|
||||||
|
hover: Some(Hover {
|
||||||
|
documentation: Some(documentation),
|
||||||
|
kind: None,
|
||||||
|
}),
|
||||||
|
autocomplete: Vec::new(),
|
||||||
|
symbol: Default::default(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_symbol(&mut self, idx: usize, symbol: SymbolId) {
|
pub fn set_symbol(&mut self, idx: usize, symbol: SymbolId) {
|
||||||
self.symbol_to_token.insert(symbol, idx);
|
self.symbol_to_token.insert(symbol, idx);
|
||||||
if let Some(token) = self.map.get_mut(&idx) {
|
if let Some(token) = self.map.get_mut(&idx) {
|
||||||
@ -246,8 +273,8 @@ pub struct AnalysisScope<'a> {
|
|||||||
tokens: &'a Vec<FullToken>,
|
tokens: &'a Vec<FullToken>,
|
||||||
variables: HashMap<String, SymbolId>,
|
variables: HashMap<String, SymbolId>,
|
||||||
types: HashMap<TypeKind, (SourceModuleId, SymbolId)>,
|
types: HashMap<TypeKind, (SourceModuleId, SymbolId)>,
|
||||||
functions: HashMap<String, (SourceModuleId, SymbolId)>,
|
functions: HashMap<String, (SourceModuleId, SymbolId, Option<String>)>,
|
||||||
associated_functions: HashMap<(TypeKind, String), (SourceModuleId, SymbolId)>,
|
associated_functions: HashMap<(TypeKind, String), (SourceModuleId, SymbolId, Option<String>)>,
|
||||||
map: &'a StateMap,
|
map: &'a StateMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -646,9 +673,10 @@ pub fn analyze_context(
|
|||||||
if source_id != module.module_id {
|
if source_id != module.module_id {
|
||||||
if let Some(state) = map.get(&source_id) {
|
if let Some(state) = map.get(&source_id) {
|
||||||
if let Some(symbol) = state.associated_functions.get(&(ty.clone(), function.name.clone())) {
|
if let Some(symbol) = state.associated_functions.get(&(ty.clone(), function.name.clone())) {
|
||||||
scope
|
scope.associated_functions.insert(
|
||||||
.associated_functions
|
(ty.clone(), function.name.clone()),
|
||||||
.insert((ty.clone(), function.name.clone()), (source_id, *symbol));
|
(source_id, *symbol, function.documentation.clone()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@ -664,9 +692,10 @@ pub fn analyze_context(
|
|||||||
.state
|
.state
|
||||||
.associated_functions
|
.associated_functions
|
||||||
.insert((ty.clone(), function.name.clone()), symbol);
|
.insert((ty.clone(), function.name.clone()), symbol);
|
||||||
scope
|
scope.associated_functions.insert(
|
||||||
.associated_functions
|
(ty.clone(), function.name.clone()),
|
||||||
.insert((ty.clone(), function.name.clone()), (module.module_id, symbol));
|
(module.module_id, symbol, function.documentation.clone()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (_, function) in &module.associated_functions {
|
for (_, function) in &module.associated_functions {
|
||||||
@ -692,7 +721,10 @@ pub fn analyze_context(
|
|||||||
if source_id != module.module_id {
|
if source_id != module.module_id {
|
||||||
if let Some(state) = map.get(&source_id) {
|
if let Some(state) = map.get(&source_id) {
|
||||||
if let Some(symbol) = state.functions.get(&function.name) {
|
if let Some(symbol) = state.functions.get(&function.name) {
|
||||||
scope.functions.insert(function.name.clone(), (source_id, *symbol));
|
scope.functions.insert(
|
||||||
|
function.name.clone(),
|
||||||
|
(source_id, *symbol, function.documentation.clone()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@ -702,7 +734,7 @@ pub fn analyze_context(
|
|||||||
scope.state.init_hover(
|
scope.state.init_hover(
|
||||||
&function.signature(),
|
&function.signature(),
|
||||||
Some(HoverKind::Type(function.return_type.clone())),
|
Some(HoverKind::Type(function.return_type.clone())),
|
||||||
None,
|
function.documentation.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let idx = scope
|
let idx = scope
|
||||||
@ -711,9 +743,10 @@ pub fn analyze_context(
|
|||||||
let function_symbol = scope.state.new_symbol(idx, SemanticKind::Function);
|
let function_symbol = scope.state.new_symbol(idx, SemanticKind::Function);
|
||||||
scope.state.set_symbol(idx, function_symbol);
|
scope.state.set_symbol(idx, function_symbol);
|
||||||
scope.state.functions.insert(function.name.clone(), function_symbol);
|
scope.state.functions.insert(function.name.clone(), function_symbol);
|
||||||
scope
|
scope.functions.insert(
|
||||||
.functions
|
function.name.clone(),
|
||||||
.insert(function.name.clone(), (module.module_id, function_symbol));
|
(module.module_id, function_symbol, function.documentation.clone()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for function in &module.functions {
|
for function in &module.functions {
|
||||||
@ -777,10 +810,12 @@ pub fn analyze_context(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let symbol = if let Some((source_id, symbol_id)) = scope.functions.get(&import_name) {
|
let symbol = if let Some((source_id, symbol_id, doc)) = scope.functions.get(&import_name) {
|
||||||
scope
|
let symbol_id = scope
|
||||||
.state
|
.state
|
||||||
.new_symbol(import_idx, SemanticKind::Reference(*source_id, *symbol_id))
|
.new_symbol(import_idx, SemanticKind::Reference(*source_id, *symbol_id));
|
||||||
|
scope.state.set_documentation(import_idx, doc.clone());
|
||||||
|
symbol_id
|
||||||
} else if let Some(module_source) = scope.map.values().find(|s| s.module_name == *module_name) {
|
} else if let Some(module_source) = scope.map.values().find(|s| s.module_name == *module_name) {
|
||||||
if let Some((source_id, symbol_id)) = scope.types.get(&TypeKind::CustomType(CustomTypeKey(
|
if let Some((source_id, symbol_id)) = scope.types.get(&TypeKind::CustomType(CustomTypeKey(
|
||||||
import_name.clone(),
|
import_name.clone(),
|
||||||
@ -1070,10 +1105,12 @@ pub fn analyze_expr(
|
|||||||
let idx = scope
|
let idx = scope
|
||||||
.token_idx(&meta, |t| matches!(t, Token::Identifier(_)))
|
.token_idx(&meta, |t| matches!(t, Token::Identifier(_)))
|
||||||
.unwrap_or(meta.range.end);
|
.unwrap_or(meta.range.end);
|
||||||
let symbol = if let Some((module_id, symbol_id)) = scope.functions.get(name) {
|
let symbol = if let Some((module_id, symbol_id, doc)) = scope.functions.get(name) {
|
||||||
scope
|
let symbol = scope
|
||||||
.state
|
.state
|
||||||
.new_symbol(idx, SemanticKind::Reference(*module_id, *symbol_id))
|
.new_symbol(idx, SemanticKind::Reference(*module_id, *symbol_id));
|
||||||
|
scope.state.set_documentation(idx, doc.clone());
|
||||||
|
symbol
|
||||||
} else {
|
} else {
|
||||||
scope.state.new_symbol(idx, SemanticKind::Function)
|
scope.state.new_symbol(idx, SemanticKind::Function)
|
||||||
};
|
};
|
||||||
@ -1106,12 +1143,14 @@ pub fn analyze_expr(
|
|||||||
let fn_idx = scope
|
let fn_idx = scope
|
||||||
.token_idx(&meta, |t| matches!(t, Token::Identifier(_)))
|
.token_idx(&meta, |t| matches!(t, Token::Identifier(_)))
|
||||||
.unwrap_or(meta.range.end);
|
.unwrap_or(meta.range.end);
|
||||||
let fn_symbol = if let Some((module_id, symbol_id)) =
|
let fn_symbol = if let Some((module_id, symbol_id, doc)) =
|
||||||
scope.associated_functions.get(&(invoked_ty.clone(), name.clone()))
|
scope.associated_functions.get(&(invoked_ty.clone(), name.clone()))
|
||||||
{
|
{
|
||||||
scope
|
let symbol = scope
|
||||||
.state
|
.state
|
||||||
.new_symbol(fn_idx, SemanticKind::Reference(*module_id, *symbol_id))
|
.new_symbol(fn_idx, SemanticKind::Reference(*module_id, *symbol_id));
|
||||||
|
scope.state.set_documentation(fn_idx, doc.clone());
|
||||||
|
symbol
|
||||||
} else {
|
} else {
|
||||||
scope.state.new_symbol(fn_idx, SemanticKind::Function)
|
scope.state.new_symbol(fn_idx, SemanticKind::Function)
|
||||||
};
|
};
|
||||||
|
@ -12,12 +12,12 @@ use tower_lsp::lsp_types::{
|
|||||||
self, CompletionItem, CompletionItemKind, CompletionOptions, CompletionParams, CompletionResponse, Diagnostic,
|
self, CompletionItem, CompletionItemKind, CompletionOptions, CompletionParams, CompletionResponse, Diagnostic,
|
||||||
DiagnosticSeverity, DidChangeTextDocumentParams, DidOpenTextDocumentParams, DidSaveTextDocumentParams,
|
DiagnosticSeverity, DidChangeTextDocumentParams, DidOpenTextDocumentParams, DidSaveTextDocumentParams,
|
||||||
DocumentFilter, GotoDefinitionParams, GotoDefinitionResponse, Hover, HoverContents, HoverParams,
|
DocumentFilter, GotoDefinitionParams, GotoDefinitionResponse, Hover, HoverContents, HoverParams,
|
||||||
HoverProviderCapability, InitializeParams, InitializeResult, InitializedParams, Location, MarkupContent,
|
HoverProviderCapability, InitializeParams, InitializeResult, InitializedParams, Location, MarkedString,
|
||||||
MarkupKind, MessageType, OneOf, Range, ReferenceParams, RenameParams, SemanticToken, SemanticTokensLegend,
|
MarkupContent, MarkupKind, MessageType, OneOf, Range, ReferenceParams, RenameParams, SemanticToken,
|
||||||
SemanticTokensOptions, SemanticTokensParams, SemanticTokensResult, SemanticTokensServerCapabilities,
|
SemanticTokensLegend, SemanticTokensOptions, SemanticTokensParams, SemanticTokensResult,
|
||||||
ServerCapabilities, TextDocumentItem, TextDocumentRegistrationOptions, TextDocumentSyncCapability,
|
SemanticTokensServerCapabilities, ServerCapabilities, TextDocumentItem, TextDocumentRegistrationOptions,
|
||||||
TextDocumentSyncKind, TextDocumentSyncOptions, TextDocumentSyncSaveOptions, TextEdit, Url, WorkspaceEdit,
|
TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions, TextDocumentSyncSaveOptions, TextEdit,
|
||||||
WorkspaceFoldersServerCapabilities, WorkspaceServerCapabilities,
|
Url, WorkspaceEdit, WorkspaceFoldersServerCapabilities, WorkspaceServerCapabilities,
|
||||||
};
|
};
|
||||||
use tower_lsp::{Client, LanguageServer, LspService, Server, jsonrpc};
|
use tower_lsp::{Client, LanguageServer, LspService, Server, jsonrpc};
|
||||||
|
|
||||||
@ -199,7 +199,7 @@ impl LanguageServer for Backend {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let (range, ty) = if let Some((idx, token)) = token {
|
let (range, ty, documentation) = if let Some((idx, token)) = token {
|
||||||
if let Some(analysis) = self.analysis.get(&path).unwrap().state.map.get(&idx) {
|
if let Some(analysis) = self.analysis.get(&path).unwrap().state.map.get(&idx) {
|
||||||
let start = token.position;
|
let start = token.position;
|
||||||
let end = token.position.add(token.token.len() as u32);
|
let end = token.position.add(token.token.len() as u32);
|
||||||
@ -216,7 +216,9 @@ impl LanguageServer for Backend {
|
|||||||
if let Some(hover) = analysis.hover.clone() {
|
if let Some(hover) = analysis.hover.clone() {
|
||||||
if let Some(kind) = hover.kind {
|
if let Some(kind) = hover.kind {
|
||||||
match kind {
|
match kind {
|
||||||
analysis::HoverKind::Type(type_kind) => (Some(range), format!("{}", type_kind)),
|
analysis::HoverKind::Type(type_kind) => {
|
||||||
|
(Some(range), format!("{}", type_kind), hover.documentation)
|
||||||
|
}
|
||||||
analysis::HoverKind::Function(name, function_params, return_type) => (
|
analysis::HoverKind::Function(name, function_params, return_type) => (
|
||||||
Some(range),
|
Some(range),
|
||||||
format!(
|
format!(
|
||||||
@ -229,25 +231,30 @@ impl LanguageServer for Backend {
|
|||||||
.join(", "),
|
.join(", "),
|
||||||
return_type
|
return_type
|
||||||
),
|
),
|
||||||
|
hover.documentation,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
(Some(range), String::from("No type"))
|
(Some(range), String::from("No type"), hover.documentation)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
(Some(range), String::from("No hover"))
|
(Some(range), String::from("No hover"), None)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
(None, String::from("no type"))
|
(None, String::from("no type"), None)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
(None, String::from("no token"))
|
(None, String::from("no token"), None)
|
||||||
};
|
};
|
||||||
|
|
||||||
let contents = HoverContents::Markup(MarkupContent {
|
let contents = if let Some(doc) = documentation {
|
||||||
kind: MarkupKind::Markdown,
|
HoverContents::Array(vec![MarkedString::String(doc), MarkedString::String(format!("`{ty}`"))])
|
||||||
value: format!("`{ty}`"),
|
} else {
|
||||||
});
|
HoverContents::Markup(MarkupContent {
|
||||||
|
kind: MarkupKind::Markdown,
|
||||||
|
value: format!("`{ty}`"),
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
Ok(Some(Hover { contents, range }))
|
Ok(Some(Hover { contents, range }))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user