Skip to content

Commit

Permalink
Add basic code completion
Browse files Browse the repository at this point in the history
  • Loading branch information
VonTum committed Mar 3, 2024
1 parent 8454bd5 commit e5ae820
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 9 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,10 @@ The main goals of the language are roughly listed below:
- [x] Hover type information
- [x] Go to definition
- [x] File Creation/Deletion/Rename
- [ ] Show last generation value
- [x] Show last generation value
- [ ] Find all references
- [ ] Highlighting
- [ ] Code completion
- [x] Code completion
- [ ] Per-Line Resource Utilization Reporting

### Code Generation
Expand Down
40 changes: 39 additions & 1 deletion src/dev_aid/lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use lsp_server::{Connection, Message, Response};
use lsp_types::notification::Notification;

use crate::{
arena_alloc::ArenaVector, ast::{IdentifierType, Module}, errors::{CompileError, ErrorCollector, ErrorLevel}, file_position::{LineCol, FileText, Span}, flattening::FlatID, instantiation::{SubModuleOrWire, CALCULATE_LATENCY_LATER}, linker::{FileData, FileUUID, FileUUIDMarker, Linker, LocationInfo}, parser::perform_full_semantic_parse, walk_name_color
arena_alloc::ArenaVector, ast::{IdentifierType, Module}, errors::{CompileError, ErrorCollector, ErrorLevel}, file_position::{FileText, LineCol, Span}, flattening::{FlatID, Instruction}, instantiation::{SubModuleOrWire, CALCULATE_LATENCY_LATER}, linker::{FileData, FileUUID, FileUUIDMarker, Linker, LocationInfo}, parser::perform_full_semantic_parse, walk_name_color
};

