From 5bb89e24600d87935c3b545d0e6c322725a4c7d1 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Thu, 3 Oct 2019 13:54:13 -0700 Subject: [PATCH] New and improved auto-indentation! Fixed some token iteration and boundary seeking bugs --- custom/4coder_auto_indent.cpp | 683 ++++++++-------------- custom/4coder_auto_indent.h | 26 +- custom/4coder_base_types.cpp | 17 + custom/4coder_combined_write_commands.cpp | 2 +- custom/4coder_default_hooks.cpp | 3 +- custom/4coder_helper.cpp | 75 +-- custom/4coder_token.cpp | 4 +- custom/4coder_token.h | 32 +- custom/api/4coder_types.h | 7 - custom/generated/command_metadata.h | 20 +- 10 files changed, 324 insertions(+), 545 deletions(-) diff --git a/custom/4coder_auto_indent.cpp b/custom/4coder_auto_indent.cpp index de0677b6..a7a81673 100644 --- a/custom/4coder_auto_indent.cpp +++ b/custom/4coder_auto_indent.cpp @@ -1,38 +1,36 @@ /* -4coder_auto_indent.cpp - Commands for auto-indentation of C++ code. +4coder_auto_indent.cpp - Commands for automatic indentation. */ // TOP internal Batch_Edit* -make_batch_from_indent_marks(Application_Links *app, Arena *arena, Buffer_ID buffer, - i64 first_line, i64 one_past_last_line, i64 *indent_marks, - Indent_Options opts){ - i64 *shifted_indent_marks = indent_marks - first_line; +make_batch_from_indentations(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 lines, i64 *indentations, Indent_Flag flags, i32 tab_width){ + i64 *shifted_indentations = indentations - lines.first; Batch_Edit *batch_first = 0; Batch_Edit *batch_last = 0; - for (i64 line_number = first_line; - line_number < one_past_last_line; + for (i64 line_number = lines.first; + line_number <= lines.max; ++line_number){ i64 line_start_pos = get_line_start_pos(app, buffer, line_number); - Indent_Info hard_start = get_indent_info_line_start(app, buffer, line_start_pos, opts.tab_width); + Indent_Info indent_info = get_indent_info_line_start(app, buffer, line_start_pos, tab_width); - i64 correct_indentation = shifted_indent_marks[line_number]; - if (hard_start.is_blank && opts.empty_blank_lines){ + i64 correct_indentation = shifted_indentations[line_number]; + if (indent_info.is_blank && HasFlag(flags, Indent_ClearLine)){ correct_indentation = 0; } if (correct_indentation == -1){ - correct_indentation = hard_start.indent_pos; + correct_indentation = indent_info.indent_pos; } - if (correct_indentation != hard_start.indent_pos){ + if (correct_indentation != indent_info.indent_pos){ umem str_size = 0; u8 *str = 0; - if (opts.use_tabs){ - i64 tab_count = correct_indentation/opts.tab_width; - i64 indent = tab_count*opts.tab_width; + if (HasFlag(flags, Indent_UseTab)){ + i64 tab_count = correct_indentation/tab_width; + i64 indent = tab_count*tab_width; i64 space_count = correct_indentation - indent; str_size = tab_count + space_count; str = push_array(arena, u8, str_size); @@ -48,7 +46,7 @@ make_batch_from_indent_marks(Application_Links *app, Arena *arena, Buffer_ID buf Batch_Edit *batch = push_array(arena, Batch_Edit, 1); sll_queue_push(batch_first, batch_last, batch); batch->edit.text = SCu8(str, str_size); - batch->edit.range = Ii64(line_start_pos, hard_start.first_char_pos); + batch->edit.range = Ii64(line_start_pos, indent_info.first_char_pos); } } @@ -56,454 +54,265 @@ make_batch_from_indent_marks(Application_Links *app, Arena *arena, Buffer_ID buf } internal void -set_line_indents(Application_Links *app, Arena *arena, Buffer_ID buffer, i64 first_line, i64 one_past_last_line, i64 *indent_marks, Indent_Options opts){ - Batch_Edit *batch = make_batch_from_indent_marks(app, arena, buffer, first_line, one_past_last_line, indent_marks, opts); +set_line_indents(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 lines, i64 *indentations, Indent_Flag flags, i32 tab_width){ + Batch_Edit *batch = make_batch_from_indentations(app, arena, buffer, lines, indentations, flags, tab_width); if (batch != 0){ buffer_batch_edit(app, buffer, batch); } } internal Token* -seek_matching_token_backwards(Token_Array tokens, Token *token, - Token_Base_Kind open, Token_Base_Kind close){ - if (token <= tokens.tokens){ - token = tokens.tokens; - } - else{ - i32 nesting_level = 0; - for (; token > tokens.tokens; --token){ - if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody)){ - if (token->kind == close){ - ++nesting_level; - } - else if (token->kind == open){ - if (nesting_level == 0){ - break; - } - else{ - --nesting_level; - } - } - } - } - } - return(token); -} - -internal Indent_Anchor_Position -find_anchor_token(Application_Links *app, Buffer_ID buffer, Token_Array tokens, i64 line_start, i32 tab_width){ - Indent_Anchor_Position anchor = {}; - if (tokens.count > 0){ - Token *first_invalid_token = get_first_token_from_line(app, buffer, tokens, line_start); - if (first_invalid_token <= tokens.tokens){ - anchor.token = tokens.tokens; - } - else{ - i32 stack[256]; - i32 top = -1; - Token *token_it = tokens.tokens; - i64 highest_checked_line_number = -1; - for (; token_it < first_invalid_token; ++token_it){ - i64 line_number = get_line_number_from_pos(app, buffer, token_it->pos); - if (highest_checked_line_number < line_number){ - highest_checked_line_number = line_number; - if (top == -1){ - anchor.token = token_it; - } - } - - switch (token_it->kind){ - case TokenBaseKind_ParentheticalOpen: - case TokenBaseKind_ScopeOpen: - { - top += 1; - stack[top] = token_it->kind; - }break; - - case TokenBaseKind_ParentheticalClose: - { - for (;top >= 0;){ - i32 index = top; - top -= 1; - if (stack[index] == TokenBaseKind_ParentheticalOpen){ - break; - } - } - }break; - - case TokenBaseKind_ScopeClose: - { - for (;top >= 0;){ - i32 index = top; - if (stack[index] == TokenBaseKind_ParentheticalOpen){ - break; - } - top -= 1; - if (stack[index] == TokenBaseKind_ScopeClose){ - break; - } - } - }break; - } - } - } - } - return(anchor); -} - -internal i64* -get_indentation_marks(Application_Links *app, Arena *arena, Buffer_ID buffer, - Token_Array tokens, i64 first_line, i64 one_past_last_line, - b32 exact_align, i32 tab_width){ - i64 indent_mark_count = one_past_last_line - first_line; - i64 *indent_marks = push_array(arena, i64, indent_mark_count); - // Shift the array so line_index works correctly. - indent_marks -= first_line; +find_anchor_token(Application_Links *app, Buffer_ID buffer, Token_Array *tokens, i64 invalid_line){ + Token *result = tokens->tokens; + i64 invalid_pos = get_line_start_pos(app, buffer, invalid_line); - // Decide where to start indentation parsing. - Indent_Anchor_Position anchor = find_anchor_token(app, buffer, tokens, first_line, tab_width); - Token *token_ptr = anchor.token; - Indent_Parse_State indent = {}; - indent.current_indent = anchor.indentation; - - if (token_ptr == 0){ - for (i64 line_index = first_line; line_index < one_past_last_line; ++line_index){ - indent_marks[line_index] = 0; + i32 scope_counter = 0; + i32 paren_counter = 0; + Token *token = tokens->tokens; + for (;;token += 1){ + if (token->pos + token->size > invalid_pos){ + break; } - } - else{ - i64 line_number = get_line_number_from_pos(app, buffer, token_ptr->pos); - line_number = clamp_top(line_number, first_line); - - if (token_ptr == tokens.tokens){ - indent.current_indent = 0; - } - - i64 next_line_start_pos = get_line_start_pos(app, buffer, line_number); - indent.previous_line_indent = indent.current_indent; - Token prev_token = {}; - Token token = {}; - if (token_ptr < tokens.tokens + tokens.count){ - token = *token_ptr; - } - - // Back up and consume this token too IF it is a scope opener. - if (token.kind == TokenBaseKind_ScopeOpen){ - --token_ptr; - } - - // LOOP OVER TOKENS - for (;;){ - if (line_number >= one_past_last_line){ - break; + if (!HasFlag(token->flags, TokenBaseFlag_PreprocessorBody)){ + if (scope_counter == 0 && paren_counter == 0){ + result = token; } - - prev_token = token; - ++token_ptr; - if (token_ptr < tokens.tokens + tokens.count){ - token = *token_ptr; - } - else{ - block_zero_struct(&token); - token.kind = TokenBaseKind_EOF; - token.pos = buffer_get_size(app, buffer); - } - - for (;token.pos >= next_line_start_pos && line_number < one_past_last_line;){ - next_line_start_pos = get_line_start_pos(app, buffer, line_number + 1); - - i64 this_indent = 0; - i64 previous_indent = indent.previous_line_indent; - - i64 this_line_start = get_line_start_pos(app, buffer, line_number); - i64 next_line_start = next_line_start_pos; - - b32 did_multi_line_behavior = false; - - // NOTE(allen): Check for multi-line tokens - if (prev_token.pos <= this_line_start && prev_token.pos + prev_token.size > this_line_start){ - if (prev_token.kind == TokenBaseKind_Comment || prev_token.kind == TokenBaseKind_LiteralString){ - Indent_Info hard_start = get_indent_info_line_start(app, buffer, this_line_start, tab_width); - - if (exact_align){ - this_indent = indent.previous_comment_indent; - } - else{ - if (hard_start.is_blank){ - this_indent = previous_indent; - } - else{ - i64 line_pos = hard_start.first_char_pos - this_line_start; - this_indent = line_pos + indent.comment_shift; - if (this_indent < 0){ - this_indent = 0; - } - } - } - - if (!hard_start.is_blank){ - if (line_number >= first_line){ - indent.previous_comment_indent = this_indent; - } - else{ - indent.previous_comment_indent = hard_start.indent_pos; - } - } - - did_multi_line_behavior = true; - } - } - - if (!did_multi_line_behavior){ - this_indent = indent.current_indent; - if (token.pos < next_line_start){ - switch (token.kind){ - case TokenBaseKind_Preprocessor: - { - this_indent = 0; - }break; - - case TokenBaseKind_ScopeClose: - { - this_indent -= tab_width; - }break; - case TokenBaseKind_ScopeOpen: - {}break; - - default: - if (indent.current_indent > 0){ - b32 statement_complete = false; - - Token *prev_usable_token_ptr = token_ptr - 1; - Token prev_usable_token = {}; - if (prev_usable_token_ptr >= tokens.tokens){ - prev_usable_token = *prev_usable_token_ptr; - } - - // Scan backwards for the previous token that actually tells us about the statement. - b32 has_prev_usable_token = true; -#define NotUsable(T) \ - (((T).flags&TokenBaseFlag_PreprocessorBody) || ((T).kind == TokenBaseKind_Comment) || ((T).kind == TokenBaseKind_Whitespace)) - if (NotUsable(prev_usable_token)){ - has_prev_usable_token = false; - - for (--prev_usable_token_ptr; - prev_usable_token_ptr >= tokens.tokens; - --prev_usable_token_ptr){ - - prev_usable_token = *prev_usable_token_ptr; - if (!NotUsable(prev_usable_token)){ - has_prev_usable_token = true; - break; - } - } - } -#undef NotUsable - - if (!has_prev_usable_token){ - statement_complete = true; - } - else{ - if (prev_usable_token.kind == TokenBaseKind_ScopeOpen || - prev_usable_token.kind == TokenBaseKind_ScopeClose || - prev_usable_token.sub_kind == TokenCppKind_Semicolon || - prev_usable_token.sub_kind == TokenCppKind_Colon || - prev_usable_token.sub_kind == TokenCppKind_Comma){ - statement_complete = true; - } - } - - if (!statement_complete){ - this_indent += tab_width; - } - }break; - } - } - if (this_indent < 0){ - this_indent = 0; - } - } - - if (indent.paren_nesting > 0){ - if (prev_token.kind != TokenBaseKind_ParentheticalOpen){ - i64 level = indent.paren_nesting - 1; - level = clamp_top(level, ArrayCount(indent.paren_anchor_indent) - 1); - this_indent = indent.paren_anchor_indent[level]; - } - } - - // Rebase the paren anchor if the first token - // after the open paren is on the next line. - if (indent.paren_nesting > 0 && - prev_token.kind == TokenBaseKind_ParentheticalOpen){ - i64 level = indent.paren_nesting - 1; - level = clamp_top(level, ArrayCount(indent.paren_anchor_indent) - 1); - indent.paren_anchor_indent[level] = this_indent; - } - - if (line_number >= first_line){ - indent_marks[line_number] = this_indent; - } - ++line_number; - - indent.previous_line_indent = this_indent; - } - - // Update indent state. - switch (token.kind){ - case TokenBaseKind_ScopeOpen: indent.current_indent += tab_width; break; - case TokenBaseKind_ScopeClose: indent.current_indent -= tab_width; break; - - case TokenBaseKind_Comment: - case TokenBaseKind_LiteralString: + switch (token->kind){ + case TokenBaseKind_ScopeOpen: { - i64 line = get_line_number_from_pos(app, buffer, token.pos); - i64 start = get_line_start_pos(app, buffer, line); - Indent_Info hard_start = get_indent_info_line_start(app, buffer, start, tab_width); - - i64 old_dist_to_token = (token.pos - start); - i64 old_indent = hard_start.indent_pos; - i64 token_start_inset = old_dist_to_token - old_indent; - i64 new_dist_to_token = indent.current_indent + token_start_inset; - - indent.comment_shift = (new_dist_to_token - old_dist_to_token); - indent.previous_comment_indent = old_indent; + scope_counter += 1; + }break; + case TokenBaseKind_ScopeClose: + { + paren_counter = 0; + if (scope_counter > 0){ + scope_counter -= 1; + } }break; - case TokenBaseKind_ParentheticalOpen: { - if (!HasFlag(token.flags, TokenBaseFlag_PreprocessorBody)){ - if (indent.paren_nesting < ArrayCount(indent.paren_anchor_indent)){ - i64 line = get_line_number_from_pos(app, buffer, token.pos); - i64 start = get_line_start_pos(app, buffer, line); - i64 char_pos = token.pos - start; - - Indent_Info hard_start = get_indent_info_line_start(app, buffer, start, tab_width); - - i64 line_pos = hard_start.first_char_pos - start; - - indent.paren_anchor_indent[indent.paren_nesting] = char_pos - line_pos + indent.previous_line_indent + 1; - } - ++indent.paren_nesting; - } + paren_counter += 1; }break; - case TokenBaseKind_ParentheticalClose: { - if (!HasFlag(token.flags, TokenBaseFlag_PreprocessorBody)){ - if (indent.paren_nesting > 0){ - --indent.paren_nesting; - } + if (paren_counter > 0){ + paren_counter -= 1; } }break; } } } - // Unshift the indent_marks array. - indent_marks += first_line; - return(indent_marks); -} - -// TODO(allen): replace these with new range operators. -internal void -get_indent_lines_minimum(Application_Links *app, Buffer_ID buffer, i64 start_pos, i64 end_pos, i64 *line_start_out, i64 *line_end_out){ - i64 line_start = get_line_number_from_pos(app, buffer, start_pos); - i64 line_end = get_line_number_from_pos(app, buffer, end_pos) + 1; - *line_start_out = line_start; - *line_end_out = line_end; -} - -internal void -get_indent_lines_whole_tokens(Application_Links *app, Buffer_ID buffer, Token_Array tokens, i64 start_pos, i64 end_pos, i64 *line_start_out, i64 *line_end_out){ - i64 line_start = get_line_number_from_pos(app, buffer, start_pos); - i64 line_end = get_line_number_from_pos(app, buffer, end_pos); - - for (;line_start > 1;){ - i64 line_start_pos = get_line_start_pos(app, buffer, line_start); - Token *token = token_from_pos(&tokens, line_start_pos); - if (token != 0 && token->pos < line_start_pos){ - line_start = get_line_number_from_pos(app, buffer, token->pos); - } - else{ - break; - } - } - - i64 line_count = buffer_get_line_count(app, buffer); - - for (;line_end < line_count;){ - i64 next_line_start_pos = get_line_start_pos(app, buffer, line_end + 1); - Token *token = token_from_pos(&tokens, next_line_start_pos); - if (token != 0 && token->pos < next_line_start_pos){ - line_end = get_line_number_from_pos(app, buffer, token->pos + token->size); - } - else{ - break; - } - } - - line_end = clamp_top(line_end, line_count); - line_end += 1; - - *line_start_out = line_start; - *line_end_out = line_end; -} - -internal b32 -buffer_auto_indent(Application_Links *app, Buffer_ID buffer, i64 start, i64 end, i32 tab_width, Auto_Indent_Flag flags){ - b32 result = false; - - Managed_Scope scope = buffer_get_managed_scope(app, buffer); - - Token_Array *tokens_ptr = scope_attachment(app, scope, attachment_tokens, Token_Array); - if (tokens_ptr != 0 && tokens_ptr->count != 0){ - Scratch_Block scratch(app); - Token_Array tokens = *tokens_ptr; - - i64 line_start = 0; - i64 line_end = 0; - if (HasFlag(flags, AutoIndent_FullTokens)){ - get_indent_lines_whole_tokens(app, buffer, tokens, start, end, &line_start, &line_end); - } - else{ - get_indent_lines_minimum(app, buffer, start, end, &line_start, &line_end); - } - - i64 *indent_marks = get_indentation_marks(app, scratch, buffer, tokens, line_start, line_end, (flags & AutoIndent_ExactAlignBlock), tab_width); - - Indent_Options opts = {}; - opts.empty_blank_lines = (flags & AutoIndent_ClearLine); - opts.use_tabs = (flags & AutoIndent_UseTab); - opts.tab_width = tab_width; - - set_line_indents(app, scratch, buffer, line_start, line_end, indent_marks, opts); - - result = true; - } - return(result); } -// -// Commands -// +internal Nest* +indent__new_nest(Arena *arena, Nest_Alloc *alloc){ + Nest *new_nest = alloc->free_nest; + if (new_nest == 0){ + new_nest = push_array(arena, Nest, 1); + } + else{ + sll_stack_pop(alloc->free_nest); + } + return(new_nest); +} -#if !defined(DEFAULT_INDENT_FLAGS) -# define DEFAULT_INDENT_FLAGS ((global_config.indent_with_tabs)?(AutoIndent_UseTab):(0)) -#endif +internal void +indent__free_nest(Nest_Alloc *alloc, Nest *nest){ + sll_stack_push(alloc->free_nest, nest); +} -#if !defined(DEF_TAB_WIDTH) -# define DEF_TAB_WIDTH global_config.indent_width -#endif +internal i64* +get_indentation_array(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 lines, Indent_Flag flags, i32 tab_width, i32 indent_width){ + i64 count = lines.max - lines.min + 1; + i64 *indentations = push_array(arena, i64, count); + i64 *shifted_indentations = indentations - lines.first; + block_fill_u64(indentations, sizeof(*indentations)*count, (u64)(-1)); + + Managed_Scope scope = buffer_get_managed_scope(app, buffer); + Token_Array *tokens = scope_attachment(app, scope, attachment_tokens, Token_Array); + i64 anchor_line = clamp_bot(1, lines.first - 1); + Token *anchor_token = find_anchor_token(app, buffer, tokens, anchor_line); + if (anchor_token != 0 && + anchor_token >= tokens->tokens && + anchor_token < tokens->tokens + tokens->count){ + i64 line = get_line_number_from_pos(app, buffer, anchor_token->pos); + line = clamp_top(line, lines.first); + + Token_Iterator_Array token_it = token_iterator(0, tokens, anchor_token); + + Scratch_Block scratch(app); + Nest *nest = 0; + Nest_Alloc nest_alloc = {}; + + i64 line_last_indented = line - 1; + i64 last_indent = 0; + + for (;;){ + Token *token = token_it_read(&token_it); + i64 line_where_token_starts = get_line_number_from_pos(app, buffer, token->pos); + i64 line_start_pos = get_line_start_pos(app, buffer, line_where_token_starts); + Indent_Info line_indent_info = get_indent_info_line_start(app, buffer, line_start_pos, tab_width); + + i64 current_indent = 0; + if (nest != 0){ + current_indent = nest->indent; + } + i64 this_indent = current_indent; + + if (HasFlag(token->flags, TokenBaseFlag_PreprocessorBody)){ + this_indent = 0; + } + else{ + switch (token->kind){ + case TokenBaseKind_ScopeOpen: + { + Nest *new_nest = indent__new_nest(arena, &nest_alloc); + sll_stack_push(nest, new_nest); + nest->kind = TokenBaseKind_ScopeOpen; + nest->indent = current_indent + indent_width; + }break; + + case TokenBaseKind_ScopeClose: + { + for (;nest != 0 && nest->kind != TokenBaseKind_ScopeOpen;){ + Nest *n = nest; + sll_stack_pop(nest); + indent__free_nest(&nest_alloc, n); + } + if (nest != 0 && nest->kind == TokenBaseKind_ScopeOpen){ + Nest *n = nest; + sll_stack_pop(nest); + indent__free_nest(&nest_alloc, n); + } + this_indent = 0; + if (nest != 0){ + this_indent = nest->indent; + } + }break; + + case TokenBaseKind_ParentheticalOpen: + { + Nest *new_nest = indent__new_nest(arena, &nest_alloc); + sll_stack_push(nest, new_nest); + nest->kind = TokenBaseKind_ParentheticalOpen; + nest->indent = line_indent_info.indent_pos + (token->pos - line_indent_info.first_char_pos) + 1; + }break; + + case TokenBaseKind_ParentheticalClose: + { + if (nest != 0 && nest->kind == TokenBaseKind_ParentheticalOpen){ + Nest *n = nest; + sll_stack_pop(nest); + indent__free_nest(&nest_alloc, n); + } + }break; + } + } + +#define EMIT(N) \ + Stmnt(if (lines.first <= line_it){shifted_indentations[line_it]=N;} \ + if (line_it == lines.end){goto finished;} ) + + i64 line_it = line_last_indented; + for (;line_it < line_where_token_starts;){ + line_it += 1; + if (line_it == line_where_token_starts){ + EMIT(this_indent); + last_indent = this_indent; + } + else{ + EMIT(last_indent); + } + } + + i64 line_where_token_starts_shift = this_indent - line_indent_info.indent_pos; + i64 line_where_token_ends = get_line_number_from_pos(app, buffer, token->pos + token->size); + for (;line_it < line_where_token_ends;){ + line_it += 1; + i64 line_it_start_pos = get_line_start_pos(app, buffer, line_it); + Indent_Info line_it_indent_info = get_indent_info_line_start(app, buffer, line_it_start_pos, tab_width); + i64 new_indent = line_it_indent_info.indent_pos + line_where_token_starts_shift; + new_indent = clamp_bot(0, new_indent); + EMIT(new_indent); + } +#undef EMIT + + line_last_indented = line_it; + + if (!token_it_inc_non_whitespace(&token_it)){ + break; + } + } + } + + finished:; + return(indentations); +} + +internal b32 +auto_indent_buffer(Application_Links *app, Buffer_ID buffer, Range_i64 pos, Indent_Flag flags, i32 tab_width, i32 indent_width){ + Managed_Scope scope = buffer_get_managed_scope(app, buffer); + Token_Array *tokens = scope_attachment(app, scope, attachment_tokens, Token_Array); + + b32 result = false; + if (tokens != 0){ + result = true; + + Scratch_Block scratch(app); + Range_i64 line_numbers = {}; + if (HasFlag(flags, Indent_FullTokens)){ + i32 safety_counter = 0; + for (;;){ + Range_i64 expanded = enclose_tokens(app, buffer, pos); + expanded = enclose_whole_lines(app, buffer, expanded); + if (expanded == pos){ + break; + } + pos = expanded; + safety_counter += 1; + if (safety_counter == 20){ + pos = buffer_range(app, buffer); + break; + } + } + } + line_numbers = get_line_range_from_pos_range(app, buffer, pos); + + i64 *indentations = get_indentation_array(app, scratch, buffer, line_numbers, flags, tab_width, indent_width); + set_line_indents(app, scratch, buffer, line_numbers, indentations, flags, tab_width); + } + + return(result); +} + +global_const i32 auto_indent_tab_width = 4; + +function void +auto_indent_buffer(Application_Links *app, Buffer_ID buffer, Range_i64 pos, Indent_Flag flags){ + i32 indent_width = global_config.indent_width; + AddFlag(flags, Indent_FullTokens); + if (global_config.indent_with_tabs){ + AddFlag(flags, Indent_UseTab); + } + auto_indent_buffer(app, buffer, pos, flags, indent_width, auto_indent_tab_width); +} + +function void +auto_indent_buffer(Application_Links *app, Buffer_ID buffer, Range_i64 pos){ + auto_indent_buffer(app, buffer, pos, 0); +} + +//////////////////////////////// CUSTOM_COMMAND_SIG(auto_tab_whole_file) CUSTOM_DOC("Audo-indents the entire current buffer.") { View_ID view = get_active_view(app, AccessOpen); Buffer_ID buffer = view_get_buffer(app, view, AccessOpen); - i32 buffer_size = (i32)buffer_get_size(app, buffer); - buffer_auto_indent(app, buffer, 0, buffer_size, DEF_TAB_WIDTH, DEFAULT_INDENT_FLAGS | AutoIndent_FullTokens); + i64 buffer_size = buffer_get_size(app, buffer); + auto_indent_buffer(app, buffer, Ii64(0, buffer_size)); } CUSTOM_COMMAND_SIG(auto_tab_line_at_cursor) @@ -512,7 +321,7 @@ CUSTOM_DOC("Auto-indents the line on which the cursor sits.") View_ID view = get_active_view(app, AccessOpen); Buffer_ID buffer = view_get_buffer(app, view, AccessOpen); i64 pos = view_get_cursor_pos(app, view); - buffer_auto_indent(app, buffer, pos, pos, DEF_TAB_WIDTH, DEFAULT_INDENT_FLAGS | AutoIndent_FullTokens); + auto_indent_buffer(app, buffer, Ii64(pos)); move_past_lead_whitespace(app, view, buffer); } @@ -522,7 +331,7 @@ CUSTOM_DOC("Auto-indents the range between the cursor and the mark.") View_ID view = get_active_view(app, AccessOpen); Buffer_ID buffer = view_get_buffer(app, view, AccessOpen); Range_i64 range = get_view_range(app, view); - buffer_auto_indent(app, buffer, range.min, range.max, DEF_TAB_WIDTH, DEFAULT_INDENT_FLAGS | AutoIndent_FullTokens); + auto_indent_buffer(app, buffer, range); move_past_lead_whitespace(app, view, buffer); } @@ -532,13 +341,13 @@ CUSTOM_DOC("Inserts a character and auto-indents the line on which the cursor si write_character(app); View_ID view = get_active_view(app, AccessOpen); Buffer_ID buffer = view_get_buffer(app, view, AccessOpen); - u32 flags = DEFAULT_INDENT_FLAGS; + i64 pos = view_get_cursor_pos(app, view); + Indent_Flag flags = 0; User_Input in = get_command_input(app); if (in.key.character == '\n'){ - flags |= AutoIndent_ExactAlignBlock; + flags |= Indent_ExactAlignBlock; } - i64 pos = view_get_cursor_pos(app, view); - buffer_auto_indent(app, buffer, pos, pos, DEF_TAB_WIDTH, flags); + auto_indent_buffer(app, buffer, Ii64(pos), flags); move_past_lead_whitespace(app, view, buffer); } diff --git a/custom/4coder_auto_indent.h b/custom/4coder_auto_indent.h index b1b99ac8..31bf6ca6 100644 --- a/custom/4coder_auto_indent.h +++ b/custom/4coder_auto_indent.h @@ -7,24 +7,22 @@ #if !defined(FCODER_AUTO_INDENT_H) #define FCODER_AUTO_INDENT_H -struct Indent_Options{ - b32 empty_blank_lines; - b32 use_tabs; - i32 tab_width; +typedef u32 Indent_Flag; +enum{ + Indent_ClearLine = 0x1, + Indent_UseTab = 0x2, + Indent_ExactAlignBlock = 0x4, + Indent_FullTokens = 0x8, }; -struct Indent_Parse_State{ - i64 current_indent; - i64 previous_line_indent; - i64 paren_nesting; - i64 paren_anchor_indent[16]; - i64 comment_shift; - i64 previous_comment_indent; +struct Nest{ + Nest *next; + Token_Base_Kind kind; + i64 indent; }; -struct Indent_Anchor_Position{ - Token *token; - i32 indentation; +struct Nest_Alloc{ + Nest *free_nest; }; #endif diff --git a/custom/4coder_base_types.cpp b/custom/4coder_base_types.cpp index 0d754d61..be548488 100644 --- a/custom/4coder_base_types.cpp +++ b/custom/4coder_base_types.cpp @@ -1741,6 +1741,23 @@ If32(f32 a){ return(interval); } +internal b32 +operator==(Interval_i32 a, Interval_i32 b){ + return(a.min == b.min && a.max == b.max); +} +internal b32 +operator==(Interval_i64 a, Interval_i64 b){ + return(a.min == b.min && a.max == b.max); +} +internal b32 +operator==(Interval_u64 a, Interval_u64 b){ + return(a.min == b.min && a.max == b.max); +} +internal b32 +operator==(Interval_f32 a, Interval_f32 b){ + return(a.min == b.min && a.max == b.max); +} + #define make_range Ii32 #define make_range_i32 Ii32 #define make_range_i64 Ii64 diff --git a/custom/4coder_combined_write_commands.cpp b/custom/4coder_combined_write_commands.cpp index 4aca4931..b59b1347 100644 --- a/custom/4coder_combined_write_commands.cpp +++ b/custom/4coder_combined_write_commands.cpp @@ -39,7 +39,7 @@ long_braces(Application_Links *app, char *text, i32 size){ i64 pos = view_get_cursor_pos(app, view); buffer_replace_range(app, buffer, Ii64(pos), SCu8(text, size)); view_set_cursor_and_preferred_x(app, view, seek_pos(pos + 2)); - buffer_auto_indent(app, buffer, pos, pos + size, DEF_TAB_WIDTH, DEFAULT_INDENT_FLAGS | AutoIndent_FullTokens); + auto_indent_buffer(app, buffer, Ii64_size(pos, size)); move_past_lead_whitespace(app, view, buffer); } diff --git a/custom/4coder_default_hooks.cpp b/custom/4coder_default_hooks.cpp index 81907e87..0cc13efb 100644 --- a/custom/4coder_default_hooks.cpp +++ b/custom/4coder_default_hooks.cpp @@ -1103,8 +1103,7 @@ BUFFER_HOOK_SIG(default_file_save){ if (global_config.automatically_indent_text_on_save && buffer_get_setting(app, buffer_id, BufferSetting_VirtualWhitespace, &is_virtual)){ if (is_virtual){ - i64 buffer_size = buffer_get_size(app, buffer_id); - buffer_auto_indent(app, buffer_id, 0, buffer_size, DEF_TAB_WIDTH, DEFAULT_INDENT_FLAGS | AutoIndent_FullTokens); + auto_indent_buffer(app, buffer_id, buffer_range(app, buffer_id)); } } // no meaning for return diff --git a/custom/4coder_helper.cpp b/custom/4coder_helper.cpp index 7c5a2164..bd5e8067 100644 --- a/custom/4coder_helper.cpp +++ b/custom/4coder_helper.cpp @@ -789,14 +789,12 @@ internal i64 boundary_token(Application_Links *app, Buffer_ID buffer, Side side, Scan_Direction direction, i64 pos){ i64 result = boundary_non_whitespace(app, buffer, side, direction, pos); Token_Array tokens = get_token_array_from_buffer(app, buffer); - if (tokens.tokens == 0){ - result = boundary_non_whitespace(app, buffer, side, direction, pos); - } - else{ + if (tokens.tokens != 0){ switch (direction){ case Scan_Forward: { i64 buffer_size = buffer_get_size(app, buffer); + result = buffer_size; if (tokens.count > 0){ Token_Iterator_Array it = token_iterator_pos(0, &tokens, pos); Token *token = token_it_read(&it); @@ -809,80 +807,45 @@ boundary_token(Application_Links *app, Buffer_ID buffer, Side side, Scan_Directi result = token->pos + token->size; } else{ - if (token->pos > pos){ - result = token->pos; + if (token->pos <= pos){ + token_it_inc_non_whitespace(&it); + token = token_it_read(&it); } - else{ - token += 1; - if (token < tokens.tokens + tokens.count){ - result = token->pos; - } - else{ - result = buffer_size; - } + if (token != 0){ + result = token->pos; } } } - else{ - result = buffer_size; - } - } - else{ - result = buffer_size; } }break; case Scan_Backward: { + result = 0; if (tokens.count > 0){ - Token_Iterator_Array it = token_iterator_pos(0, &tokens, pos - 1); + Token_Iterator_Array it = token_iterator_pos(0, &tokens, pos); Token *token = token_it_read(&it); if (token->kind == TokenBaseKind_Whitespace){ token_it_dec_non_whitespace(&it); token = token_it_read(&it); } - if (side == Side_Min){ - if (token == 0){ - token = tokens.tokens + tokens.count - 1; + if (token != 0){ + if (side == Side_Min){ + if (token->pos >= pos){ + token_it_dec_non_whitespace(&it); + token = token_it_read(&it); + } result = token->pos; } else{ - if (token->pos < pos){ - result = token->pos; + if (token->pos + token->size >= pos){ + token_it_dec_non_whitespace(&it); + token = token_it_read(&it); } - else{ - token -= 1; - if (token >= tokens.tokens){ - result = token->pos; - } - else{ - result = 0; - } - } - } - } - else{ - if (token == 0){ - token = tokens.tokens + tokens.count - 1; result = token->pos + token->size; } - else{ - token -= 1; - if (token >= tokens.tokens && token->pos + token->size == pos){ - token -= 1; - } - if (token >= tokens.tokens){ - result = token->pos + token->size; - } - else{ - result = 0; - } - } } } - else{ - result = 0; - } }break; } } @@ -1387,7 +1350,7 @@ get_indent_info_range(Application_Links *app, Buffer_ID buffer, Range_i64 range, if (!character_is_whitespace(c)){ info.is_blank = false; info.all_space = false; - info.first_char_pos = range.start + (i32)i; + info.first_char_pos = range.start + (i64)i; break; } if (c != ' '){ diff --git a/custom/4coder_token.cpp b/custom/4coder_token.cpp index b794f744..63dd46df 100644 --- a/custom/4coder_token.cpp +++ b/custom/4coder_token.cpp @@ -280,7 +280,7 @@ token_iterator_index(u64 user_id, Token_List *list, i64 index){ block = node; break; } - base_index += block->count; + base_index += node->count; } Assert(block != 0); it.user_id = user_id; @@ -320,7 +320,7 @@ token_iterator_pos(u64 user_id, Token_List *list, i64 pos){ block = node; break; } - base_index += block->count; + base_index += node->count; } Assert(block != 0); i64 sub_index = token_index_from_pos(block->tokens, block->count, pos); diff --git a/custom/4coder_token.h b/custom/4coder_token.h index 7613621f..8e2c3689 100644 --- a/custom/4coder_token.h +++ b/custom/4coder_token.h @@ -9,23 +9,23 @@ typedef i16 Token_Base_Kind; enum{ - TokenBaseKind_EOF, - TokenBaseKind_Whitespace, - TokenBaseKind_LexError, - TokenBaseKind_Comment, - TokenBaseKind_Keyword, - TokenBaseKind_Preprocessor, - TokenBaseKind_Identifier, - TokenBaseKind_Operator, - TokenBaseKind_LiteralInteger, - TokenBaseKind_LiteralFloat, - TokenBaseKind_LiteralString, - TokenBaseKind_ScopeOpen, - TokenBaseKind_ScopeClose, - TokenBaseKind_ParentheticalOpen, - TokenBaseKind_ParentheticalClose, + TokenBaseKind_EOF = 0, + TokenBaseKind_Whitespace = 1, + TokenBaseKind_LexError = 2, + TokenBaseKind_Comment = 3, + TokenBaseKind_Keyword = 4, + TokenBaseKind_Preprocessor = 5, + TokenBaseKind_Identifier = 6, + TokenBaseKind_Operator = 7, + TokenBaseKind_LiteralInteger = 8, + TokenBaseKind_LiteralFloat = 9, + TokenBaseKind_LiteralString = 10, + TokenBaseKind_ScopeOpen = 11, + TokenBaseKind_ScopeClose = 12, + TokenBaseKind_ParentheticalOpen = 13, + TokenBaseKind_ParentheticalClose = 14, - TokenBaseKind_COUNT, + TokenBaseKind_COUNT = 15, }; char *token_base_kind_names[] ={ diff --git a/custom/api/4coder_types.h b/custom/api/4coder_types.h index a47761eb..f698b221 100644 --- a/custom/api/4coder_types.h +++ b/custom/api/4coder_types.h @@ -165,13 +165,6 @@ ENUM(u32, Command_Line_Interface_Flag){ CLI_SendEndSignal = 0x8, }; -ENUM(u32, Auto_Indent_Flag){ - AutoIndent_ClearLine = 0x1, - AutoIndent_UseTab = 0x2, - AutoIndent_ExactAlignBlock = 0x4, - AutoIndent_FullTokens = 0x8, -}; - ENUM(u32, Set_Buffer_Flag){ SetBuffer_KeepOriginalGUI = 0x1 }; diff --git a/custom/generated/command_metadata.h b/custom/generated/command_metadata.h index f767358d..7ff67246 100644 --- a/custom/generated/command_metadata.h +++ b/custom/generated/command_metadata.h @@ -248,12 +248,12 @@ i32 line_number; }; static Command_Metadata fcoder_metacmd_table[226] = { { PROC_LINKS(set_bindings_mac_default, 0), "set_bindings_mac_default", 24, "Remap keybindings using the 'mac-default' mapping rule.", 55, "w:\\4ed\\code\\custom\\4coder_remapping_commands.cpp", 48, 62 }, -{ PROC_LINKS(seek_beginning_of_textual_line, 0), "seek_beginning_of_textual_line", 30, "Seeks the cursor to the beginning of the line across all text.", 62, "w:\\4ed\\code\\custom\\4coder_helper.cpp", 36, 2160 }, -{ PROC_LINKS(seek_end_of_textual_line, 0), "seek_end_of_textual_line", 24, "Seeks the cursor to the end of the line across all text.", 56, "w:\\4ed\\code\\custom\\4coder_helper.cpp", 36, 2166 }, -{ PROC_LINKS(seek_beginning_of_line, 0), "seek_beginning_of_line", 22, "Seeks the cursor to the beginning of the visual line.", 53, "w:\\4ed\\code\\custom\\4coder_helper.cpp", 36, 2172 }, -{ PROC_LINKS(seek_end_of_line, 0), "seek_end_of_line", 16, "Seeks the cursor to the end of the visual line.", 47, "w:\\4ed\\code\\custom\\4coder_helper.cpp", 36, 2178 }, -{ PROC_LINKS(goto_beginning_of_file, 0), "goto_beginning_of_file", 22, "Sets the cursor to the beginning of the file.", 45, "w:\\4ed\\code\\custom\\4coder_helper.cpp", 36, 2184 }, -{ PROC_LINKS(goto_end_of_file, 0), "goto_end_of_file", 16, "Sets the cursor to the end of the file.", 39, "w:\\4ed\\code\\custom\\4coder_helper.cpp", 36, 2192 }, +{ PROC_LINKS(seek_beginning_of_textual_line, 0), "seek_beginning_of_textual_line", 30, "Seeks the cursor to the beginning of the line across all text.", 62, "w:\\4ed\\code\\custom\\4coder_helper.cpp", 36, 2123 }, +{ PROC_LINKS(seek_end_of_textual_line, 0), "seek_end_of_textual_line", 24, "Seeks the cursor to the end of the line across all text.", 56, "w:\\4ed\\code\\custom\\4coder_helper.cpp", 36, 2129 }, +{ PROC_LINKS(seek_beginning_of_line, 0), "seek_beginning_of_line", 22, "Seeks the cursor to the beginning of the visual line.", 53, "w:\\4ed\\code\\custom\\4coder_helper.cpp", 36, 2135 }, +{ PROC_LINKS(seek_end_of_line, 0), "seek_end_of_line", 16, "Seeks the cursor to the end of the visual line.", 47, "w:\\4ed\\code\\custom\\4coder_helper.cpp", 36, 2141 }, +{ PROC_LINKS(goto_beginning_of_file, 0), "goto_beginning_of_file", 22, "Sets the cursor to the beginning of the file.", 45, "w:\\4ed\\code\\custom\\4coder_helper.cpp", 36, 2147 }, +{ PROC_LINKS(goto_end_of_file, 0), "goto_end_of_file", 16, "Sets the cursor to the end of the file.", 39, "w:\\4ed\\code\\custom\\4coder_helper.cpp", 36, 2155 }, { PROC_LINKS(change_active_panel, 0), "change_active_panel", 19, "Change the currently active panel, moving to the panel with the next highest view_id.", 85, "w:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 196 }, { PROC_LINKS(change_active_panel_backwards, 0), "change_active_panel_backwards", 29, "Change the currently active panel, moving to the panel with the next lowest view_id.", 84, "w:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 206 }, { PROC_LINKS(open_panel_vsplit, 0), "open_panel_vsplit", 17, "Create a new panel by vertically splitting the active panel.", 60, "w:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 216 }, @@ -387,10 +387,10 @@ static Command_Metadata fcoder_metacmd_table[226] = { { PROC_LINKS(interactive_new, 0), "interactive_new", 15, "Interactively creates a new file.", 33, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 847 }, { PROC_LINKS(interactive_open, 0), "interactive_open", 16, "Interactively opens a file.", 27, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 880 }, { PROC_LINKS(command_lister, 0), "command_lister", 14, "Opens an interactive list of all registered commands.", 53, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 960 }, -{ PROC_LINKS(auto_tab_whole_file, 0), "auto_tab_whole_file", 19, "Audo-indents the entire current buffer.", 39, "w:\\4ed\\code\\custom\\4coder_auto_indent.cpp", 41, 500 }, -{ PROC_LINKS(auto_tab_line_at_cursor, 0), "auto_tab_line_at_cursor", 23, "Auto-indents the line on which the cursor sits.", 47, "w:\\4ed\\code\\custom\\4coder_auto_indent.cpp", 41, 509 }, -{ PROC_LINKS(auto_tab_range, 0), "auto_tab_range", 14, "Auto-indents the range between the cursor and the mark.", 55, "w:\\4ed\\code\\custom\\4coder_auto_indent.cpp", 41, 519 }, -{ PROC_LINKS(write_and_auto_tab, 0), "write_and_auto_tab", 18, "Inserts a character and auto-indents the line on which the cursor sits.", 71, "w:\\4ed\\code\\custom\\4coder_auto_indent.cpp", 41, 529 }, +{ PROC_LINKS(auto_tab_whole_file, 0), "auto_tab_whole_file", 19, "Audo-indents the entire current buffer.", 39, "w:\\4ed\\code\\custom\\4coder_auto_indent.cpp", 41, 655 }, +{ PROC_LINKS(auto_tab_line_at_cursor, 0), "auto_tab_line_at_cursor", 23, "Auto-indents the line on which the cursor sits.", 47, "w:\\4ed\\code\\custom\\4coder_auto_indent.cpp", 41, 664 }, +{ PROC_LINKS(auto_tab_range, 0), "auto_tab_range", 14, "Auto-indents the range between the cursor and the mark.", 55, "w:\\4ed\\code\\custom\\4coder_auto_indent.cpp", 41, 674 }, +{ PROC_LINKS(write_and_auto_tab, 0), "write_and_auto_tab", 18, "Inserts a character and auto-indents the line on which the cursor sits.", 71, "w:\\4ed\\code\\custom\\4coder_auto_indent.cpp", 41, 684 }, { PROC_LINKS(list_all_locations, 0), "list_all_locations", 18, "Queries the user for a string and lists all exact case-sensitive matches found in all open buffers.", 99, "w:\\4ed\\code\\custom\\4coder_search.cpp", 36, 166 }, { PROC_LINKS(list_all_substring_locations, 0), "list_all_substring_locations", 28, "Queries the user for a string and lists all case-sensitive substring matches found in all open buffers.", 103, "w:\\4ed\\code\\custom\\4coder_search.cpp", 36, 172 }, { PROC_LINKS(list_all_locations_case_insensitive, 0), "list_all_locations_case_insensitive", 35, "Queries the user for a string and lists all exact case-insensitive matches found in all open buffers.", 101, "w:\\4ed\\code\\custom\\4coder_search.cpp", 36, 178 },