2017-01-23 06:19:43 +00:00
|
|
|
/*
|
|
|
|
4coder_auto_indent.cpp - Commands for auto-indentation of C++ code.
|
2016-09-08 00:32:31 +00:00
|
|
|
|
2017-01-23 06:19:43 +00:00
|
|
|
TYPE: 'drop-in-command-pack'
|
|
|
|
*/
|
|
|
|
|
|
|
|
// TOP
|
|
|
|
|
|
|
|
#if !defined(FCODER_AUTO_INDENT_CPP)
|
|
|
|
#define FCODER_AUTO_INDENT_CPP
|
|
|
|
|
|
|
|
#include "4coder_base_commands.cpp"
|
|
|
|
#include "4coder_helper/4coder_streaming.h"
|
|
|
|
#include "4coder_helper/4coder_long_seek.h"
|
|
|
|
#include "4coder_lib/4coder_mem.h"
|
|
|
|
#include "4coder_default_framework.h"
|
|
|
|
|
|
|
|
#if !defined(DEFAULT_INDENT_FLAGS)
|
|
|
|
# define DEFAULT_INDENT_FLAGS 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if !defined(DEF_TAB_WIDTH)
|
|
|
|
# define DEF_TAB_WIDTH 4
|
|
|
|
#endif
|
2016-09-08 00:32:31 +00:00
|
|
|
|
2016-09-09 01:02:51 +00:00
|
|
|
//
|
2017-11-28 23:31:10 +00:00
|
|
|
// Wrapper Implementation
|
2016-09-09 01:02:51 +00:00
|
|
|
//
|
|
|
|
|
2016-09-08 00:32:31 +00:00
|
|
|
struct Hard_Start_Result{
|
2017-03-23 19:15:33 +00:00
|
|
|
int32_t char_pos;
|
2016-09-08 00:32:31 +00:00
|
|
|
int32_t indent_pos;
|
2017-03-23 19:15:33 +00:00
|
|
|
int32_t all_whitespace;
|
|
|
|
int32_t all_space;
|
2016-09-08 00:32:31 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static Hard_Start_Result
|
2017-03-23 19:15:33 +00:00
|
|
|
buffer_find_hard_start(Application_Links *app, Buffer_Summary *buffer, int32_t line_start, int32_t tab_width){
|
|
|
|
tab_width -= 1;
|
|
|
|
|
2017-06-27 16:02:22 +00:00
|
|
|
Hard_Start_Result result = {0};
|
2016-09-08 00:32:31 +00:00
|
|
|
result.all_space = 1;
|
|
|
|
result.indent_pos = 0;
|
|
|
|
result.char_pos = line_start;
|
|
|
|
|
2017-06-27 16:02:22 +00:00
|
|
|
char data_chunk[1024];
|
|
|
|
Stream_Chunk stream = {0};
|
|
|
|
stream.add_null = true;
|
2016-09-08 00:32:31 +00:00
|
|
|
if (init_stream_chunk(&stream, app, buffer, line_start, data_chunk, sizeof(data_chunk))){
|
|
|
|
int32_t still_looping = 1;
|
|
|
|
do{
|
2017-03-23 19:15:33 +00:00
|
|
|
for (; result.char_pos < stream.end; ++result.char_pos){
|
2017-06-27 16:02:22 +00:00
|
|
|
char c = stream.data[result.char_pos];
|
2016-09-08 00:32:31 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
2016-09-09 01:02:51 +00:00
|
|
|
static Buffer_Batch_Edit
|
2017-03-23 19:15:33 +00:00
|
|
|
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){
|
2016-09-09 01:02:51 +00:00
|
|
|
|
|
|
|
Buffer_Batch_Edit result = {0};
|
|
|
|
|
2017-03-23 19:15:33 +00:00
|
|
|
int32_t edit_max = line_end - line_start;
|
|
|
|
int32_t edit_count = 0;
|
2016-09-09 01:02:51 +00:00
|
|
|
|
|
|
|
Buffer_Edit *edits = push_array(part, Buffer_Edit, edit_max);
|
|
|
|
|
|
|
|
char *str_base = (char*)part->base + part->pos;
|
2017-03-23 19:15:33 +00:00
|
|
|
int32_t str_size = 0;
|
2016-09-08 00:32:31 +00:00
|
|
|
|
2016-09-09 01:02:51 +00:00
|
|
|
// NOTE(allen): Shift the array so that line_i can just operate in
|
|
|
|
// it's natural value range.
|
|
|
|
indent_marks -= line_start;
|
|
|
|
|
2017-03-23 19:15:33 +00:00
|
|
|
for (int32_t line_i = line_start; line_i < line_end; ++line_i){
|
|
|
|
int32_t line_start_pos = buffer_get_line_start(app, buffer, line_i);
|
2017-06-28 15:15:54 +00:00
|
|
|
Hard_Start_Result hard_start = buffer_find_hard_start(app, buffer, line_start_pos, opts.tab_width);
|
2016-09-09 01:02:51 +00:00
|
|
|
|
|
|
|
int32_t correct_indentation = indent_marks[line_i];
|
2016-09-13 01:58:32 +00:00
|
|
|
if (hard_start.all_whitespace && opts.empty_blank_lines){
|
|
|
|
correct_indentation = 0;
|
|
|
|
}
|
|
|
|
if (correct_indentation == -1){
|
|
|
|
correct_indentation = hard_start.indent_pos;
|
|
|
|
}
|
2016-09-09 01:02:51 +00:00
|
|
|
|
|
|
|
// TODO(allen): Only replace spaces if we are using space based indentation.
|
|
|
|
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;
|
2016-09-13 01:58:32 +00:00
|
|
|
|
2016-09-09 01:02:51 +00:00
|
|
|
if (opts.use_tabs){
|
|
|
|
int32_t i = 0;
|
2016-09-13 01:58:32 +00:00
|
|
|
for (; i + opts.tab_width <= correct_indentation; i += opts.tab_width){
|
|
|
|
str[j++] = '\t';
|
|
|
|
}
|
|
|
|
for (; i < correct_indentation; ++i){
|
|
|
|
str[j++] = ' ';
|
|
|
|
}
|
2016-09-09 01:02:51 +00:00
|
|
|
}
|
|
|
|
else{
|
2016-09-13 01:58:32 +00:00
|
|
|
for (; j < correct_indentation; ++j){
|
|
|
|
str[j] = ' ';
|
|
|
|
}
|
2016-09-09 01:02:51 +00:00
|
|
|
}
|
2016-09-13 01:58:32 +00:00
|
|
|
|
2016-09-09 01:02:51 +00:00
|
|
|
new_edit.len = j;
|
2016-09-17 14:04:41 +00:00
|
|
|
new_edit.start = line_start_pos;
|
2016-09-09 01:02:51 +00:00
|
|
|
new_edit.end = hard_start.char_pos;
|
|
|
|
edits[edit_count++] = new_edit;
|
|
|
|
}
|
|
|
|
|
|
|
|
Assert(edit_count <= edit_max);
|
2016-09-08 00:32:31 +00:00
|
|
|
}
|
|
|
|
|
2016-09-09 01:02:51 +00:00
|
|
|
result.str = str_base;
|
|
|
|
result.str_len = str_size;
|
|
|
|
|
|
|
|
result.edits = edits;
|
|
|
|
result.edit_count = edit_count;
|
2016-09-08 00:32:31 +00:00
|
|
|
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
|
2016-09-09 01:02:51 +00:00
|
|
|
static void
|
2017-03-23 19:15:33 +00:00
|
|
|
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){
|
2017-06-28 15:15:54 +00:00
|
|
|
Buffer_Batch_Edit batch = make_batch_from_indent_marks(app, part, buffer, line_start, line_end, indent_marks, opts);
|
2016-09-09 01:02:51 +00:00
|
|
|
|
|
|
|
if (batch.edit_count > 0){
|
2017-06-27 15:49:27 +00:00
|
|
|
buffer_batch_edit(app, buffer, batch.str, batch.str_len, batch.edits, batch.edit_count, BatchEdit_PreserveTokens);
|
2016-09-09 01:02:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-08 00:32:31 +00:00
|
|
|
static Cpp_Token*
|
2017-01-23 06:19:43 +00:00
|
|
|
seek_matching_token_backwards(Cpp_Token_Array tokens, Cpp_Token *token, Cpp_Token_Type open_type, Cpp_Token_Type close_type){
|
2016-09-08 00:32:31 +00:00
|
|
|
if (token <= tokens.tokens){
|
|
|
|
token = tokens.tokens;
|
|
|
|
}
|
|
|
|
else{
|
2017-06-27 15:49:27 +00:00
|
|
|
int32_t nesting_level = 0;
|
2016-09-08 00:32:31 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2016-09-09 01:02:51 +00:00
|
|
|
static Cpp_Token*
|
2017-03-23 19:15:33 +00:00
|
|
|
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){
|
2017-11-28 20:16:53 +00:00
|
|
|
Cpp_Token *token = 0;
|
2016-09-09 01:02:51 +00:00
|
|
|
|
2017-11-28 20:16:53 +00:00
|
|
|
if (tokens.count != 0){
|
|
|
|
token = get_first_token_at_line(app, buffer, tokens, line_start);
|
|
|
|
|
2016-09-13 23:59:48 +00:00
|
|
|
if (token == 0){
|
|
|
|
token = tokens.tokens + (tokens.count - 1);
|
|
|
|
}
|
|
|
|
|
2017-11-28 20:16:53 +00:00
|
|
|
if (token > tokens.tokens){
|
2016-09-13 23:59:48 +00:00
|
|
|
--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;
|
|
|
|
}
|
2016-09-09 01:02:51 +00:00
|
|
|
}
|
|
|
|
}
|
2016-09-13 23:59:48 +00:00
|
|
|
out_of_loop:;
|
2016-09-09 01:02:51 +00:00
|
|
|
}
|
|
|
|
|
2016-09-13 23:59:48 +00:00
|
|
|
int32_t current_indent = 0;
|
|
|
|
int32_t found_safe_start_position = 0;
|
|
|
|
do{
|
2017-11-28 20:16:53 +00:00
|
|
|
int32_t line = buffer_get_line_number(app, buffer, token->start);
|
2017-03-23 19:15:33 +00:00
|
|
|
int32_t start = buffer_get_line_start(app, buffer, line);
|
2016-09-13 23:59:48 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2016-09-09 01:02:51 +00:00
|
|
|
}
|
|
|
|
else{
|
2016-09-13 23:59:48 +00:00
|
|
|
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:
|
2017-11-28 20:16:53 +00:00
|
|
|
{
|
|
|
|
close = token->type;
|
|
|
|
}goto out_of_loop2;
|
2016-09-13 23:59:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
out_of_loop2:;
|
|
|
|
|
2017-06-28 15:15:54 +00:00
|
|
|
Cpp_Token_Type open_type = CPP_TOKEN_JUNK;
|
|
|
|
Cpp_Token_Type close_type = CPP_TOKEN_JUNK;
|
2016-09-13 23:59:48 +00:00
|
|
|
switch (close){
|
2017-11-28 20:16:53 +00:00
|
|
|
case 0:
|
|
|
|
{
|
|
|
|
token = start_token;
|
|
|
|
found_safe_start_position = true;
|
|
|
|
}break;
|
2016-09-13 23:59:48 +00:00
|
|
|
|
2016-09-09 01:02:51 +00:00
|
|
|
case CPP_TOKEN_PARENTHESE_CLOSE:
|
2017-11-28 20:16:53 +00:00
|
|
|
{
|
|
|
|
open_type = CPP_TOKEN_PARENTHESE_OPEN;
|
|
|
|
close_type = CPP_TOKEN_PARENTHESE_CLOSE;
|
|
|
|
}break;
|
2016-09-13 23:59:48 +00:00
|
|
|
|
2016-09-09 01:02:51 +00:00
|
|
|
case CPP_TOKEN_BRACKET_CLOSE:
|
2017-11-28 20:16:53 +00:00
|
|
|
{
|
|
|
|
open_type = CPP_TOKEN_BRACKET_OPEN;
|
|
|
|
close_type = CPP_TOKEN_BRACKET_CLOSE;
|
|
|
|
}break;
|
2016-09-13 23:59:48 +00:00
|
|
|
|
2016-09-09 01:02:51 +00:00
|
|
|
case CPP_TOKEN_BRACE_CLOSE:
|
2017-11-28 20:16:53 +00:00
|
|
|
{
|
|
|
|
open_type = CPP_TOKEN_BRACE_OPEN;
|
|
|
|
close_type = CPP_TOKEN_BRACE_CLOSE;
|
|
|
|
}break;
|
2016-09-09 01:02:51 +00:00
|
|
|
}
|
2017-06-28 15:15:54 +00:00
|
|
|
if (open_type != CPP_TOKEN_JUNK){
|
|
|
|
token = seek_matching_token_backwards(tokens, token-1, open_type, close_type);
|
|
|
|
}
|
2016-09-09 01:02:51 +00:00
|
|
|
}
|
2016-09-13 23:59:48 +00:00
|
|
|
} while(found_safe_start_position == 0);
|
|
|
|
*current_indent_out = current_indent;
|
|
|
|
}
|
2016-09-09 01:02:51 +00:00
|
|
|
|
|
|
|
return(token);
|
|
|
|
}
|
|
|
|
|
2016-09-08 00:32:31 +00:00
|
|
|
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;
|
2016-09-13 01:58:32 +00:00
|
|
|
int32_t previous_comment_indent;
|
2016-09-08 00:32:31 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static int32_t*
|
2017-03-23 19:15:33 +00:00
|
|
|
get_indentation_marks(Application_Links *app, Partition *part, Buffer_Summary *buffer, Cpp_Token_Array tokens, int32_t line_start, int32_t line_end, bool32 exact_align, int32_t tab_width){
|
2016-09-08 00:32:31 +00:00
|
|
|
|
2017-03-23 19:15:33 +00:00
|
|
|
int32_t indent_mark_count = line_end - line_start;
|
2016-09-08 00:32:31 +00:00
|
|
|
int32_t *indent_marks = push_array(part, int32_t, indent_mark_count);
|
2016-09-13 13:52:54 +00:00
|
|
|
// Shift the array so line_index works correctly.
|
2016-09-09 01:02:51 +00:00
|
|
|
indent_marks -= line_start;
|
2016-09-08 00:32:31 +00:00
|
|
|
|
2017-03-23 19:15:33 +00:00
|
|
|
|
2016-09-09 01:02:51 +00:00
|
|
|
// Decide where to start indentation parsing.
|
|
|
|
Indent_Parse_State indent = {0};
|
2017-06-27 16:02:22 +00:00
|
|
|
Cpp_Token *token_ptr = find_anchor_token(app, buffer, tokens, line_start, tab_width, &indent.current_indent);
|
2016-09-08 00:32:31 +00:00
|
|
|
|
2016-09-13 23:59:48 +00:00
|
|
|
if (token_ptr == 0){
|
2017-03-23 19:15:33 +00:00
|
|
|
for (int32_t line_index = line_start; line_index < line_end; ++line_index){
|
2016-09-13 23:59:48 +00:00
|
|
|
indent_marks[line_index] = 0;
|
|
|
|
}
|
2016-09-08 00:32:31 +00:00
|
|
|
}
|
2016-09-13 23:59:48 +00:00
|
|
|
else{
|
2017-11-28 20:16:53 +00:00
|
|
|
int32_t line_number = buffer_get_line_number(app, buffer, token_ptr->start);
|
|
|
|
if (line_number > line_start){
|
|
|
|
line_number = line_start;
|
2016-09-08 00:32:31 +00:00
|
|
|
}
|
2016-09-13 23:59:48 +00:00
|
|
|
|
2017-06-27 16:02:22 +00:00
|
|
|
if (token_ptr == tokens.tokens){
|
|
|
|
indent.current_indent = 0;
|
2016-09-08 00:32:31 +00:00
|
|
|
}
|
|
|
|
|
2017-11-28 20:16:53 +00:00
|
|
|
int32_t next_line_start_pos = buffer_get_line_start(app, buffer, line_number);
|
2016-09-13 23:59:48 +00:00
|
|
|
indent.previous_line_indent = indent.current_indent;
|
2017-06-27 16:02:22 +00:00
|
|
|
Cpp_Token prev_token = {0};
|
|
|
|
Cpp_Token token = {0};
|
2017-11-28 20:49:40 +00:00
|
|
|
if (token_ptr < tokens.tokens + tokens.count){
|
|
|
|
token = *token_ptr;
|
|
|
|
}
|
2017-11-28 23:31:10 +00:00
|
|
|
|
|
|
|
// Back up and consume this token too IF it is a scope opener.
|
|
|
|
if (token.type == CPP_TOKEN_BRACE_OPEN || token.type == CPP_TOKEN_BRACKET_OPEN){
|
|
|
|
--token_ptr;
|
|
|
|
}
|
2016-09-13 23:59:48 +00:00
|
|
|
|
2017-11-28 20:16:53 +00:00
|
|
|
for (;line_number < line_end;){
|
2017-06-27 16:02:22 +00:00
|
|
|
prev_token = token;
|
2016-09-13 23:59:48 +00:00
|
|
|
++token_ptr;
|
|
|
|
if (token_ptr < tokens.tokens + tokens.count){
|
|
|
|
token = *token_ptr;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
token.type = CPP_TOKEN_EOF;
|
|
|
|
token.start = buffer->size;
|
|
|
|
token.flags = 0;
|
|
|
|
}
|
|
|
|
|
2017-11-28 20:16:53 +00:00
|
|
|
for (;token.start >= next_line_start_pos && line_number < line_end;){
|
|
|
|
next_line_start_pos = buffer_get_line_start(app, buffer, line_number+1);
|
2016-09-13 13:52:54 +00:00
|
|
|
|
2016-09-13 23:59:48 +00:00
|
|
|
int32_t this_indent = 0;
|
|
|
|
{
|
|
|
|
int32_t previous_indent = indent.previous_line_indent;
|
|
|
|
|
2017-11-28 20:16:53 +00:00
|
|
|
int32_t this_line_start = buffer_get_line_start(app, buffer, line_number);
|
|
|
|
int32_t next_line_start = buffer_get_line_start(app, buffer, line_number+1);
|
2016-09-13 23:59:48 +00:00
|
|
|
|
|
|
|
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 (exact_align){
|
|
|
|
this_indent = indent.previous_comment_indent;
|
2016-09-13 13:52:54 +00:00
|
|
|
}
|
|
|
|
else{
|
2016-09-13 23:59:48 +00:00
|
|
|
if (hard_start.all_whitespace){
|
|
|
|
this_indent = previous_indent;
|
|
|
|
}
|
|
|
|
else{
|
2017-03-23 19:15:33 +00:00
|
|
|
int32_t line_pos = hard_start.char_pos - this_line_start;
|
2016-09-13 23:59:48 +00:00
|
|
|
this_indent = line_pos + indent.comment_shift;
|
|
|
|
if (this_indent < 0){
|
|
|
|
this_indent = 0;
|
|
|
|
}
|
2016-09-13 13:52:54 +00:00
|
|
|
}
|
|
|
|
}
|
2016-09-13 23:59:48 +00:00
|
|
|
|
|
|
|
if (!hard_start.all_whitespace){
|
2017-11-28 20:16:53 +00:00
|
|
|
if (line_number >= line_start){
|
2016-09-13 23:59:48 +00:00
|
|
|
indent.previous_comment_indent = this_indent;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
indent.previous_comment_indent = hard_start.indent_pos;
|
|
|
|
}
|
2016-09-13 13:52:54 +00:00
|
|
|
}
|
2016-09-13 23:59:48 +00:00
|
|
|
|
|
|
|
did_special_behavior = true;
|
2016-09-13 13:52:54 +00:00
|
|
|
}
|
2016-09-13 23:59:48 +00:00
|
|
|
else if (prev_token.type == CPP_TOKEN_STRING_CONSTANT){
|
|
|
|
this_indent = previous_indent;
|
|
|
|
did_special_behavior = true;
|
2016-09-13 13:52:54 +00:00
|
|
|
}
|
2016-09-13 23:59:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!did_special_behavior){
|
|
|
|
this_indent = indent.current_indent;
|
|
|
|
if (token.start < next_line_start){
|
|
|
|
if (token.flags & CPP_TFLAG_PP_DIRECTIVE){
|
|
|
|
this_indent = 0;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
switch (token.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){
|
2017-11-28 23:31:10 +00:00
|
|
|
bool32 statement_complete = false;
|
|
|
|
|
|
|
|
Cpp_Token *prev_usable_token_ptr = token_ptr - 1;
|
|
|
|
Cpp_Token prev_usable_token = {0};
|
|
|
|
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.
|
|
|
|
bool32 has_prev_usable_token = true;
|
|
|
|
#define NotUsable(T) \
|
|
|
|
(((T).flags&CPP_TFLAG_PP_BODY) || ((T).flags&CPP_TFLAG_PP_DIRECTIVE) || ((T).type == CPP_TOKEN_COMMENT))
|
|
|
|
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;
|
|
|
|
}
|
2016-09-13 23:59:48 +00:00
|
|
|
}
|
2016-09-13 13:52:54 +00:00
|
|
|
}
|
2017-11-28 23:31:10 +00:00
|
|
|
#undef NotUsable
|
|
|
|
|
|
|
|
if (!has_prev_usable_token){
|
|
|
|
statement_complete = true;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
if (prev_usable_token.type == CPP_TOKEN_BRACKET_OPEN ||
|
|
|
|
prev_usable_token.type == CPP_TOKEN_BRACE_OPEN ||
|
|
|
|
prev_usable_token.type == CPP_TOKEN_BRACE_CLOSE ||
|
|
|
|
prev_usable_token.type == CPP_TOKEN_SEMICOLON ||
|
|
|
|
prev_usable_token.type == CPP_TOKEN_COLON ||
|
|
|
|
prev_usable_token.type == CPP_TOKEN_COMMA){
|
|
|
|
statement_complete = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!statement_complete){
|
|
|
|
this_indent += tab_width;
|
|
|
|
}
|
2016-09-13 13:52:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-09-13 23:59:48 +00:00
|
|
|
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];
|
|
|
|
}
|
2016-09-13 13:52:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-13 23:59:48 +00:00
|
|
|
// Rebase the paren anchor if the first token
|
|
|
|
// after the open paren is on the next line.
|
2016-09-13 13:52:54 +00:00
|
|
|
if (indent.paren_nesting > 0){
|
2016-09-13 23:59:48 +00:00
|
|
|
if (prev_token.type == CPP_TOKEN_PARENTHESE_OPEN){
|
2016-09-13 13:52:54 +00:00
|
|
|
int32_t level = indent.paren_nesting-1;
|
|
|
|
if (level >= ArrayCount(indent.paren_anchor_indent)){
|
|
|
|
level = ArrayCount(indent.paren_anchor_indent)-1;
|
|
|
|
}
|
2016-09-13 23:59:48 +00:00
|
|
|
indent.paren_anchor_indent[level] = this_indent;
|
2016-09-13 13:52:54 +00:00
|
|
|
}
|
|
|
|
}
|
2016-09-13 23:59:48 +00:00
|
|
|
|
2017-11-28 20:16:53 +00:00
|
|
|
if (line_number >= line_start){
|
|
|
|
indent_marks[line_number] = this_indent;
|
2016-09-08 00:32:31 +00:00
|
|
|
}
|
2017-11-28 20:16:53 +00:00
|
|
|
++line_number;
|
2016-09-13 23:59:48 +00:00
|
|
|
|
|
|
|
indent.previous_line_indent = this_indent;
|
2016-09-08 00:32:31 +00:00
|
|
|
}
|
|
|
|
|
2016-09-13 23:59:48 +00:00
|
|
|
// Update indent state.
|
|
|
|
switch (token.type){
|
2017-06-27 15:49:27 +00:00
|
|
|
case CPP_TOKEN_BRACKET_OPEN: indent.current_indent += tab_width; break;
|
|
|
|
case CPP_TOKEN_BRACKET_CLOSE: indent.current_indent -= tab_width; break;
|
|
|
|
case CPP_TOKEN_BRACE_OPEN: indent.current_indent += tab_width; break;
|
|
|
|
case CPP_TOKEN_BRACE_CLOSE: indent.current_indent -= tab_width; break;
|
2016-09-08 00:32:31 +00:00
|
|
|
|
2016-09-13 23:59:48 +00:00
|
|
|
case CPP_TOKEN_COMMENT:
|
|
|
|
{
|
2017-11-28 20:16:53 +00:00
|
|
|
int32_t line = buffer_get_line_number(app, buffer, token.start);
|
2017-03-23 19:15:33 +00:00
|
|
|
int32_t start = buffer_get_line_start(app, buffer, line);
|
|
|
|
|
|
|
|
indent.comment_shift = (indent.current_indent - (token.start - start));
|
|
|
|
indent.previous_comment_indent = (token.start - start);
|
2016-09-13 23:59:48 +00:00
|
|
|
}break;
|
|
|
|
|
|
|
|
case CPP_TOKEN_PARENTHESE_OPEN:
|
2017-06-27 16:02:22 +00:00
|
|
|
{
|
|
|
|
if (!(token.flags & CPP_TFLAG_PP_BODY)){
|
|
|
|
if (indent.paren_nesting < ArrayCount(indent.paren_anchor_indent)){
|
2017-11-28 20:16:53 +00:00
|
|
|
int32_t line = buffer_get_line_number(app, buffer, token.start);
|
2017-06-27 16:02:22 +00:00
|
|
|
int32_t start = buffer_get_line_start(app, buffer, line);
|
|
|
|
int32_t char_pos = token.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;
|
2016-09-13 23:59:48 +00:00
|
|
|
}
|
2017-06-27 16:02:22 +00:00
|
|
|
}break;
|
2016-09-13 23:59:48 +00:00
|
|
|
|
|
|
|
case CPP_TOKEN_PARENTHESE_CLOSE:
|
2017-06-27 16:02:22 +00:00
|
|
|
{
|
|
|
|
if (!(token.flags & CPP_TFLAG_PP_BODY)){
|
|
|
|
if (indent.paren_nesting > 0){
|
|
|
|
--indent.paren_nesting;
|
|
|
|
}
|
2016-09-23 04:56:47 +00:00
|
|
|
}
|
2017-06-27 16:02:22 +00:00
|
|
|
}break;
|
2016-09-08 00:32:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-09 01:02:51 +00:00
|
|
|
// Unshift the indent_marks array.
|
2016-09-08 00:32:31 +00:00
|
|
|
indent_marks += line_start;
|
|
|
|
return(indent_marks);
|
|
|
|
}
|
|
|
|
|
2016-09-10 15:22:25 +00:00
|
|
|
static void
|
2017-06-27 16:02:22 +00:00
|
|
|
get_indent_lines_minimum(Application_Links *app, Buffer_Summary *buffer, int32_t start_pos, int32_t end_pos, int32_t *line_start_out, int32_t *line_end_out){
|
2017-11-28 20:16:53 +00:00
|
|
|
int32_t line_start = buffer_get_line_number(app, buffer, start_pos);
|
|
|
|
int32_t line_end = buffer_get_line_number(app, buffer, end_pos) + 1;
|
2016-09-10 15:22:25 +00:00
|
|
|
|
|
|
|
*line_start_out = line_start;
|
|
|
|
*line_end_out = line_end;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2017-06-27 16:02:22 +00:00
|
|
|
get_indent_lines_whole_tokens(Application_Links *app, Buffer_Summary *buffer, Cpp_Token_Array tokens, int32_t start_pos, int32_t end_pos, int32_t *line_start_out, int32_t *line_end_out){
|
2017-11-28 20:16:53 +00:00
|
|
|
int32_t line_start = buffer_get_line_number(app, buffer, start_pos);
|
|
|
|
int32_t line_end = buffer_get_line_number(app, buffer, end_pos);
|
2016-09-10 15:22:25 +00:00
|
|
|
|
2017-06-27 15:49:27 +00:00
|
|
|
for (;line_start > 1;){
|
2017-03-23 19:16:39 +00:00
|
|
|
int32_t line_start_pos = 0;
|
2016-09-10 15:22:25 +00:00
|
|
|
Cpp_Token *token = get_first_token_at_line(app, buffer, tokens, line_start, &line_start_pos);
|
2017-03-23 19:16:39 +00:00
|
|
|
if (token && token->start < line_start_pos){
|
2017-11-28 20:16:53 +00:00
|
|
|
line_start = buffer_get_line_number(app, buffer, token->start);
|
2016-09-10 15:22:25 +00:00
|
|
|
}
|
|
|
|
else{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-27 15:49:27 +00:00
|
|
|
for (;line_end < buffer->line_count;){
|
2017-03-23 19:16:39 +00:00
|
|
|
int32_t next_line_start_pos = 0;
|
2016-09-10 15:22:25 +00:00
|
|
|
Cpp_Token *token = get_first_token_at_line(app, buffer, tokens, line_end+1, &next_line_start_pos);
|
|
|
|
if (token && token->start < next_line_start_pos){
|
2017-11-28 20:16:53 +00:00
|
|
|
line_end = buffer_get_line_number(app, buffer, token->start+token->size);
|
2016-09-10 15:22:25 +00:00
|
|
|
}
|
|
|
|
else{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2017-06-27 15:49:27 +00:00
|
|
|
|
|
|
|
if (line_end > buffer->line_count){
|
|
|
|
line_end = buffer->line_count + 1;
|
2016-09-10 15:22:25 +00:00
|
|
|
}
|
|
|
|
else{
|
|
|
|
line_end += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*line_start_out = line_start;
|
|
|
|
*line_end_out = line_end;
|
|
|
|
}
|
|
|
|
|
2016-09-08 00:32:31 +00:00
|
|
|
static bool32
|
2017-06-27 16:02:22 +00:00
|
|
|
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){
|
2016-09-08 00:32:31 +00:00
|
|
|
|
2017-06-27 16:02:22 +00:00
|
|
|
bool32 result = false;
|
2016-09-08 00:32:31 +00:00
|
|
|
if (buffer->exists && buffer->tokens_are_ready){
|
2017-06-27 16:02:22 +00:00
|
|
|
result = true;
|
2016-09-08 00:32:31 +00:00
|
|
|
|
|
|
|
Temp_Memory temp = begin_temp_memory(part);
|
|
|
|
|
2016-09-10 15:22:25 +00:00
|
|
|
// Stage 1: Read the tokens to be used for indentation.
|
2016-09-08 00:32:31 +00:00
|
|
|
Cpp_Token_Array tokens;
|
2016-09-17 00:03:09 +00:00
|
|
|
tokens.count = buffer_token_count(app, buffer);
|
2016-09-08 00:32:31 +00:00
|
|
|
tokens.max_count = tokens.count;
|
|
|
|
tokens.tokens = push_array(part, Cpp_Token, tokens.count);
|
2016-09-17 00:03:09 +00:00
|
|
|
buffer_read_tokens(app, buffer, 0, tokens.count, tokens.tokens);
|
2016-09-08 00:32:31 +00:00
|
|
|
|
2016-09-10 15:22:25 +00:00
|
|
|
// Stage 2: Decide where the first and last lines are.
|
|
|
|
// The lines in the range [line_start,line_end) will be indented.
|
2017-03-23 19:15:33 +00:00
|
|
|
int32_t line_start = 0, line_end = 0;
|
2016-09-13 01:58:32 +00:00
|
|
|
if (flags & AutoIndent_FullTokens){
|
2016-09-10 15:22:25 +00:00
|
|
|
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);
|
|
|
|
}
|
2016-09-08 00:32:31 +00:00
|
|
|
|
2016-09-10 15:22:25 +00:00
|
|
|
// Stage 3: Decide Indent Amounts
|
|
|
|
// Get an array representing how much each line in
|
|
|
|
// the range [line_start,line_end) should be indented.
|
2017-06-27 16:02:22 +00:00
|
|
|
int32_t *indent_marks = get_indentation_marks(app, part, buffer, tokens, line_start, line_end, (flags & AutoIndent_ExactAlignBlock), tab_width);
|
2016-09-08 00:32:31 +00:00
|
|
|
|
2016-09-10 15:22:25 +00:00
|
|
|
// Stage 4: Set the Line Indents
|
2016-09-09 01:02:51 +00:00
|
|
|
Indent_Options opts = {0};
|
|
|
|
opts.empty_blank_lines = (flags & AutoIndent_ClearLine);
|
|
|
|
opts.use_tabs = (flags & AutoIndent_UseTab);
|
|
|
|
opts.tab_width = tab_width;
|
2016-09-08 00:32:31 +00:00
|
|
|
|
2016-09-09 01:02:51 +00:00
|
|
|
set_line_indents(app, part, buffer, line_start, line_end, indent_marks, opts);
|
2016-09-08 00:32:31 +00:00
|
|
|
|
|
|
|
end_temp_memory(temp);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool32
|
2017-06-27 16:02:22 +00:00
|
|
|
buffer_auto_indent(Application_Links *app, Buffer_Summary *buffer, int32_t start, int32_t end, int32_t tab_width, Auto_Indent_Flag flags){
|
2016-09-08 00:32:31 +00:00
|
|
|
bool32 result = buffer_auto_indent(app, &global_part, buffer, start, end, tab_width, flags);
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
|
2017-01-23 06:19:43 +00:00
|
|
|
//
|
|
|
|
// Commands
|
|
|
|
//
|
|
|
|
|
2017-11-15 23:57:21 +00:00
|
|
|
CUSTOM_COMMAND_SIG(auto_tab_whole_file)
|
|
|
|
CUSTOM_DOC("Audo-indents the entire current buffer.")
|
|
|
|
{
|
2017-01-23 06:19:43 +00:00
|
|
|
uint32_t access = AccessOpen;
|
|
|
|
View_Summary view = get_active_view(app, access);
|
|
|
|
Buffer_Summary buffer = get_buffer(app, view.buffer_id, access);
|
|
|
|
|
2017-11-28 23:31:10 +00:00
|
|
|
buffer_auto_indent(app, &global_part, &buffer, 0, buffer.size, DEF_TAB_WIDTH, DEFAULT_INDENT_FLAGS | AutoIndent_FullTokens);
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
|
|
|
|
2017-11-15 23:57:21 +00:00
|
|
|
CUSTOM_COMMAND_SIG(auto_tab_line_at_cursor)
|
|
|
|
CUSTOM_DOC("Auto-indents the line on which the cursor sits.")
|
|
|
|
{
|
2017-01-23 06:19:43 +00:00
|
|
|
uint32_t access = AccessOpen;
|
|
|
|
View_Summary view = get_active_view(app, access);
|
|
|
|
Buffer_Summary buffer = get_buffer(app, view.buffer_id, access);
|
|
|
|
|
2017-11-28 23:31:10 +00:00
|
|
|
buffer_auto_indent(app, &global_part, &buffer, view.cursor.pos, view.cursor.pos, DEF_TAB_WIDTH, DEFAULT_INDENT_FLAGS | AutoIndent_FullTokens);
|
2017-01-23 06:19:43 +00:00
|
|
|
move_past_lead_whitespace(app, &view, &buffer);
|
|
|
|
}
|
|
|
|
|
2017-11-15 23:57:21 +00:00
|
|
|
CUSTOM_COMMAND_SIG(auto_tab_range)
|
|
|
|
CUSTOM_DOC("Auto-indents the range between the cursor and the mark.")
|
|
|
|
{
|
2017-01-23 06:19:43 +00:00
|
|
|
uint32_t access = AccessOpen;
|
|
|
|
View_Summary view = get_active_view(app, access);
|
|
|
|
Buffer_Summary buffer = get_buffer(app, view.buffer_id, access);
|
|
|
|
Range range = get_range(&view);
|
|
|
|
|
2017-11-28 23:31:10 +00:00
|
|
|
buffer_auto_indent(app, &global_part, &buffer, range.min, range.max, DEF_TAB_WIDTH, DEFAULT_INDENT_FLAGS | AutoIndent_FullTokens);
|
2017-01-23 06:19:43 +00:00
|
|
|
move_past_lead_whitespace(app, &view, &buffer);
|
|
|
|
}
|
|
|
|
|
2017-11-15 23:57:21 +00:00
|
|
|
CUSTOM_COMMAND_SIG(write_and_auto_tab)
|
|
|
|
CUSTOM_DOC("Inserts a character and auto-indents the line on which the cursor sits.")
|
|
|
|
{
|
2017-01-23 06:19:43 +00:00
|
|
|
exec_command(app, write_character);
|
|
|
|
|
|
|
|
uint32_t access = AccessOpen;
|
|
|
|
View_Summary view = get_active_view(app, access);
|
|
|
|
Buffer_Summary buffer = get_buffer(app, view.buffer_id, access);
|
|
|
|
|
2017-11-28 23:31:10 +00:00
|
|
|
buffer_auto_indent(app, &global_part, &buffer, view.cursor.pos, view.cursor.pos, DEF_TAB_WIDTH, DEFAULT_INDENT_FLAGS | AutoIndent_ExactAlignBlock);
|
2017-01-23 06:19:43 +00:00
|
|
|
move_past_lead_whitespace(app, &view, &buffer);
|
|
|
|
}
|
|
|
|
|
2016-09-08 00:32:31 +00:00
|
|
|
#endif
|
|
|
|
|
2017-01-23 06:19:43 +00:00
|
|
|
// BOTTOM
|
|
|
|
|