mod providers; mod util; use base_db::{ data::{BibtexEntryType, BibtexFieldType}, semantics::bib, util::RenderedObject, Document, FeatureParams, }; use rowan::{TextRange, TextSize}; use util::CompletionBuilder; pub const LIMIT: usize = 50; #[derive(Debug)] pub struct CompletionParams<'a> { pub feature: FeatureParams<'a>, pub offset: TextSize, } #[derive(Debug, Default)] pub struct CompletionResult<'a> { pub items: Vec>, } #[derive(Debug, PartialEq, Eq)] pub struct CompletionItem<'a> { pub score: i32, pub range: TextRange, pub preselect: bool, pub data: CompletionItemData<'a>, } impl<'a> CompletionItem<'a> { pub fn new_simple(score: i32, range: TextRange, data: CompletionItemData<'a>) -> Self { Self { score, range, preselect: false, data, } } } #[derive(Debug, PartialEq, Eq)] pub enum CompletionItemData<'a> { Command(CommandData<'a>), CommandLikeDelimiter(&'a str, &'a str), BeginEnvironment, Citation(CitationData<'a>), Environment(EnvironmentData<'a>), GlossaryEntry(GlossaryEntryData), Label(LabelData<'a>), Color(&'a str), ColorModel(&'a str), File(String), Directory(String), Argument(ArgumentData<'a>), Package(&'a str), DocumentClass(&'a str), EntryType(EntryTypeData<'a>), Field(FieldTypeData<'a>), TikzLibrary(&'a str), } impl<'a> CompletionItemData<'a> { pub fn label<'b: 'a>(&'b self) -> &'a str { match self { Self::Command(data) => data.name, Self::CommandLikeDelimiter(left, _) => left, Self::BeginEnvironment => "begin", Self::Citation(data) => &data.entry.name.text, Self::Environment(data) => data.name, Self::GlossaryEntry(data) => &data.name, Self::Label(data) => &data.name, Self::Color(name) => name, Self::ColorModel(name) => name, Self::File(name) => name, Self::Directory(name) => name, Self::Argument(data) => data.0.name, Self::Package(name) => name, Self::DocumentClass(name) => name, Self::EntryType(data) => data.0.name, Self::Field(data) => data.0.name, Self::TikzLibrary(name) => name, } } /// Returns a number that can be used to sort the completion items further before resorting to the label. /// This is useful for making snippets more visible. pub fn sort_index(&self) -> u8 { match self { Self::Command(_) => 1, Self::CommandLikeDelimiter(_, _) => 0, Self::BeginEnvironment => 1, Self::Citation(_) => 1, Self::Environment(_) => 1, Self::GlossaryEntry(_) => 1, Self::Label(_) => 1, Self::Color(_) => 1, Self::ColorModel(_) => 1, Self::File(_) => 1, Self::Directory(_) => 1, Self::Argument(_) => 1, Self::Package(_) => 1, Self::DocumentClass(_) => 1, Self::EntryType(_) => 1, Self::Field(_) => 1, Self::TikzLibrary(_) => 1, } } } #[derive(PartialEq, Eq)] pub struct CommandData<'a> { pub name: &'a str, pub glyph: Option<&'a str>, pub image: Option<&'a str>, pub package: Option<&'a completion_data::Package<'a>>, } impl<'a> std::fmt::Debug for CommandData<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("CommandData") .field("name", &self.name) .field("package", self.package.map_or(&"", |p| &p.file_names)) .finish() } } #[derive(PartialEq, Eq)] pub struct EnvironmentData<'a> { pub name: &'a str, pub package: Option<&'a completion_data::Package<'a>>, } impl<'a> std::fmt::Debug for EnvironmentData<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("EnvironmentData") .field("name", &self.name) .field("package", self.package.map_or(&"", |p| &p.file_names)) .finish() } } #[derive(PartialEq, Eq)] pub struct ArgumentData<'a>(pub &'a completion_data::Argument<'a>); impl<'a> std::fmt::Debug for ArgumentData<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("ArgumentData").field(&self.0.name).finish() } } #[derive(Debug, PartialEq, Eq)] pub struct CitationData<'a> { pub document: &'a Document, pub entry: &'a bib::Entry, } #[derive(Debug, PartialEq, Eq)] pub struct GlossaryEntryData { pub name: String, } #[derive(Debug, PartialEq, Eq)] pub struct LabelData<'a> { pub name: &'a str, pub header: Option, pub footer: Option<&'a str>, pub object: Option>, pub keywords: String, } #[derive(PartialEq, Eq)] pub struct EntryTypeData<'a>(pub BibtexEntryType<'a>); impl<'a> std::fmt::Debug for EntryTypeData<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("EntryTypeData").field(&self.0.name).finish() } } #[derive(PartialEq, Eq)] pub struct FieldTypeData<'a>(pub BibtexFieldType<'a>); impl<'a> std::fmt::Debug for FieldTypeData<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("FieldTypeData").field(&self.0.name).finish() } } pub fn complete<'a>(params: &'a CompletionParams<'a>) -> CompletionResult<'a> { let mut builder = CompletionBuilder::from(params.feature.workspace); providers::complete_commands(params, &mut builder); providers::complete_environments(params, &mut builder); providers::complete_citations(params, &mut builder); providers::complete_acronyms(params, &mut builder); providers::complete_glossaries(params, &mut builder); providers::complete_label_references(params, &mut builder); providers::complete_label_definitions(params, &mut builder); providers::complete_colors(params, &mut builder); providers::complete_color_models(params, &mut builder); providers::complete_includes(params, &mut builder); providers::complete_arguments(params, &mut builder); providers::complete_imports(params, &mut builder); providers::complete_entry_types(params, &mut builder); providers::complete_fields(params, &mut builder); providers::complete_tikz_libraries(params, &mut builder); builder.finish() } #[cfg(test)] mod tests;