2017-01-23 06:19:43 +00:00
/*
4 coder_base_commands . cpp - Base commands such as inserting characters , and
moving the cursor , which work even without the default 4 coder framework .
*/
// TOP
2019-10-08 19:16:20 +00:00
function void
2019-11-10 22:56:03 +00:00
write_text ( Application_Links * app , String_Const_u8 insert ) {
2019-10-25 06:17:54 +00:00
ProfileScope ( app , " write character " ) ;
2019-10-10 00:07:38 +00:00
if ( insert . str ! = 0 & & insert . size > 0 ) {
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadWriteVisible ) ;
2019-04-06 23:36:53 +00:00
if_view_has_highlighted_range_delete_range ( app , view ) ;
2017-11-21 18:25:19 +00:00
2019-06-20 23:43:27 +00:00
i64 pos = view_get_cursor_pos ( app , view ) ;
2019-09-02 18:59:36 +00:00
pos = view_get_character_legal_pos_from_pos ( app , view , pos ) ;
2017-02-24 02:30:29 +00:00
2019-10-18 02:54:02 +00:00
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadWriteVisible ) ;
2017-02-24 02:30:29 +00:00
2019-02-08 12:33:43 +00:00
// NOTE(allen): consecutive inserts merge logic
2019-06-20 04:45:58 +00:00
History_Record_Index first_index = buffer_history_get_current_state_index ( app , buffer ) ;
2019-02-26 23:08:42 +00:00
b32 do_merge = false ;
2019-10-10 00:07:38 +00:00
if ( insert . str [ 0 ] ! = ' \n ' ) {
2019-04-05 02:03:36 +00:00
Record_Info record = get_single_record ( app , buffer , first_index ) ;
2019-02-09 01:48:11 +00:00
if ( record . error = = RecordError_NoError & & record . kind = = RecordKind_Single ) {
2019-06-01 23:58:28 +00:00
String_Const_u8 string = record . single . string_forward ;
2019-06-20 04:45:58 +00:00
i32 last_end = ( i32 ) ( record . single . first + string . size ) ;
2019-02-09 09:07:39 +00:00
if ( last_end = = pos & & string . size > 0 ) {
2019-02-09 01:48:11 +00:00
char c = string . str [ string . size - 1 ] ;
if ( c ! = ' \n ' ) {
2019-10-10 00:07:38 +00:00
if ( character_is_whitespace ( insert . str [ 0 ] ) & &
character_is_whitespace ( c ) ) {
2019-02-09 01:48:11 +00:00
do_merge = true ;
2019-02-08 12:33:43 +00:00
}
2019-10-10 00:07:38 +00:00
else if ( character_is_alpha_numeric ( insert . str [ 0 ] ) & & character_is_alpha_numeric ( c ) ) {
2019-02-09 01:48:11 +00:00
do_merge = true ;
2019-02-08 12:33:43 +00:00
}
2019-02-09 01:48:11 +00:00
}
2019-02-08 12:33:43 +00:00
}
}
}
2019-02-08 11:18:48 +00:00
2019-02-08 12:33:43 +00:00
// NOTE(allen): perform the edit
2019-10-10 00:07:38 +00:00
b32 edit_success = buffer_replace_range ( app , buffer , Ii64 ( pos ) , insert ) ;
2017-02-24 02:30:29 +00:00
2019-02-08 12:33:43 +00:00
// NOTE(allen): finish merging records if necessary
if ( do_merge ) {
2019-06-20 04:45:58 +00:00
History_Record_Index last_index = buffer_history_get_current_state_index ( app , buffer ) ;
2019-04-05 02:03:36 +00:00
buffer_history_merge_record_range ( app , buffer , first_index , last_index , RecordMergeFlag_StateInRange_MoveStateForward ) ;
2019-02-08 12:33:43 +00:00
}
2019-02-08 11:18:48 +00:00
2019-02-08 12:33:43 +00:00
// NOTE(allen): finish updating the cursor
2019-02-12 10:21:02 +00:00
if ( edit_success ) {
2019-10-10 00:07:38 +00:00
view_set_cursor_and_preferred_x ( app , view , seek_pos ( pos + insert . size ) ) ;
2019-02-12 10:21:02 +00:00
}
2017-01-23 06:19:43 +00:00
}
}
2019-10-10 00:07:38 +00:00
CUSTOM_COMMAND_SIG ( write_text_input )
2019-11-10 22:56:03 +00:00
CUSTOM_DOC ( " Inserts whatever text was used to trigger this command. " )
2017-11-21 18:25:19 +00:00
{
2019-10-14 22:57:47 +00:00
User_Input in = get_current_input ( app ) ;
2019-10-10 00:07:38 +00:00
String_Const_u8 insert = to_writable ( & in ) ;
2019-11-10 22:56:03 +00:00
write_text ( app , insert ) ;
2019-10-10 00:07:38 +00:00
}
CUSTOM_COMMAND_SIG ( write_space )
CUSTOM_DOC ( " Inserts an underscore. " )
{
2019-11-10 22:56:03 +00:00
write_text ( app , string_u8_litexpr ( " " ) ) ;
2018-06-02 04:06:13 +00:00
}
2017-11-21 18:25:19 +00:00
CUSTOM_COMMAND_SIG ( write_underscore )
CUSTOM_DOC ( " Inserts an underscore. " )
{
2019-11-10 22:56:03 +00:00
write_text ( app , string_u8_litexpr ( " _ " ) ) ;
2017-11-21 18:25:19 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( delete_char )
CUSTOM_DOC ( " Deletes the character to the right of the cursor. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadWriteVisible ) ;
2019-04-06 23:36:53 +00:00
if ( ! if_view_has_highlighted_range_delete_range ( app , view ) ) {
2019-10-18 02:54:02 +00:00
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadWriteVisible ) ;
2019-06-20 23:43:27 +00:00
i64 start = view_get_cursor_pos ( app , view ) ;
i64 buffer_size = buffer_get_size ( app , buffer ) ;
2019-04-05 02:03:36 +00:00
if ( 0 < = start & & start < buffer_size ) {
2019-09-02 18:59:36 +00:00
Buffer_Cursor cursor = view_compute_cursor ( app , view , seek_pos ( start ) ) ;
i64 character = view_relative_character_from_pos ( app , view , cursor . line , cursor . pos ) ;
i64 end = view_pos_from_relative_character ( app , view , cursor . line , character + 1 ) ;
2019-06-20 23:43:27 +00:00
buffer_replace_range ( app , buffer , Ii64 ( start , end ) , string_u8_empty ) ;
2018-09-30 12:14:47 +00:00
}
2017-01-23 06:19:43 +00:00
}
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( backspace_char )
CUSTOM_DOC ( " Deletes the character to the left of the cursor. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadWriteVisible ) ;
2019-04-06 23:36:53 +00:00
if ( ! if_view_has_highlighted_range_delete_range ( app , view ) ) {
2019-10-18 02:54:02 +00:00
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadWriteVisible ) ;
2019-06-20 23:43:27 +00:00
i64 end = view_get_cursor_pos ( app , view ) ;
i64 buffer_size = buffer_get_size ( app , buffer ) ;
2019-04-05 02:03:36 +00:00
if ( 0 < end & & end < = buffer_size ) {
2019-09-02 18:59:36 +00:00
Buffer_Cursor cursor = view_compute_cursor ( app , view , seek_pos ( end ) ) ;
i64 character = view_relative_character_from_pos ( app , view , cursor . line , cursor . pos ) ;
i64 start = view_pos_from_relative_character ( app , view , cursor . line , character - 1 ) ;
2019-06-20 23:43:27 +00:00
if ( buffer_replace_range ( app , buffer , Ii64 ( start , end ) , string_u8_empty ) ) {
2019-09-02 21:32:52 +00:00
view_set_cursor_and_preferred_x ( app , view , seek_pos ( start ) ) ;
2019-02-12 10:21:02 +00:00
}
2018-09-30 12:14:47 +00:00
}
2017-01-23 06:19:43 +00:00
}
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( set_mark )
CUSTOM_DOC ( " Sets the mark to the current position of the cursor. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
2019-06-20 23:43:27 +00:00
i64 pos = view_get_cursor_pos ( app , view ) ;
2019-04-06 23:36:53 +00:00
view_set_mark ( app , view , seek_pos ( pos ) ) ;
2019-09-02 21:32:52 +00:00
view_set_cursor_and_preferred_x ( app , view , seek_pos ( pos ) ) ;
2017-01-23 06:19:43 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( cursor_mark_swap )
CUSTOM_DOC ( " Swaps the position of the cursor and the mark. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
2019-06-20 23:43:27 +00:00
i64 cursor = view_get_cursor_pos ( app , view ) ;
i64 mark = view_get_mark_pos ( app , view ) ;
2019-09-02 21:32:52 +00:00
view_set_cursor_and_preferred_x ( app , view , seek_pos ( mark ) ) ;
2019-04-06 23:36:53 +00:00
view_set_mark ( app , view , seek_pos ( cursor ) ) ;
2017-01-23 06:19:43 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( delete_range )
CUSTOM_DOC ( " Deletes the text in the range between the cursor and the mark. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadWriteVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadWriteVisible ) ;
2019-06-20 23:43:27 +00:00
Range_i64 range = get_view_range ( app , view ) ;
buffer_replace_range ( app , buffer , range , string_u8_empty ) ;
2017-01-23 06:19:43 +00:00
}
2019-10-15 22:30:06 +00:00
function void
2019-06-11 05:01:57 +00:00
current_view_boundary_delete ( Application_Links * app , Scan_Direction direction , Boundary_Function_List funcs ) {
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadWriteVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadWriteVisible ) ;
2019-06-20 23:43:27 +00:00
Range_i64 range = { } ;
2019-06-19 02:31:59 +00:00
range . first = view_get_cursor_pos ( app , view ) ;
2019-06-11 05:01:57 +00:00
range . one_past_last = scan ( app , funcs , buffer , direction , range . first ) ;
2019-06-09 21:05:57 +00:00
range = rectify ( range ) ;
2019-06-20 23:43:27 +00:00
buffer_replace_range ( app , buffer , range , string_u8_empty ) ;
2019-06-09 21:05:57 +00:00
}
CUSTOM_COMMAND_SIG ( backspace_alpha_numeric_boundary )
CUSTOM_DOC ( " Delete characters between the cursor position and the first alphanumeric boundary to the left. " )
{
2019-06-11 05:01:57 +00:00
Scratch_Block scratch ( app ) ;
current_view_boundary_delete ( app , Scan_Backward ,
push_boundary_list ( scratch , boundary_alpha_numeric ) ) ;
2019-06-09 21:05:57 +00:00
}
CUSTOM_COMMAND_SIG ( delete_alpha_numeric_boundary )
CUSTOM_DOC ( " Delete characters between the cursor position and the first alphanumeric boundary to the right. " )
{
2019-06-11 05:01:57 +00:00
Scratch_Block scratch ( app ) ;
current_view_boundary_delete ( app , Scan_Forward ,
push_boundary_list ( scratch , boundary_alpha_numeric ) ) ;
2019-06-09 21:05:57 +00:00
}
2019-10-15 22:30:06 +00:00
function void
2019-06-11 05:01:57 +00:00
current_view_snipe_delete ( Application_Links * app , Scan_Direction direction , Boundary_Function_List funcs ) {
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadWriteVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadWriteVisible ) ;
2019-06-20 23:43:27 +00:00
i64 pos = view_get_cursor_pos ( app , view ) ;
Range_i64 range = get_snipe_range ( app , funcs , buffer , pos , direction ) ;
2019-06-09 21:05:57 +00:00
buffer_replace_range ( app , buffer , range , string_u8_litexpr ( " " ) ) ;
}
CUSTOM_COMMAND_SIG ( snipe_backward_whitespace_or_token_boundary )
CUSTOM_DOC ( " Delete a single, whole token on or to the left of the cursor and post it to the clipboard. " )
{
2019-06-11 05:01:57 +00:00
Scratch_Block scratch ( app ) ;
current_view_snipe_delete ( app , Scan_Backward ,
push_boundary_list ( scratch , boundary_token , boundary_non_whitespace ) ) ;
2019-06-09 21:05:57 +00:00
}
CUSTOM_COMMAND_SIG ( snipe_forward_whitespace_or_token_boundary )
CUSTOM_DOC ( " Delete a single, whole token on or to the right of the cursor and post it to the clipboard. " )
{
2019-06-11 05:01:57 +00:00
Scratch_Block scratch ( app ) ;
current_view_snipe_delete ( app , Scan_Forward ,
push_boundary_list ( scratch , boundary_token , boundary_non_whitespace ) ) ;
2019-06-09 21:05:57 +00:00
}
2018-05-10 08:12:47 +00:00
////////////////////////////////
2017-01-23 06:19:43 +00:00
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( center_view )
CUSTOM_DOC ( " Centers the view vertically on the line on which the cursor sits. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
2019-06-19 02:31:59 +00:00
Rect_f32 region = view_get_buffer_region ( app , view ) ;
2019-09-02 18:59:36 +00:00
i64 pos = view_get_cursor_pos ( app , view ) ;
Buffer_Cursor cursor = view_compute_cursor ( app , view , seek_pos ( pos ) ) ;
f32 view_height = rect_height ( region ) ;
Buffer_Scroll scroll = view_get_buffer_scroll ( app , view ) ;
scroll . target . line_number = cursor . line ;
scroll . target . pixel_shift . y = - view_height * 0.5f ;
2019-10-15 03:26:00 +00:00
view_set_buffer_scroll ( app , view , scroll , SetBufferScroll_SnapCursorIntoView ) ;
2017-01-23 06:19:43 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( left_adjust_view )
CUSTOM_DOC ( " Sets the left size of the view near the x position of the cursor. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
2019-09-02 18:59:36 +00:00
i64 pos = view_get_cursor_pos ( app , view ) ;
Buffer_Cursor cursor = view_compute_cursor ( app , view , seek_pos ( pos ) ) ;
Vec2_f32 p = view_relative_xy_of_pos ( app , view , cursor . line , pos ) ;
Buffer_Scroll scroll = view_get_buffer_scroll ( app , view ) ;
scroll . target . pixel_shift . x = clamp_bot ( 0.f , p . x - 30.f ) ;
2019-10-15 03:26:00 +00:00
view_set_buffer_scroll ( app , view , scroll , SetBufferScroll_SnapCursorIntoView ) ;
2017-01-23 06:19:43 +00:00
}
2018-09-27 20:15:32 +00:00
CUSTOM_COMMAND_SIG ( click_set_cursor_and_mark )
CUSTOM_DOC ( " Sets the cursor position and mark to the mouse position. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
2019-10-14 02:13:15 +00:00
Mouse_State mouse = get_mouse_state ( app ) ;
i64 pos = view_pos_from_xy ( app , view , V2 ( mouse . p ) ) ;
view_set_cursor_and_preferred_x ( app , view , seek_pos ( pos ) ) ;
view_set_mark ( app , view , seek_pos ( pos ) ) ;
2018-09-27 20:15:32 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( click_set_cursor )
CUSTOM_DOC ( " Sets the cursor position to the mouse position. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
2019-10-14 02:13:15 +00:00
Mouse_State mouse = get_mouse_state ( app ) ;
i64 pos = view_pos_from_xy ( app , view , V2 ( mouse . p ) ) ;
view_set_cursor_and_preferred_x ( app , view , seek_pos ( pos ) ) ;
no_mark_snap_to_cursor ( app , view ) ;
2018-09-27 20:15:32 +00:00
}
CUSTOM_COMMAND_SIG ( click_set_cursor_if_lbutton )
CUSTOM_DOC ( " If the mouse left button is pressed, sets the cursor position to the mouse position. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
2019-10-14 02:13:15 +00:00
Mouse_State mouse = get_mouse_state ( app ) ;
if ( mouse . l ) {
i64 pos = view_pos_from_xy ( app , view , V2 ( mouse . p ) ) ;
view_set_cursor_and_preferred_x ( app , view , seek_pos ( pos ) ) ;
2017-01-23 06:19:43 +00:00
}
2019-10-14 02:13:15 +00:00
no_mark_snap_to_cursor ( app , view ) ;
2017-01-23 06:19:43 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( click_set_mark )
CUSTOM_DOC ( " Sets the mark position to the mouse position. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
2019-10-14 02:13:15 +00:00
Mouse_State mouse = get_mouse_state ( app ) ;
i64 pos = view_pos_from_xy ( app , view , V2 ( mouse . p ) ) ;
view_set_mark ( app , view , seek_pos ( pos ) ) ;
no_mark_snap_to_cursor ( app , view ) ;
2017-01-23 06:19:43 +00:00
}
2018-09-22 23:45:24 +00:00
CUSTOM_COMMAND_SIG ( mouse_wheel_scroll )
CUSTOM_DOC ( " Reads the scroll wheel value from the mouse state and scrolls accordingly. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
2018-09-22 23:45:24 +00:00
Mouse_State mouse = get_mouse_state ( app ) ;
if ( mouse . wheel ! = 0 ) {
2019-10-14 02:13:15 +00:00
Buffer_Scroll scroll = view_get_buffer_scroll ( app , view ) ;
scroll . target = view_move_buffer_point ( app , view , scroll . target , V2f32 ( 0.f , ( f32 ) mouse . wheel ) ) ;
2019-10-15 03:26:00 +00:00
view_set_buffer_scroll ( app , view , scroll , SetBufferScroll_SnapCursorIntoView ) ;
2018-09-22 23:45:24 +00:00
}
}
2018-05-10 08:12:47 +00:00
////////////////////////////////
2019-08-24 01:34:42 +00:00
internal void
move_vertical_pixels ( Application_Links * app , View_ID view , f32 pixels ) {
2019-10-25 06:17:54 +00:00
ProfileScope ( app , " move vertical pixels " ) ;
2019-09-02 18:59:36 +00:00
i64 pos = view_get_cursor_pos ( app , view ) ;
Buffer_Cursor cursor = view_compute_cursor ( app , view , seek_pos ( pos ) ) ;
Vec2_f32 p = view_relative_xy_of_pos ( app , view , cursor . line , pos ) ;
2019-09-02 21:32:52 +00:00
p . x = view_get_preferred_x ( app , view ) ;
2019-09-02 18:59:36 +00:00
p . y + = pixels ;
i64 new_pos = view_pos_at_relative_xy ( app , view , cursor . line , p ) ;
2019-09-02 21:32:52 +00:00
view_set_cursor ( app , view , seek_pos ( new_pos ) ) ;
2019-04-06 23:36:53 +00:00
no_mark_snap_to_cursor_if_shift ( app , view ) ;
2017-01-23 06:19:43 +00:00
}
2019-08-24 01:34:42 +00:00
internal void
move_vertical_pixels ( Application_Links * app , f32 pixels ) {
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
2019-08-24 01:34:42 +00:00
move_vertical_pixels ( app , view , pixels ) ;
}
internal void
2019-10-30 23:27:37 +00:00
move_vertical_lines ( Application_Links * app , View_ID view , i64 lines ) {
if ( lines > 0 ) {
for ( i64 i = 0 ; i < lines ; i + = 1 ) {
i64 pos = view_get_cursor_pos ( app , view ) ;
Buffer_Cursor cursor = view_compute_cursor ( app , view , seek_pos ( pos ) ) ;
Rect_f32 box = view_relative_box_of_pos ( app , view , cursor . line , cursor . pos ) ;
f32 half_height = rect_height ( box ) * 0.5f ;
move_vertical_pixels ( app , half_height + 2.f ) ;
}
}
else {
for ( i64 i = 0 ; i > lines ; i - = 1 ) {
i64 pos = view_get_cursor_pos ( app , view ) ;
Buffer_Cursor cursor = view_compute_cursor ( app , view , seek_pos ( pos ) ) ;
Rect_f32 box = view_relative_box_of_pos ( app , view , cursor . line , cursor . pos ) ;
f32 half_height = rect_height ( box ) * 0.5f ;
move_vertical_pixels ( app , - half_height - 2.f ) ;
}
}
2019-08-24 01:34:42 +00:00
}
internal void
2019-10-30 23:27:37 +00:00
move_vertical_lines ( Application_Links * app , i64 lines ) {
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
2019-08-24 01:34:42 +00:00
move_vertical_lines ( app , view , lines ) ;
}
internal f32
get_page_jump ( Application_Links * app , View_ID view ) {
Rect_f32 region = view_get_buffer_region ( app , view ) ;
return ( rect_height ( region ) * .9f ) ;
2018-05-10 08:12:47 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( move_up )
CUSTOM_DOC ( " Moves the cursor up one line. " )
{
2019-10-30 23:27:37 +00:00
move_vertical_lines ( app , - 1 ) ;
2017-01-23 06:19:43 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( move_down )
CUSTOM_DOC ( " Moves the cursor down one line. " )
{
2019-10-30 23:27:37 +00:00
move_vertical_lines ( app , 1 ) ;
2017-01-23 06:19:43 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( move_up_10 )
CUSTOM_DOC ( " Moves the cursor up ten lines. " )
{
2019-10-30 23:27:37 +00:00
move_vertical_lines ( app , - 10 ) ;
2017-01-23 06:19:43 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( move_down_10 )
CUSTOM_DOC ( " Moves the cursor down ten lines. " )
{
2019-10-30 23:27:37 +00:00
move_vertical_lines ( app , 10 ) ;
2017-01-23 06:19:43 +00:00
}
2018-05-10 08:12:47 +00:00
CUSTOM_COMMAND_SIG ( move_down_textual )
CUSTOM_DOC ( " Moves down to the next line of actual text, regardless of line wrapping. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadWriteVisible ) ;
2019-06-20 23:43:27 +00:00
i64 pos = view_get_cursor_pos ( app , view ) ;
2019-09-02 18:59:36 +00:00
Buffer_Cursor cursor = view_compute_cursor ( app , view , seek_pos ( pos ) ) ;
2019-06-20 23:43:27 +00:00
i64 next_line = cursor . line + 1 ;
2019-09-02 21:32:52 +00:00
view_set_cursor_and_preferred_x ( app , view , seek_line_col ( next_line , 1 ) ) ;
2017-01-23 06:19:43 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( page_up )
CUSTOM_DOC ( " Scrolls the view up one view height and moves the cursor up one view height. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
2019-04-06 23:36:53 +00:00
f32 page_jump = get_page_jump ( app , view ) ;
2019-08-24 01:34:42 +00:00
move_vertical_pixels ( app , - page_jump ) ;
2017-01-23 06:19:43 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( page_down )
CUSTOM_DOC ( " Scrolls the view down one view height and moves the cursor down one view height. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
2019-04-06 23:36:53 +00:00
f32 page_jump = get_page_jump ( app , view ) ;
2019-08-24 01:34:42 +00:00
move_vertical_pixels ( app , page_jump ) ;
2017-01-23 06:19:43 +00:00
}
2019-06-09 21:05:57 +00:00
internal void
2019-06-16 23:38:22 +00:00
seek_blank_line ( Application_Links * app , Scan_Direction direction , Position_Within_Line position ) {
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadVisible ) ;
2019-06-20 23:43:27 +00:00
i64 pos = view_get_cursor_pos ( app , view ) ;
i64 new_pos = get_pos_of_blank_line_grouped ( app , buffer , direction , pos ) ;
2019-06-16 23:38:22 +00:00
switch ( position ) {
case PositionWithinLine_SkipLeadingWhitespace :
{
new_pos = get_pos_past_lead_whitespace ( app , buffer , new_pos ) ;
} break ;
case PositionWithinLine_End :
{
new_pos = get_line_side_pos_from_pos ( app , buffer , new_pos , Side_Max ) ;
} break ;
2019-06-09 21:05:57 +00:00
}
2019-10-01 19:12:34 +00:00
new_pos = view_get_character_legal_pos_from_pos ( app , view , new_pos ) ;
2019-09-02 21:32:52 +00:00
view_set_cursor_and_preferred_x ( app , view , seek_pos ( new_pos ) ) ;
2019-06-09 21:05:57 +00:00
no_mark_snap_to_cursor_if_shift ( app , view ) ;
}
CUSTOM_COMMAND_SIG ( move_up_to_blank_line )
CUSTOM_DOC ( " Seeks the cursor up to the next blank line. " )
{
2019-06-16 23:38:22 +00:00
seek_blank_line ( app , Scan_Backward , PositionWithinLine_Start ) ;
2019-06-09 21:05:57 +00:00
}
CUSTOM_COMMAND_SIG ( move_down_to_blank_line )
CUSTOM_DOC ( " Seeks the cursor down to the next blank line. " )
{
2019-06-16 23:38:22 +00:00
seek_blank_line ( app , Scan_Forward , PositionWithinLine_Start ) ;
}
CUSTOM_COMMAND_SIG ( move_up_to_blank_line_skip_whitespace )
CUSTOM_DOC ( " Seeks the cursor up to the next blank line and places it at the end of the line. " )
{
seek_blank_line ( app , Scan_Backward , PositionWithinLine_SkipLeadingWhitespace ) ;
}
CUSTOM_COMMAND_SIG ( move_down_to_blank_line_skip_whitespace )
CUSTOM_DOC ( " Seeks the cursor down to the next blank line and places it at the end of the line. " )
{
seek_blank_line ( app , Scan_Forward , PositionWithinLine_SkipLeadingWhitespace ) ;
2019-06-09 21:05:57 +00:00
}
CUSTOM_COMMAND_SIG ( move_up_to_blank_line_end )
CUSTOM_DOC ( " Seeks the cursor up to the next blank line and places it at the end of the line. " )
{
2019-06-16 23:38:22 +00:00
seek_blank_line ( app , Scan_Backward , PositionWithinLine_End ) ;
2019-06-09 21:05:57 +00:00
}
CUSTOM_COMMAND_SIG ( move_down_to_blank_line_end )
CUSTOM_DOC ( " Seeks the cursor down to the next blank line and places it at the end of the line. " )
{
2019-06-16 23:38:22 +00:00
seek_blank_line ( app , Scan_Forward , PositionWithinLine_End ) ;
2019-06-09 21:05:57 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( move_left )
CUSTOM_DOC ( " Moves the cursor one character to the left. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
2019-10-30 23:27:37 +00:00
view_set_cursor_by_character_delta ( app , view , - 1 ) ;
2019-04-06 23:36:53 +00:00
no_mark_snap_to_cursor_if_shift ( app , view ) ;
2017-01-23 06:19:43 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( move_right )
CUSTOM_DOC ( " Moves the cursor one character to the right. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
2019-10-30 23:27:37 +00:00
view_set_cursor_by_character_delta ( app , view , 1 ) ;
2019-04-06 23:36:53 +00:00
no_mark_snap_to_cursor_if_shift ( app , view ) ;
2017-01-23 06:19:43 +00:00
}
2019-10-15 22:30:06 +00:00
function void
2019-06-11 05:01:57 +00:00
current_view_scan_move ( Application_Links * app , Scan_Direction direction , Boundary_Function_List funcs ) {
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadVisible ) ;
2019-06-20 23:43:27 +00:00
i64 cursor_pos = view_get_cursor_pos ( app , view ) ;
i64 pos = scan ( app , funcs , buffer , direction , cursor_pos ) ;
2019-09-02 21:32:52 +00:00
view_set_cursor_and_preferred_x ( app , view , seek_pos ( pos ) ) ;
2019-06-09 21:05:57 +00:00
no_mark_snap_to_cursor_if_shift ( app , view ) ;
}
CUSTOM_COMMAND_SIG ( move_right_whitespace_boundary )
CUSTOM_DOC ( " Seek right for the next boundary between whitespace and non-whitespace. " )
{
2019-06-11 05:01:57 +00:00
Scratch_Block scratch ( app ) ;
current_view_scan_move ( app , Scan_Forward ,
push_boundary_list ( scratch , boundary_non_whitespace ) ) ;
2019-06-09 21:05:57 +00:00
}
CUSTOM_COMMAND_SIG ( move_left_whitespace_boundary )
CUSTOM_DOC ( " Seek left for the next boundary between whitespace and non-whitespace. " )
{
2019-06-11 05:01:57 +00:00
Scratch_Block scratch ( app ) ;
current_view_scan_move ( app , Scan_Backward ,
push_boundary_list ( scratch , boundary_non_whitespace ) ) ;
2019-06-09 21:05:57 +00:00
}
CUSTOM_COMMAND_SIG ( move_right_token_boundary )
CUSTOM_DOC ( " Seek right for the next end of a token. " )
{
2019-06-11 05:01:57 +00:00
Scratch_Block scratch ( app ) ;
2019-11-13 03:38:17 +00:00
current_view_scan_move ( app , Scan_Forward , push_boundary_list ( scratch , boundary_token ) ) ;
2019-06-09 21:05:57 +00:00
}
CUSTOM_COMMAND_SIG ( move_left_token_boundary )
CUSTOM_DOC ( " Seek left for the next beginning of a token. " )
{
2019-06-11 05:01:57 +00:00
Scratch_Block scratch ( app ) ;
2019-11-13 03:38:17 +00:00
current_view_scan_move ( app , Scan_Backward , push_boundary_list ( scratch , boundary_token ) ) ;
2019-06-09 21:05:57 +00:00
}
CUSTOM_COMMAND_SIG ( move_right_whitespace_or_token_boundary )
CUSTOM_DOC ( " Seek right for the next end of a token or boundary between whitespace and non-whitespace. " )
{
2019-06-11 05:01:57 +00:00
Scratch_Block scratch ( app ) ;
2019-11-13 03:38:17 +00:00
current_view_scan_move ( app , Scan_Forward , push_boundary_list ( scratch , boundary_token , boundary_non_whitespace ) ) ;
2019-06-09 21:05:57 +00:00
}
CUSTOM_COMMAND_SIG ( move_left_whitespace_or_token_boundary )
CUSTOM_DOC ( " Seek left for the next end of a token or boundary between whitespace and non-whitespace. " )
{
2019-06-11 05:01:57 +00:00
Scratch_Block scratch ( app ) ;
2019-11-13 03:38:17 +00:00
current_view_scan_move ( app , Scan_Backward , push_boundary_list ( scratch , boundary_token , boundary_non_whitespace ) ) ;
2019-06-09 21:05:57 +00:00
}
CUSTOM_COMMAND_SIG ( move_right_alpha_numeric_boundary )
CUSTOM_DOC ( " Seek right for boundary between alphanumeric characters and non-alphanumeric characters. " )
{
2019-06-11 05:01:57 +00:00
Scratch_Block scratch ( app ) ;
2019-11-13 03:38:17 +00:00
current_view_scan_move ( app , Scan_Forward , push_boundary_list ( scratch , boundary_alpha_numeric ) ) ;
2019-06-09 21:05:57 +00:00
}
CUSTOM_COMMAND_SIG ( move_left_alpha_numeric_boundary )
CUSTOM_DOC ( " Seek left for boundary between alphanumeric characters and non-alphanumeric characters. " )
{
2019-06-11 05:01:57 +00:00
Scratch_Block scratch ( app ) ;
2019-11-13 03:38:17 +00:00
current_view_scan_move ( app , Scan_Backward , push_boundary_list ( scratch , boundary_alpha_numeric ) ) ;
2019-06-09 21:05:57 +00:00
}
CUSTOM_COMMAND_SIG ( move_right_alpha_numeric_or_camel_boundary )
CUSTOM_DOC ( " Seek right for boundary between alphanumeric characters or camel case word and non-alphanumeric characters. " )
{
2019-06-11 05:01:57 +00:00
Scratch_Block scratch ( app ) ;
2019-11-13 03:38:17 +00:00
current_view_scan_move ( app , Scan_Forward , push_boundary_list ( scratch , boundary_alpha_numeric_camel ) ) ;
2019-06-09 21:05:57 +00:00
}
CUSTOM_COMMAND_SIG ( move_left_alpha_numeric_or_camel_boundary )
CUSTOM_DOC ( " Seek left for boundary between alphanumeric characters or camel case word and non-alphanumeric characters. " )
{
2019-06-11 05:01:57 +00:00
Scratch_Block scratch ( app ) ;
2019-11-13 03:38:17 +00:00
current_view_scan_move ( app , Scan_Backward , push_boundary_list ( scratch , boundary_alpha_numeric_camel ) ) ;
2019-06-09 21:05:57 +00:00
}
////////////////////////////////
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( select_all )
CUSTOM_DOC ( " Puts the cursor at the top of the file, and the mark at the bottom of the file. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadVisible ) ;
2019-06-19 02:31:59 +00:00
i32 buffer_size = ( i32 ) buffer_get_size ( app , buffer ) ;
2019-09-02 21:32:52 +00:00
view_set_cursor_and_preferred_x ( app , view , seek_pos ( 0 ) ) ;
2019-04-06 23:36:53 +00:00
view_set_mark ( app , view , seek_pos ( buffer_size ) ) ;
no_mark_snap_to_cursor ( app , view ) ;
2017-01-23 06:19:43 +00:00
}
2018-05-10 08:12:47 +00:00
////////////////////////////////
2017-01-23 06:19:43 +00:00
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( to_uppercase )
CUSTOM_DOC ( " Converts all ascii text in the range between the cursor and the mark to uppercase. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadWriteVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadWriteVisible ) ;
2019-06-20 23:43:27 +00:00
Range_i64 range = get_view_range ( app , view ) ;
2019-06-18 04:47:00 +00:00
Scratch_Block scratch ( app ) ;
String_Const_u8 string = push_buffer_range ( app , scratch , buffer , range ) ;
string = string_mod_upper ( string ) ;
buffer_replace_range ( app , buffer , range , string ) ;
2019-09-02 21:32:52 +00:00
view_set_cursor_and_preferred_x ( app , view , seek_pos ( range . max ) ) ;
2017-01-23 06:19:43 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( to_lowercase )
CUSTOM_DOC ( " Converts all ascii text in the range between the cursor and the mark to lowercase. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadWriteVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadWriteVisible ) ;
2019-06-20 23:43:27 +00:00
Range_i64 range = get_view_range ( app , view ) ;
2019-06-18 04:47:00 +00:00
Scratch_Block scratch ( app ) ;
String_Const_u8 string = push_buffer_range ( app , scratch , buffer , range ) ;
string = string_mod_lower ( string ) ;
buffer_replace_range ( app , buffer , range , string ) ;
2019-09-02 21:32:52 +00:00
view_set_cursor_and_preferred_x ( app , view , seek_pos ( range . max ) ) ;
2017-01-23 06:19:43 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( clean_all_lines )
CUSTOM_DOC ( " Removes trailing whitespace from all lines in the current buffer. " )
{
2019-10-25 06:17:54 +00:00
ProfileScope ( app , " clean all lines " ) ;
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadWriteVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadWriteVisible ) ;
2019-04-01 02:41:39 +00:00
2019-06-14 21:47:05 +00:00
Scratch_Block scratch ( app ) ;
2019-09-02 18:59:36 +00:00
Batch_Edit * batch_first = 0 ;
Batch_Edit * batch_last = 0 ;
2017-01-23 06:19:43 +00:00
2019-06-14 21:47:05 +00:00
String_Const_u8 text = push_whole_buffer ( app , scratch , buffer ) ;
umem whitespace_start = 0 ;
for ( umem i = 0 ; i < text . size ; i + = 1 ) {
u8 v = string_get_character ( text , i ) ;
if ( v = = ' \n ' | | i + 1 = = text . size ) {
if ( whitespace_start < i ) {
2019-09-02 18:59:36 +00:00
Batch_Edit * batch = push_array ( scratch , Batch_Edit , 1 ) ;
sll_queue_push ( batch_first , batch_last , batch ) ;
batch - > edit . text = SCu8 ( ) ;
batch - > edit . range = Ii64 ( whitespace_start , i ) ;
2017-01-23 06:19:43 +00:00
}
2019-06-14 21:47:05 +00:00
whitespace_start = i + 1 ;
}
else if ( ! character_is_whitespace ( v ) ) {
whitespace_start = i + 1 ;
2017-01-23 06:19:43 +00:00
}
}
2019-06-14 21:47:05 +00:00
2019-09-02 18:59:36 +00:00
buffer_batch_edit ( app , buffer , batch_first ) ;
2017-01-23 06:19:43 +00:00
}
2018-05-10 08:12:47 +00:00
////////////////////////////////
2017-01-23 06:19:43 +00:00
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( basic_change_active_panel )
CUSTOM_DOC ( " Change the currently active panel, moving to the panel with the next highest view_id. Will not skipe the build panel if it is open. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_Always ) ;
get_next_view_looped_all_panels ( app , view , Access_Always ) ;
2019-04-06 23:36:53 +00:00
view_set_active ( app , view ) ;
2017-01-23 06:19:43 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( close_panel )
CUSTOM_DOC ( " Closes the currently active panel if it is not the only panel open. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_Always ) ;
2019-04-06 23:36:53 +00:00
view_close ( app , view ) ;
2017-01-23 06:19:43 +00:00
}
2018-05-10 08:12:47 +00:00
////////////////////////////////
2017-01-23 06:19:43 +00:00
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( show_scrollbar )
CUSTOM_DOC ( " Sets the current view to show it's scrollbar. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_Always ) ;
2019-04-06 23:36:53 +00:00
view_set_setting ( app , view , ViewSetting_ShowScrollbar , true ) ;
2017-02-12 23:04:50 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( hide_scrollbar )
CUSTOM_DOC ( " Sets the current view to hide it's scrollbar. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_Always ) ;
2019-04-06 23:36:53 +00:00
view_set_setting ( app , view , ViewSetting_ShowScrollbar , false ) ;
2017-02-12 23:04:50 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( show_filebar )
CUSTOM_DOC ( " Sets the current view to show it's filebar. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_Always ) ;
2019-04-06 23:36:53 +00:00
view_set_setting ( app , view , ViewSetting_ShowFileBar , true ) ;
2017-03-27 22:36:42 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( hide_filebar )
CUSTOM_DOC ( " Sets the current view to hide it's filebar. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_Always ) ;
2019-04-06 23:36:53 +00:00
view_set_setting ( app , view , ViewSetting_ShowFileBar , false ) ;
2017-03-27 22:36:42 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( toggle_filebar )
CUSTOM_DOC ( " Toggles the visibility status of the current view's filebar. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_Always ) ;
2019-10-10 18:21:47 +00:00
b64 value = false ;
2019-04-06 23:36:53 +00:00
view_get_setting ( app , view , ViewSetting_ShowFileBar , & value ) ;
view_set_setting ( app , view , ViewSetting_ShowFileBar , ! value ) ;
2017-03-30 15:18:16 +00:00
}
2019-02-25 23:42:13 +00:00
CUSTOM_COMMAND_SIG ( toggle_fps_meter )
CUSTOM_DOC ( " Toggles the visibility of the FPS performance meter " )
{
show_fps_hud = ! show_fps_hud ;
}
2017-11-21 18:25:19 +00:00
CUSTOM_COMMAND_SIG ( increase_face_size )
CUSTOM_DOC ( " Increase the size of the face used by the current buffer. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_Always ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_Always ) ;
2019-06-20 04:45:58 +00:00
Face_ID face_id = get_face_id ( app , buffer ) ;
2017-11-21 18:25:19 +00:00
Face_Description description = get_face_description ( app , face_id ) ;
2019-07-24 07:41:40 +00:00
+ + description . parameters . pt_size ;
2017-11-21 18:25:19 +00:00
try_modify_face ( app , face_id , & description ) ;
}
CUSTOM_COMMAND_SIG ( decrease_face_size )
CUSTOM_DOC ( " Decrease the size of the face used by the current buffer. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_Always ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_Always ) ;
2019-06-20 04:45:58 +00:00
Face_ID face_id = get_face_id ( app , buffer ) ;
2017-11-21 18:25:19 +00:00
Face_Description description = get_face_description ( app , face_id ) ;
2019-07-24 07:41:40 +00:00
- - description . parameters . pt_size ;
2017-11-21 18:25:19 +00:00
try_modify_face ( app , face_id , & description ) ;
}
2018-12-17 04:31:04 +00:00
CUSTOM_COMMAND_SIG ( mouse_wheel_change_face_size )
CUSTOM_DOC ( " Reads the state of the mouse wheel and uses it to either increase or decrease the face size. " )
{
2019-10-15 22:30:06 +00:00
local_persist u64 next_resize_time = 0 ;
2019-10-08 01:42:23 +00:00
u64 now = system_now_time ( ) ;
2018-12-17 04:31:04 +00:00
if ( now > = next_resize_time ) {
next_resize_time = now + 50 * 1000 ;
Mouse_State mouse = get_mouse_state ( app ) ;
if ( mouse . wheel > 0 ) {
decrease_face_size ( app ) ;
}
else if ( mouse . wheel < 0 ) {
increase_face_size ( app ) ;
}
}
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( toggle_show_whitespace )
CUSTOM_DOC ( " Toggles the current buffer's whitespace visibility status. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
2019-10-10 18:21:47 +00:00
b64 show_whitespace = false ;
2019-04-06 23:36:53 +00:00
view_get_setting ( app , view , ViewSetting_ShowWhitespace , & show_whitespace ) ;
view_set_setting ( app , view , ViewSetting_ShowWhitespace , ! show_whitespace ) ;
2017-01-23 06:19:43 +00:00
}
2019-02-27 21:14:25 +00:00
CUSTOM_COMMAND_SIG ( toggle_line_numbers )
CUSTOM_DOC ( " Toggles the left margin line numbers. " )
{
global_config . show_line_number_margins = ! global_config . show_line_number_margins ;
}
2019-11-11 02:51:37 +00:00
CUSTOM_COMMAND_SIG ( toggle_line_wrap )
CUSTOM_DOC ( " Toggles the line wrap setting on this buffer. " )
{
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_Always ) ;
Managed_Scope scope = buffer_get_managed_scope ( app , buffer ) ;
b32 * wrap_lines_ptr = scope_attachment ( app , scope , buffer_wrap_lines , b32 ) ;
if ( wrap_lines_ptr ! = 0 ) {
* wrap_lines_ptr = ! ( * wrap_lines_ptr ) ;
buffer_clear_layout_cache ( app , buffer ) ;
}
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( exit_4coder )
CUSTOM_DOC ( " Attempts to close 4coder. " )
{
2017-01-23 06:19:43 +00:00
send_exit_signal ( app ) ;
}
2018-05-10 08:12:47 +00:00
////////////////////////////////
2017-01-23 06:19:43 +00:00
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( goto_line )
CUSTOM_DOC ( " Queries the user for a number, and jumps the cursor to the corresponding line. " )
{
2019-10-13 20:17:22 +00:00
Query_Bar_Group group ( app ) ;
2019-06-01 23:58:28 +00:00
u8 string_space [ 256 ] ;
2018-11-20 08:18:54 +00:00
Query_Bar bar = { } ;
2019-06-01 23:58:28 +00:00
bar . prompt = string_u8_litexpr ( " Goto Line: " ) ;
bar . string = SCu8 ( string_space , ( umem ) 0 ) ;
bar . string_capacity = sizeof ( string_space ) ;
2017-01-23 06:19:43 +00:00
if ( query_user_number ( app , & bar ) ) {
2019-06-01 23:58:28 +00:00
i32 line_number = ( i32 ) string_to_integer ( bar . string , 10 ) ;
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
2019-09-02 21:32:52 +00:00
view_set_cursor_and_preferred_x ( app , view , seek_line_col ( line_number , 0 ) ) ;
2017-01-23 06:19:43 +00:00
}
}
CUSTOM_COMMAND_SIG ( search ) ;
CUSTOM_COMMAND_SIG ( reverse_search ) ;
2019-10-15 22:30:06 +00:00
function void
2019-08-02 20:07:08 +00:00
isearch__update_highlight ( Application_Links * app , View_ID view , Range_i64 range ) {
view_set_highlight_range ( app , view , range ) ;
2019-09-02 21:32:52 +00:00
view_set_cursor_and_preferred_x ( app , view , seek_pos ( range . start ) ) ;
2018-09-22 00:29:32 +00:00
}
2019-10-12 04:21:47 +00:00
function void
isearch ( Application_Links * app , Scan_Direction start_scan , i64 first_pos ,
String_Const_u8 query_init ) {
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadVisible ) ;
2019-06-20 04:45:58 +00:00
if ( ! buffer_exists ( app , buffer ) ) {
2018-09-27 20:15:32 +00:00
return ;
}
2017-01-23 06:19:43 +00:00
2019-10-01 22:45:51 +00:00
i64 buffer_size = buffer_get_size ( app , buffer ) ;
2019-10-13 20:17:22 +00:00
Query_Bar_Group group ( app ) ;
2018-11-20 08:18:54 +00:00
Query_Bar bar = { } ;
2018-09-27 20:15:32 +00:00
if ( start_query_bar ( app , & bar , 0 ) = = 0 ) {
return ;
}
2017-01-23 06:19:43 +00:00
2019-10-01 22:45:51 +00:00
Scan_Direction scan = start_scan ;
2019-06-20 23:43:27 +00:00
i64 pos = first_pos ;
2017-01-23 06:19:43 +00:00
2019-06-01 23:58:28 +00:00
u8 bar_string_space [ 256 ] ;
bar . string = SCu8 ( bar_string_space , query_init . size ) ;
block_copy ( bar . string . str , query_init . str , query_init . size ) ;
2017-01-23 06:19:43 +00:00
2019-10-01 22:45:51 +00:00
String_Const_u8 isearch_str = string_u8_litexpr ( " I-Search: " ) ;
String_Const_u8 rsearch_str = string_u8_litexpr ( " Reverse-I-Search: " ) ;
2017-03-29 16:32:06 +00:00
2019-10-01 22:45:51 +00:00
umem match_size = bar . string . size ;
2018-09-22 00:29:32 +00:00
2018-11-20 08:18:54 +00:00
User_Input in = { } ;
2017-01-23 06:19:43 +00:00
for ( ; ; ) {
2019-10-01 22:45:51 +00:00
switch ( scan ) {
case Scan_Forward :
{
bar . prompt = isearch_str ;
} break ;
case Scan_Backward :
{
bar . prompt = rsearch_str ;
} break ;
2017-03-29 16:32:06 +00:00
}
2019-10-01 22:45:51 +00:00
isearch__update_highlight ( app , view , Ii64_size ( pos , match_size ) ) ;
2019-10-14 22:57:47 +00:00
in = get_next_input ( app , EventPropertyGroup_AnyKeyboardEvent ,
2019-10-13 20:17:22 +00:00
EventProperty_Escape | EventProperty_ViewActivation ) ;
2019-10-01 22:45:51 +00:00
if ( in . abort ) {
break ;
2017-03-29 16:32:06 +00:00
}
2017-01-23 06:19:43 +00:00
2019-10-10 00:07:38 +00:00
String_Const_u8 string = to_writable ( & in ) ;
2019-10-01 22:45:51 +00:00
b32 string_change = false ;
2019-10-10 18:21:47 +00:00
if ( match_key_code ( & in , KeyCode_Return ) | |
match_key_code ( & in , KeyCode_Tab ) ) {
2019-10-11 01:40:10 +00:00
Input_Modifier_Set * mods = & in . event . key . modifiers ;
if ( has_modifier ( mods , KeyCode_Control ) ) {
2019-10-01 22:45:51 +00:00
bar . string . size = cstring_length ( previous_isearch_query ) ;
block_copy ( bar . string . str , previous_isearch_query , bar . string . size ) ;
2017-03-29 16:32:06 +00:00
}
2019-10-01 22:45:51 +00:00
else {
umem size = bar . string . size ;
size = clamp_top ( size , sizeof ( previous_isearch_query ) - 1 ) ;
block_copy ( previous_isearch_query , bar . string . str , size ) ;
previous_isearch_query [ size ] = 0 ;
break ;
2017-03-29 16:32:06 +00:00
}
2019-10-01 22:45:51 +00:00
}
2019-10-10 18:21:47 +00:00
else if ( string . str ! = 0 & & string . size > 0 ) {
String_u8 bar_string = Su8 ( bar . string , sizeof ( bar_string_space ) ) ;
string_append ( & bar_string , string ) ;
bar . string = bar_string . string ;
2019-10-01 22:45:51 +00:00
string_change = true ;
}
2019-10-10 18:21:47 +00:00
else if ( match_key_code ( & in , KeyCode_Backspace ) ) {
if ( is_unmodified_key ( & in . event ) ) {
2019-10-01 22:45:51 +00:00
umem old_bar_string_size = bar . string . size ;
bar . string = backspace_utf8 ( bar . string ) ;
string_change = ( bar . string . size < old_bar_string_size ) ;
}
2019-10-11 01:40:10 +00:00
else if ( has_modifier ( & in . event . key . modifiers , KeyCode_Control ) ) {
2019-10-01 22:45:51 +00:00
if ( bar . string . size > 0 ) {
string_change = true ;
bar . string . size = 0 ;
2018-06-16 20:57:32 +00:00
}
2017-03-29 16:32:06 +00:00
}
2019-10-01 22:45:51 +00:00
}
2019-10-10 22:57:02 +00:00
// TODO(allen): how to detect if the input corresponds to
// a search or rsearch command, a scroll wheel command?
2019-10-01 22:45:51 +00:00
b32 do_scan_action = false ;
2019-10-10 22:57:02 +00:00
b32 do_scroll_wheel = false ;
2019-10-01 22:45:51 +00:00
Scan_Direction change_scan = scan ;
if ( ! string_change ) {
2019-10-10 22:57:02 +00:00
if ( match_key_code ( & in , KeyCode_PageDown ) | |
2019-10-10 18:21:47 +00:00
match_key_code ( & in , KeyCode_Down ) ) {
2019-10-01 22:45:51 +00:00
change_scan = Scan_Forward ;
do_scan_action = true ;
}
2019-10-10 22:57:02 +00:00
if ( match_key_code ( & in , KeyCode_PageUp ) | |
2019-10-10 18:21:47 +00:00
match_key_code ( & in , KeyCode_Up ) ) {
2019-10-01 22:45:51 +00:00
change_scan = Scan_Backward ;
do_scan_action = true ;
2017-03-29 16:32:06 +00:00
}
2019-10-10 22:57:02 +00:00
#if 0
2019-10-10 18:21:47 +00:00
if ( in . command = = mouse_wheel_scroll ) {
2019-10-10 22:57:02 +00:00
do_scroll_wheel = true ;
2018-09-22 23:45:24 +00:00
}
2019-10-10 22:57:02 +00:00
# endif
2017-01-23 06:19:43 +00:00
}
2019-10-01 22:45:51 +00:00
if ( string_change ) {
switch ( scan ) {
case Scan_Forward :
{
i64 new_pos = 0 ;
2019-10-05 02:48:05 +00:00
seek_string_insensitive_forward ( app , buffer , pos - 1 , 0 , bar . string , & new_pos ) ;
2019-10-01 22:45:51 +00:00
if ( new_pos < buffer_size ) {
2017-01-23 06:19:43 +00:00
pos = new_pos ;
2019-10-01 22:45:51 +00:00
match_size = bar . string . size ;
2017-01-23 06:19:43 +00:00
}
2019-10-01 22:45:51 +00:00
} break ;
case Scan_Backward :
{
i64 new_pos = 0 ;
2019-10-05 02:48:05 +00:00
seek_string_insensitive_backward ( app , buffer , pos + 1 , 0 , bar . string , & new_pos ) ;
2019-10-01 22:45:51 +00:00
if ( new_pos > = 0 ) {
2017-01-23 06:19:43 +00:00
pos = new_pos ;
2019-10-01 22:45:51 +00:00
match_size = bar . string . size ;
2017-01-23 06:19:43 +00:00
}
2019-10-01 22:45:51 +00:00
} break ;
2017-01-23 06:19:43 +00:00
}
}
2019-10-01 22:45:51 +00:00
else if ( do_scan_action ) {
scan = change_scan ;
switch ( scan ) {
case Scan_Forward :
{
i64 new_pos = 0 ;
2019-10-05 02:48:05 +00:00
seek_string_insensitive_forward ( app , buffer , pos , 0 , bar . string , & new_pos ) ;
2019-10-01 22:45:51 +00:00
if ( new_pos < buffer_size ) {
pos = new_pos ;
match_size = bar . string . size ;
}
} break ;
case Scan_Backward :
{
i64 new_pos = 0 ;
2019-10-05 02:48:05 +00:00
seek_string_insensitive_backward ( app , buffer , pos , 0 , bar . string , & new_pos ) ;
2019-10-01 22:45:51 +00:00
if ( new_pos > = 0 ) {
pos = new_pos ;
match_size = bar . string . size ;
}
} break ;
2017-01-23 06:19:43 +00:00
}
}
2019-10-10 22:57:02 +00:00
else if ( do_scroll_wheel ) {
mouse_wheel_scroll ( app ) ;
}
else {
2019-10-14 22:57:47 +00:00
leave_current_input_unhandled ( app ) ;
2019-10-10 22:57:02 +00:00
}
2017-01-23 06:19:43 +00:00
}
2017-03-29 16:32:06 +00:00
2019-08-02 20:07:08 +00:00
view_disable_highlight_range ( app , view ) ;
2018-09-27 20:15:32 +00:00
2017-01-23 06:19:43 +00:00
if ( in . abort ) {
2019-06-01 23:58:28 +00:00
umem size = bar . string . size ;
size = clamp_top ( size , sizeof ( previous_isearch_query ) - 1 ) ;
block_copy ( previous_isearch_query , bar . string . str , size ) ;
previous_isearch_query [ size ] = 0 ;
2019-09-02 21:32:52 +00:00
view_set_cursor_and_preferred_x ( app , view , seek_pos ( first_pos ) ) ;
2017-01-23 06:19:43 +00:00
}
}
2019-10-12 04:21:47 +00:00
function void
isearch ( Application_Links * app , Scan_Direction start_scan , String_Const_u8 query_init ) {
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
2019-10-12 04:21:47 +00:00
i64 pos = view_get_cursor_pos ( app , view ) ; ;
isearch ( app , start_scan , pos , query_init ) ;
}
function void
isearch ( Application_Links * app , Scan_Direction start_scan ) {
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
2019-10-12 04:21:47 +00:00
i64 pos = view_get_cursor_pos ( app , view ) ; ;
isearch ( app , start_scan , pos , SCu8 ( ) ) ;
}
function void
isearch_identifier ( Application_Links * app , Scan_Direction scan ) {
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
Buffer_ID buffer_id = view_get_buffer ( app , view , Access_ReadVisible ) ;
2019-10-12 04:21:47 +00:00
i64 pos = view_get_cursor_pos ( app , view ) ;
Scratch_Block scratch ( app ) ;
Range_i64 range = enclose_pos_alpha_numeric_underscore ( app , buffer_id , pos ) ;
String_Const_u8 query = push_buffer_range ( app , scratch , buffer_id , range ) ;
isearch ( app , scan , range . first , query ) ;
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( search )
CUSTOM_DOC ( " Begins an incremental search down through the current buffer for a user specified string. " )
{
2019-10-12 04:21:47 +00:00
isearch ( app , Scan_Forward ) ;
2017-01-23 06:19:43 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( reverse_search )
CUSTOM_DOC ( " Begins an incremental search up through the current buffer for a user specified string. " )
{
2019-10-12 04:21:47 +00:00
isearch ( app , Scan_Backward ) ;
2017-03-29 16:32:06 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( search_identifier )
CUSTOM_DOC ( " Begins an incremental search down through the current buffer for the word or token under the cursor. " )
{
2019-10-12 04:21:47 +00:00
isearch_identifier ( app , Scan_Forward ) ;
2017-03-29 16:32:06 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( reverse_search_identifier )
CUSTOM_DOC ( " Begins an incremental search up through the current buffer for the word or token under the cursor. " )
{
2019-10-12 04:21:47 +00:00
isearch_identifier ( app , Scan_Backward ) ;
2017-01-23 06:19:43 +00:00
}
2019-07-13 00:43:17 +00:00
struct String_Pair {
b32 valid ;
String_Const_u8 a ;
String_Const_u8 b ;
} ;
internal String_Pair
query_user_replace_pair ( Application_Links * app , Arena * arena ) {
2019-07-13 03:19:24 +00:00
Query_Bar * replace = push_array ( arena , Query_Bar , 1 ) ;
u8 * replace_space = push_array ( arena , u8 , KB ( 1 ) ) ;
replace - > prompt = string_u8_litexpr ( " Replace: " ) ;
replace - > string = SCu8 ( replace_space , ( umem ) 0 ) ;
replace - > string_capacity = KB ( 1 ) ;
2017-01-23 06:19:43 +00:00
2019-07-13 03:19:24 +00:00
Query_Bar * with = push_array ( arena , Query_Bar , 1 ) ;
u8 * with_space = push_array ( arena , u8 , KB ( 1 ) ) ;
with - > prompt = string_u8_litexpr ( " With: " ) ;
with - > string = SCu8 ( with_space , ( umem ) 0 ) ;
with - > string_capacity = KB ( 1 ) ;
2017-01-23 06:19:43 +00:00
2019-07-13 00:43:17 +00:00
String_Pair result = { } ;
2019-07-13 03:19:24 +00:00
if ( query_user_string ( app , replace ) & & replace - > string . size ! = 0 & & query_user_string ( app , with ) ) {
2019-07-13 00:43:17 +00:00
result . valid = true ;
2019-07-13 03:19:24 +00:00
result . a = replace - > string ;
result . b = with - > string ;
2017-01-23 06:19:43 +00:00
}
2019-07-13 00:43:17 +00:00
return ( result ) ;
}
2019-07-13 03:19:24 +00:00
// NOTE(allen): This is a bit of a hacky setup because of Query_Bar lifetimes. This must be
// called as the last operation of a command.
2019-07-13 00:43:17 +00:00
internal void
replace_in_range_query_user ( Application_Links * app , Buffer_ID buffer , Range_i64 range ) {
Scratch_Block scratch ( app ) ;
2019-10-13 20:17:22 +00:00
Query_Bar_Group group ( app ) ;
2019-07-13 00:43:17 +00:00
String_Pair pair = query_user_replace_pair ( app , scratch ) ;
if ( pair . valid ) {
replace_in_range ( app , buffer , range , pair . a , pair . b ) ;
}
}
CUSTOM_COMMAND_SIG ( replace_in_range )
CUSTOM_DOC ( " Queries the user for a needle and string. Replaces all occurences of needle with string in the range between cursor and the mark in the active buffer. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadWriteVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadWriteVisible ) ;
2019-07-13 00:43:17 +00:00
Range_i64 range = get_view_range ( app , view ) ;
replace_in_range_query_user ( app , buffer , range ) ;
}
CUSTOM_COMMAND_SIG ( replace_in_buffer )
CUSTOM_DOC ( " Queries the user for a needle and string. Replaces all occurences of needle with string in the active buffer. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadWriteVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadWriteVisible ) ;
2019-07-13 00:43:17 +00:00
Range_i64 range = buffer_range ( app , buffer ) ;
replace_in_range_query_user ( app , buffer , range ) ;
}
CUSTOM_COMMAND_SIG ( replace_in_all_buffers )
CUSTOM_DOC ( " Queries the user for a needle and string. Replaces all occurences of needle with string in all editable buffers. " )
{
global_history_edit_group_begin ( app ) ;
Scratch_Block scratch ( app ) ;
2019-10-13 20:17:22 +00:00
Query_Bar_Group group ( app ) ;
2019-07-13 00:43:17 +00:00
String_Pair pair = query_user_replace_pair ( app , scratch ) ;
2019-10-18 02:54:02 +00:00
for ( Buffer_ID buffer = get_buffer_next ( app , 0 , Access_ReadWriteVisible ) ;
2019-07-13 00:43:17 +00:00
buffer ! = 0 ;
2019-10-18 02:54:02 +00:00
buffer = get_buffer_next ( app , buffer , Access_ReadWriteVisible ) ) {
2019-07-13 00:43:17 +00:00
Range_i64 range = buffer_range ( app , buffer ) ;
replace_in_range ( app , buffer , range , pair . a , pair . b ) ;
}
global_history_edit_group_end ( app ) ;
2017-01-23 06:19:43 +00:00
}
2019-10-15 22:30:06 +00:00
function void
2019-06-20 23:43:27 +00:00
query_replace_base ( Application_Links * app , View_ID view , Buffer_ID buffer_id , i64 pos , String_Const_u8 r , String_Const_u8 w ) {
i64 new_pos = 0 ;
2019-10-05 02:48:05 +00:00
seek_string_forward ( app , buffer_id , pos - 1 , 0 , r , & new_pos ) ;
2017-03-29 16:32:06 +00:00
2019-06-20 23:43:27 +00:00
i64 buffer_size = buffer_get_size ( app , buffer_id ) ;
2019-04-01 02:41:39 +00:00
2018-11-20 08:18:54 +00:00
User_Input in = { } ;
2019-04-01 02:41:39 +00:00
for ( ; new_pos < buffer_size ; ) {
2019-06-20 23:43:27 +00:00
Range_i64 match = Ii64 ( new_pos , new_pos + r . size ) ;
2019-08-02 20:07:08 +00:00
isearch__update_highlight ( app , view , match ) ;
2017-03-29 16:32:06 +00:00
2019-10-14 22:57:47 +00:00
in = get_next_input ( app , EventProperty_AnyKey , EventProperty_MouseButton ) ;
2019-10-10 18:21:47 +00:00
if ( in . abort | | match_key_code ( & in , KeyCode_Escape ) | | ! is_unmodified_key ( & in . event ) ) {
break ;
}
2017-03-29 16:32:06 +00:00
2019-10-10 18:21:47 +00:00
if ( match_key_code ( & in , KeyCode_Y ) | |
match_key_code ( & in , KeyCode_Return ) | |
match_key_code ( & in , KeyCode_Tab ) ) {
2019-04-05 23:30:24 +00:00
buffer_replace_range ( app , buffer_id , match , w ) ;
2019-06-20 23:43:27 +00:00
pos = match . start + w . size ;
2017-03-29 16:32:06 +00:00
}
else {
pos = match . max ;
}
2019-10-05 02:48:05 +00:00
seek_string_forward ( app , buffer_id , pos , 0 , r , & new_pos ) ;
2017-03-29 16:32:06 +00:00
}
2019-08-02 20:07:08 +00:00
view_disable_highlight_range ( app , view ) ;
2018-09-30 12:14:47 +00:00
if ( in . abort ) {
return ;
}
2017-03-29 16:32:06 +00:00
2019-09-02 21:32:52 +00:00
view_set_cursor_and_preferred_x ( app , view , seek_pos ( pos ) ) ;
2017-03-29 16:32:06 +00:00
}
2019-10-12 04:10:56 +00:00
function void
2019-06-20 23:43:27 +00:00
query_replace_parameter ( Application_Links * app , String_Const_u8 replace_str , i64 start_pos , b32 add_replace_query_bar ) {
2019-10-13 20:17:22 +00:00
Query_Bar_Group group ( app ) ;
2019-06-01 23:58:28 +00:00
Query_Bar replace = { } ;
replace . prompt = string_u8_litexpr ( " Replace: " ) ;
2017-11-21 18:25:19 +00:00
replace . string = replace_str ;
if ( add_replace_query_bar ) {
start_query_bar ( app , & replace , 0 ) ;
}
2017-01-23 06:19:43 +00:00
2019-06-01 23:58:28 +00:00
Query_Bar with = { } ;
u8 with_space [ 1024 ] ;
with . prompt = string_u8_litexpr ( " With: " ) ;
with . string = SCu8 ( with_space , ( umem ) 0 ) ;
with . string_capacity = sizeof ( with_space ) ;
2017-01-23 06:19:43 +00:00
2019-04-06 23:36:53 +00:00
if ( query_user_string ( app , & with ) ) {
2019-06-01 23:58:28 +00:00
String_Const_u8 r = replace . string ;
String_Const_u8 w = with . string ;
2019-04-06 23:36:53 +00:00
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadVisible ) ;
2019-06-20 23:43:27 +00:00
i64 pos = start_pos ;
2019-04-06 23:36:53 +00:00
2019-06-01 23:58:28 +00:00
Query_Bar bar = { } ;
bar . prompt = string_u8_litexpr ( " Replace? (y)es, (n)ext, (esc) \n " ) ;
2019-04-06 23:36:53 +00:00
start_query_bar ( app , & bar , 0 ) ;
2019-06-19 02:31:59 +00:00
query_replace_base ( app , view , buffer , pos , r , w ) ;
2018-09-30 12:14:47 +00:00
}
2017-03-29 16:32:06 +00:00
}
2017-11-21 18:25:19 +00:00
CUSTOM_COMMAND_SIG ( query_replace )
CUSTOM_DOC ( " Queries the user for two strings, and incrementally replaces every occurence of the first string with the second string. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadWriteVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadWriteVisible ) ;
2019-04-05 02:03:36 +00:00
if ( buffer ! = 0 ) {
2019-10-13 20:17:22 +00:00
Query_Bar_Group group ( app ) ;
2019-04-05 02:03:36 +00:00
Query_Bar replace = { } ;
2019-06-01 23:58:28 +00:00
u8 replace_space [ 1024 ] ;
replace . prompt = string_u8_litexpr ( " Replace: " ) ;
replace . string = SCu8 ( replace_space , ( umem ) 0 ) ;
replace . string_capacity = sizeof ( replace_space ) ;
2019-04-05 02:03:36 +00:00
if ( query_user_string ( app , & replace ) ) {
if ( replace . string . size > 0 ) {
2019-06-20 23:43:27 +00:00
i64 pos = view_get_cursor_pos ( app , view ) ;
2019-04-06 23:36:53 +00:00
query_replace_parameter ( app , replace . string , pos , false ) ;
2019-04-05 02:03:36 +00:00
}
}
2018-09-30 12:14:47 +00:00
}
2017-11-21 18:25:19 +00:00
}
2017-11-15 23:57:21 +00:00
CUSTOM_COMMAND_SIG ( query_replace_identifier )
CUSTOM_DOC ( " Queries the user for a string, and incrementally replace every occurence of the word or token found at the cursor with the specified string. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadWriteVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadWriteVisible ) ;
2019-06-09 21:05:57 +00:00
if ( buffer ! = 0 ) {
2019-06-01 23:58:28 +00:00
Scratch_Block scratch ( app ) ;
2019-06-20 23:43:27 +00:00
i64 pos = view_get_cursor_pos ( app , view ) ;
Range_i64 range = enclose_pos_alpha_numeric_underscore ( app , buffer , pos ) ;
2019-06-09 21:05:57 +00:00
String_Const_u8 replace = push_buffer_range ( app , scratch , buffer , range ) ;
2019-04-05 02:03:36 +00:00
if ( replace . size ! = 0 ) {
query_replace_parameter ( app , replace , range . min , true ) ;
}
2017-01-23 06:19:43 +00:00
}
}
2018-05-10 03:55:00 +00:00
CUSTOM_COMMAND_SIG ( query_replace_selection )
CUSTOM_DOC ( " Queries the user for a string, and incrementally replace every occurence of the string found in the selected range with the specified string. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadWriteVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadWriteVisible ) ;
2019-04-05 02:03:36 +00:00
if ( buffer ! = 0 ) {
2019-06-20 23:43:27 +00:00
Scratch_Block scratch ( app ) ;
Range_i64 range = get_view_range ( app , view ) ;
String_Const_u8 replace = push_buffer_range ( app , scratch , buffer , range ) ;
if ( replace . size ! = 0 ) {
query_replace_parameter ( app , replace , range . min , true ) ;
2018-05-10 03:55:00 +00:00
}
}
}
2018-05-10 08:12:47 +00:00
////////////////////////////////
2017-02-12 23:04:50 +00:00
2019-10-15 22:30:06 +00:00
function void
2019-06-01 23:58:28 +00:00
delete_file_base ( Application_Links * app , String_Const_u8 file_name , Buffer_ID buffer_id ) {
String_Const_u8 path = string_remove_last_folder ( file_name ) ;
Scratch_Block scratch ( app ) ;
List_String_Const_u8 list = { } ;
# if OS_WINDOWS
string_list_push_u8_lit ( scratch , & list , " del " ) ;
# elif OS_LINUX || OS_MAC
string_list_push_u8_lit ( scratch , & list , " rm " ) ;
2017-11-21 21:30:40 +00:00
# else
# error no delete file command for this platform
# endif
2019-06-01 23:58:28 +00:00
string_list_pushf ( scratch , & list , " \" %.*s \" " , string_expand ( file_name ) ) ;
String_Const_u8 cmd = string_list_flatten ( scratch , list , StringFill_NullTerminate ) ;
exec_system_command ( app , 0 , buffer_identifier ( 0 ) , path , cmd , 0 ) ;
2019-06-19 02:31:59 +00:00
buffer_kill ( app , buffer_id , BufferKill_AlwaysKill ) ;
2017-11-21 21:30:40 +00:00
}
CUSTOM_COMMAND_SIG ( delete_file_query )
CUSTOM_DOC ( " Deletes the file of the current buffer if 4coder has the appropriate access rights. Will ask the user for confirmation first. " )
2017-11-21 19:48:04 +00:00
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_Always ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_Always ) ;
2019-06-01 23:58:28 +00:00
Scratch_Block scratch ( app ) ;
2019-06-02 03:07:57 +00:00
String_Const_u8 file_name = push_buffer_file_name ( app , scratch , buffer ) ;
2019-04-05 02:03:36 +00:00
if ( file_name . size > 0 ) {
2019-10-13 20:17:22 +00:00
Query_Bar_Group group ( app ) ;
2019-06-01 23:58:28 +00:00
Query_Bar bar = { } ;
2019-06-18 22:56:09 +00:00
bar . prompt = push_u8_stringf ( scratch , " Delete '%.*s' (Y)es, (n)o " , string_expand ( file_name ) ) ;
2019-04-05 02:03:36 +00:00
if ( start_query_bar ( app , & bar , 0 ) ! = 0 ) {
2019-06-01 23:58:28 +00:00
b32 cancelled = false ;
for ( ; ! cancelled ; ) {
2019-10-14 22:57:47 +00:00
User_Input in = get_next_input ( app , EventProperty_AnyKey , 0 ) ;
2019-10-10 22:57:02 +00:00
if ( in . abort ) {
cancelled = true ;
}
else {
switch ( in . event . key . code ) {
case KeyCode_Y :
{
delete_file_base ( app , file_name , buffer ) ;
cancelled = true ;
} break ;
case KeyCode_Shift :
case KeyCode_Control :
case KeyCode_Alt :
case KeyCode_Command :
case KeyCode_CapsLock :
{ } break ;
default :
{
cancelled = true ;
} break ;
}
2019-06-01 23:58:28 +00:00
}
2019-04-05 02:03:36 +00:00
}
}
2017-11-21 21:30:40 +00:00
}
}
2018-03-24 10:06:45 +00:00
CUSTOM_COMMAND_SIG ( save_to_query )
2018-09-15 23:48:02 +00:00
CUSTOM_DOC ( " Queries the user for a file name and saves the contents of the current buffer, altering the buffer's name too. " )
2018-03-24 10:06:45 +00:00
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_Always ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_Always ) ;
2018-03-24 10:06:45 +00:00
2019-10-01 02:06:21 +00:00
Scratch_Block scratch ( app ) ;
2019-10-13 20:17:22 +00:00
Query_Bar_Group group ( app ) ;
2019-06-02 03:07:57 +00:00
String_Const_u8 buffer_name = push_buffer_unique_name ( app , scratch , buffer ) ;
2018-03-24 10:06:45 +00:00
2019-04-05 02:03:36 +00:00
// Query the user
2019-06-01 23:58:28 +00:00
u8 name_space [ 4096 ] ;
2019-04-05 02:03:36 +00:00
Query_Bar bar = { } ;
2019-06-18 22:56:09 +00:00
bar . prompt = push_u8_stringf ( scratch , " Save '%.*s' to: " , string_expand ( buffer_name ) ) ;
2019-06-01 23:58:28 +00:00
bar . string = SCu8 ( name_space , ( umem ) 0 ) ;
bar . string_capacity = sizeof ( name_space ) ;
2019-04-05 02:03:36 +00:00
if ( query_user_string ( app , & bar ) ) {
if ( bar . string . size ! = 0 ) {
2019-06-01 23:58:28 +00:00
List_String_Const_u8 new_file_name_list = { } ;
string_list_push ( scratch , & new_file_name_list , push_hot_directory ( app , scratch ) ) ;
string_list_push ( scratch , & new_file_name_list , bar . string ) ;
String_Const_u8 new_file_name = string_list_flatten ( scratch , new_file_name_list ) ;
if ( buffer_save ( app , buffer , new_file_name , BufferSave_IgnoreDirtyFlag ) ) {
2019-06-19 02:31:59 +00:00
Buffer_ID new_buffer = create_buffer ( app , new_file_name , BufferCreate_NeverNew | BufferCreate_JustChangedFile ) ;
2019-06-01 23:58:28 +00:00
if ( new_buffer ! = 0 & & new_buffer ! = buffer ) {
2019-06-19 02:31:59 +00:00
buffer_kill ( app , buffer , BufferKill_AlwaysKill ) ;
2019-06-01 23:58:28 +00:00
view_set_buffer ( app , view , new_buffer , 0 ) ;
2018-03-24 10:06:45 +00:00
}
}
}
}
}
2017-11-21 21:30:40 +00:00
CUSTOM_COMMAND_SIG ( rename_file_query )
CUSTOM_DOC ( " Queries the user for a new name and renames the file of the current buffer, altering the buffer's name too. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_Always ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_Always ) ;
2019-04-05 02:03:36 +00:00
2019-10-01 02:06:21 +00:00
Scratch_Block scratch ( app ) ;
2019-04-05 02:03:36 +00:00
2019-06-02 03:07:57 +00:00
String_Const_u8 file_name = push_buffer_file_name ( app , scratch , buffer ) ;
2019-04-05 02:03:36 +00:00
if ( file_name . size > 0 ) {
// Query the user
2019-10-13 20:17:22 +00:00
Query_Bar_Group group ( app ) ;
2019-06-01 23:58:28 +00:00
String_Const_u8 front = string_front_of_path ( file_name ) ;
u8 name_space [ 4096 ] ;
2019-04-05 02:03:36 +00:00
Query_Bar bar = { } ;
2019-06-18 22:56:09 +00:00
bar . prompt = push_u8_stringf ( scratch , " Rename '%.*s' to: " , string_expand ( front ) ) ;
2019-06-01 23:58:28 +00:00
bar . string = SCu8 ( name_space , ( umem ) 0 ) ;
bar . string_capacity = sizeof ( name_space ) ;
2019-04-05 02:03:36 +00:00
if ( query_user_string ( app , & bar ) ) {
if ( bar . string . size ! = 0 ) {
// TODO(allen): There should be a way to say, "detach a buffer's file" and "attach this file to a buffer"
2019-06-01 23:58:28 +00:00
List_String_Const_u8 new_file_name_list = { } ;
string_list_push ( scratch , & new_file_name_list , file_name ) ;
string_list_push ( scratch , & new_file_name_list , bar . string ) ;
String_Const_u8 new_file_name = string_list_flatten ( scratch , new_file_name_list , StringFill_NullTerminate ) ;
2019-04-05 02:03:36 +00:00
if ( buffer_save ( app , buffer , new_file_name , BufferSave_IgnoreDirtyFlag ) ) {
2019-06-19 02:31:59 +00:00
Buffer_ID new_buffer = create_buffer ( app , new_file_name , BufferCreate_NeverNew | BufferCreate_JustChangedFile ) ;
2019-04-05 02:03:36 +00:00
if ( new_buffer ! = 0 & & new_buffer ! = buffer ) {
delete_file_base ( app , file_name , buffer ) ;
2019-04-06 23:36:53 +00:00
view_set_buffer ( app , view , new_buffer , 0 ) ;
2019-04-05 02:03:36 +00:00
}
2018-12-16 00:22:28 +00:00
}
2017-11-21 21:30:40 +00:00
}
}
2019-04-05 02:03:36 +00:00
2017-11-21 19:48:04 +00:00
}
}
2017-11-21 21:47:40 +00:00
CUSTOM_COMMAND_SIG ( make_directory_query )
CUSTOM_DOC ( " Queries the user for a name and creates a new directory with the given name. " )
{
2019-06-01 23:58:28 +00:00
Scratch_Block scratch ( app ) ;
String_Const_u8 hot = push_hot_directory ( app , scratch ) ;
// Query the user
2019-10-13 20:17:22 +00:00
Query_Bar_Group group ( app ) ;
2019-06-01 23:58:28 +00:00
u8 name_space [ 4096 ] ;
Query_Bar bar = { } ;
2019-06-18 22:56:09 +00:00
bar . prompt = push_u8_stringf ( scratch , " Make directory at '%.*s': " , string_expand ( hot ) ) ;
2019-06-01 23:58:28 +00:00
bar . string = SCu8 ( name_space , ( umem ) 0 ) ;
bar . string_capacity = sizeof ( name_space ) ;
if ( ! query_user_string ( app , & bar ) ) return ;
if ( bar . string . size = = 0 ) return ;
2019-06-18 22:56:09 +00:00
String_Const_u8 cmd = push_u8_stringf ( scratch , " mkdir %.*s " , string_expand ( bar . string ) ) ;
2019-06-01 23:58:28 +00:00
exec_system_command ( app , 0 , buffer_identifier ( 0 ) , hot , cmd , 0 ) ;
2017-11-21 21:47:40 +00:00
}
2018-05-10 08:12:47 +00:00
////////////////////////////////
2019-06-14 22:01:50 +00:00
internal void
current_view_move_line ( Application_Links * app , Scan_Direction direction ) {
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadWriteVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadWriteVisible ) ;
2019-06-20 23:43:27 +00:00
i64 pos = view_get_cursor_pos ( app , view ) ;
i64 line_number = get_line_number_from_pos ( app , buffer , pos ) ;
2019-06-14 22:01:50 +00:00
pos = move_line ( app , buffer , line_number , direction ) ;
2019-09-02 21:32:52 +00:00
view_set_cursor_and_preferred_x ( app , view , seek_pos ( pos ) ) ;
2019-06-14 22:01:50 +00:00
}
2018-05-10 08:12:47 +00:00
CUSTOM_COMMAND_SIG ( move_line_up )
CUSTOM_DOC ( " Swaps the line under the cursor with the line above it, and moves the cursor up with it. " )
{
2019-06-14 22:01:50 +00:00
current_view_move_line ( app , Scan_Backward ) ;
2018-05-10 08:12:47 +00:00
}
CUSTOM_COMMAND_SIG ( move_line_down )
CUSTOM_DOC ( " Swaps the line under the cursor with the line below it, and moves the cursor down with it. " )
{
2019-06-14 22:01:50 +00:00
current_view_move_line ( app , Scan_Forward ) ;
2018-05-10 08:12:47 +00:00
}
CUSTOM_COMMAND_SIG ( duplicate_line )
CUSTOM_DOC ( " Create a copy of the line on which the cursor sits. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadWriteVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadWriteVisible ) ;
2019-06-20 23:43:27 +00:00
i64 pos = view_get_cursor_pos ( app , view ) ;
i64 line = get_line_number_from_pos ( app , buffer , pos ) ;
2019-06-01 23:58:28 +00:00
Scratch_Block scratch ( app ) ;
2019-06-14 22:01:50 +00:00
String_Const_u8 s = push_buffer_line ( app , scratch , buffer , line ) ;
2019-06-18 22:56:09 +00:00
s = push_u8_stringf ( scratch , " %.*s \n " , string_expand ( s ) ) ;
2019-06-16 23:38:22 +00:00
pos = get_line_side_pos ( app , buffer , line , Side_Min ) ;
2019-06-20 23:43:27 +00:00
buffer_replace_range ( app , buffer , Ii64 ( pos ) , s ) ;
2018-05-10 08:12:47 +00:00
}
CUSTOM_COMMAND_SIG ( delete_line )
CUSTOM_DOC ( " Delete the line the on which the cursor sits. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadWriteVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadWriteVisible ) ;
2019-06-20 23:43:27 +00:00
i64 pos = view_get_cursor_pos ( app , view ) ;
i64 line = get_line_number_from_pos ( app , buffer , pos ) ;
Range_i64 range = get_line_pos_range ( app , buffer , line ) ;
2019-06-14 22:01:50 +00:00
range . end + = 1 ;
2019-06-19 02:31:59 +00:00
i32 size = ( i32 ) buffer_get_size ( app , buffer ) ;
2019-06-14 22:01:50 +00:00
range . end = clamp_top ( range . end , size ) ;
if ( range_size ( range ) = = 0 | |
buffer_get_char ( app , buffer , range . end - 1 ) ! = ' \n ' ) {
2019-06-02 03:07:57 +00:00
range . start - = 1 ;
range . first = clamp_bot ( 0 , range . first ) ;
2018-05-10 08:12:47 +00:00
}
2019-06-02 03:07:57 +00:00
buffer_replace_range ( app , buffer , range , string_u8_litexpr ( " " ) ) ;
2018-05-10 08:12:47 +00:00
}
////////////////////////////////
2017-01-23 06:19:43 +00:00
2019-10-15 22:30:06 +00:00
function b32
2019-04-04 08:25:16 +00:00
get_cpp_matching_file ( Application_Links * app , Buffer_ID buffer , Buffer_ID * buffer_out ) {
2019-02-26 23:08:42 +00:00
b32 result = false ;
2019-06-01 23:58:28 +00:00
Scratch_Block scratch ( app ) ;
2019-06-02 03:07:57 +00:00
String_Const_u8 file_name = push_buffer_file_name ( app , scratch , buffer ) ;
2019-04-04 08:25:16 +00:00
if ( file_name . size > 0 ) {
2019-06-01 23:58:28 +00:00
String_Const_u8 extension = string_file_extension ( file_name ) ;
String_Const_u8 new_extensions [ 2 ] = { } ;
2019-02-26 23:17:53 +00:00
i32 new_extensions_count = 0 ;
2019-06-01 23:58:28 +00:00
if ( string_match ( extension , string_u8_litexpr ( " cpp " ) ) | | string_match ( extension , string_u8_litexpr ( " cc " ) ) ) {
new_extensions [ 0 ] = string_u8_litexpr ( " h " ) ;
new_extensions [ 1 ] = string_u8_litexpr ( " hpp " ) ;
2018-05-11 20:46:26 +00:00
new_extensions_count = 2 ;
}
2019-06-01 23:58:28 +00:00
else if ( string_match ( extension , string_u8_litexpr ( " c " ) ) ) {
new_extensions [ 0 ] = string_u8_litexpr ( " h " ) ;
2018-05-11 20:46:26 +00:00
new_extensions_count = 1 ;
}
2019-06-01 23:58:28 +00:00
else if ( string_match ( extension , string_u8_litexpr ( " h " ) ) ) {
new_extensions [ 0 ] = string_u8_litexpr ( " c " ) ;
new_extensions [ 1 ] = string_u8_litexpr ( " cpp " ) ;
2018-05-11 20:46:26 +00:00
new_extensions_count = 2 ;
}
2019-06-01 23:58:28 +00:00
else if ( string_match ( extension , string_u8_litexpr ( " hpp " ) ) ) {
new_extensions [ 0 ] = string_u8_litexpr ( " cpp " ) ;
2018-05-11 20:46:26 +00:00
new_extensions_count = 1 ;
}
2019-06-01 23:58:28 +00:00
String_Const_u8 file_without_extension = string_file_without_extension ( file_name ) ;
for ( i32 i = 0 ; i < new_extensions_count ; i + = 1 ) {
Temp_Memory temp = begin_temp ( scratch ) ;
String_Const_u8 new_extension = new_extensions [ i ] ;
2019-06-18 22:56:09 +00:00
String_Const_u8 new_file_name = push_u8_stringf ( scratch , " %.*s.%.*s " , string_expand ( file_without_extension ) , string_expand ( new_extension ) ) ;
2019-06-01 23:58:28 +00:00
if ( open_file ( app , buffer_out , new_file_name , false , true ) ) {
result = true ;
break ;
}
end_temp ( temp ) ;
}
2018-05-11 20:46:26 +00:00
}
return ( result ) ;
}
CUSTOM_COMMAND_SIG ( open_file_in_quotes )
CUSTOM_DOC ( " Reads a filename from surrounding ' \" ' characters and attempts to open the corresponding file. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadVisible ) ;
2019-06-20 23:43:27 +00:00
if ( buffer_exists ( app , buffer ) ) {
2019-06-01 23:58:28 +00:00
Scratch_Block scratch ( app ) ;
2019-04-01 02:41:39 +00:00
2019-06-20 23:43:27 +00:00
i64 pos = view_get_cursor_pos ( app , view ) ;
2019-04-06 23:36:53 +00:00
2019-06-20 23:43:27 +00:00
Range_i64 range = enclose_pos_inside_quotes ( app , buffer , pos ) ;
2019-04-06 23:36:53 +00:00
2019-06-20 23:43:27 +00:00
String_Const_u8 quoted_name = push_buffer_range ( app , scratch , buffer , range ) ;
2019-06-01 23:58:28 +00:00
2019-06-20 23:43:27 +00:00
String_Const_u8 file_name = push_buffer_file_name ( app , scratch , buffer ) ;
2019-06-01 23:58:28 +00:00
String_Const_u8 path = string_remove_last_folder ( file_name ) ;
if ( character_is_slash ( string_get_character ( path , path . size - 1 ) ) ) {
path = string_chop ( path , 1 ) ;
2018-05-11 20:46:26 +00:00
}
2019-04-06 23:36:53 +00:00
2019-06-18 22:56:09 +00:00
String_Const_u8 new_file_name = push_u8_stringf ( scratch , " %.*s/%.*s " , string_expand ( path ) , string_expand ( quoted_name ) ) ;
2019-06-01 23:58:28 +00:00
2019-10-18 02:54:02 +00:00
view = get_next_view_looped_primary_panels ( app , view , Access_Always ) ;
2019-06-01 23:58:28 +00:00
if ( view ! = 0 ) {
if ( view_open_file ( app , view , new_file_name , true ) ) {
view_set_active ( app , view ) ;
}
}
2018-05-11 20:46:26 +00:00
}
}
CUSTOM_COMMAND_SIG ( open_matching_file_cpp )
CUSTOM_DOC ( " If the current file is a *.cpp or *.h, attempts to open the corresponding *.h or *.cpp file in the other view. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_Always ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_Always ) ;
2019-04-04 08:25:16 +00:00
Buffer_ID new_buffer = 0 ;
2018-05-11 20:46:26 +00:00
if ( get_cpp_matching_file ( app , buffer , & new_buffer ) ) {
2019-10-18 02:54:02 +00:00
view = get_next_view_looped_primary_panels ( app , view , Access_Always ) ;
2019-04-06 23:36:53 +00:00
view_set_buffer ( app , view , new_buffer , 0 ) ;
view_set_active ( app , view ) ;
2018-05-11 20:46:26 +00:00
}
}
CUSTOM_COMMAND_SIG ( view_buffer_other_panel )
CUSTOM_DOC ( " Set the other non-active panel to view the buffer that the active panel views, and switch to that panel. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_Always ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_Always ) ;
2019-06-20 23:43:27 +00:00
i64 pos = view_get_cursor_pos ( app , view ) ;
2018-05-11 20:46:26 +00:00
change_active_panel ( app ) ;
2019-10-18 02:54:02 +00:00
view = get_active_view ( app , Access_Always ) ;
2019-04-06 23:36:53 +00:00
view_set_buffer ( app , view , buffer , 0 ) ;
2019-09-02 21:32:52 +00:00
view_set_cursor_and_preferred_x ( app , view , seek_pos ( pos ) ) ;
2018-05-11 20:46:26 +00:00
}
2019-11-08 04:58:13 +00:00
CUSTOM_COMMAND_SIG ( swap_panels )
CUSTOM_DOC ( " Swaps the active panel with it's sibling. " )
2018-05-11 20:46:26 +00:00
{
2019-11-08 04:58:13 +00:00
View_ID view = get_active_view ( app , Access_Always ) ;
Panel_ID panel = view_get_panel ( app , view ) ;
Panel_ID parent = panel_get_parent ( app , panel ) ;
for ( ; parent ! = 0 ; ) {
Panel_ID child_1 = panel_get_child ( app , parent , Side_Min ) ;
Panel_ID child_2 = panel_get_child ( app , parent , Side_Max ) ;
View_ID view_1 = panel_get_view ( app , child_1 , Access_Always ) ;
View_ID view_2 = panel_get_view ( app , child_2 , Access_Always ) ;
if ( ! view_get_is_passive ( app , view_1 ) & & ! view_get_is_passive ( app , view_2 ) ) {
panel_swap_children ( app , parent ) ;
break ;
2018-06-08 22:51:36 +00:00
}
2019-11-08 04:58:13 +00:00
parent = panel_get_parent ( app , parent ) ;
2018-05-11 20:46:26 +00:00
}
}
////////////////////////////////
2018-08-05 07:09:18 +00:00
CUSTOM_COMMAND_SIG ( kill_buffer )
CUSTOM_DOC ( " Kills the current buffer. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadVisible ) ;
2019-06-19 02:31:59 +00:00
try_buffer_kill ( app , buffer , view , 0 ) ;
2018-08-05 07:09:18 +00:00
}
2018-11-21 07:48:42 +00:00
CUSTOM_COMMAND_SIG ( save )
CUSTOM_DOC ( " Saves the current buffer. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadVisible ) ;
2019-10-01 02:06:21 +00:00
Scratch_Block scratch ( app ) ;
2019-06-02 03:07:57 +00:00
String_Const_u8 file_name = push_buffer_file_name ( app , scratch , buffer ) ;
2019-04-05 02:03:36 +00:00
buffer_save ( app , buffer , file_name , 0 ) ;
2018-11-21 07:48:42 +00:00
}
CUSTOM_COMMAND_SIG ( reopen )
CUSTOM_DOC ( " Reopen the current buffer from the hard drive. " )
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadVisible ) ;
2019-06-19 02:31:59 +00:00
buffer_reopen ( app , buffer , 0 ) ;
2018-11-21 07:48:42 +00:00
}
2018-08-05 07:09:18 +00:00
////////////////////////////////
2019-10-01 19:04:15 +00:00
internal i32
2019-03-22 05:06:30 +00:00
record_get_new_cursor_position_undo ( Application_Links * app , Buffer_ID buffer_id , History_Record_Index index , Record_Info record ) {
i32 new_edit_position = 0 ;
switch ( record . kind ) {
default :
case RecordKind_Single :
{
2019-06-20 04:45:58 +00:00
new_edit_position = ( i32 ) ( record . single . first + record . single . string_backward . size ) ;
2019-03-22 05:06:30 +00:00
} break ;
case RecordKind_Group :
{
2019-06-20 04:45:58 +00:00
Record_Info sub_record = buffer_history_get_group_sub_record ( app , buffer_id , index , 0 ) ;
new_edit_position = ( i32 ) ( sub_record . single . first + sub_record . single . string_backward . size ) ;
2019-03-22 05:06:30 +00:00
} break ;
}
return ( new_edit_position ) ;
}
2019-10-01 19:04:15 +00:00
internal i32
2019-03-22 05:06:30 +00:00
record_get_new_cursor_position_undo ( Application_Links * app , Buffer_ID buffer_id , History_Record_Index index ) {
2019-06-20 04:45:58 +00:00
Record_Info record = buffer_history_get_record_info ( app , buffer_id , index ) ;
2019-03-22 05:06:30 +00:00
return ( record_get_new_cursor_position_undo ( app , buffer_id , index , record ) ) ;
}
2019-10-01 19:04:15 +00:00
internal i32
2019-03-22 05:06:30 +00:00
record_get_new_cursor_position_redo ( Application_Links * app , Buffer_ID buffer_id , History_Record_Index index , Record_Info record ) {
2019-06-20 04:45:58 +00:00
i64 new_edit_position = 0 ;
2019-03-22 05:06:30 +00:00
switch ( record . kind ) {
default :
case RecordKind_Single :
{
2019-06-20 04:45:58 +00:00
new_edit_position = record . single . first + record . single . string_forward . size ;
2019-03-22 05:06:30 +00:00
} break ;
case RecordKind_Group :
{
2019-06-20 04:45:58 +00:00
Record_Info sub_record = buffer_history_get_group_sub_record ( app , buffer_id , index , record . group . count - 1 ) ;
new_edit_position = sub_record . single . first + sub_record . single . string_forward . size ;
2019-03-22 05:06:30 +00:00
} break ;
}
2019-06-20 04:45:58 +00:00
return ( ( i32 ) ( new_edit_position ) ) ;
2019-03-22 05:06:30 +00:00
}
2019-10-01 19:04:15 +00:00
internal i32
2019-03-22 05:06:30 +00:00
record_get_new_cursor_position_redo ( Application_Links * app , Buffer_ID buffer_id , History_Record_Index index ) {
2019-06-20 04:45:58 +00:00
Record_Info record = buffer_history_get_record_info ( app , buffer_id , index ) ;
2019-03-22 05:06:30 +00:00
return ( record_get_new_cursor_position_redo ( app , buffer_id , index , record ) ) ;
}
2019-04-07 17:36:24 +00:00
CUSTOM_COMMAND_SIG ( undo )
2019-02-12 03:03:49 +00:00
CUSTOM_DOC ( " Advances backwards through the undo history of the current buffer. " )
2017-11-15 23:57:21 +00:00
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadWriteVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadWriteVisible ) ;
2019-06-20 04:45:58 +00:00
History_Record_Index current = buffer_history_get_current_state_index ( app , buffer ) ;
2019-02-08 10:03:48 +00:00
if ( current > 0 ) {
2019-04-06 23:36:53 +00:00
i32 new_position = record_get_new_cursor_position_undo ( app , buffer , current ) ;
buffer_history_set_current_state_index ( app , buffer , current - 1 ) ;
2019-09-02 21:32:52 +00:00
view_set_cursor_and_preferred_x ( app , view , seek_pos ( new_position ) ) ;
2019-02-08 10:03:48 +00:00
}
2017-01-23 06:19:43 +00:00
}
2019-04-07 17:36:24 +00:00
CUSTOM_COMMAND_SIG ( redo )
2019-02-12 03:03:49 +00:00
CUSTOM_DOC ( " Advances forwards through the undo history of the current buffer. " )
2019-02-08 10:03:48 +00:00
{
2019-10-18 02:54:02 +00:00
View_ID view = get_active_view ( app , Access_ReadWriteVisible ) ;
Buffer_ID buffer = view_get_buffer ( app , view , Access_ReadWriteVisible ) ;
2019-06-20 04:45:58 +00:00
History_Record_Index current = buffer_history_get_current_state_index ( app , buffer ) ;
History_Record_Index max_index = buffer_history_get_max_record_index ( app , buffer ) ;
2019-02-08 10:03:48 +00:00
if ( current < max_index ) {
2019-04-06 23:36:53 +00:00
i32 new_position = record_get_new_cursor_position_redo ( app , buffer , current + 1 ) ;
buffer_history_set_current_state_index ( app , buffer , current + 1 ) ;
2019-09-02 21:32:52 +00:00
view_set_cursor_and_preferred_x ( app , view , seek_pos ( new_position ) ) ;
2019-02-12 03:03:49 +00:00
}
}
2019-04-07 17:36:24 +00:00
CUSTOM_COMMAND_SIG ( undo_all_buffers )
2019-02-12 03:03:49 +00:00
CUSTOM_DOC ( " Advances backward through the undo history in the buffer containing the most recent regular edit. " )
{
2019-10-01 02:06:21 +00:00
Scratch_Block scratch ( app , Scratch_Share ) ;
2019-02-26 23:17:53 +00:00
i32 highest_edit_number = - 1 ;
2019-02-12 03:03:49 +00:00
Buffer_ID first_buffer_match = 0 ;
Buffer_ID last_buffer_match = 0 ;
2019-02-26 23:17:53 +00:00
i32 match_count = 0 ;
2019-02-12 03:03:49 +00:00
2019-04-05 21:18:16 +00:00
{
2019-10-18 02:54:02 +00:00
for ( Buffer_ID buffer = get_buffer_next ( app , 0 , Access_Always ) ;
2019-04-05 21:18:16 +00:00
buffer ! = 0 ;
2019-10-18 02:54:02 +00:00
buffer = get_buffer_next ( app , buffer , Access_Always ) ) {
2019-06-20 04:45:58 +00:00
History_Record_Index index = buffer_history_get_current_state_index ( app , buffer ) ;
2019-04-05 21:18:16 +00:00
if ( index > 0 ) {
2019-06-20 04:45:58 +00:00
Record_Info record = buffer_history_get_record_info ( app , buffer , index ) ;
2019-04-05 21:18:16 +00:00
if ( record . edit_number > highest_edit_number ) {
highest_edit_number = record . edit_number ;
first_buffer_match = buffer ;
last_buffer_match = buffer ;
match_count = 1 ;
}
else if ( record . edit_number = = highest_edit_number ) {
last_buffer_match = buffer ;
match_count + = 1 ;
}
2019-02-12 03:03:49 +00:00
}
}
}
2019-02-12 03:10:42 +00:00
Buffer_ID * match_buffers = push_array ( scratch , Buffer_ID , match_count ) ;
2019-03-22 05:06:30 +00:00
i32 * new_positions = push_array ( scratch , i32 , match_count ) ;
2019-02-12 03:10:42 +00:00
match_count = 0 ;
2019-02-12 03:03:49 +00:00
if ( highest_edit_number ! = - 1 ) {
2019-04-05 02:03:36 +00:00
for ( Buffer_ID buffer = first_buffer_match ;
buffer ! = 0 ;
2019-10-18 02:54:02 +00:00
buffer = get_buffer_next ( app , buffer , Access_Always ) ) {
2019-02-26 23:08:42 +00:00
b32 did_match = false ;
2019-03-22 05:06:30 +00:00
i32 new_edit_position = 0 ;
2019-02-12 03:03:49 +00:00
for ( ; ; ) {
2019-06-20 04:45:58 +00:00
History_Record_Index index = buffer_history_get_current_state_index ( app , buffer ) ;
2019-02-12 03:03:49 +00:00
if ( index > 0 ) {
2019-06-20 04:45:58 +00:00
Record_Info record = buffer_history_get_record_info ( app , buffer , index ) ;
2019-02-12 03:03:49 +00:00
if ( record . edit_number = = highest_edit_number ) {
2019-02-12 03:10:42 +00:00
did_match = true ;
2019-04-05 02:03:36 +00:00
new_edit_position = record_get_new_cursor_position_undo ( app , buffer , index , record ) ;
buffer_history_set_current_state_index ( app , buffer , index - 1 ) ;
2019-02-12 03:03:49 +00:00
}
else {
break ;
}
}
else {
break ;
}
}
2019-02-12 03:10:42 +00:00
if ( did_match ) {
2019-04-05 02:03:36 +00:00
match_buffers [ match_count ] = buffer ;
2019-03-22 05:06:30 +00:00
new_positions [ match_count ] = new_edit_position ;
2019-02-12 03:10:42 +00:00
match_count + = 1 ;
}
2019-04-05 02:03:36 +00:00
if ( buffer = = last_buffer_match ) {
2019-02-12 03:03:49 +00:00
break ;
}
}
}
2019-02-12 03:10:42 +00:00
2019-03-22 05:06:30 +00:00
view_buffer_set ( app , match_buffers , new_positions , match_count ) ;
2019-02-12 03:03:49 +00:00
}
2019-04-07 17:36:24 +00:00
CUSTOM_COMMAND_SIG ( redo_all_buffers )
2019-02-12 03:03:49 +00:00
CUSTOM_DOC ( " Advances forward through the undo history in the buffer containing the most recent regular edit. " )
{
2019-10-01 02:06:21 +00:00
Scratch_Block scratch ( app , Scratch_Share ) ;
2019-02-26 23:17:53 +00:00
i32 lowest_edit_number = 0x7FFFFFFF ;
2019-02-12 03:03:49 +00:00
Buffer_ID first_buffer_match = 0 ;
Buffer_ID last_buffer_match = 0 ;
2019-02-26 23:17:53 +00:00
i32 match_count = 0 ;
2019-02-12 03:03:49 +00:00
2019-04-05 21:18:16 +00:00
{
2019-10-18 02:54:02 +00:00
for ( Buffer_ID buffer = get_buffer_next ( app , 0 , Access_Always ) ;
2019-04-05 21:18:16 +00:00
buffer ! = 0 ;
2019-10-18 02:54:02 +00:00
buffer = get_buffer_next ( app , buffer , Access_Always ) ) {
2019-06-20 04:45:58 +00:00
History_Record_Index max_index = buffer_history_get_max_record_index ( app , buffer ) ;
History_Record_Index index = buffer_history_get_current_state_index ( app , buffer ) ;
2019-04-05 21:18:16 +00:00
if ( index < max_index ) {
2019-06-20 04:45:58 +00:00
Record_Info record = buffer_history_get_record_info ( app , buffer , index + 1 ) ;
2019-04-05 21:18:16 +00:00
if ( record . edit_number < lowest_edit_number ) {
lowest_edit_number = record . edit_number ;
first_buffer_match = buffer ;
last_buffer_match = buffer ;
match_count = 1 ;
}
else if ( record . edit_number = = lowest_edit_number ) {
last_buffer_match = buffer ;
match_count + = 1 ;
}
2019-02-12 03:03:49 +00:00
}
}
}
2019-02-12 03:17:21 +00:00
Buffer_ID * match_buffers = push_array ( scratch , Buffer_ID , match_count ) ;
2019-03-22 05:06:30 +00:00
i32 * new_positions = push_array ( scratch , i32 , match_count ) ;
2019-02-12 03:17:21 +00:00
match_count = 0 ;
2019-02-12 03:10:42 +00:00
2019-02-12 03:03:49 +00:00
if ( lowest_edit_number ! = - 1 ) {
2019-04-05 02:03:36 +00:00
for ( Buffer_ID buffer = first_buffer_match ;
buffer ! = 0 ;
2019-10-18 02:54:02 +00:00
buffer = get_buffer_next ( app , buffer , Access_Always ) ) {
2019-02-26 23:08:42 +00:00
b32 did_match = false ;
2019-03-22 05:06:30 +00:00
i32 new_edit_position = 0 ;
2019-06-20 04:45:58 +00:00
History_Record_Index max_index = buffer_history_get_max_record_index ( app , buffer ) ;
2019-02-12 03:10:42 +00:00
for ( ; ; ) {
2019-06-20 04:45:58 +00:00
History_Record_Index index = buffer_history_get_current_state_index ( app , buffer ) ;
2019-02-12 03:10:42 +00:00
if ( index < max_index ) {
2019-06-20 04:45:58 +00:00
Record_Info record = buffer_history_get_record_info ( app , buffer , index + 1 ) ;
2019-02-12 03:10:42 +00:00
if ( record . edit_number = = lowest_edit_number ) {
did_match = true ;
2019-04-05 02:03:36 +00:00
new_edit_position = record_get_new_cursor_position_redo ( app , buffer , index + 1 , record ) ;
buffer_history_set_current_state_index ( app , buffer , index + 1 ) ;
2019-02-12 03:10:42 +00:00
}
else {
break ;
}
}
else {
break ;
2019-02-12 03:03:49 +00:00
}
}
2019-02-12 03:10:42 +00:00
if ( did_match ) {
2019-04-05 02:03:36 +00:00
match_buffers [ match_count ] = buffer ;
2019-03-22 05:06:30 +00:00
new_positions [ match_count ] = new_edit_position ;
2019-02-12 03:10:42 +00:00
match_count + = 1 ;
}
2019-04-05 02:03:36 +00:00
if ( buffer = = last_buffer_match ) {
2019-02-12 03:03:49 +00:00
break ;
}
}
2019-02-08 10:03:48 +00:00
}
2019-02-12 03:10:42 +00:00
2019-03-22 05:06:30 +00:00
view_buffer_set ( app , match_buffers , new_positions , match_count ) ;
2017-01-23 06:19:43 +00:00
}
2018-05-11 20:46:26 +00:00
////////////////////////////////
CUSTOM_COMMAND_SIG ( open_in_other )
2018-06-02 04:06:13 +00:00
CUSTOM_DOC ( " Interactively opens a file in the other panel. " )
2018-05-11 20:46:26 +00:00
{
2019-10-30 23:27:37 +00:00
change_active_panel_send_command ( app , interactive_open_or_new ) ;
2018-05-11 20:46:26 +00:00
}
2019-10-14 22:57:47 +00:00
CUSTOM_COMMAND_SIG ( default_file_externally_modified )
CUSTOM_DOC ( " Notes the external modification of attached files by printing a message. " )
{
User_Input input = get_current_input ( app ) ;
if ( match_core_code ( & input , CoreCode_FileExternallyModified ) ) {
Scratch_Block scratch ( app ) ;
Buffer_ID buffer_id = input . event . core . id ;
String_Const_u8 name = push_buffer_unique_name ( app , scratch , buffer_id ) ;
String_Const_u8 str = push_u8_stringf ( scratch , " Modified externally: %s \n " , name . str ) ;
print_message ( app , str ) ;
}
}
2017-01-23 06:19:43 +00:00
// BOTTOM