/* ======================================================================== $File: work/apps/4coder/custom/4coder_casey_pending.cpp $ $Date: 2019/03/30 23:57:38 UTC $ $Revision: 21 $ $Creator: Casey Muratori $ $Notice: (C) Copyright by Molly Rocket, Inc., All Rights Reserved. $ ======================================================================== */ /* NOTE(casey): Allen, this is a file full of things that I think 4coder should have provided natively, so unless there's something objectionable about them, I think they could be merged? */ #include static Range clip_range_to_width(Range range, int32_t max_width) { Range result = range; if((result.start + max_width) < result.end) { result.end = result.start + max_width; } return(result); } #define CStrCase(a) case a: return(#a) #define StringCase(a) case a: return(make_lit_string(#a)) // TODO(casey): Merge this with Allen's Token_Iterator when it's ready? struct token_iterator { Buffer_ID buffer; bool32 valid; int32_t index; }; #if 0 static void Append(Found_String_List *dest, Found_String_List source) { if(dest->last) { dest->last->next = source.first; dest->last = source.last; dest->count += source.count; } else { *dest = source; } } #endif static Vec2 center_of(f32_Rect a) { Vec2 result; result.x = 0.5f*(a.x0 + a.x1); result.y = 0.5f*(a.y0 + a.y1); return(result); } static f32_Rect f32_rect_from(i32_Rect a) { f32_Rect result; result.x0 = (float)a.x0; result.x1 = (float)a.x1; result.y0 = (float)a.y0; result.y1 = (float)a.y1; return(result); } static i32_Rect i32_rect_from(f32_Rect a) { i32_Rect result; result.x0 = round32(a.x0); result.x1 = round32(a.x1); result.y0 = round32(a.y0); result.y1 = round32(a.y1); return(result); } static bool32 is_valid(Range range) { bool32 result = (range.start < range.one_past_last); return(result); } static bool32 is_in(f32_Rect a, Vec2 p) { bool32 result = ((p.x >= a.x0) && (p.x < a.x1) && (p.y >= a.y0) && (p.y < a.y1)); return(result); } static bool32 is_visible(View_Summary *view, Vec2 p) { bool32 result = is_in(f32_rect_from(view->render_region), p); return(result); } static token_iterator iterate_tokens(Application_Links *app, Buffer_ID buffer, int32_t absolute_position) { token_iterator iter = {}; iter.buffer = buffer; Cpp_Get_Token_Result temp; iter.valid = buffer_get_token_index(app, buffer, absolute_position, &temp); if(iter.valid) { iter.index = temp.token_index; } return(iter); } static Cpp_Token get_next_token(Application_Links *app, token_iterator *iter) { Cpp_Token result = {}; if(buffer_read_tokens(app, iter->buffer, iter->index, iter->index + 1, &result)) { ++iter->index; } else { iter->valid = false; } return(result); } static Cpp_Token peek_token(Application_Links *app, token_iterator *iter) { Cpp_Token result = {}; buffer_read_tokens(app, iter->buffer, iter->index, iter->index + 1, &result); return(result); } static Cpp_Token get_prev_token(Application_Links *app, token_iterator *iter) { Cpp_Token result = {}; if(buffer_read_tokens(app, iter->buffer, iter->index, iter->index + 1, &result)) { --iter->index; } else { iter->valid = false; } return(result); } static String scratch_read(Application_Links *app, Arena *scratch, Buffer_ID buffer, int32_t start, int32_t end) { String result = {}; if(start <= end) { int32_t len = end - start; result = push_string_space(scratch, len); if(buffer_read_range(app, buffer, start, end, result.str)) { result.size = len; } } return(result); } static String scratch_read(Application_Links *app, Arena *scratch, Buffer_ID buffer, Range location) { String result = scratch_read(app, scratch, buffer, location.start, location.one_past_last); return(result); } static String scratch_read(Application_Links *app, Arena *scratch, Buffer_ID buffer, Cpp_Token token) { String result = scratch_read(app, scratch, buffer, token.start, token.start + token.size); return(result); } static bool32 token_text_is(Application_Links *app, Buffer_Summary *buffer, Cpp_Token token, String match) { Scratch_Block scratch(app); String text = scratch_read(app, scratch, buffer->buffer_id, token.start, token.start + token.size); bool32 result = (compare_ss(text, match) == 0); return(result); } static Range token_range_from_abs(Application_Links *app, Buffer_ID buffer, int32_t pos, bool32 favor_forward) { Range result = {}; Cpp_Get_Token_Result get; if(buffer_get_token_index(app, buffer, pos, &get)) { if(favor_forward && get.in_whitespace_after_token) { Cpp_Token token; buffer_read_tokens(app, buffer, get.token_index + 1, get.token_index + 2, &token); result = make_range(token.start, token.start + token.size); } else { result = make_range(get.token_start, get.token_one_past_last); } } return(result); } static int32_t line_from_abs(Application_Links *app, Buffer_ID buffer, int32_t pos) { int32_t Result = 0; Buffer_Seek seek = {}; seek.type = buffer_seek_pos; seek.pos = pos; Partial_Cursor at; if(buffer_compute_cursor(app, buffer, seek, &at)) { Result = at.line; } return(Result); } static i32 abs_from_seek(Application_Links *app, Buffer_ID buffer, Buffer_Seek seek) { i32 Result = 0; // TODO(casey): I feel like there need to be faster methods for round-tripping through the (column/line <-> pos) routes. Partial_Cursor at; if(buffer_compute_cursor(app, buffer, seek, &at)) { Result = at.pos; } return(Result); } static int32_t line_from_abs(Application_Links *app, Buffer_Summary *buffer, int32_t pos) { int32_t Result = 0; Buffer_Seek seek = {}; seek.type = buffer_seek_pos; seek.pos = pos; Partial_Cursor at; if(buffer_compute_cursor(app, buffer, seek, &at)) { Result = at.line; } return(Result); } static int32_t line_from_abs(Application_Links *app, View_Summary *view, int32_t pos) { int32_t Result = 0; Buffer_Seek seek = {}; seek.type = buffer_seek_pos; seek.pos = pos; Full_Cursor at; if(view_compute_cursor(app, view, seek, &at)) { Result = at.line; } return(Result); } static bool32 cursor_from_abs(Application_Links *app, View_Summary *view, int32_t pos, Full_Cursor *cursor) { Buffer_Seek seek = {}; seek.type = buffer_seek_pos; seek.pos = pos; bool32 result = view_compute_cursor(app, view, seek, cursor); return(result); } // TODO(casey): Rename these now that they are "render space", not screen space static Vec2 screen_p_from(View_Summary *view, Full_Cursor *at) { Vec2 Result = {}; Result.x = (float)at->wrapped_x - (float)view->scroll_vars.scroll_x; Result.y = (float)at->wrapped_y - (float)view->scroll_vars.scroll_y; return(Result); } static Vec2 screen_p_from_abs(Application_Links *app, View_Summary *view, int32_t pos) { Vec2 Result = {}; Full_Cursor at; if(cursor_from_abs(app, view, pos, &at)) { Result = screen_p_from(view, &at); } return(Result); } static String read_entire_file(Partition *arena, char *filename) { String result = {}; FILE *file = fopen(filename, "rb"); if(file) { fseek(file, 0, SEEK_END); // TODO(casey): Can't we have 64-bit sized strings? :( i32_4tech size = (i32_4tech)ftell(file); fseek(file, 0, SEEK_SET); result = string_push(arena, (i32_4tech)size); if(result.str) { result.size = size; fread(result.str, result.size, 1, file); } fclose(file); } return(result); } static void draw_line(Application_Links *app, Vec2 from, Vec2 to, int_color color, float thickness) { // TODO(casey): Allen, this should eventually be an actual line primitive, for non-rectangular lines float half = 0.5f*thickness; f32_Rect rect; rect.x0 = Min(from.x, to.x) - half; rect.x1 = Max(from.x, to.x) + half; rect.y0 = Min(from.y, to.y) - half; rect.y1 = Max(from.y, to.y) + half; draw_rectangle(app, rect, color); } static void draw_line_loop(Application_Links *app, int32_t p_count, Vec2 *p, int_color color, float thickness) { if(p_count) { int32_t prev = p_count - 1; for(int32_t i = 0; i < p_count; ++i) { draw_line(app, p[prev], p[i], color, thickness); prev = i; } } } static float get_dpi_scaling_value(Application_Links *app) { // TODO(casey): Allen, this should return the multiplier for the display relative to whatever 4coder // gets tuned to. float result = 2.0f; return(result); } static f32_Rect minkowski_sum(f32_Rect a, Vec2 b) { f32_Rect r = a; r.x0 -= b.x; r.x1 += b.x; r.x0 -= b.y; r.x1 += b.y; return(r); } static f32_Rect minkowski_sum(f32_Rect a, f32 b) { f32_Rect r = minkowski_sum(a, V2(b, b)); return(r); } static void clear_buffer(Application_Links *app, Buffer_ID buffer_id) { Buffer_Summary buffer = get_buffer(app, buffer_id, AccessAll); if(buffer.exists) { buffer_replace_range(app, buffer_id, 0, buffer.size, empty_string); } } static int32_t get_end_of_line(Application_Links *app, Buffer_ID buffer, int32_t from) { int32_t result = from; Partial_Cursor line; if(buffer_compute_cursor(app, buffer, seek_pos(from), &line)) { Partial_Cursor eol; if(buffer_compute_cursor(app, buffer, seek_line_char(line.line, max_i32), &eol)) { result = eol.pos; } } return(result); } enum Coordinate { Coordinate_X = 0, Coordinate_Y = 1, }; enum Side { Side_Min = 0, Side_Max = 1, }; static f32_Rect_Pair split_rect(f32_Rect rect, View_Split_Kind kind, Coordinate coord, Side from_side, f32 t) { f32_Rect_Pair result; if(kind == ViewSplitKind_FixedPixels) { result.E[0] = rect; result.E[1] = rect; if(coord == Coordinate_X) { result.E[0].x1 = (from_side == Side_Max) ? (rect.x1 - t) : (rect.x0 + t); result.E[1].x0 = result.E[0].x1; } else { Assert(coord == Coordinate_Y); result.E[0].y1 = (from_side == Side_Max) ? (rect.y1 - t) : (rect.y0 + t); result.E[1].y0 = result.E[0].y1; } } else { Assert(kind == ViewSplitKind_Ratio); f32 pixel_count; if(coord == Coordinate_X) { pixel_count = t*(rect.x1 - rect.x0); } else { Assert(coord == Coordinate_Y); pixel_count = t*(rect.y1 - rect.y0); } result = split_rect(rect, ViewSplitKind_FixedPixels, coord, from_side, pixel_count); } return(result); }