diff options
| -rw-r--r-- | src/analysis.odin | 55 | ||||
| -rw-r--r-- | src/config.odin | 1 | ||||
| -rw-r--r-- | src/documents.odin | 107 | ||||
| -rw-r--r-- | src/main.odin | 5 | ||||
| -rw-r--r-- | src/requests.odin | 4 |
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; } |