Skip to content

Commit

Permalink
Use a trait instead of duck typing in feature API
Browse files Browse the repository at this point in the history
  • Loading branch information
pfoerster committed May 31, 2019
1 parent 65c8e29 commit 17e1646
Show file tree
Hide file tree
Showing 46 changed files with 1,231 additions and 627 deletions.
76 changes: 45 additions & 31 deletions src/completion/bibtex/entry_type.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,53 @@
use crate::completion::factory;
use crate::data::bibtex_entry_type::BIBTEX_ENTRY_TYPES;
use crate::feature::FeatureRequest;
use crate::feature::{FeatureProvider, FeatureRequest};
use crate::syntax::bibtex::BibtexDeclaration;
use crate::syntax::text::SyntaxNode;
use crate::syntax::SyntaxTree;
use futures::prelude::*;
use futures_boxed::boxed;
use lsp_types::{CompletionItem, CompletionParams};

pub struct BibtexEntryTypeCompletionProvider;
#[derive(Debug, PartialEq, Clone)]
pub struct BibtexEntryTypeCompletionProvider {
items: Vec<CompletionItem>,
}

impl BibtexEntryTypeCompletionProvider {
pub async fn execute(request: &FeatureRequest<CompletionParams>) -> Vec<CompletionItem> {
pub fn new() -> Self {
let items = BIBTEX_ENTRY_TYPES
.iter()
.map(factory::create_entry_type)
.collect();
Self { items }
}
}

impl FeatureProvider for BibtexEntryTypeCompletionProvider {
type Params = CompletionParams;
type Output = Vec<CompletionItem>;

#[boxed]
async fn execute<'a>(
&'a self,
request: &'a FeatureRequest<CompletionParams>,
) -> Vec<CompletionItem> {
if let SyntaxTree::Bibtex(tree) = &request.document.tree {
for declaration in &tree.root.children {
match declaration {
BibtexDeclaration::Preamble(preamble) => {
if preamble.ty.range().contains(request.params.position) {
return Self::generate_items();
return self.items.clone();
}
}
BibtexDeclaration::String(string) => {
if string.ty.range().contains(request.params.position) {
return Self::generate_items();
return self.items.clone();
}
}
BibtexDeclaration::Entry(entry) => {
if entry.ty.range().contains(request.params.position) {
return Self::generate_items();
return self.items.clone();
}
}
BibtexDeclaration::Comment(_) => {}
Expand All @@ -34,74 +56,66 @@ impl BibtexEntryTypeCompletionProvider {
}
Vec::new()
}

fn generate_items() -> Vec<CompletionItem> {
BIBTEX_ENTRY_TYPES
.iter()
.map(factory::create_entry_type)
.collect()
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::feature::FeatureSpec;
use crate::test_feature;
use crate::feature::{test_feature, FeatureSpec};
use lsp_types::Position;

#[test]
fn test_after_at_sign() {
let items = test_feature!(
BibtexEntryTypeCompletionProvider,
let items = test_feature(
BibtexEntryTypeCompletionProvider::new(),
FeatureSpec {
files: vec![FeatureSpec::file("foo.bib", "@"),],
files: vec![FeatureSpec::file("foo.bib", "@")],
main_file: "foo.bib",
position: Position::new(0, 1),
..FeatureSpec::default()
}
},
);
assert_eq!(items.len() > 0, true);
}

#[test]
fn test_inside_entry() {
let items = test_feature!(
BibtexEntryTypeCompletionProvider,
let items = test_feature(
BibtexEntryTypeCompletionProvider::new(),
FeatureSpec {
files: vec![FeatureSpec::file("foo.bib", "@article{foo,}"),],
files: vec![FeatureSpec::file("foo.bib", "@article{foo,}")],
main_file: "foo.bib",
position: Position::new(0, 11),
..FeatureSpec::default()
}
},
);
assert_eq!(items.len() == 0, true);
}

#[test]
fn test_inside_comments() {
let items = test_feature!(
BibtexEntryTypeCompletionProvider,
let items = test_feature(
BibtexEntryTypeCompletionProvider::new(),
FeatureSpec {
files: vec![FeatureSpec::file("foo.bib", "foo"),],
files: vec![FeatureSpec::file("foo.bib", "foo")],
main_file: "foo.bib",
position: Position::new(0, 2),
..FeatureSpec::default()
}
},
);
assert_eq!(items.len() == 0, true);
}

#[test]
fn test_latex() {
let items = test_feature!(
BibtexEntryTypeCompletionProvider,
let items = test_feature(
BibtexEntryTypeCompletionProvider::new(),
FeatureSpec {
files: vec![FeatureSpec::file("foo.tex", "@"),],
files: vec![FeatureSpec::file("foo.tex", "@")],
main_file: "foo.tex",
position: Position::new(0, 1),
..FeatureSpec::default()
}
},
);
assert_eq!(items.len() == 0, true);
}
Expand Down
86 changes: 50 additions & 36 deletions src/completion/bibtex/field_name.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,52 @@
use crate::completion::factory;
use crate::data::bibtex_field::BIBTEX_FIELDS;
use crate::feature::FeatureRequest;
use crate::feature::{FeatureProvider, FeatureRequest};
use crate::syntax::bibtex::BibtexNode;
use crate::syntax::text::SyntaxNode;
use crate::syntax::SyntaxTree;
use futures::prelude::*;
use futures_boxed::boxed;
use lsp_types::{CompletionItem, CompletionParams};

pub struct BibtexFieldNameCompletionProvider;
#[derive(Debug, PartialEq, Clone)]
pub struct BibtexFieldNameCompletionProvider {
items: Vec<CompletionItem>,
}

impl BibtexFieldNameCompletionProvider {
pub async fn execute(request: &FeatureRequest<CompletionParams>) -> Vec<CompletionItem> {
pub fn new() -> Self {
let items = BIBTEX_FIELDS
.iter()
.map(|field| factory::create_field_name(field))
.collect();
Self { items }
}
}

impl FeatureProvider for BibtexFieldNameCompletionProvider {
type Params = CompletionParams;
type Output = Vec<CompletionItem>;

#[boxed]
async fn execute<'a>(
&'a self,
request: &'a FeatureRequest<CompletionParams>,
) -> Vec<CompletionItem> {
if let SyntaxTree::Bibtex(tree) = &request.document.tree {
match tree.find(request.params.position).last() {
Some(BibtexNode::Field(field)) => {
if field.name.range().contains(request.params.position) {
return Self::generate_items();
return self.items.clone();
}
}
Some(BibtexNode::Entry(entry)) => {
if !entry.is_comment() && !entry.ty.range().contains(request.params.position) {
if let Some(key) = &entry.key {
if !key.range().contains(request.params.position) {
return Self::generate_items();
return self.items.clone();
}
} else {
return Self::generate_items();
return self.items.clone();
}
}
}
Expand All @@ -33,91 +55,83 @@ impl BibtexFieldNameCompletionProvider {
}
Vec::new()
}

fn generate_items() -> Vec<CompletionItem> {
BIBTEX_FIELDS
.iter()
.map(|field| factory::create_field_name(field))
.collect()
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::feature::FeatureSpec;
use crate::test_feature;
use crate::feature::{test_feature, FeatureSpec};
use lsp_types::Position;

#[test]
fn test_inside_first_field() {
let items = test_feature!(
BibtexFieldNameCompletionProvider,
let items = test_feature(
BibtexFieldNameCompletionProvider::new(),
FeatureSpec {
files: vec![FeatureSpec::file("foo.bib", "@article{foo,\nbar}"),],
files: vec![FeatureSpec::file("foo.bib", "@article{foo,\nbar}")],
main_file: "foo.bib",
position: Position::new(1, 1),
..FeatureSpec::default()
}
},
);
assert_eq!(items.len() > 0, true);
}

#[test]
fn test_inside_second_field() {
let items = test_feature!(
BibtexFieldNameCompletionProvider,
let items = test_feature(
BibtexFieldNameCompletionProvider::new(),
FeatureSpec {
files: vec![FeatureSpec::file(
"foo.bib",
"@article{foo, bar = {baz}, qux}"
),],
"@article{foo, bar = {baz}, qux}",
)],
main_file: "foo.bib",
position: Position::new(0, 27),
..FeatureSpec::default()
}
},
);
assert_eq!(items.len() > 0, true);
}

#[test]
fn test_inside_entry() {
let items = test_feature!(
BibtexFieldNameCompletionProvider,
let items = test_feature(
BibtexFieldNameCompletionProvider::new(),
FeatureSpec {
files: vec![FeatureSpec::file("foo.bib", "@article{foo, \n}"),],
files: vec![FeatureSpec::file("foo.bib", "@article{foo, \n}")],
main_file: "foo.bib",
position: Position::new(1, 0),
..FeatureSpec::default()
}
},
);
assert_eq!(items.len() > 0, true);
}

#[test]
fn test_inside_content() {
let items = test_feature!(
BibtexFieldNameCompletionProvider,
let items = test_feature(
BibtexFieldNameCompletionProvider::new(),
FeatureSpec {
files: vec![FeatureSpec::file("foo.bib", "@article{foo,\nbar = {baz}}"),],
files: vec![FeatureSpec::file("foo.bib", "@article{foo,\nbar = {baz}}")],
main_file: "foo.bib",
position: Position::new(1, 7),
..FeatureSpec::default()
}
},
);
assert_eq!(items.len() == 0, true);
}

#[test]
fn test_inside_entry_type() {
let items = test_feature!(
BibtexFieldNameCompletionProvider,
let items = test_feature(
BibtexFieldNameCompletionProvider::new(),
FeatureSpec {
files: vec![FeatureSpec::file("foo.bib", "@article{foo,}"),],
files: vec![FeatureSpec::file("foo.bib", "@article{foo,}")],
main_file: "foo.bib",
position: Position::new(0, 3),
..FeatureSpec::default()
}
},
);
assert_eq!(items.len() == 0, true);
}
Expand Down
Loading

0 comments on commit 17e1646

Please sign in to comment.