implemented custom side auto indent
This commit is contained in:
parent
992058578d
commit
bdd893438d
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,556 @@
|
|||
|
||||
#ifndef FCODER_AUTO_INDENT_INC
|
||||
#define FCODER_AUTO_INDENT_INC
|
||||
|
||||
struct Hard_Start_Result{
|
||||
int32_t char_pos;
|
||||
int32_t indent_pos;
|
||||
int32_t all_whitespace;
|
||||
int32_t all_space;
|
||||
};
|
||||
|
||||
static Hard_Start_Result
|
||||
buffer_find_hard_start(Application_Links *app, Buffer_Summary *buffer, int32_t line_start, int32_t tab_width){
|
||||
Hard_Start_Result result = {0};
|
||||
char data_chunk[1024];
|
||||
Stream_Chunk stream = {0};
|
||||
char c;
|
||||
|
||||
tab_width -= 1;
|
||||
|
||||
result.all_space = 1;
|
||||
result.indent_pos = 0;
|
||||
result.char_pos = line_start;
|
||||
|
||||
stream.add_null = 1;
|
||||
if (init_stream_chunk(&stream, app, buffer, line_start, data_chunk, sizeof(data_chunk))){
|
||||
int32_t still_looping = 1;
|
||||
do{
|
||||
for (; result.char_pos < stream.end; ++result.char_pos){
|
||||
c = stream.data[result.char_pos];
|
||||
|
||||
if (c == '\n' || c == 0){
|
||||
result.all_whitespace = 1;
|
||||
goto double_break;
|
||||
}
|
||||
|
||||
if (c >= '!' && c <= '~'){
|
||||
goto double_break;
|
||||
}
|
||||
|
||||
if (c == '\t'){
|
||||
result.indent_pos += tab_width;
|
||||
}
|
||||
|
||||
if (c != ' '){
|
||||
result.all_space = 0;
|
||||
}
|
||||
|
||||
result.indent_pos += 1;
|
||||
}
|
||||
still_looping = forward_stream_chunk(&stream);
|
||||
}while(still_looping);
|
||||
}
|
||||
|
||||
double_break:;
|
||||
return(result);
|
||||
}
|
||||
|
||||
struct Indent_Options{
|
||||
bool32 empty_blank_lines;
|
||||
bool32 use_tabs;
|
||||
int32_t tab_width;
|
||||
};
|
||||
|
||||
#include "4cpp_lexer.h"
|
||||
|
||||
static int32_t
|
||||
buffer_get_line_start(Application_Links *app, Buffer_Summary *buffer, int32_t line){
|
||||
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){
|
||||
get_token.token_index += 1;
|
||||
}
|
||||
|
||||
Cpp_Token *result = tokens.tokens + get_token.token_index;
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
static Cpp_Token*
|
||||
seek_matching_token_backwards(Cpp_Token_Array tokens, Cpp_Token *token,
|
||||
Cpp_Token_Type open_type, Cpp_Token_Type close_type){
|
||||
int32_t nesting_level = 0;
|
||||
if (token <= tokens.tokens){
|
||||
token = tokens.tokens;
|
||||
}
|
||||
else{
|
||||
for (; token > tokens.tokens; --token){
|
||||
if (!(token->flags & CPP_TFLAG_PP_BODY)){
|
||||
if (token->type == close_type){
|
||||
++nesting_level;
|
||||
}
|
||||
else if (token->type == open_type){
|
||||
if (nesting_level == 0){
|
||||
break;
|
||||
}
|
||||
else{
|
||||
--nesting_level;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return(token);
|
||||
}
|
||||
|
||||
struct Indent_Parse_State{
|
||||
int32_t current_indent;
|
||||
int32_t previous_line_indent;
|
||||
int32_t paren_nesting;
|
||||
int32_t paren_anchor_indent[16];
|
||||
int32_t comment_shift;
|
||||
};
|
||||
|
||||
static int32_t
|
||||
compute_this_indent(Application_Links *app, Buffer_Summary *buffer, Indent_Parse_State indent,
|
||||
Cpp_Token T, Cpp_Token prev_token, int32_t line_i, int32_t tab_width){
|
||||
|
||||
int32_t previous_indent = indent.previous_line_indent;
|
||||
int32_t this_indent = 0;
|
||||
|
||||
int32_t this_line_start = buffer_get_line_start(app, buffer, line_i);
|
||||
int32_t next_line_start = 0;
|
||||
|
||||
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;
|
||||
|
||||
if (prev_token.start <= this_line_start &&
|
||||
prev_token.start + prev_token.size > this_line_start){
|
||||
if (prev_token.type == CPP_TOKEN_COMMENT){
|
||||
Hard_Start_Result hard_start = buffer_find_hard_start(app, buffer, this_line_start, tab_width);
|
||||
|
||||
if (hard_start.all_whitespace){
|
||||
this_indent = previous_indent;
|
||||
did_special_behavior = true;
|
||||
}
|
||||
else{
|
||||
int32_t line_pos = hard_start.char_pos - this_line_start;
|
||||
this_indent = line_pos + indent.comment_shift;
|
||||
if (this_indent < 0){
|
||||
this_indent = 0;
|
||||
}
|
||||
did_special_behavior = true;
|
||||
}
|
||||
}
|
||||
else if (prev_token.type == CPP_TOKEN_STRING_CONSTANT){
|
||||
this_indent = previous_indent;
|
||||
did_special_behavior = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!did_special_behavior){
|
||||
this_indent = indent.current_indent;
|
||||
if (T.start < next_line_start){
|
||||
if (T.flags & CPP_TFLAG_PP_DIRECTIVE){
|
||||
this_indent = 0;
|
||||
}
|
||||
else{
|
||||
switch (T.type){
|
||||
case CPP_TOKEN_BRACKET_CLOSE: this_indent -= tab_width; break;
|
||||
case CPP_TOKEN_BRACE_CLOSE: this_indent -= tab_width; break;
|
||||
case CPP_TOKEN_BRACE_OPEN: break;
|
||||
|
||||
default:
|
||||
if (indent.current_indent > 0){
|
||||
if (!(prev_token.flags & CPP_TFLAG_PP_BODY ||
|
||||
prev_token.flags & CPP_TFLAG_PP_DIRECTIVE)){
|
||||
switch (prev_token.type){
|
||||
case CPP_TOKEN_BRACKET_OPEN:
|
||||
case CPP_TOKEN_BRACE_OPEN: case CPP_TOKEN_BRACE_CLOSE:
|
||||
case CPP_TOKEN_SEMICOLON: case CPP_TOKEN_COLON:
|
||||
case CPP_TOKEN_COMMA: case CPP_TOKEN_COMMENT: break;
|
||||
default: this_indent += tab_width;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this_indent < 0) this_indent = 0;
|
||||
}
|
||||
|
||||
if (indent.paren_nesting > 0){
|
||||
if (prev_token.type != CPP_TOKEN_PARENTHESE_OPEN){
|
||||
int32_t level = indent.paren_nesting-1;
|
||||
if (level >= ArrayCount(indent.paren_anchor_indent)){
|
||||
level = ArrayCount(indent.paren_anchor_indent)-1;
|
||||
}
|
||||
this_indent = indent.paren_anchor_indent[level];
|
||||
}
|
||||
}
|
||||
return(this_indent);
|
||||
}
|
||||
|
||||
static int32_t*
|
||||
get_line_indentation_marks(Application_Links *app, Partition *part, Buffer_Summary *buffer, 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_marks = push_array(part, int32_t, indent_mark_count);
|
||||
|
||||
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;
|
||||
|
||||
int32_t line_i = buffer_get_line_index(app, buffer, token->start);
|
||||
|
||||
if (line_i > line_start){
|
||||
line_i = line_start;
|
||||
}
|
||||
|
||||
int32_t next_line_start = buffer->size;
|
||||
if (line_i+1 < buffer->line_count){
|
||||
next_line_start = buffer_get_line_start(app, buffer, line_i+1);
|
||||
}
|
||||
|
||||
switch (token->type){
|
||||
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_PARENTHESE_OPEN: indent.current_indent += tab_width; break;
|
||||
}
|
||||
|
||||
indent.previous_line_indent = indent.current_indent;
|
||||
Cpp_Token T;
|
||||
Cpp_Token prev_token = *token;
|
||||
++token;
|
||||
|
||||
for (; line_i < line_end; ++token){
|
||||
if (token < tokens.tokens + tokens.count){
|
||||
T = *token;
|
||||
}
|
||||
else{
|
||||
T.type = CPP_TOKEN_EOF;
|
||||
T.start = buffer->size;
|
||||
T.flags = 0;
|
||||
}
|
||||
|
||||
for (; T.start >= next_line_start && line_i < line_end;){
|
||||
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;
|
||||
}
|
||||
|
||||
int32_t this_indent =
|
||||
compute_this_indent(app, buffer, indent, T, prev_token, line_i, tab_width);
|
||||
|
||||
// NOTE(allen): Rebase the paren anchor if the first token
|
||||
// after an open paren is on the next line.
|
||||
if (indent.paren_nesting > 0){
|
||||
if (prev_token.type == CPP_TOKEN_PARENTHESE_OPEN){
|
||||
int32_t level = indent.paren_nesting-1;
|
||||
if (level >= ArrayCount(indent.paren_anchor_indent)){
|
||||
level = ArrayCount(indent.paren_anchor_indent)-1;
|
||||
}
|
||||
indent.paren_anchor_indent[level] = this_indent;
|
||||
}
|
||||
}
|
||||
|
||||
if (line_i >= line_start){
|
||||
indent_marks[line_i] = this_indent;
|
||||
}
|
||||
++line_i;
|
||||
|
||||
indent.previous_line_indent = this_indent;
|
||||
}
|
||||
|
||||
switch (T.type){
|
||||
case CPP_TOKEN_BRACKET_OPEN: 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_CLOSE: indent.current_indent -= 4; break;
|
||||
|
||||
case CPP_TOKEN_COMMENT:
|
||||
{
|
||||
int32_t line = buffer_get_line_index(app, buffer, T.start);
|
||||
int32_t start = buffer_get_line_start(app, buffer, line);
|
||||
|
||||
indent.comment_shift = (indent.current_indent - (T.start - start));
|
||||
}break;
|
||||
|
||||
case CPP_TOKEN_PARENTHESE_OPEN:
|
||||
if (!(T.flags & CPP_TFLAG_PP_BODY)){
|
||||
if (indent.paren_nesting < ArrayCount(indent.paren_anchor_indent)){
|
||||
int32_t line = buffer_get_line_index(app, buffer, T.start);
|
||||
int32_t start = buffer_get_line_start(app, buffer, line);
|
||||
int32_t char_pos = T.start - start;
|
||||
|
||||
Hard_Start_Result hard_start =
|
||||
buffer_find_hard_start(app, buffer, start, tab_width);
|
||||
|
||||
int32_t line_pos = hard_start.char_pos - start;
|
||||
|
||||
indent.paren_anchor_indent[indent.paren_nesting] =
|
||||
char_pos - line_pos + indent.previous_line_indent + 1;
|
||||
}
|
||||
++indent.paren_nesting;
|
||||
}
|
||||
break;
|
||||
|
||||
case CPP_TOKEN_PARENTHESE_CLOSE:
|
||||
if (!(T.flags & CPP_TFLAG_PP_BODY)){
|
||||
--indent.paren_nesting;
|
||||
}
|
||||
break;
|
||||
}
|
||||
prev_token = T;
|
||||
}
|
||||
|
||||
// NOTE(allen): Unshift the indent_marks array so that the return value
|
||||
// is the exact starting point of the array that was actually allocated.
|
||||
indent_marks += line_start;
|
||||
|
||||
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
|
||||
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)/*
|
||||
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;
|
||||
if (buffer->exists && buffer->tokens_are_ready){
|
||||
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);
|
||||
|
||||
// TODO(allen): Only read in the tokens in the range we need.
|
||||
Cpp_Token_Array tokens;
|
||||
tokens.count = app->buffer_token_count(app, buffer);
|
||||
tokens.max_count = tokens.count;
|
||||
tokens.tokens = push_array(part, Cpp_Token, tokens.count);
|
||||
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_end = buffer_get_line_index(app, buffer, end);
|
||||
|
||||
int32_t *indent_marks =
|
||||
get_line_indentation_marks(app, part, buffer, tokens,
|
||||
line_start, line_end, opts.tab_width);
|
||||
|
||||
Make_Batch_Result 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_base, batch.str_size,
|
||||
batch.edits, batch.edit_count, BatchEdit_PreserveTokens);
|
||||
}
|
||||
|
||||
end_temp_memory(temp);
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
static bool32
|
||||
buffer_auto_indent(Application_Links *app, Buffer_Summary *buffer,
|
||||
int32_t start, int32_t end, int32_t tab_width, Auto_Indent_Flag flags){
|
||||
bool32 result = buffer_auto_indent(app, &global_part, buffer, start, end, tab_width, flags);
|
||||
return(result);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -14,7 +14,8 @@
|
|||
#define BUFFER_COMPUTE_CURSOR_SIG(n) bool32 n(Application_Links *app, Buffer_Summary *buffer, Buffer_Seek seek, Partial_Cursor *cursor_out)
|
||||
#define BUFFER_BATCH_EDIT_SIG(n) bool32 n(Application_Links *app, Buffer_Summary *buffer, char *str, int32_t str_len, Buffer_Edit *edits, int32_t edit_count, Buffer_Batch_Edit_Type type)
|
||||
#define BUFFER_SET_SETTING_SIG(n) bool32 n(Application_Links *app, Buffer_Summary *buffer, Buffer_Setting_ID setting, int32_t value)
|
||||
#define BUFFER_AUTO_INDENT_SIG(n) bool32 n(Application_Links *app, Buffer_Summary *buffer, int32_t start, int32_t end, int32_t tab_width, Auto_Indent_Flag flags)
|
||||
#define BUFFER_TOKEN_COUNT_SIG(n) int32_t n(Application_Links *app, Buffer_Summary *buffer)
|
||||
#define BUFFER_READ_TOKENS_SIG(n) bool32 n(Application_Links *app, Buffer_Summary *buffer, int32_t first_token, int32_t last_token, Cpp_Token *tokens_out)
|
||||
#define CREATE_BUFFER_SIG(n) Buffer_Summary n(Application_Links *app, char *filename, int32_t filename_len, Buffer_Create_Flag flags)
|
||||
#define SAVE_BUFFER_SIG(n) bool32 n(Application_Links *app, Buffer_Summary *buffer, char *filename, int32_t filename_len, uint32_t flags)
|
||||
#define KILL_BUFFER_SIG(n) bool32 n(Application_Links *app, Buffer_Identifier buffer, View_ID view_id, Buffer_Kill_Flag flags)
|
||||
|
@ -74,7 +75,8 @@ typedef BUFFER_REPLACE_RANGE_SIG(Buffer_Replace_Range_Function);
|
|||
typedef BUFFER_COMPUTE_CURSOR_SIG(Buffer_Compute_Cursor_Function);
|
||||
typedef BUFFER_BATCH_EDIT_SIG(Buffer_Batch_Edit_Function);
|
||||
typedef BUFFER_SET_SETTING_SIG(Buffer_Set_Setting_Function);
|
||||
typedef BUFFER_AUTO_INDENT_SIG(Buffer_Auto_Indent_Function);
|
||||
typedef BUFFER_TOKEN_COUNT_SIG(Buffer_Token_Count_Function);
|
||||
typedef BUFFER_READ_TOKENS_SIG(Buffer_Read_Tokens_Function);
|
||||
typedef CREATE_BUFFER_SIG(Create_Buffer_Function);
|
||||
typedef SAVE_BUFFER_SIG(Save_Buffer_Function);
|
||||
typedef KILL_BUFFER_SIG(Kill_Buffer_Function);
|
||||
|
@ -135,7 +137,8 @@ Buffer_Replace_Range_Function *buffer_replace_range;
|
|||
Buffer_Compute_Cursor_Function *buffer_compute_cursor;
|
||||
Buffer_Batch_Edit_Function *buffer_batch_edit;
|
||||
Buffer_Set_Setting_Function *buffer_set_setting;
|
||||
Buffer_Auto_Indent_Function *buffer_auto_indent;
|
||||
Buffer_Token_Count_Function *buffer_token_count;
|
||||
Buffer_Read_Tokens_Function *buffer_read_tokens;
|
||||
Create_Buffer_Function *create_buffer;
|
||||
Save_Buffer_Function *save_buffer;
|
||||
Kill_Buffer_Function *kill_buffer;
|
||||
|
@ -203,7 +206,8 @@ app_links->buffer_replace_range = Buffer_Replace_Range;\
|
|||
app_links->buffer_compute_cursor = Buffer_Compute_Cursor;\
|
||||
app_links->buffer_batch_edit = Buffer_Batch_Edit;\
|
||||
app_links->buffer_set_setting = Buffer_Set_Setting;\
|
||||
app_links->buffer_auto_indent = Buffer_Auto_Indent;\
|
||||
app_links->buffer_token_count = Buffer_Token_Count;\
|
||||
app_links->buffer_read_tokens = Buffer_Read_Tokens;\
|
||||
app_links->create_buffer = Create_Buffer;\
|
||||
app_links->save_buffer = Save_Buffer;\
|
||||
app_links->kill_buffer = Kill_Buffer;\
|
||||
|
|
|
@ -142,6 +142,7 @@ struct Stream_Chunk{
|
|||
char *base_data;
|
||||
int32_t start, end;
|
||||
int32_t min_start, max_end;
|
||||
bool32 add_null;
|
||||
int32_t data_size;
|
||||
|
||||
char *data;
|
||||
|
@ -175,11 +176,11 @@ refresh_view(Application_Links *app, View_Summary *view){
|
|||
*view = app->get_view(app, view->view_id, AccessAll);
|
||||
}
|
||||
|
||||
int32_t
|
||||
bool32
|
||||
init_stream_chunk(Stream_Chunk *chunk,
|
||||
Application_Links *app, Buffer_Summary *buffer,
|
||||
int32_t pos, char *data, int32_t size){
|
||||
int32_t result = false;
|
||||
bool32 result = false;
|
||||
|
||||
refresh_buffer(app, buffer);
|
||||
if (pos >= 0 && pos < buffer->size && size > 0){
|
||||
|
@ -190,8 +191,7 @@ init_stream_chunk(Stream_Chunk *chunk,
|
|||
chunk->start = round_down(pos, size);
|
||||
chunk->end = round_up(pos, size);
|
||||
|
||||
if (chunk->max_end > buffer->size
|
||||
|| chunk->max_end == 0){
|
||||
if (chunk->max_end > buffer->size || chunk->max_end == 0){
|
||||
chunk->max_end = buffer->size;
|
||||
}
|
||||
|
||||
|
@ -235,6 +235,15 @@ forward_stream_chunk(Stream_Chunk *chunk){
|
|||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
else if (chunk->add_null && chunk->end + 1 < buffer->size){
|
||||
chunk->start = buffer->size;
|
||||
chunk->end = buffer->size + 1;
|
||||
chunk->base_data[0] = 0;
|
||||
chunk->data = chunk->base_data - chunk->start;
|
||||
result = true;
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
@ -262,6 +271,14 @@ backward_stream_chunk(Stream_Chunk *chunk){
|
|||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
else if (chunk->add_null && chunk->start > -1){
|
||||
chunk->start = -1;
|
||||
chunk->end = 0;
|
||||
chunk->base_data[0] = 0;
|
||||
chunk->data = chunk->base_data - chunk->start;
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
@ -887,17 +904,17 @@ move_past_lead_whitespace(Application_Links *app, View_Summary *view, Buffer_Sum
|
|||
}
|
||||
}
|
||||
|
||||
//#include "4coder_auto_indent.cpp"
|
||||
#include "4coder_auto_indent.cpp"
|
||||
|
||||
CUSTOM_COMMAND_SIG(auto_tab_line_at_cursor){
|
||||
uint32_t access = AccessOpen;
|
||||
View_Summary view = app->get_active_view(app, access);
|
||||
Buffer_Summary buffer = app->get_buffer(app, view.buffer_id, access);
|
||||
|
||||
app->buffer_auto_indent(app, &buffer,
|
||||
view.cursor.pos, view.cursor.pos,
|
||||
DEF_TAB_WIDTH,
|
||||
DEFAULT_INDENT_FLAGS);
|
||||
buffer_auto_indent(app, &buffer,
|
||||
view.cursor.pos, view.cursor.pos,
|
||||
DEF_TAB_WIDTH,
|
||||
DEFAULT_INDENT_FLAGS);
|
||||
move_past_lead_whitespace(app, &view, &buffer);
|
||||
}
|
||||
|
||||
|
@ -906,10 +923,10 @@ CUSTOM_COMMAND_SIG(auto_tab_whole_file){
|
|||
View_Summary view = app->get_active_view(app, access);
|
||||
Buffer_Summary buffer = app->get_buffer(app, view.buffer_id, access);
|
||||
|
||||
app->buffer_auto_indent(app, &buffer,
|
||||
0, buffer.size,
|
||||
DEF_TAB_WIDTH,
|
||||
DEFAULT_INDENT_FLAGS);
|
||||
buffer_auto_indent(app, &buffer,
|
||||
0, buffer.size,
|
||||
DEF_TAB_WIDTH,
|
||||
DEFAULT_INDENT_FLAGS);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(auto_tab_range){
|
||||
|
@ -918,10 +935,10 @@ CUSTOM_COMMAND_SIG(auto_tab_range){
|
|||
Buffer_Summary buffer = app->get_buffer(app, view.buffer_id, access);
|
||||
Range range = get_range(&view);
|
||||
|
||||
app->buffer_auto_indent(app, &buffer,
|
||||
range.min, range.max,
|
||||
DEF_TAB_WIDTH,
|
||||
DEFAULT_INDENT_FLAGS);
|
||||
buffer_auto_indent(app, &buffer,
|
||||
range.min, range.max,
|
||||
DEF_TAB_WIDTH,
|
||||
DEFAULT_INDENT_FLAGS);
|
||||
move_past_lead_whitespace(app, &view, &buffer);
|
||||
}
|
||||
|
||||
|
@ -1417,10 +1434,10 @@ long_braces(Application_Links *app, char *text, int32_t size){
|
|||
app->buffer_replace_range(app, &buffer, pos, pos, text, size);
|
||||
app->view_set_cursor(app, &view, seek_pos(pos + 2), true);
|
||||
|
||||
app->buffer_auto_indent(app, &buffer,
|
||||
pos, pos + size,
|
||||
DEF_TAB_WIDTH,
|
||||
DEFAULT_INDENT_FLAGS);
|
||||
buffer_auto_indent(app, &buffer,
|
||||
pos, pos + size,
|
||||
DEF_TAB_WIDTH,
|
||||
DEFAULT_INDENT_FLAGS);
|
||||
move_past_lead_whitespace(app, &view, &buffer);
|
||||
}
|
||||
|
||||
|
@ -1491,10 +1508,10 @@ CUSTOM_COMMAND_SIG(if0_off){
|
|||
}
|
||||
|
||||
range = get_range(&view);
|
||||
app->buffer_auto_indent(app, &buffer,
|
||||
range.min, range.max,
|
||||
DEF_TAB_WIDTH,
|
||||
DEFAULT_INDENT_FLAGS);
|
||||
buffer_auto_indent(app, &buffer,
|
||||
range.min, range.max,
|
||||
DEF_TAB_WIDTH,
|
||||
DEFAULT_INDENT_FLAGS);
|
||||
move_past_lead_whitespace(app, &view, &buffer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -607,6 +607,11 @@ struct Buffer_Summary{
|
|||
|
||||
/* DOC(If this is not a null summary, this field indicates whether the buffer is set to lex tokens.) */
|
||||
bool32 is_lexed;
|
||||
/* DOC(If this is not a null summary, this field indicates whether the buffer has up to date tokens available.
|
||||
If this field is false, it may simply mean the tokens are still being generated in a background task and will
|
||||
be available later. If that is the case, is_lexed will be true to indicate that the buffer is trying to get
|
||||
it's tokens up to date.) */
|
||||
bool32 tokens_are_ready;
|
||||
/* DOC(If this is not a null summary, this field specifies the id of the command map for this buffer.) */
|
||||
int32_t map_id;
|
||||
/* DOC(If this is not a null summary, this field indicates whether the buffer 'prefers' wrapped lines.) */
|
||||
|
|
|
@ -32,6 +32,16 @@ fill_buffer_summary(Buffer_Summary *buffer, Editing_File *file, Working_Set *wor
|
|||
buffer->buffer_name = file->name.live_name.str;
|
||||
|
||||
buffer->is_lexed = file->settings.tokens_exist;
|
||||
|
||||
if (file->state.token_array.tokens &&
|
||||
file->state.tokens_complete &&
|
||||
!file->state.still_lexing){
|
||||
buffer->tokens_are_ready = 1;
|
||||
}
|
||||
else{
|
||||
buffer->tokens_are_ready = 0;
|
||||
}
|
||||
|
||||
buffer->map_id = file->settings.base_map_id;
|
||||
buffer->unwrapped_lines = file->settings.unwrapped_lines;
|
||||
|
||||
|
@ -752,7 +762,9 @@ Buffer_Compute_Cursor(Application_Links *app, Buffer_Summary *buffer, Buffer_See
|
|||
DOC_PARAM(buffer, The buffer parameter specifies the buffer on which to run the cursor computation.)
|
||||
DOC_PARAM(seek, The seek parameter specifies the target position for the seek.)
|
||||
DOC_PARAM(cursor_out, On success this struct is filled with the result of the seek.)
|
||||
DOC_RETURN(This call returns non-zero on success.)
|
||||
DOC_RETURN(This call returns non-zero on success. This call can fail if the buffer summary provided
|
||||
does not summarize an actual buffer in 4coder, or if the provided seek format is invalid. The valid
|
||||
seek types are seek_pos and seek_line_char.)
|
||||
DOC(Computes a Partial_Cursor for the given seek position with no side effects.
|
||||
The seek position must be one of the types supported by Partial_Cursor. Those
|
||||
types are absolute position and line,column position.)
|
||||
|
@ -780,7 +792,8 @@ DOC_PARAM(str_len, This parameter specifies the length of the str string.)
|
|||
DOC_PARAM(edits, This parameter provides about the source string and destination range of each edit as an array.)
|
||||
DOC_PARAM(edit_count, This parameter specifies the number of Buffer_Edit structs in edits.)
|
||||
DOC_PARAM(type, This prameter specifies what type of batch edit to execute.)
|
||||
DOC_RETURN(This call returns non-zero if the batch edit succeeds.)
|
||||
DOC_RETURN(This call returns non-zero if the batch edit succeeds. This call can fail if the provided
|
||||
buffer summary does not refer to an actual buffer in 4coder.)
|
||||
DOC(TODO)
|
||||
DOC_SEE(Buffer_Edit)
|
||||
DOC_SEE(Buffer_Batch_Edit_Type)
|
||||
|
@ -812,9 +825,8 @@ DOC_SEE(Buffer_Batch_Edit_Type)
|
|||
|
||||
end_temp_memory(temp);
|
||||
}
|
||||
else{
|
||||
result = true;
|
||||
}
|
||||
|
||||
result = true;
|
||||
}
|
||||
|
||||
return(result);
|
||||
|
@ -916,43 +928,32 @@ DOC_SEE(Buffer_Setting_ID)
|
|||
return(result);
|
||||
}
|
||||
|
||||
API_EXPORT bool32
|
||||
Buffer_Auto_Indent(Application_Links *app, Buffer_Summary *buffer, 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)
|
||||
*/{
|
||||
API_EXPORT int32_t
|
||||
Buffer_Token_Count(Application_Links *app, Buffer_Summary *buffer){
|
||||
Command_Data *cmd = (Command_Data*)app->cmd_context;
|
||||
System_Functions *system = cmd->system;
|
||||
Models *models = cmd->models;
|
||||
|
||||
Indent_Options opts = {0};
|
||||
bool32 result = false;
|
||||
|
||||
Editing_File *file = imp_get_file(cmd, buffer);
|
||||
if (file && file->state.token_array.tokens &&
|
||||
file->state.tokens_complete && !file->state.still_lexing){
|
||||
result = true;
|
||||
|
||||
int32_t count = 0;
|
||||
|
||||
if (file && file->state.token_array.tokens && file->state.tokens_complete){
|
||||
count = file->state.token_array.count;
|
||||
}
|
||||
|
||||
return(count);
|
||||
}
|
||||
|
||||
API_EXPORT bool32
|
||||
Buffer_Read_Tokens(Application_Links *app, Buffer_Summary *buffer, int32_t first_token, int32_t last_token, Cpp_Token *tokens_out){
|
||||
Command_Data *cmd = (Command_Data*)app->cmd_context;
|
||||
Editing_File *file = imp_get_file(cmd, buffer);
|
||||
|
||||
bool32 result = 0;
|
||||
|
||||
if (file && file->state.token_array.tokens && file->state.tokens_complete){
|
||||
result = 1;
|
||||
|
||||
opts.empty_blank_lines = (flags & AutoIndent_ClearLine);
|
||||
opts.use_tabs = (flags & AutoIndent_UseTab);
|
||||
opts.tab_width = tab_width;
|
||||
|
||||
file_auto_tab_tokens(system, models, file, start, start, end, opts);
|
||||
|
||||
fill_buffer_summary(buffer, file, cmd);
|
||||
memcpy(tokens_out, file->state.token_array.tokens + first_token,
|
||||
sizeof(Cpp_Token)*(last_token - first_token));
|
||||
}
|
||||
|
||||
return(result);
|
||||
|
|
|
@ -41,9 +41,6 @@ typedef double f64;
|
|||
|
||||
#define globalconst static const
|
||||
|
||||
inline i32
|
||||
raw_ptr_dif(void *a, void *b) { return (i32)((u8*)a - (u8*)b); }
|
||||
|
||||
#define COMP_ID_(a,b,c,d) (d << 24) | (c << 16) | (b << 8) | a
|
||||
#define COMPOSE_ID(a,b,c,d) (COMP_ID_((a),(b),(c),(d)))
|
||||
|
||||
|
|
|
@ -2517,465 +2517,6 @@ file_compute_edit(Mem_Options *mem, Editing_File *file,
|
|||
return(spec);
|
||||
}
|
||||
|
||||
struct Indent_Options{
|
||||
b32 empty_blank_lines;
|
||||
b32 use_tabs;
|
||||
i32 tab_width;
|
||||
};
|
||||
|
||||
struct Make_Batch_Result{
|
||||
char *str_base;
|
||||
i32 str_size;
|
||||
|
||||
Buffer_Edit *edits;
|
||||
i32 edit_max;
|
||||
i32 edit_count;
|
||||
};
|
||||
|
||||
internal Cpp_Token*
|
||||
get_first_token_at_line(Buffer *buffer, Cpp_Token_Array tokens, i32 line){
|
||||
i32 start_pos = buffer->line_starts[line];
|
||||
Cpp_Get_Token_Result get_token = cpp_get_token(&tokens, start_pos);
|
||||
|
||||
if (get_token.in_whitespace){
|
||||
get_token.token_index += 1;
|
||||
}
|
||||
|
||||
Cpp_Token *result = tokens.tokens + get_token.token_index;
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal Cpp_Token*
|
||||
seek_matching_token_backwards(Cpp_Token_Array tokens, Cpp_Token *token,
|
||||
Cpp_Token_Type open_type, Cpp_Token_Type close_type){
|
||||
int32_t nesting_level = 0;
|
||||
if (token <= tokens.tokens){
|
||||
token = tokens.tokens;
|
||||
}
|
||||
else{
|
||||
for (; token > tokens.tokens; --token){
|
||||
if (!(token->flags & CPP_TFLAG_PP_BODY)){
|
||||
if (token->type == close_type){
|
||||
++nesting_level;
|
||||
}
|
||||
else if (token->type == open_type){
|
||||
if (nesting_level == 0){
|
||||
break;
|
||||
}
|
||||
else{
|
||||
--nesting_level;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return(token);
|
||||
}
|
||||
|
||||
struct Indent_Parse_State{
|
||||
i32 current_indent;
|
||||
i32 previous_line_indent;
|
||||
i32 paren_nesting;
|
||||
i32 paren_anchor_indent[16];
|
||||
i32 comment_shift;
|
||||
};
|
||||
|
||||
internal i32
|
||||
compute_this_indent(Buffer *buffer, Indent_Parse_State indent,
|
||||
Cpp_Token T, Cpp_Token prev_token, i32 line_i, i32 tab_width){
|
||||
|
||||
i32 previous_indent = indent.previous_line_indent;
|
||||
i32 this_indent = 0;
|
||||
|
||||
i32 this_line_start = buffer->line_starts[line_i];
|
||||
i32 next_line_start = 0;
|
||||
|
||||
if (line_i+1 < buffer->line_count){
|
||||
next_line_start = buffer->line_starts[line_i+1];
|
||||
}
|
||||
else{
|
||||
next_line_start = buffer_size(buffer);
|
||||
}
|
||||
|
||||
b32 did_special_behavior = false;
|
||||
|
||||
if (prev_token.start <= this_line_start &&
|
||||
prev_token.start + prev_token.size > this_line_start){
|
||||
if (prev_token.type == CPP_TOKEN_COMMENT){
|
||||
Hard_Start_Result hard_start = buffer_find_hard_start(buffer, this_line_start, tab_width);
|
||||
|
||||
if (hard_start.all_whitespace){
|
||||
this_indent = previous_indent;
|
||||
did_special_behavior = true;
|
||||
}
|
||||
else{
|
||||
i32 line_pos = hard_start.char_pos - this_line_start;
|
||||
this_indent = line_pos + indent.comment_shift;
|
||||
if (this_indent < 0){
|
||||
this_indent = 0;
|
||||
}
|
||||
did_special_behavior = true;
|
||||
}
|
||||
}
|
||||
else if (prev_token.type == CPP_TOKEN_STRING_CONSTANT){
|
||||
this_indent = previous_indent;
|
||||
did_special_behavior = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!did_special_behavior){
|
||||
this_indent = indent.current_indent;
|
||||
if (T.start < next_line_start){
|
||||
if (T.flags & CPP_TFLAG_PP_DIRECTIVE){
|
||||
this_indent = 0;
|
||||
}
|
||||
else{
|
||||
switch (T.type){
|
||||
case CPP_TOKEN_BRACKET_CLOSE: this_indent -= tab_width; break;
|
||||
case CPP_TOKEN_BRACE_CLOSE: this_indent -= tab_width; break;
|
||||
case CPP_TOKEN_BRACE_OPEN: break;
|
||||
|
||||
default:
|
||||
if (indent.current_indent > 0){
|
||||
if (!(prev_token.flags & CPP_TFLAG_PP_BODY ||
|
||||
prev_token.flags & CPP_TFLAG_PP_DIRECTIVE)){
|
||||
switch (prev_token.type){
|
||||
case CPP_TOKEN_BRACKET_OPEN:
|
||||
case CPP_TOKEN_BRACE_OPEN: case CPP_TOKEN_BRACE_CLOSE:
|
||||
case CPP_TOKEN_SEMICOLON: case CPP_TOKEN_COLON:
|
||||
case CPP_TOKEN_COMMA: case CPP_TOKEN_COMMENT: break;
|
||||
default: this_indent += tab_width;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this_indent < 0) this_indent = 0;
|
||||
}
|
||||
|
||||
if (indent.paren_nesting > 0){
|
||||
if (prev_token.type != CPP_TOKEN_PARENTHESE_OPEN){
|
||||
i32 level = indent.paren_nesting-1;
|
||||
if (level >= ArrayCount(indent.paren_anchor_indent)){
|
||||
level = ArrayCount(indent.paren_anchor_indent)-1;
|
||||
}
|
||||
this_indent = indent.paren_anchor_indent[level];
|
||||
}
|
||||
}
|
||||
return(this_indent);
|
||||
}
|
||||
|
||||
internal i32*
|
||||
get_line_indentation_marks(Partition *part, Buffer *buffer, Cpp_Token_Array tokens,
|
||||
i32 line_start, i32 line_end, i32 tab_width){
|
||||
|
||||
i32 indent_mark_count = line_end - line_start;
|
||||
i32 *indent_marks = push_array(part, i32, indent_mark_count);
|
||||
|
||||
Indent_Parse_State indent = {0};
|
||||
Cpp_Token *token = get_first_token_at_line(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.
|
||||
i32 found_safe_start_position = 0;
|
||||
do{
|
||||
i32 line = buffer_get_line_index(buffer, token->start);
|
||||
i32 start = buffer->line_starts[line];
|
||||
Hard_Start_Result hard_start = buffer_find_hard_start(buffer, start, tab_width);
|
||||
|
||||
indent.current_indent = hard_start.indent_pos;
|
||||
|
||||
Cpp_Token *start_token = get_first_token_at_line(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;
|
||||
|
||||
i32 line_i = buffer_get_line_index(buffer, token->start);
|
||||
|
||||
if (line_i > line_start){
|
||||
line_i = line_start;
|
||||
}
|
||||
|
||||
i32 next_line_start = buffer_size(buffer);
|
||||
if (line_i+1 < buffer->line_count){
|
||||
next_line_start = buffer->line_starts[line_i+1];
|
||||
}
|
||||
|
||||
switch (token->type){
|
||||
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_PARENTHESE_OPEN: indent.current_indent += tab_width; break;
|
||||
}
|
||||
|
||||
indent.previous_line_indent = indent.current_indent;
|
||||
Cpp_Token T;
|
||||
Cpp_Token prev_token = *token;
|
||||
++token;
|
||||
|
||||
for (; line_i < line_end; ++token){
|
||||
if (token < tokens.tokens + tokens.count){
|
||||
T = *token;
|
||||
}
|
||||
else{
|
||||
T.type = CPP_TOKEN_EOF;
|
||||
T.start = buffer_size(buffer);
|
||||
T.flags = 0;
|
||||
}
|
||||
|
||||
for (; T.start >= next_line_start && line_i < line_end;){
|
||||
if (line_i+1 < buffer->line_count){
|
||||
next_line_start = buffer->line_starts[line_i+1];
|
||||
}
|
||||
else{
|
||||
next_line_start = buffer_size(buffer);
|
||||
}
|
||||
|
||||
i32 this_indent =
|
||||
compute_this_indent(buffer, indent, T, prev_token, line_i, tab_width);
|
||||
|
||||
// NOTE(allen): Rebase the paren anchor if the first token
|
||||
// after an open paren is on the next line.
|
||||
if (indent.paren_nesting > 0){
|
||||
if (prev_token.type == CPP_TOKEN_PARENTHESE_OPEN){
|
||||
i32 level = indent.paren_nesting-1;
|
||||
if (level >= ArrayCount(indent.paren_anchor_indent)){
|
||||
level = ArrayCount(indent.paren_anchor_indent)-1;
|
||||
}
|
||||
indent.paren_anchor_indent[level] = this_indent;
|
||||
}
|
||||
}
|
||||
|
||||
if (line_i >= line_start){
|
||||
indent_marks[line_i] = this_indent;
|
||||
}
|
||||
++line_i;
|
||||
|
||||
indent.previous_line_indent = this_indent;
|
||||
}
|
||||
|
||||
switch (T.type){
|
||||
case CPP_TOKEN_BRACKET_OPEN: 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_CLOSE: indent.current_indent -= 4; break;
|
||||
|
||||
case CPP_TOKEN_COMMENT:
|
||||
{
|
||||
i32 line = buffer_get_line_index(buffer, T.start);
|
||||
i32 start = buffer->line_starts[line];
|
||||
|
||||
indent.comment_shift = (indent.current_indent - (T.start - start));
|
||||
}break;
|
||||
|
||||
case CPP_TOKEN_PARENTHESE_OPEN:
|
||||
if (!(T.flags & CPP_TFLAG_PP_BODY)){
|
||||
if (indent.paren_nesting < ArrayCount(indent.paren_anchor_indent)){
|
||||
i32 line = buffer_get_line_index(buffer, T.start);
|
||||
i32 start = buffer->line_starts[line];
|
||||
i32 char_pos = T.start - start;
|
||||
|
||||
Hard_Start_Result hard_start =
|
||||
buffer_find_hard_start(buffer, start, tab_width);
|
||||
|
||||
i32 line_pos = hard_start.char_pos - start;
|
||||
|
||||
indent.paren_anchor_indent[indent.paren_nesting] =
|
||||
char_pos - line_pos + indent.previous_line_indent + 1;
|
||||
}
|
||||
++indent.paren_nesting;
|
||||
}
|
||||
break;
|
||||
|
||||
case CPP_TOKEN_PARENTHESE_CLOSE:
|
||||
if (!(T.flags & CPP_TFLAG_PP_BODY)){
|
||||
--indent.paren_nesting;
|
||||
}
|
||||
break;
|
||||
}
|
||||
prev_token = T;
|
||||
}
|
||||
|
||||
// NOTE(allen): Unshift the indent_marks array so that the return value
|
||||
// is the exact starting point of the array that was actually allocated.
|
||||
indent_marks += line_start;
|
||||
|
||||
return(indent_marks);
|
||||
}
|
||||
|
||||
internal Make_Batch_Result
|
||||
make_batch_from_indent_marks(Partition *part, Buffer *buffer, i32 line_start, i32 line_end,
|
||||
i32 *indent_marks, Indent_Options opts){
|
||||
|
||||
Make_Batch_Result result = {0};
|
||||
|
||||
i32 edit_max = line_end - line_start;
|
||||
i32 edit_count = 0;
|
||||
|
||||
Buffer_Edit *edits = push_array(part, Buffer_Edit, edit_max);
|
||||
|
||||
char *str_base = (char*)part->base + part->pos;
|
||||
i32 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 (i32 line_i = line_start; line_i < line_end; ++line_i){
|
||||
i32 start = buffer->line_starts[line_i];
|
||||
Hard_Start_Result hard_start =
|
||||
buffer_find_hard_start(buffer, start, opts.tab_width);
|
||||
|
||||
i32 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;
|
||||
|
||||
if ((hard_start.all_whitespace && hard_start.char_pos > 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);
|
||||
i32 j = 0;
|
||||
if (opts.use_tabs){
|
||||
i32 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 = 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);
|
||||
}
|
||||
|
||||
internal void
|
||||
file_auto_tab_tokens(System_Functions *system, Models *models,
|
||||
Editing_File *file, i32 pos, i32 start, i32 end, Indent_Options opts){
|
||||
#if BUFFER_EXPERIMENT_SCALPEL <= 0
|
||||
Mem_Options *mem = &models->mem;
|
||||
Partition *part = &mem->part;
|
||||
Buffer *buffer = &file->state.buffer;
|
||||
|
||||
Assert(file && !file->is_dummy);
|
||||
Cpp_Token_Array tokens = file->state.token_array;
|
||||
Assert(tokens.tokens);
|
||||
|
||||
i32 line_start = buffer_get_line_index(buffer, start);
|
||||
i32 line_end = buffer_get_line_index(buffer, end) + 1;
|
||||
|
||||
Temp_Memory temp = begin_temp_memory(part);
|
||||
|
||||
i32 *indent_marks =
|
||||
get_line_indentation_marks(part, buffer, tokens, line_start, line_end, opts.tab_width);
|
||||
|
||||
Make_Batch_Result batch =
|
||||
make_batch_from_indent_marks(part, buffer, line_start, line_end, indent_marks, opts);
|
||||
|
||||
if (batch.edit_count > 0){
|
||||
Assert(buffer_batch_debug_sort_check(batch.edits, batch.edit_count));
|
||||
|
||||
// NOTE(allen): computing edit spec, doing batch edit
|
||||
Buffer_Edit *inverse_array = push_array(part, Buffer_Edit, batch.edit_count);
|
||||
Assert(inverse_array);
|
||||
|
||||
char *inv_str = (char*)part->base + part->pos;
|
||||
Edit_Spec spec =
|
||||
file_compute_edit(mem, file,
|
||||
batch.edits, batch.str_base, batch.str_size,
|
||||
inverse_array, inv_str, part->max - part->pos,
|
||||
batch.edit_count, BatchEdit_PreserveTokens);
|
||||
|
||||
file_do_batch_edit(system, models, file, spec, hist_normal, BatchEdit_PreserveTokens);
|
||||
}
|
||||
end_temp_memory(temp);
|
||||
#endif
|
||||
}
|
||||
|
||||
struct Get_Link_Result{
|
||||
b32 in_link;
|
||||
i32 index;
|
||||
};
|
||||
|
||||
internal u32*
|
||||
style_get_color(Style *style, Cpp_Token token){
|
||||
u32 *result;
|
||||
|
@ -5555,54 +5096,73 @@ draw_file_bar(Render_Target *target, View *view, Editing_File *file, i32_Rect re
|
|||
bar.text_shift_y = 2;
|
||||
bar.text_shift_x = 0;
|
||||
|
||||
draw_rectangle(target, bar.rect, back_color);
|
||||
if (!file){
|
||||
intbar_draw_string(target, &bar, make_lit_string("*NULL*"), base_color);
|
||||
draw_rectangle(target, bar.rect, back_color);
|
||||
|
||||
Assert(file);
|
||||
|
||||
intbar_draw_string(target, &bar, file->name.live_name, base_color);
|
||||
intbar_draw_string(target, &bar, make_lit_string(" -"), base_color);
|
||||
|
||||
if (file->is_loading){
|
||||
intbar_draw_string(target, &bar, make_lit_string(" loading"), base_color);
|
||||
}
|
||||
else{
|
||||
intbar_draw_string(target, &bar, file->name.live_name, base_color);
|
||||
intbar_draw_string(target, &bar, make_lit_string(" -"), base_color);
|
||||
char bar_space[526];
|
||||
String bar_text = make_fixed_width_string(bar_space);
|
||||
append_ss (&bar_text, make_lit_string(" L#"));
|
||||
append_int_to_str(&bar_text, view->edit_pos->cursor.line);
|
||||
append_ss (&bar_text, make_lit_string(" C#"));
|
||||
append_int_to_str(&bar_text, view->edit_pos->cursor.character);
|
||||
|
||||
if (file->is_loading){
|
||||
intbar_draw_string(target, &bar, make_lit_string(" loading"), base_color);
|
||||
append_ss(&bar_text, make_lit_string(" -"));
|
||||
|
||||
if (file->settings.dos_write_mode){
|
||||
append_ss(&bar_text, make_lit_string(" dos"));
|
||||
}
|
||||
else{
|
||||
char line_number_space[30];
|
||||
String line_number = make_fixed_width_string(line_number_space);
|
||||
append_ss(&line_number, make_lit_string(" L#"));
|
||||
append_int_to_str(&line_number, view->edit_pos->cursor.line);
|
||||
append_ss(&line_number, make_lit_string(" C#"));
|
||||
append_int_to_str(&line_number, view->edit_pos->cursor.character);
|
||||
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];
|
||||
|
||||
intbar_draw_string(target, &bar, line_number, base_color);
|
||||
|
||||
intbar_draw_string(target, &bar, make_lit_string(" -"), base_color);
|
||||
|
||||
if (file->settings.dos_write_mode){
|
||||
intbar_draw_string(target, &bar, make_lit_string(" dos"), base_color);
|
||||
}
|
||||
else{
|
||||
intbar_draw_string(target, &bar, make_lit_string(" nix"), base_color);
|
||||
}
|
||||
|
||||
if (file->state.still_lexing){
|
||||
intbar_draw_string(target, &bar, make_lit_string(" parsing"), pop1_color);
|
||||
}
|
||||
|
||||
if (!file->settings.unimportant){
|
||||
switch (file_get_sync(file)){
|
||||
case SYNC_BEHIND_OS:
|
||||
{
|
||||
persist String out_of_sync = make_lit_string(" !");
|
||||
intbar_draw_string(target, &bar, out_of_sync, pop2_color);
|
||||
}break;
|
||||
|
||||
case SYNC_UNSAVED:
|
||||
{
|
||||
persist String out_of_sync = make_lit_string(" *");
|
||||
intbar_draw_string(target, &bar, out_of_sync, pop2_color);
|
||||
}break;
|
||||
}
|
||||
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);
|
||||
|
||||
|
||||
if (file->state.still_lexing){
|
||||
intbar_draw_string(target, &bar, make_lit_string(" parsing"), pop1_color);
|
||||
}
|
||||
|
||||
if (!file->settings.unimportant){
|
||||
switch (file_get_sync(file)){
|
||||
case SYNC_BEHIND_OS:
|
||||
{
|
||||
persist String out_of_sync = make_lit_string(" !");
|
||||
intbar_draw_string(target, &bar, out_of_sync, pop2_color);
|
||||
}break;
|
||||
|
||||
case SYNC_UNSAVED:
|
||||
{
|
||||
persist String out_of_sync = make_lit_string(" *");
|
||||
intbar_draw_string(target, &bar, out_of_sync, pop2_color);
|
||||
}break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
15
TODO.txt
15
TODO.txt
|
@ -82,8 +82,11 @@
|
|||
|
||||
; BEFORE I SHIP
|
||||
;
|
||||
; [] tokens in the custom API
|
||||
; [] auto indent on the custom side
|
||||
; [X] tokens in the custom API
|
||||
; [X] auto indent on the custom side
|
||||
; [] clean up and comment the auto indent code to allow for customizations
|
||||
; [] more built in options for auto indenting
|
||||
; [] token seeking on custom side
|
||||
; [] expose dirty flags
|
||||
; [] option to not open *messages* every startup
|
||||
; [] commands for resizing panels
|
||||
|
@ -96,7 +99,12 @@
|
|||
; [] hook on exit
|
||||
; [] read only files
|
||||
; [] occasionally missing the (!) mark on files on windows
|
||||
; [] don't execute frames on events dealing only with ctrl/alt/shift
|
||||
; [] 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
|
||||
;
|
||||
|
||||
; TODOS
|
||||
|
@ -134,6 +142,7 @@
|
|||
; [X] full screen option
|
||||
; [X] add to APIs
|
||||
; [X] try to make win32 version better
|
||||
; [X] don't execute frames on events dealing only with ctrl/alt/shift
|
||||
;
|
||||
; [] support full length unicode file names
|
||||
; [] switch based word complete
|
||||
|
|
|
@ -18,12 +18,12 @@
|
|||
# define FSTRING_C
|
||||
# include "4coder_string.h"
|
||||
|
||||
#include "4coder_version.h"
|
||||
# include "4coder_version.h"
|
||||
# include "4coder_keycodes.h"
|
||||
# include "4coder_style.h"
|
||||
# include "4coder_rect.h"
|
||||
|
||||
# include "4coder_mem.h"
|
||||
# include "4cpp_lexer.h"
|
||||
|
||||
// TODO(allen): This is duplicated from 4coder_custom.h
|
||||
// I need to work out a way to avoid this.
|
||||
|
@ -111,11 +111,7 @@ struct Control_Keys{
|
|||
b8 l_alt;
|
||||
b8 r_alt;
|
||||
};
|
||||
inline Control_Keys
|
||||
control_keys_zero(){
|
||||
Control_Keys result = {0};
|
||||
return(result);
|
||||
}
|
||||
static Control_Keys null_control_keys;
|
||||
|
||||
struct Win32_Input_Chunk_Transient{
|
||||
Key_Input_Data key_data;
|
||||
|
@ -1837,7 +1833,8 @@ Win32Callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
|
|||
win32vars.input_chunk.pers.mouse_l = 0;
|
||||
win32vars.input_chunk.pers.mouse_r = 0;
|
||||
|
||||
win32vars.input_chunk.pers.controls = control_keys_zero();
|
||||
win32vars.input_chunk.pers.control_keys[MDFR_SHIFT_INDEX] = 0;
|
||||
win32vars.input_chunk.pers.controls = null_control_keys;
|
||||
}break;
|
||||
|
||||
case WM_SIZE:
|
||||
|
|
Loading…
Reference in New Issue