diff options
| author | DanielGavin <danielgavin5@hotmail.com> | 2020-11-03 22:40:40 +0100 |
|---|---|---|
| committer | DanielGavin <danielgavin5@hotmail.com> | 2020-11-03 22:40:40 +0100 |
| commit | 35ca720dd6fa200c70a5727507fc6e432bd1a44b (patch) | |
| tree | 6addf746aefbf1299723780183042c06a451d680 /src | |
| parent | a0edba18861a8f11dccca7e97baf73912173353d (diff) | |
incremental sync seems to work correctly now
Diffstat (limited to 'src')
| -rw-r--r-- | src/documents.odin | 108 | ||||
| -rw-r--r-- | src/position.odin | 54 | ||||
| -rw-r--r-- | src/requests.odin | 26 | ||||
| -rw-r--r-- | src/types.odin | 29 | ||||
| -rw-r--r-- | src/unmarshal.odin | 2 |
5 files changed, 161 insertions, 58 deletions
diff --git a/src/documents.odin b/src/documents.odin index 0618f0f..0be8cae 100644 --- a/src/documents.odin +++ b/src/documents.odin @@ -5,15 +5,15 @@ import "core:fmt" import "core:log" Package :: struct { - documents: [dynamic]^Document, + documents: [dynamic]^Document, }; Document :: struct { uri: string, path: string, - text: string, + text: [] u8, //transmuted version of text plus potential unused space + used_text: int, //allow for the text to be reallocated with more data than needed client_owned: bool, - lines: [dynamic] int, }; DocumentStorage :: struct { @@ -25,26 +25,27 @@ document_storage: DocumentStorage; document_open :: proc(uri_string: string, text: string) -> Error { - uri, parsed_ok := parse_uri(uri_string, context.temp_allocator); + uri, parsed_ok := parse_uri(uri_string); if !parsed_ok { return .ParseError; } if document := &document_storage.documents[uri.path]; document != nil { - + //According to the specification you can't call open more than once without closing it. if document.client_owned { log.errorf("Client called open on an already open document: %v ", document.path); return .InvalidRequest; } - if document.text != "" { + if document.text != nil { delete(document.text); } document.client_owned = true; - document.text = text; + document.text = transmute([] u8)text; + document.used_text = len(document.text); if err := document_refresh(document); err != .None { return err; @@ -58,8 +59,9 @@ document_open :: proc(uri_string: string, text: string) -> Error { document := Document { uri = uri.full, path = uri.path, - text = text, + text = transmute([] u8)text, client_owned = true, + used_text = len(text), }; if err := document_refresh(&document); err != .None { @@ -69,25 +71,93 @@ document_open :: proc(uri_string: string, text: string) -> Error { document_storage.documents[uri.path] = document; } - - //hmm feels like odin needs some ownership semantic + + //hmm feels like odin needs some ownership semantic delete(uri_string); return .None; -} +} document_apply_changes :: proc(uri_string: string, changes: [dynamic] TextDocumentContentChangeEvent) -> Error { - - + uri, parsed_ok := 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.path); + return .InvalidRequest; + } + + for change in changes { + + absolute_range, ok := get_absolute_range(change.range, document.text); + + if !ok { + return .ParseError; + } + + //lower bound is before the change + lower := document.text[:absolute_range.start]; + + //new change between lower and upper + middle := change.text; + + //upper bound is after the change + upper := document.text[min(len(document.text), absolute_range.end+1):]; + + //total new size needed + document.used_text = len(lower) + len(change.text) + len(upper); + + if document.used_text > len(document.text) { + new_text := make([]u8, document.used_text * 2); + + //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); + + delete(document.text); + + document.text = new_text; + } + + else { + //no need to copy the lower since it is already in the document. + copy(document.text[len(lower):], middle); + copy(document.text[len(lower)+len(middle):], upper); + } + + + /* + fmt.println(string(document.text[:document.used_text])); + + fmt.println("LOWER"); + fmt.println(string(lower)); + + fmt.println("CHANGE"); + fmt.println(change.text); + fmt.println(len(change.text)); + + fmt.println("UPPER"); + fmt.println(string(upper)); + */ + + } + + return .None; } -document_close :: proc(uri_string: string, text: string) -> Error { +document_close :: proc(uri_string: string) -> Error { uri, parsed_ok := parse_uri(uri_string, context.temp_allocator); @@ -104,16 +174,6 @@ document_close :: proc(uri_string: string, text: string) -> Error { document.client_owned = false; - if document.text != "" { - delete(document.text); - } - - document.text = text; - - if err := document_refresh(document); err != .None { - return err; - } - return .None; } diff --git a/src/position.odin b/src/position.odin index bcc095f..a0856fb 100644 --- a/src/position.odin +++ b/src/position.odin @@ -2,22 +2,23 @@ package main import "core:strings" import "core:unicode/utf8" +import "core:fmt" /* - This file handles the conversion from utf-16 to utf-8 offsets in the text document + This file handles the conversion between utf-16 and utf-8 offsets in the text document */ AbsoluteRange :: struct { - begin: int, + start: int, end: int, }; -get_absolute_range :: proc(range: Range, document_text: string) -> (AbsoluteRange, bool) { +get_absolute_range :: proc(range: Range, document_text: [] u8) -> (AbsoluteRange, bool) { absolute: AbsoluteRange; - if len(document_text) >= 2 { + if len(document_text) <= 2 { return absolute, false; } @@ -25,16 +26,27 @@ get_absolute_range :: proc(range: Range, document_text: string) -> (AbsoluteRang index := 1; last := document_text[0]; - get_index_at_line(&index, &index, &last, document_text, range.start.line); + if !get_index_at_line(&index, &line_count, &last, document_text, range.start.line) { + return absolute, false; + } + + absolute.start = index + get_character_offset_u16_to_u8(range.start.character, document_text[index:]); + + if !get_index_at_line(&index, &line_count, &last, document_text, range.end.line) { + return absolute, false; + } - - + absolute.end = index + get_character_offset_u16_to_u8(range.end.character, document_text[index:]); return absolute, true; } -get_index_at_line :: proc(current_index: ^int, current_line: ^int, last: ^u8, document_text: string, end_line: int) -> bool { +get_index_at_line :: proc(current_index: ^int, current_line: ^int, last: ^u8, document_text: []u8, end_line: int) -> bool { + + if current_line^ == end_line { + return true; + } for ; current_index^ < len(document_text); current_index^ += 1 { @@ -67,4 +79,30 @@ get_index_at_line :: proc(current_index: ^int, current_line: ^int, last: ^u8, do return false; +} + +get_character_offset_u16_to_u8 :: proc(character_offset: int, document_text: [] u8) -> int { + + utf8_idx := 0; + utf16_idx := 0; + + fmt.println(character_offset); + + for utf16_idx < character_offset { + + r, w := utf8.decode_rune(document_text[utf8_idx:]); + + if r < 0x10000 { + utf16_idx += 1; + } + + else { + utf16_idx += 2; + } + + utf8_idx += w; + + } + + return utf8_idx; }
\ No newline at end of file diff --git a/src/requests.odin b/src/requests.odin index 61f4f6a..50d6dd7 100644 --- a/src/requests.odin +++ b/src/requests.odin @@ -1,4 +1,4 @@ -package main +package main import "core:fmt" import "core:log" @@ -99,7 +99,7 @@ read_and_parse_header :: proc(reader: ^Reader) -> (Header, bool) { return header, false; } } - + } return header, found_content_length; @@ -126,12 +126,12 @@ read_and_parse_body :: proc(reader: ^Reader, header: Header) -> (json.Value, boo } return value, true; -} +} handle_request :: proc(request: json.Value, config: ^Config, writer: ^Writer) -> bool { log.info("Handling request"); - + root, ok := request.value.(json.Object); if !ok { @@ -151,13 +151,13 @@ handle_request :: proc(request: json.Value, config: ^Config, writer: ^Writer) -> case json.Integer: id = v; case: - id = 0; + id = 0; } } method := root["method"].value.(json.String); - call_map : map [string] proc(json.Value, RequestId, ^Config, ^Writer) -> Error = + call_map : map [string] proc(json.Value, RequestId, ^Config, ^Writer) -> Error = {"initialize" = request_initialize, "initialized" = request_initialized, "shutdown" = request_shutdown, @@ -196,7 +196,7 @@ handle_request :: proc(request: json.Value, config: ^Config, writer: ^Writer) -> return true; } -request_initialize :: proc(params: json.Value, id: RequestId, config: ^Config, writer: ^Writer) -> Error { +request_initialize :: proc(params: json.Value, id: RequestId, config: ^Config, writer: ^Writer) -> Error { params_object, ok := params.value.(json.Object); @@ -221,8 +221,8 @@ request_initialize :: proc(params: json.Value, id: RequestId, config: ^Config, w config.hover_support_md = true; } } - - response := make_response_message( + + response := make_response_message( params = ResponseInitializeParams { capabilities = ServerCapabilities { textDocumentSync = 2, //incremental @@ -242,7 +242,7 @@ request_initialized :: proc(params: json.Value, id: RequestId, config: ^Config, request_shutdown :: proc(params: json.Value, id: RequestId, config: ^Config, writer: ^Writer) -> Error { - response := make_response_message( + response := make_response_message( params = nil, id = id, ); @@ -270,7 +270,7 @@ notification_did_open :: proc(params: json.Value, id: RequestId, config: ^Config if unmarshal(params, open_params, context.allocator) != .None { return .ParseError; } - + return document_open(open_params.textDocument.uri, open_params.textDocument.text); } @@ -288,7 +288,7 @@ notification_did_change :: proc(params: json.Value, id: RequestId, config: ^Conf return .ParseError; } - fmt.println(change_params); + document_apply_changes(change_params.textDocument.uri, change_params.contentChanges); return .None; } @@ -307,6 +307,6 @@ notification_did_close :: proc(params: json.Value, id: RequestId, config: ^Confi return .ParseError; } - return document_close(close_params.textDocument.uri, close_params.textDocument.text); + return document_close(close_params.textDocument.uri); } diff --git a/src/types.odin b/src/types.odin index 8ef22be..2edd135 100644 --- a/src/types.odin +++ b/src/types.odin @@ -49,7 +49,7 @@ ResponseError :: struct { }; NotificationLoggingParams :: struct { - type: int, + type: int, message: string, }; @@ -58,8 +58,8 @@ NotificationParams :: union { }; Notification :: struct { - jsonrpc: string, - method: string, + jsonrpc: string, + method: string, params: NotificationParams }; @@ -106,10 +106,6 @@ ClientCapabilities :: struct { textDocument: TextDocumentClientCapabilities, }; -DidOpenTextDocumentParams :: struct { - textDocument: TextDocumentItem, -}; - Position :: struct { line: int, character: int, @@ -134,16 +130,25 @@ VersionedTextDocumentIdentifier :: struct { uri: string, }; +TextDocumentIdentifier :: struct { + uri: string, +}; + +TextDocumentItem :: struct { + uri: string, + text: string, +}; + +DidOpenTextDocumentParams :: struct { + textDocument: TextDocumentItem, +}; + DidChangeTextDocumentParams :: struct { textDocument: VersionedTextDocumentIdentifier, contentChanges: [dynamic] TextDocumentContentChangeEvent, }; DidCloseTextDocumentParams :: struct{ - textDocument: TextDocumentItem, + textDocument: TextDocumentIdentifier, }; -TextDocumentItem :: struct { - uri: string, - text: string, -};
\ No newline at end of file diff --git a/src/unmarshal.odin b/src/unmarshal.odin index 07498c2..297bd89 100644 --- a/src/unmarshal.odin +++ b/src/unmarshal.odin @@ -78,7 +78,7 @@ unmarshal :: proc(json_value: json.Value, v: any, allocator := context.allocator case json.Integer: #partial switch variant in &type_info.variant { case Type_Info_Integer: - switch type_info.size {< + switch type_info.size { case 8: tmp := i64(j); mem.copy(v.data, &tmp, type_info.size); |