Buffer_Summary acts as a handle to a buffer and describes the state of the buffer.
exists
This field indicates whether the Buffer_Summary describes a buffer that is open in 4coder.
+will be replaced into the buffer.
Fields
str_start
The str_start field specifies the first character in the accompanying string that corresponds with this edit.
len
The len field specifies the length of the string being written into the buffer.
start
The start field specifies the start of the range in the buffer to replace in absolute position.
end
The end field specifies one past the end of the range in the buffer to replace in absolute position.
§3.4.38: Buffer_Summary
struct Buffer_Summary {
bool32 exists;
bool32 ready;
int32_t buffer_id;
Access_Flag lock_flags;
int32_t size;
int32_t line_count;
char * file_name;
int32_t file_name_len;
char * buffer_name;
int32_t buffer_name_len;
bool32 is_lexed;
bool32 tokens_are_ready;
int32_t map_id;
bool32 unwrapped_lines;
};
Description
Buffer_Summary acts as a handle to a buffer and describes the state of the buffer.
Fields
exists
This field indicates whether the Buffer_Summary describes a buffer that is open in 4coder.
When this field is false the summary is referred to as a "null summary".
ready
If this is not a null summary, this field indicates whether the buffer has finished loading.
buffer_id
If this is not a null summary this field is the id of the associated buffer.
- If this is a null summary then buffer_id is 0.
lock_flags
If this is not a null summary, this field contains flags describing the protection status of the buffer.
size
If this is not a null summary, this field specifies the size of the text in the buffer.
line_count
If this is not a null summary, this field specifies the number of lines in the buffer.
file_name
If this is not a null summary, this field specifies the file name associated to this buffer.
file_name_len
This field specifies the length of the file_name string.
buffer_name
If this is not a null summary, this field specifies the name of the buffer.
buffer_name_len
This field specifies the length of the buffer_name string.
is_lexed
If this is not a null summary, this field indicates whether the buffer is set to lex tokens.
map_id
If this is not a null summary, this field specifies the id of the command map for this buffer.
unwrapped_lines
If this is not a null summary, this field indicates whether the buffer 'prefers' wrapped lines.
See Also
§3.4.39: View_Summary
struct View_Summary {
bool32 exists;
int32_t view_id;
int32_t buffer_id;
Access_Flag lock_flags;
Full_Cursor cursor;
Full_Cursor mark;
float preferred_x;
float line_height;
bool32 unwrapped_lines;
bool32 show_whitespace;
i32_Rect file_region;
GUI_Scroll_Vars scroll_vars;
};
Description
View_Summary acts as a handle to a view and describes the state of the view.
Fields
exists
This field indicates whether the View_Summary describes a view that is open in 4coder.
+ If this is a null summary then buffer_id is 0.
lock_flags
If this is not a null summary, this field contains flags describing the protection status of the buffer.
size
If this is not a null summary, this field specifies the size of the text in the buffer.
line_count
If this is not a null summary, this field specifies the number of lines in the buffer.
file_name
If this is not a null summary, this field specifies the file name associated to this buffer.
file_name_len
This field specifies the length of the file_name string.
buffer_name
If this is not a null summary, this field specifies the name of the buffer.
buffer_name_len
This field specifies the length of the buffer_name string.
is_lexed
If this is not a null summary, this field indicates whether the buffer is set to lex tokens.
tokens_are_ready
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.
map_id
If this is not a null summary, this field specifies the id of the command map for this buffer.
unwrapped_lines
If this is not a null summary, this field indicates whether the buffer 'prefers' wrapped lines.
See Also
§3.4.39: View_Summary
struct View_Summary {
bool32 exists;
int32_t view_id;
int32_t buffer_id;
Access_Flag lock_flags;
Full_Cursor cursor;
Full_Cursor mark;
float preferred_x;
float line_height;
bool32 unwrapped_lines;
bool32 show_whitespace;
i32_Rect file_region;
GUI_Scroll_Vars scroll_vars;
};
Description
View_Summary acts as a handle to a view and describes the state of the view.
Fields
exists
This field indicates whether the View_Summary describes a view that is open in 4coder.
When this field is false the summary is referred to as a "null summary".
view_id
If this is not a null summary, this field is the id of the associated view.
If this is a null summary then view_id is 0.
buffer_id
If this is not a null summary, then this is the id of the buffer this view currently sees.
lock_flags
If this is not a null summary, this field contains flags describing the protection status of the view.
cursor
If this is not a null summary, this describes the position of the cursor.
mark
If this is not a null summary, this describes the position of the mark.
preferred_x
If this is not a null summary, this is the x position that is maintained in vertical navigation.
line_height
If this is not a null summary, this specifies the height of a line rendered in the view.
unwrapped_lines
If this is not a null summary, this indicates that the view is set to render with unwrapped lines.
show_whitespace
If this is not a null summary, this indicates that the view is set to highlight white space.
file_region
If this is not a null summary, this describes the screen position in which this view's buffer is displayed.
scroll_vars
If this is not a null summary, this describes the scrolling position inside the view.
See Also
§3.4.41: Query_Bar
struct Query_Bar {
String prompt;
String string;
};
Description
Query_Bar is a struct used to store information in the user's control
that will be displayed as a drop down bar durring an interactive command.
Fields
prompt
This specifies the prompt portion of the drop down bar.
string
This specifies the main string portion of the drop down bar.
§3.4.42: Event_Message
struct Event_Message {
int32_t type;
};
Description
This feature is not implemented.
Fields
type
This feature is not implemented.
§3.4.43: Theme_Color
struct Theme_Color {
Style_Tag tag;
int_color color;
};
Description
Theme_Color stores a style tag/color pair, for the purpose of setting and getting colors in the theme .
Fields
See Also
diff --git a/4coder_auto_indent.cpp b/4coder_auto_indent.cpp
new file mode 100644
index 00000000..7f3cd5ae
--- /dev/null
+++ b/4coder_auto_indent.cpp
@@ -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
+
diff --git a/4coder_custom_api.h b/4coder_custom_api.h
index 64dd0a0e..5dfc3251 100644
--- a/4coder_custom_api.h
+++ b/4coder_custom_api.h
@@ -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;\
diff --git a/4coder_default_include.cpp b/4coder_default_include.cpp
index a3671bed..f1d507d2 100644
--- a/4coder_default_include.cpp
+++ b/4coder_default_include.cpp
@@ -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);
}
}
diff --git a/4coder_types.h b/4coder_types.h
index 94b6b285..140f2c73 100644
--- a/4coder_types.h
+++ b/4coder_types.h
@@ -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.) */
diff --git a/4ed_api_implementation.cpp b/4ed_api_implementation.cpp
index 3c0dab5b..9926bb6d 100644
--- a/4ed_api_implementation.cpp
+++ b/4ed_api_implementation.cpp
@@ -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);
diff --git a/4ed_defines.h b/4ed_defines.h
index 60680774..2ae6067d 100644
--- a/4ed_defines.h
+++ b/4ed_defines.h
@@ -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)))
diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp
index 5ed4447f..1c674764 100644
--- a/4ed_file_view.cpp
+++ b/4ed_file_view.cpp
@@ -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;
}
}
}
diff --git a/TODO.txt b/TODO.txt
index 8eaeca3f..673ec61c 100644
--- a/TODO.txt
+++ b/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
diff --git a/win32_4ed.cpp b/win32_4ed.cpp
index 7061a645..f89ebf40 100644
--- a/win32_4ed.cpp
+++ b/win32_4ed.cpp
@@ -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: