aboutsummaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
authorDanielGavin <danielgavin5@hotmail.com>2020-11-07 15:44:30 +0100
committerDanielGavin <danielgavin5@hotmail.com>2020-11-07 15:44:30 +0100
commit6ec424ed8d34cf8a5f51e277a20429741b33ee96 (patch)
tree6d0eed732e01d19effbae5cc525a9c2f6e28534f /src/common
parent3f1027bd4003cdb9fdc80665548181df2fb60810 (diff)
complete refractor of the project into packages
Diffstat (limited to 'src/common')
-rw-r--r--src/common/config.odin10
-rw-r--r--src/common/position.odin257
-rw-r--r--src/common/types.odin26
-rw-r--r--src/common/uri.odin156
4 files changed, 449 insertions, 0 deletions
diff --git a/src/common/config.odin b/src/common/config.odin
new file mode 100644
index 0000000..cdbe4fd
--- /dev/null
+++ b/src/common/config.odin
@@ -0,0 +1,10 @@
+package common
+
+Config :: struct {
+ workspace_folders: [dynamic] WorkspaceFolder,
+ completion_support_md: bool,
+ hover_support_md: bool,
+ collections: map [string] string,
+ running: bool,
+};
+
diff --git a/src/common/position.odin b/src/common/position.odin
new file mode 100644
index 0000000..7eb4173
--- /dev/null
+++ b/src/common/position.odin
@@ -0,0 +1,257 @@
+package common
+
+import "core:strings"
+import "core:unicode/utf8"
+import "core:fmt"
+import "core:odin/ast"
+
+/*
+ This file handles the conversion between utf-16 and utf-8 offsets in the text document
+ */
+
+Position :: struct {
+ line: int,
+ character: int,
+};
+
+Range :: struct {
+ start: Position,
+ end: Position,
+};
+
+Location :: struct {
+ uri: string,
+ range: Range,
+};
+
+
+AbsoluteRange :: struct {
+ start: int,
+ end: int,
+};
+
+AbsolutePosition :: int;
+
+get_absolute_position :: proc(position: Position, document_text: [] u8) -> (AbsolutePosition, bool) {
+ absolute: AbsolutePosition;
+
+ if len(document_text) == 0 {
+ absolute = 0;
+ return absolute, true;
+ }
+
+ line_count := 0;
+ index := 1;
+ last := document_text[0];
+
+ if !get_index_at_line(&index, &line_count, &last, document_text, position.line) {
+ return absolute, false;
+ }
+
+ absolute = index + get_character_offset_u16_to_u8(position.character, document_text[index:]);
+
+ return absolute, true;
+}
+
+/*
+ Get the range of a token in utf16 space
+ */
+get_token_range :: proc(node: ast.Node, document_text: [] u8) -> Range {
+ range: Range;
+
+
+ go_backwards_to_endline :: proc(offset: int, document_text: [] u8) -> int {
+
+ index := offset;
+
+ for index > 0 && (document_text[index] != '\n' || document_text[index] != '\r') {
+ index -= 1;
+ }
+
+ if index == 0 {
+ return 0;
+ }
+
+ return index+1;
+ }
+
+ pos_offset := min(len(document_text)-1, node.pos.offset);
+ end_offset := min(len(document_text)-1, node.end.offset);
+
+ offset := go_backwards_to_endline(pos_offset, document_text);
+
+ range.start.line = node.pos.line-1;
+ range.start.character = get_character_offset_u8_to_u16(node.pos.column-1, document_text[offset:]);
+
+ offset = go_backwards_to_endline(end_offset, document_text);
+
+ range.end.line = node.end.line-1;
+ range.end.character = get_character_offset_u8_to_u16(node.end.column-1, document_text[offset:]);
+
+ return range;
+}
+
+get_absolute_range :: proc(range: Range, document_text: [] u8) -> (AbsoluteRange, bool) {
+
+ absolute: AbsoluteRange;
+
+ if len(document_text) == 0 {
+ absolute.start = 0;
+ absolute.end = 0;
+ return absolute, true;
+ }
+
+ line_count := 0;
+ index := 1;
+ last := document_text[0];
+
+ 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 the last line was indexed at zero we have to move it back to index 1.
+ //This happens when line = 0
+ if index == 0 {
+ index = 1;
+ }
+
+ 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: []u8, end_line: int) -> bool {
+
+ if end_line == 0 {
+ current_index^ = 0;
+ return true;
+ }
+
+ if current_line^ == end_line {
+ return true;
+ }
+
+
+ for ; current_index^ < len(document_text); current_index^ += 1 {
+
+ current := document_text[current_index^];
+
+ if last^ == '\r' {
+ current_line^ += 1;
+
+ if current_line^ == end_line {
+ last^ = current;
+ current_index^ += 1;
+ return true;
+ }
+
+ }
+
+ else if current == '\n' {
+ current_line^ += 1;
+
+ if current_line^ == end_line {
+ last^ = current;
+ current_index^ += 1;
+ return true;
+ }
+
+ }
+
+ last^ = document_text[current_index^];
+ }
+
+ return false;
+
+}
+
+get_character_offset_u16_to_u8 :: proc(character_offset: int, document_text: [] u8) -> int {
+
+ utf8_idx := 0;
+ utf16_idx := 0;
+
+ for utf16_idx < character_offset {
+
+ r, w := utf8.decode_rune(document_text[utf8_idx:]);
+
+ if r == '\n' {
+ return utf8_idx;
+ }
+
+ else if r < 0x10000 {
+ utf16_idx += 1;
+ }
+
+ else {
+ utf16_idx += 2;
+ }
+
+ utf8_idx += w;
+
+ }
+
+ return utf8_idx;
+}
+
+get_character_offset_u8_to_u16 :: proc(character_offset: int, document_text: [] u8) -> int {
+
+ utf8_idx := 0;
+ utf16_idx := 0;
+
+ for utf16_idx < character_offset {
+
+ r, w := utf8.decode_rune(document_text[utf8_idx:]);
+
+ if r == '\n' {
+ return utf16_idx;
+ }
+
+ else if r < 0x10000 {
+ utf16_idx += 1;
+ }
+
+ else {
+ utf16_idx += 2;
+ }
+
+ utf8_idx += w;
+
+ }
+
+ return utf16_idx;
+
+}
+
+get_end_line_u16 :: proc(document_text: [] u8) -> int {
+
+ utf8_idx := 0;
+ utf16_idx := 0;
+
+ for utf8_idx < len(document_text) {
+ r, w := utf8.decode_rune(document_text[utf8_idx:]);
+
+ if r == '\n' {
+ return utf16_idx;
+ }
+
+ else if r < 0x10000 {
+ utf16_idx += 1;
+ }
+
+ else {
+ utf16_idx += 2;
+ }
+
+ utf8_idx += w;
+
+ }
+
+ return utf16_idx;
+} \ No newline at end of file
diff --git a/src/common/types.odin b/src/common/types.odin
new file mode 100644
index 0000000..08bd8c2
--- /dev/null
+++ b/src/common/types.odin
@@ -0,0 +1,26 @@
+package common
+
+
+Error :: enum {
+ None = 0,
+
+ // Defined by JSON RPC
+ ParseError = -32700,
+ InvalidRequest = -32600,
+ MethodNotFound = -32601,
+ InvalidParams = -32602,
+ InternalError = -32603,
+ serverErrorStart = -32099,
+ serverErrorEnd = -32000,
+ ServerNotInitialized = -32002,
+ UnknownErrorCode = -32001,
+
+ // Defined by the protocol.
+ RequestCancelled = -32800,
+ ContentModified = -32801,
+};
+
+WorkspaceFolder :: struct {
+ name: string,
+ uri: string,
+};
diff --git a/src/common/uri.odin b/src/common/uri.odin
new file mode 100644
index 0000000..f8bee9e
--- /dev/null
+++ b/src/common/uri.odin
@@ -0,0 +1,156 @@
+package common
+
+import "core:mem"
+import "core:strings"
+import "core:strconv"
+import "core:fmt"
+import "core:unicode/utf8"
+
+Uri :: struct {
+ uri: string,
+ decode_full: string,
+ path: string,
+};
+
+//Note(Daniel, This is an extremely incomplete uri parser and for now ignores fragment and query and only handles file schema)
+
+parse_uri :: proc(value: string, allocator := context.allocator) -> (Uri, bool) {
+
+ uri: Uri;
+
+ decoded, ok := decode_percent(value, allocator);
+
+ if !ok {
+ return uri, false;
+ }
+
+ starts := "file:///";
+
+ if !starts_with(decoded, starts) {
+ return uri, false;
+ }
+
+ uri.uri = strings.clone(value);
+ uri.decode_full = decoded;
+ uri.path = decoded[len(starts):];
+
+ return uri, true;
+}
+
+
+//Note(Daniel, Again some really incomplete and scuffed uri writer)
+create_uri :: proc(path: string, allocator := context.allocator) -> Uri {
+
+ builder := strings.make_builder(allocator);
+
+ strings.write_string(&builder, "file:///");
+ strings.write_string(&builder, encode_percent(path, context.temp_allocator));
+
+ uri: Uri;
+
+ uri.uri = strings.to_string(builder);
+ uri.decode_full = strings.clone(path, allocator);
+ uri.path = uri.decode_full;
+
+ return uri;
+}
+
+delete_uri :: proc(uri: Uri) {
+
+ if uri.uri != "" {
+ delete(uri.uri);
+ }
+
+ if uri.decode_full != "" {
+ delete(uri.decode_full);
+ }
+}
+
+encode_percent :: proc(value: string, allocator: mem.Allocator) -> string {
+
+ builder := strings.make_builder(allocator);
+
+ data := transmute([]u8)value;
+ index: int;
+
+ for index < len(value) {
+
+ r, w := utf8.decode_rune(data[index:]);
+
+ if r > 127 || r == ':'{
+
+ for i := 0; i < w; i += 1 {
+ strings.write_string(&builder, strings.concatenate({"%", fmt.tprintf("%X", data[index+i])},
+ context.temp_allocator));
+ }
+
+ }
+
+ else {
+ strings.write_byte(&builder, data[index]);
+ }
+
+ index += w;
+ }
+
+ return strings.to_string(builder);
+}
+
+@(private)
+starts_with :: proc(value: string, starts_with: string) -> bool {
+
+ if len(value) < len(starts_with) {
+ return false;
+ }
+
+ for i := 0; i < len(starts_with); i += 1 {
+
+ if value[i] != starts_with[i] {
+ return false;
+ }
+
+ }
+
+ return true;
+}
+
+
+@(private)
+decode_percent :: proc(value: string, allocator: mem.Allocator) -> (string, bool) {
+
+ builder := strings.make_builder(allocator);
+
+ for i := 0; i < len(value); i += 1 {
+
+ if value[i] == '%' {
+
+ if i+2 < len(value) {
+
+ v, ok := strconv.parse_i64_of_base(value[i+1:i+3], 16);
+
+ if !ok {
+ strings.destroy_builder(&builder);
+ return "", false;
+ }
+
+ strings.write_byte(&builder, cast(byte)v);
+
+ i+= 2;
+ }
+
+ else {
+ strings.destroy_builder(&builder);
+ return "", false;
+ }
+
+ }
+
+ else {
+ strings.write_byte(&builder, value[i]);
+ }
+
+ }
+
+ return strings.to_string(builder), true;
+}
+