mirror of
https://github.com/oxalica/nil.git
synced 2025-12-23 09:19:49 +00:00
Show docs for builtin completions
This commit is contained in:
parent
cf182a8ca4
commit
c361e61da0
4 changed files with 70 additions and 10 deletions
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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\" ]`.\
|
||||
"
|
||||
),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue