some clean up on the indent rule code
parent
55eb007f68
commit
5b2077c6d7
File diff suppressed because one or more lines are too long
|
@ -2,6 +2,10 @@
|
||||||
#ifndef FCODER_AUTO_INDENT_INC
|
#ifndef FCODER_AUTO_INDENT_INC
|
||||||
#define FCODER_AUTO_INDENT_INC
|
#define FCODER_AUTO_INDENT_INC
|
||||||
|
|
||||||
|
//
|
||||||
|
// Generic Line Indenter
|
||||||
|
//
|
||||||
|
|
||||||
struct Hard_Start_Result{
|
struct Hard_Start_Result{
|
||||||
int32_t char_pos;
|
int32_t char_pos;
|
||||||
int32_t indent_pos;
|
int32_t indent_pos;
|
||||||
|
@ -62,36 +66,80 @@ struct Indent_Options{
|
||||||
int32_t tab_width;
|
int32_t tab_width;
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "4cpp_lexer.h"
|
static Buffer_Batch_Edit
|
||||||
|
make_batch_from_indent_marks(Application_Links *app, Partition *part, Buffer_Summary *buffer,
|
||||||
static int32_t
|
int32_t line_start, int32_t line_end, int32_t *indent_marks,
|
||||||
buffer_get_line_start(Application_Links *app, Buffer_Summary *buffer, int32_t line){
|
Indent_Options opts){
|
||||||
Partial_Cursor partial_cursor;
|
|
||||||
app->buffer_compute_cursor(app, buffer, seek_line_char(line, 1), &partial_cursor);
|
|
||||||
return(partial_cursor.pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t
|
|
||||||
buffer_get_line_index(Application_Links *app, Buffer_Summary *buffer, int32_t pos){
|
|
||||||
Partial_Cursor partial_cursor;
|
|
||||||
app->buffer_compute_cursor(app, buffer, seek_pos(pos), &partial_cursor);
|
|
||||||
return(partial_cursor.line);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Cpp_Token*
|
|
||||||
get_first_token_at_line(Application_Links *app, Buffer_Summary *buffer, Cpp_Token_Array tokens, int32_t line){
|
|
||||||
int32_t line_start = buffer_get_line_start(app, buffer, line);
|
|
||||||
Cpp_Get_Token_Result get_token = cpp_get_token(&tokens, line_start);
|
|
||||||
|
|
||||||
if (get_token.in_whitespace){
|
Buffer_Batch_Edit result = {0};
|
||||||
get_token.token_index += 1;
|
|
||||||
|
int32_t edit_max = line_end - line_start;
|
||||||
|
int32_t edit_count = 0;
|
||||||
|
|
||||||
|
Buffer_Edit *edits = push_array(part, Buffer_Edit, edit_max);
|
||||||
|
|
||||||
|
char *str_base = (char*)part->base + part->pos;
|
||||||
|
int32_t str_size = 0;
|
||||||
|
|
||||||
|
// NOTE(allen): Shift the array so that line_i can just operate in
|
||||||
|
// it's natural value range.
|
||||||
|
indent_marks -= line_start;
|
||||||
|
|
||||||
|
for (int32_t line_i = line_start; line_i < line_end; ++line_i){
|
||||||
|
int32_t line_start = buffer_get_line_start(app, buffer, line_i);
|
||||||
|
Hard_Start_Result hard_start =
|
||||||
|
buffer_find_hard_start(app, buffer, line_start, opts.tab_width);
|
||||||
|
|
||||||
|
int32_t correct_indentation = indent_marks[line_i];
|
||||||
|
if (hard_start.all_whitespace && opts.empty_blank_lines) correct_indentation = 0;
|
||||||
|
if (correct_indentation == -1) correct_indentation = hard_start.indent_pos;
|
||||||
|
|
||||||
|
// TODO(allen): Only replace spaces if we are using space based indentation.
|
||||||
|
// TODO(allen): See if the first clause can just be removed because it's dumb.
|
||||||
|
if (!hard_start.all_space || correct_indentation != hard_start.indent_pos){
|
||||||
|
Buffer_Edit new_edit;
|
||||||
|
new_edit.str_start = str_size;
|
||||||
|
str_size += correct_indentation;
|
||||||
|
char *str = push_array(part, char, correct_indentation);
|
||||||
|
int32_t j = 0;
|
||||||
|
if (opts.use_tabs){
|
||||||
|
int32_t i = 0;
|
||||||
|
for (; i + opts.tab_width <= correct_indentation; i += opts.tab_width) str[j++] = '\t';
|
||||||
|
for (; i < correct_indentation; ++i) str[j++] = ' ';
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
for (; j < correct_indentation; ++j) str[j] = ' ';
|
||||||
|
}
|
||||||
|
new_edit.len = j;
|
||||||
|
new_edit.start = line_start;
|
||||||
|
new_edit.end = hard_start.char_pos;
|
||||||
|
edits[edit_count++] = new_edit;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert(edit_count <= edit_max);
|
||||||
}
|
}
|
||||||
|
|
||||||
Cpp_Token *result = tokens.tokens + get_token.token_index;
|
result.str = str_base;
|
||||||
|
result.str_len = str_size;
|
||||||
|
|
||||||
|
result.edits = edits;
|
||||||
|
result.edit_count = edit_count;
|
||||||
|
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_line_indents(Application_Links *app, Partition *part, Buffer_Summary *buffer,
|
||||||
|
int32_t line_start, int32_t line_end, int32_t *indent_marks, Indent_Options opts){
|
||||||
|
Buffer_Batch_Edit batch =
|
||||||
|
make_batch_from_indent_marks(app, part, buffer, line_start, line_end, indent_marks, opts);
|
||||||
|
|
||||||
|
if (batch.edit_count > 0){
|
||||||
|
app->buffer_batch_edit(app, buffer, batch.str, batch.str_len,
|
||||||
|
batch.edits, batch.edit_count, BatchEdit_PreserveTokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static Cpp_Token*
|
static Cpp_Token*
|
||||||
seek_matching_token_backwards(Cpp_Token_Array tokens, Cpp_Token *token,
|
seek_matching_token_backwards(Cpp_Token_Array tokens, Cpp_Token *token,
|
||||||
Cpp_Token_Type open_type, Cpp_Token_Type close_type){
|
Cpp_Token_Type open_type, Cpp_Token_Type close_type){
|
||||||
|
@ -119,6 +167,91 @@ seek_matching_token_backwards(Cpp_Token_Array tokens, Cpp_Token *token,
|
||||||
return(token);
|
return(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Cpp_Token*
|
||||||
|
find_anchor_token(Application_Links *app, Buffer_Summary *buffer, Cpp_Token_Array tokens,
|
||||||
|
int32_t line_start, int32_t tab_width, int32_t *current_indent_out){
|
||||||
|
Cpp_Token *token = get_first_token_at_line(app, buffer, tokens, line_start);
|
||||||
|
|
||||||
|
if (token != tokens.tokens){
|
||||||
|
--token;
|
||||||
|
for (; token > tokens.tokens; --token){
|
||||||
|
if (!(token->flags & CPP_TFLAG_PP_BODY)){
|
||||||
|
switch(token->type){
|
||||||
|
case CPP_TOKEN_BRACE_OPEN:
|
||||||
|
case CPP_TOKEN_BRACE_CLOSE:
|
||||||
|
goto out_of_loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out_of_loop:;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t current_indent = 0;
|
||||||
|
int32_t found_safe_start_position = 0;
|
||||||
|
do{
|
||||||
|
int32_t line = buffer_get_line_index(app, buffer, token->start);
|
||||||
|
int32_t start = buffer_get_line_start(app, buffer, line);
|
||||||
|
|
||||||
|
Hard_Start_Result hard_start = buffer_find_hard_start(app, buffer, start, tab_width);
|
||||||
|
current_indent = hard_start.indent_pos;
|
||||||
|
|
||||||
|
Cpp_Token *start_token = get_first_token_at_line(app, buffer, tokens, line);
|
||||||
|
Cpp_Token *brace_token = token;
|
||||||
|
|
||||||
|
if (start_token->type == CPP_TOKEN_PARENTHESE_OPEN){
|
||||||
|
if (start_token == tokens.tokens){
|
||||||
|
found_safe_start_position = 1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
token = start_token-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
int32_t close = 0;
|
||||||
|
|
||||||
|
for (token = brace_token; token > start_token; --token){
|
||||||
|
switch(token->type){
|
||||||
|
case CPP_TOKEN_PARENTHESE_CLOSE:
|
||||||
|
case CPP_TOKEN_BRACKET_CLOSE:
|
||||||
|
case CPP_TOKEN_BRACE_CLOSE:
|
||||||
|
close = token->type;
|
||||||
|
goto out_of_loop2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out_of_loop2:;
|
||||||
|
|
||||||
|
switch (close){
|
||||||
|
case 0: token = start_token; found_safe_start_position = 1; break;
|
||||||
|
|
||||||
|
case CPP_TOKEN_PARENTHESE_CLOSE:
|
||||||
|
token = seek_matching_token_backwards(tokens, token-1,
|
||||||
|
CPP_TOKEN_PARENTHESE_OPEN,
|
||||||
|
CPP_TOKEN_PARENTHESE_CLOSE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPP_TOKEN_BRACKET_CLOSE:
|
||||||
|
token = seek_matching_token_backwards(tokens, token-1,
|
||||||
|
CPP_TOKEN_BRACKET_OPEN,
|
||||||
|
CPP_TOKEN_BRACKET_CLOSE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPP_TOKEN_BRACE_CLOSE:
|
||||||
|
token = seek_matching_token_backwards(tokens, token-1,
|
||||||
|
CPP_TOKEN_BRACE_OPEN,
|
||||||
|
CPP_TOKEN_BRACE_CLOSE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while(found_safe_start_position == 0);
|
||||||
|
*current_indent_out = current_indent;
|
||||||
|
|
||||||
|
return(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Indent Rules
|
||||||
|
//
|
||||||
|
|
||||||
struct Indent_Parse_State{
|
struct Indent_Parse_State{
|
||||||
int32_t current_indent;
|
int32_t current_indent;
|
||||||
int32_t previous_line_indent;
|
int32_t previous_line_indent;
|
||||||
|
@ -135,14 +268,7 @@ compute_this_indent(Application_Links *app, Buffer_Summary *buffer, Indent_Parse
|
||||||
int32_t this_indent = 0;
|
int32_t this_indent = 0;
|
||||||
|
|
||||||
int32_t this_line_start = buffer_get_line_start(app, buffer, line_i);
|
int32_t this_line_start = buffer_get_line_start(app, buffer, line_i);
|
||||||
int32_t next_line_start = 0;
|
int32_t next_line_start = buffer_get_line_start(app, buffer, line_i+1);
|
||||||
|
|
||||||
if (line_i+1 < buffer->line_count){
|
|
||||||
next_line_start = buffer_get_line_start(app, buffer, line_i+1);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
next_line_start = buffer->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool32 did_special_behavior = false;
|
bool32 did_special_behavior = false;
|
||||||
|
|
||||||
|
@ -215,134 +341,55 @@ compute_this_indent(Application_Links *app, Buffer_Summary *buffer, Indent_Parse
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t*
|
static int32_t*
|
||||||
get_line_indentation_marks(Application_Links *app, Partition *part, Buffer_Summary *buffer, Cpp_Token_Array tokens,
|
get_indentation_marks(Application_Links *app, Partition *part, Buffer_Summary *buffer,
|
||||||
int32_t line_start, int32_t line_end, int32_t tab_width){
|
Cpp_Token_Array tokens, int32_t line_start, int32_t line_end, int32_t tab_width){
|
||||||
|
|
||||||
int32_t indent_mark_count = line_end - line_start;
|
int32_t indent_mark_count = line_end - line_start;
|
||||||
int32_t *indent_marks = push_array(part, int32_t, indent_mark_count);
|
int32_t *indent_marks = push_array(part, int32_t, indent_mark_count);
|
||||||
|
// Shift the array so line_i works correctly.
|
||||||
Indent_Parse_State indent = {0};
|
|
||||||
Cpp_Token *token = get_first_token_at_line(app, buffer, tokens, line_start);
|
|
||||||
|
|
||||||
if (token != tokens.tokens){
|
|
||||||
--token;
|
|
||||||
for (; token > tokens.tokens; --token){
|
|
||||||
if (!(token->flags & CPP_TFLAG_PP_BODY)){
|
|
||||||
switch(token->type){
|
|
||||||
case CPP_TOKEN_BRACE_OPEN:
|
|
||||||
case CPP_TOKEN_BRACE_CLOSE:
|
|
||||||
goto out_of_loop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out_of_loop:;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(allen): This can maybe be it's own function now, so that we
|
|
||||||
// can do the decls in the order we want and avoid the extra binary search.
|
|
||||||
int32_t found_safe_start_position = 0;
|
|
||||||
do{
|
|
||||||
int32_t line = buffer_get_line_index(app, buffer, token->start);
|
|
||||||
int32_t start = buffer_get_line_start(app, buffer, line);
|
|
||||||
Hard_Start_Result hard_start = buffer_find_hard_start(app, buffer, start, tab_width);
|
|
||||||
|
|
||||||
indent.current_indent = hard_start.indent_pos;
|
|
||||||
|
|
||||||
Cpp_Token *start_token = get_first_token_at_line(app, buffer, tokens, line);
|
|
||||||
Cpp_Token *brace_token = token;
|
|
||||||
|
|
||||||
if (start_token->type == CPP_TOKEN_PARENTHESE_OPEN){
|
|
||||||
if (start_token == tokens.tokens){
|
|
||||||
found_safe_start_position = 1;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
token = start_token-1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
int32_t close = 0;
|
|
||||||
|
|
||||||
for (token = brace_token; token > start_token; --token){
|
|
||||||
switch(token->type){
|
|
||||||
case CPP_TOKEN_PARENTHESE_CLOSE:
|
|
||||||
case CPP_TOKEN_BRACKET_CLOSE:
|
|
||||||
case CPP_TOKEN_BRACE_CLOSE:
|
|
||||||
close = token->type;
|
|
||||||
goto out_of_loop2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out_of_loop2:;
|
|
||||||
|
|
||||||
switch (close){
|
|
||||||
case 0: token = start_token; found_safe_start_position = 1; break;
|
|
||||||
|
|
||||||
case CPP_TOKEN_PARENTHESE_CLOSE:
|
|
||||||
token = seek_matching_token_backwards(tokens, token-1,
|
|
||||||
CPP_TOKEN_PARENTHESE_OPEN,
|
|
||||||
CPP_TOKEN_PARENTHESE_CLOSE);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CPP_TOKEN_BRACKET_CLOSE:
|
|
||||||
token = seek_matching_token_backwards(tokens, token-1,
|
|
||||||
CPP_TOKEN_BRACKET_OPEN,
|
|
||||||
CPP_TOKEN_BRACKET_CLOSE);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CPP_TOKEN_BRACE_CLOSE:
|
|
||||||
token = seek_matching_token_backwards(tokens, token-1,
|
|
||||||
CPP_TOKEN_BRACE_OPEN,
|
|
||||||
CPP_TOKEN_BRACE_CLOSE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while(found_safe_start_position == 0);
|
|
||||||
|
|
||||||
// NOTE(allen): Shift the array so that line_i can just operate in
|
|
||||||
// it's natural value range.
|
|
||||||
indent_marks -= line_start;
|
indent_marks -= line_start;
|
||||||
|
|
||||||
int32_t line_i = buffer_get_line_index(app, buffer, token->start);
|
|
||||||
|
|
||||||
if (line_i > line_start){
|
// Decide where to start indentation parsing.
|
||||||
line_i = line_start;
|
Indent_Parse_State indent = {0};
|
||||||
|
Cpp_Token *token_ptr = find_anchor_token(app, buffer, tokens, line_start,
|
||||||
|
tab_width, &indent.current_indent);
|
||||||
|
|
||||||
|
int32_t line_index = buffer_get_line_index(app, buffer, token_ptr->start);
|
||||||
|
|
||||||
|
if (line_index > line_start){
|
||||||
|
line_index = line_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t next_line_start = buffer->size;
|
int32_t next_line_start_pos = buffer_get_line_start(app, buffer, line_index+1);
|
||||||
if (line_i+1 < buffer->line_count){
|
|
||||||
next_line_start = buffer_get_line_start(app, buffer, line_i+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (token->type){
|
switch (token_ptr->type){
|
||||||
case CPP_TOKEN_BRACKET_OPEN: indent.current_indent += tab_width; break;
|
case CPP_TOKEN_BRACKET_OPEN: indent.current_indent += tab_width; break;
|
||||||
case CPP_TOKEN_BRACE_OPEN: indent.current_indent += tab_width; break;
|
case CPP_TOKEN_BRACE_OPEN: indent.current_indent += tab_width; break;
|
||||||
case CPP_TOKEN_PARENTHESE_OPEN: indent.current_indent += tab_width; break;
|
case CPP_TOKEN_PARENTHESE_OPEN: indent.current_indent += tab_width; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
indent.previous_line_indent = indent.current_indent;
|
indent.previous_line_indent = indent.current_indent;
|
||||||
Cpp_Token T;
|
|
||||||
Cpp_Token prev_token = *token;
|
|
||||||
++token;
|
|
||||||
|
|
||||||
for (; line_i < line_end; ++token){
|
for (;line_index < line_end;){
|
||||||
if (token < tokens.tokens + tokens.count){
|
Cpp_Token prev_token = *token_ptr;
|
||||||
T = *token;
|
Cpp_Token token;
|
||||||
|
|
||||||
|
++token_ptr;
|
||||||
|
if (token_ptr < tokens.tokens + tokens.count){
|
||||||
|
token = *token_ptr;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
T.type = CPP_TOKEN_EOF;
|
token.type = CPP_TOKEN_EOF;
|
||||||
T.start = buffer->size;
|
token.start = buffer->size;
|
||||||
T.flags = 0;
|
token.flags = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; T.start >= next_line_start && line_i < line_end;){
|
for (;token.start >= next_line_start_pos && line_index < line_end;){
|
||||||
if (line_i+1 < buffer->line_count){
|
next_line_start_pos = buffer_get_line_start(app, buffer, line_index+1);
|
||||||
next_line_start = buffer_get_line_start(app, buffer, line_i+1);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
next_line_start = buffer->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t this_indent =
|
int32_t this_indent =
|
||||||
compute_this_indent(app, buffer, indent, T, prev_token, line_i, tab_width);
|
compute_this_indent(app, buffer, indent, token, prev_token, line_index, tab_width);
|
||||||
|
|
||||||
// NOTE(allen): Rebase the paren anchor if the first token
|
// NOTE(allen): Rebase the paren anchor if the first token
|
||||||
// after an open paren is on the next line.
|
// after an open paren is on the next line.
|
||||||
|
@ -356,15 +403,16 @@ get_line_indentation_marks(Application_Links *app, Partition *part, Buffer_Summa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (line_i >= line_start){
|
if (line_index >= line_start){
|
||||||
indent_marks[line_i] = this_indent;
|
indent_marks[line_index] = this_indent;
|
||||||
}
|
}
|
||||||
++line_i;
|
++line_index;
|
||||||
|
|
||||||
indent.previous_line_indent = this_indent;
|
indent.previous_line_indent = this_indent;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (T.type){
|
// Update indent state.
|
||||||
|
switch (token.type){
|
||||||
case CPP_TOKEN_BRACKET_OPEN: indent.current_indent += 4; break;
|
case CPP_TOKEN_BRACKET_OPEN: indent.current_indent += 4; break;
|
||||||
case CPP_TOKEN_BRACKET_CLOSE: indent.current_indent -= 4; break;
|
case CPP_TOKEN_BRACKET_CLOSE: indent.current_indent -= 4; break;
|
||||||
case CPP_TOKEN_BRACE_OPEN: indent.current_indent += 4; break;
|
case CPP_TOKEN_BRACE_OPEN: indent.current_indent += 4; break;
|
||||||
|
@ -372,18 +420,18 @@ get_line_indentation_marks(Application_Links *app, Partition *part, Buffer_Summa
|
||||||
|
|
||||||
case CPP_TOKEN_COMMENT:
|
case CPP_TOKEN_COMMENT:
|
||||||
{
|
{
|
||||||
int32_t line = buffer_get_line_index(app, buffer, T.start);
|
int32_t line = buffer_get_line_index(app, buffer, token.start);
|
||||||
int32_t start = buffer_get_line_start(app, buffer, line);
|
int32_t start = buffer_get_line_start(app, buffer, line);
|
||||||
|
|
||||||
indent.comment_shift = (indent.current_indent - (T.start - start));
|
indent.comment_shift = (indent.current_indent - (token.start - start));
|
||||||
}break;
|
}break;
|
||||||
|
|
||||||
case CPP_TOKEN_PARENTHESE_OPEN:
|
case CPP_TOKEN_PARENTHESE_OPEN:
|
||||||
if (!(T.flags & CPP_TFLAG_PP_BODY)){
|
if (!(token.flags & CPP_TFLAG_PP_BODY)){
|
||||||
if (indent.paren_nesting < ArrayCount(indent.paren_anchor_indent)){
|
if (indent.paren_nesting < ArrayCount(indent.paren_anchor_indent)){
|
||||||
int32_t line = buffer_get_line_index(app, buffer, T.start);
|
int32_t line = buffer_get_line_index(app, buffer, token.start);
|
||||||
int32_t start = buffer_get_line_start(app, buffer, line);
|
int32_t start = buffer_get_line_start(app, buffer, line);
|
||||||
int32_t char_pos = T.start - start;
|
int32_t char_pos = token.start - start;
|
||||||
|
|
||||||
Hard_Start_Result hard_start =
|
Hard_Start_Result hard_start =
|
||||||
buffer_find_hard_start(app, buffer, start, tab_width);
|
buffer_find_hard_start(app, buffer, start, tab_width);
|
||||||
|
@ -398,126 +446,31 @@ get_line_indentation_marks(Application_Links *app, Partition *part, Buffer_Summa
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPP_TOKEN_PARENTHESE_CLOSE:
|
case CPP_TOKEN_PARENTHESE_CLOSE:
|
||||||
if (!(T.flags & CPP_TFLAG_PP_BODY)){
|
if (!(token.flags & CPP_TFLAG_PP_BODY)){
|
||||||
--indent.paren_nesting;
|
--indent.paren_nesting;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
prev_token = T;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(allen): Unshift the indent_marks array so that the return value
|
// Unshift the indent_marks array.
|
||||||
// is the exact starting point of the array that was actually allocated.
|
|
||||||
indent_marks += line_start;
|
indent_marks += line_start;
|
||||||
|
|
||||||
return(indent_marks);
|
return(indent_marks);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Make_Batch_Result{
|
|
||||||
char *str_base;
|
|
||||||
int32_t str_size;
|
|
||||||
|
|
||||||
Buffer_Edit *edits;
|
|
||||||
int32_t edit_max;
|
|
||||||
int32_t edit_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
static Make_Batch_Result
|
|
||||||
make_batch_from_indent_marks(Application_Links *app, Partition *part, Buffer_Summary *buffer,
|
|
||||||
int32_t line_start, int32_t line_end, int32_t *indent_marks, Indent_Options opts){
|
|
||||||
|
|
||||||
Make_Batch_Result result = {0};
|
|
||||||
|
|
||||||
int32_t edit_max = line_end - line_start;
|
|
||||||
int32_t edit_count = 0;
|
|
||||||
|
|
||||||
Buffer_Edit *edits = push_array(part, Buffer_Edit, edit_max);
|
|
||||||
|
|
||||||
char *str_base = (char*)part->base + part->pos;
|
|
||||||
int32_t str_size = 0;
|
|
||||||
|
|
||||||
// NOTE(allen): Shift the array so that line_i can just operate in
|
|
||||||
// it's natural value range.
|
|
||||||
indent_marks -= line_start;
|
|
||||||
|
|
||||||
for (int32_t line_i = line_start; line_i < line_end; ++line_i){
|
|
||||||
int32_t line_start = buffer_get_line_start(app, buffer, line_i);
|
|
||||||
Hard_Start_Result hard_start =
|
|
||||||
buffer_find_hard_start(app, buffer, line_start, opts.tab_width);
|
|
||||||
|
|
||||||
int32_t correct_indentation = indent_marks[line_i];
|
|
||||||
if (hard_start.all_whitespace && opts.empty_blank_lines) correct_indentation = 0;
|
|
||||||
if (correct_indentation == -1) correct_indentation = hard_start.indent_pos;
|
|
||||||
|
|
||||||
// TODO(allen): Only replace spaces if we are using space based indentation.
|
|
||||||
// TODO(allen): See if the first clause can just be removed because it's dumb.
|
|
||||||
if ((hard_start.all_whitespace && hard_start.char_pos > line_start) ||
|
|
||||||
!hard_start.all_space || correct_indentation != hard_start.indent_pos){
|
|
||||||
|
|
||||||
Buffer_Edit new_edit;
|
|
||||||
new_edit.str_start = str_size;
|
|
||||||
str_size += correct_indentation;
|
|
||||||
char *str = push_array(part, char, correct_indentation);
|
|
||||||
int32_t j = 0;
|
|
||||||
if (opts.use_tabs){
|
|
||||||
int32_t i = 0;
|
|
||||||
for (; i + opts.tab_width <= correct_indentation; i += opts.tab_width) str[j++] = '\t';
|
|
||||||
for (; i < correct_indentation; ++i) str[j++] = ' ';
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
for (; j < correct_indentation; ++j) str[j] = ' ';
|
|
||||||
}
|
|
||||||
new_edit.len = j;
|
|
||||||
new_edit.start = line_start;
|
|
||||||
new_edit.end = hard_start.char_pos;
|
|
||||||
edits[edit_count++] = new_edit;
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert(edit_count <= edit_max);
|
|
||||||
}
|
|
||||||
|
|
||||||
result.str_base = str_base;
|
|
||||||
result.str_size = str_size;
|
|
||||||
|
|
||||||
result.edits = edits;
|
|
||||||
result.edit_max = edit_max;
|
|
||||||
result.edit_count = edit_count;
|
|
||||||
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool32
|
static bool32
|
||||||
buffer_auto_indent(Application_Links *app, Partition *part, Buffer_Summary *buffer,
|
buffer_auto_indent(Application_Links *app, Partition *part, Buffer_Summary *buffer,
|
||||||
int32_t start, int32_t end, int32_t tab_width, Auto_Indent_Flag flags)/*
|
int32_t start, int32_t end, int32_t tab_width, Auto_Indent_Flag flags){
|
||||||
DOC_PARAM(buffer, The buffer specifies the buffer in which to apply auto indentation.)
|
|
||||||
DOC_PARAM(start, This parameter specifies the absolute position of the start of the indentation range.)
|
|
||||||
DOC_PARAM(end, This parameter specifies the absolute position of the end of the indentation range.)
|
|
||||||
DOC_PARAM(tab_width, The tab_width parameter specifies how many spaces should be used for one indentation in space mode.)
|
|
||||||
DOC_PARAM(flags, This parameter specifies behaviors for the indentation.)
|
|
||||||
DOC_RETURN(This call returns non-zero when the call succeeds.)
|
|
||||||
|
|
||||||
DOC(Applies the built in auto-indentation rule to the code in the range
|
|
||||||
from start to end by inserting spaces or tabs at the beginning of the
|
|
||||||
lines. If the buffer does not have lexing enabled or the lexing job has
|
|
||||||
not completed this function will fail.)
|
|
||||||
|
|
||||||
DOC_SEE(Auto_Indent_Flag)
|
|
||||||
DOC_SEE(4coder_Buffer_Positioning_System)
|
|
||||||
*/{
|
|
||||||
|
|
||||||
Indent_Options opts = {0};
|
|
||||||
|
|
||||||
bool32 result = 0;
|
bool32 result = 0;
|
||||||
if (buffer->exists && buffer->tokens_are_ready){
|
if (buffer->exists && buffer->tokens_are_ready){
|
||||||
result = 1;
|
result = 1;
|
||||||
|
|
||||||
opts.empty_blank_lines = (flags & AutoIndent_ClearLine);
|
|
||||||
opts.use_tabs = (flags & AutoIndent_UseTab);
|
|
||||||
opts.tab_width = tab_width;
|
|
||||||
|
|
||||||
Temp_Memory temp = begin_temp_memory(part);
|
Temp_Memory temp = begin_temp_memory(part);
|
||||||
|
|
||||||
// TODO(allen): Only read in the tokens in the range we need.
|
// Stage 1: Setup
|
||||||
|
// Read the tokens to be used for indentation.
|
||||||
|
// Get the first and last lines to indent.
|
||||||
Cpp_Token_Array tokens;
|
Cpp_Token_Array tokens;
|
||||||
tokens.count = app->buffer_token_count(app, buffer);
|
tokens.count = app->buffer_token_count(app, buffer);
|
||||||
tokens.max_count = tokens.count;
|
tokens.max_count = tokens.count;
|
||||||
|
@ -525,19 +478,21 @@ DOC_SEE(4coder_Buffer_Positioning_System)
|
||||||
app->buffer_read_tokens(app, buffer, 0, tokens.count, tokens.tokens);
|
app->buffer_read_tokens(app, buffer, 0, tokens.count, tokens.tokens);
|
||||||
|
|
||||||
int32_t line_start = buffer_get_line_index(app, buffer, start);
|
int32_t line_start = buffer_get_line_index(app, buffer, start);
|
||||||
int32_t line_end = buffer_get_line_index(app, buffer, end);
|
int32_t line_end = buffer_get_line_index(app, buffer, end) + 1;
|
||||||
|
|
||||||
|
// Stage 2: Decide Indent Amounts
|
||||||
|
// Get an array representing how much each line in [line_start,line_end]
|
||||||
|
// should be indented.
|
||||||
int32_t *indent_marks =
|
int32_t *indent_marks =
|
||||||
get_line_indentation_marks(app, part, buffer, tokens,
|
get_indentation_marks(app, part, buffer, tokens, line_start, line_end, tab_width);
|
||||||
line_start, line_end, opts.tab_width);
|
|
||||||
|
|
||||||
Make_Batch_Result batch =
|
// Stage 3: Set the Line Indents
|
||||||
make_batch_from_indent_marks(app, part, buffer, line_start, line_end, indent_marks, opts);
|
Indent_Options opts = {0};
|
||||||
|
opts.empty_blank_lines = (flags & AutoIndent_ClearLine);
|
||||||
|
opts.use_tabs = (flags & AutoIndent_UseTab);
|
||||||
|
opts.tab_width = tab_width;
|
||||||
|
|
||||||
if (batch.edit_count > 0){
|
set_line_indents(app, part, buffer, line_start, line_end, indent_marks, opts);
|
||||||
app->buffer_batch_edit(app, buffer, batch.str_base, batch.str_size,
|
|
||||||
batch.edits, batch.edit_count, BatchEdit_PreserveTokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
end_temp_memory(temp);
|
end_temp_memory(temp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -547,6 +547,46 @@ buffer_seek_string_insensitive_backward(Application_Links *app, Buffer_Summary *
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Some Basic Buffer Positioning
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "4cpp_lexer.h"
|
||||||
|
|
||||||
|
static int32_t
|
||||||
|
buffer_get_line_start(Application_Links *app, Buffer_Summary *buffer, int32_t line){
|
||||||
|
Partial_Cursor partial_cursor;
|
||||||
|
int32_t result = buffer->size;
|
||||||
|
if (line < buffer->line_count){
|
||||||
|
app->buffer_compute_cursor(app, buffer, seek_line_char(line, 1), &partial_cursor);
|
||||||
|
result = partial_cursor.pos;
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t
|
||||||
|
buffer_get_line_index(Application_Links *app, Buffer_Summary *buffer, int32_t pos){
|
||||||
|
Partial_Cursor partial_cursor;
|
||||||
|
app->buffer_compute_cursor(app, buffer, seek_pos(pos), &partial_cursor);
|
||||||
|
return(partial_cursor.line);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Cpp_Token*
|
||||||
|
get_first_token_at_line(Application_Links *app, Buffer_Summary *buffer, Cpp_Token_Array tokens, int32_t line){
|
||||||
|
int32_t line_start = buffer_get_line_start(app, buffer, line);
|
||||||
|
Cpp_Get_Token_Result get_token = cpp_get_token(&tokens, line_start);
|
||||||
|
|
||||||
|
if (get_token.in_whitespace){
|
||||||
|
get_token.token_index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cpp_Token *result = tokens.tokens + get_token.token_index;
|
||||||
|
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Fundamental Editing
|
// Fundamental Editing
|
||||||
//
|
//
|
||||||
|
|
|
@ -123,15 +123,6 @@ ENUM(int32_t, Event_Message_Type_ID){
|
||||||
EventMessage_CloseView
|
EventMessage_CloseView
|
||||||
};
|
};
|
||||||
|
|
||||||
/* DOC(A Buffer_Batch_Edit_Type is a type of batch operation.) */
|
|
||||||
ENUM(int32_t, Buffer_Batch_Edit_Type){
|
|
||||||
/* DOC(The BatchEdit_Normal operation is always correct but does the most work.) */
|
|
||||||
BatchEdit_Normal,
|
|
||||||
/* DOC(The BatchEdit_PreserveTokens operation is one in which none of the edits add, delete, or change any tokens.
|
|
||||||
This usually applies when whitespace is being replaced with whitespace.) */
|
|
||||||
BatchEdit_PreserveTokens
|
|
||||||
};
|
|
||||||
|
|
||||||
/* DOC(A Buffer_Setting_ID names a setting in a buffer.) */
|
/* DOC(A Buffer_Setting_ID names a setting in a buffer.) */
|
||||||
ENUM(int32_t, Buffer_Setting_ID){
|
ENUM(int32_t, Buffer_Setting_ID){
|
||||||
/* DOC(BufferSetting_Null is not a valid setting, it is reserved to detect errors.) */
|
/* DOC(BufferSetting_Null is not a valid setting, it is reserved to detect errors.) */
|
||||||
|
@ -702,14 +693,41 @@ struct Event_Message{
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
DOC(Theme_Color stores a style tag/color pair, for the purpose of setting and getting colors in the theme .)
|
DOC(Theme_Color stores a style tag/color pair, for the purpose of setting and getting colors in the theme.)
|
||||||
DOC_SEE(Style_Tag)
|
DOC_SEE(Style_Tag)
|
||||||
DOC_SEE(int_color)
|
DOC_SEE(int_color)
|
||||||
*/
|
*/
|
||||||
struct Theme_Color{
|
struct Theme_Color{
|
||||||
|
/* DOC(The style slot in the style palette.) */
|
||||||
Style_Tag tag;
|
Style_Tag tag;
|
||||||
|
/* DOC(The color in the slot.) */
|
||||||
int_color color;
|
int_color color;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* DOC(A Buffer_Batch_Edit_Type is a type of batch operation.) */
|
||||||
|
ENUM(int32_t, Buffer_Batch_Edit_Type){
|
||||||
|
/* DOC(The BatchEdit_Normal operation is always correct but does the most work if there are tokens to correct.) */
|
||||||
|
BatchEdit_Normal,
|
||||||
|
/* DOC(The BatchEdit_PreserveTokens operation is one in which none of the edits add, delete, or change any tokens.
|
||||||
|
This usually applies when whitespace is being replaced with whitespace.) */
|
||||||
|
BatchEdit_PreserveTokens
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
DOC(This struct is used to bundle the parameters of the buffer_batch_edit function. It is convenient
|
||||||
|
for a few functions that return a batch edit to the user.)
|
||||||
|
DOC_SEE(buffer_batch_edit)
|
||||||
|
*/
|
||||||
|
struct Buffer_Batch_Edit{
|
||||||
|
/* DOC(The pointer to the edit string buffer.) */
|
||||||
|
char *str;
|
||||||
|
/* DOC(The length of the edit string buffer.) */
|
||||||
|
int32_t str_len;
|
||||||
|
|
||||||
|
/* DOC(The array of edits to be applied.) */
|
||||||
|
Buffer_Edit *edits;
|
||||||
|
/* DOC(The number of edits in the array.) */
|
||||||
|
int32_t edit_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1295,10 +1295,10 @@ in the system, the call will fail.)
|
||||||
Assert(panel_ptr != panel);
|
Assert(panel_ptr != panel);
|
||||||
active = (i32)(panel_ptr - models->layout.panels);
|
active = (i32)(panel_ptr - models->layout.panels);
|
||||||
}
|
}
|
||||||
|
Assert(active != -1 && panel != models->layout.panels + active);
|
||||||
|
|
||||||
// If the panel we're closing was previously active, we have to switch to it's sibling.
|
// If the panel we're closing was previously active, we have to switch to it's sibling.
|
||||||
if (models->layout.active_panel == (i32)(panel - models->layout.panels)){
|
if (models->layout.active_panel == (i32)(panel - models->layout.panels)){
|
||||||
Assert(active != -1 && panel != models->layout.panels + active);
|
|
||||||
models->layout.active_panel = active;
|
models->layout.active_panel = active;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5123,26 +5123,6 @@ draw_file_bar(Render_Target *target, View *view, Editing_File *file, i32_Rect re
|
||||||
append_ss(&bar_text, make_lit_string(" nix"));
|
append_ss(&bar_text, make_lit_string(" nix"));
|
||||||
}
|
}
|
||||||
|
|
||||||
append_ss(&bar_text, make_lit_string(" -"));
|
|
||||||
|
|
||||||
Command_Map *map = view->map;
|
|
||||||
if (map == &models->map_top){
|
|
||||||
append_ss(&bar_text, make_lit_string(" global"));
|
|
||||||
}
|
|
||||||
else if (map == &models->map_file){
|
|
||||||
append_ss(&bar_text, make_lit_string(" file"));
|
|
||||||
}
|
|
||||||
else if (map == &models->map_ui){
|
|
||||||
append_ss(&bar_text, make_lit_string(" gui"));
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
i32 map_index = (i32)(view->map - models->user_maps);
|
|
||||||
i32 map_id = models->map_id_table[map_index];
|
|
||||||
|
|
||||||
append_ss (&bar_text, make_lit_string(" user:"));
|
|
||||||
append_int_to_str(&bar_text, map_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
intbar_draw_string(target, &bar, bar_text, base_color);
|
intbar_draw_string(target, &bar, bar_text, base_color);
|
||||||
|
|
||||||
|
|
||||||
|
|
24
TODO.txt
24
TODO.txt
|
@ -82,30 +82,32 @@
|
||||||
|
|
||||||
; BEFORE I SHIP
|
; BEFORE I SHIP
|
||||||
;
|
;
|
||||||
|
; [X] killing compilation panel changes active panel
|
||||||
; [X] tokens in the custom API
|
; [X] tokens in the custom API
|
||||||
; [X] token seeking on custom side
|
; [X] token seeking on custom side
|
||||||
; [X] auto indent on the custom side
|
; [X] auto indent on the custom side
|
||||||
; [] clean up and comment the auto indent code to allow for customizations
|
; [] clean up and comment the auto indent code to allow for customizations
|
||||||
; [] more built in options for auto indenting
|
; [] more built in options for auto indenting
|
||||||
; [] expose dirty flags
|
; [] expose dirty flags
|
||||||
; [] option to not open *messages* every startup
|
|
||||||
; [] commands for resizing panels
|
|
||||||
; [] make panel resizing not whacky with child panels
|
; [] make panel resizing not whacky with child panels
|
||||||
; [] killing compilation panel changes active panel
|
|
||||||
; [] control over how mouse effects panel focus
|
|
||||||
; [] API docs as text file
|
|
||||||
; [] user file bar string
|
|
||||||
; [] mouse down/up distinction
|
; [] mouse down/up distinction
|
||||||
; [] hook on exit
|
; [] hook on exit
|
||||||
; [] read only files
|
|
||||||
; [] occasionally missing the (!) mark on files on windows
|
; [] occasionally missing the (!) mark on files on windows
|
||||||
; [] case insensitive interactive switch buffer
|
; [] case insensitive interactive switch buffer
|
||||||
; [] option to hide hidden files
|
|
||||||
; [] tab to complete folder names in the new file dialogue
|
|
||||||
; [] view fails to follow cursor when the view is shrunk
|
|
||||||
; [] view fails to follow cursor after deleting long line
|
|
||||||
; [] scroll down on compilation buffer durring compilation
|
; [] scroll down on compilation buffer durring compilation
|
||||||
;
|
;
|
||||||
|
;
|
||||||
|
|
||||||
|
; [] commands for resizing panels
|
||||||
|
; [] user file bar string
|
||||||
|
; [] option to not open *messages* every startup
|
||||||
|
; [] API docs as text file
|
||||||
|
; [] read only files
|
||||||
|
; [] tab to complete folder names in the new file dialogue
|
||||||
|
; [] option to hide hidden files
|
||||||
|
; [] view fails to follow cursor when the view is shrunk
|
||||||
|
; [] view fails to follow cursor after deleting long line
|
||||||
|
; [] control over how mouse effects panel focus
|
||||||
|
|
||||||
; TODOS
|
; TODOS
|
||||||
; [X] success message when compiler works
|
; [X] success message when compiler works
|
||||||
|
|
Loading…
Reference in New Issue