diff --git a/4coder_API.html b/4coder_API.html index 8c080761..7bef8f01 100644 --- a/4coder_API.html +++ b/4coder_API.html @@ -22,7 +22,7 @@ ul { list-style: none; padding: 0; margin: 0; }

§1 Introduction

-This is the documentation for alpha 4.0.9 super! The documentation is still under construction so some of the links are linking to sections that have not been written yet. What is here should be correct and I suspect useful even without some of the other sections.

+This is the documentation for alpha 4.0.10 The documentation is still under construction so some of the links are linking to sections that have not been written yet. What is here should be correct and I suspect useful even without some of the other sections.

If you have questions or discover errors please contact editor@4coder.net or to get help from community members you can post on the 4coder forums hosted on handmade.network at 4coder.handmade.network

@@ -34,9 +34,13 @@ Coming Soon

+
+

§3.3.3: memory_alloc

+
void* app->memory_alloc( +
Application_Links *app,
int32_t size
) +
+
Description
TODO

+
+

§3.3.4: memory_set_protection

+
int32_t app->memory_set_protection( +
Application_Links *app,
void *ptr,
int32_t size,
Memory_Protect_Flags flags
) +
+
Description
TODO

+
+

§3.3.5: memory_free

+
void app->memory_free( +
Application_Links *app,
void *mem
) +
+
Description
TODO

-

§3.3.3: clipboard_post

+

§3.3.6: clipboard_post

void app->clipboard_post(
Application_Links *app,
int32_t clipboard_id,
char *str,
int32_t len
)
@@ -202,7 +225,7 @@ If the view parameter is NULL, no view will switch to the output.
See Also
The_4coder_Clipboard

-

§3.3.4: clipboard_count

+

§3.3.7: clipboard_count

int32_t app->clipboard_count(
Application_Links *app,
int32_t clipboard_id
)
@@ -212,7 +235,7 @@ be pasted into other applications.
Description
This call returns the number of items in the clipboard.
See Also
The_4coder_Clipboard

-

§3.3.5: clipboard_index

+

§3.3.8: clipboard_index

int32_t app->clipboard_index(
Application_Links *app,
int32_t clipboard_id,
int32_t item_index,
char *out,
int32_t len
)
@@ -235,8 +258,14 @@ be pasted into other applications.
Return
This call returns the size of the item associated with item_index.
Description
This function always returns the size of the item even if the output buffer is NULL. If the output buffer is too small to contain the whole string, it is filled with the first len character of the clipboard contents. The output string is not null terminated.
See Also
The_4coder_Clipboard

+
+

§3.3.9: get_buffer_count

+
int32_t app->get_buffer_count( +
Application_Links *app
) +
+
Description
TODO

-

§3.3.6: get_buffer_first

+

§3.3.10: get_buffer_first

Buffer_Summary app->get_buffer_first(
Application_Links *app,
Access_Flag access
)
@@ -249,7 +278,7 @@ first len character of the clipboard contents. The output string is not null te If the buffer returned does not exist, the loop is finished. Buffers should not be killed durring a buffer loop.
See Also
Access_Flag
get_buffer_next

-

§3.3.7: get_buffer_next

+

§3.3.11: get_buffer_next

void app->get_buffer_next(
Application_Links *app,
Buffer_Summary *buffer,
Access_Flag access
)
@@ -267,7 +296,7 @@ The global buffer order is kept roughly in the order of most recently used to le If the buffer outputted does not exist, the loop is finished. Buffers should not be killed or created durring a buffer loop.
See Also
Access_Flag
get_buffer_first

-

§3.3.8: get_buffer

+

§3.3.12: get_buffer

Buffer_Summary app->get_buffer(
Application_Links *app,
Buffer_ID buffer_id,
Access_Flag access
)
@@ -281,7 +310,7 @@ Buffers should not be killed or created durring a buffer loop.
Return
This call returns a summary that describes the indicated buffer if it exists and is accessible.
See Also
Access_Flag
Buffer_ID

-

§3.3.9: get_buffer_by_name

+

§3.3.13: get_buffer_by_name

Buffer_Summary app->get_buffer_by_name(
Application_Links *app,
char *name,
int32_t len,
Access_Flag access
)
@@ -299,7 +328,7 @@ Buffers should not be killed or created durring a buffer loop.
Return
This call returns a summary that describes the indicated buffer if it exists and is accessible.
See Also
Access_Flag

-

§3.3.10: buffer_boundary_seek

+

§3.3.14: buffer_boundary_seek

int32_t app->buffer_boundary_seek(
Application_Links *app,
Buffer_Summary *buffer,
int32_t start_pos,
bool32 seek_forward,
Seek_Boundary_Flag flags
)
@@ -323,7 +352,7 @@ Buffers should not be killed or created durring a buffer loop.
See Also
Seek_Boundary_Flag
4coder_Buffer_Positioning_System

-

§3.3.11: buffer_read_range

+

§3.3.15: buffer_read_range

bool32 app->buffer_read_range(
Application_Links *app,
Buffer_Summary *buffer,
int32_t start,
int32_t end,
char *out
)
@@ -349,7 +378,7 @@ The output is not null terminated. This call fails if the buffer does not exist, or if the read range is not within the bounds of the buffer.
See Also
4coder_Buffer_Positioning_System

-

§3.3.12: buffer_replace_range

+

§3.3.16: buffer_replace_range

bool32 app->buffer_replace_range(
Application_Links *app,
Buffer_Summary *buffer,
int32_t start,
int32_t end,
char *str,
int32_t len
)
@@ -382,7 +411,7 @@ from start to end. This call fails if the buffer does not exist, or if the replace range is not within the bounds of the buffer.
See Also
4coder_Buffer_Positioning_System

-

§3.3.13: buffer_batch_edit

+

§3.3.17: buffer_batch_edit

bool32 app->buffer_batch_edit(
Application_Links *app,
Buffer_Summary *buffer,
char *str,
int32_t str_len,
Buffer_Edit *edits,
int32_t edit_count,
Buffer_Batch_Edit_Type type
)
@@ -406,9 +435,9 @@ range is not within the bounds of the buffer.
type
This prameter specifies what type of batch edit to execute.
-
Return
This call returns non-zero if the batch edit succeeds.
See Also
Buffer_Edit
Buffer_Batch_Edit_Type

+
Return
This call returns non-zero if the batch edit succeeds.
Description
TODO
See Also
Buffer_Edit
Buffer_Batch_Edit_Type

-

§3.3.14: buffer_set_setting

+

§3.3.18: buffer_set_setting

bool32 app->buffer_set_setting(
Application_Links *app,
Buffer_Summary *buffer,
Buffer_Setting_ID setting,
int32_t value
)
@@ -426,7 +455,7 @@ range is not within the bounds of the buffer.
See Also
Buffer_Setting_ID

-

§3.3.15: buffer_auto_indent

+

§3.3.19: buffer_auto_indent

bool32 app->buffer_auto_indent(
Application_Links *app,
Buffer_Summary *buffer,
int32_t start,
int32_t end,
int32_t tab_width,
Auto_Indent_Flag flags
)
@@ -455,7 +484,7 @@ 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.
See Also
Auto_Indent_Flag
4coder_Buffer_Positioning_System

-

§3.3.16: create_buffer

+

§3.3.20: create_buffer

Buffer_Summary app->create_buffer(
Application_Links *app,
char *filename,
int32_t filename_len,
Buffer_Create_Flag flags
)
@@ -477,7 +506,7 @@ If the buffer does not exist a new buffer is created and named after the given f the filename corresponds to a file on the disk that file is loaded and put into buffer, if the filename does not correspond to a file on disk the buffer is created empty.
See Also
Buffer_Create_Flag

-

§3.3.17: save_buffer

+

§3.3.21: save_buffer

bool32 app->save_buffer(
Application_Links *app,
Buffer_Summary *buffer,
char *filename,
int32_t filename_len,
uint32_t flags
)
@@ -499,7 +528,7 @@ the filename does not correspond to a file on disk the buffer is created empty.<
Return
This call returns non-zero on success.

-

§3.3.18: kill_buffer

+

§3.3.22: kill_buffer

bool32 app->kill_buffer(
Application_Links *app,
Buffer_Identifier buffer,
View_ID view_id,
Buffer_Kill_Flag flags
)
@@ -519,7 +548,7 @@ the filename does not correspond to a file on disk the buffer is created empty.< dialogue needs to be displayed the provided view is used to show the dialogue. If the view is not open the kill fails.
See Also
Buffer_Kill_Flag
Buffer_Identifier

-

§3.3.19: get_view_first

+

§3.3.23: get_view_first

View_Summary app->get_view_first(
Application_Links *app,
Access_Flag access
)
@@ -532,7 +561,7 @@ If the view is not open the kill fails.
See Also
Access_Flag
get_view_next

-

§3.3.20: get_view_next

+

§3.3.24: get_view_next

void app->get_view_next(
Application_Links *app,
View_Summary *view,
Access_Flag access
)
@@ -549,7 +578,7 @@ Views should not be closed or opened durring a view loop.
See Also
Access_Flag
get_view_first

-

§3.3.21: get_view

+

§3.3.25: get_view

View_Summary app->get_view(
Application_Links *app,
View_ID view_id,
Access_Flag access
)
@@ -563,7 +592,7 @@ Views should not be closed or opened durring a view loop.
Return
This call returns a summary that describes the indicated view if it is open and accessible.
See Also
Access_Flag

-

§3.3.22: get_active_view

+

§3.3.26: get_active_view

View_Summary app->get_active_view(
Application_Links *app,
Access_Flag access
)
@@ -573,7 +602,7 @@ Views should not be closed or opened durring a view loop.
Return
This call returns a summary that describes the active view.
See Also
set_active_view
Access_Flag

-

§3.3.23: open_view

+

§3.3.27: open_view

View_Summary app->open_view(
Application_Links *app,
View_Summary *view_location,
View_Split_Position position
)
@@ -589,7 +618,7 @@ Views should not be closed or opened durring a view loop.
Description
4coder is built with a limit of 16 views. If 16 views are already open when this is called the call will fail.
See Also
View_Split_Position

-

§3.3.24: close_view

+

§3.3.28: close_view

bool32 app->close_view(
Application_Links *app,
View_Summary *view
)
@@ -602,7 +631,7 @@ If the given view is the active view, the next active view in the global order of view will be made active. If the given view is the last open view in the system, the call will fail.

-

§3.3.25: set_active_view

+

§3.3.29: set_active_view

bool32 app->set_active_view(
Application_Links *app,
View_Summary *view
)
@@ -614,7 +643,7 @@ If the given view is the last open view in the system, the call will fail.
active view, and takes subsequent commands and is returned from get_active_view.
See Also
get_active_view

-

§3.3.26: view_set_setting

+

§3.3.30: view_set_setting

bool32 app->view_set_setting(
Application_Links *app,
View_Summary *view,
View_Setting_ID setting,
int32_t value
)
@@ -632,7 +661,7 @@ from get_active_view.
Return
This call returns non-zero on success.
See Also
View_Setting_ID

-

§3.3.27: view_set_split_proportion

+

§3.3.31: view_set_split_proportion

bool32 app->view_set_split_proportion(
Application_Links *app,
View_Summary *view,
float t
)
@@ -646,7 +675,7 @@ from get_active_view.
Return
This call returns non-zero on success.

-

§3.3.28: view_compute_cursor

+

§3.3.32: view_compute_cursor

bool32 app->view_compute_cursor(
Application_Links *app,
View_Summary *view,
Buffer_Seek seek,
Full_Cursor *cursor_out
)
@@ -664,7 +693,7 @@ from get_active_view.
Return
This call returns non-zero on success.
Description
Computes a Full_Cursor for the given seek position with no side effects.
See Also
Buffer_Seek
Full_Cursor

-

§3.3.29: view_set_cursor

+

§3.3.33: view_set_cursor

bool32 app->view_set_cursor(
Application_Links *app,
View_Summary *view,
Buffer_Seek seek,
bool32 set_preferred_x
)
@@ -684,7 +713,7 @@ from get_active_view.
See Also
Buffer_Seek

-

§3.3.30: view_set_mark

+

§3.3.34: view_set_mark

bool32 app->view_set_mark(
Application_Links *app,
View_Summary *view,
Buffer_Seek seek
)
@@ -698,7 +727,7 @@ cursor in the same column or x position.
Return
This call returns non-zero on success.
Description
This call sets the the view's mark position.
See Also
Buffer_Seek

-

§3.3.31: view_set_highlight

+

§3.3.35: view_set_highlight

bool32 app->view_set_highlight(
Application_Links *app,
View_Summary *view,
int32_t start,
int32_t end,
bool32 turn_on
)
@@ -723,7 +752,7 @@ is set to true the highlight will be shown and the cursor will be hidden. After that either setting the with view_set_cursor or calling view_set_highlight and the turn_on set to false, will switch back to showing the cursor.

-

§3.3.32: view_set_buffer

+

§3.3.36: view_set_buffer

bool32 app->view_set_buffer(
Application_Links *app,
View_Summary *view,
Buffer_ID buffer_id,
Set_Buffer_Flag flags
)
@@ -742,7 +771,7 @@ the turn_on set to false, will switch back to showing the cursor.

Return
This call returns non-zero on success.
Description
On success view_set_buffer sets the specified view's current buffer and cancels and dialogue shown in the view and displays the file.
See Also
Set_Buffer_Flag

-

§3.3.33: view_post_fade

+

§3.3.37: view_post_fade

bool32 app->view_post_fade(
Application_Links *app,
View_Summary *view,
float seconds,
int32_t start,
int32_t end,
int_color color
)
@@ -768,7 +797,7 @@ cancels and dialogue shown in the view and displays the file.
Return
This call returns non-zero on success.
See Also
int_color

-

§3.3.34: get_user_input

+

§3.3.38: get_user_input

User_Input app->get_user_input(
Application_Links *app,
Input_Type_Flag get_type,
Input_Type_Flag abort_type
)
@@ -786,19 +815,19 @@ command is executed an abort signal is returned. If an abort signal is ever ret command should finish execution without any more calls that preempt the command. If a get condition is met the user input is returned.
See Also
Input_Type_Flag
User_Input

-

§3.3.35: get_command_input

+

§3.3.39: get_command_input

User_Input app->get_command_input(
Application_Links *app
)
Return
This call returns the input that triggered the currently executing command.
See Also
User_Input

-

§3.3.36: get_mouse_state

+

§3.3.40: get_mouse_state

Mouse_State app->get_mouse_state(
Application_Links *app
)
Return
This call returns the current mouse state as of the beginning of the frame.
See Also
Mouse_State

-

§3.3.37: start_query_bar

+

§3.3.41: start_query_bar

bool32 app->start_query_bar(
Application_Links *app,
Query_Bar *bar,
uint32_t flags
)
@@ -818,7 +847,7 @@ can be changed after the call to start_query_bar and the query bar shown by 4cod will reflect the change. Since the bar stops showing when the command exits the only use for this call is in an interactive command that makes calls to get_user_input.

