Show docs for builtin completions

This commit is contained in:
oxalica 2022-09-22 18:29:55 +08:00
parent cf182a8ca4
commit c361e61da0
4 changed files with 70 additions and 10 deletions

View file

@ -1,4 +1,5 @@
use serde::Deserialize;
use std::collections::BTreeMap;
use std::path::Path;
use std::process::{Command, Stdio};
use std::{env, fs};
@ -34,6 +35,14 @@ fn main() {
.collect()
};
// Use a secret subcommand `__dump-builtins` to dump Nix builtins with documentations.
// It is introduced since Nix 2.4 in
// https://github.com/NixOS/nix/commit/0f314f3c2594e80322c675b70a61dcfda11bf423#diff-20a8b5b2a231db80eab27840bd32ac0214aa0c4e9e923e649d3d741c3da77b48R187
let builtins_dump: DumpBuiltins = Command::new("nix")
.arg("__dump-builtins")
.json()
.expect("Failed to dump builtins");
let mut phf_gen = phf_codegen::Map::<&'static str>::new();
for (name, is_global) in builtin_names.iter().zip(&global_names) {
let name = &**name;
@ -42,12 +51,15 @@ fn main() {
"true" | "false" | "null" => "Const",
_ => "Function",
};
phf_gen.entry(
name,
&format!(
"crate::Builtin {{ kind: crate::BuiltinKind::{kind}, is_global: {is_global} }}"
),
);
let summary = builtins_dump
.get(name)
.map(|b @ DumpBuiltin { args, arity, .. }| {
assert_eq!(args.len(), *arity, "Arity mismatch: {b:?}");
let args = args.iter().flat_map(|arg| [" ", arg]).collect::<String>();
format!("builtins.{name}{args}")
});
let doc = builtins_dump.get(name).map(|b| &b.doc);
phf_gen.entry(name, &format!("crate::Builtin {{ kind: crate::BuiltinKind::{kind}, is_global: {is_global}, summary: {summary:?}, doc: {doc:?} }}"));
}
let path = Path::new(&env::var("OUT_DIR").unwrap()).join("generated.expr");
@ -67,3 +79,13 @@ impl CommandExt for Command {
Ok(serde_json::from_slice(&output.stdout)?)
}
}
// Keep names sorted.
type DumpBuiltins = BTreeMap<String, DumpBuiltin>;
#[derive(Debug, Deserialize)]
struct DumpBuiltin {
args: Vec<String>,
arity: usize,
doc: String,
}

View file

@ -2,6 +2,8 @@
pub struct Builtin {
pub kind: BuiltinKind,
pub is_global: bool,
pub summary: Option<&'static str>,
pub doc: Option<&'static str>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -25,6 +27,8 @@ mod tests {
Builtin {
kind: BuiltinKind::Const,
is_global: true,
summary: None,
doc: None,
},
);
@ -33,6 +37,14 @@ mod tests {
Builtin {
kind: BuiltinKind::Function,
is_global: false,
summary: Some("builtins.attrNames set"),
doc: Some(
"\
Return the names of the attributes in the set *set* in an
alphabetically sorted list. For instance, `builtins.attrNames { y
= 1; x = \"foo\"; }` evaluates to `[ \"x\" \"y\" ]`.\
"
),
}
);
}

View file

@ -32,6 +32,10 @@ pub struct CompletionItem {
pub replace: SmolStr,
/// What item (struct, function, etc) are we completing.
pub kind: CompletionItemKind,
/// A brief summary.
pub brief: Option<String>,
/// The detailed documentation.
pub doc: Option<String>,
}
/// The type of the completion item.
@ -159,6 +163,8 @@ fn complete_expr(
.kind
.try_into()
.expect("NonRecAttrset names are not definitions"),
brief: None,
doc: None,
})
.for_each(&mut feed);
@ -171,6 +177,8 @@ fn complete_expr(
source_range,
replace: name.into(),
kind: b.kind.into(),
brief: b.summary.map(|s| s.to_owned()),
doc: b.doc.map(|s| s.to_owned()),
})
.for_each(&mut feed);
@ -212,6 +220,8 @@ fn keyword_to_completion(kw: &str, source_range: TextRange) -> CompletionItem {
source_range,
replace: kw.into(),
kind: CompletionItemKind::Keyword,
brief: None,
doc: None,
}
}

View file

@ -5,11 +5,11 @@ use ide::{
CompletionItem, CompletionItemKind, Diagnostic, FileId, FilePos, FileRange, HlRange, Severity,
TextEdit, WorkspaceEdit,
};
use lsp::SemanticToken;
use lsp_server::ErrorCode;
use lsp_types::{
self as lsp, DiagnosticRelatedInformation, DiagnosticSeverity, DiagnosticTag, Location,
Position, PrepareRenameResponse, Range, TextDocumentIdentifier, TextDocumentPositionParams,
self as lsp, DiagnosticRelatedInformation, DiagnosticSeverity, DiagnosticTag, Documentation,
Location, MarkupContent, MarkupKind, Position, PrepareRenameResponse, Range, SemanticToken,
TextDocumentIdentifier, TextDocumentPositionParams,
};
use text_size::{TextRange, TextSize};
@ -147,8 +147,24 @@ pub(crate) fn to_completion_item(line_map: &LineMap, item: CompletionItem) -> ls
range: to_range(line_map, item.source_range),
new_text: item.replace.into(),
})),
detail: item.brief,
documentation: item.doc.map(|doc| {
Documentation::MarkupContent(MarkupContent {
kind: MarkupKind::Markdown,
value: doc,
})
}),
// TODO
..Default::default()
deprecated: None,
preselect: None,
sort_text: None,
filter_text: None,
additional_text_edits: None,
command: None,
commit_characters: None,
data: None,
tags: None,
}
}