aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analysis.odin55
-rw-r--r--src/config.odin1
-rw-r--r--src/documents.odin107
-rw-r--r--src/main.odin5
-rw-r--r--src/requests.odin4
5 files changed, 155 insertions, 17 deletions
diff --git a/src/analysis.odin b/src/analysis.odin
index 8cba000..3e0fc4c 100644
--- a/src/analysis.odin
+++ b/src/analysis.odin
@@ -5,6 +5,8 @@ import "core:odin/ast"
import "core:odin/tokenizer"
import "core:fmt"
import "core:log"
+import "core:strings"
+import "core:path"
ParserError :: struct {
message: string,
@@ -22,13 +24,20 @@ ProcedureSymbol :: struct {
};
+PackageSymbol :: struct {
+
+};
+
Symbol :: union {
StructSymbol,
ProcedureSymbol,
+ PackageSymbol
};
DocumentSymbols :: struct {
+ file: ast.File,
globals: map [string] Symbol,
+ imports: [] string,
};
DocumentPositionContext :: struct {
@@ -52,10 +61,14 @@ parser_warning_handler :: proc(pos: tokenizer.Pos, msg: string, args: ..any) {
Parses and walks through the ast saving all the global symbols for the document. Local symbols are not saved
because they are determined by the position.
- Document is responsible in freeing the DocumentSymbols
+ Document is responsible in freeing the DocumentSymbols with free_document_symbols
+
+ Returns DocumentSymbols, Errors, file package name, imports processed with correct path directory
*/
-parse_document_symbols :: proc(document: ^Document) -> (DocumentSymbols, [dynamic] ParserError, bool) {
+parse_document_symbols :: proc(document: ^Document, config: ^Config) -> (DocumentSymbols, [dynamic] ParserError, string, []string, bool) {
+
+ symbols: DocumentSymbols;
p := parser.Parser {
err = parser_error_handler,
@@ -64,17 +77,47 @@ parse_document_symbols :: proc(document: ^Document) -> (DocumentSymbols, [dynami
current_errors = make([dynamic] ParserError, context.temp_allocator);
-
- ast := ast.File {
+ symbols.file = ast.File {
fullpath = document.path,
src = document.text[:document.used_text],
};
- parser.parse_file(&p, &ast);
+ parser.parse_file(&p, &symbols.file);
+
+ symbols.imports = make([]string, len(symbols.file.imports));
+
+ for imp, index in symbols.file.imports {
+
+ //collection specified
+ if i := strings.index(imp.fullpath, ":"); i != -1 {
+
+ collection := imp.fullpath[1:i];
+ p := imp.fullpath[i+1:len(imp.fullpath)-1];
- return DocumentSymbols {}, current_errors, true;
+ dir, ok := config.collections[collection];
+
+ if !ok {
+ continue;
+ }
+
+ symbols.imports[index] = path.join(allocator = context.temp_allocator, elems = {dir, p});
+
+ }
+
+ //relative
+ else {
+
+ }
+ }
+
+
+
+ return symbols, current_errors, symbols.file.pkg_name, symbols.imports, true;
}
+free_document_symbols :: proc(symbols: DocumentSymbols) {
+
+}
/*
diff --git a/src/config.odin b/src/config.odin
index 7557259..b4df050 100644
--- a/src/config.odin
+++ b/src/config.odin
@@ -4,5 +4,6 @@ Config :: struct {
workspace_folders: [dynamic] WorkspaceFolder,
completion_support_md: bool,
hover_support_md: bool,
+ collections: map [string] string,
};
diff --git a/src/documents.odin b/src/documents.odin
index ecab990..84e495c 100644
--- a/src/documents.odin
+++ b/src/documents.odin
@@ -3,6 +3,7 @@ package main
import "core:strings"
import "core:fmt"
import "core:log"
+import "core:os"
Package :: struct {
documents: [dynamic]^Document,
@@ -15,6 +16,7 @@ Document :: struct {
used_text: int, //allow for the text to be reallocated with more data than needed
client_owned: bool,
diagnosed_errors: bool,
+ symbols: DocumentSymbols,
};
DocumentStorage :: struct {
@@ -23,8 +25,46 @@ DocumentStorage :: struct {
document_storage: DocumentStorage;
+/*
+ Note(Daniel, Should there be reference counting of documents or just clear everything on workspace change?
+ You usually always need the documents that are loaded in core files, your own files, etc.)
+ */
+
+/*
+ Server opens a new document with text from filesystem
+*/
+document_new :: proc(path: string, config: ^Config) -> Error {
+
+ text, ok := os.read_entire_file(path);
+
+ cloned_path := strings.clone(path);
-document_open :: proc(uri_string: string, text: string, writer: ^Writer) -> Error {
+ if !ok {
+ return .ParseError;
+ }
+
+ document := Document {
+ uri = cloned_path,
+ path = cloned_path,
+ text = transmute([] u8)text,
+ client_owned = true,
+ used_text = len(text),
+ };
+
+ if err := document_refresh(&document, config, nil); err != .None {
+ return err;
+ }
+
+ document_storage.documents[path] = document;
+
+ return .None;
+}
+
+/*
+ Client opens a document with transferred text
+*/
+
+document_open :: proc(uri_string: string, text: string, config: ^Config, writer: ^Writer) -> Error {
uri, parsed_ok := parse_uri(uri_string);
@@ -43,11 +83,17 @@ document_open :: proc(uri_string: string, text: string, writer: ^Writer) -> Erro
delete(document.text);
}
+ if len(document.uri) > 0 {
+ delete(document.uri);
+ }
+
+ document.uri = uri.full;
+ document.path = uri.path;
document.client_owned = true;
document.text = transmute([] u8)text;
document.used_text = len(document.text);
- if err := document_refresh(document, writer); err != .None {
+ if err := document_refresh(document, config, writer); err != .None {
return err;
}
@@ -63,7 +109,7 @@ document_open :: proc(uri_string: string, text: string, writer: ^Writer) -> Erro
used_text = len(text),
};
- if err := document_refresh(&document, writer); err != .None {
+ if err := document_refresh(&document, config, writer); err != .None {
return err;
}
@@ -81,7 +127,7 @@ document_open :: proc(uri_string: string, text: string, writer: ^Writer) -> Erro
/*
Function that applies changes to the given document through incremental syncronization
*/
-document_apply_changes :: proc(uri_string: string, changes: [dynamic] TextDocumentContentChangeEvent, writer: ^Writer) -> Error {
+document_apply_changes :: proc(uri_string: string, changes: [dynamic] TextDocumentContentChangeEvent, config: ^Config, writer: ^Writer) -> Error {
uri, parsed_ok := parse_uri(uri_string, context.temp_allocator);
@@ -139,7 +185,7 @@ document_apply_changes :: proc(uri_string: string, changes: [dynamic] TextDocume
}
- return document_refresh(document, writer);
+ return document_refresh(document, config, writer);
}
document_close :: proc(uri_string: string) -> Error {
@@ -164,16 +210,19 @@ document_close :: proc(uri_string: string) -> Error {
-document_refresh :: proc(document: ^Document, writer: ^Writer) -> Error {
+document_refresh :: proc(document: ^Document, config: ^Config, writer: ^Writer) -> Error {
- document_symbols, errors, ok := parse_document_symbols(document);
+ document_symbols, errors, package_name, imports, ok := parse_document_symbols(document, config);
+
+ document.symbols = document_symbols;
if !ok {
return .ParseError;
}
- if len(errors) > 0 {
+ //right now we don't allow to writer errors out from files read from the file directory, core files, etc.
+ if writer != nil && len(errors) > 0 {
document.diagnosed_errors = true;
params := NotificationPublishDiagnosticsParams {
@@ -211,7 +260,7 @@ document_refresh :: proc(document: ^Document, writer: ^Writer) -> Error {
}
- if len(errors) == 0 {
+ if writer != nil && len(errors) == 0 {
//send empty diagnosis to remove the clients errors
if document.diagnosed_errors {
@@ -233,6 +282,46 @@ document_refresh :: proc(document: ^Document, writer: ^Writer) -> Error {
}
+
+ /*
+ go through the imports from this document and see if we need to load them into memory(not owned by client),
+ and also refresh them if needed
+ */
+ for imp in imports {
+
+ if err := document_load_package(imp, config); err != .None {
+ return err;
+ }
+
+ }
+
+
return .None;
}
+document_load_package :: proc(package_directory: string, config: ^Config) -> Error {
+
+ fd, err := os.open(package_directory);
+
+ if err != 0 {
+ return .ParseError;
+ }
+
+ files: []os.File_Info;
+ files, err = os.read_dir(fd, 100, context.temp_allocator);
+
+ for file in files {
+
+ //if we have never encountered the document
+ if _, ok := document_storage.documents[file.fullpath]; !ok {
+
+ if doc_err := document_new(file.fullpath, config); doc_err != .None {
+ return doc_err;
+ }
+
+ }
+
+ }
+
+ return .None;
+}
diff --git a/src/main.odin b/src/main.odin
index e388be5..382fd31 100644
--- a/src/main.odin
+++ b/src/main.odin
@@ -27,6 +27,11 @@ run :: proc(reader: ^Reader, writer: ^Writer) {
config: Config;
+ //temporary collections being set manually, need to get client configuration set up.
+ config.collections = make(map [string] string);
+
+ config.collections["core"] = "C:/Users/danie/OneDrive/Desktop/Computer_Science/Odin/core";
+
log.info("Starting Odin Language Server");
running = true;
diff --git a/src/requests.odin b/src/requests.odin
index 84d131c..43b96aa 100644
--- a/src/requests.odin
+++ b/src/requests.odin
@@ -272,7 +272,7 @@ notification_did_open :: proc(params: json.Value, id: RequestId, config: ^Config
return .ParseError;
}
- return document_open(open_params.textDocument.uri, open_params.textDocument.text, writer);
+ return document_open(open_params.textDocument.uri, open_params.textDocument.text, config, writer);
}
notification_did_change :: proc(params: json.Value, id: RequestId, config: ^Config, writer: ^Writer) -> Error {
@@ -289,7 +289,7 @@ notification_did_change :: proc(params: json.Value, id: RequestId, config: ^Conf
return .ParseError;
}
- document_apply_changes(change_params.textDocument.uri, change_params.contentChanges, writer);
+ document_apply_changes(change_params.textDocument.uri, change_params.contentChanges, config, writer);
return .None;
}