diff --git a/4coder_API/types.h b/4coder_API/types.h index adfe80e0..16613b58 100644 --- a/4coder_API/types.h +++ b/4coder_API/types.h @@ -19,7 +19,7 @@ /* DOC(bool32 is an alias name to signal that an integer parameter or field is for true/false values.) */ TYPEDEF int32_t bool32; -/* DOC(int_color is an alias name to signal that an integer parameter or field is for a color value, colors are specified as 24 bit integers in 3 channels: 0xRRGGBB.) */ +/* DOC(int_color is an alias name to signal that an integer parameter or field is for a color value, colors are specified as 32 bit integers (8 bit + 24 bit) with 3 channels: 0x**RRGGBB.) */ TYPEDEF uint32_t int_color; /* DOC(Buffer_ID is used to name a 4coder buffer. Each buffer has a unique id but when a buffer is closed it's id may be recycled by future, different buffers.) */ diff --git a/4coder_base_commands.cpp b/4coder_base_commands.cpp index 391588b7..0dd14732 100644 --- a/4coder_base_commands.cpp +++ b/4coder_base_commands.cpp @@ -25,16 +25,17 @@ CUSTOM_COMMAND_SIG(write_character){ User_Input in = get_command_input(app); - char character = 0; + uint8_t character[4]; + uint32_t length = 0; if (in.type == UserInputKey){ - character = to_writable_char(in.key.character); + u32_to_utf8_unchecked(in.key.character, character, &length); } - if (character != 0){ + if (length != 0){ Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); int32_t pos = view.cursor.pos; - buffer_replace_range(app, &buffer, pos, pos, &character, 1); - view_set_cursor(app, &view, seek_pos(view.cursor.pos + 1), true); + buffer_replace_range(app, &buffer, pos, pos, (char*)character, length); + view_set_cursor(app, &view, seek_character_pos(view.cursor.character_pos + 1), true); } } diff --git a/4coder_helper/4coder_helper.h b/4coder_helper/4coder_helper.h index da00f800..882cc93c 100644 --- a/4coder_helper/4coder_helper.h +++ b/4coder_helper/4coder_helper.h @@ -151,7 +151,7 @@ inline char buffer_get_char(Application_Links *app, Buffer_Summary *buffer, int32_t pos){ char result = ' '; *buffer = get_buffer(app, buffer->buffer_id, AccessAll); - if (pos >= 0 && pos < buffer->size){ + if (pos < buffer->size){ buffer_read_range(app, buffer, pos, pos+1, &result); } return(result); diff --git a/4coder_helper/4coder_streaming.h b/4coder_helper/4coder_streaming.h index a239d08e..ac3bc849 100644 --- a/4coder_helper/4coder_streaming.h +++ b/4coder_helper/4coder_streaming.h @@ -17,7 +17,7 @@ struct Stream_Chunk{ int32_t start, end; int32_t min_start, max_end; bool32 add_null; - int32_t data_size; + uint32_t data_size; char *data; }; @@ -42,7 +42,7 @@ round_up(int32_t x, int32_t b){ static bool32 init_stream_chunk(Stream_Chunk *chunk, Application_Links *app, Buffer_Summary *buffer, - int32_t pos, char *data, int32_t size){ + int32_t pos, char *data, uint32_t size){ bool32 result = 0; refresh_buffer(app, buffer); diff --git a/4coder_lib/4coder_utf8.h b/4coder_lib/4coder_utf8.h index a5632580..51209a9d 100644 --- a/4coder_lib/4coder_utf8.h +++ b/4coder_lib/4coder_utf8.h @@ -41,31 +41,137 @@ typedef int32_t b32_4tech; // standard preamble end static u32_4tech -utf8_to_u32_unchecked(u8_4tech *buffer){ +utf8_to_u32_length_unchecked(u8_4tech *buffer, u32_4tech *length_out){ u32_4tech result = 0; if (buffer[0] <= 0x7F){ result = (u32_4tech)buffer[0]; + *length_out = 1; } else if (buffer[0] <= 0xE0){ result = ((u32_4tech)((buffer[0])&0x1F)) << 6; result |= ((u32_4tech)((buffer[1])&0x3F)); + *length_out = 2; } else if (buffer[0] <= 0xF0){ result = ((u32_4tech)((buffer[0])&0x0F)) << 12; result |= ((u32_4tech)((buffer[1])&0x3F)) << 6; result |= ((u32_4tech)((buffer[2])&0x3F)); + *length_out = 3; } else{ result = ((u32_4tech)((buffer[0])&0x07)) << 18; result |= ((u32_4tech)((buffer[1])&0x3F)) << 12; result |= ((u32_4tech)((buffer[2])&0x3F)) << 6; result |= ((u32_4tech)((buffer[3])&0x3F)); + *length_out = 4; } return(result); } +static u32_4tech +utf8_to_u32_unchecked(u8_4tech *buffer){ + u32_4tech ignore; + u32_4tech result = utf8_to_u32_length_unchecked(buffer, &ignore); + return(result); +} + +static u32_4tech +utf8_to_u32(u8_4tech **buffer_ptr, u8_4tech *end){ + u8_4tech *buffer = *buffer_ptr; + u32_4tech limit = (u32_4tech)(end - buffer); + + u32_4tech length = 0; + if (buffer[0] < 0x80){ + length = 1; + } + else if (buffer[0] < 0xC0){ + length = 0; + } + else if (buffer[0] < 0xE0){ + length = 2; + } + else if (buffer[0] < 0xF0){ + length = 3; + } + else{ + length = 4; + } + + for (u32_4tech i = 1; i < length; ++i){ + if ((buffer[i] & 0xC0) != 0x80){ + length = 0; + break; + } + } + + u32_4tech result = 0; + if (length != 0 && length <= limit){ + switch (length){ + case 1: + { + result = (u32_4tech)buffer[0]; + }break; + + case 2: + { + result = ((u32_4tech)((buffer[0])&0x1F)) << 6; + result |= ((u32_4tech)((buffer[1])&0x3F)); + }break; + + case 3: + { + result = ((u32_4tech)((buffer[0])&0x0F)) << 12; + result |= ((u32_4tech)((buffer[1])&0x3F)) << 6; + result |= ((u32_4tech)((buffer[2])&0x3F)); + }break; + + case 4: + { + result = ((u32_4tech)((buffer[0])&0x07)) << 18; + result |= ((u32_4tech)((buffer[1])&0x3F)) << 12; + result |= ((u32_4tech)((buffer[2])&0x3F)) << 6; + result |= ((u32_4tech)((buffer[3])&0x3F)); + }break; + } + + *buffer_ptr = buffer + length; + } + else{ + *buffer_ptr = end; + } + + return(result); +} + +static void +u32_to_utf8_unchecked(u32_4tech code_point, u8_4tech *buffer, u32_4tech *length_out){ + if (code_point <= 0x7F){ + buffer[0] = (u8_4tech)code_point; + *length_out = 1; + } + else if (code_point <= 0x7FF){ + buffer[0] = (u8_4tech)(0xC0 | (code_point >> 6)); + buffer[1] = (u8_4tech)(0x80 | (code_point & 0x3F)); + *length_out = 2; + } + else if (code_point <= 0xFFFF){ + buffer[0] = (u8_4tech)(0xE0 | (code_point >> 12)); + buffer[1] = (u8_4tech)(0x80 | ((code_point >> 6) & 0x3F)); + buffer[2] = (u8_4tech)(0x80 | (code_point & 0x3F)); + *length_out = 3; + } + else{ + code_point &= 0x001FFFFF; + buffer[0] = (u8_4tech)(0xF0 | (code_point >> 18)); + buffer[1] = (u8_4tech)(0x80 | ((code_point >> 12) & 0x3F)); + buffer[2] = (u8_4tech)(0x80 | ((code_point >> 6) & 0x3F)); + buffer[3] = (u8_4tech)(0x80 | (code_point & 0x3F)); + *length_out = 4; + } +} + static umem_4tech utf8_to_utf16_minimal_checking(u16_4tech *dst, umem_4tech max_wchars, u8_4tech *src, umem_4tech length, b32_4tech *error){ u8_4tech *s = src; @@ -247,6 +353,22 @@ utf16_to_utf8_minimal_checking(u8_4tech *dst, umem_4tech max_chars, u16_4tech *s return(needed_max); } +static void +byte_to_ascii(u8_4tech n, u8_4tech *out){ + u8_4tech C = '0' + (n / 0x10); + if ((n / 0x10) > 0x9){ + C = ('A' - 0xA) + (n / 0x10); + } + out[0] = C; + + n = (n % 0x10); + C = '0' + n; + if (n > 0x9){ + C = ('A' - 0xA) + n; + } + out[1] = C; +} + #endif // BOTTOM diff --git a/4ed.cpp b/4ed.cpp index 70e6196c..5216f543 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -2361,6 +2361,10 @@ App_Step_Sig(app_step){ "If you're new to 4coder there are some tutorials at http://4coder.net/tutorials.html\n" "\n" "Newest features:\n" + "-New support for extended ascii input.\n" + "-Extended ascii encoded in buffers as utf8.\n" + "\n" + "New in alpha 4.0.16:\n" "- If the current file is a C++ code file, this opens the matching header.\n"" If the current file is a C++ header, this opens the matching code file.\n" "-Option to automatically save changes on build in the config file.\n" " This works for builds triggered by .\n" diff --git a/4ed_api_implementation.cpp b/4ed_api_implementation.cpp index a9daab06..9644ff86 100644 --- a/4ed_api_implementation.cpp +++ b/4ed_api_implementation.cpp @@ -786,7 +786,7 @@ DOC_SEE(Buffer_Setting_ID) if (new_value != file->settings.display_width){ i16 font_id = file->settings.font_id; Render_Font *font = get_font_info(models->font_set, font_id)->font; - file_set_display_width_and_fix_cursor(models, file, new_value, (f32)font->height, font->advance_data); + file_set_width(models, file, new_value, (f32)font->height, font->codepoint_advance_data, font->byte_advance); } }break; @@ -799,7 +799,7 @@ DOC_SEE(Buffer_Setting_ID) if (new_value != file->settings.minimum_base_display_width){ i16 font_id = file->settings.font_id; Render_Font *font = get_font_info(models->font_set, font_id)->font; - file_set_minimum_base_display_width_and_fix_cursor(models, file, new_value, (f32)font->height, font->advance_data); + file_set_min_base_width(models, file, new_value, (f32)font->height, font->codepoint_advance_data, font->byte_advance); } }break; @@ -888,7 +888,7 @@ DOC_SEE(Buffer_Setting_ID) file_allocate_character_starts_as_needed(&models->mem.general, file); buffer_measure_character_starts(&file->state.buffer, file->state.character_starts, 0, file->settings.virtual_white); - file_measure_wraps(models, file, (f32)font->height, font->advance_data); + file_measure_wraps(models, file, (f32)font->height, font->codepoint_advance_data, font->byte_advance); file_update_cursor_positions(models, file); } }break; @@ -2071,12 +2071,9 @@ Set_Theme_Colors(Application_Links *app, Theme_Color *colors, int32_t count) /* DOC_PARAM(colors, The colors pointer provides an array of color structs pairing differet style tags to color codes.) DOC_PARAM(count, The count parameter specifies the number of Theme_Color structs in the colors array.) -DOC -( -For each struct in the array, the slot in the main color pallet specified by the -struct's tag is set to the color code in the struct. If the tag value is invalid -no change is made to the color pallet. -) +DOC( +For each struct in the array, the slot in the main color pallet specified by the struct's tag is set to the color code in the struct. If the tag value is invalid no change is made to the color pallet.) +DOC_SEE(Theme_Color) */{ Command_Data *cmd = (Command_Data*)app->cmd_context; Style *style = main_style(cmd->models); @@ -2098,11 +2095,8 @@ Get_Theme_Colors(Application_Links *app, Theme_Color *colors, int32_t count) /* DOC_PARAM(colors, an array of color structs listing style tags to get color values for) DOC_PARAM(count, the number of color structs in the colors array) -DOC( -For each struct in the array, the color field of the struct is filled with the -color from the slot in the main color pallet specified by the tag. If the tag -value is invalid the color is filled with black. -) +DOC(For each struct in the array, the color field of the struct is filled with the color from the slot in the main color pallet specified by the tag. If the tag value is invalid the color is filled with black.) +DOC_SEE(Theme_Color) */{ Command_Data *cmd = (Command_Data*)app->cmd_context; Style *style = main_style(cmd->models); diff --git a/4ed_app_target.cpp b/4ed_app_target.cpp index 5b711e6f..44d34bc7 100644 --- a/4ed_app_target.cpp +++ b/4ed_app_target.cpp @@ -28,6 +28,7 @@ #include "4coder_lib/4coder_string.h" #include "4coder_lib/4coder_mem.h" #include "4coder_lib/4coder_table.h" +#include "4coder_lib/4coder_utf8.h" #if defined(USE_DEBUG_MEMORY) # include "4ed_debug_mem.h" #endif diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index c8f56991..6e158b05 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -396,7 +396,8 @@ view_compute_cursor(View *view, Buffer_Seek seek, b32 return_hint){ params.buffer = &file->state.buffer; params.seek = seek; params.font_height = (f32)font->height; - params.adv = font->advance_data; + params.cp_adv = font->codepoint_advance_data; + params.byte_adv = font->byte_advance; params.wrap_line_index = file->state.wrap_line_index; params.character_starts = file->state.character_starts; params.virtual_white = file->settings.virtual_white; @@ -1007,14 +1008,18 @@ struct Code_Wrap_State{ b32 consume_newline; Gap_Buffer_Stream stream; + i32 size; i32 i; - f32 *adv; + f32 *cp_adv; + f32 byte_adv; f32 tab_indent_amount; + + Buffer_Translating_State tran; }; internal void -wrap_state_init(Code_Wrap_State *state, Editing_File *file, f32 *adv){ +wrap_state_init(Code_Wrap_State *state, Editing_File *file, f32 *cp_adv, f32 byte_adv){ state->token_array = file->state.token_array; state->token_ptr = state->token_array.tokens; state->end_token = state->token_ptr + state->token_array.count; @@ -1025,9 +1030,14 @@ wrap_state_init(Code_Wrap_State *state, Editing_File *file, f32 *adv){ Gap_Buffer *buffer = &file->state.buffer; i32 size = buffer_size(buffer); buffer_stringify_loop(&state->stream, buffer, 0, size); + state->size = size; + state->i = 0; - state->adv = adv; - state->tab_indent_amount = adv['\t']; + state->cp_adv = cp_adv; + state->byte_adv = byte_adv; + state->tab_indent_amount = cp_adv['\t']; + + state->tran = null_buffer_translating_state; } internal void @@ -1085,11 +1095,11 @@ wrap_state_consume_token(Code_Wrap_State *state, i32 fixed_end_point){ } } - b32 skipping_whitespace = 0; + b32 skipping_whitespace = false; if (i >= state->next_line_start){ state->x = state->wrap_x.paren_nesting[state->wrap_x.paren_safe_top]; state->x = state->wrap_x.paren_nesting[state->wrap_x.paren_safe_top]; - skipping_whitespace = 1; + skipping_whitespace = true; } // TODO(allen): exponential search this shit! @@ -1111,34 +1121,49 @@ wrap_state_consume_token(Code_Wrap_State *state, i32 fixed_end_point){ } if (i == line_start){ - skipping_whitespace = 1; + skipping_whitespace = true; } - b32 recorded_start_x = 0; + b32 recorded_start_x = false; do{ for (; i < state->stream.end; ++i){ if (!(i < end)){ + Assert(state->tran.fill_expected == 0); goto doublebreak; } u8 ch = (u8)state->stream.data[i]; - if (ch != ' ' && ch != '\t'){ - skipping_whitespace = 0; - } + translating_consume_byte(&state->tran, ch, i, state->size); - if (!skipping_whitespace){ - if (ch == '\n'){ + for (TRANSLATION_OUTPUT(&state->tran)){ + TRANSLATION_GET_STEP(&state->tran); + + if (state->tran.do_newline){ state->consume_newline = 1; goto doublebreak; } - else{ - if (!recorded_start_x){ - result.start_x = state->x; - recorded_start_x = 1; + else if(state->tran.do_number_advance || state->tran.do_codepoint_advance){ + u32 n = state->tran.step_current.value; + f32 adv = 0; + if (state->tran.do_codepoint_advance){ + adv = state->cp_adv[n]; + if (n != ' ' && n != '\t'){ + skipping_whitespace = false; + } + } + else{ + adv = state->byte_adv; + skipping_whitespace = false; } - state->x += state->adv[ch]; + if (!skipping_whitespace){ + if (!recorded_start_x){ + result.start_x = state->x; + recorded_start_x = 1; + } + state->x += adv; + } } } } @@ -1425,7 +1450,7 @@ get_current_shift(Code_Wrap_State *wrap_state, i32 next_line_start, b32 *adjust_ } internal void -file_measure_wraps(Models *models, Editing_File *file, f32 font_height, f32 *adv){ +file_measure_wraps(Models *models, Editing_File *file, f32 font_height, f32 *cp_adv, f32 byte_adv){ General_Memory *general = &models->mem.general; Partition *part = &models->mem.part; @@ -1438,7 +1463,8 @@ file_measure_wraps(Models *models, Editing_File *file, f32 font_height, f32 *adv Buffer_Measure_Wrap_Params params; params.buffer = &file->state.buffer; params.wrap_line_index = file->state.wrap_line_index; - params.adv = adv; + params.cp_adv = cp_adv; + params.byte_adv = byte_adv; params.virtual_white = file->settings.virtual_white; f32 width = (f32)file->settings.display_width; @@ -1468,8 +1494,9 @@ file_measure_wraps(Models *models, Editing_File *file, f32 font_height, f32 *adv Wrap_Indent_Pair *wrap_indent_marks = 0; Potential_Wrap_Indent_Pair *potential_marks = 0; i32 max_wrap_indent_mark = 0; + if (params.virtual_white && file->state.tokens_complete && !file->state.still_lexing){ - wrap_state_init(&wrap_state, file, adv); + wrap_state_init(&wrap_state, file, cp_adv, byte_adv); use_tokens = 1; potential_marks = push_array(part, Potential_Wrap_Indent_Pair, floor32(width)); @@ -1521,7 +1548,7 @@ file_measure_wraps(Models *models, Editing_File *file, f32 font_height, f32 *adv word_stage = 1; } else{ - f32 adv = params.adv[ch]; + f32 adv = params.cp_adv[ch]; x += adv; self_x += adv; if (self_x > width){ @@ -1648,7 +1675,7 @@ file_measure_wraps(Models *models, Editing_File *file, f32 font_height, f32 *adv goto doublebreak_stage1; } - f32 adv = params.adv[ch]; + f32 adv = params.cp_adv[ch]; x += adv; if (!first_word && x > current_width){ emit_comment_position = 1; @@ -1674,7 +1701,7 @@ file_measure_wraps(Models *models, Editing_File *file, f32 font_height, f32 *adv goto doublebreak_stage2; } - f32 adv = params.adv[ch]; + f32 adv = params.cp_adv[ch]; x += adv; } still_looping = buffer_stringify_next(&stream); @@ -1881,21 +1908,21 @@ file_measure_wraps(Models *models, Editing_File *file, f32 font_height, f32 *adv } internal void -file_measure_wraps_and_fix_cursor(Models *models, Editing_File *file, f32 font_height, f32 *adv){ - file_measure_wraps(models, file, font_height, adv); +file_measure_wraps_and_fix_cursor(Models *models, Editing_File *file, f32 font_height, f32 *cp_adv, f32 byte_adv){ + file_measure_wraps(models, file, font_height, cp_adv, byte_adv); file_update_cursor_positions(models, file); } internal void -file_set_display_width_and_fix_cursor(Models *models, Editing_File *file, i32 display_width, f32 font_height, f32 *adv){ +file_set_width(Models *models, Editing_File *file, i32 display_width, f32 font_height, f32 *cp_adv, f32 byte_adv){ file->settings.display_width = display_width; - file_measure_wraps_and_fix_cursor(models, file, font_height, adv); + file_measure_wraps_and_fix_cursor(models, file, font_height, cp_adv, byte_adv); } internal void -file_set_minimum_base_display_width_and_fix_cursor(Models *models, Editing_File *file, i32 minimum_base_display_width, f32 font_height, f32 *adv){ +file_set_min_base_width(Models *models, Editing_File *file, i32 minimum_base_display_width, f32 font_height, f32 *cp_adv, f32 byte_adv){ file->settings.minimum_base_display_width = minimum_base_display_width; - file_measure_wraps_and_fix_cursor(models, file, font_height, adv); + file_measure_wraps_and_fix_cursor(models, file, font_height, cp_adv, byte_adv); } // @@ -1944,7 +1971,7 @@ file_create_from_string(System_Functions *system, Models *models, Editing_File * file->settings.font_id = font_id; Render_Font *font = get_font_info(font_set, font_id)->font; - file_measure_wraps(models, file, (f32)font->height, font->advance_data); + file_measure_wraps(models, file, (f32)font->height, font->codepoint_advance_data, font->byte_advance); file->settings.read_only = read_only; if (!read_only){ @@ -3215,7 +3242,7 @@ file_do_single_edit(System_Functions *system, Models *models, Editing_File *file (f32)file->settings.display_width); #endif - file_measure_wraps(models, file, (f32)font->height, font->advance_data); + file_measure_wraps(models, file, (f32)font->height, font->codepoint_advance_data, font->byte_advance); // NOTE(allen): cursor fixing Cursor_Fix_Descriptor desc = {}; @@ -3330,16 +3357,14 @@ file_do_batch_edit(System_Functions *system, Models *models, Editing_File *file, buffer_measure_character_starts(&file->state.buffer, file->state.character_starts, 0, file->settings.virtual_white); Render_Font *font = get_font_info(models->font_set, file->settings.font_id)->font; - file_measure_wraps(models, file, (f32)font->height, font->advance_data); + file_measure_wraps(models, file, (f32)font->height, font->codepoint_advance_data, font->byte_advance); // NOTE(allen): cursor fixing - { - Cursor_Fix_Descriptor desc = {}; - desc.is_batch = 1; - desc.batch = batch; - desc.batch_size = batch_size; - file_edit_cursor_fix(system, models, file, layout, desc); - } + Cursor_Fix_Descriptor desc = {0}; + desc.is_batch = 1; + desc.batch = batch; + desc.batch_size = batch_size; + file_edit_cursor_fix(system, models, file, layout, desc); } inline void @@ -3697,7 +3722,7 @@ internal void file_set_font(Models *models, Editing_File *file, i16 font_id){ file->settings.font_id = font_id; Render_Font *font = get_font_info(models->font_set, file->settings.font_id)->font; - file_measure_wraps_and_fix_cursor(models, file, (f32)font->height, font->advance_data); + file_measure_wraps_and_fix_cursor(models, file, (f32)font->height, font->codepoint_advance_data, font->byte_advance); Editing_Layout *layout = &models->layout; for (View_Iter iter = file_view_iter_init(layout, file, 0); @@ -5966,7 +5991,6 @@ draw_file_loaded(View *view, i32_Rect rect, b32 is_active, Render_Target *target i16 font_id = file->settings.font_id; Render_Font *font = get_font_info(models->font_set, font_id)->font; - float *advance_data = font->advance_data; f32 scroll_x = view->edit_pos->scroll.scroll_x; f32 scroll_y = view->edit_pos->scroll.scroll_y; @@ -6005,7 +6029,8 @@ draw_file_loaded(View *view, i32_Rect rect, b32 is_active, Render_Target *target params.start_cursor = render_cursor; params.wrapped = wrapped; params.font_height = (f32)line_height; - params.adv = advance_data; + params.cp_adv = font->codepoint_advance_data; + params.byte_adv = font->byte_advance; params.virtual_white = file->settings.virtual_white; params.wrap_slashes = file->settings.wrap_indicator; @@ -6162,8 +6187,7 @@ draw_file_loaded(View *view, i32_Rect rect, b32 is_active, Render_Target *target draw_rectangle_outline(target, char_rect, mark_color); } if (item->glyphid != 0){ - font_draw_glyph(target, font_id, (u8)item->glyphid, - item->x0, item->y0, char_color); + font_draw_glyph(target, font_id, (u8)item->glyphid, item->x0, item->y0, char_color); } prev_ind = ind; } @@ -6194,8 +6218,7 @@ draw_text_field(Render_Target *target, View *view, i16 font_id, } internal void -draw_text_with_cursor(Render_Target *target, View *view, i16 font_id, - i32_Rect rect, String s, i32 pos){ +draw_text_with_cursor(Render_Target *target, View *view, i16 font_id, i32_Rect rect, String s, i32 pos){ Models *models = view->persistent.models; Style *style = main_style(models); @@ -6222,8 +6245,9 @@ draw_text_with_cursor(Render_Target *target, View *view, i16 font_id, x = draw_string(target, font_id, part1, floor32(x), y, text_color); + // TODO(allen): WHAT TO DO NOW? cursor_rect.x0 = floor32(x); - cursor_rect.x1 = floor32(x) + ceil32(font->advance_data[s.str[pos]]); + cursor_rect.x1 = floor32(x) + ceil32(font->codepoint_advance_data[s.str[pos]]); cursor_rect.y0 = y; cursor_rect.y1 = y + view->line_height; draw_rectangle(target, cursor_rect, cursor_color); diff --git a/4ed_rendering.h b/4ed_rendering.h index b7d2f26d..2e5a2ca8 100644 --- a/4ed_rendering.h +++ b/4ed_rendering.h @@ -28,7 +28,8 @@ struct Render_Font{ b32 loaded; Glyph_Data glyphs[256]; - f32 advance_data[256]; + f32 byte_advance; + f32 codepoint_advance_data[256]; i32 height, ascent, descent, line_skip; i32 advance; u32 tex; diff --git a/4ed_rendering_helper.cpp b/4ed_rendering_helper.cpp index dc35d1ce..f84069a6 100644 --- a/4ed_rendering_helper.cpp +++ b/4ed_rendering_helper.cpp @@ -116,9 +116,9 @@ font_predict_size(i32 pt_size){ } internal void -font_draw_glyph_mono(Render_Target *target, i16 font_id, u8 character, f32 x, f32 y, f32 advance, u32 color){ +font_draw_glyph(Render_Target *target, i16 font_id, i32 type, u8 character, f32 x, f32 y, u32 color){ Render_Piece_Combined piece; - piece.header.type = piece_type_mono_glyph; + piece.header.type = type; piece.glyph.pos.x = x; piece.glyph.pos.y = y; piece.glyph.color = color; @@ -128,113 +128,111 @@ font_draw_glyph_mono(Render_Target *target, i16 font_id, u8 character, f32 x, f3 font_set_use(target->partition, &target->font_set, font_id); } -inline void -font_draw_glyph_mono(Render_Target *target, i16 font_id, - u8 character, f32 x, f32 y, u32 color){ - f32 advance = (f32)get_font_info(&target->font_set, font_id)->advance; - font_draw_glyph_mono(target, font_id, character, x, y, advance, color); -} - internal void font_draw_glyph(Render_Target *target, i16 font_id, u8 character, f32 x, f32 y, u32 color){ - Render_Piece_Combined piece; - piece.header.type = piece_type_glyph; - piece.glyph.pos.x = x; - piece.glyph.pos.y = y; - piece.glyph.color = color; - piece.glyph.font_id = font_id; - piece.glyph.character = character; - target->push_piece(target, piece); - font_set_use(target->partition, &target->font_set, font_id); + font_draw_glyph(target, font_id, piece_type_glyph, character, x, y, color); } internal f32 -font_string_width(Render_Target *target, i16 font_id, char *str){ - f32 x = 0; +draw_string_base(Render_Target *target, i16 font_id, i32 type, String str_, i32 x_, i32 y_, u32 color){ Render_Font *font = get_font_info(&target->font_set, font_id)->font; - f32 *advance_data = font->advance_data; + f32 x = 0; if (font){ - for (i32 i = 0; str[i]; ++i){ - u8 c = str[i]; - x += advance_data[c]; + f32 y = (f32)y_; + x = (f32)x_; + + f32 byte_advance = font->byte_advance; + f32 *codepoint_advance_data = font->codepoint_advance_data; + + u8 *str = (u8*)str_.str; + u8 *str_end = str + str_.size; + + for (;str < str_end;){ + u8 *byte = str; + u32 codepoint = utf8_to_u32(&str, str_end); + + b32 do_codepoint = false; + b32 do_numbers = false; + if (codepoint){ + if (codepoint >= ' ' && codepoint <= 0xFF && codepoint != 127){ + do_codepoint = true; + } + else{ + do_numbers = true; + } + } + else{ + do_numbers = true; + } + + if (do_codepoint){ + if (color != 0){ + font_draw_glyph(target, font_id, type, (u8)codepoint, x, y, color); + } + x += codepoint_advance_data[codepoint]; + } + else if (do_numbers){ + for (;byte < str; ++byte){ + u8_4tech n = *byte; + if (color != 0){ + u8 cs[3]; + cs[0] = '\\'; + byte_to_ascii(n, cs+1); + + f32 xx = x; + for (u32 j = 0; j < 3; ++j){ + font_draw_glyph(target, font_id, type, cs[j], xx, y, color); + xx += byte_advance; + } + } + + x += byte_advance; + } + } } } return(x); } +internal f32 +draw_string(Render_Target *target, i16 font_id, String str, i32 x, i32 y, u32 color){ + f32 w = draw_string_base(target, font_id, piece_type_glyph, str, x, y, color); + return(w); +} + +internal f32 +draw_string(Render_Target *target, i16 font_id, char *str, i32 x, i32 y, u32 color){ + String string = make_string_slowly(str); + f32 w = draw_string_base(target, font_id, piece_type_glyph, string, x, y, color); + return(w); +} + +internal f32 +draw_string_mono(Render_Target *target, i16 font_id, String str, i32 x, i32 y, f32 advance, u32 color){ + f32 w = draw_string_base(target, font_id, piece_type_mono_glyph, str, x, y, color); + return(w); +} + +internal f32 +draw_string_mono(Render_Target *target, i16 font_id, char *str, i32 x, i32 y, f32 advance, u32 color){ + String string = make_string_slowly(str); + f32 w = draw_string_base(target, font_id, piece_type_mono_glyph, string, x, y, color); + return(w); +} + internal f32 font_string_width(Render_Target *target, i16 font_id, String str){ - f32 x = 0; - Render_Font *font = get_font_info(&target->font_set, font_id)->font; - f32 *advance_data = font->advance_data; - - if (font){ - for (i32 i = 0; i < str.size; ++i){ - u8 c = str.str[i]; - x += advance_data[c]; - } - } - - return(x); + f32 w = draw_string_base(target, font_id, piece_type_glyph, str, 0, 0, 0); + return(w); } internal f32 -draw_string(Render_Target *target, i16 font_id, - char *str, i32 x_, i32 y, u32 color){ - f32 x = (f32)x_; - Render_Font *font = get_font_info(&target->font_set, font_id)->font; - f32 *advance_data = font->advance_data; - - if (font){ - for (i32 i = 0; str[i]; ++i){ - u8 c = str[i]; - font_draw_glyph(target, font_id, c, x, (f32)y, color); - x += advance_data[c]; - } - } - - return(x); -} - -internal f32 -draw_string_mono(Render_Target *target, i16 font_id, char *str, f32 x, f32 y, f32 advance, u32 color){ - for (i32 i = 0; str[i]; ++i){ - u8 c = str[i]; - font_draw_glyph_mono(target, font_id, c, x, y, advance, color); - x += advance; - } - - return(x); -} - -internal f32 -draw_string(Render_Target *target, i16 font_id, String str, i32 x_, i32 y, u32 color){ - f32 x = (f32)x_; - Render_Font *font = get_font_info(&target->font_set, font_id)->font; - f32 *advance_data = font->advance_data; - - if (font){ - for (i32 i = 0; i < str.size; ++i){ - u8 c = str.str[i]; - font_draw_glyph(target, font_id, c, x, (f32)y, color); - x += advance_data[c]; - } - } - - return(x); -} - -internal f32 -draw_string_mono(Render_Target *target, i16 font_id, String str, f32 x, f32 y, f32 advance, u32 color){ - for (i32 i = 0; i < str.size; ++i){ - u8 c = str.str[i] % 128; - font_draw_glyph_mono(target, font_id, c, x, y, advance, color); - x += advance; - } - - return(x); +font_string_width(Render_Target *target, i16 font_id, char *str){ + String string = make_string_slowly(str); + f32 w = draw_string_base(target, font_id, piece_type_glyph, string, 0, 0, 0); + return(w); } // BOTTOM diff --git a/4ed_site.ctm b/4ed_site.ctm index 4169d1d9..77ce8a41 100644 Binary files a/4ed_site.ctm and b/4ed_site.ctm differ diff --git a/4ed_system_shared.cpp b/4ed_system_shared.cpp index a2cb91b2..cba64e05 100644 --- a/4ed_system_shared.cpp +++ b/4ed_system_shared.cpp @@ -544,6 +544,7 @@ launch_rendering(Render_Target *target){ #undef ExtractStruct +#if 0 internal void* part_alloc(i32 size, void *context){ Partition *part = (Partition*)context; @@ -552,8 +553,7 @@ part_alloc(i32 size, void *context){ } internal void -part_free(void *ptr, void *context){ -} +part_free(void *ptr, void *context){} #define STBTT_malloc part_alloc #define STBTT_free part_free @@ -561,34 +561,28 @@ part_free(void *ptr, void *context){ #define STB_TRUETYPE_IMPLEMENTATION #include "stb_truetype.h" -internal i32 -stb_font_load(Partition *part, - Render_Font *font_out, - char *filename_untranslated, - i32 pt_size, - i32 tab_width, - i32 oversample, - b32 store_texture){ +internal b32 +stb_font_load(Partition *part, Render_Font *font_out, char *filename_untranslated, i32 pt_size, i32 tab_width, i32 oversample, b32 store_texture){ char space_[1024]; String filename = make_fixed_width_string(space_); b32 translate_success = sysshared_to_binary_path(&filename, filename_untranslated); if (!translate_success) return 0; - i32 result = 1; + b32 result = true; stbtt_packedchar chardata[256]; File_Data file = sysshared_load_file(filename.str); if (!file.data){ - result = 0; + result = false; } else{ stbtt_fontinfo font; if (!stbtt_InitFont(&font, (u8*)file.data, 0)){ - result = 0; + result = false; } else{ memset(font_out, 0, sizeof(*font_out)); @@ -620,19 +614,16 @@ stb_font_load(Partition *part, ///////////////////////////////////////////////////////////////// stbtt_pack_context spc; - if (stbtt_PackBegin(&spc, (u8*)block, tex_width, tex_height, - tex_width, 1, part)){ + if (stbtt_PackBegin(&spc, (u8*)block, tex_width, tex_height, tex_width, 1, part)){ stbtt_PackSetOversampling(&spc, oversample, oversample); - if (!stbtt_PackFontRange(&spc, (u8*)file.data, 0, - STBTT_POINT_SIZE((f32)pt_size), - 0, 128, chardata)){ - result = 0; + if (!stbtt_PackFontRange(&spc, (u8*)file.data, 0, STBTT_POINT_SIZE((f32)pt_size), 0, 128, chardata)){ + result = false; } stbtt_PackEnd(&spc); } else{ - result = 0; + result = false; } ///////////////////////////////////////////////////////////////// @@ -694,6 +685,7 @@ stb_font_load(Partition *part, return(result); } +#endif // NOTE(allen): Thanks to insofaras. This is copy-pasted from some work he originally did to get free type working on Linux. @@ -826,11 +818,11 @@ font_load_freetype(Partition *part, Render_Font *rf, char *filename, i32 pt_size // TODO(allen): maybe advance data should be integers for a while... // I require the actual values to be integers anyway... hmm... - rf->advance_data[i] = (f32)ceil32(face->glyph->advance.x / 64.0f); + f32 advance = (f32)ceil32(face->glyph->advance.x / 64.0f); + rf->codepoint_advance_data[i] = advance; rf->glyphs[i].exists = 1; - i32 pitch = face->glyph->bitmap.pitch; // write to texture atlas @@ -865,40 +857,23 @@ font_load_freetype(Partition *part, Render_Font *rf, char *filename, i32 pt_size pen_x = ceil32(c->x1 + 1); } - // TODO(allen): advance data is still too stupid. - // Provide an "unedited" version, then generate these - // on the fly. Maybe later introduce a caching system or whatevs. - f32 *adv = rf->advance_data; - for (i32 i = 0; i < 256; ++i){ - if (i < ' ' || i == 127){ - switch (i){ - case '\n': - adv[i] = adv[' ']; - break; - - case '\r': - adv[i] = adv['\\'] + adv['r']; - break; - - case '\t': - adv[i] = adv[' ']*tab_width; - break; - - default: - { - int8_t d1 = (int8_t)(i/0x10), d2 = (int8_t)(i%0x10); - char c1 = '0' + d1, c2 = '0' + d2; - if (d1 >= 0xA){ - c1 = ('A' - 0xA) + d1; - } - if (d2 >= 0xA){ - c2 = ('A' - 0xA) + d2; - } - adv[i] = adv['\\'] + adv[c1] + adv[c2]; - }break; - } - } + f32 *cp_adv = rf->codepoint_advance_data; + cp_adv['\n'] = cp_adv[' ']; + cp_adv['\r'] = cp_adv['\\'] + cp_adv['r']; + cp_adv['\t'] = cp_adv[' ']*tab_width; + + f32 max_hex_advance = cp_adv['0']; + for (u32 i = '1'; i <= '9'; ++i){ + max_hex_advance = Max(max_hex_advance, cp_adv[i]); } + for (u32 i = 'a'; i <= 'f'; ++i){ + max_hex_advance = Max(max_hex_advance, cp_adv[i]); + } + for (u32 i = 'A'; i <= 'F'; ++i){ + max_hex_advance = Max(max_hex_advance, cp_adv[i]); + } + + rf->byte_advance = cp_adv['\\'] + max_hex_advance*2; FT_Done_FreeType(ft); diff --git a/buildsuper.sh b/buildsuper.sh index 384b2607..db6ef1ba 100755 --- a/buildsuper.sh +++ b/buildsuper.sh @@ -13,5 +13,7 @@ fi echo "Building custom_4coders.so from $SOURCE ..." +SOURCE=$(readlink -f "$SOURCE") + g++ -I"$CODE_HOME" -Wno-write-strings -std=gnu++0x "$SOURCE" -shared -o custom_4coder.so -fPIC diff --git a/file/4coder_buffer.cpp b/file/4coder_buffer.cpp index b61194d3..8c3ede72 100644 --- a/file/4coder_buffer.cpp +++ b/file/4coder_buffer.cpp @@ -235,6 +235,7 @@ eol_in_place_convert_out(char *data, i32 size, i32 max, i32 *size_out){ return(result); } +// TODO(allen): ditch this shit yo inline i32 is_whitespace(char c){ i32 result; @@ -288,6 +289,203 @@ is_match_insensitive(char *a, char *b, i32 len){ return(result); } +// +// Translation state for turning byte streams into unicode/trash byte streams +// + +struct Buffer_Model_Step{ + u32 type; + u32 value; + i32 i; + u32 byte_length; +}; + +enum{ + BufferModelUnit_None, + BufferModelUnit_Codepoint, + BufferModelUnit_Numbers, +}; + +struct Buffer_Translating_State{ + u8 fill_buffer[4]; + u32 fill_start_i; + u32 fill_i; + u32 fill_expected; + + u32 byte_class; + b32 emit_type; + b32 rebuffer_current; + b32 emit_current_as_cp; + + Buffer_Model_Step steps[5]; + Buffer_Model_Step step_current; + u32 step_count; + u32 step_j; + + u32 codepoint; + u32 codepoint_length; + b32 do_codepoint; + b32 do_numbers; + + b32 do_newline; + b32 do_codepoint_advance; + b32 do_number_advance; +}; +global_const Buffer_Translating_State null_buffer_translating_state = {0}; + +internal void +translating_consume_byte(Buffer_Translating_State *tran, u8 ch, u32 i, u32 size){ + tran->byte_class = 0; + if ((ch >= ' ' && ch < 0x7F) || ch == '\t' || ch == '\n' || ch == '\r'){ + tran->byte_class = 1; + } + else if (ch < 0xC0){ + tran->byte_class = 1000; + } + else if (ch < 0xE0){ + tran->byte_class = 2; + } + else if (ch < 0xF0){ + tran->byte_class = 3; + } + else{ + tran->byte_class = 4; + } + + tran->emit_type = BufferModelUnit_None; + tran->rebuffer_current = false; + tran->emit_current_as_cp = false; + if (tran->fill_expected == 0){ + tran->fill_buffer[0] = ch; + tran->fill_start_i = i; + tran->fill_i = 1; + + if (tran->byte_class == 1){ + tran->emit_type = BufferModelUnit_Codepoint; + } + else if (tran->byte_class == 0 || tran->byte_class == 1000){ + tran->emit_type = BufferModelUnit_Numbers; + } + else{ + tran->fill_expected = tran->byte_class; + } + } + else{ + if (tran->byte_class == 1000){ + tran->fill_buffer[tran->fill_i] = ch; + ++tran->fill_i; + + if (tran->fill_i == tran->fill_expected){ + tran->emit_type = BufferModelUnit_Codepoint; + } + } + else{ + if (tran->byte_class >= 2 && tran->byte_class <= 4){ + tran->rebuffer_current = true; + } + else if (tran->byte_class == 1){ + tran->emit_current_as_cp = true; + } + else{ + tran->fill_buffer[tran->fill_i] = ch; + ++tran->fill_i; + } + tran->emit_type = BufferModelUnit_Numbers; + } + } + + if (tran->emit_type == BufferModelUnit_None && i+1 == size){ + tran->emit_type = BufferModelUnit_Numbers; + } + + tran->codepoint = 0; + tran->codepoint_length = 0; + tran->do_codepoint = false; + tran->do_numbers = false; + if (tran->emit_type == BufferModelUnit_Codepoint){ + tran->codepoint = utf8_to_u32_length_unchecked(tran->fill_buffer, &tran->codepoint_length); + if ((tran->codepoint >= ' ' && tran->codepoint <= 255 && tran->codepoint != 127) || tran->codepoint == '\t' || tran->codepoint == '\n' || tran->codepoint == '\r'){ + tran->do_codepoint = true; + } + else{ + tran->do_numbers = true; + } + } + else if (tran->emit_type == BufferModelUnit_Numbers){ + tran->do_numbers = true; + } + + Assert((tran->do_codepoint + tran->do_numbers) <= 1); + + tran->step_count = 0; + if (tran->do_codepoint){ + tran->steps[0].type = 1; + tran->steps[0].value = tran->codepoint; + tran->steps[0].i = tran->fill_start_i; + tran->steps[0].byte_length = tran->codepoint_length; + tran->step_count = 1; + } + else if (tran->do_numbers){ + for (u32 j = 0; j < tran->fill_i; ++j){ + tran->steps[j].type = 0; + tran->steps[j].value = tran->fill_buffer[j]; + tran->steps[j].i = tran->fill_start_i + j; + tran->steps[j].byte_length = 1; + } + tran->step_count = tran->fill_i; + } + + if (tran->do_codepoint || tran->do_numbers){ + tran->fill_start_i = 0; + tran->fill_i = 0; + tran->fill_expected = 0; + } + + if (tran->rebuffer_current){ + Assert(tran->do_codepoint || tran->do_numbers); + + tran->fill_buffer[0] = ch; + tran->fill_start_i = i; + tran->fill_i = 1; + tran->fill_expected = tran->byte_class; + } + else if (tran->emit_current_as_cp){ + Assert(tran->do_codepoint || tran->do_numbers); + + tran->steps[tran->step_count].type = 1; + tran->steps[tran->step_count].value = ch; + tran->steps[tran->step_count].i = i; + tran->steps[tran->step_count].byte_length = 1; + ++tran->step_count; + } +} + +internal void +translation_step_read(Buffer_Translating_State *tran){ + tran->do_newline = false; + tran->do_codepoint_advance = false; + tran->do_number_advance = false; + if (tran->step_current.type == 1){ + switch (tran->step_current.value){ + case '\n': + { + tran->do_newline = true; + }break; + + default: + { + tran->do_codepoint_advance = true; + }break; + } + } + else{ + tran->do_number_advance = true; + } +} + +#define TRANSLATION_OUTPUT(t) (t)->step_j = 0; (t)->step_j < (t)->step_count; ++(t)->step_j +#define TRANSLATION_GET_STEP(t) (t)->step_current = (t)->steps[(t)->step_j]; translation_step_read(t) + // // Implementation of the gap buffer // @@ -700,6 +898,8 @@ buffer_measure_character_starts(Gap_Buffer *buffer, i32 *character_starts, i32 m skipping_whitespace = 1; } + Buffer_Translating_State tran = {0}; + stream.use_termination_character = 1; stream.terminator = '\n'; if (buffer_stringify_loop(&stream, buffer, i, size)){ @@ -707,20 +907,27 @@ buffer_measure_character_starts(Gap_Buffer *buffer, i32 *character_starts, i32 m do{ for (; i < stream.end; ++i){ u8 ch = (u8)stream.data[i]; - if (ch == '\n'){ - ++character_index; - character_starts[line_index++] = character_index; - if (virtual_white){ - skipping_whitespace = 1; - } - } - else{ - if (ch != ' ' && ch != '\t'){ - skipping_whitespace = 0; - } + + translating_consume_byte(&tran, ch, i, size); + + for (TRANSLATION_OUTPUT(&tran)){ + TRANSLATION_GET_STEP(&tran); - if (!skipping_whitespace){ + if (tran.do_newline){ ++character_index; + character_starts[line_index++] = character_index; + if (virtual_white){ + skipping_whitespace = 1; + } + } + else if (tran.do_codepoint_advance || tran.do_number_advance){ + if (ch != ' ' && ch != '\t'){ + skipping_whitespace = 0; + } + + if (!skipping_whitespace){ + ++character_index; + } } } } @@ -750,7 +957,8 @@ struct Buffer_Layout_Stop{ struct Buffer_Measure_Wrap_Params{ Gap_Buffer *buffer; i32 *wrap_line_index; - f32 *adv; + f32 *cp_adv; + f32 byte_adv; b32 virtual_white; }; @@ -773,6 +981,8 @@ struct Buffer_Measure_Wrap_State{ u8 ch; + Buffer_Translating_State tran; + i32 __pc__; }; @@ -807,7 +1017,7 @@ buffer_measure_wrap_y(Buffer_Measure_Wrap_State *S_ptr, Buffer_Measure_Wrap_Para params.wrap_line_index[S.line_index++] = 0; if (params.virtual_white){ - S.skipping_whitespace = 1; + S.skipping_whitespace = true; } S.first_of_the_line = 1; @@ -816,65 +1026,78 @@ buffer_measure_wrap_y(Buffer_Measure_Wrap_State *S_ptr, Buffer_Measure_Wrap_Para do{ for (; S.i < S.stream.end; ++S.i){ S.ch = (u8)S.stream.data[S.i]; - if (S.ch == '\n'){ - ++S.current_wrap_index; - params.wrap_line_index[S.line_index++] = S.current_wrap_index; - - if (params.virtual_white){ - S_stop.status = BLStatus_NeedLineShift; - S_stop.line_index = S.line_index - 1; - S_stop.wrap_line_index = S.current_wrap_index; - S_stop.pos = S.i+1; - DrYield(2, S_stop); - } - - S.x = line_shift; - - if (params.virtual_white){ - S.skipping_whitespace = 1; - } - S.first_of_the_line = 1; + + if (S.ch != ' ' && S.ch != '\t'){ + S.skipping_whitespace = false; } - else{ - if (S.ch != ' ' && S.ch != '\t'){ - S.skipping_whitespace = 0; - } + + translating_consume_byte(&S.tran, S.ch, S.i, S.size); + + for (TRANSLATION_OUTPUT(&S.tran)){ + TRANSLATION_GET_STEP(&S.tran); - if (!S.skipping_whitespace){ - S.current_adv = params.adv[S.ch]; + if (S.tran.do_newline){ + ++S.current_wrap_index; + params.wrap_line_index[S.line_index++] = S.current_wrap_index; - S.did_wrap = 0; - if (S.i >= S.wrap_unit_end){ - S_stop.status = BLStatus_NeedWrapDetermination; + if (params.virtual_white){ + S_stop.status = BLStatus_NeedLineShift; S_stop.line_index = S.line_index - 1; S_stop.wrap_line_index = S.current_wrap_index; - S_stop.pos = S.i; - S_stop.x = S.x; - DrYield(4, S_stop); + S_stop.pos = S.i+1; + DrYield(2, S_stop); + } + + S.x = line_shift; + + if (params.virtual_white){ + S.skipping_whitespace = 1; + } + S.first_of_the_line = 1; + } + else if (S.tran.do_number_advance || S.tran.do_codepoint_advance){ + if (!S.skipping_whitespace){ - S.wrap_unit_end = wrap_unit_end; - - if (do_wrap && !S.first_of_the_line){ - S.did_wrap = 1; - ++S.current_wrap_index; - - if (params.virtual_white){ - S_stop.status = BLStatus_NeedWrapLineShift; - S_stop.line_index = S.line_index - 1; - S_stop.wrap_line_index = S.current_wrap_index; - S_stop.pos = S.i; - DrYield(3, S_stop); - } - - S.x = line_shift + S.current_adv; + if (S.tran.do_codepoint_advance){ + S.current_adv = params.cp_adv[S.tran.step_current.value]; } + else{ + S.current_adv = params.byte_adv; + } + + S.did_wrap = false; + if (S.i >= S.wrap_unit_end){ + S_stop.status = BLStatus_NeedWrapDetermination; + S_stop.line_index = S.line_index - 1; + S_stop.wrap_line_index = S.current_wrap_index; + S_stop.pos = S.i; + S_stop.x = S.x; + DrYield(4, S_stop); + + S.wrap_unit_end = wrap_unit_end; + + if (do_wrap && !S.first_of_the_line){ + S.did_wrap = true; + ++S.current_wrap_index; + + if (params.virtual_white){ + S_stop.status = BLStatus_NeedWrapLineShift; + S_stop.line_index = S.line_index - 1; + S_stop.wrap_line_index = S.current_wrap_index; + S_stop.pos = S.i; + DrYield(3, S_stop); + } + + S.x = line_shift + S.current_adv; + } + } + + if (!S.did_wrap){ + S.x += S.current_adv; + } + + S.first_of_the_line = 0; } - - if (!S.did_wrap){ - S.x += S.current_adv; - } - - S.first_of_the_line = 0; } } } @@ -970,8 +1193,7 @@ buffer_remeasure_starts(Gap_Buffer *buffer, i32 line_start, i32 line_end, i32 li } internal void -buffer_remeasure_character_starts(Gap_Buffer *buffer, i32 line_start, i32 line_end, i32 line_shift, - i32 *character_starts, i32 mode, i32 virtual_whitespace){ +buffer_remeasure_character_starts(Gap_Buffer *buffer, i32 line_start, i32 line_end, i32 line_shift, i32 *character_starts, i32 mode, i32 virtual_whitespace){ assert(mode == 0); i32 new_line_count = buffer->line_count; @@ -989,11 +1211,10 @@ buffer_remeasure_character_starts(Gap_Buffer *buffer, i32 line_start, i32 line_e line_count -= line_shift; new_line_end += line_shift; - memmove(character_starts + line_end + line_shift, character_starts + line_end, - sizeof(i32)*(line_count - line_end + 1)); + memmove(character_starts + line_end + line_shift, character_starts + line_end, sizeof(i32)*(line_count - line_end + 1)); } - // Iteration data (yikes! Need better loop system) + // Iteration data Gap_Buffer_Stream stream = {0}; i32 size = buffer_size(buffer); i32 char_i = buffer->line_starts[line_start]; @@ -1009,6 +1230,9 @@ buffer_remeasure_character_starts(Gap_Buffer *buffer, i32 line_start, i32 line_e skipping_whitespace = 1; } + // Translation + Buffer_Translating_State tran = {0}; + stream.use_termination_character = 1; stream.terminator = '\n'; if (buffer_stringify_loop(&stream, buffer, char_i, size)){ @@ -1016,25 +1240,31 @@ buffer_remeasure_character_starts(Gap_Buffer *buffer, i32 line_start, i32 line_e do{ for (; char_i < stream.end; ++char_i){ u8 ch = (u8)stream.data[char_i]; - if (ch == '\n'){ - character_starts[line_i++] = last_char_start; - ++current_char_start; - last_char_start = current_char_start; - if (virtual_whitespace){ - skipping_whitespace = 1; - } + translating_consume_byte(&tran, ch, char_i, size); + + for (TRANSLATION_OUTPUT(&tran)){ + TRANSLATION_GET_STEP(&tran); - if (line_i >= new_line_end){ - goto buffer_remeasure_character_starts_end; - } - } - else{ - if (ch != ' ' && ch != '\t'){ - skipping_whitespace = 0; - } - - if (!skipping_whitespace){ + if (tran.do_newline){ + character_starts[line_i++] = last_char_start; ++current_char_start; + last_char_start = current_char_start; + if (virtual_whitespace){ + skipping_whitespace = 1; + } + + if (line_i >= new_line_end){ + goto buffer_remeasure_character_starts_end; + } + } + else if (tran.do_codepoint_advance || tran.do_number_advance){ + if (ch != ' ' && ch != '\t'){ + skipping_whitespace = 0; + } + + if (!skipping_whitespace){ + ++current_char_start; + } } } } @@ -1275,7 +1505,8 @@ struct Buffer_Cursor_Seek_Params{ Gap_Buffer *buffer; Buffer_Seek seek; f32 font_height; - f32 *adv; + f32 *cp_adv; + f32 byte_adv; i32 *wrap_line_index; i32 *character_starts; b32 virtual_white; @@ -1299,6 +1530,8 @@ struct Buffer_Cursor_Seek_State{ f32 ch_width; u8 ch; + Buffer_Translating_State tran; + i32 __pc__; }; @@ -1331,9 +1564,6 @@ buffer_cursor_seek(Buffer_Cursor_Seek_State *S_ptr, Buffer_Cursor_Seek_Params pa if (params.seek.pos > S.size){ params.seek.pos = S.size; } - if (params.seek.pos < 0){ - params.seek.pos = 0; - } line_index = buffer_get_line_index(params.buffer, params.seek.pos); }break; @@ -1345,9 +1575,6 @@ buffer_cursor_seek(Buffer_Cursor_Seek_State *S_ptr, Buffer_Cursor_Seek_Params pa if (params.seek.pos > max_character){ params.seek.pos = max_character; } - if (params.seek.pos < 0){ - params.seek.pos = 0; - } line_index = buffer_get_line_index_from_character_pos(params.character_starts, params.seek.pos, 0, params.buffer->line_count); @@ -1429,7 +1656,7 @@ buffer_cursor_seek(Buffer_Cursor_Seek_State *S_ptr, Buffer_Cursor_Seek_Params pa double_break_vwhite:; } - // If the user just wants the hint, return that now. + // If the caller just wants the hint, return that now. if (params.return_hint){ *params.cursor_out = S.next_cursor; S_stop.status = BLStatus_Finished; @@ -1491,12 +1718,15 @@ buffer_cursor_seek(Buffer_Cursor_Seek_State *S_ptr, Buffer_Cursor_Seek_Params pa for (; S.i < S.stream.end; ++S.i){ S.ch = (u8)S.stream.data[S.i]; - S.prev_cursor = S.this_cursor; - S.this_cursor = S.next_cursor; + translating_consume_byte(&S.tran, S.ch, S.i, S.size); - switch (S.ch){ - case '\n': - { + for (TRANSLATION_OUTPUT(&S.tran)){ + TRANSLATION_GET_STEP(&S.tran); + + S.prev_cursor = S.this_cursor; + S.this_cursor = S.next_cursor; + + if (S.tran.do_newline){ ++S.next_cursor.character_pos; ++S.next_cursor.line; ++S.next_cursor.wrap_line; @@ -1514,17 +1744,21 @@ buffer_cursor_seek(Buffer_Cursor_Seek_State *S_ptr, Buffer_Cursor_Seek_Params pa S.next_cursor.wrapped_x = line_shift; S.first_of_the_line = 1; - }break; - - default: - { - S.ch_width = params.adv[S.ch]; + } + else if (S.tran.do_number_advance || S.tran.do_codepoint_advance){ - if (S.i >= S.wrap_unit_end){ + if (S.tran.do_codepoint_advance){ + S.ch_width = params.cp_adv[S.tran.step_current.value]; + } + else{ + S.ch_width = params.byte_adv; + } + + if (S.tran.step_current.i >= S.wrap_unit_end){ S_stop.status = BLStatus_NeedWrapDetermination; S_stop.line_index = S.next_cursor.line-1; S_stop.wrap_line_index = S.next_cursor.wrap_line-1; - S_stop.pos = S.i; + S_stop.pos = S.tran.step_current.i; S_stop.x = S.next_cursor.wrapped_x; DrYield(4, S_stop); @@ -1552,73 +1786,73 @@ buffer_cursor_seek(Buffer_Cursor_Seek_State *S_ptr, Buffer_Cursor_Seek_Params pa S.next_cursor.wrapped_x += S.ch_width; S.first_of_the_line = 0; - }break; - } - - ++S.next_cursor.pos; - - f32 x = 0, px = 0, y = 0, py = 0; - switch (params.seek.type){ - case buffer_seek_pos: - if (S.this_cursor.pos >= params.seek.pos){ - goto buffer_cursor_seek_end; - }break; - - case buffer_seek_character_pos: - if (S.this_cursor.character_pos >= params.seek.pos){ - goto buffer_cursor_seek_end; - }break; - - case buffer_seek_wrapped_xy: - { - x = S.this_cursor.wrapped_x; - px = S.prev_cursor.wrapped_x; - y = S.this_cursor.wrapped_y; - py = S.prev_cursor.wrapped_y; - }break; - - case buffer_seek_unwrapped_xy: - { - x = S.this_cursor.unwrapped_x; - px = S.prev_cursor.unwrapped_x; - y = S.this_cursor.unwrapped_y; - py = S.prev_cursor.wrapped_y; - }break; - - case buffer_seek_line_char: - if (S.this_cursor.line == params.seek.line && S.this_cursor.character >= params.seek.character){ - goto buffer_cursor_seek_end; - } - else if (S.this_cursor.line > params.seek.line){ - S.this_cursor = S.prev_cursor; - goto buffer_cursor_seek_end; - }break; - } - - if (S.xy_seek){ - if (y > params.seek.y){ - S.this_cursor = S.prev_cursor; - goto buffer_cursor_seek_end; } - if (y > params.seek.y - params.font_height && x >= params.seek.x){ - if (!params.seek.round_down){ - if (py >= y && S.ch != '\n' && (params.seek.x - px) < (x - params.seek.x)){ + S.next_cursor.pos += S.tran.step_current.byte_length; + + f32 x = 0, px = 0, y = 0, py = 0; + switch (params.seek.type){ + case buffer_seek_pos: + if (S.this_cursor.pos >= params.seek.pos){ + goto buffer_cursor_seek_end; + }break; + + case buffer_seek_character_pos: + if (S.this_cursor.character_pos >= params.seek.pos){ + goto buffer_cursor_seek_end; + }break; + + case buffer_seek_wrapped_xy: + { + x = S.this_cursor.wrapped_x; + px = S.prev_cursor.wrapped_x; + y = S.this_cursor.wrapped_y; + py = S.prev_cursor.wrapped_y; + }break; + + case buffer_seek_unwrapped_xy: + { + x = S.this_cursor.unwrapped_x; + px = S.prev_cursor.unwrapped_x; + y = S.this_cursor.unwrapped_y; + py = S.prev_cursor.wrapped_y; + }break; + + case buffer_seek_line_char: + if (S.this_cursor.line == params.seek.line && S.this_cursor.character >= params.seek.character){ + goto buffer_cursor_seek_end; + } + else if (S.this_cursor.line > params.seek.line){ + S.this_cursor = S.prev_cursor; + goto buffer_cursor_seek_end; + }break; + } + + if (S.xy_seek){ + if (y > params.seek.y){ + S.this_cursor = S.prev_cursor; + goto buffer_cursor_seek_end; + } + + if (y > params.seek.y - params.font_height && x >= params.seek.x){ + if (!params.seek.round_down){ + if (py >= y && S.ch != '\n' && (params.seek.x - px) < (x - params.seek.x)){ + S.this_cursor = S.prev_cursor; + } + goto buffer_cursor_seek_end; + } + + if (py >= y){ S.this_cursor = S.prev_cursor; } goto buffer_cursor_seek_end; } - - if (py >= y){ - S.this_cursor = S.prev_cursor; - } + } + + if (S.next_cursor.pos > S.size){ goto buffer_cursor_seek_end; } } - - if (S.next_cursor.pos > S.size){ - goto buffer_cursor_seek_end; - } } S.still_looping = buffer_stringify_next(&S.stream); }while(S.still_looping); @@ -1697,8 +1931,8 @@ enum Buffer_Render_Flag{ typedef struct Buffer_Render_Item{ i32 index; - u16 glyphid; - u16 flags; + u32 glyphid; + u32 flags; f32 x0, y0; f32 x1, y1; } Buffer_Render_Item; @@ -1713,7 +1947,7 @@ typedef struct Render_Item_Write{ } Render_Item_Write; inline Render_Item_Write -write_render_item(Render_Item_Write write, i32 index, u16 glyphid, u16 flags){ +write_render_item(Render_Item_Write write, i32 index, u32 glyphid, u32 flags){ f32 ch_width = write.adv[(u8)glyphid]; if (write.x <= write.x_max && write.x + ch_width >= write.x_min){ @@ -1749,7 +1983,8 @@ struct Buffer_Render_Params{ Full_Cursor start_cursor; i32 wrapped; f32 font_height; - f32 *adv; + f32 *cp_adv; + f32 byte_adv; b32 virtual_white; i32 wrap_slashes; }; @@ -1758,6 +1993,10 @@ struct Buffer_Render_State{ Gap_Buffer_Stream stream; b32 still_looping; i32 i; + i32 size; + + f32 shift_x; + f32 shift_y; f32 ch_width; u8 ch; @@ -1770,6 +2009,8 @@ struct Buffer_Render_State{ b32 first_of_the_line; i32 wrap_unit_end; + Buffer_Translating_State tran; + i32 __pc__; }; @@ -1783,17 +2024,6 @@ buffer_render_data(Buffer_Render_State *S_ptr, Buffer_Render_Params params, f32 Buffer_Render_State S = *S_ptr; Buffer_Layout_Stop S_stop; - i32 size = buffer_size(params.buffer); - f32 shift_x = params.port_x - params.scroll_x; - f32 shift_y = params.port_y - params.scroll_y; - - if (params.wrapped){ - shift_y += params.start_cursor.wrapped_y; - } - else{ - shift_y += params.start_cursor.unwrapped_y; - } - Buffer_Render_Item *item_end = params.items + params.max; switch (S.__pc__){ @@ -1803,6 +2033,17 @@ buffer_render_data(Buffer_Render_State *S_ptr, Buffer_Render_Params params, f32 DrCase(4); } + S.size = buffer_size(params.buffer); + S.shift_x = params.port_x - params.scroll_x; + S.shift_y = params.port_y - params.scroll_y; + + if (params.wrapped){ + S.shift_y += params.start_cursor.wrapped_y; + } + else{ + S.shift_y += params.start_cursor.unwrapped_y; + } + S.line = params.start_cursor.line - 1; S.wrap_line = params.start_cursor.wrap_line - 1; @@ -1814,9 +2055,9 @@ buffer_render_data(Buffer_Render_State *S_ptr, Buffer_Render_Params params, f32 } S.write.item = params.items; - S.write.x = shift_x + line_shift; - S.write.y = shift_y; - S.write.adv = params.adv; + S.write.x = S.shift_x + line_shift; + S.write.y = S.shift_y; + S.write.adv = params.cp_adv; S.write.font_height = params.font_height; S.write.x_min = params.port_x; S.write.x_max = params.port_x + params.clip_w; @@ -1827,136 +2068,141 @@ buffer_render_data(Buffer_Render_State *S_ptr, Buffer_Render_Params params, f32 S.first_of_the_line = 1; S.i = params.start_cursor.pos; - if (buffer_stringify_loop(&S.stream, params.buffer, S.i, size)){ + if (buffer_stringify_loop(&S.stream, params.buffer, S.i, S.size)){ do{ for (; S.i < S.stream.end; ++S.i){ S.ch = (u8)S.stream.data[S.i]; - S.ch_width = params.adv[S.ch]; + translating_consume_byte(&S.tran, S.ch, S.i, S.size); - if (S.ch != '\n' && S.i >= S.wrap_unit_end){ - S_stop.status = BLStatus_NeedWrapDetermination; - S_stop.line_index = S.line; - S_stop.wrap_line_index = S.wrap_line; - S_stop.pos = S.i; - S_stop.x = S.write.x - shift_x; - DrYield(4, S_stop); + for (TRANSLATION_OUTPUT(&S.tran)){ + TRANSLATION_GET_STEP(&S.tran); - S.wrap_unit_end = wrap_unit_end; - - if (do_wrap && !S.first_of_the_line){ - if (params.virtual_white){ - S_stop.status = BLStatus_NeedWrapLineShift; - S_stop.line_index = S.line; - S_stop.wrap_line_index = S.wrap_line + 1; - DrYield(2, S_stop); - } + if (!S.tran.do_newline && S.tran.step_current.i >= S.wrap_unit_end){ + S_stop.status = BLStatus_NeedWrapDetermination; + S_stop.line_index = S.line; + S_stop.wrap_line_index = S.wrap_line; + S_stop.pos = S.tran.step_current.i; + S_stop.x = S.write.x - S.shift_x; + DrYield(4, S_stop); - ++S.wrap_line; + S.wrap_unit_end = wrap_unit_end; - if (params.wrapped){ - switch (params.wrap_slashes){ - case WrapIndicator_Show_After_Line: - { - S.write = write_render_item(S.write, S.i-1, '\\', BRFlag_Ghost_Character); - }break; - - case WrapIndicator_Show_At_Wrap_Edge: - { - if (S.write.x < shift_x + params.width){ - S.write.x = shift_x + params.width; - } - S.write = write_render_item(S.write, S.i-1, '\\', BRFlag_Ghost_Character); - }break; - } - - S.write.x = shift_x + line_shift; - S.write.y += params.font_height; - } - } - } - - if (S.write.y > params.height + params.port_y){ - goto buffer_get_render_data_end; - } - - if (S.ch != ' ' && S.ch != '\t'){ - S.skipping_whitespace = 0; - } - - if (!S.skipping_whitespace){ - S.first_of_the_line = 0; - switch (S.ch){ - case '\n': - if (S.write.item < item_end){ - S.write = write_render_item(S.write, S.i, ' ', 0); - + if (do_wrap && !S.first_of_the_line){ if (params.virtual_white){ - S_stop.status = BLStatus_NeedLineShift; - S_stop.line_index = S.line+1; - S_stop.wrap_line_index = S.wrap_line+1; - DrYield(3, S_stop); - - S.skipping_whitespace = 1; + S_stop.status = BLStatus_NeedWrapLineShift; + S_stop.line_index = S.line; + S_stop.wrap_line_index = S.wrap_line + 1; + DrYield(2, S_stop); } - ++S.line; ++S.wrap_line; - S.write.x = shift_x + line_shift; - S.write.y += params.font_height; - - S.first_of_the_line = 1; + if (params.wrapped){ + switch (params.wrap_slashes){ + case WrapIndicator_Show_After_Line: + { + S.write = write_render_item(S.write, S.tran.step_current.i-1, '\\', BRFlag_Ghost_Character); + }break; + + case WrapIndicator_Show_At_Wrap_Edge: + { + if (S.write.x < S.shift_x + params.width){ + S.write.x = S.shift_x + params.width; + } + S.write = write_render_item(S.write, S.tran.step_current.i-1, '\\', BRFlag_Ghost_Character); + }break; + } + + S.write.x = S.shift_x + line_shift; + S.write.y += params.font_height; + } } - break; + } + + if (S.write.y > params.height + params.port_y || S.write.item >= item_end){ + goto buffer_get_render_data_end; + } + + S.first_of_the_line = false; + if (S.tran.do_newline){ + S.write = write_render_item(S.write, S.tran.step_current.i, ' ', 0); - case '\r': - if (S.write.item < item_end){ - S.write = write_render_item(S.write, S.i, '\\', BRFlag_Special_Character); + if (params.virtual_white){ + S_stop.status = BLStatus_NeedLineShift; + S_stop.line_index = S.line+1; + S_stop.wrap_line_index = S.wrap_line+1; + DrYield(3, S_stop); + S.skipping_whitespace = 1; + } + + ++S.line; + ++S.wrap_line; + + S.write.x = S.shift_x + line_shift; + S.write.y += params.font_height; + + S.first_of_the_line = true; + } + else if (S.tran.do_codepoint_advance){ + u32 n = S.tran.step_current.value; + if (n != ' ' && n != '\t'){ + S.skipping_whitespace = false; + } + + if (!S.skipping_whitespace){ + u32 I = S.tran.step_current.i; + switch (n){ + case '\r': + { + S.write = write_render_item(S.write, I, '\\', BRFlag_Special_Character); + if (S.write.item < item_end){ + S.write = write_render_item(S.write, I, 'r', BRFlag_Special_Character); + } + }break; + + case '\t': + { + S.ch_width = params.cp_adv['\t']; + f32 new_x = S.write.x + S.ch_width; + S.write = write_render_item(S.write, I, ' ', 0); + S.write.x = new_x; + }break; + + default: + { + S.write = write_render_item(S.write, I, n, 0); + }break; + } + } + } + else if (S.tran.do_number_advance){ + u8 n = (u8)S.tran.step_current.value; + u32 I = S.tran.step_current.i; + S.skipping_whitespace = false; + + S.ch_width = params.byte_adv; + f32 new_x = S.write.x + S.ch_width; + + u8 cs[3]; + cs[0] = '\\'; + byte_to_ascii(n, cs+1); + + if (S.write.item < item_end){ + S.write = write_render_item(S.write, I, cs[0], BRFlag_Special_Character); if (S.write.item < item_end){ - S.write = write_render_item(S.write, S.i, 'r', BRFlag_Special_Character); - } - } - break; - - case '\t': - if (S.write.item < item_end){ - f32 new_x = S.write.x + S.ch_width; - S.write = write_render_item(S.write, S.i, ' ', 0); - S.write.x = new_x; - } - break; - - default: - if (S.write.item < item_end){ - if (S.ch >= ' ' && S.ch <= 256 && S.ch != 127){ - S.write = write_render_item(S.write, S.i, S.ch, 0); - } - else{ - S.write = write_render_item(S.write, S.i, '\\', BRFlag_Special_Character); - - u8 ch = S.ch; - char C = '0' + (ch / 0x10); - if ((ch / 0x10) > 0x9){ - C = ('A' - 0xA) + (ch / 0x10); - } - + S.write = write_render_item(S.write, I, cs[1], BRFlag_Special_Character); if (S.write.item < item_end){ - S.write = write_render_item(S.write, S.i, C, BRFlag_Special_Character); - } - - ch = (ch % 0x10); - C = '0' + ch; - if (ch > 0x9){ - C = ('A' - 0xA) + ch; - } - - if (S.write.item < item_end){ - S.write = write_render_item(S.write, S.i, C, BRFlag_Special_Character); + S.write = write_render_item(S.write, I, cs[2], BRFlag_Special_Character); } } } - break; + Assert(S.write.x <= new_x); + S.write.x = new_x; + } + + if (!S.skipping_whitespace && !S.tran.do_newline){ + S.first_of_the_line = false; } } } @@ -1965,9 +2211,9 @@ buffer_render_data(Buffer_Render_State *S_ptr, Buffer_Render_Params params, f32 } buffer_get_render_data_end:; - if (S.write.y <= params.height + shift_y || S.write.item == params.items){ + if (S.write.y <= params.height + S.shift_y || S.write.item == params.items){ if (S.write.item < item_end){ - S.write = write_render_item(S.write, size, ' ', 0); + S.write = write_render_item(S.write, S.size, ' ', 0); } } diff --git a/linux_4ed.cpp b/linux_4ed.cpp index a9522eb0..6f6cbc1c 100644 --- a/linux_4ed.cpp +++ b/linux_4ed.cpp @@ -357,6 +357,9 @@ Sys_Set_File_List_Sig(system_set_file_list){ if (d){ if (canon_directory_out != 0){ u32 length = copy_fast_unsafe_cc(canon_directory_out, directory); + if (canon_directory_out[length-1] != '/'){ + canon_directory_out[length++] = '/'; + } canon_directory_out[length] = 0; *canon_directory_size_out = length; } @@ -2653,11 +2656,11 @@ LinuxHandleX11Events(void) fputs("FIXME: XBufferOverflow from LookupString.\n", stderr); } - u16 key = utf8_to_u32_unchecked(buff); - u16 key_no_caps = key; + u32 key = utf8_to_u32_unchecked(buff); + u32 key_no_caps = key; if(mods[MDFR_CAPS_INDEX] && status == XLookupBoth && Event.xkey.keycode){ - u8 buff_no_caps[32] = {}; + u8 buff_no_caps[32] = {0}; Event.xkey.state &= ~(LockMask); XLookupString( @@ -2669,7 +2672,7 @@ LinuxHandleX11Events(void) ); if(*buff_no_caps){ - key_no_caps = utf8_to_u16_unchecked(buff_no_caps); + key_no_caps = utf8_to_u32_unchecked(buff_no_caps); } } diff --git a/power/4coder_experiments.cpp b/power/4coder_experiments.cpp index 812fd754..6e1ec0a8 100644 --- a/power/4coder_experiments.cpp +++ b/power/4coder_experiments.cpp @@ -19,6 +19,7 @@ TYPE: 'build-target' # define BIND_4CODER_TESTS(context) ((void)context) #endif +#include #include static float @@ -1344,6 +1345,27 @@ CUSTOM_COMMAND_SIG(write_explicit_enum_values){ end_temp_memory(temp); } +CUSTOM_COMMAND_SIG(punishment){ + Theme_Color colors[4]; + colors[0].tag = Stag_Back; + colors[1].tag = Stag_Margin; + colors[2].tag = Stag_Margin_Hover; + colors[3].tag = Stag_Margin_Active; + get_theme_colors(app, colors, 4); + + for (uint32_t i = 0; i < 4; ++i){ + int_color color = colors[i].color; + uint8_t *c = (uint8_t*)(&color); + c[0] = 0xFF - c[0]; + c[1] = 0xFF - c[1]; + c[2] = 0xFF - c[2]; + c[3] = 0xFF - c[3]; + colors[i].color = color; + } + + set_theme_colors(app, colors, 4); +} + extern "C" int32_t get_bindings(void *data, int32_t size){ Bind_Helper context_ = begin_bind_helper(data, size); @@ -1370,6 +1392,9 @@ get_bindings(void *data, int32_t size){ end_map(context); begin_map(context, mapid_file); + bind(context, 's', MDFR_CTRL, punishment); + bind(context, 's', MDFR_ALT, save); + bind(context, 'k', MDFR_ALT, kill_rect); bind(context, ' ', MDFR_ALT | MDFR_CTRL, multi_line_edit); diff --git a/win32_4ed.cpp b/win32_4ed.cpp index c35d4b38..b0635a68 100644 --- a/win32_4ed.cpp +++ b/win32_4ed.cpp @@ -768,7 +768,7 @@ Sys_Set_File_List_Sig(system_set_file_list){ if (canon_directory_out != 0){ if (final_length+1 < canon_directory_max){ memcpy(canon_directory_out, c_str_dir, final_length); - if (char_is_slash(dir.str[dir.size-1]) && canon_directory_out[final_length-1] != '\\'){ + if (canon_directory_out[final_length-1] != '\\'){ canon_directory_out[final_length++] = '\\'; } canon_directory_out[final_length] = 0;