-

§3.3.38: end_query_bar

+

§3.3.42: end_query_bar

void app->end_query_bar(
Application_Links *app,
Query_Bar *bar,
uint32_t flags
)
@@ -832,7 +861,7 @@ only use for this call is in an interactive command that makes calls to get_user
Description
Stops showing the particular query bar specified by the bar parameter.

Description
This call posts a string to the *messages* buffer.

-

§3.3.40: change_theme

+

§3.3.44: change_theme

void app->change_theme(
Application_Links *app,
char *name,
int32_t len
)
@@ -860,7 +889,7 @@ only use for this call is in an interactive command that makes calls to get_user
Description
This call changes 4coder's theme to one of the built in themes.

-

§3.3.41: change_font

+

§3.3.45: change_font

void app->change_font(
Application_Links *app,
char *name,
int32_t len
)
@@ -874,7 +903,7 @@ only use for this call is in an interactive command that makes calls to get_user
Description
This call changes 4coder's font to one of the built in fonts.

-

§3.3.42: set_theme_colors

+

§3.3.46: set_theme_colors

void app->set_theme_colors(
Application_Links *app,
Theme_Color *colors,
int32_t count
)
@@ -890,7 +919,7 @@ only use for this call is in an interactive command that makes calls to get_user struct's tag is set to the color code in the struct. If the tag value is invalid no change is made to the color pallet.

-

§3.3.43: get_theme_colors

+

§3.3.47: get_theme_colors

void app->get_theme_colors(
Application_Links *app,
Theme_Color *colors,
int32_t count
)
@@ -906,7 +935,7 @@ no change is made to the color pallet.

color from the slot in the main color pallet specified by the tag. If the tag value is invalid the color is filled with black.
-

§3.3.44: directory_get_hot

+

§3.3.48: directory_get_hot

int32_t app->directory_get_hot(
Application_Links *app,
char *out,
int32_t capacity
)
@@ -924,7 +953,7 @@ accessed in the GUI. Whenever the GUI is opened it shows the hot directory. In the future this will be deprecated and eliminated in favor of more flexible directories controlled on the custom side.

-

§3.3.45: get_file_list

+

§3.3.49: get_file_list

File_List app->get_file_list(
Application_Links *app,
char *dir,
int32_t len
)
@@ -940,7 +969,7 @@ directories controlled on the custom side.

the specified directory. The File_List returned should be passed to free_file_list when it is no longer in use.
-

§3.3.46: free_file_list

+

§3.3.50: free_file_list

void app->free_file_list(
Application_Links *app,
File_List list
)
@@ -950,7 +979,7 @@ when it is no longer in use.

Description
After this call the file list passed in should not be read or written to.

-

§3.3.47: file_exists

+

§3.3.51: file_exists

bool32 app->file_exists(
Application_Links *app,
char *filename,
int len
)
@@ -964,7 +993,7 @@ when it is no longer in use.

Return
This call returns non-zero if and only if the file exists.

-

§3.3.48: directory_cd

+

§3.3.52: directory_cd

bool32 app->directory_cd(
Application_Links *app,
char *dir,
int *len,
int capacity,
char *rel_path,
int rel_len
)
@@ -997,7 +1026,7 @@ will contain "C:/Users/MySelf/Documents" and len will contain the length of that string. This call can also be used with rel set to ".." to traverse to parent folders.

-

§3.3.49: get_4ed_path

+

§3.3.53: get_4ed_path

bool32 app->get_4ed_path(
Application_Links *app,
char *out,
int32_t capacity
)
@@ -1011,7 +1040,7 @@ folders.

Return
This call returns non-zero on success.

-

§3.3.50: show_mouse_cursor

+

§3.3.54: show_mouse_cursor

void app->show_mouse_cursor(
Application_Links *app,
Mouse_Cursor_Show_Type show
)
@@ -1110,10 +1139,6 @@ the range [1,16].

cmdid_history_forward unperforms the previous cmdid_history_backward step if possib.e
-
cmdid_clean_all_lines
-
cmdid_clean_all_lines deletes extra whitespace out the currently active buffer.
-
-
cmdid_interactive_new
cmdid_interactive_new begins an interactive dialogue to create a new buffer.
@@ -1207,11 +1232,12 @@ the range [1,16].
enum Buffer_Batch_Edit_Type;
Description
A Buffer_Batch_Edit_Type is a type of batch operation.
Values
BatchEdit_Normal
-
+
The BatchEdit_Normal operation is always correct but does the most work.
BatchEdit_PreserveTokens
-
+
The BatchEdit_PreserveTokens operation is one in which none of the edits add, delete, or change any tokens. + This usually applies when whitespace is being replaced with whitespace.

@@ -1342,8 +1368,24 @@ Flags can be combined with bit or to specify a state with multiple modifiers.

+
+

§3.4.17: Memory_Protect_Flags

+
enum Memory_Protect_Flags;
+
Description
TODO
Flags
+
MemProtect_Read = 0x1
+
+
+
+
MemProtect_Write = 0x2
+
+
+
+
MemProtect_Execute = 0x4
+
+
+

-

§3.4.17: Buffer_Create_Flag

+

§3.4.18: Buffer_Create_Flag

enum Buffer_Create_Flag;
Description
A Buffer_Create_Flag field specifies how a buffer should be created.
Flags
BufferCreate_Background = 0x1
@@ -1356,7 +1398,7 @@ Flags can be combined with bit or to specify a state with multiple modifiers.

-

§3.4.18: Buffer_Kill_Flag

+

§3.4.19: Buffer_Kill_Flag

enum Buffer_Kill_Flag;
Description
A Buffer_Kill_Flag field specifies how a buffer should be killed.
Flags
BufferKill_Background = 0x1
@@ -1369,7 +1411,7 @@ Flags can be combined with bit or to specify a state with multiple modifiers.

-

§3.4.19: Access_Flag

+

§3.4.20: Access_Flag

enum Access_Flag;
Description
An Access_Flag field specifies what sort of permission you grant to an access call. An access call is usually one the returns a summary struct. If a @@ -1399,7 +1441,7 @@ that protection flag, the object is still returned from the access call.

-

§3.4.20: Seek_Boundary_Flag

+

§3.4.21: Seek_Boundary_Flag

enum Seek_Boundary_Flag;
Description
A Seek_Boundary_Flag field specifies a set of "boundary" types used in seeks for the beginning or end of different types of words.
Flags
@@ -1420,7 +1462,7 @@ beginning or end of different types of words.
-

§3.4.21: Command_Line_Input_Flag

+

§3.4.22: Command_Line_Input_Flag

enum Command_Line_Input_Flag;
Description
A Command_Line_Input_Flag field specifies the behavior of a call to a command line interface.
Flags
CLI_OverlapWithConflict = 0x1
@@ -1441,7 +1483,7 @@ beginning or end of different types of words.
-

§3.4.22: Auto_Indent_Flag

+

§3.4.23: Auto_Indent_Flag

enum Auto_Indent_Flag;
Description
An Auto_Indent_Flag field specifies the behavior of an auto indentation operation.
Flags
AutoIndent_ClearLine = 0x1
@@ -1457,7 +1499,7 @@ beginning or end of different types of words.
-

§3.4.23: Set_Buffer_Flag

+

§3.4.24: Set_Buffer_Flag

enum Set_Buffer_Flag;
Description
A Set_Buffer_Flag field specifies the behavior of an operation that sets the buffer of a view.
Flags
SetBuffer_KeepOriginalGUI = 0x1
@@ -1467,7 +1509,7 @@ beginning or end of different types of words.
-

§3.4.24: Input_Type_Flag

+

§3.4.25: Input_Type_Flag

enum Input_Type_Flag;
Description
A Input_Type_Flag field specifies a set of input event types.
Flags
EventOnAnyKey = 0x1
@@ -1507,7 +1549,7 @@ beginning or end of different types of words.
-

§3.4.25: Generic_Command

+

§3.4.26: Generic_Command

