diff options
| -rw-r--r-- | modules/TUI/module.jai | 6 | ||||
| -rw-r--r-- | modules/UTF8.jai | 60 | ||||
| -rw-r--r-- | ttt.jai | 11 |
3 files changed, 39 insertions, 38 deletions
diff --git a/modules/TUI/module.jai b/modules/TUI/module.jai index e25672f..7c3a71d 100644 --- a/modules/TUI/module.jai +++ b/modules/TUI/module.jai @@ -398,7 +398,7 @@ get_key :: (timeout_milliseconds: s32 = -1) -> Key { // By default, parse a single UTF8 character (1 to 4 bytes). to_parse := input_string; - to_parse.count = count_utf8_bytes(input_string[0]); + to_parse.count = count_character_bytes(input_string[0]); defer advance(*input_string, to_parse.count); // Advance over parsed input. // Try to parse escape code. @@ -555,7 +555,7 @@ read_input_line :: (count_limit: int, is_visible: bool = true) -> string, Key { case; if is_escape_code(key) continue; - buff_idx := map_character_to_buffer_idx(str, idx); + buff_idx := get_byte_idx(str, idx); key_str := to_string(key,, allocator = temporary_allocator); // Make sure we have space to append the new character at the end (in case we're trying to do it). @@ -572,7 +572,7 @@ read_input_line :: (count_limit: int, is_visible: bool = true) -> string, Key { idx += 1; // Truncate string to avoid incomplete utf8 codes on the string tail. - str.count = truncate_string(str, count_limit); + truncate(*str, count_limit); } } diff --git a/modules/UTF8.jai b/modules/UTF8.jai index eba4585..b583809 100644 --- a/modules/UTF8.jai +++ b/modules/UTF8.jai @@ -1,25 +1,29 @@ -// BBBB BBBB & 1100 0000 == 10XX XXXX -> is continuation byte -// TODO Maybe rename to: is_continuation_byte -is_utf8_continuation_byte :: inline (byte: u8) -> bool { +// Some procedures to help working with UTF8 strings. +// https://en.wikipedia.org/wiki/UTF-8 + +// Returns true if argument is a continuation byte. +is_continuation_byte :: inline (byte: u8) -> bool { + // BBBB BBBB & 1100 0000 == 10XX XXXX -> is continuation byte return (byte & 0xC0) == 0x80; } -// BBBB BBBB & 1110 0000 == 110X XXXX -> 1 initial + 1 continuation byte -// BBBB BBBB & 1111 0000 == 1110 XXXX -> 1 initial + 2 continuation byte -// BBBB BBBB & 1111 1000 == 1111 0XXX -> 1 initial + 3 continuation byte -// TODO Maybe rename to: count_character_bytes -count_utf8_bytes :: inline (byte: u8) -> int { - if (byte & 0xE0) == 0xC0 return 1+1; - if (byte & 0xF0) == 0xE0 return 1+2; - if (byte & 0xF8) == 0xF0 return 1+3; +// Given a leading_byte, returns the number of bytes on the character. +count_character_bytes :: inline (leading_byte: u8) -> int { + // BBBB BBBB & 1110 0000 == 110X XXXX -> 1 initial + 1 continuation byte + if (leading_byte & 0xE0) == 0xC0 return 1+1; + + // BBBB BBBB & 1111 0000 == 1110 XXXX -> 1 initial + 2 continuation byte + if (leading_byte & 0xF0) == 0xE0 return 1+2; + + // BBBB BBBB & 1111 1000 == 1111 0XXX -> 1 initial + 3 continuation byte + if (leading_byte & 0xF8) == 0xF0 return 1+3; + return 1; } -// Truncates the string to the length provided or shorter, in case of UTF8 strings that require so. -// Truncation is done by zeroing the tail of the string in place. -// Returns length of truncated string. -// TODO Maybe rename to: truncate -truncate_string :: (str: string, length: int) -> length: int { +// Truncates the string to the provided length and zeroes the discarded bytes. +// Returns the length of truncated string or -1 if string has no data. +truncate :: (str: *string, length: int) -> length: int { if str.data == null then return -1; if str.count < length then length = str.count; @@ -29,7 +33,7 @@ truncate_string :: (str: string, length: int) -> length: int { // Find index of first continuation byte. idx := length; - while (idx > 0 && is_utf8_continuation_byte(data[idx - 1])) { + while (idx > 0 && is_continuation_byte(data[idx - 1])) { idx -= 1; } continuation_bytes := length - idx; @@ -50,13 +54,12 @@ truncate_string :: (str: string, length: int) -> length: int { } memset(data + length, 0, count - length); - // str.count = length; TODO We should be doing this... + str.count = length; return length; } // Returns true when the string is empty or consists of space characters. -// TODO Maybe rename to: is_empty -is_empty_string :: (str: string) -> bool { +is_empty :: (str: string) -> bool { for 0..str.count-1 { if str[it] == { case #char "\0"; #through; @@ -74,21 +77,21 @@ is_empty_string :: (str: string) -> bool { return true; } -// Counts number of characters in string. +// Counts the number of characters. count_characters :: (str: string) -> int { characters := 0; idx := 0; while idx < str.count { - idx += count_utf8_bytes(str[idx]); + idx += count_character_bytes(str[idx]); characters += 1; } return characters; } -// Delete character. +// Deletes character by it's index, and moves tail data to take its place. delete_character :: (str: *string, character_idx: int) { - buffer_idx := map_character_to_buffer_idx(str.*, character_idx); - bytes_to_delete := count_utf8_bytes(str.data[buffer_idx]); + buffer_idx := get_byte_idx(str.*, character_idx); + bytes_to_delete := count_character_bytes(str.data[buffer_idx]); for buffer_idx..str.count-1-bytes_to_delete { str.data[it] = str.data[it+bytes_to_delete]; @@ -100,9 +103,8 @@ delete_character :: (str: *string, character_idx: int) { str.count -= bytes_to_delete; } -// Get character index. -// TODO Maybe rename to: map_character_to_byte_idx or get_character_byte_idx -map_character_to_buffer_idx :: (str: string, character_idx: int) -> buffer_idx: int, success: bool { +// Searches for the given character index and returns its byte index on the string. +get_byte_idx :: (str: string, character_idx: int) -> buffer_idx: int, success: bool { if character_idx < 0 then return -1, false; if character_idx > str.count then return -2, false; if character_idx == 0 then return 0, true; @@ -110,7 +112,7 @@ map_character_to_buffer_idx :: (str: string, character_idx: int) -> buffer_idx: buff_idx := 0; char_idx := 0; while buff_idx < str.count && char_idx != character_idx { - buff_idx += count_utf8_bytes(str[buff_idx]); + buff_idx += count_character_bytes(str[buff_idx]); char_idx += 1; } return buff_idx, char_idx == character_idx; @@ -718,10 +718,9 @@ import_from_csv :: (db: *Database, path: string) -> bool { task: Task; csv_values := split(line, ",",, temporary_allocator); - // Import task name. - name_length := min(task.name.count, csv_values[0].count); - memcpy(task.name.data, csv_values[0].data, name_length); - truncate_string(xx task.name, name_length); + // Truncate and import task name. + truncate(*csv_values[0], task.name.count); + memcpy(task.name.data, csv_values[0].data, csv_values[0].count); advance(*csv_values); for csv_values @@ -1466,7 +1465,7 @@ main :: () { // Change task name. TUI.using_style(action_style); input := read_input_string(2, selected_task_row, Task.name.count, size_x - 2 - Task.name.count,, temporary_allocator); - if is_empty_string(input) == false { + if is_empty(input) == false { replace_chars(input, "\t\x0B\x0C\r", #char " "); // Replace weird spaces with space. memset(selected_task.name.data, 0, Task.name.count); memcpy(selected_task.name.data, input.data, min(Task.name.count, input.count)); @@ -1516,7 +1515,7 @@ main :: () { input := read_input_string(input_pos_x, selected_task_row, input_width,, temporary_allocator); // Abort if input if empty. - if is_empty_string(input) continue; + if is_empty(input) continue; // Search for assign '=' operator and discard everything before it. assign_idx := find_index_from_left(input, "="); |
