Skip to content

Commit

Permalink
Added autocompletion scaffold #20
Browse files Browse the repository at this point in the history
  • Loading branch information
SpontanCombust committed Aug 27, 2024
1 parent 3f35786 commit 98f8d60
Show file tree
Hide file tree
Showing 10 changed files with 184 additions and 5 deletions.
9 changes: 9 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ dyn-clone = "1.0"
rayon = "1.9"
bitmask-enum = "2.2.3"
filetime = "0.2.23"
smallvec = "1.13"
smallvec = "1.13"
lazy_static = "1.5"
4 changes: 2 additions & 2 deletions crates/core/src/ast/annotation.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use strum_macros::{EnumString, Display, AsRefStr};
use strum_macros::{AsRefStr, Display, EnumIter, EnumString};
use crate::{tokens::*, AnyNode, DebugRange, NamedSyntaxNode, SyntaxNode};
use super::*;

Expand All @@ -7,7 +7,7 @@ mod tags {
pub struct Annotation;
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, EnumString, Display, AsRefStr)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, EnumString, Display, AsRefStr, EnumIter)]
pub enum AnnotationKind {
#[strum(serialize="@addMethod")]
AddMethod,
Expand Down
4 changes: 3 additions & 1 deletion crates/core/src/attribs/functions.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use std::fmt::Debug;
use std::str::FromStr;
use strum_macros::EnumIter;

use crate::{tokens::Keyword, AnyNode, DebugRange, NamedSyntaxNode, SyntaxNode};
use super::{AccessModifier, Specifier};


#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumIter)]
pub enum FunctionFlavour {
Cleanup,
Entry,
Expand Down
5 changes: 4 additions & 1 deletion crates/core/src/attribs/specifier.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use std::str::FromStr;

use strum_macros::EnumIter;

use crate::{tokens::Keyword, AnyNode, DebugRange, NamedSyntaxNode, SyntaxNode};


#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumIter)]
pub enum Specifier {
Abstract,
Const,
Expand Down
3 changes: 3 additions & 0 deletions crates/lsp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ rayon.workspace = true
bitmask-enum.workspace = true
shrinkwraprs.workspace = true
filetime.workspace = true
strum.workspace = true
strum_macros.workspace = true
lazy_static.workspace = true
tower-lsp = "0.20.0"
tokio = { version = "1.38", features = ["macros", "rt", "rt-multi-thread", "io-std", "time"] }
fuzzy-matcher = "0.3.7"
9 changes: 9 additions & 0 deletions crates/lsp/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,15 @@ impl LanguageServer for Backend {
async fn hover(&self, params: lsp::HoverParams) -> Result<Option<lsp::Hover>> {
self.hover_impl(params).await
}


async fn completion(&self, params: lsp::CompletionParams) -> Result<Option<lsp::CompletionResponse>> {
self.completion_impl(params).await
}

async fn completion_resolve(&self, params: lsp::CompletionItem) -> Result<lsp::CompletionItem> {
self.completion_resolve_impl(params).await
}
}


Expand Down
143 changes: 143 additions & 0 deletions crates/lsp/src/providers/completion.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
use lazy_static::lazy_static;
use strum::IntoEnumIterator;
use tower_lsp::lsp_types as lsp;
use tower_lsp::jsonrpc::Result;

use witcherscript::ast::AnnotationKind;
use witcherscript::attribs::{FunctionFlavour, Specifier};
use witcherscript::tokens::Keyword;
use witcherscript_analysis::symbol_analysis::symbol_path::SymbolPathBuf;

use crate::Backend;


impl Backend {
pub async fn completion_impl(&self, params: lsp::CompletionParams) -> Result<Option<lsp::CompletionResponse>> {

Ok(None)
}

pub async fn completion_resolve_impl(&self, params: lsp::CompletionItem) -> Result<lsp::CompletionItem> {
// return the data back for now
// this will be used for displaying documentation once that is taken care of
Ok(params)
}
}


#[derive(Debug, Default, Clone, PartialEq, Eq)]
enum CompletionExpectation {
/// Default when context cannot be fully resolved or simply nothing can be suggested
#[default]
None,
/// Syntax requires a new identifier to be written
/// No suggestions should be produced in that case
NewIdentifier,
/// Valid syntax in the root of the document
Root,
/// Any expression acccessible in a given context
/// Expected type should not be taken into account at this stage
AnyExpression,
/// Cursor is placed after a dot signaling member access expression
MemberAccess {
accessor_sympath: SymbolPathBuf
},
/// Syntax expects a known type identifier
KnownTypeIdentifier,
/// Any syntax valid inside a function body
FunctionBody {
available_local_var_sympaths: Vec<SymbolPathBuf>
},
/// Any syntax valid inside class's or state's definition
ClassBody {
class_sympath: SymbolPathBuf
},
/// Any syntax valid inside struct's definition
StructBody {
struct_sympath: SymbolPathBuf
},
/// When specifically a field is expected, for example in the `default` assignment
ClassField {
class_sympath: SymbolPathBuf
}
}



trait ToCompletionItem {
fn to_completion_item(&self, text_edit_range: lsp::Range) -> lsp::CompletionItem;
}

impl ToCompletionItem for Keyword {
fn to_completion_item(&self, _text_edit_range: lsp::Range) -> lsp::CompletionItem {
lsp::CompletionItem {
label: self.as_ref().to_string(),
kind: Some(lsp::CompletionItemKind::KEYWORD),
..Default::default()
}
}
}

impl ToCompletionItem for AnnotationKind {
fn to_completion_item(&self, text_edit_range: lsp::Range) -> lsp::CompletionItem {
let mut text = self.as_ref().to_string();
if self.requires_arg() {
text += "($1)";
}

lsp::CompletionItem {
label: self.as_ref().to_string(),
kind: Some(lsp::CompletionItemKind::KEYWORD),
insert_text_format: Some(lsp::InsertTextFormat::SNIPPET),
text_edit: Some(lsp::TextEdit {
new_text: text,
range: text_edit_range
}.into()),
..Default::default()
}
}
}


lazy_static! {
static ref ROOT_KEYWORDS: Vec<Keyword> = {
let mut kws: Vec<Keyword> = Vec::new();

kws.extend(
Specifier::iter()
.map(|s| {
let k: Keyword = s.into();
k
})
);

kws.extend(
FunctionFlavour::iter()
.map(|f| {
let k: Keyword = f.into();
k
})
);

kws.extend([
Keyword::Class,
Keyword::State,
Keyword::Enum,
Keyword::Function,
Keyword::Struct,
Keyword::Var
]);

kws
};
}

fn root_completions(text_edit_range: lsp::Range) -> Vec<lsp::CompletionItem> {
let annotations = AnnotationKind::iter()
.map(|ak| ak.to_completion_item(text_edit_range.clone()));

let keywords = ROOT_KEYWORDS.iter()
.map(|k| k.to_completion_item(text_edit_range.clone()));

annotations.chain(keywords).collect()
}
8 changes: 8 additions & 0 deletions crates/lsp/src/providers/initialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,14 @@ impl Backend {
type_definition_provider: Some(lsp::TypeDefinitionProviderCapability::Simple(true)),
implementation_provider: None,
hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
completion_provider: Some(lsp::CompletionOptions {
trigger_characters: Some(vec![".".to_string()]),
resolve_provider: Some(true),
completion_item: Some(lsp::CompletionOptionsCompletionItem {
label_details_support: Some(true)
}),
..Default::default()
}),
..lsp::ServerCapabilities::default()
}
})
Expand Down
1 change: 1 addition & 0 deletions crates/lsp/src/providers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod document_symbols;
pub mod goto;
pub mod hover;
pub mod workspace_symbols;
pub mod completion;

pub mod custom;

Expand Down

0 comments on commit 98f8d60

Please sign in to comment.