union Generic_Command {
Command_ID cmdid;
@@ -1528,7 +1570,7 @@ internal command or a custom command.
-

§3.4.26: Key_Event_Data

+

§3.4.27: Key_Event_Data

struct Key_Event_Data {
Key_Code keycode;
@@ -1562,7 +1604,7 @@ at the time of the event.
-

§3.4.27: Mouse_State

+

§3.4.28: Mouse_State

struct Mouse_State {
char l;
@@ -1622,7 +1664,7 @@ mouse if in the window.
-

§3.4.28: Range

+

§3.4.29: Range

union Range {
struct {
@@ -1662,7 +1704,7 @@ Throughout the API ranges are thought of in the form [min,max
-

§3.4.29: File_Info

+

§3.4.30: File_Info

struct File_Info {
char * filename;
@@ -1685,7 +1727,7 @@ int folder;
See Also

-

§3.4.30: File_List

+

§3.4.31: File_List

struct File_List {
void * block;
@@ -1713,7 +1755,7 @@ int block_size;

-

§3.4.31: Buffer_Identifier

+

§3.4.32: Buffer_Identifier

struct Buffer_Identifier {
char * name;
@@ -1738,7 +1780,7 @@ can either be a name or an id. If the
-

§3.4.32: GUI_Scroll_Vars

+

§3.4.33: GUI_Scroll_Vars

struct GUI_Scroll_Vars {
float scroll_y;
@@ -1776,7 +1818,7 @@ int32_t prev_target_x;

-

§3.4.33: Full_Cursor

+

§3.4.34: Full_Cursor

struct Full_Cursor {
int32_t pos;
@@ -1820,7 +1862,7 @@ coordinate system supported by 4coder.
See Also

-

§3.4.34: Buffer_Seek

+

§3.4.35: Buffer_Seek

struct Buffer_Seek {
Buffer_Seek_Type type;
@@ -1885,7 +1927,7 @@ for concisely creating Buffer_Seek structs. They can be found in 4coder_buffer_
See Also

-

§3.4.35: Buffer_Edit

+

§3.4.36: Buffer_Edit

struct Buffer_Edit {
int32_t str_start;
@@ -1915,7 +1957,7 @@ will be replaced into the buffer.
-

§3.4.36: Buffer_Summary

+

§3.4.37: Buffer_Summary

struct Buffer_Summary {
bool32 exists;
@@ -1990,7 +2032,7 @@ bool32 unwrapped_lines;
See Also

-

§3.4.37: View_Summary

+

§3.4.38: View_Summary

struct View_Summary {
bool32 exists;
@@ -2060,7 +2102,7 @@ GUI_Scroll_Vars scroll_vars;
See Also

-

§3.4.38: User_Input

+

§3.4.39: User_Input

struct User_Input {
User_Input_Type_ID type;
@@ -2097,7 +2139,7 @@ Generic_Command command;
See Also

-

§3.4.39: Query_Bar

+

§3.4.40: Query_Bar

struct Query_Bar {
String prompt;
@@ -2116,7 +2158,7 @@ that will be displayed as a drop down bar durring an interactive command.
<

-

§3.4.40: Event_Message

+

§3.4.41: Event_Message

struct Event_Message {
int type;
@@ -2129,7 +2171,7 @@ int type;

-

§3.4.41: Theme_Color

+

§3.4.42: Theme_Color

struct Theme_Color {
Style_Tag tag;
diff --git a/4coder_custom_api.h b/4coder_custom_api.h index 2086c39e..9908cb45 100644 --- a/4coder_custom_api.h +++ b/4coder_custom_api.h @@ -1,8 +1,12 @@ #define EXEC_COMMAND_SIG(n) bool32 n(Application_Links *app, Command_ID command_id) #define EXEC_SYSTEM_COMMAND_SIG(n) bool32 n(Application_Links *app, View_Summary *view, Buffer_Identifier buffer, char *path, int32_t path_len, char *command, int32_t command_len, Command_Line_Input_Flag flags) +#define MEMORY_ALLOC_SIG(n) void* n(Application_Links *app, int32_t size) +#define MEMORY_SET_PROTECTION_SIG(n) int32_t n(Application_Links *app, void *ptr, int32_t size, Memory_Protect_Flags flags) +#define MEMORY_FREE_SIG(n) void n(Application_Links *app, void *mem) #define CLIPBOARD_POST_SIG(n) void n(Application_Links *app, int32_t clipboard_id, char *str, int32_t len) #define CLIPBOARD_COUNT_SIG(n) int32_t n(Application_Links *app, int32_t clipboard_id) #define CLIPBOARD_INDEX_SIG(n) int32_t n(Application_Links *app, int32_t clipboard_id, int32_t item_index, char *out, int32_t len) +#define GET_BUFFER_COUNT_SIG(n) int32_t n(Application_Links *app) #define GET_BUFFER_FIRST_SIG(n) Buffer_Summary n(Application_Links *app, Access_Flag access) #define GET_BUFFER_NEXT_SIG(n) void n(Application_Links *app, Buffer_Summary *buffer, Access_Flag access) #define GET_BUFFER_SIG(n) Buffer_Summary n(Application_Links *app, Buffer_ID buffer_id, Access_Flag access) @@ -51,9 +55,13 @@ extern "C"{ typedef EXEC_COMMAND_SIG(Exec_Command_Function); typedef EXEC_SYSTEM_COMMAND_SIG(Exec_System_Command_Function); + typedef MEMORY_ALLOC_SIG(Memory_Alloc_Function); + typedef MEMORY_SET_PROTECTION_SIG(Memory_Set_Protection_Function); + typedef MEMORY_FREE_SIG(Memory_Free_Function); typedef CLIPBOARD_POST_SIG(Clipboard_Post_Function); typedef CLIPBOARD_COUNT_SIG(Clipboard_Count_Function); typedef CLIPBOARD_INDEX_SIG(Clipboard_Index_Function); + typedef GET_BUFFER_COUNT_SIG(Get_Buffer_Count_Function); typedef GET_BUFFER_FIRST_SIG(Get_Buffer_First_Function); typedef GET_BUFFER_NEXT_SIG(Get_Buffer_Next_Function); typedef GET_BUFFER_SIG(Get_Buffer_Function); @@ -105,9 +113,13 @@ struct Application_Links{ int memory_size; Exec_Command_Function *exec_command; Exec_System_Command_Function *exec_system_command; + Memory_Alloc_Function *memory_alloc; + Memory_Set_Protection_Function *memory_set_protection; + Memory_Free_Function *memory_free; Clipboard_Post_Function *clipboard_post; Clipboard_Count_Function *clipboard_count; Clipboard_Index_Function *clipboard_index; + Get_Buffer_Count_Function *get_buffer_count; Get_Buffer_First_Function *get_buffer_first; Get_Buffer_Next_Function *get_buffer_next; Get_Buffer_Function *get_buffer; @@ -161,9 +173,13 @@ struct Application_Links{ #define FillAppLinksAPI(app_links) do{\ app_links->exec_command = Exec_Command;\ app_links->exec_system_command = Exec_System_Command;\ +app_links->memory_alloc = Memory_Alloc;\ +app_links->memory_set_protection = Memory_Set_Protection;\ +app_links->memory_free = Memory_Free;\ app_links->clipboard_post = Clipboard_Post;\ app_links->clipboard_count = Clipboard_Count;\ app_links->clipboard_index = Clipboard_Index;\ +app_links->get_buffer_count = Get_Buffer_Count;\ app_links->get_buffer_first = Get_Buffer_First;\ app_links->get_buffer_next = Get_Buffer_Next;\ app_links->get_buffer = Get_Buffer;\ diff --git a/4coder_default_include.cpp b/4coder_default_include.cpp index 1f6e6dcd..b58cdd1d 100644 --- a/4coder_default_include.cpp +++ b/4coder_default_include.cpp @@ -11,6 +11,414 @@ #include +// +// Memory +// + +static Partition scratch; + + +// +// Buffer Streaming +// + +struct Stream_Chunk{ + Application_Links *app; + Buffer_Summary *buffer; + + char *base_data; + int start, end; + int min_start, max_end; + int data_size; + + char *data; +}; + +int +round_down(int x, int b){ + int r = 0; + if (x >= 0){ + r = x - (x % b); + } + return(r); +} + +int +round_up(int x, int b){ + int r = 0; + if (x >= 0){ + r = x - (x % b) + b; + } + return(r); +} + +void +refresh_buffer(Application_Links *app, Buffer_Summary *buffer){ + *buffer = app->get_buffer(app, buffer->buffer_id, AccessAll); +} + +void +refresh_view(Application_Links *app, View_Summary *view){ + *view = app->get_view(app, view->view_id, AccessAll); +} + +int +init_stream_chunk(Stream_Chunk *chunk, + Application_Links *app, Buffer_Summary *buffer, + int pos, char *data, int size){ + int result = false; + + refresh_buffer(app, buffer); + if (pos >= 0 && pos < buffer->size && size > 0){ + chunk->app = app; + chunk->buffer = buffer; + chunk->base_data = data; + chunk->data_size = size; + chunk->start = round_down(pos, size); + chunk->end = round_up(pos, size); + + if (chunk->max_end > buffer->size + || chunk->max_end == 0){ + chunk->max_end = buffer->size; + } + + if (chunk->max_end && chunk->max_end < chunk->end){ + chunk->end = chunk->max_end; + } + if (chunk->min_start && chunk->min_start > chunk->start){ + chunk->start = chunk->min_start; + } + + if (chunk->start < chunk->end){ + app->buffer_read_range(app, buffer, chunk->start, chunk->end, chunk->base_data); + chunk->data = chunk->base_data - chunk->start; + result = true; + } + } + return(result); +} + +int +forward_stream_chunk(Stream_Chunk *chunk){ + Application_Links *app = chunk->app; + Buffer_Summary *buffer = chunk->buffer; + int result = false; + + refresh_buffer(app, buffer); + if (chunk->end < buffer->size){ + chunk->start = chunk->end; + chunk->end += chunk->data_size; + + if (chunk->max_end && chunk->max_end < chunk->end){ + chunk->end = chunk->max_end; + } + if (chunk->min_start && chunk->min_start > chunk->start){ + chunk->start = chunk->min_start; + } + + if (chunk->start < chunk->end){ + app->buffer_read_range(app, buffer, chunk->start, chunk->end, chunk->base_data); + chunk->data = chunk->base_data - chunk->start; + result = true; + } + } + return(result); +} + +int +backward_stream_chunk(Stream_Chunk *chunk){ + Application_Links *app = chunk->app; + Buffer_Summary *buffer = chunk->buffer; + int result = false; + + refresh_buffer(app, buffer); + if (chunk->start > 0){ + chunk->end = chunk->start; + chunk->start -= chunk->data_size; + + if (chunk->max_end && chunk->max_end < chunk->end){ + chunk->end = chunk->max_end; + } + if (chunk->min_start && chunk->min_start > chunk->start){ + chunk->start = chunk->min_start; + } + + if (chunk->start < chunk->end){ + app->buffer_read_range(app, buffer, chunk->start, chunk->end, chunk->base_data); + chunk->data = chunk->base_data - chunk->start; + result = true; + } + } + return(result); +} + +void +buffer_seek_delimiter_forward(Application_Links *app, Buffer_Summary *buffer, + int pos, char delim, int *result){ + if (buffer->exists){ + char chunk[1024]; + int size = sizeof(chunk); + Stream_Chunk stream = {0}; + + if (init_stream_chunk(&stream, app, buffer, pos, chunk, size)){ + int still_looping = 1; + do{ + for(; pos < stream.end; ++pos){ + char at_pos = stream.data[pos]; + if (at_pos == delim){ + *result = pos; + goto finished; + } + } + still_looping = forward_stream_chunk(&stream); + }while (still_looping); + } + } + + *result = buffer->size; + + finished:; +} + +void +buffer_seek_delimiter_backward(Application_Links *app, Buffer_Summary *buffer, + int pos, char delim, int *result){ + if (buffer->exists){ + char chunk[1024]; + int size = sizeof(chunk); + Stream_Chunk stream = {0}; + + if (init_stream_chunk(&stream, app, buffer, pos, chunk, size)){ + int still_looping = 1; + do{ + for(; pos >= stream.start; --pos){ + char at_pos = stream.data[pos]; + if (at_pos == delim){ + *result = pos; + goto finished; + } + } + still_looping = backward_stream_chunk(&stream); + }while (still_looping); + } + } + + *result = 0; + + finished:; +} + +// TODO(allen): This duplication is driving me crazy... I've gotta +// upgrade the meta programming system another level. + +// NOTE(allen): This is limitted to a string size of 512. +// You can push it up or do something more clever by just +// replacing char read_buffer[512]; with more memory. +void +buffer_seek_string_forward(Application_Links *app, Buffer_Summary *buffer, + int pos, int end, char *str, int size, int *result){ + char read_buffer[512]; + + if (size <= 0){ + *result = pos; + } + else if (size > sizeof(read_buffer)){ + *result = pos; + } + else{ + if (buffer->exists){ + String read_str = make_fixed_width_string(read_buffer); + String needle_str = make_string(str, size); + char first_char = str[0]; + + read_str.size = size; + + char chunk[1024]; + int chunk_size = sizeof(chunk); + Stream_Chunk stream = {0}; + stream.max_end = end; + + if (init_stream_chunk(&stream, app, buffer, pos, chunk, chunk_size)){ + int still_looping = 1; + do{ + for(; pos < stream.end; ++pos){ + char at_pos = stream.data[pos]; + if (at_pos == first_char){ + app->buffer_read_range(app, buffer, pos, pos+size, read_buffer); + if (match(needle_str, read_str)){ + *result = pos; + goto finished; + } + } + } + still_looping = forward_stream_chunk(&stream); + }while (still_looping); + } + } + + if (end == 0){ + *result = buffer->size; + } + else{ + *result = end; + } + + finished:; + } +} + +// NOTE(allen): This is limitted to a string size of 512. +// You can push it up or do something more clever by just +// replacing char read_buffer[512]; with more memory. +void +buffer_seek_string_backward(Application_Links *app, Buffer_Summary *buffer, + int pos, int min, char *str, int size, int *result){ + char read_buffer[512]; + if (size <= 0){ + *result = min-1; + } + else if (size > sizeof(read_buffer)){ + *result = min-1; + } + else{ + if (buffer->exists){ + String read_str = make_fixed_width_string(read_buffer); + String needle_str = make_string(str, size); + char first_char = str[0]; + + read_str.size = size; + + char chunk[1024]; + int chunk_size = sizeof(chunk); + Stream_Chunk stream = {0}; + stream.min_start = min; + + if (init_stream_chunk(&stream, app, buffer, pos, chunk, chunk_size)){ + int still_looping = 1; + do{ + for(; pos >= stream.start; --pos){ + char at_pos = stream.data[pos]; + if (at_pos == first_char){ + app->buffer_read_range(app, buffer, pos, pos+size, read_buffer); + if (match(needle_str, read_str)){ + *result = pos; + goto finished; + } + } + } + still_looping = backward_stream_chunk(&stream); + }while (still_looping); + } + } + + *result = min-1; + + finished:; + } +} + +// NOTE(allen): This is limitted to a string size of 512. +// You can push it up or do something more clever by just +// replacing char read_buffer[512]; with more memory. +void +buffer_seek_string_insensitive_forward(Application_Links *app, Buffer_Summary *buffer, + int pos, char *str, int size, int *result){ + char read_buffer[512]; + char chunk[1024]; + int chunk_size = sizeof(chunk); + Stream_Chunk stream = {0}; + + if (size <= 0){ + *result = buffer->size; + } + else if (size > sizeof(read_buffer)){ + *result = buffer->size; + } + else{ + if (buffer->exists){ + String read_str = make_fixed_width_string(read_buffer); + String needle_str = make_string(str, size); + char first_char = char_to_upper(str[0]); + + read_str.size = size; + + if (init_stream_chunk(&stream, app, buffer, pos, chunk, chunk_size)){ + int still_looping = 1; + do{ + for(; pos < stream.end; ++pos){ + char at_pos = char_to_upper(stream.data[pos]); + if (at_pos == first_char){ + app->buffer_read_range(app, buffer, pos, pos+size, read_buffer); + if (match_insensitive(needle_str, read_str)){ + *result = pos; + goto finished; + } + } + } + still_looping = forward_stream_chunk(&stream); + }while (still_looping); + } + } + + *result = buffer->size; + + finished:; + } +} + +// NOTE(allen): This is limitted to a string size of 512. +// You can push it up or do something more clever by just +// replacing char read_buffer[512]; with more memory. +void +buffer_seek_string_insensitive_backward(Application_Links *app, Buffer_Summary *buffer, + int pos, char *str, int size, int *result){ + char read_buffer[512]; + char chunk[1024]; + int chunk_size = sizeof(chunk); + Stream_Chunk stream = {0}; + + if (size <= 0){ + *result = -1; + } + else if (size > sizeof(read_buffer)){ + *result = -1; + } + else{ + if (buffer->exists){ + String read_str = make_fixed_width_string(read_buffer); + String needle_str = make_string(str, size); + char first_char = char_to_upper(str[0]); + + read_str.size = size; + + if (init_stream_chunk(&stream, app, buffer, pos, chunk, chunk_size)){ + int still_looping = 1; + do{ + for(; pos >= stream.start; --pos){ + char at_pos = char_to_upper(stream.data[pos]); + if (at_pos == first_char){ + app->buffer_read_range(app, buffer, pos, pos+size, read_buffer); + if (match_insensitive(needle_str, read_str)){ + *result = pos; + goto finished; + } + } + } + still_looping = backward_stream_chunk(&stream); + }while (still_looping); + } + } + + *result = -1; + + finished:; + } +} + +// +// Fundamental Editing +// + inline float get_view_y(View_Summary view){ float y = view.cursor.wrapped_y; @@ -29,10 +437,6 @@ get_view_x(View_Summary view){ return(x); } -// -// Fundamental Editing -// - CUSTOM_COMMAND_SIG(write_character){ unsigned int access = AccessOpen; View_Summary view = app->get_active_view(app, access); @@ -304,6 +708,12 @@ CUSTOM_COMMAND_SIG(cut){ clipboard_cut(app, range.min, range.max, 0, access); } +enum Rewrite_Type{ + RewriteNone, + RewritePaste, + RewriteWordComplete +}; + struct View_Paste_Index{ int rewrite; int next_rewrite; @@ -319,7 +729,7 @@ CUSTOM_COMMAND_SIG(paste){ if (count > 0){ View_Summary view = app->get_active_view(app, access); - view_paste_index[view.view_id].next_rewrite = true; + view_paste_index[view.view_id].next_rewrite = RewritePaste; int paste_index = 0; view_paste_index[view.view_id].index = paste_index; @@ -355,11 +765,8 @@ CUSTOM_COMMAND_SIG(paste_next){ if (count > 0){ View_Summary view = app->get_active_view(app, access); - // NOTE(allen): THIS is a very temporary poop-sauce - // system that I just threw in to get this working. - // Please don't start calling it anywhere. - if (view_paste_index[view.view_id].rewrite){ - view_paste_index[view.view_id].next_rewrite = true; + if (view_paste_index[view.view_id].rewrite == RewritePaste){ + view_paste_index[view.view_id].next_rewrite = RewritePaste; int paste_index = view_paste_index[view.view_id].index + 1; view_paste_index[view.view_id].index = paste_index; @@ -823,8 +1230,9 @@ CUSTOM_COMMAND_SIG(if0_off){ move_past_lead_whitespace(app, &view, &buffer); } + // -// +// Fast Deletes // CUSTOM_COMMAND_SIG(backspace_word){ @@ -1009,6 +1417,28 @@ CUSTOM_COMMAND_SIG(open_file_in_quotes_regular){ # define open_file_in_quotes open_file_in_quotes_regular #endif +CUSTOM_COMMAND_SIG(open_in_other_regular){ + exec_command(app, change_active_panel_regular); + exec_command(app, cmdid_interactive_open); +} + +// TODO(allen): This is a bit nasty. I want a system for picking +// the most advanced and correct version of a command to bind to a +// name based on which files are included. +#ifndef OPEN_IN_OTHER +# define OPEN_IN_OTHER 1 +#elif OPEN_IN_OTHER <= 1 +# undef OPEN_IN_OTHER +# define OPEN_IN_OTHER 1 +#endif + +#if OPEN_IN_OTHER <= 1 +# ifdef open_in_other +# undef open_in_other +# endif +# define open_in_other open_in_other_regular +#endif + CUSTOM_COMMAND_SIG(save_as){ @@ -1018,15 +1448,14 @@ CUSTOM_COMMAND_SIG(save_as){ CUSTOM_COMMAND_SIG(goto_line){ unsigned int access = AccessProtected; - int line_number; - Query_Bar bar; + Query_Bar bar = {0}; char string_space[256]; bar.prompt = make_lit_string("Goto Line: "); bar.string = make_fixed_width_string(string_space); if (query_user_number(app, &bar)){ - line_number = str_to_int(bar.string); + int line_number = str_to_int(bar.string); active_view_to_line(app, access, line_number); } } @@ -1070,6 +1499,7 @@ isearch(Application_Links *app, int start_reversed){ // NOTE(allen): If we're getting mouse events here it's a 4coder bug, because we // only asked to intercept key events. + assert(in.type == UserInputKey); int made_change = 0; @@ -1095,7 +1525,7 @@ isearch(Application_Links *app, int start_reversed){ if ((in.command.command == reverse_search) || in.key.keycode == key_page_up || in.key.keycode == key_up) step_backward = 1; - int start_pos = pos; + start_pos = pos; if (step_forward && reverse){ start_pos = match.start + 1; pos = start_pos; @@ -1158,11 +1588,11 @@ isearch(Application_Links *app, int start_reversed){ } CUSTOM_COMMAND_SIG(search){ - isearch(app, 0); + isearch(app, false); } CUSTOM_COMMAND_SIG(reverse_search){ - isearch(app, 1); + isearch(app, true); } CUSTOM_COMMAND_SIG(replace_in_range){ @@ -1193,14 +1623,15 @@ CUSTOM_COMMAND_SIG(replace_in_range){ int pos, new_pos; pos = range.min; - buffer_seek_string_forward(app, &buffer, pos, r.str, r.size, &new_pos); + + buffer_seek_string_forward(app, &buffer, pos, 0, r.str, r.size, &new_pos); while (new_pos + r.size <= range.end){ app->buffer_replace_range(app, &buffer, new_pos, new_pos + r.size, w.str, w.size); refresh_view(app, &view); range = get_range(&view); pos = new_pos + w.size; - buffer_seek_string_forward(app, &buffer, pos, r.str, r.size, &new_pos); + buffer_seek_string_forward(app, &buffer, pos, 0, r.str, r.size, &new_pos); } } @@ -1239,7 +1670,7 @@ CUSTOM_COMMAND_SIG(query_replace){ buffer = app->get_buffer(app, view.buffer_id, access); pos = view.cursor.pos; - buffer_seek_string_forward(app, &buffer, pos, r.str, r.size, &new_pos); + buffer_seek_string_forward(app, &buffer, pos, 0, r.str, r.size, &new_pos); User_Input in = {0}; while (new_pos < buffer.size){ @@ -1260,7 +1691,7 @@ CUSTOM_COMMAND_SIG(query_replace){ pos = match.max; } - buffer_seek_string_forward(app, &buffer, pos, r.str, r.size, &new_pos); + buffer_seek_string_forward(app, &buffer, pos, 0, r.str, r.size, &new_pos); } app->view_set_highlight(app, &view, 0, 0, 0); @@ -1269,6 +1700,10 @@ CUSTOM_COMMAND_SIG(query_replace){ app->view_set_cursor(app, &view, seek_pos(pos), 1); } +// +// Fast Buffer Management +// + CUSTOM_COMMAND_SIG(close_all_code){ String extension; Buffer_Summary buffer; @@ -1340,8 +1775,8 @@ char command_space[1024]; char hot_directory_space[1024]; CUSTOM_COMMAND_SIG(execute_any_cli){ - Query_Bar bar_out, bar_cmd; - String hot_directory; + Query_Bar bar_out = {0}; + Query_Bar bar_cmd = {0}; bar_out.prompt = make_lit_string("Output Buffer: "); bar_out.string = make_fixed_width_string(out_buffer_space); @@ -1351,7 +1786,7 @@ CUSTOM_COMMAND_SIG(execute_any_cli){ bar_cmd.string = make_fixed_width_string(command_space); if (!query_user_string(app, &bar_cmd)) return; - hot_directory = make_fixed_width_string(hot_directory_space); + String hot_directory = make_fixed_width_string(hot_directory_space); hot_directory.size = app->directory_get_hot(app, hot_directory.str, hot_directory.memory_size); unsigned int access = AccessAll; @@ -1365,11 +1800,9 @@ CUSTOM_COMMAND_SIG(execute_any_cli){ } CUSTOM_COMMAND_SIG(execute_previous_cli){ - String out_buffer, cmd, hot_directory; - - out_buffer = make_string_slowly(out_buffer_space); - cmd = make_string_slowly(command_space); - hot_directory = make_string_slowly(hot_directory_space); + String out_buffer = make_string_slowly(out_buffer_space); + String cmd = make_string_slowly(command_space); + String hot_directory = make_string_slowly(hot_directory_space); if (out_buffer.size > 0 && cmd.size > 0 && hot_directory.size > 0){ unsigned int access = AccessAll; @@ -1383,28 +1816,6 @@ CUSTOM_COMMAND_SIG(execute_previous_cli){ } } -CUSTOM_COMMAND_SIG(open_in_other_regular){ - exec_command(app, change_active_panel_regular); - exec_command(app, cmdid_interactive_open); -} - -// TODO(allen): This is a bit nasty. I want a system for picking -// the most advanced and correct version of a command to bind to a -// name based on which files are included. -#ifndef OPEN_IN_OTHER -# define OPEN_IN_OTHER 1 -#elif OPEN_IN_OTHER <= 1 -# undef OPEN_IN_OTHER -# define OPEN_IN_OTHER 1 -#endif - -#if OPEN_IN_OTHER <= 1 -# ifdef open_in_other -# undef open_in_other -# endif -# define open_in_other open_in_other_regular -#endif - // // Auto Indenting and Whitespace // @@ -1515,8 +1926,8 @@ CUSTOM_COMMAND_SIG(clean_all_lines){ // NOTE(allen|a4.0.9): This is provided to establish a default method of getting // a "build directory". This function tries to setup the build directory in the -// directory of the given buffer, it cannot it get's the 4coder hot directory. -// This behavior is a little different than previous versions of 4coder. +// directory of the given buffer, if it cannot get that information it get's the +// 4coder hot directory. // // There is no requirement that a custom build system in 4coder actually use the // directory given by this function. @@ -1674,8 +2085,8 @@ execute_standard_build(Application_Links *app, View_Summary *view, char dir_space[512]; String dir = make_fixed_width_string(dir_space); - char command_space[512]; - String command = make_fixed_width_string(command_space); + char command_str_space[512]; + String command = make_fixed_width_string(command_str_space); int build_dir_type = get_build_directory(app, active_buffer, &dir); @@ -1750,6 +2161,193 @@ CUSTOM_COMMAND_SIG(eol_nixify){ app->buffer_set_setting(app, &buffer, BufferSetting_Eol, false); } +// +// "Full Search" Based Commands +// + +#include "4coder_table.cpp" +#include "4coder_search.cpp" + +struct Word_Complete_State{ + Search_Set set; + Search_Iter iter; + Table hits; + String_Space str; + int word_start; + int word_end; + int initialized; +}; + +static Word_Complete_State complete_state = {0}; + +CUSTOM_COMMAND_SIG(word_complete){ + View_Summary view = app->get_active_view(app, AccessOpen); + Buffer_Summary buffer = app->get_buffer(app, view.buffer_id, AccessOpen); + + // NOTE(allen): I just do this because this command is a lot of work + // and there is no point in doing any of it if nothing will happen anyway. + if (buffer.exists){ + int do_init = false; + + if (view_paste_index[view.view_id].rewrite != RewriteWordComplete){ + do_init = true; + } + view_paste_index[view.view_id].next_rewrite != RewriteWordComplete; + if (!complete_state.initialized){ + do_init = true; + } + + int word_end = 0; + int word_start = 0; + int cursor_pos = 0; + int size = 0; + + if (do_init){ + // NOTE(allen): Get the range where the + // partial word is written. + word_end = view.cursor.pos; + word_start = word_end; + cursor_pos = word_end - 1; + + char space[1024]; + Stream_Chunk chunk = {0}; + if (init_stream_chunk(&chunk, app, &buffer, + cursor_pos, space, sizeof(space))){ + int still_looping = true; + do{ + for (; cursor_pos >= chunk.start; --cursor_pos){ + char c = chunk.data[cursor_pos]; + if (char_is_alpha(c)){ + word_start = cursor_pos; + } + else if (!char_is_numeric(c)){ + goto double_break; + } + } + still_looping = backward_stream_chunk(&chunk); + }while(still_looping); + } + double_break:; + + size = word_end - word_start; + + if (size == 0){ + complete_state.initialized = false; + return; + } + + // NOTE(allen): Initialize the search iterator + // with the partial word. + complete_state.initialized = true; + search_iter_init(app, &complete_state.iter, size); + app->buffer_read_range(app, &buffer, word_start, word_end, + complete_state.iter.word.str); + complete_state.iter.word.size = size; + + // NOTE(allen): Initialize the set of ranges + // to be searched. + int buffer_count = app->get_buffer_count(app); + search_set_init(app, &complete_state.set, buffer_count); + + Search_Range *ranges = complete_state.set.ranges; + ranges[0].type = SearchRange_Wave; + ranges[0].buffer = buffer.buffer_id; + ranges[0].start = 0; + ranges[0].size = buffer.size; + ranges[0].mid_start = word_start; + ranges[0].mid_size = size; + + int j = 1; + for (Buffer_Summary buffer_it = app->get_buffer_first(app, AccessAll); + buffer_it.exists; + app->get_buffer_next(app, &buffer_it, AccessAll)){ + if (buffer.buffer_id != buffer_it.buffer_id){ + ranges[j].type = SearchRange_FrontToBack; + ranges[j].buffer = buffer_it.buffer_id; + ranges[j].start = 0; + ranges[j].size = buffer_it.size; + ++j; + } + } + complete_state.set.count = j; + + // NOTE(allen): Initialize the search hit table. + search_hits_init(app, &complete_state.hits, &complete_state.str, + 100, (4 << 10)); + search_hit_add(app, &complete_state.hits, &complete_state.str, + complete_state.iter.word.str, + complete_state.iter.word.size); + + complete_state.word_start = word_start; + complete_state.word_end = word_end; + } + else{ + word_start = complete_state.word_start; + word_end = complete_state.word_end; + size = complete_state.iter.word.size; + } + + // NOTE(allen): Iterate through matches. + if (size > 0){ + for (;;){ + int match_size = 0; + Search_Match match = + search_next_match(app, &complete_state.set, + &complete_state.iter); + + if (match.found_match){ + int match_size = match.end - match.start; + char *spare = (char*)GET_MEMORY(match_size); + + app->buffer_read_range(app, &match.buffer, + match.start, match.end, spare); + + if (search_hit_add(app, &complete_state.hits, &complete_state.str, + spare, match_size)){ + app->buffer_replace_range(app, &buffer, word_start, word_end, + spare, match_size); + app->view_set_cursor(app, &view, + seek_pos(word_start + match_size), + true); + + complete_state.word_end = word_start + match_size; + complete_state.set.ranges[0].mid_size = match_size; + FREE_MEMORY(spare); + break; + } + FREE_MEMORY(spare); + } + else{ + complete_state.iter.pos = 0; + complete_state.iter.i = 0; + + search_hits_init(app, &complete_state.hits, &complete_state.str, + 100, (4 << 10)); + search_hit_add(app, &complete_state.hits, &complete_state.str, + complete_state.iter.word.str, + complete_state.iter.word.size); + + match_size = complete_state.iter.word.size; + char *str = complete_state.iter.word.str; + app->buffer_replace_range(app, &buffer, word_start, word_end, + str, match_size); + app->view_set_cursor(app, &view, + seek_pos(word_start + match_size), + true); + + complete_state.word_end = word_start + match_size; + complete_state.set.ranges[0].mid_size = match_size; + break; + } + } + } + } +} + +// +// +// + CUSTOM_COMMAND_SIG(execute_arbitrary_command){ // NOTE(allen): This isn't a super powerful version of this command, I will expand // upon it so that it has all the cmdid_* commands by default. However, with this diff --git a/4coder_helper.h b/4coder_helper.h index a7330b6b..c11b5409 100644 --- a/4coder_helper.h +++ b/4coder_helper.h @@ -417,365 +417,13 @@ get_active_buffer(Application_Links *app, unsigned int access){ return(buffer); } - -struct Stream_Chunk{ - Application_Links *app; - Buffer_Summary *buffer; - - char *base_data; - int start, end; - int data_size; - - char *data; -}; - -int -round_down(int x, int b){ - int r = 0; - if (x >= 0){ - r = x - (x % b); - } - return(r); -} - -int -round_up(int x, int b){ - int r = 0; - if (x >= 0){ - r = x - (x % b) + b; - } - return(r); -} - -void -refresh_buffer(Application_Links *app, Buffer_Summary *buffer){ - *buffer = app->get_buffer(app, buffer->buffer_id, AccessAll); -} - -void -refresh_view(Application_Links *app, View_Summary *view){ - *view = app->get_view(app, view->view_id, AccessAll); -} - -int -init_stream_chunk(Stream_Chunk *chunk, - Application_Links *app, Buffer_Summary *buffer, - int pos, char *data, int size){ - int result = 0; - - refresh_buffer(app, buffer); - if (pos >= 0 && pos < buffer->size && size > 0){ - result = 1; - chunk->app = app; - chunk->buffer = buffer; - chunk->base_data = data; - chunk->data_size = size; - chunk->start = round_down(pos, size); - chunk->end = round_up(pos, size); - if (chunk->end > buffer->size){ - chunk->end = buffer->size; - } - app->buffer_read_range(app, buffer, chunk->start, chunk->end, chunk->base_data); - chunk->data = chunk->base_data - chunk->start; - } +inline char +buffer_get_char(Application_Links *app, Buffer_Summary *buffer, int pos){ + char result = 0; + app->buffer_read_range(app, buffer, pos, pos+1, &result); return(result); } -int -forward_stream_chunk(Stream_Chunk *chunk){ - Application_Links *app = chunk->app; - Buffer_Summary *buffer = chunk->buffer; - int result = 0; - - refresh_buffer(app, buffer); - if (chunk->end < buffer->size){ - result = 1; - chunk->start = chunk->end; - chunk->end += chunk->data_size; - if (chunk->end > buffer->size){ - chunk->end = buffer->size; - } - app->buffer_read_range(app, buffer, chunk->start, chunk->end, chunk->base_data); - chunk->data = chunk->base_data - chunk->start; - } - return(result); -} - -int -backward_stream_chunk(Stream_Chunk *chunk){ - Application_Links *app = chunk->app; - Buffer_Summary *buffer = chunk->buffer; - int result = 0; - - refresh_buffer(app, buffer); - if (chunk->start > 0){ - result = 1; - chunk->end = chunk->start; - chunk->start -= chunk->data_size; - if (chunk->start < 0){ - chunk->start = 0; - } - app->buffer_read_range(app, buffer, chunk->start, chunk->end, chunk->base_data); - chunk->data = chunk->base_data - chunk->start; - } - return(result); -} - -void -buffer_seek_delimiter_forward(Application_Links *app, Buffer_Summary *buffer, - int pos, char delim, int *result){ - if (buffer->exists){ - char chunk[1024]; - int size = sizeof(chunk); - Stream_Chunk stream = {0}; - - if (init_stream_chunk(&stream, app, buffer, pos, chunk, size)){ - int still_looping = 1; - do{ - for(; pos < stream.end; ++pos){ - char at_pos = stream.data[pos]; - if (at_pos == delim){ - *result = pos; - goto finished; - } - } - still_looping = forward_stream_chunk(&stream); - }while (still_looping); - } - } - - *result = buffer->size; - - finished:; -} - -void -buffer_seek_delimiter_backward(Application_Links *app, Buffer_Summary *buffer, - int pos, char delim, int *result){ - if (buffer->exists){ - char chunk[1024]; - int size = sizeof(chunk); - Stream_Chunk stream = {0}; - - if (init_stream_chunk(&stream, app, buffer, pos, chunk, size)){ - int still_looping = 1; - do{ - for(; pos >= stream.start; --pos){ - char at_pos = stream.data[pos]; - if (at_pos == delim){ - *result = pos; - goto finished; - } - } - still_looping = backward_stream_chunk(&stream); - }while (still_looping); - } - } - - *result = 0; - - finished:; -} - -// TODO(allen): This duplication is driving me crazy... I've gotta -// upgrade the meta programming system another level. - -// NOTE(allen): This is limitted to a string size of 512. -// You can push it up or do something more clever by just -// replacing char read_buffer[512]; with more memory. -void -buffer_seek_string_forward(Application_Links *app, Buffer_Summary *buffer, - int pos, char *str, int size, int *result){ - char read_buffer[512]; - char chunk[1024]; - int chunk_size = sizeof(chunk); - Stream_Chunk stream = {0}; - - if (size <= 0){ - *result = pos; - } - else if (size > sizeof(read_buffer)){ - *result = pos; - } - else{ - if (buffer->exists){ - String read_str = make_fixed_width_string(read_buffer); - String needle_str = make_string(str, size); - char first_char = str[0]; - - read_str.size = size; - - if (init_stream_chunk(&stream, app, buffer, pos, chunk, chunk_size)){ - int still_looping = 1; - do{ - for(; pos < stream.end; ++pos){ - char at_pos = stream.data[pos]; - if (at_pos == first_char){ - app->buffer_read_range(app, buffer, pos, pos+size, read_buffer); - if (match(needle_str, read_str)){ - *result = pos; - goto finished; - } - } - } - still_looping = forward_stream_chunk(&stream); - }while (still_looping); - } - } - - *result = buffer->size; - - finished:; - } -} - -// NOTE(allen): This is limitted to a string size of 512. -// You can push it up or do something more clever by just -// replacing char read_buffer[512]; with more memory. -void -buffer_seek_string_backward(Application_Links *app, Buffer_Summary *buffer, - int pos, char *str, int size, int *result){ - char read_buffer[512]; - char chunk[1024]; - int chunk_size = sizeof(chunk); - Stream_Chunk stream = {0}; - - if (size <= 0){ - *result = 0; - } - else if (size > sizeof(read_buffer)){ - *result = 0; - } - else{ - if (buffer->exists){ - String read_str = make_fixed_width_string(read_buffer); - String needle_str = make_string(str, size); - char first_char = str[0]; - - read_str.size = size; - - if (init_stream_chunk(&stream, app, buffer, pos, chunk, chunk_size)){ - int still_looping = 1; - do{ - for(; pos >= stream.start; --pos){ - char at_pos = stream.data[pos]; - if (at_pos == first_char){ - app->buffer_read_range(app, buffer, pos, pos+size, read_buffer); - if (match(needle_str, read_str)){ - *result = pos; - goto finished; - } - } - } - still_looping = backward_stream_chunk(&stream); - }while (still_looping); - } - } - - *result = 0; - - finished:; - } -} - -// NOTE(allen): This is limitted to a string size of 512. -// You can push it up or do something more clever by just -// replacing char read_buffer[512]; with more memory. -void -buffer_seek_string_insensitive_forward(Application_Links *app, Buffer_Summary *buffer, - int pos, char *str, int size, int *result){ - char read_buffer[512]; - char chunk[1024]; - int chunk_size = sizeof(chunk); - Stream_Chunk stream = {0}; - - if (size <= 0){ - *result = pos; - } - else if (size > sizeof(read_buffer)){ - *result = pos; - } - else{ - if (buffer->exists){ - String read_str = make_fixed_width_string(read_buffer); - String needle_str = make_string(str, size); - char first_char = char_to_upper(str[0]); - - read_str.size = size; - - if (init_stream_chunk(&stream, app, buffer, pos, chunk, chunk_size)){ - int still_looping = 1; - do{ - for(; pos < stream.end; ++pos){ - char at_pos = char_to_upper(stream.data[pos]); - if (at_pos == first_char){ - app->buffer_read_range(app, buffer, pos, pos+size, read_buffer); - if (match_insensitive(needle_str, read_str)){ - *result = pos; - goto finished; - } - } - } - still_looping = forward_stream_chunk(&stream); - }while (still_looping); - } - } - - *result = buffer->size; - - finished:; - } -} - -// NOTE(allen): This is limitted to a string size of 512. -// You can push it up or do something more clever by just -// replacing char read_buffer[512]; with more memory. -void -buffer_seek_string_insensitive_backward(Application_Links *app, Buffer_Summary *buffer, - int pos, char *str, int size, int *result){ - char read_buffer[512]; - char chunk[1024]; - int chunk_size = sizeof(chunk); - Stream_Chunk stream = {0}; - - if (size <= 0){ - *result = -1; - } - else if (size > sizeof(read_buffer)){ - *result = -1; - } - else{ - if (buffer->exists){ - String read_str = make_fixed_width_string(read_buffer); - String needle_str = make_string(str, size); - char first_char = char_to_upper(str[0]); - - read_str.size = size; - - if (init_stream_chunk(&stream, app, buffer, pos, chunk, chunk_size)){ - int still_looping = 1; - do{ - for(; pos >= stream.start; --pos){ - char at_pos = char_to_upper(stream.data[pos]); - if (at_pos == first_char){ - app->buffer_read_range(app, buffer, pos, pos+size, read_buffer); - if (match_insensitive(needle_str, read_str)){ - *result = pos; - goto finished; - } - } - } - still_looping = backward_stream_chunk(&stream); - }while (still_looping); - } - } - - *result = -1; - - finished:; - } -} - inline Buffer_Identifier buffer_identifier(char *str, int len){ Buffer_Identifier identifier; diff --git a/4coder_mem.h b/4coder_mem.h index 391b7e85..9aa865da 100644 --- a/4coder_mem.h +++ b/4coder_mem.h @@ -72,5 +72,179 @@ end_temp_memory(Temp_Memory temp){ ((Partition*)temp.handle)->pos = temp.pos; } +/* +NOTE(allen): +This is a very week general purpose allocator system. +It should only be used for infrequent large allocations (4K+). +*/ + +#include +#include +#include + +enum{ + MEM_BUBBLE_FLAG_INIT = 0x0, + MEM_BUBBLE_USED = 0x1, +}; + +struct Bubble{ + Bubble *prev; + Bubble *next; + int32_t size; + uint32_t flags; + uint32_t _unused_[2]; +}; + +struct General_Memory{ + Bubble sentinel; +}; + +struct Mem_Options{ + Partition part; + General_Memory general; +}; + +inline void +insert_bubble(Bubble *prev, Bubble *bubble){ + bubble->prev = prev; + bubble->next = prev->next; + bubble->prev->next = bubble; + bubble->next->prev = bubble; +} + +inline void +remove_bubble(Bubble *bubble){ + bubble->prev->next = bubble->next; + bubble->next->prev = bubble->prev; +} + +static void +general_memory_open(General_Memory *general, void *memory, int32_t size){ + general->sentinel.prev = &general->sentinel; + general->sentinel.next = &general->sentinel; + general->sentinel.flags = MEM_BUBBLE_USED; + general->sentinel.size = 0; + + Bubble *first = (Bubble*)memory; + first->flags = (uint32_t)MEM_BUBBLE_FLAG_INIT; + first->size = size - sizeof(Bubble); + insert_bubble(&general->sentinel, first); +} + +static int32_t +general_memory_check(General_Memory *general){ + Bubble *sentinel = &general->sentinel; + for (Bubble *bubble = sentinel->next; + bubble != sentinel; + bubble = bubble->next){ + assert(bubble); + + Bubble *next = bubble->next; + assert(bubble == next->prev); + if (next != sentinel && bubble->prev != sentinel){ + assert(bubble->next > bubble); + assert(bubble > bubble->prev); + + char *end_ptr = (char*)(bubble + 1) + bubble->size; + char *next_ptr = (char*)next; + (void)(end_ptr); + (void)(next_ptr); + assert(end_ptr == next_ptr); + } + } + return(1); +} + +#define BUBBLE_MIN_SIZE 1024 + +static void +general_memory_attempt_split(Bubble *bubble, int32_t wanted_size){ + int32_t remaining_size = bubble->size - wanted_size; + if (remaining_size >= BUBBLE_MIN_SIZE){ + bubble->size = wanted_size; + Bubble *new_bubble = (Bubble*)((char*)(bubble + 1) + wanted_size); + new_bubble->flags = (uint32_t)MEM_BUBBLE_FLAG_INIT; + new_bubble->size = remaining_size - sizeof(Bubble); + insert_bubble(bubble, new_bubble); + } +} + +static void* +general_memory_allocate(General_Memory *general, int32_t size){ + void *result = 0; + for (Bubble *bubble = general->sentinel.next; + bubble != &general->sentinel; + bubble = bubble->next){ + if (!(bubble->flags & MEM_BUBBLE_USED)){ + if (bubble->size >= size){ + result = bubble + 1; + bubble->flags |= MEM_BUBBLE_USED; + general_memory_attempt_split(bubble, size); + break; + } + } + } + return result; +} + +inline void +general_memory_do_merge(Bubble *left, Bubble *right){ + assert(left->next == right); + assert(right->prev == left); + left->size += sizeof(Bubble) + right->size; + remove_bubble(right); +} + +inline void +general_memory_attempt_merge(Bubble *left, Bubble *right){ + if (!(left->flags & MEM_BUBBLE_USED) && + !(right->flags & MEM_BUBBLE_USED)){ + general_memory_do_merge(left, right); + } +} + +static void +general_memory_free(General_Memory *general, void *memory){ + Bubble *bubble = ((Bubble*)memory) - 1; + bubble->flags &= ~MEM_BUBBLE_USED; + Bubble *prev, *next; + prev = bubble->prev; + next = bubble->next; + general_memory_attempt_merge(bubble, next); + general_memory_attempt_merge(prev, bubble); +} + +static void* +general_memory_reallocate(General_Memory *general, void *old, int32_t old_size, int32_t size){ + void *result = old; + Bubble *bubble = ((Bubble*)old) - 1; + int32_t additional_space = size - bubble->size; + if (additional_space > 0){ + Bubble *next = bubble->next; + if (!(next->flags & MEM_BUBBLE_USED) && + next->size + sizeof(Bubble) >= additional_space){ + general_memory_do_merge(bubble, next); + general_memory_attempt_split(bubble, size); + } + else{ + result = general_memory_allocate(general, size); + if (old_size) memcpy(result, old, old_size); + general_memory_free(general, old); + } + } + return result; +} + +inline void* +general_memory_reallocate_nocopy(General_Memory *general, void *old, int32_t size){ + return general_memory_reallocate(general, old, 0, size); +} + +#define reset_temp_memory end_temp_memory + +#define gen_struct(g, T) (T*)general_memory_allocate(g, sizeof(T), 0) +#define gen_array(g, T, size) (T*)general_memory_allocate(g, sizeof(T)*(size)) +#define gen_block(g, size) general_memory_open(g, size, 0) + #endif diff --git a/4coder_search.cpp b/4coder_search.cpp new file mode 100644 index 00000000..94ec9206 --- /dev/null +++ b/4coder_search.cpp @@ -0,0 +1,406 @@ + +#ifndef FCODER_SEARCH +#define FCODER_SEARCH + +enum Search_Range_Type{ + SearchRange_FrontToBack, + SearchRange_BackToFront, + SearchRange_Wave, +}; + +struct Search_Range{ + int type; + int buffer; + int start; + int size; + int mid_start; + int mid_size; +}; + +struct Search_Set{ + Search_Range *ranges; + int count; + int max; +}; + +struct Search_Iter{ + String word; + int pos; + int back_pos; + int i; + int range_initialized; +}; + +struct Search_Match{ + Buffer_Summary buffer; + int start; + int end; + int found_match; +}; + +// TODO(allen): HOW DO I WANT TO GET MEMORY CUSTOM SIDE?? +#define GET_MEMORY(a) (void*)(0) +#define REGET_MEMORY(a,b) (void*)(0) +#define REGET_NOCOPY_MEMORY(a,b) (void*)(0) +#define FREE_MEMORY(a) (void)(a) + +static void +search_iter_init(Application_Links *app, Search_Iter *iter, int size){ + int str_max = size*2; + if (iter->word.str == 0){ + iter->word.str = (char*)GET_MEMORY(str_max); + iter->word.memory_size = str_max; + } + else if (iter->word.memory_size < size){ + iter->word.str = (char*)REGET_MEMORY(iter->word.str, str_max); + iter->word.memory_size = str_max; + } + + iter->i = 0; + iter->pos = 0; +} + +static void +search_set_init(Application_Links *app, Search_Set *set, int range_count){ + int max = range_count*2; + + if (set->ranges == 0){ + set->ranges = (Search_Range*)GET_MEMORY(sizeof(Search_Range)*max); + set->max = max; + } + else if (set->max < range_count){ + set->ranges = (Search_Range*)REGET_MEMORY(set->ranges, sizeof(Search_Range)*max); + set->max = max; + } + + set->count = range_count; +} + +static void +search_hits_table_alloc(Application_Links *app, Table *hits, int table_size){ + void *mem = 0; + int mem_size = table_required_mem_size(table_size, sizeof(Offset_String)); + if (hits->hash_array == 0){ + mem = GET_MEMORY(mem_sze); + } + else{ + mem = REGET_NOCOPY_MEMORY(hits->hash_array, mem_sze); + } + table_init_memory(hits, mem, table_size, sizeof(Offset_String)); +} + +static void +search_hits_init(Application_Links *app, Table *hits, String_Space *str, int table_size, int str_size){ + if (hits->hash_array == 0){ + search_hits_table_alloc(app, hits, table_size); + } + else{ + int mem_size = table_required_mem_size(table_size, sizeof(Offset_String)); + void *mem = REGET_NOCOPY_MEMORY(mem, mem_size); + table_init_memory(hits, mem, table_size, sizeof(Offset_String)); + } + + if (str->space == 0){ + str->space = (char*)GET_MEMORY(str_size); + str->max = str_size; + } + else if (str->max < str_size){ + str->space = (char*)REGET_NOCOPY_MEMORY(str->space, str_size); + str->max = str_size; + } + + str->pos = str->new_pos = 0; + table_clear(hits); +} + +static int +search_hit_add(Application_Links *app, Table *hits, String_Space *space, char *str, int len){ + int result = false; + + assert(len != 0); + + Offset_String ostring = strspace_append(space, str, len); + if (ostring.size == 0){ + int new_size = space->max*2; + if (new_size < space->max + len){ + new_size = space->max + len; + } + space->space = (char*)REGET_MEMORY(space->space, new_size); + ostring = strspace_append(space, str, len); + } + + assert(ostring.size != 0); + + if (table_at_capacity(hits)){ + Table new_hits = {0}; + search_hits_table_alloc(app, &new_hits, hits->max*2); + table_clear(&new_hits); + table_rehash(hits, &new_hits, space->space, tbl_offset_string_hash, tbl_offset_string_compare); + FREE_MEMORY(hits->hash_array); + *hits = new_hits; + } + + if (!table_add(hits, &ostring, space->space, tbl_offset_string_hash, tbl_offset_string_compare)){ + result = true; + strspace_keep_prev(space); + } + else{ + strspace_discard_prev(space); + } + + return(result); +} + +static int +buffer_seek_alpha_numeric_end(Application_Links *app, Buffer_Summary *buffer, int pos){ + char space[1024]; + Stream_Chunk chunk = {0}; + if (init_stream_chunk(&chunk, app, buffer, pos, space, sizeof(space))){ + int still_looping = true; + do{ + for (; pos < chunk.end; ++pos){ + char at_pos = chunk.data[pos]; + if (!char_is_alpha_numeric(at_pos)) goto double_break; + } + still_looping = forward_stream_chunk(&chunk); + }while(still_looping); + } + double_break:; + return(pos); +} + +static void +search_iter_next_range(Search_Iter *it){ + ++it->i; + it->pos = 0; + it->back_pos = 0; + it->range_initialized = 0; +} + +enum{ + FindResult_None, + FindResult_FoundMatch, + FindResult_PastEnd +}; + +static int +search_front_to_back_step(Application_Links *app, + Search_Range *range, + String word, + int *pos, + Search_Match *result_ptr){ + int found_match = FindResult_None; + + Search_Match result = *result_ptr; + + int end_pos = range->start + range->size; + if (*pos + word.size < end_pos){ + int start_pos = *pos; + if (start_pos < range->start){ + start_pos = range->start; + } + + result.buffer = app->get_buffer(app, range->buffer, AccessAll); + buffer_seek_string_forward(app, &result.buffer, + start_pos, end_pos, + word.str, word.size, + &result.start); + + if (result.start < end_pos){ + *pos = result.start + 1; + char prev = ' '; + if (result.start > 0){ + prev = buffer_get_char(app, &result.buffer, result.start - 1); + } + if (!char_is_alpha_numeric(prev)){ + result.end = + buffer_seek_alpha_numeric_end( + app, &result.buffer, result.start); + + if (result.end < end_pos){ + result.found_match = true; + *pos = result.end; + found_match = FindResult_FoundMatch; + } + } + } + else{ + found_match = FindResult_PastEnd; + } + } + else{ + found_match = FindResult_PastEnd; + } + + *result_ptr = result; + + return(found_match); +} + +static int +search_back_to_front_step(Application_Links *app, + Search_Range *range, + String word, + int *pos, + Search_Match *result_ptr){ + int found_match = FindResult_None; + + Search_Match result = *result_ptr; + + int end_pos = range->start + range->size; + if (*pos > range->start){ + int start_pos = *pos; + + result.buffer = app->get_buffer(app, range->buffer, AccessAll); + buffer_seek_string_backward(app, &result.buffer, + start_pos, range->start, + word.str, word.size, + &result.start); + + if (result.start >= range->start){ + *pos = result.start - 1; + char prev = ' '; + if (result.start > 0){ + prev = buffer_get_char(app, &result.buffer, result.start - 1); + } + if (!char_is_alpha_numeric(prev)){ + result.end = + buffer_seek_alpha_numeric_end( + app, &result.buffer, result.start); + + if (result.end < end_pos){ + result.found_match = true; + *pos = result.start - word.size; + found_match = FindResult_FoundMatch; + } + } + } + else{ + found_match = FindResult_PastEnd; + } + } + else{ + found_match = FindResult_PastEnd; + } + + *result_ptr = result; + + return(found_match); +} + +static Search_Match +search_next_match(Application_Links *app, Search_Set *set, Search_Iter *it_ptr){ + Search_Match result = {0}; + Search_Iter iter = *it_ptr; + + char *spare = (char*)GET_MEMORY(iter.word.size); + + int count = set->count; + for (; iter.i < count;){ + Search_Range *range = set->ranges + iter.i; + + int find_result = FindResult_None; + + if (!iter.range_initialized){ + iter.range_initialized = true; + switch (range->type){ + case SearchRange_BackToFront: + { + iter.back_pos = range->start+range->size-1; + }break; + + case SearchRange_Wave: + { + iter.back_pos = range->mid_start-1; + iter.pos = range->mid_start + range->mid_size; + }break; + } + } + + switch (range->type){ + case SearchRange_FrontToBack: + { + find_result = + search_front_to_back_step(app, range, + iter.word, + &iter.pos, + &result); + }break; + + case SearchRange_BackToFront: + { + find_result = + search_back_to_front_step(app, range, + iter.word, + &iter.back_pos, + &result); + }break; + + case SearchRange_Wave: + { + Search_Match forward_match = {0}; + int forward_result = + search_front_to_back_step(app, range, + iter.word, + &iter.pos, + &forward_match); + + Search_Match backward_match = {0}; + int backward_result = + search_back_to_front_step(app, range, + iter.word, + &iter.back_pos, + &backward_match); + + if (forward_result == FindResult_FoundMatch){ + if (backward_result == FindResult_FoundMatch){ + find_result = FindResult_FoundMatch; + + int forward_start = range->mid_start + range->mid_size; + int forward_distance = (forward_match.start - forward_start); + int backward_distance = (forward_match.end - range->mid_start); + + if (backward_distance < forward_distance){ + --iter.pos; + result = forward_match; + } + else{ + ++iter.back_pos; + result = backward_match; + } + } + else{ + find_result = FindResult_FoundMatch; + result = forward_match; + } + } + else{ + if (backward_result == FindResult_FoundMatch){ + find_result = FindResult_FoundMatch; + result = backward_match; + --iter.pos; + } + else{ + find_result = FindResult_PastEnd; + } + } + }break; + } + + if (find_result == FindResult_FoundMatch){ + goto double_break; + } + else if (find_result == FindResult_PastEnd){ + search_iter_next_range(&iter); + } + } + double_break:; + + FREE_MEMORY(spare); + + *it_ptr = iter; + + return(result); +} + +#endif diff --git a/4tech_table.cpp b/4coder_table.cpp similarity index 63% rename from 4tech_table.cpp rename to 4coder_table.cpp index c1e47932..0a7ec22a 100644 --- a/4tech_table.cpp +++ b/4coder_table.cpp @@ -3,7 +3,7 @@ * * 14.02.2016 * - * 4tech C style genereic hash table + * C style genereic hash table * */ @@ -13,57 +13,57 @@ #define TableHashDeleted 1 #define TableHashMin 0x10000000 -typedef u32 Hash_Function(void *item, void *arg); -typedef i32 Compare_Function(void *key, void *item, void *arg); +#include +#include +#include + +typedef uint32_t Hash_Function(void *item, void *arg); +typedef int32_t Compare_Function(void *key, void *item, void *arg); struct Table{ - u32 *hash_array; - u8 *data_array; - i32 count, max; - i32 item_size; + uint32_t *hash_array; + char *data_array; + int32_t count, max; + int32_t item_size; }; -internal i32 -table_required_mem_size(i32 table_size, i32 item_size){ - i32 mem_size, hash_size; - hash_size = ((table_size * sizeof(u32)) + 7) & ~7; - mem_size = hash_size + table_size * item_size; +static int32_t +table_required_mem_size(int32_t table_size, int32_t item_size){ + int32_t hash_size = ((table_size * sizeof(uint32_t)) + 7) & ~7; + int32_t mem_size = hash_size + table_size * item_size; return(mem_size); } -internal void -table_init_memory(Table *table, void *memory, i32 table_size, i32 item_size){ - i32 hash_size = table_size * sizeof(u32); +static void +table_init_memory(Table *table, void *memory, int32_t table_size, int32_t item_size){ + int32_t hash_size = table_size * sizeof(uint32_t); hash_size = (hash_size + 7) & ~7; - table->hash_array = (u32*)memory; - table->data_array = (u8*)(table->hash_array) + hash_size; + table->hash_array = (uint32_t*)memory; + table->data_array = (char*)(table->hash_array) + hash_size; table->count = 0; table->max = table_size; table->item_size = item_size; } -internal b32 +static int32_t table_at_capacity(Table *table){ - b32 result = 1; + int32_t result = true; if (table->count * 8 < table->max * 7){ - result = 0; + result = false; } return(result); } -internal b32 +static int32_t table_add(Table *table, void *item, void *arg, Hash_Function *hash_func, Compare_Function *comp_func){ - u32 hash, *inspect; - i32 i, start; + assert(table->count * 8 < table->max * 7); - Assert(table->count * 8 < table->max * 7); - - hash = (hash_func(item, arg) | TableHashMin); - i = hash % table->max; - start = i; - inspect = table->hash_array + i; + uint32_t hash = (hash_func(item, arg) | TableHashMin); + int32_t i = hash % table->max; + int32_t start = i; + uint32_t *inspect = table->hash_array + i; while (*inspect >= TableHashMin){ if (*inspect == hash){ @@ -77,7 +77,7 @@ table_add(Table *table, void *item, void *arg, Hash_Function *hash_func, Compare i = 0; inspect = table->hash_array; } - Assert(i != start); + assert(i != start); } *inspect = hash; memcpy(table->data_array + i*table->item_size, item, table->item_size); @@ -86,17 +86,14 @@ table_add(Table *table, void *item, void *arg, Hash_Function *hash_func, Compare return(0); } -internal b32 -table_find_pos(Table *table, void *search_key, void *arg, i32 *pos, i32 *index, Hash_Function *hash_func, Compare_Function *comp_func){ - u32 hash, *inspect; - i32 i, start; +static int32_t +table_find_pos(Table *table, void *search_key, void *arg, int32_t *pos, int32_t *index, Hash_Function *hash_func, Compare_Function *comp_func){ + assert((table->count - 1) * 8 < table->max * 7); - Assert((table->count - 1) * 8 < table->max * 7); - - hash = (hash_func(search_key, arg) | TableHashMin); - i = hash % table->max; - start = i; - inspect = table->hash_array + i; + uint32_t hash = (hash_func(search_key, arg) | TableHashMin); + int32_t i = hash % table->max; + int32_t start = i; + uint32_t *inspect = table->hash_array + i; while (*inspect != TableHashEmpty){ if (*inspect == hash){ @@ -120,8 +117,8 @@ table_find_pos(Table *table, void *search_key, void *arg, i32 *pos, i32 *index, inline void* table_find_item(Table *table, void *search_key, void *arg, Hash_Function *hash_func, Compare_Function *comp_func){ - i32 pos; void *result = 0; + int32_t pos; if (table_find_pos(table, search_key, arg, &pos, 0, hash_func, comp_func)){ result = table->data_array + pos; } @@ -129,18 +126,18 @@ table_find_item(Table *table, void *search_key, void *arg, Hash_Function *hash_f } inline void -table_remove_index(Table *table, i32 index){ +table_remove_index(Table *table, int32_t index){ table->hash_array[index] = TableHashDeleted; --table->count; } -inline b32 +inline int32_t table_remove_match(Table *table, void *search_key, void *arg, Hash_Function *hash_func, Compare_Function *comp_func){ - i32 index; - b32 result = 0; + int32_t result = false; + int32_t index; if (table_find_pos(table, search_key, arg, 0, &index, hash_func, comp_func)){ table_remove_index(table, index); - result = 1; + result = true; } return(result); } @@ -151,20 +148,18 @@ table_clear(Table *table){ memset(table->hash_array, 0, table->max*sizeof(*table->hash_array)); } -internal void +static void table_rehash(Table *src, Table *dst, void *arg, Hash_Function *hash_func, Compare_Function *comp_func){ - i32 i, c, count, item_size; - u32 *hash_item; - u8 *data_item; + assert((dst->count + src->count - 1) * 7 < dst->max * 8); + assert(dst->item_size == src->item_size); - Assert((dst->count + src->count - 1) * 7 < dst->max * 8); - Assert(dst->item_size == src->item_size); - - count = src->count; - hash_item = src->hash_array; - data_item = src->data_array; - item_size = src->item_size; - for (i = 0, c = 0; c < count; ++i, ++hash_item, data_item += item_size){ + int32_t count = src->count; + int32_t item_size = src->item_size; + uint32_t *hash_item = src->hash_array; + char *data_item = src->data_array; + for (int32_t i = 0, c = 0; + c < count; + ++i, ++hash_item, data_item += item_size){ if (*hash_item >= TableHashMin){ ++c; table_add(dst, data_item, arg, hash_func, comp_func); @@ -172,12 +167,12 @@ table_rehash(Table *src, Table *dst, void *arg, Hash_Function *hash_func, Compar } } -internal u32 +static uint32_t tbl_string_hash(void *item, void *arg){ String *string = (String*)item; char *str; - i32 i,len; - u32 x = 5381; + int32_t i,len; + uint32_t x = 5381; char c; (void)arg; @@ -192,20 +187,20 @@ tbl_string_hash(void *item, void *arg){ return(x); } -internal i32 +static int32_t tbl_string_compare(void *a, void *b, void *arg){ String *stra = (String*)a; String *strb = (String*)b; - i32 result = !match(*stra, *strb); + int32_t result = !match(*stra, *strb); return(result); } -internal u32 +static uint32_t tbl_offset_string_hash(void *item, void *arg){ Offset_String *string = (Offset_String*)item; char *str; - i32 i,len; - u32 x = 5381; + int32_t i,len; + uint32_t x = 5381; char c; str = ((char*)arg) + string->offset; @@ -219,23 +214,23 @@ tbl_offset_string_hash(void *item, void *arg){ return(x); } -internal i32 +static int32_t tbl_offset_string_compare(void *a, void *b, void *arg){ Offset_String *ostra = (Offset_String*)a; Offset_String *ostrb = (Offset_String*)b; String stra = make_string((char*)arg + ostra->offset, ostra->size); String strb = make_string((char*)arg + ostrb->offset, ostrb->size); - i32 result = !match(stra, strb); + int32_t result = !match(stra, strb); return(result); } struct String_Space{ char *space; - i32 pos, new_pos, max; + int32_t pos, new_pos, max; }; -internal Offset_String -strspace_append(String_Space *space, char *str, i32 len){ +static Offset_String +strspace_append(String_Space *space, char *str, int32_t len){ Offset_String result = {}; if (space->new_pos + len <= space->max){ result.offset = space->new_pos; @@ -247,12 +242,12 @@ strspace_append(String_Space *space, char *str, i32 len){ return(result); } -internal void +static void strspace_keep_prev(String_Space *space){ space->pos = space->new_pos; } -internal void +static void strspace_discard_prev(String_Space *space){ space->new_pos = space->pos; } diff --git a/4coder_types.h b/4coder_types.h index 2920fd34..d3e6f7ff 100644 --- a/4coder_types.h +++ b/4coder_types.h @@ -98,6 +98,16 @@ ENUM(uint64_t, Command_ID){ cmdid_count }; +/* DOC(TODO) */ +FLAGENUM(Memory_Protect_Flags){ + /* DOC(TODO) */ + MemProtect_Read = 0x1, + /* DOC(TODO) */ + MemProtect_Write = 0x2, + /* DOC(TODO) */ + MemProtect_Execute = 0x4, +}; + /* DOC(User_Input_Type_ID specifies a type of user input event.) */ ENUM(int32_t, User_Input_Type_ID){ /* DOC(UserInputNone indicates that no event has occurred.) */ diff --git a/4ed.cpp b/4ed.cpp index 16188de9..6e9dacce 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -472,6 +472,7 @@ COMMAND_DECL(word_complete){ complete_state->word_end = word_start + match_size; complete_state->set.ranges[1].start = word_start + match_size; + end_temp_memory(temp); break; } end_temp_memory(temp); diff --git a/4ed_api_implementation.cpp b/4ed_api_implementation.cpp index 51a1c5b7..ac98f6c8 100644 --- a/4ed_api_implementation.cpp +++ b/4ed_api_implementation.cpp @@ -338,6 +338,28 @@ DOC_SEE(Command_Line_Input_Flag) return(result); } +API_EXPORT void* +Memory_Alloc(Application_Links *app, int32_t size)/* +DOC(TODO) +*/{ + void *result = 0; + return(result); +} + +API_EXPORT int32_t +Memory_Set_Protection(Application_Links *app, void *ptr, int32_t size, Memory_Protect_Flags flags)/* +DOC(TODO) +*/{ + int32_t result = 0; + return(result); +} + +API_EXPORT void +Memory_Free(Application_Links *app, void *mem)/* +DOC(TODO) +*/{ +} + API_EXPORT void Clipboard_Post(Application_Links *app, int32_t clipboard_id, char *str, int32_t len)/* DOC_PARAM(clipboard_id, This parameter is set up to prepare for future features, it should always be 0 for now.) @@ -405,6 +427,16 @@ DOC_SEE(The_4coder_Clipboard) return(size); } +API_EXPORT int32_t +Get_Buffer_Count(Application_Links *app)/* +DOC(TODO) +*/{ + Command_Data *cmd = (Command_Data*)app->cmd_context; + Working_Set *working_set = &cmd->models->working_set; + int32_t result = working_set->file_count; + return(result); +} + internal void internal_get_buffer_first(Working_Set *working_set, Buffer_Summary *buffer){ if (working_set->file_count > 0){ @@ -710,7 +742,7 @@ DOC_PARAM(edits, This parameter provides about the source string and destination 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() +DOC(TODO) DOC_SEE(Buffer_Edit) DOC_SEE(Buffer_Batch_Edit_Type) */{ diff --git a/4ed_app_target.cpp b/4ed_app_target.cpp index 77ef2693..ee787c2e 100644 --- a/4ed_app_target.cpp +++ b/4ed_app_target.cpp @@ -19,14 +19,13 @@ #define FSTRING_IMPLEMENTATION #include "4coder_string.h" -#include "4ed_mem.cpp" #include "4ed_math.cpp" #include "4ed_system.h" #include "4ed_rendering.h" #include "4ed.h" -#include "4tech_table.cpp" +#include "4coder_table.cpp" #define FCPP_LEXER_IMPLEMENTATION //#include "test/4cpp_new_lexer.h" diff --git a/4ed_file.cpp b/4ed_file.cpp index 8b9685c0..00e0f160 100644 --- a/4ed_file.cpp +++ b/4ed_file.cpp @@ -528,7 +528,7 @@ working_set_init(Working_Set *working_set, Partition *partition, General_Memory table_size = working_set->file_max; mem_size = table_required_mem_size(table_size, item_size); - mem = general_memory_allocate(general, mem_size, 0); + mem = general_memory_allocate(general, mem_size); memset(mem, 0, mem_size); table_init_memory(&working_set->table, mem, table_size, item_size); } @@ -542,7 +542,7 @@ working_set__grow_if_needed(Table *table, General_Memory *general, void *arg, Ha if (table_at_capacity(table)){ new_max = table->max * 2; mem_size = table_required_mem_size(new_max, table->item_size); - mem = general_memory_allocate(general, mem_size, 0); + mem = general_memory_allocate(general, mem_size); table_init_memory(&btable, mem, new_max, table->item_size); table_clear(&btable); table_rehash(table, &btable, 0, hash_func, comp_func); diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index cd844c29..3702b307 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -848,7 +848,7 @@ file_save(System_Functions *system, Mem_Options *mem, Editing_File *file, char * if (!data){ used_general = 1; - data = (char*)general_memory_allocate(&mem->general, max, 0); + data = (char*)general_memory_allocate(&mem->general, max); } } Assert(data); @@ -885,23 +885,12 @@ file_save_and_set_names(System_Functions *system, Mem_Options *mem, return result; } -enum File_Bubble_Type{ - BUBBLE_BUFFER = 1, - BUBBLE_STARTS, - BUBBLE_WIDTHS, - BUBBLE_WRAPS, - BUBBLE_TOKENS, - BUBBLE_UNDO_STRING, - BUBBLE_UNDO, - BUBBLE_UNDO_CHILDREN, - // - FILE_BUBBLE_TYPE_END, +enum{ + GROW_FAILED, + GROW_NOT_NEEDED, + GROW_SUCCESS, }; -#define GROW_FAILED 0 -#define GROW_NOT_NEEDED 1 -#define GROW_SUCCESS 2 - internal i32 file_grow_starts_widths_as_needed(General_Memory *general, Buffer_Type *buffer, i32 additional_lines){ b32 result = GROW_NOT_NEEDED; @@ -915,11 +904,11 @@ file_grow_starts_widths_as_needed(General_Memory *general, Buffer_Type *buffer, f32 *new_widths = (f32*)general_memory_reallocate( general, buffer->line_widths, - sizeof(f32)*count, sizeof(f32)*max, BUBBLE_WIDTHS); + sizeof(f32)*count, sizeof(f32)*max); i32 *new_lines = (i32*)general_memory_reallocate( general, buffer->line_starts, - sizeof(i32)*count, sizeof(i32)*max, BUBBLE_STARTS); + sizeof(i32)*count, sizeof(i32)*max); if (new_lines){ buffer->line_starts = new_lines; @@ -945,13 +934,13 @@ file_measure_starts_widths(System_Functions *system, General_Memory *general, Buffer_Type *buffer, float *advance_data){ if (!buffer->line_starts){ i32 max = buffer->line_max = Kbytes(1); - buffer->line_starts = (i32*)general_memory_allocate(general, max*sizeof(i32), BUBBLE_STARTS); + buffer->line_starts = (i32*)general_memory_allocate(general, max*sizeof(i32)); TentativeAssert(buffer->line_starts); // TODO(allen): when unable to allocate? } if (!buffer->line_widths){ i32 max = buffer->widths_max = Kbytes(1); - buffer->line_widths = (f32*)general_memory_allocate(general, max*sizeof(f32), BUBBLE_WIDTHS); + buffer->line_widths = (f32*)general_memory_allocate(general, max*sizeof(f32)); TentativeAssert(buffer->line_starts); // TODO(allen): when unable to allocate? } @@ -964,7 +953,7 @@ file_measure_starts_widths(System_Functions *system, General_Memory *general, { i32 *new_lines = (i32*)general_memory_reallocate( - general, buffer->line_starts, sizeof(i32)*count, sizeof(i32)*max, BUBBLE_STARTS); + general, buffer->line_starts, sizeof(i32)*count, sizeof(i32)*max); // TODO(allen): when unable to grow? TentativeAssert(new_lines); @@ -975,7 +964,7 @@ file_measure_starts_widths(System_Functions *system, General_Memory *general, { f32 *new_lines = (f32*) general_memory_reallocate(general, buffer->line_widths, - sizeof(f32)*count, sizeof(f32)*max, BUBBLE_WIDTHS); + sizeof(f32)*count, sizeof(f32)*max); // TODO(allen): when unable to grow? TentativeAssert(new_lines); @@ -999,11 +988,11 @@ view_measure_wraps(General_Memory *general, View *view){ i32 max = view->file_data.line_max = LargeRoundUp(line_count, Kbytes(1)); if (view->file_data.line_wrap_y){ view->file_data.line_wrap_y = (f32*) - general_memory_reallocate_nocopy(general, view->file_data.line_wrap_y, sizeof(f32)*max, BUBBLE_WRAPS); + general_memory_reallocate_nocopy(general, view->file_data.line_wrap_y, sizeof(f32)*max); } else{ view->file_data.line_wrap_y = (f32*) - general_memory_allocate(general, sizeof(f32)*max, BUBBLE_WRAPS); + general_memory_allocate(general, sizeof(f32)*max); } } @@ -1033,7 +1022,7 @@ file_create_from_string(System_Functions *system, Models *models, page_size = buffer_init_page_size(&init); page_size = LargeRoundUp(page_size, Kbytes(4)); if (page_size < Kbytes(4)) page_size = Kbytes(4); - void *data = general_memory_allocate(general, page_size, BUBBLE_BUFFER); + void *data = general_memory_allocate(general, page_size); buffer_init_provide_page(&init, data, page_size); } @@ -1064,24 +1053,24 @@ file_create_from_string(System_Functions *system, Models *models, // TODO(allen): Redo undo system (if you don't mind the pun) i32 request_size = Kbytes(64); file->state.undo.undo.max = request_size; - file->state.undo.undo.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); + file->state.undo.undo.strings = (u8*)general_memory_allocate(general, request_size); file->state.undo.undo.edit_max = request_size / sizeof(Edit_Step); - file->state.undo.undo.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO); + file->state.undo.undo.edits = (Edit_Step*)general_memory_allocate(general, request_size); file->state.undo.redo.max = request_size; - file->state.undo.redo.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); + file->state.undo.redo.strings = (u8*)general_memory_allocate(general, request_size); file->state.undo.redo.edit_max = request_size / sizeof(Edit_Step); - file->state.undo.redo.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO); + file->state.undo.redo.edits = (Edit_Step*)general_memory_allocate(general, request_size); file->state.undo.history.max = request_size; - file->state.undo.history.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); + file->state.undo.history.strings = (u8*)general_memory_allocate(general, request_size); file->state.undo.history.edit_max = request_size / sizeof(Edit_Step); - file->state.undo.history.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO); + file->state.undo.history.edits = (Edit_Step*)general_memory_allocate(general, request_size); file->state.undo.children.max = request_size; - file->state.undo.children.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); + file->state.undo.children.strings = (u8*)general_memory_allocate(general, request_size); file->state.undo.children.edit_max = request_size / sizeof(Buffer_Edit); - file->state.undo.children.edits = (Buffer_Edit*)general_memory_allocate(general, request_size, BUBBLE_UNDO); + file->state.undo.children.edits = (Buffer_Edit*)general_memory_allocate(general, request_size); file->state.undo.history_block_count = 1; file->state.undo.history_head_block = 0; @@ -1253,7 +1242,7 @@ Job_Callback_Sig(job_full_lex){ { Assert(file->state.swap_stack.tokens == 0); file->state.swap_stack.tokens = (Cpp_Token*) - general_memory_allocate(general, new_max*sizeof(Cpp_Token), BUBBLE_TOKENS); + general_memory_allocate(general, new_max*sizeof(Cpp_Token)); } system->release_lock(FRAME_LOCK); @@ -1368,7 +1357,7 @@ file_relex_parallel(System_Functions *system, stack->tokens = (Cpp_Token*) general_memory_reallocate(general, stack->tokens, stack->count*sizeof(Cpp_Token), - new_max*sizeof(Cpp_Token), BUBBLE_TOKENS); + new_max*sizeof(Cpp_Token)); stack->max_count = new_max; } @@ -2109,7 +2098,7 @@ file_do_single_edit(System_Functions *system, part->base + part->pos, scratch_size, &request_amount)){ void *new_data = 0; if (request_amount > 0){ - new_data = general_memory_allocate(general, request_amount, BUBBLE_BUFFER); + new_data = general_memory_allocate(general, request_amount); } void *old_data = buffer_edit_provide_memory(&file->state.buffer, new_data, request_amount); if (old_data) general_memory_free(general, old_data); @@ -2185,7 +2174,7 @@ file_do_white_batch_edit(System_Functions *system, Models *models, Editing_File scratch_size, &request_amount)){ void *new_data = 0; if (request_amount > 0){ - new_data = general_memory_allocate(general, request_amount, BUBBLE_BUFFER); + new_data = general_memory_allocate(general, request_amount); } void *old_data = buffer_edit_provide_memory(&file->state.buffer, new_data, request_amount); if (old_data) general_memory_free(general, old_data); @@ -2258,6 +2247,7 @@ file_clear(System_Functions *system, Models *models, Editing_File *file){ file_replace_range(system, models, file, 0, buffer_size(&file->state.buffer), 0, 0); } +// TODO(allen): get rid of this inline void view_replace_range(System_Functions *system, Models *models, View *view, i32 start, i32 end, char *str, i32 len){ @@ -3116,6 +3106,17 @@ view_show_file(View *view){ } } + +internal String +make_string_terminated(Partition *part, char *str, i32 len){ + char *space = (char*)push_array(part, char, len + 1); + String string = make_string(str, len, len+1); + copy_fast_unsafe(space, string); + string.str = space; + terminate_with_null(&string); + return(string); +} + internal void view_save_file(System_Functions *system, Models *models, Editing_File *file, View *view, String filename, b32 save_as){ @@ -4774,8 +4775,6 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su append_int_to_str(&string, bubble->size); append_padding(&string, ' ', 40); - append(&string, " type: "); - append_int_to_str(&string, bubble->type); gui_do_text_field(target, string, empty_str); } }break; @@ -6011,12 +6010,12 @@ search_iter_init(General_Memory *general, Search_Iter *iter, i32 size){ if (iter->word.str == 0){ str_max = size*2; - iter->word.str = (char*)general_memory_allocate(general, str_max, 0); + iter->word.str = (char*)general_memory_allocate(general, str_max); iter->word.memory_size = str_max; } else if (iter->word.memory_size < size){ str_max = size*2; - iter->word.str = (char*)general_memory_reallocate_nocopy(general, iter->word.str, str_max, 0); + iter->word.str = (char*)general_memory_reallocate_nocopy(general, iter->word.str, str_max); iter->word.memory_size = str_max; } @@ -6030,13 +6029,13 @@ search_set_init(General_Memory *general, Search_Set *set, i32 set_count){ if (set->ranges == 0){ max = set_count*2; - set->ranges = (Search_Range*)general_memory_allocate(general, sizeof(Search_Range)*max, 0); + set->ranges = (Search_Range*)general_memory_allocate(general, sizeof(Search_Range)*max); set->max = max; } else if (set->max < set_count){ max = set_count*2; set->ranges = (Search_Range*)general_memory_reallocate_nocopy( - general, set->ranges, sizeof(Search_Range)*max, 0); + general, set->ranges, sizeof(Search_Range)*max); set->max = max; } @@ -6050,10 +6049,10 @@ search_hits_table_alloc(General_Memory *general, Table *hits, i32 table_size){ mem_size = table_required_mem_size(table_size, sizeof(Offset_String)); if (hits->hash_array == 0){ - mem = general_memory_allocate(general, mem_size, 0); + mem = general_memory_allocate(general, mem_size); } else{ - mem = general_memory_reallocate_nocopy(general, hits->hash_array, mem_size, 0); + mem = general_memory_reallocate_nocopy(general, hits->hash_array, mem_size); } table_init_memory(hits, mem, table_size, sizeof(Offset_String)); } @@ -6068,16 +6067,16 @@ search_hits_init(General_Memory *general, Table *hits, String_Space *str, i32 ta } else if (hits->max < table_size){ mem_size = table_required_mem_size(table_size, sizeof(Offset_String)); - mem = general_memory_reallocate_nocopy(general, hits->hash_array, mem_size, 0); + mem = general_memory_reallocate_nocopy(general, hits->hash_array, mem_size); table_init_memory(hits, mem, table_size, sizeof(Offset_String)); } if (str->space == 0){ - str->space = (char*)general_memory_allocate(general, str_size, 0); + str->space = (char*)general_memory_allocate(general, str_size); str->max = str_size; } else if (str->max < str_size){ - str->space = (char*)general_memory_reallocate_nocopy(general, str->space, str_size, 0); + str->space = (char*)general_memory_reallocate_nocopy(general, str->space, str_size); str->max = str_size; } @@ -6097,7 +6096,7 @@ search_hit_add(General_Memory *general, Table *hits, String_Space *space, char * ostring = strspace_append(space, str, len); if (ostring.size == 0){ new_size = Max(space->max*2, space->max + len); - space->space = (char*)general_memory_reallocate(general, space->space, space->new_pos, new_size, 0); + space->space = (char*)general_memory_reallocate(general, space->space, space->new_pos, new_size); ostring = strspace_append(space, str, len); } @@ -6210,7 +6209,7 @@ live_set_alloc_view(Live_Views *live_set, Panel *panel, Models *models){ { i32 gui_mem_size = Kbytes(32); - void *gui_mem = general_memory_allocate(&models->mem.general, gui_mem_size + 8, 0); + void *gui_mem = general_memory_allocate(&models->mem.general, gui_mem_size + 8); result.view->gui_mem = gui_mem; gui_mem = advance_to_alignment(gui_mem); result.view->gui_target.push = make_part(gui_mem, gui_mem_size); diff --git a/4ed_mem.cpp b/4ed_mem.cpp deleted file mode 100644 index 0e9a3ef6..00000000 --- a/4ed_mem.cpp +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 13.11.2015 - * - * Memory utils for 4coder - * - */ - -// TOP - -enum Memory_Bubble_Flag{ - MEM_BUBBLE_USED = 0x1, - MEM_BUBBLE_DEBUG = 0xD3000000, - MEM_BUBBLE_SYS_DEBUG = 0x5D000000, - MEM_BUBBLE_DEBUG_MASK = 0xFF000000 -}; - -struct Bubble{ - Bubble *prev; - Bubble *next; - u32 flags; - i32 size; - u32 type; - u32 _unused_; -}; - -struct General_Memory{ - Bubble sentinel; -}; - -struct Mem_Options{ - Partition part; - General_Memory general; -}; - -inline void -insert_bubble(Bubble *prev, Bubble *bubble){ - bubble->prev = prev; - bubble->next = prev->next; - bubble->prev->next = bubble; - bubble->next->prev = bubble; -} - -inline void -remove_bubble(Bubble *bubble){ - bubble->prev->next = bubble->next; - bubble->next->prev = bubble->prev; -} - -#if FRED_INTERNAL -#define MEM_BUBBLE_FLAG_INIT MEM_BUBBLE_DEBUG -#else -#define MEM_BUBBLE_FLAG_INIT 0 -#endif - -internal void -general_memory_open(General_Memory *general, void *memory, i32 size){ - general->sentinel.prev = &general->sentinel; - general->sentinel.next = &general->sentinel; - general->sentinel.flags = MEM_BUBBLE_USED; - general->sentinel.size = 0; - - Bubble *first = (Bubble*)memory; - first->flags = (u32)MEM_BUBBLE_FLAG_INIT; - first->size = size - sizeof(Bubble); - insert_bubble(&general->sentinel, first); -} - -internal b32 -general_memory_check(General_Memory *general){ - Bubble *sentinel = &general->sentinel; - for (Bubble *bubble = sentinel->next; - bubble != sentinel; - bubble = bubble->next){ - Assert(bubble); - - Bubble *next = bubble->next; - Assert(bubble == next->prev); - if (next != sentinel && bubble->prev != sentinel){ - Assert(bubble->next > bubble); - Assert(bubble > bubble->prev); - - char *end_ptr = (char*)(bubble + 1) + bubble->size; - char *next_ptr = (char*)next; - AllowLocal(end_ptr); - AllowLocal(next_ptr); - Assert(end_ptr == next_ptr); - } - } - return(1); -} - -#define BUBBLE_MIN_SIZE 1024 - -internal void -general_memory_attempt_split(Bubble *bubble, i32 wanted_size){ - i32 remaining_size = bubble->size - wanted_size; - if (remaining_size >= BUBBLE_MIN_SIZE){ - bubble->size = wanted_size; - Bubble *new_bubble = (Bubble*)((u8*)(bubble + 1) + wanted_size); - new_bubble->flags = (u32)MEM_BUBBLE_FLAG_INIT; - new_bubble->size = remaining_size - sizeof(Bubble); - insert_bubble(bubble, new_bubble); - } -} - -internal void* -general_memory_allocate(General_Memory *general, i32 size, u32 type = 0){ - void *result = 0; - for (Bubble *bubble = general->sentinel.next; - bubble != &general->sentinel; - bubble = bubble->next){ - if (!(bubble->flags & MEM_BUBBLE_USED)){ - if (bubble->size >= size){ - result = bubble + 1; - bubble->flags |= MEM_BUBBLE_USED; - bubble->type = type; - general_memory_attempt_split(bubble, size); - break; - } - } - } - return result; -} - -inline void -general_memory_do_merge(Bubble *left, Bubble *right){ - Assert(left->next == right); - Assert(right->prev == left); - left->size += sizeof(Bubble) + right->size; - remove_bubble(right); -} - -inline void -general_memory_attempt_merge(Bubble *left, Bubble *right){ - if (!(left->flags & MEM_BUBBLE_USED) && - !(right->flags & MEM_BUBBLE_USED)){ - general_memory_do_merge(left, right); - } -} - -internal void -general_memory_free(General_Memory *general, void *memory){ - Bubble *bubble = ((Bubble*)memory) - 1; -#if FRED_INTERNAL - Assert((bubble->flags & MEM_BUBBLE_DEBUG_MASK) == MEM_BUBBLE_DEBUG); -#endif - bubble->flags &= ~MEM_BUBBLE_USED; - bubble->type = 0; - Bubble *prev, *next; - prev = bubble->prev; - next = bubble->next; - general_memory_attempt_merge(bubble, next); - general_memory_attempt_merge(prev, bubble); -} - -internal void* -general_memory_reallocate(General_Memory *general, void *old, i32 old_size, i32 size, u32 type = 0){ - void *result = old; - Bubble *bubble = ((Bubble*)old) - 1; - bubble->type = type; -#if FRED_INTERNAL - Assert((bubble->flags & MEM_BUBBLE_DEBUG_MASK) == MEM_BUBBLE_DEBUG); -#endif - i32 additional_space = size - bubble->size; - if (additional_space > 0){ - Bubble *next = bubble->next; - if (!(next->flags & MEM_BUBBLE_USED) && - next->size + sizeof(Bubble) >= additional_space){ - general_memory_do_merge(bubble, next); - general_memory_attempt_split(bubble, size); - } - else{ - result = general_memory_allocate(general, size, type); - if (old_size) memcpy(result, old, old_size); - general_memory_free(general, old); - } - } - return result; -} - -inline void* -general_memory_reallocate_nocopy(General_Memory *general, void *old, i32 size, u32 type = 0){ - return general_memory_reallocate(general, old, 0, size, type); -} - -#define reset_temp_memory end_temp_memory - -#define gen_struct(g, T) (T*)general_memory_allocate(g, sizeof(T), 0) -#define gen_array(g, T, size) (T*)general_memory_allocate(g, sizeof(T)*(size), 0) -#define gen_block(g, size) general_memory_open(g, size, 0) - -internal String -make_string_terminated(Partition *part, char *str, int len){ - char *space = (char*)push_array(part, char, len + 1); - String string = make_string(str, len, len+1); - copy_fast_unsafe(space, string); - string.str = space; - terminate_with_null(&string); - return(string); -} - -// BOTTOM - diff --git a/TODO.txt b/TODO.txt index c53e3b61..5c435565 100644 --- a/TODO.txt +++ b/TODO.txt @@ -174,24 +174,24 @@ ; [] tutorials ; [] 4edT thing ; [] unicode/UTF support +; [] console emulator ; ; INTERNAL TODOS ; [X] switch building non-extensible version by statically linking to custom.cpp ; [X] pack fonts more squarely -; [] general parameter handling +; [X] change job canceling to a polling based thing ; [] hashed string pool for clipboard/filenames/etc ; [] new profiling/debugging system -; [] change job canceling to a polling based thing ; ; EASY TODOS ; [X] better messages for example not "BEHIND OS" ; [X] shift backspace ; [X] center view on cursor +; [X] delta time in scroll interpolation ; [] close editor command ; [] panel grow/shrink commands -; [] delta time in scroll interpolation ; ; HARD BUGS @@ -200,13 +200,12 @@ ; [] fyoucon's segfaults with malloc on win10 ; [] handling cursor in non-client part of window so it doesn't spaz ; [] fill screen right away -; [] how to get fast repaint (do I really need double buffering?) -; [] history breaks when heavily used (disk swaping?) +; [] history breaks when heavily used? (disk swaping?) ; -; [] minimize and reopen problem (reported by two users now, still not reproduced here) +; [] minimize and reopen problem (still not reproduced here) ; -; FANCY PANTS IDEAS +; FANCY-PANTS IDEAS ; [] pass messages to 'jobs' to try to avoid cancelling them ; if the job still thinks it should be cancelled it will say so ; but otherwise the job can try to incorporate the new info @@ -225,27 +224,24 @@ ; [X] position in file to open ; [X] invoking special tools ; [X] transition Win32 layer to using system_shared stuff +; [X] event driven file synchronization ; [] user settings file ; [] system fonts ; [] file drag and drop ; [] low latency stuff -; [] event driven file synchronization ; [] actually write the port ; [X] 4coder code compiling ; [X] opengl window up ; [X] basic versions of system functions ; [X] get 4coder to render to window -; [X] keyboard and mouse input (TY:insofaras) -; [X] file exchange (TY:insofaras) -; [X] clipboard (TY:insofaras) +; [X] keyboard and mouse input (TY:insofaras) +; [X] file exchange (TY:insofaras) +; [X] clipboard (TY:insofaras) ; [X] background threads (TY:insofaras) -; [X] cli stuff (TY:insofaras) +; [X] cli stuff (TY:insofaras) +; [X] event diven file synchronization (TY:insofaras) ; [] system fonts ; [] file drag and drop -; [] low latency stuff ; [] allow for multiple clipboards -; [] event diven file synchronization -; - ; diff --git a/linux_4ed.cpp b/linux_4ed.cpp index 2fb85dce..712e2819 100644 --- a/linux_4ed.cpp +++ b/linux_4ed.cpp @@ -24,7 +24,6 @@ #define FCPP_STRING_IMPLEMENTATION #include "4coder_string.h" -#include "4ed_mem.cpp" #include "4ed_math.cpp" #include "4ed_system.h" @@ -286,7 +285,7 @@ LinuxGetMemory_(i32 size, i32 line_number, char *file_name){ result = mmap(0, size + sizeof(Sys_Bubble), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); Sys_Bubble* bubble = (Sys_Bubble*)result; - bubble->flags = MEM_BUBBLE_SYS_DEBUG; + bubble->flags = 0; bubble->line_number = line_number; bubble->file_name = file_name; bubble->size = size; @@ -316,7 +315,6 @@ LinuxFreeMemory(void *block){ if (block){ #if FRED_INTERNAL Sys_Bubble *bubble = ((Sys_Bubble*)block) - 1; - Assert((bubble->flags & MEM_BUBBLE_DEBUG_MASK) == MEM_BUBBLE_SYS_DEBUG); size_t size = bubble->size + sizeof(Sys_Bubble); @@ -2453,7 +2451,7 @@ main(int argc, char **argv) #if FRED_INTERNAL linuxvars.internal_bubble.next = &linuxvars.internal_bubble; linuxvars.internal_bubble.prev = &linuxvars.internal_bubble; - linuxvars.internal_bubble.flags = MEM_BUBBLE_SYS_DEBUG; + linuxvars.internal_bubble.flags = 0; pthread_mutex_init(&linuxvars.DEBUG_sysmem_lock, 0); #endif diff --git a/power/4coder_default_building.cpp b/power/4coder_default_building.cpp index 713c3db3..4f295a53 100644 --- a/power/4coder_default_building.cpp +++ b/power/4coder_default_building.cpp @@ -242,6 +242,9 @@ gcc_style_verify(String line, int colon_pos){ else if (match_part(line_part, ": warning")){ result = true; } + else if (match_part(line_part, ": fatal")){ + result = true; + } return(result); } diff --git a/win32_4ed.cpp b/win32_4ed.cpp index 4b9aad87..aec6a4e9 100644 --- a/win32_4ed.cpp +++ b/win32_4ed.cpp @@ -16,7 +16,6 @@ #define FSTRING_IMPLEMENTATION #include "4coder_string.h" -#include "4ed_mem.cpp" #include "4ed_math.cpp" #include "4ed_system.h" @@ -245,7 +244,7 @@ Sys_Get_Memory_Sig(system_get_memory_){ #if FRED_INTERNAL ptr = VirtualAlloc(0, size + sizeof(Sys_Bubble), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); Sys_Bubble *bubble = (Sys_Bubble*)ptr; - bubble->flags = MEM_BUBBLE_SYS_DEBUG; + bubble->flags = 0; bubble->line_number = line_number; bubble->file_name = file_name; bubble->size = size; @@ -264,7 +263,6 @@ Sys_Free_Memory_Sig(system_free_memory){ if (block){ #if FRED_INTERNAL Sys_Bubble *bubble = ((Sys_Bubble*)block) - 1; - Assert((bubble->flags & MEM_BUBBLE_DEBUG_MASK) == MEM_BUBBLE_SYS_DEBUG); EnterCriticalSection(&win32vars.DEBUG_sysmem_lock); remove_bubble(bubble); LeaveCriticalSection(&win32vars.DEBUG_sysmem_lock); @@ -1698,7 +1696,7 @@ WinMain(HINSTANCE hInstance, #if FRED_INTERNAL win32vars.internal_bubble.next = &win32vars.internal_bubble; win32vars.internal_bubble.prev = &win32vars.internal_bubble; - win32vars.internal_bubble.flags = MEM_BUBBLE_SYS_DEBUG; + win32vars.internal_bubble.flags = 0; InitializeCriticalSection(&win32vars.DEBUG_sysmem_lock); #endif