diff options
| author | DanielGavin <danielgavin5@hotmail.com> | 2021-03-12 16:31:09 +0100 |
|---|---|---|
| committer | DanielGavin <danielgavin5@hotmail.com> | 2021-03-12 16:31:09 +0100 |
| commit | 00ccd7e03e17dac40efb9b34a048d968dd77c218 (patch) | |
| tree | 24e9e8d9743bc3e98b63183d1f976b11ab6d93d2 /src/server/documents.odin | |
| parent | baf86e02a2c45170d58ab828a13f52361129b255 (diff) | |
ran odinfmt on project
Diffstat (limited to 'src/server/documents.odin')
| -rw-r--r-- | src/server/documents.odin | 638 |
1 files changed, 304 insertions, 334 deletions
diff --git a/src/server/documents.odin b/src/server/documents.odin index dd4ef85..ab8b54d 100644 --- a/src/server/documents.odin +++ b/src/server/documents.odin @@ -15,454 +15,424 @@ import "intrinsics" import "shared:common" ParserError :: struct { - message: string, - line: int, - column: int, - file: string, - offset: int, -}; - + message: string, + line: int, + column: int, + file: string, + offset: int, +} Package :: struct { - name: string, //the entire absolute path to the directory - base: string, -}; + name: string, //the entire absolute path to the directory + base: string, +} Document :: struct { - uri: common.Uri, - text: [] u8, - used_text: int, //allow for the text to be reallocated with more data than needed - client_owned: bool, - diagnosed_errors: bool, - ast: ast.File, - imports: [] Package, - package_name: string, - allocator: ^common.Scratch_Allocator, //because does not support freeing I use arena allocators for each document - operating_on: int, //atomic -}; + uri: common.Uri, + text: []u8, + used_text: int, //allow for the text to be reallocated with more data than needed + client_owned: bool, + diagnosed_errors: bool, + ast: ast.File, + imports: []Package, + package_name: string, + allocator: ^common.Scratch_Allocator, //because does not support freeing I use arena allocators for each document + operating_on: int, //atomic +} DocumentStorage :: struct { - documents: map [string] Document, - free_allocators: [dynamic] ^common.Scratch_Allocator, -}; + documents: map[string]Document, + free_allocators: [dynamic]^common.Scratch_Allocator, +} document_storage: DocumentStorage; -document_storage_shutdown :: proc() { +document_storage_shutdown :: proc () { - for k, v in document_storage.documents { - delete(k); - } + for k, v in document_storage.documents { + delete(k); + } - for alloc in document_storage.free_allocators { - common.scratch_allocator_destroy(alloc); - free(alloc); - } + for alloc in document_storage.free_allocators { + common.scratch_allocator_destroy(alloc); + free(alloc); + } - delete(document_storage.free_allocators); - delete(document_storage.documents); + delete(document_storage.free_allocators); + delete(document_storage.documents); } -document_get_allocator :: proc() -> ^common.Scratch_Allocator { - - if len(document_storage.free_allocators) > 0 { - return pop(&document_storage.free_allocators); - } - - else { - allocator := new(common.Scratch_Allocator); - common.scratch_allocator_init(allocator, mem.megabytes(1)); - return allocator; - } +document_get_allocator :: proc () -> ^common.Scratch_Allocator { + if len(document_storage.free_allocators) > 0 { + return pop(&document_storage.free_allocators); + } else { + allocator := new(common.Scratch_Allocator); + common.scratch_allocator_init(allocator, mem.megabytes(1)); + return allocator; + } } -document_free_allocator :: proc(allocator: ^common.Scratch_Allocator) { - append(&document_storage.free_allocators, allocator); +document_free_allocator :: proc (allocator: ^common.Scratch_Allocator) { + append(&document_storage.free_allocators, allocator); } -document_get :: proc(uri_string: string) -> ^Document { +document_get :: proc (uri_string: string) -> ^Document { - uri, parsed_ok := common.parse_uri(uri_string, context.temp_allocator); + uri, parsed_ok := common.parse_uri(uri_string, context.temp_allocator); - if !parsed_ok { - return nil; - } + if !parsed_ok { + return nil; + } - document := &document_storage.documents[uri.path]; + document := &document_storage.documents[uri.path]; - if document == nil { - return nil; - } + if document == nil { + return nil; + } - intrinsics.atomic_add(&document.operating_on, 1); + intrinsics.atomic_add(&document.operating_on, 1); - return document; + return document; } -document_release :: proc(document: ^Document) { - - if document != nil { - intrinsics.atomic_sub(&document.operating_on, 1); - } +document_release :: proc (document: ^Document) { + if document != nil { + intrinsics.atomic_sub(&document.operating_on, 1); + } } /* - Client opens a document with transferred text + Client opens a document with transferred text */ -document_open :: proc(uri_string: string, text: string, config: ^common.Config, writer: ^Writer) -> common.Error { - - uri, parsed_ok := common.parse_uri(uri_string, context.allocator); - - log.infof("document_open: %v", uri_string); - - if !parsed_ok { - log.error("Failed to parse uri"); - return .ParseError; - } - - if document := &document_storage.documents[uri.path]; document != nil { +document_open :: proc (uri_string: string, text: string, config: ^common.Config, writer: ^Writer) -> common.Error { - if document.client_owned { - log.errorf("Client called open on an already open document: %v ", document.uri.path); - return .InvalidRequest; - } + uri, parsed_ok := common.parse_uri(uri_string, context.allocator); - document.uri = uri; - document.client_owned = true; - document.text = transmute([] u8)text; - document.used_text = len(document.text); - document.allocator = document_get_allocator(); + log.infof("document_open: %v", uri_string); - if err := document_refresh(document, config, writer); err != .None { - return err; - } + if !parsed_ok { + log.error("Failed to parse uri"); + return .ParseError; + } - } + if document := &document_storage.documents[uri.path]; document != nil { - else { + if document.client_owned { + log.errorf("Client called open on an already open document: %v ", document.uri.path); + return .InvalidRequest; + } - document := Document { - uri = uri, - text = transmute([] u8)text, - client_owned = true, - used_text = len(text), - allocator = document_get_allocator(), - }; + document.uri = uri; + document.client_owned = true; + document.text = transmute([]u8)text; + document.used_text = len(document.text); + document.allocator = document_get_allocator(); - if err := document_refresh(&document, config, writer); err != .None { - return err; - } + if err := document_refresh(document, config, writer); err != .None { + return err; + } + } else { - document_storage.documents[strings.clone(uri.path)] = document; - } + document := Document { + uri = uri, + text = transmute([]u8)text, + client_owned = true, + used_text = len(text), + allocator = document_get_allocator(), + }; + if err := document_refresh(&document, config, writer); err != .None { + return err; + } + document_storage.documents[strings.clone(uri.path)] = document; + } - //hmm feels like odin needs some ownership semantic - delete(uri_string); + //hmm feels like odin needs some ownership semantic + delete(uri_string); - return .None; + return .None; } /* - Function that applies changes to the given document through incremental syncronization - */ -document_apply_changes :: proc(uri_string: string, changes: [dynamic] TextDocumentContentChangeEvent, config: ^common.Config, writer: ^Writer) -> common.Error { - - uri, parsed_ok := common.parse_uri(uri_string, context.temp_allocator); - - if !parsed_ok { - return .ParseError; - } - - document := &document_storage.documents[uri.path]; - - if !document.client_owned { - log.errorf("Client called change on an document not opened: %v ", document.uri.path); - return .InvalidRequest; - } - - for change in changes { - - //for some reason sublime doesn't seem to care even if i tell it to do incremental sync - if range, ok := change.range.(common.Range); ok { - - absolute_range, ok := common.get_absolute_range(range, document.text[:document.used_text]); + Function that applies changes to the given document through incremental syncronization +*/ +document_apply_changes :: proc (uri_string: string, changes: [dynamic]TextDocumentContentChangeEvent, config: ^common.Config, writer: ^Writer) -> common.Error { - if !ok { - return .ParseError; - } + uri, parsed_ok := common.parse_uri(uri_string, context.temp_allocator); - //lower bound is before the change - lower := document.text[:absolute_range.start]; + if !parsed_ok { + return .ParseError; + } - //new change between lower and upper - middle := change.text; + document := &document_storage.documents[uri.path]; - //upper bound is after the change - upper := document.text[absolute_range.end:document.used_text]; + if !document.client_owned { + log.errorf("Client called change on an document not opened: %v ", document.uri.path); + return .InvalidRequest; + } - //total new size needed - document.used_text = len(lower) + len(change.text) + len(upper); + for change in changes { - //Reduce the amount of allocation by allocating more memory than needed - if document.used_text > len(document.text) { - new_text := make([]u8, document.used_text * 2); + //for some reason sublime doesn't seem to care even if i tell it to do incremental sync + if range, ok := change.range.(common.Range); ok { - //join the 3 splices into the text - copy(new_text, lower); - copy(new_text[len(lower):], middle); - copy(new_text[len(lower)+len(middle):], upper); + absolute_range, ok := common.get_absolute_range(range, document.text[:document.used_text]); - delete(document.text); + if !ok { + return .ParseError; + } - document.text = new_text; - } + //lower bound is before the change + lower := document.text[:absolute_range.start]; - else { - //order matters here, we need to make sure we swap the data already in the text before the middle - copy(document.text, lower); - copy(document.text[len(lower)+len(middle):], upper); - copy(document.text[len(lower):], middle); - } + //new change between lower and upper + middle := change.text; - } + //upper bound is after the change + upper := document.text[absolute_range.end:document.used_text]; - else { + //total new size needed + document.used_text = len(lower) + len(change.text) + len(upper); - document.used_text = len(change.text); + //Reduce the amount of allocation by allocating more memory than needed + if document.used_text > len(document.text) { + new_text := make([]u8, document.used_text * 2); - if document.used_text > len(document.text) { - new_text := make([]u8, document.used_text * 2); - copy(new_text, change.text); - delete(document.text); - document.text = new_text; - } + //join the 3 splices into the text + copy(new_text, lower); + copy(new_text[len(lower):], middle); + copy(new_text[len(lower) + len(middle):], upper); - else { - copy(document.text, change.text); - } + delete(document.text); - } + document.text = new_text; + } else { + //order matters here, we need to make sure we swap the data already in the text before the middle + copy(document.text, lower); + copy(document.text[len(lower) + len(middle):], upper); + copy(document.text[len(lower):], middle); + } + } else { + document.used_text = len(change.text); - } + if document.used_text > len(document.text) { + new_text := make([]u8, document.used_text * 2); + copy(new_text, change.text); + delete(document.text); + document.text = new_text; + } else { + copy(document.text, change.text); + } + } + } - //log.info(string(document.text[:document.used_text])); + //log.info(string(document.text[:document.used_text])); - return document_refresh(document, config, writer); + return document_refresh(document, config, writer); } -document_close :: proc(uri_string: string) -> common.Error { +document_close :: proc (uri_string: string) -> common.Error { - log.infof("document_close: %v", uri_string); + log.infof("document_close: %v", uri_string); - uri, parsed_ok := common.parse_uri(uri_string, context.temp_allocator); + uri, parsed_ok := common.parse_uri(uri_string, context.temp_allocator); - if !parsed_ok { - return .ParseError; - } + if !parsed_ok { + return .ParseError; + } - document := &document_storage.documents[uri.path]; + document := &document_storage.documents[uri.path]; - if document == nil || !document.client_owned { - log.errorf("Client called close on a document that was never opened: %v ", document.uri.path); - return .InvalidRequest; - } + if document == nil || !document.client_owned { + log.errorf("Client called close on a document that was never opened: %v ", document.uri.path); + return .InvalidRequest; + } - free_all(common.scratch_allocator(document.allocator)); - document_free_allocator(document.allocator); - document.allocator = nil; + free_all(common.scratch_allocator(document.allocator)); + document_free_allocator(document.allocator); + document.allocator = nil; - document.client_owned = false; + document.client_owned = false; - common.delete_uri(document.uri); + common.delete_uri(document.uri); - delete(document.text); + delete(document.text); - document.used_text = 0; + document.used_text = 0; - return .None; + return .None; } - - -document_refresh :: proc(document: ^Document, config: ^common.Config, writer: ^Writer) -> common.Error { - - errors, ok := parse_document(document, config); - - if !ok { - return .ParseError; - } - - if writer != nil && len(errors) > 0 { - document.diagnosed_errors = true; - - params := NotificationPublishDiagnosticsParams { - uri = document.uri.uri, - diagnostics = make([] Diagnostic, len(errors), context.temp_allocator), - }; - - for error, i in errors { - - params.diagnostics[i] = Diagnostic { - range = common.Range { - start = common.Position { - line = error.line - 1, - character = 0, - }, - end = common.Position { - line = error.line, - character = 0, - }, - }, - severity = DiagnosticSeverity.Error, - code = "test", - message = error.message, - }; - - } - - notifaction := Notification { - jsonrpc = "2.0", - method = "textDocument/publishDiagnostics", - params = params, - }; - - send_notification(notifaction, writer); - - } - - if writer != nil && len(errors) == 0 { - - //send empty diagnosis to remove the clients errors - if document.diagnosed_errors { - - notifaction := Notification { - jsonrpc = "2.0", - method = "textDocument/publishDiagnostics", - - params = NotificationPublishDiagnosticsParams { - uri = document.uri.uri, - diagnostics = make([] Diagnostic, len(errors), context.temp_allocator), - }, - }; - - document.diagnosed_errors = false; - - send_notification(notifaction, writer); - } - - } - - return .None; +document_refresh :: proc (document: ^Document, config: ^common.Config, writer: ^Writer) -> common.Error { + + errors, ok := parse_document(document, config); + + if !ok { + return .ParseError; + } + + if writer != nil && len(errors) > 0 { + document.diagnosed_errors = true; + + params := NotificationPublishDiagnosticsParams { + uri = document.uri.uri, + diagnostics = make([]Diagnostic, len(errors), context.temp_allocator), + }; + + for error, i in errors { + + params.diagnostics[i] = Diagnostic { + range = common.Range { + start = common.Position { + line = error.line - 1, + character = 0, + }, + end = common.Position { + line = error.line, + character = 0, + }, + }, + severity = DiagnosticSeverity.Error, + code = "test", + message = error.message, + }; + } + + notifaction := Notification { + jsonrpc = "2.0", + method = "textDocument/publishDiagnostics", + params = params, + }; + + send_notification(notifaction, writer); + } + + if writer != nil && len(errors) == 0 { + + //send empty diagnosis to remove the clients errors + if document.diagnosed_errors { + + notifaction := Notification { + jsonrpc = "2.0", + method = "textDocument/publishDiagnostics", + params = NotificationPublishDiagnosticsParams { + uri = document.uri.uri, + diagnostics = make([]Diagnostic, len(errors), context.temp_allocator), + }, + }; + + document.diagnosed_errors = false; + + send_notification(notifaction, writer); + } + } + + return .None; } -current_errors: [dynamic] ParserError; +current_errors: [dynamic]ParserError; -parser_error_handler :: proc(pos: tokenizer.Pos, msg: string, args: ..any) { - error := ParserError { line = pos.line, column = pos.column, file = pos.file, - offset = pos.offset, message = fmt.tprintf(msg, ..args) }; - append(¤t_errors, error); +parser_error_handler :: proc (pos: tokenizer.Pos, msg: string, args: ..any) { + error := ParserError { + line = pos.line,column = pos.column,file = pos.file, + offset = pos.offset,message = fmt.tprintf(msg, ..args), + }; + append(¤t_errors, error); } -parser_warning_handler :: proc(pos: tokenizer.Pos, msg: string, args: ..any) { - +parser_warning_handler :: proc (pos: tokenizer.Pos, msg: string, args: ..any) { } -parse_document :: proc(document: ^Document, config: ^common.Config) -> ([] ParserError, bool) { +parse_document :: proc (document: ^Document, config: ^common.Config) -> ([]ParserError, bool) { - p := parser.Parser { - err = parser_error_handler, + p := parser.Parser { + err = parser_error_handler, warn = parser_warning_handler, }; - current_errors = make([dynamic] ParserError, context.temp_allocator); - - free_all(common.scratch_allocator(document.allocator)); - - context.allocator = common.scratch_allocator(document.allocator); + current_errors = make([dynamic]ParserError, context.temp_allocator); - //have to cheat the parser since it really wants to parse an entire package with the new changes... - pkg := new(ast.Package); - pkg.kind = .Normal; - pkg.fullpath = document.uri.path; + free_all(common.scratch_allocator(document.allocator)); - document.ast = ast.File { - fullpath = document.uri.path, - src = document.text[:document.used_text], - pkg = pkg, - }; + context.allocator = common.scratch_allocator(document.allocator); - parser.parse_file(&p, &document.ast); + //have to cheat the parser since it really wants to parse an entire package with the new changes... + pkg := new(ast.Package); + pkg.kind = .Normal; + pkg.fullpath = document.uri.path; - imports := make([dynamic]Package); - document.package_name = strings.to_lower(path.dir(document.uri.path, context.temp_allocator)); + document.ast = ast.File { + fullpath = document.uri.path, + src = document.text[:document.used_text], + pkg = pkg, + }; - for imp, index in document.ast.imports { + parser.parse_file(&p, &document.ast); - if i := strings.index(imp.fullpath, "\""); i == -1 { - continue; - } + imports := make([dynamic]Package); + document.package_name = strings.to_lower(path.dir(document.uri.path, context.temp_allocator)); - //collection specified - if i := strings.index(imp.fullpath, ":"); i != -1 && i > 1 && i < len(imp.fullpath) - 1 { + for imp, index in document.ast.imports { - if len(imp.fullpath) < 2 { - continue; - } + if i := strings.index(imp.fullpath, "\""); i == -1 { + continue; + } - collection := imp.fullpath[1:i]; - p := imp.fullpath[i+1:len(imp.fullpath)-1]; + //collection specified + if i := strings.index(imp.fullpath, ":"); i != -1 && i > 1 && i < len(imp.fullpath) - 1 { - dir, ok := config.collections[collection]; + if len(imp.fullpath) < 2 { + continue; + } - if !ok { - continue; - } + collection := imp.fullpath[1:i]; + p := imp.fullpath[i + 1:len(imp.fullpath) - 1]; - import_: Package; - import_.name = strings.clone(path.join(elems = {strings.to_lower(dir, context.temp_allocator), p}, allocator = context.temp_allocator)); + dir, ok := config.collections[collection]; - if imp.name.text != "" { - import_.base = imp.name.text; - } + if !ok { + continue; + } - else { - import_.base = path.base(import_.name, false); - } + import_: Package; + import_.name = strings.clone(path.join(elems = {strings.to_lower(dir, context.temp_allocator), p}, allocator = context.temp_allocator)); - append(&imports, import_); - } + if imp.name.text != "" { + import_.base = imp.name.text; + } else { + import_.base = path.base(import_.name, false); + } - //relative - else { + append(&imports, import_); + } else - if len(imp.fullpath) < 2 { - continue; - } + //relative + { - import_: Package; - import_.name = path.join(elems = {document.package_name, imp.fullpath[1:len(imp.fullpath)-1]}, allocator = context.temp_allocator); - import_.name = path.clean(import_.name); + if len(imp.fullpath) < 2 { + continue; + } - if imp.name.text != "" { - import_.base = imp.name.text; - } + import_: Package; + import_.name = path.join(elems = {document.package_name, imp.fullpath[1:len(imp.fullpath) - 1]}, allocator = context.temp_allocator); + import_.name = path.clean(import_.name); - else { - import_.base = path.base(import_.name, false); - } + if imp.name.text != "" { + import_.base = imp.name.text; + } else { + import_.base = path.base(import_.name, false); + } - append(&imports, import_); - } + append(&imports, import_); + } + } - } + document.imports = imports[:]; - document.imports = imports[:]; - - return current_errors[:], true; -} + return current_errors[:], true; +}
\ No newline at end of file |