aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDanielGavin <danielgavin5@hotmail.com>2020-11-03 22:40:40 +0100
committerDanielGavin <danielgavin5@hotmail.com>2020-11-03 22:40:40 +0100
commit35ca720dd6fa200c70a5727507fc6e432bd1a44b (patch)
tree6addf746aefbf1299723780183042c06a451d680 /src
parenta0edba18861a8f11dccca7e97baf73912173353d (diff)
incremental sync seems to work correctly now
Diffstat (limited to 'src')
-rw-r--r--src/documents.odin108
-rw-r--r--src/position.odin54
-rw-r--r--src/requests.odin26
-rw-r--r--src/types.odin29
-rw-r--r--src/unmarshal.odin2
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);