diff --git a/src/eval/eval_parse.c b/src/eval/eval_parse.c index 5a7dcebc..f84126ce 100644 --- a/src/eval/eval_parse.c +++ b/src/eval/eval_parse.c @@ -1177,20 +1177,28 @@ e_push_parse_from_string_tokens__prec(Arena *arena, String8 text, E_TokenArray t // rjf: look for member name E_Token member_name_maybe = e_token_at_it(it, &tokens); String8 member_name_maybe_string = str8_substr(text, member_name_maybe.range); + B32 member_name_is_good = (member_name_maybe.kind == E_TokenKind_Identifier); - // rjf: if we have a member name, build dot-operator tree - if(member_name_maybe.kind == E_TokenKind_Identifier) + // rjf: build dot-operator tree + E_Expr *lhs = atom; + E_Expr *rhs = &e_expr_nil; + if(member_name_is_good) { - it += 1; - E_Expr *lhs = atom; - E_Expr *rhs = e_push_expr(arena, E_ExprKind_LeafIdentifier, member_name_maybe.range); + rhs = e_push_expr(arena, E_ExprKind_LeafIdentifier, member_name_maybe.range); rhs->string = member_name_maybe_string; - atom = e_push_expr(arena, E_ExprKind_MemberAccess, token.range); - e_expr_push_child(atom, lhs); + } + atom = e_push_expr(arena, E_ExprKind_MemberAccess, token.range); + e_expr_push_child(atom, lhs); + if(member_name_is_good) + { e_expr_push_child(atom, rhs); } // rjf: no identifier after `.`? -> error + if(member_name_is_good) + { + it += 1; + } else { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token.range, "Missing member name after `%S`.", token_string); diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 1f108d6f..5622f84d 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -3578,13 +3578,12 @@ rd_view_ui(Rng2F32 rect) if(autocomplete_hint_string.size != 0) { take_autocomplete = 1; - String8 word_query = rd_lister_query_word_from_input_string_off(string, edit_state->cursor.column-1); - U64 word_off = (U64)(word_query.str - string.str); - String8 new_string = ui_push_string_replace_range(scratch.arena, string, r1s64(word_off+1, word_off+1+word_query.size), autocomplete_hint_string); + RD_AutocompCursorInfo autocomp_cursor_info = rd_autocomp_cursor_info_from_input_string_off(scratch.arena, string, edit_state->cursor.column-1); + String8 new_string = ui_push_string_replace_range(scratch.arena, string, r1s64(autocomp_cursor_info.replaced_range.min+1, autocomp_cursor_info.replaced_range.max+1), autocomplete_hint_string); new_string.size = Min(sizeof(edit_state->input_buffer), new_string.size); MemoryCopy(edit_state->input_buffer, new_string.str, new_string.size); edit_state->input_size = new_string.size; - edit_state->cursor = edit_state->mark = txt_pt(1, word_off+1+autocomplete_hint_string.size); + edit_state->cursor = edit_state->mark = txt_pt(1, 1+autocomp_cursor_info.replaced_range.min+autocomplete_hint_string.size); string = str8(edit_state->input_buffer, edit_state->input_size); op = ui_single_line_txt_op_from_event(scratch.arena, evt, string, edit_state->cursor, edit_state->mark); } @@ -4956,7 +4955,10 @@ rd_view_ui(Rng2F32 rect) txt_pt_match(cell_edit_state->cursor, cell_edit_state->mark)) { String8 input = str8(cell_edit_state->input_buffer, cell_edit_state->input_size); - rd_set_autocomp_regs(.ui_key = sig.box->key, .string = input, .cursor = cell_edit_state->cursor); + RD_AutocompCursorInfo cursor_info = rd_autocomp_cursor_info_from_input_string_off(scratch.arena, input, cell_edit_state->cursor.column-1); + rd_set_autocomp_regs(.ui_key = sig.box->key, + .string = cursor_info.filter, + .expr = cursor_info.list_expr); } } } @@ -6663,7 +6665,7 @@ rd_window_frame(void) RD_Cfg *input = rd_cfg_child_from_string_or_alloc(query, str8_lit("input")); rd_cfg_new_replace(input, ws->autocomp_regs->string); RD_Cfg *expr = rd_cfg_child_from_string_or_alloc(view, str8_lit("expression")); - rd_cfg_new_replacef(expr, "query:locals, query:globals, query:thread_locals, query:procedures, query:types"); + rd_cfg_new_replace(expr, ws->autocomp_regs->expr); // rjf: determine container size EV_BlockTree predicted_block_tree = {0}; @@ -9722,8 +9724,85 @@ rd_set_hover_eval(Vec2F32 pos, String8 string) //////////////////////////////// //~ rjf: Autocompletion Lister +internal RD_AutocompCursorInfo +rd_autocomp_cursor_info_from_input_string_off(Arena *arena, String8 input, U64 cursor_off) +{ + RD_AutocompCursorInfo result = {0}; + { + result.list_expr = str8_lit("query:locals, query:globals, query:thread_locals, query:procedures, query:types"); + result.filter = input; + result.replaced_range = r1u64(0, input.size); + } + Temp scratch = scratch_begin(&arena, 1); + E_Parse parse = e_parse_from_string(input); + + //- rjf: cursor offset -> cursor containing node + E_Expr *cursor_expr = &e_expr_nil; + E_Expr *cursor_expr_parent = &e_expr_nil; + { + typedef struct ExprWalkTask ExprWalkTask; + struct ExprWalkTask + { + ExprWalkTask *next; + E_Expr *parent; + E_Expr *expr; + }; + ExprWalkTask start_task = {0, &e_expr_nil, parse.expr}; + ExprWalkTask *first_task = &start_task; + ExprWalkTask *last_task = first_task; + for(E_Expr *chain = parse.expr->next; chain != &e_expr_nil; chain = chain->next) + { + ExprWalkTask *task = push_array(scratch.arena, ExprWalkTask, 1); + SLLQueuePush(first_task, last_task, task); + task->parent = &e_expr_nil; + task->expr = chain; + } + for(ExprWalkTask *t = first_task; t != 0; t = t->next) + { + E_Expr *e = t->expr; + if(contains_1u64(e->range, cursor_off) || cursor_off == e->range.max) + { + cursor_expr_parent = t->parent; + cursor_expr = e; + break; + } + for(E_Expr *child = e->first; child != &e_expr_nil; child = child->next) + { + ExprWalkTask *task = push_array(scratch.arena, ExprWalkTask, 1); + SLLQueuePush(first_task, last_task, task); + task->parent = e; + task->expr = child; + } + } + } + + //- rjf: cursor is on right-hand-side of dot? -> show members of left-hand-side + { + E_Expr *dot_expr = &e_expr_nil; + if(cursor_expr->kind == E_ExprKind_MemberAccess && cursor_off == cursor_expr->range.max) + { + dot_expr = cursor_expr; + } + else if(cursor_expr_parent->kind == E_ExprKind_MemberAccess && cursor_expr == cursor_expr_parent->first->next) + { + dot_expr = cursor_expr_parent; + } + if(dot_expr != &e_expr_nil) + { + E_Eval lhs_eval = e_eval_from_expr(dot_expr->first); + E_Eval type_of_lhs_eval = e_eval_wrapf(lhs_eval, "typeof($)"); + result.list_expr = e_full_expr_string_from_key(arena, type_of_lhs_eval.key); + result.filter = cursor_expr->string; + result.replaced_range = union_1u64(dot_expr->range, cursor_expr->range); + } + } + + scratch_end(scratch); + return result; +} + internal String8 -rd_lister_query_word_from_input_string_off(String8 input, U64 cursor_off) +rd_autocomp_query_word_from_input_string_off(String8 input, U64 cursor_off) { U64 word_start_off = 0; for(U64 off = 0; off < input.size && off < cursor_off; off += 1) diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index bb05d6ed..9b3a9415 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -162,6 +162,17 @@ enum RD_CmdKindFlag_ListInTextRng = (1<<4), }; +//////////////////////////////// +//~ rjf: Autocompletion Cursor Info Type + +typedef struct RD_AutocompCursorInfo RD_AutocompCursorInfo; +struct RD_AutocompCursorInfo +{ + String8 list_expr; + String8 filter; + Rng1U64 replaced_range; +}; + //////////////////////////////// //~ rjf: Generated Code @@ -951,7 +962,8 @@ internal void rd_set_hover_eval(Vec2F32 pos, String8 string); //////////////////////////////// //~ rjf: Autocompletion Lister -internal String8 rd_lister_query_word_from_input_string_off(String8 input, U64 cursor_off); +internal RD_AutocompCursorInfo rd_autocomp_cursor_info_from_input_string_off(Arena *arena, String8 input, U64 cursor_off); +internal String8 rd_autocomp_query_word_from_input_string_off(String8 input, U64 cursor_off); internal void rd_set_autocomp_regs_(RD_Regs *regs); #define rd_set_autocomp_regs(...) rd_set_autocomp_regs_(&(RD_Regs){rd_regs_lit_init_top __VA_ARGS__}) diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index a0563509..8e9631d0 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -1689,14 +1689,10 @@ rd_info_from_watch_row_cell(Arena *arena, EV_Row *row, EV_StringFlags string_fla // do a code-string of ".member_name" String8 member_name = notable_expr->first->next->string; String8 fancy_name = {0}; - if(str8_match(member_name, str8_lit("$padding"), StringMatchFlag_RightSideSloppy)) - { - fancy_name = str8_lit("Padding"); - } - else if(cell->eval.space.kind == RD_EvalSpaceKind_MetaCfg || - cell->eval.space.kind == RD_EvalSpaceKind_MetaCtrlEntity || - cell->eval.space.kind == E_SpaceKind_File || - cell->eval.space.kind == E_SpaceKind_FileSystem) + if(cell->eval.space.kind == RD_EvalSpaceKind_MetaCfg || + cell->eval.space.kind == RD_EvalSpaceKind_MetaCtrlEntity || + cell->eval.space.kind == E_SpaceKind_File || + cell->eval.space.kind == E_SpaceKind_FileSystem) { fancy_name = rd_display_from_code_name(member_name); } diff --git a/src/raddbg/raddbg_widgets.c b/src/raddbg/raddbg_widgets.c index 1fcd8b6e..35710899 100644 --- a/src/raddbg/raddbg_widgets.c +++ b/src/raddbg/raddbg_widgets.c @@ -3576,13 +3576,12 @@ rd_cell(RD_CellParams *params, String8 string) // rjf: any valid op & autocomplete hint? -> perform autocomplete first, then re-compute op if(autocomplete_hint_string.size != 0) { - String8 word_query = rd_lister_query_word_from_input_string_off(edit_string, params->cursor->column-1); - U64 word_off = (U64)(word_query.str - edit_string.str); - String8 new_string = ui_push_string_replace_range(scratch.arena, edit_string, r1s64(word_off+1, word_off+1+word_query.size), autocomplete_hint_string); + RD_AutocompCursorInfo autocomp_cursor_info = rd_autocomp_cursor_info_from_input_string_off(scratch.arena, edit_string, params->cursor->column-1); + String8 new_string = ui_push_string_replace_range(scratch.arena, edit_string, r1s64(autocomp_cursor_info.replaced_range.min+1, autocomp_cursor_info.replaced_range.max+1), autocomplete_hint_string); new_string.size = Min(params->edit_buffer_size, new_string.size); MemoryCopy(params->edit_buffer, new_string.str, new_string.size); params->edit_string_size_out[0] = new_string.size; - params->cursor[0] = params->mark[0] = txt_pt(1, word_off+1+autocomplete_hint_string.size); + params->cursor[0] = params->mark[0] = txt_pt(1, 1+autocomp_cursor_info.replaced_range.min+autocomplete_hint_string.size); edit_string = str8(params->edit_buffer, params->edit_string_size_out[0]); op = ui_single_line_txt_op_from_event(scratch.arena, evt, edit_string, params->cursor[0], params->mark[0]); MemoryZeroStruct(&autocomplete_hint_string); @@ -3652,8 +3651,8 @@ rd_cell(RD_CellParams *params, String8 string) DR_FStrList code_fstrs = rd_fstrs_from_code_string(scratch.arena, 1.f, 0, ui_color_from_name(str8_lit("text")), edit_string); if(autocomplete_hint_string.size != 0) { - String8 query_word = rd_lister_query_word_from_input_string_off(edit_string, params->cursor->column-1); - String8 autocomplete_append_string = str8_skip(autocomplete_hint_string, query_word.size); + RD_AutocompCursorInfo autocomp_cursor_info = rd_autocomp_cursor_info_from_input_string_off(scratch.arena, edit_string, params->cursor->column-1); + String8 autocomplete_append_string = str8_skip(autocomplete_hint_string, params->cursor->column-1 - autocomp_cursor_info.replaced_range.min); U64 off = 0; U64 cursor_off = params->cursor->column-1; DR_FStrNode *prev_n = 0;