diff options
| author | DanielGavin <danielgavin5@hotmail.com> | 2020-11-07 15:44:30 +0100 |
|---|---|---|
| committer | DanielGavin <danielgavin5@hotmail.com> | 2020-11-07 15:44:30 +0100 |
| commit | 6ec424ed8d34cf8a5f51e277a20429741b33ee96 (patch) | |
| tree | 6d0eed732e01d19effbae5cc525a9c2f6e28534f /src/common | |
| parent | 3f1027bd4003cdb9fdc80665548181df2fb60810 (diff) | |
complete refractor of the project into packages
Diffstat (limited to 'src/common')
| -rw-r--r-- | src/common/config.odin | 10 | ||||
| -rw-r--r-- | src/common/position.odin | 257 | ||||
| -rw-r--r-- | src/common/types.odin | 26 | ||||
| -rw-r--r-- | src/common/uri.odin | 156 |
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; +} + |