use super::syntax_highlighting::IDEIdentifierType;
Expand Down Expand Up @@ -103,6 +103,7 @@ pub fn lsp_main(port : u16, debug : bool) -> Result<(), Box<dyn Error + Sync + S
range: Some(false), // Don't support ranges yet
full: Some(SemanticTokensFullOptions::Bool(true)), // TODO: Support delta updating for faster syntax highlighting, just do whole file for now
})),
completion_provider : Some(CompletionOptions{resolve_provider : Some(true), ..Default::default()}),
/*workspace: Some(WorkspaceClientCapabilities{
did_change_watched_files : Some(DidChangeWatchedFilesClientCapabilities{
Expand Down Expand Up @@ -329,6 +330,31 @@ fn gather_hover_infos(md: &Module, id: FlatID, is_generative : bool, file_cache:
});
}

fn gather_completions(linker : &Linker, file_id : FileUUID, position : usize) -> Vec<CompletionItem> {
let mut result = Vec::new();

use crate::linker::Linkable;
for (_, m) in &linker.modules {
result.push(CompletionItem{label : m.link_info.name.to_string(), kind : Some(CompletionItemKind::FUNCTION), ..Default::default()});

if m.link_info.file == file_id && m.link_info.span.contains_pos(position) {
for (_id, v) in &m.flattened.instructions {
if let Instruction::Declaration(d) = v {
result.push(CompletionItem{label : d.name.to_string(), kind : Some(CompletionItemKind::VARIABLE), ..Default::default()});
}
}
}
}
for (_, c) in &linker.constants {
result.push(CompletionItem{label : c.get_name().to_string(), kind : Some(CompletionItemKind::CONSTANT), ..Default::default()});
}
for (_, t) in &linker.types {
result.push(CompletionItem{label : t.get_name().to_string(), kind : Some(CompletionItemKind::STRUCT), ..Default::default()});
}

result
}

fn handle_request(method : &str, params : serde_json::Value, file_cache : &mut LoadedFileCache, debug : bool) -> Result<serde_json::Value, serde_json::Error> {
match method {
request::HoverRequest::METHOD => {
Expand Down Expand Up @@ -424,6 +450,18 @@ fn handle_request(method : &str, params : serde_json::Value, file_cache : &mut L
todo!()
}*/
request::Completion::METHOD => {
let params : CompletionParams = serde_json::from_value(params).expect("JSON Encoding Error while parsing params");
println!("Completion");

let uuid = file_cache.ensure_contains_file(&params.text_document_position.text_document.uri);

let file_data = &file_cache.linker.files[uuid];

let position = file_data.file_text.linecol_to_byte(from_position(params.text_document_position.position));

serde_json::to_value(&CompletionResponse::Array(gather_completions(&file_cache.linker, uuid, position)))
}
req => {
println!("Other request: {req:?}");
Ok(serde_json::Value::Null)
Expand Down
2 changes: 1 addition & 1 deletion src/file_position.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub struct Span(usize, usize);
impl Span {
/// Only really used for having a span with the maximum size.
pub const MAX_POSSIBLE_SPAN : Span = Span(0, usize::MAX);
pub const INVALID_SPAN : Span = Span(usize::MAX, usize::MAX);

pub fn new_from_byte_range(rng : Range<usize>) -> Span {
assert!(rng.end >= rng.start);
Expand Down Expand Up @@ -130,7 +131,6 @@ impl FileText {
lines_start_at.push(idx + 1);
}
}
//lines_start_at.push(file_text.len());

FileText{file_text, lines_start_at}
}
Expand Down
8 changes: 4 additions & 4 deletions src/flattening/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub struct ConnectionWrite {

#[derive(Debug)]
pub enum WriteType {
Connection{num_regs : i64, regs_span : Option<Span>},
Connection{num_regs : i64, regs_span : Span},
Initial
}

Expand Down Expand Up @@ -372,7 +372,7 @@ impl<'prev, 'inst, 'l, 'runtime> FlatteningContext<'prev, 'inst, 'l, 'runtime> {
for (field, arg_expr) in zip(inputs, args) {
let arg_read_side = self.flatten_expr(arg_expr);
let func_input_port = &submodule_local_wires.ports[field];
self.instructions.alloc(Instruction::Write(Write{write_type : WriteType::Connection{num_regs : 0, regs_span : None}, from: arg_read_side, to: ConnectionWrite{root : *func_input_port, root_span : arg_expr.1, path : Vec::new(), span : *name_expr_span, is_declared_in_this_module : self.is_declared_in_this_module}}));
self.instructions.alloc(Instruction::Write(Write{write_type : WriteType::Connection{num_regs : 0, regs_span : Span::INVALID_SPAN}, from: arg_read_side, to: ConnectionWrite{root : *func_input_port, root_span : arg_expr.1, path : Vec::new(), span : *name_expr_span, is_declared_in_this_module : self.is_declared_in_this_module}}));
}

Some((md, submodule_local_wires))
Expand Down Expand Up @@ -479,9 +479,9 @@ impl<'prev, 'inst, 'l, 'runtime> FlatteningContext<'prev, 'inst, 'l, 'runtime> {

fn flatten_assignment_modifiers(&mut self, modifiers : &AssignableExpressionModifiers) -> WriteType {
match modifiers {
&AssignableExpressionModifiers::LatencyAdding{num_regs, regs_span} => WriteType::Connection{num_regs, regs_span : Some(regs_span)},
&AssignableExpressionModifiers::LatencyAdding{num_regs, regs_span} => WriteType::Connection{num_regs, regs_span},
AssignableExpressionModifiers::Initial{initial_token : _} => WriteType::Initial,
AssignableExpressionModifiers::NoModifiers => WriteType::Connection{num_regs : 0, regs_span : None},
AssignableExpressionModifiers::NoModifiers => WriteType::Connection{num_regs : 0, regs_span : Span::INVALID_SPAN},
}
}
fn flatten_code(&mut self, code : &'l CodeBlock) {
Expand Down
2 changes: 1 addition & 1 deletion src/instantiation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> {
if num_regs >= 1 {
did_place_error = true;
let this_register_plural = if num_regs == 1 {"This register is"} else {"These registers are"};
self.errors.error_basic(regs_span.unwrap(), format!("{this_register_plural}{rest_of_message}"));
self.errors.error_basic(regs_span, format!("{this_register_plural}{rest_of_message}"));
}
}
WriteType::Initial => {unreachable!("Initial assignment can only be from compile-time constant. Cannot be part of latency loop. ")}
Expand Down

0 comments on commit e5ae820

Please sign in to comment.