2016-03-15 14:12:06 +00:00
2016-06-28 22:58:50 +00:00
# ifndef FCODER_DEFAULT_INCLUDE
# define FCODER_DEFAULT_INCLUDE
2016-03-15 14:12:06 +00:00
# include "4coder_custom.h"
2016-07-06 19:18:10 +00:00
# define FSTRING_IMPLEMENTATION
2016-03-15 14:12:06 +00:00
# include "4coder_string.h"
# include "4coder_helper.h"
2016-05-27 14:51:12 +00:00
# include <assert.h>
2016-07-13 23:19:42 +00:00
# ifndef DEFAULT_INDENT_FLAGS
# define DEFAULT_INDENT_FLAGS 0
# endif
2016-07-17 02:24:13 +00:00
# ifndef DEF_TAB_WIDTH
# define DEF_TAB_WIDTH 4
# endif
2016-09-01 00:26:52 +00:00
//
// Useful helper functions
//
static int32_t
2016-12-24 21:09:53 +00:00
open_file ( Application_Links * app , Buffer_Summary * buffer_out , char * filename , int32_t filename_len , int32_t background , int32_t never_new ) {
2016-09-01 00:26:52 +00:00
int32_t result = false ;
Buffer_Summary buffer =
2016-09-17 00:03:09 +00:00
get_buffer_by_name ( app , filename , filename_len ,
AccessProtected | AccessHidden ) ;
2016-09-01 00:26:52 +00:00
if ( buffer . exists ) {
if ( buffer_out ) * buffer_out = buffer ;
result = true ;
}
else {
Buffer_Create_Flag flags = 0 ;
if ( background ) {
flags | = BufferCreate_Background ;
}
if ( never_new ) {
flags | = BufferCreate_NeverNew ;
}
2016-09-17 00:03:09 +00:00
buffer = create_buffer ( app , filename , filename_len , flags ) ;
2016-09-01 00:26:52 +00:00
if ( buffer . exists ) {
if ( buffer_out ) * buffer_out = buffer ;
result = true ;
}
}
return ( result ) ;
}
static int32_t
2016-12-24 21:09:53 +00:00
view_open_file ( Application_Links * app , View_Summary * view , char * filename , int32_t filename_len , int32_t never_new ) {
2016-09-25 00:13:24 +00:00
int32_t result = 0 ;
2016-09-01 00:26:52 +00:00
if ( view ) {
Buffer_Summary buffer = { 0 } ;
if ( open_file ( app , & buffer , filename , filename_len , false , never_new ) ) {
2016-09-17 00:03:09 +00:00
view_set_buffer ( app , view , buffer . buffer_id , 0 ) ;
2016-09-25 00:13:24 +00:00
result = 1 ;
2016-09-01 00:26:52 +00:00
}
}
return ( result ) ;
}
static int32_t
2016-12-24 21:09:53 +00:00
read_line ( Application_Links * app , Partition * part , Buffer_Summary * buffer , int32_t line , String * str ) {
2016-09-01 00:26:52 +00:00
Partial_Cursor begin = { 0 } ;
Partial_Cursor end = { 0 } ;
2016-09-24 21:26:37 +00:00
int32_t success = 0 ;
2016-09-01 00:26:52 +00:00
2016-09-24 21:26:37 +00:00
if ( buffer_compute_cursor ( app , buffer , seek_line_char ( line , 1 ) , & begin ) ) {
if ( buffer_compute_cursor ( app , buffer , seek_line_char ( line , 65536 ) , & end ) ) {
2016-09-01 00:26:52 +00:00
if ( begin . line = = line ) {
if ( 0 < = begin . pos & & begin . pos < = end . pos & & end . pos < = buffer - > size ) {
int32_t size = ( end . pos - begin . pos ) ;
* str = make_string ( push_array ( part , char , size + 1 ) , size + 1 ) ;
if ( str - > str ) {
2016-09-24 21:26:37 +00:00
success = 1 ;
2016-09-17 00:03:09 +00:00
buffer_read_range ( app , buffer , begin . pos , end . pos , str - > str ) ;
2016-09-01 00:26:52 +00:00
str - > size = size ;
terminate_with_null ( str ) ;
}
}
}
}
}
return ( success ) ;
}
2016-07-13 23:19:42 +00:00
2016-07-10 05:49:11 +00:00
//
// Memory
//
2016-07-12 18:20:06 +00:00
static Partition global_part ;
static General_Memory global_general ;
2016-07-10 05:49:11 +00:00
2016-07-11 16:15:37 +00:00
void
init_memory ( Application_Links * app ) {
2016-09-24 06:17:06 +00:00
int32_t part_size = ( 32 < < 20 ) ;
int32_t general_size = ( 4 < < 20 ) ;
2016-07-11 16:15:37 +00:00
2016-09-17 00:03:09 +00:00
void * part_mem = memory_allocate ( app , part_size ) ;
2016-07-12 18:20:06 +00:00
global_part = make_part ( part_mem , part_size ) ;
2016-07-11 16:15:37 +00:00
2016-09-17 00:03:09 +00:00
void * general_mem = memory_allocate ( app , general_size ) ;
2016-07-12 18:20:06 +00:00
general_memory_open ( & global_general , general_mem , general_size ) ;
2016-07-11 16:15:37 +00:00
}
2016-07-10 05:49:11 +00:00
2016-10-05 06:08:23 +00:00
2016-09-15 15:01:52 +00:00
//
// Helpers
//
static void
refresh_buffer ( Application_Links * app , Buffer_Summary * buffer ) {
2016-09-17 00:03:09 +00:00
* buffer = get_buffer ( app , buffer - > buffer_id , AccessAll ) ;
2016-09-15 15:01:52 +00:00
}
static void
refresh_view ( Application_Links * app , View_Summary * view ) {
2016-09-17 00:03:09 +00:00
* view = get_view ( app , view - > view_id , AccessAll ) ;
2016-09-15 15:01:52 +00:00
}
2016-10-05 06:08:23 +00:00
2016-07-10 05:49:11 +00:00
//
// Buffer Streaming
//
struct Stream_Chunk {
Application_Links * app ;
Buffer_Summary * buffer ;
char * base_data ;
2016-08-29 01:03:26 +00:00
int32_t start , end ;
int32_t min_start , max_end ;
2016-09-08 00:32:31 +00:00
bool32 add_null ;
2016-08-29 01:03:26 +00:00
int32_t data_size ;
2016-07-10 05:49:11 +00:00
char * data ;
} ;
2016-09-15 15:01:52 +00:00
static int32_t
2016-08-29 01:03:26 +00:00
round_down ( int32_t x , int32_t b ) {
int32_t r = 0 ;
2016-07-10 05:49:11 +00:00
if ( x > = 0 ) {
r = x - ( x % b ) ;
}
return ( r ) ;
}
2016-09-15 15:01:52 +00:00
static int32_t
2016-08-29 01:03:26 +00:00
round_up ( int32_t x , int32_t b ) {
int32_t r = 0 ;
2016-07-10 05:49:11 +00:00
if ( x > = 0 ) {
r = x - ( x % b ) + b ;
}
return ( r ) ;
}
2016-09-15 15:01:52 +00:00
static bool32
init_stream_chunk ( Stream_Chunk * chunk , Application_Links * app , Buffer_Summary * buffer ,
2016-08-29 01:03:26 +00:00
int32_t pos , char * data , int32_t size ) {
2016-09-15 15:01:52 +00:00
bool32 result = 0 ;
2016-07-10 05:49:11 +00:00
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 ) ;
2016-09-08 00:32:31 +00:00
if ( chunk - > max_end > buffer - > size | | chunk - > max_end = = 0 ) {
2016-07-10 05:49:11 +00:00
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 ) {
2016-09-17 00:03:09 +00:00
buffer_read_range ( app , buffer , chunk - > start , chunk - > end , chunk - > base_data ) ;
2016-07-10 05:49:11 +00:00
chunk - > data = chunk - > base_data - chunk - > start ;
2016-09-15 15:01:52 +00:00
result = 1 ;
2016-07-10 05:49:11 +00:00
}
}
2016-09-15 15:01:52 +00:00
2016-07-10 05:49:11 +00:00
return ( result ) ;
}
2016-09-15 15:01:52 +00:00
static bool32
2016-07-10 05:49:11 +00:00
forward_stream_chunk ( Stream_Chunk * chunk ) {
Application_Links * app = chunk - > app ;
Buffer_Summary * buffer = chunk - > buffer ;
2016-09-15 15:01:52 +00:00
bool32 result = 0 ;
2016-07-10 05:49:11 +00:00
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 ) {
2016-09-17 00:03:09 +00:00
buffer_read_range ( app , buffer , chunk - > start , chunk - > end , chunk - > base_data ) ;
2016-07-10 05:49:11 +00:00
chunk - > data = chunk - > base_data - chunk - > start ;
2016-09-15 15:01:52 +00:00
result = 1 ;
2016-07-10 05:49:11 +00:00
}
}
2016-09-08 00:32:31 +00:00
else if ( chunk - > add_null & & chunk - > end + 1 < buffer - > size ) {
chunk - > start = buffer - > size ;
chunk - > end = buffer - > size + 1 ;
chunk - > base_data [ 0 ] = 0 ;
chunk - > data = chunk - > base_data - chunk - > start ;
2016-09-15 15:01:52 +00:00
result = 1 ;
2016-09-08 00:32:31 +00:00
}
2016-07-10 05:49:11 +00:00
return ( result ) ;
}
2016-09-15 15:01:52 +00:00
static bool32
2016-07-10 05:49:11 +00:00
backward_stream_chunk ( Stream_Chunk * chunk ) {
Application_Links * app = chunk - > app ;
Buffer_Summary * buffer = chunk - > buffer ;
2016-09-15 15:01:52 +00:00
bool32 result = 0 ;
2016-07-10 05:49:11 +00:00
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 ) {
2016-09-17 00:03:09 +00:00
buffer_read_range ( app , buffer , chunk - > start , chunk - > end , chunk - > base_data ) ;
2016-07-10 05:49:11 +00:00
chunk - > data = chunk - > base_data - chunk - > start ;
2016-09-15 15:01:52 +00:00
result = 1 ;
2016-07-10 05:49:11 +00:00
}
}
2016-09-08 00:32:31 +00:00
else if ( chunk - > add_null & & chunk - > start > - 1 ) {
chunk - > start = - 1 ;
chunk - > end = 0 ;
chunk - > base_data [ 0 ] = 0 ;
chunk - > data = chunk - > base_data - chunk - > start ;
2016-09-15 15:01:52 +00:00
result = 1 ;
}
return ( result ) ;
}
typedef struct Stream_Tokens {
Application_Links * app ;
Buffer_Summary * buffer ;
Cpp_Token * base_tokens ;
Cpp_Token * tokens ;
int32_t start , end ;
int32_t count , token_count ;
} Stream_Tokens ;
static bool32
init_stream_tokens ( Stream_Tokens * stream , Application_Links * app , Buffer_Summary * buffer ,
int32_t pos , Cpp_Token * data , int32_t count ) {
bool32 result = 0 ;
refresh_buffer ( app , buffer ) ;
2016-09-17 00:03:09 +00:00
int32_t token_count = buffer_token_count ( app , buffer ) ;
2016-09-15 15:01:52 +00:00
if ( pos > = 0 & & pos < token_count & & count > 0 ) {
stream - > app = app ;
stream - > buffer = buffer ;
stream - > base_tokens = data ;
stream - > count = count ;
stream - > start = round_down ( pos , count ) ;
stream - > end = round_up ( pos , count ) ;
2016-09-16 14:10:45 +00:00
stream - > token_count = token_count ;
2016-09-15 15:01:52 +00:00
2016-09-17 00:03:09 +00:00
buffer_read_tokens ( app , buffer , stream - > start , stream - > end , stream - > base_tokens ) ;
2016-09-15 15:01:52 +00:00
stream - > tokens = stream - > base_tokens - stream - > start ;
result = 1 ;
}
return ( result ) ;
}
2016-09-16 14:10:45 +00:00
static Stream_Tokens
begin_temp_stream_token ( Stream_Tokens * stream ) {
return ( * stream ) ;
}
static void
end_temp_stream_token ( Stream_Tokens * stream , Stream_Tokens temp ) {
if ( stream - > start ! = temp . start | | stream - > end ! = temp . end ) {
Application_Links * app = stream - > app ;
2016-09-17 00:03:09 +00:00
buffer_read_tokens ( app , stream - > buffer , stream - > start , stream - > end , stream - > base_tokens ) ;
2016-09-16 14:10:45 +00:00
}
}
2016-09-15 15:01:52 +00:00
static bool32
forward_stream_tokens ( Stream_Tokens * stream ) {
Application_Links * app = stream - > app ;
Buffer_Summary * buffer = stream - > buffer ;
bool32 result = 0 ;
refresh_buffer ( app , buffer ) ;
if ( stream - > end < stream - > token_count ) {
stream - > start = stream - > end ;
stream - > end + = stream - > count ;
if ( stream - > token_count < stream - > end ) {
stream - > end = stream - > token_count ;
}
if ( stream - > start < stream - > end ) {
2016-09-17 00:03:09 +00:00
buffer_read_tokens ( app , buffer , stream - > start , stream - > end , stream - > base_tokens ) ;
2016-09-15 15:01:52 +00:00
stream - > tokens = stream - > base_tokens - stream - > start ;
result = 1 ;
}
}
return ( result ) ;
}
static bool32
backward_stream_tokens ( Stream_Tokens * stream ) {
Application_Links * app = stream - > app ;
Buffer_Summary * buffer = stream - > buffer ;
bool32 result = 0 ;
refresh_buffer ( app , buffer ) ;
if ( stream - > start > 0 ) {
stream - > end = stream - > start ;
stream - > start - = stream - > count ;
if ( 0 > stream - > start ) {
stream - > start = 0 ;
}
if ( stream - > start < stream - > end ) {
2016-09-17 00:03:09 +00:00
buffer_read_tokens ( app , buffer , stream - > start , stream - > end , stream - > base_tokens ) ;
2016-09-15 15:01:52 +00:00
stream - > tokens = stream - > base_tokens - stream - > start ;
result = 1 ;
}
2016-09-08 00:32:31 +00:00
}
2016-07-10 05:49:11 +00:00
return ( result ) ;
}
void
2016-12-18 20:42:11 +00:00
buffer_seek_delimiter_forward ( Application_Links * app , Buffer_Summary * buffer , int32_t pos , char delim , int32_t * result ) {
2016-07-10 05:49:11 +00:00
if ( buffer - > exists ) {
char chunk [ 1024 ] ;
2016-08-29 01:03:26 +00:00
int32_t size = sizeof ( chunk ) ;
2016-07-10 05:49:11 +00:00
Stream_Chunk stream = { 0 } ;
if ( init_stream_chunk ( & stream , app , buffer , pos , chunk , size ) ) {
2016-08-29 01:03:26 +00:00
int32_t still_looping = 1 ;
2016-07-10 05:49:11 +00:00
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 : ;
}
2016-09-15 15:01:52 +00:00
static void
2016-12-18 20:42:11 +00:00
buffer_seek_delimiter_backward ( Application_Links * app , Buffer_Summary * buffer , int32_t pos , char delim , int32_t * result ) {
2016-07-10 05:49:11 +00:00
if ( buffer - > exists ) {
char chunk [ 1024 ] ;
2016-08-29 01:03:26 +00:00
int32_t size = sizeof ( chunk ) ;
2016-07-10 05:49:11 +00:00
Stream_Chunk stream = { 0 } ;
if ( init_stream_chunk ( & stream , app , buffer , pos , chunk , size ) ) {
2016-08-29 01:03:26 +00:00
int32_t still_looping = 1 ;
2016-07-10 05:49:11 +00:00
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.
2016-09-15 15:01:52 +00:00
static void
2016-12-18 20:42:11 +00:00
buffer_seek_string_forward ( Application_Links * app , Buffer_Summary * buffer , int32_t pos , int32_t end , char * str , int32_t size , int32_t * result ) {
2016-07-10 05:49:11 +00:00
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 ] ;
Stream_Chunk stream = { 0 } ;
stream . max_end = end ;
2016-09-09 22:56:43 +00:00
if ( init_stream_chunk ( & stream , app , buffer , pos , chunk , sizeof ( chunk ) ) ) {
2016-08-29 01:03:26 +00:00
int32_t still_looping = 1 ;
2016-07-10 05:49:11 +00:00
do {
for ( ; pos < stream . end ; + + pos ) {
char at_pos = stream . data [ pos ] ;
if ( at_pos = = first_char ) {
2016-09-17 00:03:09 +00:00
buffer_read_range ( app , buffer , pos , pos + size , read_buffer ) ;
2016-08-28 04:31:06 +00:00
if ( match_ss ( needle_str , read_str ) ) {
2016-07-10 05:49:11 +00:00
* 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.
2016-09-15 15:01:52 +00:00
static void
2016-12-18 20:42:11 +00:00
buffer_seek_string_backward ( Application_Links * app , Buffer_Summary * buffer , int32_t pos , int32_t min , char * str , int32_t size , int32_t * result ) {
2016-07-10 05:49:11 +00:00
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 ] ;
Stream_Chunk stream = { 0 } ;
stream . min_start = min ;
2016-09-09 22:56:43 +00:00
if ( init_stream_chunk ( & stream , app , buffer , pos , chunk , sizeof ( chunk ) ) ) {
2016-08-29 01:03:26 +00:00
int32_t still_looping = 1 ;
2016-07-10 05:49:11 +00:00
do {
for ( ; pos > = stream . start ; - - pos ) {
char at_pos = stream . data [ pos ] ;
if ( at_pos = = first_char ) {
2016-09-17 00:03:09 +00:00
buffer_read_range ( app , buffer , pos , pos + size , read_buffer ) ;
2016-08-28 04:31:06 +00:00
if ( match_ss ( needle_str , read_str ) ) {
2016-07-10 05:49:11 +00:00
* 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.
2016-09-15 15:01:52 +00:00
static void
2016-12-18 20:42:11 +00:00
buffer_seek_string_insensitive_forward ( Application_Links * app , Buffer_Summary * buffer , int32_t pos , int32_t end , char * str , int32_t size , int32_t * result ) {
2016-07-10 05:49:11 +00:00
char read_buffer [ 512 ] ;
char chunk [ 1024 ] ;
2016-08-29 01:03:26 +00:00
int32_t chunk_size = sizeof ( chunk ) ;
2016-07-10 05:49:11 +00:00
Stream_Chunk stream = { 0 } ;
2016-07-18 18:36:53 +00:00
stream . max_end = end ;
2016-07-10 05:49:11 +00:00
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 ) ) {
2016-08-29 01:03:26 +00:00
int32_t still_looping = 1 ;
2016-07-10 05:49:11 +00:00
do {
for ( ; pos < stream . end ; + + pos ) {
char at_pos = char_to_upper ( stream . data [ pos ] ) ;
if ( at_pos = = first_char ) {
2016-09-17 00:03:09 +00:00
buffer_read_range ( app , buffer , pos , pos + size , read_buffer ) ;
2016-08-28 04:31:06 +00:00
if ( match_insensitive_ss ( needle_str , read_str ) ) {
2016-07-10 05:49:11 +00:00
* 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.
2016-09-15 15:01:52 +00:00
static void
2016-12-18 20:42:11 +00:00
buffer_seek_string_insensitive_backward ( Application_Links * app , Buffer_Summary * buffer , int32_t pos , int32_t min , char * str , int32_t size , int32_t * result ) {
2016-07-10 05:49:11 +00:00
char read_buffer [ 512 ] ;
char chunk [ 1024 ] ;
2016-08-29 01:03:26 +00:00
int32_t chunk_size = sizeof ( chunk ) ;
2016-07-10 05:49:11 +00:00
Stream_Chunk stream = { 0 } ;
2016-07-18 18:36:53 +00:00
stream . min_start = min ;
2016-07-10 05:49:11 +00:00
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 ) ) {
2016-08-29 01:03:26 +00:00
int32_t still_looping = 1 ;
2016-07-10 05:49:11 +00:00
do {
for ( ; pos > = stream . start ; - - pos ) {
char at_pos = char_to_upper ( stream . data [ pos ] ) ;
if ( at_pos = = first_char ) {
2016-09-17 00:03:09 +00:00
buffer_read_range ( app , buffer , pos , pos + size , read_buffer ) ;
2016-08-28 04:31:06 +00:00
if ( match_insensitive_ss ( needle_str , read_str ) ) {
2016-07-10 05:49:11 +00:00
* result = pos ;
goto finished ;
}
}
}
still_looping = backward_stream_chunk ( & stream ) ;
} while ( still_looping ) ;
}
}
* result = - 1 ;
finished : ;
}
}
2016-09-09 01:02:51 +00:00
//
// Some Basic Buffer Positioning
//
# include "4cpp_lexer.h"
static int32_t
buffer_get_line_start ( Application_Links * app , Buffer_Summary * buffer , int32_t line ) {
Partial_Cursor partial_cursor ;
int32_t result = buffer - > size ;
2016-09-13 23:59:48 +00:00
if ( line < = buffer - > line_count ) {
2016-09-17 00:03:09 +00:00
buffer_compute_cursor ( app , buffer , seek_line_char ( line , 1 ) , & partial_cursor ) ;
2016-09-09 01:02:51 +00:00
result = partial_cursor . pos ;
}
return ( result ) ;
}
static int32_t
buffer_get_line_index ( Application_Links * app , Buffer_Summary * buffer , int32_t pos ) {
Partial_Cursor partial_cursor ;
2016-09-17 00:03:09 +00:00
buffer_compute_cursor ( app , buffer , seek_pos ( pos ) , & partial_cursor ) ;
2016-09-09 01:02:51 +00:00
return ( partial_cursor . line ) ;
}
static Cpp_Token *
2016-09-10 15:22:25 +00:00
get_first_token_at_line ( Application_Links * app , Buffer_Summary * buffer , Cpp_Token_Array tokens , int32_t line ,
int32_t * line_start_out = 0 ) {
2016-09-09 01:02:51 +00:00
int32_t line_start = buffer_get_line_start ( app , buffer , line ) ;
2016-09-23 17:50:55 +00:00
Cpp_Get_Token_Result get_token = cpp_get_token ( tokens , line_start ) ;
2016-09-09 01:02:51 +00:00
if ( get_token . in_whitespace ) {
get_token . token_index + = 1 ;
}
2016-09-10 15:22:25 +00:00
if ( line_start_out ) {
* line_start_out = line_start ;
}
Cpp_Token * result = 0 ;
if ( get_token . token_index < tokens . count ) {
result = tokens . tokens + get_token . token_index ;
}
2016-09-09 01:02:51 +00:00
return ( result ) ;
}
2016-07-10 05:49:11 +00:00
//
// Fundamental Editing
//
2016-06-03 16:20:45 +00:00
inline float
get_view_y ( View_Summary view ) {
2016-06-22 17:53:31 +00:00
float y = view . cursor . wrapped_y ;
2016-06-03 16:20:45 +00:00
if ( view . unwrapped_lines ) {
y = view . cursor . unwrapped_y ;
}
return ( y ) ;
2016-03-15 14:12:06 +00:00
}
2016-06-03 16:20:45 +00:00
inline float
get_view_x ( View_Summary view ) {
2016-06-22 17:53:31 +00:00
float x = view . cursor . wrapped_x ;
2016-06-03 16:20:45 +00:00
if ( view . unwrapped_lines ) {
x = view . cursor . unwrapped_x ;
}
return ( x ) ;
}
CUSTOM_COMMAND_SIG ( write_character ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessOpen ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
2016-06-03 16:20:45 +00:00
2016-09-17 00:03:09 +00:00
User_Input in = get_command_input ( app ) ;
2016-06-03 16:20:45 +00:00
char character = 0 ;
if ( in . type = = UserInputKey ) {
character = in . key . character ;
}
if ( character ! = 0 ) {
2016-09-17 00:03:09 +00:00
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-06-20 20:34:48 +00:00
2016-08-29 01:03:26 +00:00
int32_t pos = view . cursor . pos ;
2016-09-24 06:17:06 +00:00
buffer_replace_range ( app , & buffer , pos , pos , & character , 1 ) ;
2016-09-25 19:25:27 +00:00
view_set_cursor ( app , & view , seek_pos ( view . cursor . pos + 1 ) , true ) ;
2016-06-03 16:20:45 +00:00
}
}
CUSTOM_COMMAND_SIG ( delete_char ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessOpen ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-06-03 16:20:45 +00:00
2016-09-24 06:17:06 +00:00
int32_t start = view . cursor . pos ;
2016-09-25 00:13:24 +00:00
Full_Cursor cursor ;
view_compute_cursor ( app , & view , seek_character_pos ( view . cursor . character_pos + 1 ) , & cursor ) ;
2016-09-24 06:17:06 +00:00
int32_t end = cursor . pos ;
if ( 0 < = start & & start < buffer . size ) {
buffer_replace_range ( app , & buffer , start , end , 0 , 0 ) ;
2016-06-03 16:20:45 +00:00
}
}
CUSTOM_COMMAND_SIG ( backspace_char ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessOpen ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-06-03 16:20:45 +00:00
2016-09-24 06:17:06 +00:00
int32_t end = view . cursor . pos ;
2016-09-25 00:13:24 +00:00
Full_Cursor cursor ;
view_compute_cursor ( app , & view , seek_character_pos ( view . cursor . character_pos - 1 ) , & cursor ) ;
2016-09-24 06:17:06 +00:00
int32_t start = cursor . pos ;
if ( 0 < end & & end < = buffer . size ) {
buffer_replace_range ( app , & buffer , start , end , 0 , 0 ) ;
view_set_cursor ( app , & view , seek_character_pos ( view . cursor . character_pos - 1 ) , true ) ;
2016-06-03 16:20:45 +00:00
}
}
CUSTOM_COMMAND_SIG ( set_mark ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessProtected ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
2016-06-03 16:20:45 +00:00
2016-09-17 00:03:09 +00:00
view_set_mark ( app , & view , seek_pos ( view . cursor . pos ) ) ;
2016-09-24 06:17:06 +00:00
view_set_cursor ( app , & view , seek_pos ( view . cursor . pos ) , 1 ) ;
2016-06-06 18:41:17 +00:00
}
CUSTOM_COMMAND_SIG ( cursor_mark_swap ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessProtected ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
2016-06-06 18:41:17 +00:00
2016-08-29 01:03:26 +00:00
int32_t cursor = view . cursor . pos ;
int32_t mark = view . mark . pos ;
2016-06-06 18:41:17 +00:00
2016-09-17 00:03:09 +00:00
view_set_cursor ( app , & view , seek_pos ( mark ) , true ) ;
view_set_mark ( app , & view , seek_pos ( cursor ) ) ;
2016-06-03 16:20:45 +00:00
}
CUSTOM_COMMAND_SIG ( delete_range ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessOpen ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-06-03 16:20:45 +00:00
Range range = get_range ( & view ) ;
2016-09-24 06:17:06 +00:00
buffer_replace_range ( app , & buffer , range . min , range . max , 0 , 0 ) ;
2016-06-03 16:20:45 +00:00
}
//
// Basic Navigation
//
2016-07-12 18:20:06 +00:00
CUSTOM_COMMAND_SIG ( center_view ) {
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , AccessProtected ) ;
2016-07-12 18:20:06 +00:00
i32_Rect region = view . file_region ;
GUI_Scroll_Vars scroll = view . scroll_vars ;
float h = ( float ) ( region . y1 - region . y0 ) ;
float y = get_view_y ( view ) ;
y = y - h * .5f ;
scroll . target_y = ( int32_t ) ( y + .5f ) ;
2016-09-17 00:03:09 +00:00
view_set_scroll ( app , & view , scroll ) ;
2016-07-12 18:20:06 +00:00
}
CUSTOM_COMMAND_SIG ( left_adjust_view ) {
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , AccessProtected ) ;
2016-07-12 18:20:06 +00:00
GUI_Scroll_Vars scroll = view . scroll_vars ;
2016-11-12 21:33:54 +00:00
float x = get_view_x ( view ) - 30.f ;
if ( x < 0 ) {
x = 0.f ;
}
2016-07-12 18:20:06 +00:00
scroll . target_x = ( int32_t ) ( x + .5f ) ;
2016-09-17 00:03:09 +00:00
view_set_scroll ( app , & view , scroll ) ;
2016-07-12 18:20:06 +00:00
}
2016-08-29 01:03:26 +00:00
int32_t
get_relative_xy ( View_Summary * view , int32_t x , int32_t y , float * x_out , float * y_out ) {
int32_t result = false ;
2016-06-10 23:46:30 +00:00
i32_Rect region = view - > file_region ;
2016-08-29 01:03:26 +00:00
int32_t max_x = ( region . x1 - region . x0 ) ;
int32_t max_y = ( region . y1 - region . y0 ) ;
2016-06-10 23:46:30 +00:00
GUI_Scroll_Vars scroll_vars = view - > scroll_vars ;
2016-08-29 01:03:26 +00:00
int32_t rx = x - region . x0 ;
int32_t ry = y - region . y0 ;
2016-06-10 23:46:30 +00:00
if ( ry > = 0 ) {
if ( rx > = 0 & & rx < max_x & & ry > = 0 & & ry < max_y ) {
result = 1 ;
}
}
* x_out = ( float ) rx + scroll_vars . scroll_x ;
* y_out = ( float ) ry + scroll_vars . scroll_y ;
return ( result ) ;
}
CUSTOM_COMMAND_SIG ( click_set_cursor ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessProtected ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
2016-06-20 20:34:48 +00:00
2016-09-17 00:03:09 +00:00
Mouse_State mouse = get_mouse_state ( app ) ;
2016-06-20 20:34:48 +00:00
float rx = 0 , ry = 0 ;
if ( get_relative_xy ( & view , mouse . x , mouse . y , & rx , & ry ) ) {
2016-09-25 00:13:24 +00:00
view_set_cursor ( app , & view , seek_xy ( rx , ry , 1 , view . unwrapped_lines ) , 1 ) ;
2016-06-10 23:46:30 +00:00
}
}
CUSTOM_COMMAND_SIG ( click_set_mark ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessProtected ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
2016-06-20 20:34:48 +00:00
2016-09-17 00:03:09 +00:00
Mouse_State mouse = get_mouse_state ( app ) ;
2016-06-20 20:34:48 +00:00
float rx = 0 , ry = 0 ;
if ( get_relative_xy ( & view , mouse . x , mouse . y , & rx , & ry ) ) {
2016-09-25 00:13:24 +00:00
view_set_mark ( app , & view , seek_xy ( rx , ry , 1 , view . unwrapped_lines ) ) ;
2016-06-10 23:46:30 +00:00
}
}
2016-06-03 16:20:45 +00:00
inline void
move_vertical ( Application_Links * app , float line_multiplier ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessProtected ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
2016-06-03 16:20:45 +00:00
float new_y = get_view_y ( view ) + line_multiplier * view . line_height ;
float x = view . preferred_x ;
2016-09-25 00:13:24 +00:00
view_set_cursor ( app , & view , seek_xy ( x , new_y , 0 , view . unwrapped_lines ) , 0 ) ;
2016-06-03 16:20:45 +00:00
}
CUSTOM_COMMAND_SIG ( move_up ) {
move_vertical ( app , - 1.f ) ;
}
CUSTOM_COMMAND_SIG ( move_down ) {
move_vertical ( app , 1.f ) ;
}
CUSTOM_COMMAND_SIG ( move_up_10 ) {
move_vertical ( app , - 10.f ) ;
}
CUSTOM_COMMAND_SIG ( move_down_10 ) {
move_vertical ( app , 10.f ) ;
}
2016-07-04 20:40:57 +00:00
static float
get_page_jump ( View_Summary * view ) {
i32_Rect region = view - > file_region ;
float page_jump = 1 ;
if ( view - > line_height > 0 ) {
page_jump = ( float ) ( region . y1 - region . y0 ) / view - > line_height ;
page_jump - = 3.f ;
if ( page_jump < = 0 ) {
page_jump = 1.f ;
}
}
return ( page_jump ) ;
}
CUSTOM_COMMAND_SIG ( page_up ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessProtected ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
2016-07-04 20:40:57 +00:00
float page_jump = get_page_jump ( & view ) ;
move_vertical ( app , - page_jump ) ;
}
CUSTOM_COMMAND_SIG ( page_down ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessProtected ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
2016-07-04 20:40:57 +00:00
float page_jump = get_page_jump ( & view ) ;
move_vertical ( app , page_jump ) ;
}
2016-06-03 16:20:45 +00:00
CUSTOM_COMMAND_SIG ( move_left ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessProtected ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
2016-09-24 17:25:11 +00:00
int32_t new_pos = view . cursor . character_pos - 1 ;
view_set_cursor ( app , & view , seek_character_pos ( new_pos ) , 1 ) ;
2016-06-03 16:20:45 +00:00
}
CUSTOM_COMMAND_SIG ( move_right ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessProtected ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
2016-09-24 17:25:11 +00:00
int32_t new_pos = view . cursor . character_pos + 1 ;
view_set_cursor ( app , & view , seek_character_pos ( new_pos ) , 1 ) ;
2016-06-03 16:20:45 +00:00
}
2016-07-17 02:24:13 +00:00
//
// Auto Indenting and Whitespace
//
2016-08-29 01:03:26 +00:00
static int32_t
seek_line_end ( Application_Links * app , Buffer_Summary * buffer , int32_t pos ) {
2016-07-17 02:24:13 +00:00
char chunk [ 1024 ] ;
2016-08-29 01:03:26 +00:00
int32_t chunk_size = sizeof ( chunk ) ;
2016-07-17 02:24:13 +00:00
Stream_Chunk stream = { 0 } ;
2016-08-29 01:03:26 +00:00
int32_t still_looping ;
2016-07-17 02:24:13 +00:00
char at_pos ;
if ( init_stream_chunk ( & stream , app , buffer , pos , chunk , chunk_size ) ) {
still_looping = 1 ;
do {
for ( ; pos < stream . end ; + + pos ) {
at_pos = stream . data [ pos ] ;
if ( at_pos = = ' \n ' ) {
goto double_break ;
}
}
still_looping = forward_stream_chunk ( & stream ) ;
} while ( still_looping ) ;
double_break : ;
if ( pos > buffer - > size ) {
pos = buffer - > size ;
}
}
return ( pos ) ;
}
2016-08-29 01:03:26 +00:00
static int32_t
seek_line_beginning ( Application_Links * app , Buffer_Summary * buffer , int32_t pos ) {
2016-07-17 02:24:13 +00:00
char chunk [ 1024 ] ;
2016-08-29 01:03:26 +00:00
int32_t chunk_size = sizeof ( chunk ) ;
2016-07-17 02:24:13 +00:00
Stream_Chunk stream = { 0 } ;
2016-08-29 01:03:26 +00:00
int32_t still_looping ;
2016-07-17 02:24:13 +00:00
char at_pos ;
- - pos ;
if ( init_stream_chunk ( & stream , app , buffer , pos , chunk , chunk_size ) ) {
still_looping = 1 ;
do {
for ( ; pos > = stream . start ; - - pos ) {
at_pos = stream . data [ pos ] ;
if ( at_pos = = ' \n ' ) {
goto double_break ;
}
}
still_looping = backward_stream_chunk ( & stream ) ;
} while ( still_looping ) ;
double_break : ;
if ( pos ! = 0 ) {
+ + pos ;
}
if ( pos < 0 ) {
pos = 0 ;
}
}
return ( pos ) ;
}
static void
move_past_lead_whitespace ( Application_Links * app , View_Summary * view , Buffer_Summary * buffer ) {
refresh_view ( app , view ) ;
2016-08-29 01:03:26 +00:00
int32_t new_pos = seek_line_beginning ( app , buffer , view - > cursor . pos ) ;
2016-07-17 02:24:13 +00:00
char space [ 1024 ] ;
Stream_Chunk chunk = { 0 } ;
2016-08-29 01:03:26 +00:00
int32_t still_looping = false ;
2016-07-17 02:24:13 +00:00
2016-08-29 01:03:26 +00:00
int32_t i = new_pos ;
2016-07-17 02:24:13 +00:00
if ( init_stream_chunk ( & chunk , app , buffer , i , space , sizeof ( space ) ) ) {
do {
for ( ; i < chunk . end ; + + i ) {
char at_pos = chunk . data [ i ] ;
if ( at_pos = = ' \n ' | | ! char_is_whitespace ( at_pos ) ) {
goto break2 ;
}
}
still_looping = forward_stream_chunk ( & chunk ) ;
} while ( still_looping ) ;
break2 : ;
if ( i > view - > cursor . pos ) {
2016-09-17 00:03:09 +00:00
view_set_cursor ( app , view , seek_pos ( i ) , true ) ;
2016-07-17 02:24:13 +00:00
}
}
}
2016-09-08 00:32:31 +00:00
# include "4coder_auto_indent.cpp"
2016-09-07 19:07:10 +00:00
2016-07-17 02:24:13 +00:00
CUSTOM_COMMAND_SIG ( auto_tab_line_at_cursor ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessOpen ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-07-17 02:24:13 +00:00
2016-12-18 20:42:11 +00:00
buffer_auto_indent ( app , & buffer , view . cursor . pos , view . cursor . pos , DEF_TAB_WIDTH , DEFAULT_INDENT_FLAGS | AutoIndent_FullTokens ) ;
2016-07-17 02:24:13 +00:00
move_past_lead_whitespace ( app , & view , & buffer ) ;
}
2016-12-26 22:49:01 +00:00
static void
auto_tab_whole_file_by_summary ( Application_Links * app , Buffer_Summary * buffer ) {
buffer_auto_indent ( app , buffer , 0 , buffer - > size , DEF_TAB_WIDTH , DEFAULT_INDENT_FLAGS | AutoIndent_FullTokens ) ;
}
2016-07-17 02:24:13 +00:00
CUSTOM_COMMAND_SIG ( auto_tab_whole_file ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessOpen ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-07-17 02:24:13 +00:00
2016-12-26 22:49:01 +00:00
auto_tab_whole_file_by_summary ( app , & buffer ) ;
2016-07-17 02:24:13 +00:00
}
CUSTOM_COMMAND_SIG ( auto_tab_range ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessOpen ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-07-17 02:24:13 +00:00
Range range = get_range ( & view ) ;
2016-12-18 20:42:11 +00:00
buffer_auto_indent ( app , & buffer , range . min , range . max , DEF_TAB_WIDTH , DEFAULT_INDENT_FLAGS | AutoIndent_FullTokens ) ;
2016-07-17 02:24:13 +00:00
move_past_lead_whitespace ( app , & view , & buffer ) ;
}
CUSTOM_COMMAND_SIG ( write_and_auto_tab ) {
exec_command ( app , write_character ) ;
2016-09-13 01:58:32 +00:00
uint32_t access = AccessOpen ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-09-13 01:58:32 +00:00
2016-12-18 20:42:11 +00:00
buffer_auto_indent ( app , & buffer , view . cursor . pos , view . cursor . pos , DEF_TAB_WIDTH , DEFAULT_INDENT_FLAGS | AutoIndent_ExactAlignBlock ) ;
2016-09-13 01:58:32 +00:00
move_past_lead_whitespace ( app , & view , & buffer ) ;
2016-07-17 02:24:13 +00:00
}
CUSTOM_COMMAND_SIG ( clean_all_lines ) {
// TODO(allen): This command always iterates accross the entire
// buffer, so streaming it is actually the wrong call. Rewrite this
2016-09-17 00:03:09 +00:00
// to minimize calls to buffer_read_range.
View_Summary view = get_active_view ( app , AccessOpen ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , AccessOpen ) ;
2016-07-17 02:24:13 +00:00
2016-08-29 01:03:26 +00:00
int32_t line_count = buffer . line_count ;
int32_t edit_max = line_count ;
2016-07-17 02:24:13 +00:00
if ( edit_max * sizeof ( Buffer_Edit ) < app - > memory_size ) {
Buffer_Edit * edits = ( Buffer_Edit * ) app - > memory ;
char data [ 1024 ] ;
Stream_Chunk chunk = { 0 } ;
2016-08-29 01:03:26 +00:00
int32_t i = 0 ;
2016-12-18 20:42:11 +00:00
if ( init_stream_chunk ( & chunk , app , & buffer , i , data , sizeof ( data ) ) ) {
2016-07-17 02:24:13 +00:00
Buffer_Edit * edit = edits ;
2016-08-29 01:03:26 +00:00
int32_t buffer_size = buffer . size ;
int32_t still_looping = true ;
int32_t last_hard = buffer_size ;
2016-07-17 02:24:13 +00:00
do {
for ( ; i < chunk . end ; + + i ) {
char at_pos = chunk . data [ i ] ;
if ( at_pos = = ' \n ' ) {
if ( last_hard + 1 < i ) {
edit - > str_start = 0 ;
edit - > len = 0 ;
edit - > start = last_hard + 1 ;
edit - > end = i ;
+ + edit ;
}
last_hard = buffer_size ;
}
else if ( char_is_whitespace ( at_pos ) ) {
// NOTE(allen): do nothing
}
else {
last_hard = i ;
}
}
still_looping = forward_stream_chunk ( & chunk ) ;
} while ( still_looping ) ;
if ( last_hard + 1 < buffer_size ) {
edit - > str_start = 0 ;
edit - > len = 0 ;
edit - > start = last_hard + 1 ;
edit - > end = buffer_size ;
+ + edit ;
}
2016-08-29 01:03:26 +00:00
int32_t edit_count = ( int32_t ) ( edit - edits ) ;
2016-09-17 00:03:09 +00:00
buffer_batch_edit ( app , & buffer , 0 , 0 , edits , edit_count , BatchEdit_PreserveTokens ) ;
2016-07-17 02:24:13 +00:00
}
}
}
2016-06-14 14:20:15 +00:00
//
// Clipboard
//
2016-09-17 00:03:09 +00:00
static bool32
2016-08-29 01:03:26 +00:00
clipboard_copy ( Application_Links * app , int32_t start , int32_t end , Buffer_Summary * buffer_out ,
uint32_t access ) {
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
bool32 result = 0 ;
2016-06-14 14:20:15 +00:00
2016-06-21 14:00:07 +00:00
if ( buffer . exists ) {
if ( 0 < = start & & start < = end & & end < = buffer . size ) {
2016-08-29 01:03:26 +00:00
int32_t size = ( end - start ) ;
2016-06-21 14:00:07 +00:00
char * str = ( char * ) app - > memory ;
if ( size < = app - > memory_size ) {
2016-09-17 00:03:09 +00:00
buffer_read_range ( app , & buffer , start , end , str ) ;
clipboard_post ( app , 0 , str , size ) ;
2016-06-21 14:00:07 +00:00
if ( buffer_out ) { * buffer_out = buffer ; }
2016-09-17 00:03:09 +00:00
result = 1 ;
2016-06-21 14:00:07 +00:00
}
2016-06-14 14:20:15 +00:00
}
}
return ( result ) ;
}
2016-08-29 01:03:26 +00:00
static int32_t
2016-12-18 20:42:11 +00:00
clipboard_cut ( Application_Links * app , int32_t start , int32_t end , Buffer_Summary * buffer_out , uint32_t access ) {
2016-06-14 14:20:15 +00:00
Buffer_Summary buffer = { 0 } ;
2016-08-29 01:03:26 +00:00
int32_t result = false ;
2016-06-14 14:20:15 +00:00
2016-06-21 17:43:25 +00:00
if ( clipboard_copy ( app , start , end , & buffer , access ) ) {
2016-09-17 00:03:09 +00:00
buffer_replace_range ( app , & buffer , start , end , 0 , 0 ) ;
2016-06-21 17:43:25 +00:00
if ( buffer_out ) { * buffer_out = buffer ; }
2016-06-14 14:20:15 +00:00
}
return ( result ) ;
}
CUSTOM_COMMAND_SIG ( copy ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessProtected ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
2016-06-14 14:20:15 +00:00
Range range = get_range ( & view ) ;
2016-06-20 20:34:48 +00:00
clipboard_copy ( app , range . min , range . max , 0 , access ) ;
2016-06-14 14:20:15 +00:00
}
CUSTOM_COMMAND_SIG ( cut ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessOpen ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
2016-06-14 14:20:15 +00:00
Range range = get_range ( & view ) ;
2016-06-20 20:34:48 +00:00
clipboard_cut ( app , range . min , range . max , 0 , access ) ;
2016-06-14 14:20:15 +00:00
}
2016-07-10 05:49:11 +00:00
enum Rewrite_Type {
RewriteNone ,
RewritePaste ,
RewriteWordComplete
} ;
2016-06-14 19:00:03 +00:00
struct View_Paste_Index {
2016-08-29 01:03:26 +00:00
int32_t rewrite ;
int32_t next_rewrite ;
int32_t index ;
2016-06-14 19:00:03 +00:00
} ;
View_Paste_Index view_paste_index_ [ 16 ] ;
View_Paste_Index * view_paste_index = view_paste_index_ - 1 ;
CUSTOM_COMMAND_SIG ( paste ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessOpen ;
2016-09-17 00:03:09 +00:00
int32_t count = clipboard_count ( app , 0 ) ;
2016-06-14 19:00:03 +00:00
if ( count > 0 ) {
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
2016-06-14 19:00:03 +00:00
2016-07-10 05:49:11 +00:00
view_paste_index [ view . view_id ] . next_rewrite = RewritePaste ;
2016-06-14 19:00:03 +00:00
2016-08-29 01:03:26 +00:00
int32_t paste_index = 0 ;
2016-06-14 19:00:03 +00:00
view_paste_index [ view . view_id ] . index = paste_index ;
2016-09-17 00:03:09 +00:00
int32_t len = clipboard_index ( app , 0 , paste_index , 0 , 0 ) ;
2016-06-14 19:00:03 +00:00
char * str = 0 ;
if ( len < = app - > memory_size ) {
str = ( char * ) app - > memory ;
}
if ( str ) {
2016-09-17 00:03:09 +00:00
clipboard_index ( app , 0 , paste_index , str , len ) ;
2016-06-14 19:00:03 +00:00
2016-09-17 00:03:09 +00:00
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-08-29 01:03:26 +00:00
int32_t pos = view . cursor . pos ;
2016-09-17 00:03:09 +00:00
buffer_replace_range ( app , & buffer , pos , pos , str , len ) ;
view_set_mark ( app , & view , seek_pos ( pos ) ) ;
view_set_cursor ( app , & view , seek_pos ( pos + len ) , true ) ;
2016-06-14 19:00:03 +00:00
// TODO(allen): Send this to all views.
Theme_Color paste ;
paste . tag = Stag_Paste ;
2016-09-17 00:03:09 +00:00
get_theme_colors ( app , & paste , 1 ) ;
view_post_fade ( app , & view , 0.667f , pos , pos + len , paste . color ) ;
2016-06-14 19:00:03 +00:00
}
}
}
CUSTOM_COMMAND_SIG ( paste_next ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessOpen ;
2016-09-17 00:03:09 +00:00
int32_t count = clipboard_count ( app , 0 ) ;
2016-06-14 19:00:03 +00:00
if ( count > 0 ) {
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
2016-06-14 19:00:03 +00:00
2016-07-10 05:49:11 +00:00
if ( view_paste_index [ view . view_id ] . rewrite = = RewritePaste ) {
view_paste_index [ view . view_id ] . next_rewrite = RewritePaste ;
2016-06-14 19:00:03 +00:00
2016-08-29 01:03:26 +00:00
int32_t paste_index = view_paste_index [ view . view_id ] . index + 1 ;
2016-06-14 19:00:03 +00:00
view_paste_index [ view . view_id ] . index = paste_index ;
2016-09-17 00:03:09 +00:00
int32_t len = clipboard_index ( app , 0 , paste_index , 0 , 0 ) ;
2016-06-14 19:00:03 +00:00
char * str = 0 ;
if ( len < = app - > memory_size ) {
str = ( char * ) app - > memory ;
}
if ( str ) {
2016-09-17 00:03:09 +00:00
clipboard_index ( app , 0 , paste_index , str , len ) ;
2016-06-14 19:00:03 +00:00
2016-09-17 00:03:09 +00:00
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-06-14 19:00:03 +00:00
Range range = get_range ( & view ) ;
2016-08-29 01:03:26 +00:00
int32_t pos = range . min ;
2016-06-14 19:00:03 +00:00
2016-09-17 00:03:09 +00:00
buffer_replace_range ( app , & buffer , range . min , range . max , str , len ) ;
view_set_cursor ( app , & view , seek_pos ( pos + len ) , true ) ;
2016-06-14 19:00:03 +00:00
// TODO(allen): Send this to all views.
Theme_Color paste ;
paste . tag = Stag_Paste ;
2016-09-17 00:03:09 +00:00
get_theme_colors ( app , & paste , 1 ) ;
view_post_fade ( app , & view , 0.667f , pos , pos + len , paste . color ) ;
2016-06-14 19:00:03 +00:00
}
}
else {
exec_command ( app , paste ) ;
}
}
}
2016-06-14 14:20:15 +00:00
2016-07-17 02:24:13 +00:00
CUSTOM_COMMAND_SIG ( paste_and_indent ) {
exec_command ( app , paste ) ;
exec_command ( app , auto_tab_range ) ;
}
CUSTOM_COMMAND_SIG ( paste_next_and_indent ) {
exec_command ( app , paste_next ) ;
exec_command ( app , auto_tab_range ) ;
}
2016-07-05 13:11:26 +00:00
//
// Fancy Editing
//
CUSTOM_COMMAND_SIG ( to_uppercase ) {
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , AccessOpen ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , AccessOpen ) ;
2016-07-05 13:11:26 +00:00
Range range = get_range ( & view ) ;
2016-08-29 01:03:26 +00:00
int32_t size = range . max - range . min ;
2016-07-05 13:11:26 +00:00
if ( size < = app - > memory_size ) {
char * mem = ( char * ) app - > memory ;
2016-09-17 00:03:09 +00:00
buffer_read_range ( app , & buffer , range . min , range . max , mem ) ;
2016-08-29 01:03:26 +00:00
for ( int32_t i = 0 ; i < size ; + + i ) {
2016-07-05 13:11:26 +00:00
mem [ i ] = char_to_upper ( mem [ i ] ) ;
}
2016-09-17 00:03:09 +00:00
buffer_replace_range ( app , & buffer , range . min , range . max , mem , size ) ;
view_set_cursor ( app , & view , seek_pos ( range . max ) , true ) ;
2016-07-05 13:11:26 +00:00
}
}
CUSTOM_COMMAND_SIG ( to_lowercase ) {
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , AccessOpen ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , AccessOpen ) ;
2016-07-05 13:11:26 +00:00
Range range = get_range ( & view ) ;
2016-08-29 01:03:26 +00:00
int32_t size = range . max - range . min ;
2016-07-05 13:11:26 +00:00
if ( size < = app - > memory_size ) {
char * mem = ( char * ) app - > memory ;
2016-09-17 00:03:09 +00:00
buffer_read_range ( app , & buffer , range . min , range . max , mem ) ;
2016-08-29 01:03:26 +00:00
for ( int32_t i = 0 ; i < size ; + + i ) {
2016-07-05 13:11:26 +00:00
mem [ i ] = char_to_lower ( mem [ i ] ) ;
}
2016-09-17 00:03:09 +00:00
buffer_replace_range ( app , & buffer , range . min , range . max , mem , size ) ;
view_set_cursor ( app , & view , seek_pos ( range . max ) , true ) ;
2016-07-05 13:11:26 +00:00
}
}
2016-06-03 16:20:45 +00:00
//
// Various Forms of Seek
//
2016-08-29 01:03:26 +00:00
static int32_t
buffer_seek_whitespace_up ( Application_Links * app , Buffer_Summary * buffer , int32_t pos ) {
2016-06-03 16:20:45 +00:00
char chunk [ 1024 ] ;
2016-08-29 01:03:26 +00:00
int32_t chunk_size = sizeof ( chunk ) ;
2016-06-03 16:20:45 +00:00
Stream_Chunk stream = { 0 } ;
char at_pos ;
- - pos ;
if ( init_stream_chunk ( & stream , app , buffer , pos , chunk , chunk_size ) ) {
// Step 1: Find the first non-whitespace character
// behind the current position.
2016-10-27 23:45:41 +00:00
int32_t still_looping = 1 ;
while ( still_looping ) {
2016-06-03 16:20:45 +00:00
for ( ; pos > = stream . start ; - - pos ) {
at_pos = stream . data [ pos ] ;
if ( ! char_is_whitespace ( at_pos ) ) {
goto double_break_1 ;
}
}
still_looping = backward_stream_chunk ( & stream ) ;
2016-10-27 23:45:41 +00:00
}
2016-06-03 16:20:45 +00:00
double_break_1 : ;
// Step 2: Continue scanning backward, at each '\n'
// mark the beginning of another line by setting
// no_hard to true, set it back to false if a
// non-whitespace character is discovered before
// the next '\n'
2016-10-27 23:45:41 +00:00
int32_t no_hard = false ;
2016-06-03 16:20:45 +00:00
while ( still_looping ) {
for ( ; pos > = stream . start ; - - pos ) {
at_pos = stream . data [ pos ] ;
if ( at_pos = = ' \n ' ) {
if ( no_hard ) {
goto double_break_2 ;
}
else {
no_hard = true ;
}
}
else if ( ! char_is_whitespace ( at_pos ) ) {
no_hard = false ;
}
}
still_looping = backward_stream_chunk ( & stream ) ;
}
double_break_2 : ;
if ( pos ! = 0 ) {
+ + pos ;
}
}
2016-12-08 17:16:50 +00:00
2016-06-03 16:20:45 +00:00
return ( pos ) ;
}
2016-08-29 01:03:26 +00:00
static int32_t
buffer_seek_whitespace_down ( Application_Links * app , Buffer_Summary * buffer , int32_t pos ) {
2016-06-03 16:20:45 +00:00
char chunk [ 1024 ] ;
2016-08-29 01:03:26 +00:00
int32_t chunk_size = sizeof ( chunk ) ;
2016-06-03 16:20:45 +00:00
Stream_Chunk stream = { 0 } ;
2016-08-29 01:03:26 +00:00
int32_t no_hard ;
int32_t prev_endline ;
int32_t still_looping ;
2016-06-03 16:20:45 +00:00
char at_pos ;
if ( init_stream_chunk ( & stream , app , buffer , pos , chunk , chunk_size ) ) {
2016-08-29 01:03:26 +00:00
// step 1: find the first non-whitespace character
2016-06-03 16:20:45 +00:00
// ahead of the current position.
still_looping = true ;
do {
for ( ; pos < stream . end ; + + pos ) {
at_pos = stream . data [ pos ] ;
if ( ! char_is_whitespace ( at_pos ) ) {
goto double_break_1 ;
}
}
still_looping = forward_stream_chunk ( & stream ) ;
} while ( still_looping ) ;
double_break_1 : ;
2016-08-29 01:03:26 +00:00
// step 2: continue scanning forward, at each '\n'
2016-06-03 16:20:45 +00:00
// mark it as the beginning of a new line by updating
2016-08-29 01:03:26 +00:00
// the prev_endline value. if another '\n' is found
2016-06-03 16:20:45 +00:00
// with non-whitespace then the previous line was
// all whitespace.
no_hard = false ;
prev_endline = - 1 ;
while ( still_looping ) {
for ( ; pos < stream . end ; + + pos ) {
at_pos = stream . data [ pos ] ;
if ( at_pos = = ' \n ' ) {
if ( no_hard ) {
goto double_break_2 ;
}
else {
no_hard = true ;
prev_endline = pos ;
}
}
else if ( ! char_is_whitespace ( at_pos ) ) {
no_hard = false ;
}
}
still_looping = forward_stream_chunk ( & stream ) ;
}
double_break_2 : ;
if ( prev_endline = = - 1 | | prev_endline + 1 > = buffer - > size ) {
pos = buffer - > size ;
}
else {
pos = prev_endline + 1 ;
}
}
return ( pos ) ;
}
CUSTOM_COMMAND_SIG ( seek_whitespace_up ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessProtected ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-06-03 16:20:45 +00:00
2016-08-29 01:03:26 +00:00
int32_t new_pos = buffer_seek_whitespace_up ( app , & buffer , view . cursor . pos ) ;
2016-09-17 00:03:09 +00:00
view_set_cursor ( app , & view ,
2016-12-08 17:16:50 +00:00
seek_pos ( new_pos ) ,
true ) ;
2016-06-03 16:20:45 +00:00
}
CUSTOM_COMMAND_SIG ( seek_whitespace_down ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessProtected ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-06-03 16:20:45 +00:00
2016-08-29 01:03:26 +00:00
int32_t new_pos = buffer_seek_whitespace_down ( app , & buffer , view . cursor . pos ) ;
2016-09-17 00:03:09 +00:00
view_set_cursor ( app , & view ,
2016-12-08 17:16:50 +00:00
seek_pos ( new_pos ) ,
true ) ;
2016-06-06 18:41:17 +00:00
}
2016-10-06 01:38:08 +00:00
CUSTOM_COMMAND_SIG ( seek_end_of_textual_line ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessProtected ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-06-06 18:41:17 +00:00
2016-08-29 01:03:26 +00:00
int32_t new_pos = seek_line_end ( app , & buffer , view . cursor . pos ) ;
2016-09-17 00:03:09 +00:00
view_set_cursor ( app , & view , seek_pos ( new_pos ) , true ) ;
2016-06-06 18:41:17 +00:00
}
2016-10-06 01:38:08 +00:00
CUSTOM_COMMAND_SIG ( seek_beginning_of_textual_line ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessProtected ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-06-06 18:41:17 +00:00
2016-08-29 01:03:26 +00:00
int32_t new_pos = seek_line_beginning ( app , & buffer , view . cursor . pos ) ;
2016-09-17 00:03:09 +00:00
view_set_cursor ( app , & view , seek_pos ( new_pos ) , true ) ;
2016-03-15 14:12:06 +00:00
}
2016-10-06 01:38:08 +00:00
CUSTOM_COMMAND_SIG ( seek_beginning_of_line ) {
View_Summary view = get_active_view ( app , AccessProtected ) ;
float y = view . cursor . wrapped_y ;
if ( view . unwrapped_lines ) {
y = view . cursor . unwrapped_y ;
}
view_set_cursor ( app , & view , seek_xy ( 0 , y , 1 , view . unwrapped_lines ) , 1 ) ;
}
CUSTOM_COMMAND_SIG ( seek_end_of_line ) {
View_Summary view = get_active_view ( app , AccessProtected ) ;
float y = view . cursor . wrapped_y ;
if ( view . unwrapped_lines ) {
y = view . cursor . unwrapped_y ;
}
view_set_cursor ( app , & view , seek_xy ( 100000.f , y , 1 , view . unwrapped_lines ) , 1 ) ;
}
2016-09-08 22:03:43 +00:00
// TODO(allen): REDUCE DUPLICATION!
static int32_t
buffer_seek_whitespace_right ( Application_Links * app , Buffer_Summary * buffer , int32_t pos ) {
char data_chunk [ 1024 ] ;
Stream_Chunk stream = { 0 } ;
if ( init_stream_chunk ( & stream , app , buffer ,
pos , data_chunk , sizeof ( data_chunk ) ) ) {
bool32 still_looping = 1 ;
do {
for ( ; pos < stream . end ; + + pos ) {
if ( ! char_is_whitespace ( stream . data [ pos ] ) ) {
goto double_break1 ;
}
}
still_looping = forward_stream_chunk ( & stream ) ;
} while ( still_looping ) ;
double_break1 : ;
still_looping = 1 ;
do {
for ( ; pos < stream . end ; + + pos ) {
if ( char_is_whitespace ( stream . data [ pos ] ) ) {
goto double_break2 ;
}
}
still_looping = forward_stream_chunk ( & stream ) ;
} while ( still_looping ) ;
double_break2 : ;
}
return ( pos ) ;
}
static int32_t
buffer_seek_whitespace_left ( Application_Links * app , Buffer_Summary * buffer , int32_t pos ) {
char data_chunk [ 1024 ] ;
Stream_Chunk stream = { 0 } ;
- - pos ;
if ( pos > 0 ) {
if ( init_stream_chunk ( & stream , app , buffer ,
pos , data_chunk , sizeof ( data_chunk ) ) ) {
bool32 still_looping = 1 ;
do {
for ( ; pos > = stream . start ; - - pos ) {
if ( ! char_is_whitespace ( stream . data [ pos ] ) ) {
goto double_break1 ;
}
}
still_looping = backward_stream_chunk ( & stream ) ;
} while ( still_looping ) ;
double_break1 : ;
still_looping = 1 ;
do {
for ( ; pos > = stream . start ; - - pos ) {
if ( char_is_whitespace ( stream . data [ pos ] ) ) {
+ + pos ;
goto double_break2 ;
}
}
still_looping = backward_stream_chunk ( & stream ) ;
} while ( still_looping ) ;
double_break2 : ;
}
}
else {
pos = 0 ;
}
return ( pos ) ;
}
static int32_t
buffer_seek_alphanumeric_right ( Application_Links * app , Buffer_Summary * buffer , int32_t pos ) {
char data_chunk [ 1024 ] ;
Stream_Chunk stream = { 0 } ;
if ( init_stream_chunk ( & stream , app , buffer ,
pos , data_chunk , sizeof ( data_chunk ) ) ) {
bool32 still_looping = 1 ;
do {
for ( ; pos < stream . end ; + + pos ) {
if ( char_is_alpha_numeric_true ( stream . data [ pos ] ) ) {
goto double_break1 ;
}
}
still_looping = forward_stream_chunk ( & stream ) ;
} while ( still_looping ) ;
double_break1 : ;
still_looping = 1 ;
do {
for ( ; pos < stream . end ; + + pos ) {
if ( ! char_is_alpha_numeric_true ( stream . data [ pos ] ) ) {
goto double_break2 ;
}
}
still_looping = forward_stream_chunk ( & stream ) ;
} while ( still_looping ) ;
double_break2 : ;
}
return ( pos ) ;
}
static int32_t
buffer_seek_alphanumeric_left ( Application_Links * app , Buffer_Summary * buffer , int32_t pos ) {
char data_chunk [ 1024 ] ;
Stream_Chunk stream = { 0 } ;
- - pos ;
if ( pos > 0 ) {
if ( init_stream_chunk ( & stream , app , buffer ,
pos , data_chunk , sizeof ( data_chunk ) ) ) {
bool32 still_looping = 1 ;
do {
for ( ; pos > = stream . start ; - - pos ) {
if ( char_is_alpha_numeric_true ( stream . data [ pos ] ) ) {
goto double_break1 ;
}
}
still_looping = backward_stream_chunk ( & stream ) ;
} while ( still_looping ) ;
double_break1 : ;
still_looping = 1 ;
do {
for ( ; pos > = stream . start ; - - pos ) {
if ( ! char_is_alpha_numeric_true ( stream . data [ pos ] ) ) {
+ + pos ;
goto double_break2 ;
}
}
still_looping = backward_stream_chunk ( & stream ) ;
} while ( still_looping ) ;
double_break2 : ;
}
}
else {
pos = 0 ;
}
return ( pos ) ;
}
static int32_t
buffer_seek_range_camel_right ( Application_Links * app , Buffer_Summary * buffer , int32_t pos , int32_t an_pos ) {
char data_chunk [ 1024 ] ;
Stream_Chunk stream = { 0 } ;
+ + pos ;
if ( pos < an_pos ) {
stream . max_end = an_pos ;
if ( init_stream_chunk ( & stream , app , buffer ,
pos , data_chunk , sizeof ( data_chunk ) ) ) {
char c = 0 , pc = stream . data [ pos ] ;
+ + pos ;
bool32 still_looping = 1 ;
do {
for ( ; pos < stream . end ; + + pos ) {
c = stream . data [ pos ] ;
if ( char_is_upper ( c ) & & char_is_lower ( pc ) ) {
goto double_break1 ;
}
pc = c ;
}
still_looping = forward_stream_chunk ( & stream ) ;
} while ( still_looping ) ;
double_break1 : ;
}
}
else {
pos = an_pos ;
}
return ( pos ) ;
}
static int32_t
buffer_seek_range_camel_left ( Application_Links * app , Buffer_Summary * buffer , int32_t pos , int32_t an_pos ) {
char data_chunk [ 1024 ] ;
Stream_Chunk stream = { 0 } ;
- - pos ;
if ( pos > 0 ) {
stream . min_start = an_pos + 1 ;
if ( init_stream_chunk ( & stream , app , buffer ,
pos , data_chunk , sizeof ( data_chunk ) ) ) {
char c = 0 , pc = stream . data [ pos ] ;
bool32 still_looping = 1 ;
do {
for ( ; pos > = stream . start ; - - pos ) {
c = stream . data [ pos ] ;
if ( char_is_upper ( c ) & & char_is_lower ( pc ) ) {
goto double_break1 ;
}
pc = c ;
}
still_looping = backward_stream_chunk ( & stream ) ;
} while ( still_looping ) ;
double_break1 : ;
}
}
else {
pos = 0 ;
}
return ( pos ) ;
}
static int32_t
buffer_seek_alphanumeric_or_camel_right ( Application_Links * app , Buffer_Summary * buffer , int32_t pos ) {
int32_t an_pos = buffer_seek_alphanumeric_right ( app , buffer , pos ) ;
int32_t result = buffer_seek_range_camel_right ( app , buffer , pos , an_pos ) ;
return ( result ) ;
}
static int32_t
buffer_seek_alphanumeric_or_camel_left ( Application_Links * app , Buffer_Summary * buffer , int32_t pos ) {
int32_t an_pos = buffer_seek_alphanumeric_left ( app , buffer , pos ) ;
int32_t result = buffer_seek_range_camel_left ( app , buffer , pos , an_pos ) ;
return ( result ) ;
}
static int32_t
seek_token_left ( Cpp_Token_Array * tokens , int32_t pos ) {
2016-09-23 17:50:55 +00:00
Cpp_Get_Token_Result get = cpp_get_token ( * tokens , pos ) ;
2016-09-08 22:03:43 +00:00
if ( get . token_index = = - 1 ) {
get . token_index = 0 ;
}
Cpp_Token * token = tokens - > tokens + get . token_index ;
if ( token - > start = = pos & & get . token_index > 0 ) {
- - token ;
}
2016-09-13 23:59:48 +00:00
return ( token - > start ) ;
2016-09-08 22:03:43 +00:00
}
static int32_t
seek_token_right ( Cpp_Token_Array * tokens , int32_t pos ) {
2016-09-23 17:50:55 +00:00
Cpp_Get_Token_Result get = cpp_get_token ( * tokens , pos ) ;
2016-09-08 22:03:43 +00:00
if ( get . in_whitespace ) {
+ + get . token_index ;
}
if ( get . token_index > = tokens - > count ) {
get . token_index = tokens - > count - 1 ;
}
Cpp_Token * token = tokens - > tokens + get . token_index ;
2016-09-13 23:59:48 +00:00
return ( token - > start + token - > size ) ;
}
static Cpp_Token_Array
buffer_get_all_tokens ( Application_Links * app , Partition * part , Buffer_Summary * buffer ) {
Cpp_Token_Array array = { 0 } ;
if ( buffer - > exists & & buffer - > is_lexed ) {
2016-09-17 00:03:09 +00:00
array . count = buffer_token_count ( app , buffer ) ;
2016-09-13 23:59:48 +00:00
array . max_count = array . count ;
array . tokens = push_array ( part , Cpp_Token , array . count ) ;
2016-09-17 00:03:09 +00:00
buffer_read_tokens ( app , buffer , 0 , array . count , array . tokens ) ;
2016-09-13 23:59:48 +00:00
}
return ( array ) ;
2016-09-08 22:03:43 +00:00
}
static int32_t
2016-09-13 23:59:48 +00:00
buffer_boundary_seek ( Application_Links * app , Buffer_Summary * buffer , Partition * part ,
int32_t start_pos , bool32 seek_forward , Seek_Boundary_Flag flags ) /*
2016-09-08 22:03:43 +00:00
DOC_PARAM ( buffer , The buffer parameter specifies the buffer through which to seek . )
DOC_PARAM ( start_pos , The beginning position of the seek is specified by start_pos measured in absolute position . )
DOC_PARAM ( seek_forward , If this parameter is non - zero it indicates that the seek should move foward through the buffer . )
DOC_PARAM ( flags , This field specifies the types of boundaries at which the seek should stop . )
2016-09-13 23:59:48 +00:00
2016-09-08 22:03:43 +00:00
DOC_RETURN ( This call returns the absolute position where the seek stopped .
If the seek goes below 0 the returned value is - 1.
If the seek goes past the end the returned value is the size of the buffer . )
2016-09-13 23:59:48 +00:00
2016-09-08 22:03:43 +00:00
DOC_SEE ( Seek_Boundary_Flag )
DOC_SEE ( 4 coder_Buffer_Positioning_System )
*/ {
int32_t result = 0 ;
2016-09-13 23:59:48 +00:00
// TODO(allen): reduce duplication?
Temp_Memory temp = begin_temp_memory ( part ) ;
2016-09-08 22:03:43 +00:00
if ( buffer - > exists ) {
2016-09-13 23:59:48 +00:00
int32_t pos [ 4 ] ;
2016-09-08 22:03:43 +00:00
int32_t size = buffer - > size ;
int32_t new_pos = 0 ;
if ( start_pos < 0 ) {
start_pos = 0 ;
}
else if ( start_pos > size ) {
start_pos = size ;
}
if ( seek_forward ) {
2016-09-13 23:59:48 +00:00
for ( int32_t i = 0 ; i < ArrayCount ( pos ) ; + + i ) {
pos [ i ] = size ;
}
2016-09-08 22:03:43 +00:00
2016-09-13 23:59:48 +00:00
if ( flags & BoundaryWhitespace ) {
2016-09-08 22:03:43 +00:00
pos [ 0 ] = buffer_seek_whitespace_right ( app , buffer , start_pos ) ;
}
2016-09-13 23:59:48 +00:00
if ( flags & BoundaryToken ) {
2016-09-08 22:03:43 +00:00
if ( buffer - > tokens_are_ready ) {
2016-09-13 23:59:48 +00:00
Cpp_Token_Array array = buffer_get_all_tokens ( app , part , buffer ) ;
2016-09-08 22:03:43 +00:00
pos [ 1 ] = seek_token_right ( & array , start_pos ) ;
}
else {
pos [ 1 ] = buffer_seek_whitespace_right ( app , buffer , start_pos ) ;
}
}
2016-09-13 23:59:48 +00:00
if ( flags & BoundaryAlphanumeric ) {
2016-09-08 22:03:43 +00:00
pos [ 2 ] = buffer_seek_alphanumeric_right ( app , buffer , start_pos ) ;
2016-09-13 23:59:48 +00:00
if ( flags & BoundaryCamelCase ) {
2016-09-08 22:03:43 +00:00
pos [ 3 ] = buffer_seek_range_camel_right ( app , buffer , start_pos , pos [ 2 ] ) ;
}
}
else {
2016-09-13 23:59:48 +00:00
if ( flags & BoundaryCamelCase ) {
2016-09-08 22:03:43 +00:00
pos [ 3 ] = buffer_seek_alphanumeric_or_camel_right ( app , buffer , start_pos ) ;
}
}
new_pos = size ;
for ( int32_t i = 0 ; i < ArrayCount ( pos ) ; + + i ) {
2016-09-13 23:59:48 +00:00
if ( pos [ i ] < new_pos ) {
new_pos = pos [ i ] ;
}
2016-09-08 22:03:43 +00:00
}
}
else {
2016-09-13 23:59:48 +00:00
for ( int32_t i = 0 ; i < ArrayCount ( pos ) ; + + i ) {
pos [ i ] = 0 ;
}
if ( flags & BoundaryWhitespace ) {
2016-09-08 22:03:43 +00:00
pos [ 0 ] = buffer_seek_whitespace_left ( app , buffer , start_pos ) ;
}
2016-09-13 23:59:48 +00:00
if ( flags & BoundaryToken ) {
2016-09-08 22:03:43 +00:00
if ( buffer - > tokens_are_ready ) {
2016-09-13 23:59:48 +00:00
Cpp_Token_Array array = buffer_get_all_tokens ( app , part , buffer ) ;
2016-09-08 22:03:43 +00:00
pos [ 1 ] = seek_token_left ( & array , start_pos ) ;
}
else {
pos [ 1 ] = buffer_seek_whitespace_left ( app , buffer , start_pos ) ;
}
}
2016-09-13 23:59:48 +00:00
if ( flags & BoundaryAlphanumeric ) {
2016-09-08 22:03:43 +00:00
pos [ 2 ] = buffer_seek_alphanumeric_left ( app , buffer , start_pos ) ;
2016-09-13 23:59:48 +00:00
if ( flags & BoundaryCamelCase ) {
2016-09-08 22:03:43 +00:00
pos [ 3 ] = buffer_seek_range_camel_left ( app , buffer , start_pos , pos [ 2 ] ) ;
}
}
else {
2016-09-13 23:59:48 +00:00
if ( flags & BoundaryCamelCase ) {
2016-09-08 22:03:43 +00:00
pos [ 3 ] = buffer_seek_alphanumeric_or_camel_left ( app , buffer , start_pos ) ;
}
}
new_pos = 0 ;
for ( int32_t i = 0 ; i < ArrayCount ( pos ) ; + + i ) {
2016-09-13 23:59:48 +00:00
if ( pos [ i ] > new_pos ) {
new_pos = pos [ i ] ;
}
2016-09-08 22:03:43 +00:00
}
}
result = new_pos ;
}
2016-09-13 23:59:48 +00:00
end_temp_memory ( temp ) ;
2016-09-08 22:03:43 +00:00
return ( result ) ;
}
2016-09-13 23:59:48 +00:00
static int32_t
buffer_boundary_seek ( Application_Links * app , Buffer_Summary * buffer ,
int32_t start_pos , bool32 seek_forward , Seek_Boundary_Flag flags ) {
int32_t result = buffer_boundary_seek ( app , buffer , & global_part , start_pos , seek_forward , flags ) ;
return ( result ) ;
}
2016-03-15 14:12:06 +00:00
static void
2016-08-29 01:03:26 +00:00
basic_seek ( Application_Links * app , int32_t seek_type , uint32_t flags ) {
uint32_t access = AccessProtected ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-09-08 22:03:43 +00:00
int32_t pos = buffer_boundary_seek ( app , & buffer , view . cursor . pos , seek_type , flags ) ;
2016-09-17 00:03:09 +00:00
view_set_cursor ( app , & view , seek_pos ( pos ) , true ) ;
2016-03-15 14:12:06 +00:00
}
2016-08-29 01:03:26 +00:00
# define seek_command(n, dir, flags)\
2016-06-13 16:56:33 +00:00
CUSTOM_COMMAND_SIG ( seek_ # # n # # _ # # dir ) { basic_seek ( app , dir , flags ) ; }
# define right true
# define left false
2016-08-29 01:03:26 +00:00
seek_command ( whitespace , right , BoundaryWhitespace )
seek_command ( whitespace , left , BoundaryWhitespace )
seek_command ( token , right , BoundaryToken )
seek_command ( token , left , BoundaryToken )
seek_command ( white_or_token , right , BoundaryToken | BoundaryWhitespace )
seek_command ( white_or_token , left , BoundaryToken | BoundaryWhitespace )
seek_command ( alphanumeric , right , BoundaryAlphanumeric )
seek_command ( alphanumeric , left , BoundaryAlphanumeric )
seek_command ( alphanumeric_or_camel , right , BoundaryAlphanumeric | BoundaryCamelCase )
seek_command ( alphanumeric_or_camel , left , BoundaryAlphanumeric | BoundaryCamelCase )
2016-06-13 16:56:33 +00:00
# undef right
# undef left
2016-03-15 14:12:06 +00:00
2016-06-03 16:20:45 +00:00
//
2016-08-29 01:03:26 +00:00
// special string writing commands
2016-06-03 16:20:45 +00:00
//
2016-10-25 02:45:34 +00:00
static void
write_string ( Application_Links * app , View_Summary * view , Buffer_Summary * buffer , String string ) {
buffer_replace_range ( app , buffer , view - > cursor . pos , view - > cursor . pos , string . str , string . size ) ;
view_set_cursor ( app , view , seek_pos ( view - > cursor . pos + string . size ) , 1 ) ;
}
2016-06-03 16:20:45 +00:00
static void
write_string ( Application_Links * app , String string ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessOpen ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-10-25 02:45:34 +00:00
write_string ( app , & view , & buffer , string ) ;
2016-06-03 16:20:45 +00:00
}
CUSTOM_COMMAND_SIG ( write_increment ) {
write_string ( app , make_lit_string ( " ++ " ) ) ;
}
2016-03-15 14:12:06 +00:00
static void
2016-08-29 01:03:26 +00:00
long_braces ( Application_Links * app , char * text , int32_t size ) {
uint32_t access = AccessOpen ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-08-29 01:03:26 +00:00
int32_t pos = view . cursor . pos ;
2016-06-13 16:56:33 +00:00
2016-09-17 00:03:09 +00:00
buffer_replace_range ( app , & buffer , pos , pos , text , size ) ;
view_set_cursor ( app , & view , seek_pos ( pos + 2 ) , true ) ;
2016-06-13 16:56:33 +00:00
2016-12-18 20:42:11 +00:00
buffer_auto_indent ( app , & buffer , pos , pos + size , DEF_TAB_WIDTH , DEFAULT_INDENT_FLAGS | AutoIndent_FullTokens ) ;
2016-06-24 03:11:24 +00:00
move_past_lead_whitespace ( app , & view , & buffer ) ;
2016-03-15 14:12:06 +00:00
}
CUSTOM_COMMAND_SIG ( open_long_braces ) {
char text [ ] = " { \n \n } " ;
2016-08-29 01:03:26 +00:00
int32_t size = sizeof ( text ) - 1 ;
2016-03-15 14:12:06 +00:00
long_braces ( app , text , size ) ;
}
CUSTOM_COMMAND_SIG ( open_long_braces_semicolon ) {
char text [ ] = " { \n \n }; " ;
2016-08-29 01:03:26 +00:00
int32_t size = sizeof ( text ) - 1 ;
2016-03-15 14:12:06 +00:00
long_braces ( app , text , size ) ;
}
CUSTOM_COMMAND_SIG ( open_long_braces_break ) {
char text [ ] = " { \n \n }break; " ;
2016-08-29 01:03:26 +00:00
int32_t size = sizeof ( text ) - 1 ;
2016-03-15 14:12:06 +00:00
long_braces ( app , text , size ) ;
}
2016-08-29 01:03:26 +00:00
// TODO(allen): have this thing check if it is on
2016-05-20 14:54:06 +00:00
// a blank line and insert newlines as needed.
2016-03-15 14:12:06 +00:00
CUSTOM_COMMAND_SIG ( if0_off ) {
2016-05-23 14:41:39 +00:00
char text1 [ ] = " \n #if 0 " ;
2016-08-29 01:03:26 +00:00
int32_t size1 = sizeof ( text1 ) - 1 ;
2016-06-21 14:00:07 +00:00
2016-05-23 14:41:39 +00:00
char text2 [ ] = " #endif \n " ;
2016-08-29 01:03:26 +00:00
int32_t size2 = sizeof ( text2 ) - 1 ;
2016-06-21 14:00:07 +00:00
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , AccessOpen ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , AccessOpen ) ;
2016-06-10 15:19:29 +00:00
2016-07-13 23:19:42 +00:00
Range range = get_range ( & view ) ;
2016-06-10 15:19:29 +00:00
2016-07-13 23:19:42 +00:00
if ( range . min < range . max ) {
Buffer_Edit edits [ 2 ] ;
char * str = 0 ;
char * base = ( char * ) partition_current ( & global_part ) ;
str = push_array ( & global_part , char , size1 ) ;
memcpy ( str , text1 , size1 ) ;
2016-08-29 01:03:26 +00:00
edits [ 0 ] . str_start = ( int32_t ) ( str - base ) ;
2016-07-13 23:19:42 +00:00
edits [ 0 ] . len = size1 ;
edits [ 0 ] . start = range . min ;
edits [ 0 ] . end = range . min ;
str = push_array ( & global_part , char , size2 ) ;
memcpy ( str , text2 , size2 ) ;
2016-08-29 01:03:26 +00:00
edits [ 1 ] . str_start = ( int32_t ) ( str - base ) ;
2016-07-13 23:19:42 +00:00
edits [ 1 ] . len = size2 ;
edits [ 1 ] . start = range . max ;
edits [ 1 ] . end = range . max ;
2016-12-18 20:42:11 +00:00
buffer_batch_edit ( app , & buffer , base , global_part . pos , edits , ArrayCount ( edits ) , BatchEdit_Normal ) ;
2016-07-13 23:19:42 +00:00
2016-09-17 00:03:09 +00:00
view = get_view ( app , view . view_id , AccessAll ) ;
2016-07-13 23:19:42 +00:00
if ( view . cursor . pos > view . mark . pos ) {
2016-12-18 20:42:11 +00:00
view_set_cursor ( app , & view , seek_line_char ( view . cursor . line + 1 , view . cursor . character ) , 1 ) ;
2016-07-13 23:19:42 +00:00
}
else {
2016-12-18 20:42:11 +00:00
view_set_mark ( app , & view , seek_line_char ( view . mark . line + 1 , view . mark . character ) ) ;
2016-07-13 23:19:42 +00:00
}
range = get_range ( & view ) ;
2016-12-18 20:42:11 +00:00
buffer_auto_indent ( app , & buffer , range . min , range . max , DEF_TAB_WIDTH , DEFAULT_INDENT_FLAGS | AutoIndent_FullTokens ) ;
2016-07-13 23:19:42 +00:00
move_past_lead_whitespace ( app , & view , & buffer ) ;
}
2016-03-15 14:12:06 +00:00
}
2016-07-10 05:49:11 +00:00
2016-06-28 19:48:12 +00:00
//
2016-07-10 05:49:11 +00:00
// Fast Deletes
2016-06-28 19:48:12 +00:00
//
2016-03-15 14:12:06 +00:00
CUSTOM_COMMAND_SIG ( backspace_word ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessOpen ;
2016-06-20 20:34:48 +00:00
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-06-10 15:19:29 +00:00
2016-07-14 17:18:40 +00:00
if ( buffer . exists ) {
2016-08-29 01:03:26 +00:00
int32_t pos2 = 0 , pos1 = 0 ;
2016-07-14 17:18:40 +00:00
pos2 = view . cursor . pos ;
exec_command ( app , seek_alphanumeric_left ) ;
refresh_view ( app , & view ) ;
pos1 = view . cursor . pos ;
2016-08-29 01:03:26 +00:00
2016-09-17 00:03:09 +00:00
buffer_replace_range ( app , & buffer , pos1 , pos2 , 0 , 0 ) ;
2016-07-14 17:18:40 +00:00
}
2016-06-10 15:19:29 +00:00
}
2016-03-15 14:12:06 +00:00
2016-06-10 15:19:29 +00:00
CUSTOM_COMMAND_SIG ( delete_word ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessOpen ;
2016-06-20 20:34:48 +00:00
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-06-10 15:19:29 +00:00
2016-07-14 17:18:40 +00:00
if ( buffer . exists ) {
2016-08-29 01:03:26 +00:00
int32_t pos2 = 0 , pos1 = 0 ;
2016-07-14 17:18:40 +00:00
pos1 = view . cursor . pos ;
exec_command ( app , seek_alphanumeric_right ) ;
refresh_view ( app , & view ) ;
pos2 = view . cursor . pos ;
2016-09-17 00:03:09 +00:00
buffer_replace_range ( app , & buffer , pos1 , pos2 , 0 , 0 ) ;
2016-07-14 17:18:40 +00:00
}
2016-03-15 14:12:06 +00:00
}
CUSTOM_COMMAND_SIG ( snipe_token_or_word ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessOpen ;
2016-06-20 20:34:48 +00:00
2016-10-27 23:45:41 +00:00
View_Summary view = get_active_view ( app , access ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-06-06 17:33:23 +00:00
2016-12-18 20:42:11 +00:00
int32_t pos1 = buffer_boundary_seek ( app , & buffer , view . cursor . pos , 0 , BoundaryToken | BoundaryWhitespace ) ;
int32_t pos2 = buffer_boundary_seek ( app , & buffer , pos1 , 1 , BoundaryToken | BoundaryWhitespace ) ;
2016-06-06 17:33:23 +00:00
2016-03-15 14:12:06 +00:00
Range range = make_range ( pos1 , pos2 ) ;
2016-09-17 00:03:09 +00:00
buffer_replace_range ( app , & buffer , range . start , range . end , 0 , 0 ) ;
2016-03-15 14:12:06 +00:00
}
2016-06-29 18:38:58 +00:00
//
// Scroll Bar Controlling
//
CUSTOM_COMMAND_SIG ( show_scrollbar ) {
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , AccessProtected ) ;
view_set_setting ( app , & view , ViewSetting_ShowScrollbar , true ) ;
2016-06-29 18:38:58 +00:00
}
CUSTOM_COMMAND_SIG ( hide_scrollbar ) {
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , AccessProtected ) ;
view_set_setting ( app , & view , ViewSetting_ShowScrollbar , false ) ;
2016-06-29 18:38:58 +00:00
}
2016-06-28 19:48:12 +00:00
//
2016-07-05 01:36:30 +00:00
// Panel Management
2016-06-28 19:48:12 +00:00
//
2016-07-05 01:36:30 +00:00
2016-09-01 19:40:25 +00:00
static void
get_view_next_looped ( Application_Links * app , View_Summary * view , uint32_t access ) {
2016-09-17 00:03:09 +00:00
get_view_next ( app , view , access ) ;
2016-09-01 19:40:25 +00:00
if ( ! view - > exists ) {
2016-09-17 00:03:09 +00:00
* view = get_view_first ( app , access ) ;
2016-07-05 01:36:30 +00:00
}
2016-09-01 19:40:25 +00:00
}
static View_ID special_note_view_id = 0 ;
static void
close_special_note_view ( Application_Links * app ) {
2016-09-17 00:03:09 +00:00
View_Summary special_view = get_view ( app , special_note_view_id , AccessAll ) ;
2016-09-01 19:40:25 +00:00
if ( special_view . exists ) {
2016-09-17 00:03:09 +00:00
close_view ( app , & special_view ) ;
2016-07-05 01:36:30 +00:00
}
2016-09-01 19:40:25 +00:00
special_note_view_id = 0 ;
2016-07-05 01:36:30 +00:00
}
2016-09-01 19:40:25 +00:00
static View_Summary
open_special_note_view ( Application_Links * app , bool32 create_if_not_exist = true ) {
2016-09-17 00:03:09 +00:00
View_Summary special_view = get_view ( app , special_note_view_id , AccessAll ) ;
2016-09-01 19:40:25 +00:00
if ( create_if_not_exist & & ! special_view . exists ) {
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , AccessAll ) ;
special_view = open_view ( app , & view , ViewSplit_Bottom ) ;
view_set_setting ( app , & special_view , ViewSetting_ShowScrollbar , false ) ;
view_set_split_proportion ( app , & special_view , .2f ) ;
set_active_view ( app , & view ) ;
2016-09-01 19:40:25 +00:00
special_note_view_id = special_view . view_id ;
}
return ( special_view ) ;
}
2016-07-05 01:36:30 +00:00
2016-09-01 19:40:25 +00:00
CUSTOM_COMMAND_SIG ( change_active_panel ) {
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , AccessAll ) ;
2016-09-01 19:40:25 +00:00
View_ID original_view_id = view . view_id ;
do {
get_view_next_looped ( app , & view , AccessAll ) ;
if ( view . view_id ! = special_note_view_id ) {
break ;
}
} while ( view . view_id ! = original_view_id ) ;
if ( view . exists ) {
2016-09-17 00:03:09 +00:00
set_active_view ( app , & view ) ;
2016-09-01 19:40:25 +00:00
}
}
2016-07-05 01:36:30 +00:00
CUSTOM_COMMAND_SIG ( close_panel ) {
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , AccessAll ) ;
close_view ( app , & view ) ;
2016-07-05 01:36:30 +00:00
}
CUSTOM_COMMAND_SIG ( open_panel_vsplit ) {
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , AccessAll ) ;
View_Summary new_view = open_view ( app , & view , ViewSplit_Right ) ;
view_set_setting ( app , & new_view , ViewSetting_ShowScrollbar , false ) ;
2016-07-05 01:36:30 +00:00
}
CUSTOM_COMMAND_SIG ( open_panel_hsplit ) {
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , AccessAll ) ;
View_Summary new_view = open_view ( app , & view , ViewSplit_Bottom ) ;
view_set_setting ( app , & new_view , ViewSetting_ShowScrollbar , false ) ;
2016-07-05 01:36:30 +00:00
}
//
// Open File In Quotes
2016-06-28 19:48:12 +00:00
//
2016-08-29 01:03:26 +00:00
static int32_t
2016-06-28 19:48:12 +00:00
file_name_in_quotes ( Application_Links * app , String * file_name ) {
2016-08-29 01:03:26 +00:00
int32_t result = false ;
uint32_t access = AccessProtected ;
2016-06-20 20:34:48 +00:00
2016-03-15 14:12:06 +00:00
View_Summary view ;
Buffer_Summary buffer ;
char short_file_name [ 128 ] ;
2016-08-29 01:03:26 +00:00
int32_t pos , start , end , size ;
2016-06-06 17:33:23 +00:00
2016-09-17 00:03:09 +00:00
view = get_active_view ( app , access ) ;
buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-03-15 14:12:06 +00:00
pos = view . cursor . pos ;
2016-05-31 01:22:55 +00:00
buffer_seek_delimiter_forward ( app , & buffer , pos , ' " ' , & end ) ;
buffer_seek_delimiter_backward ( app , & buffer , pos , ' " ' , & start ) ;
2016-06-06 17:33:23 +00:00
2016-03-15 14:12:06 +00:00
+ + start ;
size = end - start ;
2016-06-06 17:33:23 +00:00
2016-09-17 00:03:09 +00:00
// NOTE(allen): This check is necessary because buffer_read_range
2016-03-15 14:12:06 +00:00
// requiers that the output buffer you provide is at least (end - start) bytes long.
if ( size < sizeof ( short_file_name ) ) {
2016-09-17 00:03:09 +00:00
if ( buffer_read_range ( app , & buffer , start , end , short_file_name ) ) {
2016-06-28 19:48:12 +00:00
result = true ;
2016-08-28 04:31:06 +00:00
copy_ss ( file_name , make_string ( buffer . file_name , buffer . file_name_len ) ) ;
2016-06-28 19:48:12 +00:00
remove_last_folder ( file_name ) ;
2016-08-28 04:31:06 +00:00
append_ss ( file_name , make_string ( short_file_name , size ) ) ;
2016-06-28 19:48:12 +00:00
}
}
return ( result ) ;
}
2016-09-01 19:40:25 +00:00
CUSTOM_COMMAND_SIG ( open_file_in_quotes ) {
2016-06-28 19:48:12 +00:00
char file_name_ [ 256 ] ;
String file_name = make_fixed_width_string ( file_name_ ) ;
if ( file_name_in_quotes ( app , & file_name ) ) {
2016-09-01 19:40:25 +00:00
exec_command ( app , change_active_panel ) ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , AccessAll ) ;
2016-09-01 00:26:52 +00:00
view_open_file ( app , & view , expand_str ( file_name ) , true ) ;
2016-03-15 14:12:06 +00:00
}
}
2016-09-01 19:40:25 +00:00
CUSTOM_COMMAND_SIG ( open_in_other ) {
exec_command ( app , change_active_panel ) ;
2016-07-10 05:49:11 +00:00
exec_command ( app , cmdid_interactive_open ) ;
}
2016-06-28 19:48:12 +00:00
2016-03-24 01:05:28 +00:00
CUSTOM_COMMAND_SIG ( save_as ) {
2016-06-13 16:56:33 +00:00
exec_command ( app , cmdid_save_as ) ;
2016-03-24 01:05:28 +00:00
}
2016-03-15 14:12:06 +00:00
CUSTOM_COMMAND_SIG ( goto_line ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessProtected ;
2016-06-20 20:34:48 +00:00
2016-07-10 05:49:11 +00:00
Query_Bar bar = { 0 } ;
2016-03-15 14:12:06 +00:00
char string_space [ 256 ] ;
2016-06-20 20:34:48 +00:00
2016-03-15 14:12:06 +00:00
bar . prompt = make_lit_string ( " Goto Line: " ) ;
bar . string = make_fixed_width_string ( string_space ) ;
2016-06-20 20:34:48 +00:00
2016-03-15 14:12:06 +00:00
if ( query_user_number ( app , & bar ) ) {
2016-08-29 01:03:26 +00:00
int32_t line_number = str_to_int_s ( bar . string ) ;
2016-06-20 20:34:48 +00:00
active_view_to_line ( app , access , line_number ) ;
2016-03-15 14:12:06 +00:00
}
}
CUSTOM_COMMAND_SIG ( search ) ;
CUSTOM_COMMAND_SIG ( reverse_search ) ;
static void
2016-08-29 01:03:26 +00:00
isearch ( Application_Links * app , int32_t start_reversed ) {
uint32_t access = AccessProtected ;
2016-06-20 20:34:48 +00:00
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-05-31 01:22:55 +00:00
2016-03-24 15:00:13 +00:00
if ( ! buffer . exists ) return ;
2016-07-03 00:37:24 +00:00
Query_Bar bar = { 0 } ;
2016-09-17 00:03:09 +00:00
if ( start_query_bar ( app , & bar , 0 ) = = 0 ) return ;
2016-05-31 01:22:55 +00:00
2016-08-29 01:03:26 +00:00
int32_t reverse = start_reversed ;
int32_t pos = view . cursor . pos ;
int32_t start_pos = pos ;
int32_t first_pos = pos ;
2016-06-22 17:53:31 +00:00
Range match = make_range ( pos , pos ) ;
2016-05-31 01:22:55 +00:00
2016-03-15 14:12:06 +00:00
char bar_string_space [ 256 ] ;
bar . string = make_fixed_width_string ( bar_string_space ) ;
2016-05-31 01:22:55 +00:00
2016-06-22 17:53:31 +00:00
String isearch_str = make_lit_string ( " I-Search: " ) ;
String rsearch_str = make_lit_string ( " Reverse-I-Search: " ) ;
2016-05-31 01:22:55 +00:00
2016-07-03 00:37:24 +00:00
User_Input in = { 0 } ;
2016-06-22 17:53:31 +00:00
for ( ; ; ) {
2016-09-17 00:03:09 +00:00
view_set_highlight ( app , & view , match . start , match . end , true ) ;
2016-06-22 17:53:31 +00:00
2016-03-15 14:12:06 +00:00
// NOTE(allen): Change the bar's prompt to match the current direction.
2016-06-22 17:53:31 +00:00
if ( reverse ) bar . prompt = rsearch_str ;
else bar . prompt = isearch_str ;
2016-05-31 01:22:55 +00:00
2016-09-17 00:03:09 +00:00
in = get_user_input ( app , EventOnAnyKey , EventOnEsc | EventOnButton ) ;
2016-03-15 14:12:06 +00:00
if ( in . abort ) break ;
2016-05-31 01:22:55 +00:00
2016-03-15 14:12:06 +00:00
// NOTE(allen): If we're getting mouse events here it's a 4coder bug, because we
// only asked to intercept key events.
2016-07-10 05:49:11 +00:00
2016-03-15 14:12:06 +00:00
assert ( in . type = = UserInputKey ) ;
2016-05-31 01:22:55 +00:00
2016-08-29 01:03:26 +00:00
int32_t made_change = 0 ;
2016-03-15 14:12:06 +00:00
if ( in . key . keycode = = ' \n ' | | in . key . keycode = = ' \t ' ) {
break ;
}
else if ( in . key . character & & key_is_unmodified ( & in . key ) ) {
2016-08-28 04:31:06 +00:00
append_s_char ( & bar . string , in . key . character ) ;
2016-03-15 14:12:06 +00:00
made_change = 1 ;
}
else if ( in . key . keycode = = key_back ) {
if ( bar . string . size > 0 ) {
- - bar . string . size ;
made_change = 1 ;
}
}
2016-05-31 01:22:55 +00:00
2016-08-29 01:03:26 +00:00
int32_t step_forward = 0 ;
int32_t step_backward = 0 ;
2016-05-31 01:22:55 +00:00
2016-07-02 14:15:15 +00:00
if ( ( in . command . command = = search ) | |
2016-05-31 01:22:55 +00:00
in . key . keycode = = key_page_down | | in . key . keycode = = key_down ) step_forward = 1 ;
2016-07-02 14:15:15 +00:00
if ( ( in . command . command = = reverse_search ) | |
2016-05-31 01:22:55 +00:00
in . key . keycode = = key_page_up | | in . key . keycode = = key_up ) step_backward = 1 ;
2016-07-10 05:49:11 +00:00
start_pos = pos ;
2016-03-15 14:12:06 +00:00
if ( step_forward & & reverse ) {
start_pos = match . start + 1 ;
pos = start_pos ;
reverse = 0 ;
step_forward = 0 ;
}
if ( step_backward & & ! reverse ) {
start_pos = match . start - 1 ;
pos = start_pos ;
reverse = 1 ;
step_backward = 0 ;
}
2016-05-31 01:22:55 +00:00
2016-03-15 14:12:06 +00:00
if ( in . key . keycode ! = key_back ) {
2016-08-29 01:03:26 +00:00
int32_t new_pos ;
2016-03-15 14:12:06 +00:00
if ( reverse ) {
2016-07-18 18:36:53 +00:00
buffer_seek_string_insensitive_backward ( app , & buffer , start_pos - 1 , 0 ,
2016-05-31 01:22:55 +00:00
bar . string . str , bar . string . size , & new_pos ) ;
2016-03-15 14:12:06 +00:00
if ( new_pos > = 0 ) {
if ( step_backward ) {
pos = new_pos ;
start_pos = new_pos ;
2016-07-18 18:36:53 +00:00
buffer_seek_string_insensitive_backward ( app , & buffer , start_pos - 1 , 0 ,
2016-05-31 01:22:55 +00:00
bar . string . str , bar . string . size , & new_pos ) ;
2016-03-15 14:12:06 +00:00
if ( new_pos < 0 ) new_pos = start_pos ;
}
match . start = new_pos ;
match . end = match . start + bar . string . size ;
}
}
else {
2016-07-18 18:36:53 +00:00
buffer_seek_string_insensitive_forward ( app , & buffer , start_pos + 1 , 0 ,
2016-05-31 01:22:55 +00:00
bar . string . str , bar . string . size , & new_pos ) ;
2016-03-15 14:12:06 +00:00
if ( new_pos < buffer . size ) {
if ( step_forward ) {
pos = new_pos ;
start_pos = new_pos ;
2016-07-18 18:36:53 +00:00
buffer_seek_string_insensitive_forward ( app , & buffer , start_pos + 1 , 0 ,
2016-05-31 01:22:55 +00:00
bar . string . str , bar . string . size , & new_pos ) ;
2016-03-15 14:12:06 +00:00
if ( new_pos > = buffer . size ) new_pos = start_pos ;
}
match . start = new_pos ;
match . end = match . start + bar . string . size ;
}
}
}
else {
2016-05-12 02:15:54 +00:00
if ( match . end > match . start + bar . string . size ) {
match . end = match . start + bar . string . size ;
}
2016-03-15 14:12:06 +00:00
}
}
2016-09-17 00:03:09 +00:00
view_set_highlight ( app , & view , 0 , 0 , false ) ;
2016-07-03 00:37:24 +00:00
if ( in . abort ) {
2016-09-17 00:03:09 +00:00
view_set_cursor ( app , & view , seek_pos ( first_pos ) , true ) ;
2016-07-03 00:37:24 +00:00
return ;
}
2016-05-31 01:22:55 +00:00
2016-09-17 00:03:09 +00:00
view_set_cursor ( app , & view , seek_pos ( match . min ) , true ) ;
2016-03-15 14:12:06 +00:00
}
CUSTOM_COMMAND_SIG ( search ) {
2016-07-10 05:49:11 +00:00
isearch ( app , false ) ;
2016-03-15 14:12:06 +00:00
}
CUSTOM_COMMAND_SIG ( reverse_search ) {
2016-07-10 05:49:11 +00:00
isearch ( app , true ) ;
2016-03-15 14:12:06 +00:00
}
CUSTOM_COMMAND_SIG ( replace_in_range ) {
Query_Bar replace ;
char replace_space [ 1024 ] ;
replace . prompt = make_lit_string ( " Replace: " ) ;
replace . string = make_fixed_width_string ( replace_space ) ;
2016-06-20 20:34:48 +00:00
2016-03-15 14:12:06 +00:00
Query_Bar with ;
char with_space [ 1024 ] ;
with . prompt = make_lit_string ( " With: " ) ;
with . string = make_fixed_width_string ( with_space ) ;
2016-06-20 20:34:48 +00:00
2016-03-15 14:12:06 +00:00
if ( ! query_user_string ( app , & replace ) ) return ;
if ( replace . string . size = = 0 ) return ;
2016-06-20 20:34:48 +00:00
2016-03-15 14:12:06 +00:00
if ( ! query_user_string ( app , & with ) ) return ;
2016-06-20 20:34:48 +00:00
2016-09-14 23:39:33 +00:00
String r = replace . string , w = with . string ;
2016-06-20 20:34:48 +00:00
2016-08-29 01:03:26 +00:00
uint32_t access = AccessOpen ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-06-20 20:34:48 +00:00
2016-03-15 14:12:06 +00:00
Range range = get_range ( & view ) ;
2016-06-20 20:34:48 +00:00
2016-08-29 01:03:26 +00:00
int32_t pos , new_pos ;
2016-03-15 14:12:06 +00:00
pos = range . min ;
2016-07-10 05:49:11 +00:00
buffer_seek_string_forward ( app , & buffer , pos , 0 , r . str , r . size , & new_pos ) ;
2016-06-20 20:34:48 +00:00
2016-03-22 01:55:18 +00:00
while ( new_pos + r . size < = range . end ) {
2016-09-17 00:03:09 +00:00
buffer_replace_range ( app , & buffer , new_pos , new_pos + r . size , w . str , w . size ) ;
2016-06-23 23:11:09 +00:00
refresh_view ( app , & view ) ;
2016-03-15 14:12:06 +00:00
range = get_range ( & view ) ;
pos = new_pos + w . size ;
2016-07-10 05:49:11 +00:00
buffer_seek_string_forward ( app , & buffer , pos , 0 , r . str , r . size , & new_pos ) ;
2016-03-15 14:12:06 +00:00
}
}
CUSTOM_COMMAND_SIG ( query_replace ) {
Query_Bar replace ;
char replace_space [ 1024 ] ;
replace . prompt = make_lit_string ( " Replace: " ) ;
replace . string = make_fixed_width_string ( replace_space ) ;
2016-06-20 20:34:48 +00:00
2016-03-15 14:12:06 +00:00
Query_Bar with ;
char with_space [ 1024 ] ;
with . prompt = make_lit_string ( " With: " ) ;
with . string = make_fixed_width_string ( with_space ) ;
2016-06-20 20:34:48 +00:00
2016-03-15 14:12:06 +00:00
if ( ! query_user_string ( app , & replace ) ) return ;
if ( replace . string . size = = 0 ) return ;
2016-06-20 20:34:48 +00:00
2016-03-15 14:12:06 +00:00
if ( ! query_user_string ( app , & with ) ) return ;
2016-06-20 20:34:48 +00:00
2016-03-15 14:12:06 +00:00
String r , w ;
r = replace . string ;
w = with . string ;
2016-06-20 20:34:48 +00:00
2016-03-15 14:12:06 +00:00
Query_Bar bar ;
Buffer_Summary buffer ;
View_Summary view ;
2016-08-29 01:03:26 +00:00
int32_t pos , new_pos ;
2016-06-20 20:34:48 +00:00
2016-03-15 14:12:06 +00:00
bar . prompt = make_lit_string ( " Replace? (y)es, (n)ext, (esc) \n " ) ;
2016-09-04 17:09:13 +00:00
bar . string = null_string ;
2016-06-20 20:34:48 +00:00
2016-09-17 00:03:09 +00:00
start_query_bar ( app , & bar , 0 ) ;
2016-06-20 20:34:48 +00:00
2016-08-29 01:03:26 +00:00
uint32_t access = AccessOpen ;
2016-09-17 00:03:09 +00:00
view = get_active_view ( app , access ) ;
buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-06-20 20:34:48 +00:00
2016-03-15 14:12:06 +00:00
pos = view . cursor . pos ;
2016-07-10 05:49:11 +00:00
buffer_seek_string_forward ( app , & buffer , pos , 0 , r . str , r . size , & new_pos ) ;
2016-06-20 20:34:48 +00:00
2016-03-15 14:12:06 +00:00
User_Input in = { 0 } ;
while ( new_pos < buffer . size ) {
Range match = make_range ( new_pos , new_pos + r . size ) ;
2016-09-17 00:03:09 +00:00
view_set_highlight ( app , & view , match . min , match . max , 1 ) ;
2016-06-20 20:34:48 +00:00
2016-09-17 00:03:09 +00:00
in = get_user_input ( app , EventOnAnyKey , EventOnButton ) ;
2016-03-15 14:12:06 +00:00
if ( in . abort | | in . key . keycode = = key_esc | | ! key_is_unmodified ( & in . key ) ) break ;
2016-06-20 20:34:48 +00:00
2016-06-22 17:53:31 +00:00
if ( in . key . character = = ' y ' | |
in . key . character = = ' Y ' | |
in . key . character = = ' \n ' | |
in . key . character = = ' \t ' ) {
2016-09-17 00:03:09 +00:00
buffer_replace_range ( app , & buffer , match . min , match . max , w . str , w . size ) ;
2016-03-15 14:12:06 +00:00
pos = match . start + w . size ;
}
else {
pos = match . max ;
}
2016-06-20 20:34:48 +00:00
2016-07-10 05:49:11 +00:00
buffer_seek_string_forward ( app , & buffer , pos , 0 , r . str , r . size , & new_pos ) ;
2016-03-15 14:12:06 +00:00
}
2016-06-20 20:34:48 +00:00
2016-09-17 00:03:09 +00:00
view_set_highlight ( app , & view , 0 , 0 , 0 ) ;
2016-03-15 14:12:06 +00:00
if ( in . abort ) return ;
2016-06-20 20:34:48 +00:00
2016-09-17 00:03:09 +00:00
view_set_cursor ( app , & view , seek_pos ( pos ) , 1 ) ;
2016-03-15 14:12:06 +00:00
}
2016-07-10 05:49:11 +00:00
//
// Fast Buffer Management
//
2016-12-26 22:49:01 +00:00
static char out_buffer_space [ 1024 ] ;
static char command_space [ 1024 ] ;
static char hot_directory_space [ 1024 ] ;
2016-05-10 17:36:53 +00:00
2016-03-15 14:12:06 +00:00
CUSTOM_COMMAND_SIG ( execute_any_cli ) {
2016-07-10 05:49:11 +00:00
Query_Bar bar_out = { 0 } ;
Query_Bar bar_cmd = { 0 } ;
2016-06-13 16:56:33 +00:00
2016-03-15 14:12:06 +00:00
bar_out . prompt = make_lit_string ( " Output Buffer: " ) ;
2016-05-10 17:36:53 +00:00
bar_out . string = make_fixed_width_string ( out_buffer_space ) ;
2016-03-15 14:12:06 +00:00
if ( ! query_user_string ( app , & bar_out ) ) return ;
2016-06-13 16:56:33 +00:00
2016-03-15 14:12:06 +00:00
bar_cmd . prompt = make_lit_string ( " Command: " ) ;
2016-05-10 17:36:53 +00:00
bar_cmd . string = make_fixed_width_string ( command_space ) ;
2016-03-15 14:12:06 +00:00
if ( ! query_user_string ( app , & bar_cmd ) ) return ;
2016-06-13 16:56:33 +00:00
2016-07-10 05:49:11 +00:00
String hot_directory = make_fixed_width_string ( hot_directory_space ) ;
2016-09-17 00:03:09 +00:00
hot_directory . size = directory_get_hot ( app , hot_directory . str , hot_directory . memory_size ) ;
2016-05-10 17:36:53 +00:00
2016-08-29 01:03:26 +00:00
uint32_t access = AccessAll ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
2016-06-13 16:56:33 +00:00
2016-12-26 22:49:01 +00:00
exec_system_command ( app , & view , buffer_identifier ( bar_out . string . str , bar_out . string . size ) , hot_directory . str , hot_directory . size , bar_cmd . string . str , bar_cmd . string . size , CLI_OverlapWithConflict | CLI_CursorAtEnd ) ;
2016-05-10 17:36:53 +00:00
}
CUSTOM_COMMAND_SIG ( execute_previous_cli ) {
2016-07-10 05:49:11 +00:00
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 ) ;
2016-05-10 17:36:53 +00:00
if ( out_buffer . size > 0 & & cmd . size > 0 & & hot_directory . size > 0 ) {
2016-08-29 01:03:26 +00:00
uint32_t access = AccessAll ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
2016-06-13 16:56:33 +00:00
2016-12-26 22:49:01 +00:00
exec_system_command ( app , & view , buffer_identifier ( out_buffer . str , out_buffer . size ) , hot_directory . str , hot_directory . size , cmd . str , cmd . size , CLI_OverlapWithConflict | CLI_CursorAtEnd ) ;
2016-05-10 17:36:53 +00:00
}
2016-03-15 14:12:06 +00:00
}
2016-07-04 20:40:57 +00:00
//
// Common Settings Commands
//
2016-09-17 00:03:09 +00:00
//toggle_fullscreen can be used as a command
2016-09-01 03:06:46 +00:00
2016-07-04 20:40:57 +00:00
CUSTOM_COMMAND_SIG ( toggle_line_wrap ) {
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , AccessProtected ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , AccessProtected ) ;
2016-07-04 20:40:57 +00:00
bool32 unwrapped = view . unwrapped_lines ;
2016-09-17 00:03:09 +00:00
buffer_set_setting ( app , & buffer , BufferSetting_WrapLine , unwrapped ) ;
2016-07-04 20:40:57 +00:00
}
2016-09-20 19:48:02 +00:00
CUSTOM_COMMAND_SIG ( increase_line_wrap ) {
View_Summary view = get_active_view ( app , AccessProtected ) ;
2016-09-22 00:01:12 +00:00
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , AccessProtected ) ;
2016-11-02 03:27:51 +00:00
int32_t wrap = 0 ;
2016-12-08 17:16:50 +00:00
buffer_get_setting ( app , & buffer , BufferSetting_WrapPosition , & wrap ) ;
2016-09-22 00:01:12 +00:00
buffer_set_setting ( app , & buffer , BufferSetting_WrapPosition , wrap + 10 ) ;
2016-09-20 19:48:02 +00:00
}
CUSTOM_COMMAND_SIG ( decrease_line_wrap ) {
View_Summary view = get_active_view ( app , AccessProtected ) ;
2016-09-22 00:01:12 +00:00
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , AccessProtected ) ;
2016-11-02 03:27:51 +00:00
int32_t wrap = 0 ;
buffer_get_setting ( app , & buffer , BufferSetting_WrapPosition , & wrap ) ;
2016-09-22 00:01:12 +00:00
buffer_set_setting ( app , & buffer , BufferSetting_WrapPosition , wrap - 10 ) ;
2016-09-20 19:48:02 +00:00
}
2016-10-05 06:08:23 +00:00
CUSTOM_COMMAND_SIG ( toggle_virtual_whitespace ) {
View_Summary view = get_active_view ( app , AccessProtected ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , AccessProtected ) ;
2016-11-02 03:27:51 +00:00
int32_t vwhite = 0 ;
buffer_get_setting ( app , & buffer , BufferSetting_VirtualWhitespace , & vwhite ) ;
2016-10-05 06:08:23 +00:00
buffer_set_setting ( app , & buffer , BufferSetting_VirtualWhitespace , ! vwhite ) ;
}
2016-07-04 20:40:57 +00:00
CUSTOM_COMMAND_SIG ( toggle_show_whitespace ) {
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , AccessProtected ) ;
view_set_setting ( app , & view , ViewSetting_ShowWhitespace , ! view . show_whitespace ) ;
2016-07-04 20:40:57 +00:00
}
CUSTOM_COMMAND_SIG ( eol_dosify ) {
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , AccessOpen ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , AccessOpen ) ;
2016-10-05 06:08:23 +00:00
buffer_set_setting ( app , & buffer , BufferSetting_Eol , 1 ) ;
2016-07-04 20:40:57 +00:00
}
CUSTOM_COMMAND_SIG ( eol_nixify ) {
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , AccessOpen ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , AccessOpen ) ;
2016-10-05 06:08:23 +00:00
buffer_set_setting ( app , & buffer , BufferSetting_Eol , 0 ) ;
2016-07-04 20:40:57 +00:00
}
2016-09-01 20:29:07 +00:00
CUSTOM_COMMAND_SIG ( exit_4coder ) {
2016-09-17 00:03:09 +00:00
send_exit_signal ( app ) ;
2016-09-01 20:29:07 +00:00
}
2016-09-01 19:40:25 +00:00
2016-07-10 05:49:11 +00:00
//
// "Full Search" Based Commands
//
# include "4coder_table.cpp"
# include "4coder_search.cpp"
2016-09-01 00:26:52 +00:00
# include "4coder_jump_parsing.cpp"
2016-07-10 05:49:11 +00:00
2016-07-18 18:36:53 +00:00
static void
2016-09-23 17:50:55 +00:00
get_search_all_string ( Application_Links * app , Query_Bar * bar ) {
2016-07-12 18:20:06 +00:00
char string_space [ 1024 ] ;
2016-09-23 17:50:55 +00:00
bar - > prompt = make_lit_string ( " List Locations For: " ) ;
bar - > string = make_fixed_width_string ( string_space ) ;
2016-07-12 18:20:06 +00:00
2016-09-23 17:50:55 +00:00
if ( ! query_user_string ( app , bar ) ) {
bar - > string . size = 0 ;
}
}
static void
2016-12-26 22:49:01 +00:00
generic_search_all_buffers ( Application_Links * app , General_Memory * general , Partition * part , String string , uint32_t match_flags ) {
2016-07-12 18:20:06 +00:00
Search_Set set = { 0 } ;
Search_Iter iter = { 0 } ;
2016-09-23 17:50:55 +00:00
search_iter_init ( general , & iter , string . size ) ;
copy_ss ( & iter . word , string ) ;
2016-07-12 18:20:06 +00:00
2016-09-17 00:03:09 +00:00
int32_t buffer_count = get_buffer_count ( app ) ;
2016-07-18 18:36:53 +00:00
search_set_init ( general , & set , buffer_count ) ;
2016-07-12 18:20:06 +00:00
Search_Range * ranges = set . ranges ;
2016-09-01 00:26:52 +00:00
String search_name = make_lit_string ( " *search* " ) ;
2016-09-17 00:03:09 +00:00
Buffer_Summary search_buffer = get_buffer_by_name ( app , search_name . str , search_name . size ,
2016-09-23 17:50:55 +00:00
AccessAll ) ;
2016-07-20 15:19:54 +00:00
if ( ! search_buffer . exists ) {
2016-09-17 00:03:09 +00:00
search_buffer = create_buffer ( app , search_name . str , search_name . size , BufferCreate_AlwaysNew ) ;
buffer_set_setting ( app , & search_buffer , BufferSetting_Unimportant , true ) ;
buffer_set_setting ( app , & search_buffer , BufferSetting_ReadOnly , true ) ;
buffer_set_setting ( app , & search_buffer , BufferSetting_WrapLine , false ) ;
2016-07-20 15:19:54 +00:00
}
else {
2016-09-17 00:03:09 +00:00
buffer_replace_range ( app , & search_buffer , 0 , search_buffer . size , 0 , 0 ) ;
2016-07-20 15:19:54 +00:00
}
2016-07-12 18:20:06 +00:00
{
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , AccessProtected ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , AccessProtected ) ;
2016-07-12 18:20:06 +00:00
2016-08-29 01:03:26 +00:00
int32_t j = 0 ;
2016-07-12 18:20:06 +00:00
if ( buffer . exists ) {
2016-07-20 15:19:54 +00:00
if ( buffer . buffer_id ! = search_buffer . buffer_id ) {
ranges [ 0 ] . type = SearchRange_FrontToBack ;
ranges [ 0 ] . flags = match_flags ;
ranges [ 0 ] . buffer = buffer . buffer_id ;
ranges [ 0 ] . start = 0 ;
ranges [ 0 ] . size = buffer . size ;
j = 1 ;
}
2016-07-12 18:20:06 +00:00
}
2016-09-17 00:03:09 +00:00
for ( Buffer_Summary buffer_it = get_buffer_first ( app , AccessAll ) ;
2016-07-12 18:20:06 +00:00
buffer_it . exists ;
2016-09-17 00:03:09 +00:00
get_buffer_next ( app , & buffer_it , AccessAll ) ) {
2016-07-12 18:20:06 +00:00
if ( buffer . buffer_id ! = buffer_it . buffer_id ) {
2016-07-20 15:19:54 +00:00
if ( search_buffer . buffer_id ! = buffer_it . buffer_id ) {
ranges [ j ] . type = SearchRange_FrontToBack ;
ranges [ j ] . flags = match_flags ;
ranges [ j ] . buffer = buffer_it . buffer_id ;
ranges [ j ] . start = 0 ;
ranges [ j ] . size = buffer_it . size ;
+ + j ;
}
2016-07-12 18:20:06 +00:00
}
}
set . count = j ;
}
2016-07-18 18:36:53 +00:00
Temp_Memory temp = begin_temp_memory ( part ) ;
Partition line_part = partition_sub_part ( part , ( 4 < < 10 ) ) ;
char * str = ( char * ) partition_current ( part ) ;
2016-08-29 01:03:26 +00:00
int32_t part_size = 0 ;
int32_t size = 0 ;
2016-07-12 18:20:06 +00:00
for ( ; ; ) {
Search_Match match = search_next_match ( app , & set , & iter ) ;
if ( match . found_match ) {
Partial_Cursor word_pos = { 0 } ;
2016-09-17 00:03:09 +00:00
if ( buffer_compute_cursor ( app , & match . buffer , seek_pos ( match . start ) , & word_pos ) ) {
2016-08-29 01:03:26 +00:00
int32_t file_len = match . buffer . file_name_len ;
int32_t line_num_len = int_to_str_size ( word_pos . line ) ;
int32_t column_num_len = int_to_str_size ( word_pos . character ) ;
2016-07-12 18:20:06 +00:00
Temp_Memory line_temp = begin_temp_memory ( & line_part ) ;
String line_str = { 0 } ;
read_line ( app , & line_part , & match . buffer , word_pos . line , & line_str ) ;
line_str = skip_chop_whitespace ( line_str ) ;
2016-08-29 01:03:26 +00:00
int32_t str_len = file_len + 1 + line_num_len + 1 + column_num_len + 1 + 1 + line_str . size + 1 ;
2016-07-12 18:20:06 +00:00
2016-07-18 18:36:53 +00:00
char * spare = push_array ( part , char , str_len ) ;
if ( spare = = 0 ) {
2016-09-17 00:03:09 +00:00
buffer_replace_range ( app , & search_buffer ,
2016-09-23 17:50:55 +00:00
size , size , str , part_size ) ;
2016-07-18 18:36:53 +00:00
size + = part_size ;
end_temp_memory ( temp ) ;
temp = begin_temp_memory ( part ) ;
part_size = 0 ;
spare = push_array ( part , char , str_len ) ;
}
part_size + = str_len ;
2016-07-12 18:20:06 +00:00
2016-08-28 04:31:06 +00:00
String out_line = make_string_cap ( spare , 0 , str_len ) ;
append_ss ( & out_line , make_string ( match . buffer . file_name , file_len ) ) ;
append_s_char ( & out_line , ' : ' ) ;
2016-07-12 18:20:06 +00:00
append_int_to_str ( & out_line , word_pos . line ) ;
2016-08-28 04:31:06 +00:00
append_s_char ( & out_line , ' : ' ) ;
2016-07-12 18:20:06 +00:00
append_int_to_str ( & out_line , word_pos . character ) ;
2016-08-28 04:31:06 +00:00
append_s_char ( & out_line , ' : ' ) ;
append_s_char ( & out_line , ' ' ) ;
append_ss ( & out_line , line_str ) ;
append_s_char ( & out_line , ' \n ' ) ;
2016-07-12 18:20:06 +00:00
end_temp_memory ( line_temp ) ;
}
}
else {
break ;
}
}
2016-09-17 00:03:09 +00:00
buffer_replace_range ( app , & search_buffer , size , size , str , part_size ) ;
2016-07-12 18:20:06 +00:00
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , AccessAll ) ;
view_set_buffer ( app , & view , search_buffer . buffer_id , 0 ) ;
2016-07-12 18:20:06 +00:00
2016-09-01 00:26:52 +00:00
lock_jump_buffer ( search_name . str , search_name . size ) ;
2016-07-12 18:20:06 +00:00
end_temp_memory ( temp ) ;
}
2016-07-18 18:36:53 +00:00
CUSTOM_COMMAND_SIG ( list_all_locations ) {
2016-09-23 17:50:55 +00:00
Query_Bar bar ;
get_search_all_string ( app , & bar ) ;
if ( bar . string . size = = 0 ) return ;
2016-12-26 22:49:01 +00:00
generic_search_all_buffers ( app , & global_general , & global_part , bar . string , SearchFlag_MatchWholeWord ) ;
2016-07-18 18:36:53 +00:00
}
CUSTOM_COMMAND_SIG ( list_all_substring_locations ) {
2016-09-23 17:50:55 +00:00
Query_Bar bar ;
get_search_all_string ( app , & bar ) ;
if ( bar . string . size = = 0 ) return ;
2016-12-26 22:49:01 +00:00
generic_search_all_buffers ( app , & global_general , & global_part , bar . string , SearchFlag_MatchSubstring ) ;
2016-07-18 18:36:53 +00:00
}
CUSTOM_COMMAND_SIG ( list_all_locations_case_insensitive ) {
2016-09-23 17:50:55 +00:00
Query_Bar bar ;
get_search_all_string ( app , & bar ) ;
if ( bar . string . size = = 0 ) return ;
2016-12-26 22:49:01 +00:00
generic_search_all_buffers ( app , & global_general , & global_part , bar . string , SearchFlag_CaseInsensitive | SearchFlag_MatchWholeWord ) ;
2016-07-18 18:36:53 +00:00
}
CUSTOM_COMMAND_SIG ( list_all_substring_locations_case_insensitive ) {
2016-09-23 17:50:55 +00:00
Query_Bar bar ;
get_search_all_string ( app , & bar ) ;
if ( bar . string . size = = 0 ) return ;
2016-12-26 22:49:01 +00:00
generic_search_all_buffers ( app , & global_general , & global_part , bar . string , SearchFlag_CaseInsensitive | SearchFlag_MatchSubstring ) ;
2016-09-23 17:50:55 +00:00
}
CUSTOM_COMMAND_SIG ( list_all_locations_of_identifier ) {
View_Summary view = get_active_view ( app , AccessProtected ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , AccessProtected ) ;
Cpp_Get_Token_Result get_result = { 0 } ;
bool32 success = buffer_get_token_index ( app , & buffer , view . cursor . pos , & get_result ) ;
if ( success & & ! get_result . in_whitespace ) {
char space [ 128 ] ;
int32_t size = get_result . token_end - get_result . token_start ;
if ( size > 0 & & size < = sizeof ( space ) ) {
success = buffer_read_range ( app , & buffer , get_result . token_start ,
get_result . token_end , space ) ;
if ( success ) {
String str = make_string ( space , size ) ;
exec_command ( app , change_active_panel ) ;
generic_search_all_buffers ( app , & global_general , & global_part ,
str , SearchFlag_MatchWholeWord ) ;
}
}
}
2016-07-18 18:36:53 +00:00
}
2016-07-10 05:49:11 +00:00
struct Word_Complete_State {
Search_Set set ;
Search_Iter iter ;
Table hits ;
String_Space str ;
2016-08-29 01:03:26 +00:00
int32_t word_start ;
int32_t word_end ;
int32_t initialized ;
2016-07-10 05:49:11 +00:00
} ;
static Word_Complete_State complete_state = { 0 } ;
CUSTOM_COMMAND_SIG ( word_complete ) {
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , AccessOpen ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , AccessOpen ) ;
2016-07-10 05:49:11 +00:00
// 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 ) {
2016-08-29 01:03:26 +00:00
int32_t do_init = false ;
2016-07-10 05:49:11 +00:00
if ( view_paste_index [ view . view_id ] . rewrite ! = RewriteWordComplete ) {
do_init = true ;
}
2016-07-11 16:15:37 +00:00
view_paste_index [ view . view_id ] . next_rewrite = RewriteWordComplete ;
2016-07-10 05:49:11 +00:00
if ( ! complete_state . initialized ) {
do_init = true ;
}
2016-08-29 01:03:26 +00:00
int32_t word_end = 0 ;
int32_t word_start = 0 ;
int32_t cursor_pos = 0 ;
int32_t size = 0 ;
2016-07-10 05:49:11 +00:00
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 ) ) ) {
2016-08-29 01:03:26 +00:00
int32_t still_looping = true ;
2016-07-10 05:49:11 +00:00
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 ;
2016-07-12 18:20:06 +00:00
search_iter_init ( & global_general , & complete_state . iter , size ) ;
2016-09-17 00:03:09 +00:00
buffer_read_range ( app , & buffer , word_start , word_end ,
2016-12-08 17:16:50 +00:00
complete_state . iter . word . str ) ;
2016-07-10 05:49:11 +00:00
complete_state . iter . word . size = size ;
2016-07-18 18:36:53 +00:00
// NOTE(allen): Initialize the set of ranges to be searched.
2016-09-17 00:03:09 +00:00
int32_t buffer_count = get_buffer_count ( app ) ;
2016-07-12 18:20:06 +00:00
search_set_init ( & global_general , & complete_state . set , buffer_count ) ;
2016-07-10 05:49:11 +00:00
Search_Range * ranges = complete_state . set . ranges ;
ranges [ 0 ] . type = SearchRange_Wave ;
2016-07-18 18:36:53 +00:00
ranges [ 0 ] . flags = SearchFlag_MatchWordPrefix ;
2016-07-10 05:49:11 +00:00
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 ;
2016-08-29 01:03:26 +00:00
int32_t j = 1 ;
2016-09-17 00:03:09 +00:00
for ( Buffer_Summary buffer_it = get_buffer_first ( app , AccessAll ) ;
2016-07-10 05:49:11 +00:00
buffer_it . exists ;
2016-09-17 00:03:09 +00:00
get_buffer_next ( app , & buffer_it , AccessAll ) ) {
2016-07-10 05:49:11 +00:00
if ( buffer . buffer_id ! = buffer_it . buffer_id ) {
ranges [ j ] . type = SearchRange_FrontToBack ;
2016-07-18 18:36:53 +00:00
ranges [ j ] . flags = SearchFlag_MatchWordPrefix ;
2016-07-10 05:49:11 +00:00
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.
2016-07-12 18:20:06 +00:00
search_hits_init ( & global_general , & complete_state . hits , & complete_state . str ,
2016-07-10 05:49:11 +00:00
100 , ( 4 < < 10 ) ) ;
2016-07-12 18:20:06 +00:00
search_hit_add ( & global_general , & complete_state . hits , & complete_state . str ,
2016-07-10 05:49:11 +00:00
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 ( ; ; ) {
2016-08-29 01:03:26 +00:00
int32_t match_size = 0 ;
2016-07-10 05:49:11 +00:00
Search_Match match =
search_next_match ( app , & complete_state . set ,
& complete_state . iter ) ;
if ( match . found_match ) {
2016-08-22 19:31:19 +00:00
match_size = match . end - match . start ;
2016-07-12 18:20:06 +00:00
Temp_Memory temp = begin_temp_memory ( & global_part ) ;
char * spare = push_array ( & global_part , char , match_size ) ;
2016-07-10 05:49:11 +00:00
2016-09-17 00:03:09 +00:00
buffer_read_range ( app , & match . buffer ,
2016-12-08 17:16:50 +00:00
match . start , match . end , spare ) ;
2016-07-10 05:49:11 +00:00
2016-07-12 18:20:06 +00:00
if ( search_hit_add ( & global_general , & complete_state . hits , & complete_state . str ,
2016-07-10 05:49:11 +00:00
spare , match_size ) ) {
2016-09-17 00:03:09 +00:00
buffer_replace_range ( app , & buffer , word_start , word_end ,
2016-12-08 17:16:50 +00:00
spare , match_size ) ;
2016-09-17 00:03:09 +00:00
view_set_cursor ( app , & view ,
2016-12-08 17:16:50 +00:00
seek_pos ( word_start + match_size ) ,
true ) ;
2016-07-10 05:49:11 +00:00
complete_state . word_end = word_start + match_size ;
complete_state . set . ranges [ 0 ] . mid_size = match_size ;
2016-07-11 16:15:37 +00:00
end_temp_memory ( temp ) ;
2016-07-10 05:49:11 +00:00
break ;
}
2016-07-11 16:15:37 +00:00
end_temp_memory ( temp ) ;
2016-07-10 05:49:11 +00:00
}
else {
complete_state . iter . pos = 0 ;
complete_state . iter . i = 0 ;
2016-07-12 18:20:06 +00:00
search_hits_init ( & global_general , & complete_state . hits , & complete_state . str ,
2016-07-10 05:49:11 +00:00
100 , ( 4 < < 10 ) ) ;
2016-07-12 18:20:06 +00:00
search_hit_add ( & global_general , & complete_state . hits , & complete_state . str ,
2016-07-10 05:49:11 +00:00
complete_state . iter . word . str ,
complete_state . iter . word . size ) ;
match_size = complete_state . iter . word . size ;
char * str = complete_state . iter . word . str ;
2016-09-17 00:03:09 +00:00
buffer_replace_range ( app , & buffer , word_start , word_end ,
2016-12-08 17:16:50 +00:00
str , match_size ) ;
2016-09-17 00:03:09 +00:00
view_set_cursor ( app , & view ,
2016-12-08 17:16:50 +00:00
seek_pos ( word_start + match_size ) ,
true ) ;
2016-07-10 05:49:11 +00:00
complete_state . word_end = word_start + match_size ;
complete_state . set . ranges [ 0 ] . mid_size = match_size ;
break ;
}
}
}
}
}
2016-09-01 19:40:25 +00:00
//
// Default Building Stuff
//
// 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, if it cannot get that information it get's the
// 4coder hot directory.
2016-07-10 05:49:11 +00:00
//
2016-09-01 19:40:25 +00:00
// There is no requirement that a custom build system in 4coder actually use the
// directory given by this function.
enum Get_Build_Directory_Result {
BuildDir_None ,
BuildDir_AtFile ,
BuildDir_AtHot
} ;
static int32_t
get_build_directory ( Application_Links * app , Buffer_Summary * buffer , String * dir_out ) {
int32_t result = BuildDir_None ;
if ( buffer & & buffer - > file_name ) {
if ( ! match_cc ( buffer - > file_name , buffer - > buffer_name ) ) {
String dir = make_string_cap ( buffer - > file_name ,
buffer - > file_name_len ,
buffer - > file_name_len + 1 ) ;
remove_last_folder ( & dir ) ;
append_ss ( dir_out , dir ) ;
result = BuildDir_AtFile ;
}
}
if ( ! result ) {
2016-09-17 00:03:09 +00:00
int32_t len = directory_get_hot ( app , dir_out - > str ,
2016-12-08 17:16:50 +00:00
dir_out - > memory_size - dir_out - > size ) ;
2016-09-01 19:40:25 +00:00
if ( len + dir_out - > size < dir_out - > memory_size ) {
dir_out - > size + = len ;
result = BuildDir_AtHot ;
}
}
return ( result ) ;
}
// TODO(allen): Better names for the "standard build search" family.
static int32_t
2016-11-12 21:33:54 +00:00
standard_build_search ( Application_Links * app , View_Summary * view , Buffer_Summary * active_buffer , String * dir , String * command , int32_t perform_backup , int32_t use_path_in_command , String filename , String commandname ) {
2016-09-01 19:40:25 +00:00
int32_t result = false ;
for ( ; ; ) {
int32_t old_size = dir - > size ;
append_ss ( dir , filename ) ;
2016-09-17 00:03:09 +00:00
if ( file_exists ( app , dir - > str , dir - > size ) ) {
2016-09-01 19:40:25 +00:00
dir - > size = old_size ;
if ( use_path_in_command ) {
append_s_char ( command , ' " ' ) ;
append_ss ( command , * dir ) ;
append_ss ( command , commandname ) ;
append_s_char ( command , ' " ' ) ;
}
else {
append_ss ( command , commandname ) ;
}
char space [ 512 ] ;
String message = make_fixed_width_string ( space ) ;
append_ss ( & message , make_lit_string ( " Building with: " ) ) ;
append_ss ( & message , * command ) ;
append_s_char ( & message , ' \n ' ) ;
2016-09-17 00:03:09 +00:00
print_message ( app , message . str , message . size ) ;
2016-09-01 19:40:25 +00:00
2016-12-26 22:49:01 +00:00
exec_system_command ( app , view , buffer_identifier ( literal ( " *compilation* " ) ) , dir - > str , dir - > size , command - > str , command - > size , CLI_OverlapWithConflict ) ;
2016-09-01 19:40:25 +00:00
result = true ;
break ;
}
dir - > size = old_size ;
2016-09-17 00:03:09 +00:00
if ( directory_cd ( app , dir - > str , & dir - > size , dir - > memory_size , literal ( " .. " ) ) = = 0 ) {
2016-09-01 19:40:25 +00:00
if ( perform_backup ) {
2016-09-17 00:03:09 +00:00
dir - > size = directory_get_hot ( app , dir - > str , dir - > memory_size ) ;
2016-09-01 19:40:25 +00:00
char backup_space [ 256 ] ;
String backup_command = make_fixed_width_string ( backup_space ) ;
append_ss ( & backup_command , make_lit_string ( " echo could not find " ) ) ;
append_ss ( & backup_command , filename ) ;
2016-12-26 22:49:01 +00:00
exec_system_command ( app , view , buffer_identifier ( literal ( " *compilation* " ) ) , dir - > str , dir - > size , backup_command . str , backup_command . size , CLI_OverlapWithConflict ) ;
2016-09-01 19:40:25 +00:00
}
break ;
}
}
return ( result ) ;
}
# if defined(_WIN32)
// NOTE(allen): Build search rule for windows.
static int32_t
execute_standard_build_search ( Application_Links * app , View_Summary * view ,
Buffer_Summary * active_buffer ,
String * dir , String * command , int32_t perform_backup ) {
2016-12-26 22:49:01 +00:00
int32_t result = standard_build_search ( app , view , active_buffer , dir , command , perform_backup , true , make_lit_string ( " build.bat " ) , make_lit_string ( " build " ) ) ;
2016-09-01 19:40:25 +00:00
return ( result ) ;
}
# elif defined(__linux__)
// NOTE(allen): Build search rule for linux.
static int32_t
2016-11-23 03:37:28 +00:00
execute_standard_build_search ( Application_Links * app , View_Summary * view , Buffer_Summary * active_buffer , String * dir , String * command , bool32 perform_backup ) {
2016-09-01 19:40:25 +00:00
char dir_space [ 512 ] ;
String dir_copy = make_fixed_width_string ( dir_space ) ;
copy ( & dir_copy , * dir ) ;
2016-11-23 03:37:28 +00:00
int32_t result = standard_build_search ( app , view , active_buffer , dir , command , 0 , 1 , make_lit_string ( " build.sh " ) , make_lit_string ( " build.sh " ) ) ;
2016-09-01 19:40:25 +00:00
if ( ! result ) {
2016-11-23 03:37:28 +00:00
result = standard_build_search ( app , view , active_buffer , & dir_copy , command , perform_backup , 0 , make_lit_string ( " Makefile " ) , make_lit_string ( " make " ) ) ;
2016-09-01 19:40:25 +00:00
}
return ( result ) ;
}
# else
# error No build search rule for this platform.
# endif
// NOTE(allen): This searches first using the active file's directory,
// then if no build script is found, it searches from 4coders hot directory.
static void
2016-12-26 22:49:01 +00:00
execute_standard_build ( Application_Links * app , View_Summary * view , Buffer_Summary * active_buffer ) {
2016-09-01 19:40:25 +00:00
char dir_space [ 512 ] ;
String dir = make_fixed_width_string ( dir_space ) ;
char command_str_space [ 512 ] ;
String command = make_fixed_width_string ( command_str_space ) ;
int32_t build_dir_type = get_build_directory ( app , active_buffer , & dir ) ;
if ( build_dir_type = = BuildDir_AtFile ) {
2016-12-26 22:49:01 +00:00
if ( ! execute_standard_build_search ( app , view , active_buffer , & dir , & command , false ) ) {
2016-09-01 19:40:25 +00:00
dir . size = 0 ;
command . size = 0 ;
build_dir_type = get_build_directory ( app , 0 , & dir ) ;
}
}
if ( build_dir_type = = BuildDir_AtHot ) {
2016-12-26 22:49:01 +00:00
execute_standard_build_search ( app , view , active_buffer , & dir , & command , true ) ;
2016-09-01 19:40:25 +00:00
}
}
CUSTOM_COMMAND_SIG ( build_search ) {
uint32_t access = AccessAll ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-09-01 19:40:25 +00:00
execute_standard_build ( app , & view , & buffer ) ;
prev_location = null_location ;
lock_jump_buffer ( literal ( " *compilation* " ) ) ;
}
2016-09-17 00:03:09 +00:00
# define GET_COMP_BUFFER(app) get_buffer_by_name(app, literal("*compilation*"), AccessAll)
2016-09-01 19:40:25 +00:00
static View_Summary
get_or_open_build_panel ( Application_Links * app ) {
View_Summary view = { 0 } ;
Buffer_Summary buffer = GET_COMP_BUFFER ( app ) ;
if ( buffer . exists ) {
view = get_first_view_with_buffer ( app , buffer . buffer_id ) ;
}
if ( ! view . exists ) {
view = open_special_note_view ( app ) ;
}
return ( view ) ;
}
static void
set_fancy_compilation_buffer_font ( Application_Links * app ) {
2016-09-17 00:03:09 +00:00
Buffer_Summary comp_buffer = get_buffer_by_name ( app , literal ( " *compilation* " ) , AccessAll ) ;
buffer_set_font ( app , & comp_buffer , literal ( " Inconsolata " ) ) ;
2016-10-05 06:08:23 +00:00
}
CUSTOM_COMMAND_SIG ( build_in_build_panel ) {
uint32_t access = AccessAll ;
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , access ) ;
Buffer_Summary buffer = get_buffer ( app , view . buffer_id , access ) ;
2016-10-05 06:08:23 +00:00
2016-09-01 19:40:25 +00:00
View_Summary build_view = get_or_open_build_panel ( app ) ;
2016-10-05 06:08:23 +00:00
2016-09-01 19:40:25 +00:00
execute_standard_build ( app , & build_view , & buffer ) ;
set_fancy_compilation_buffer_font ( app ) ;
prev_location = null_location ;
lock_jump_buffer ( literal ( " *compilation* " ) ) ;
}
CUSTOM_COMMAND_SIG ( close_build_panel ) {
close_special_note_view ( app ) ;
}
CUSTOM_COMMAND_SIG ( change_to_build_panel ) {
View_Summary view = open_special_note_view ( app , false ) ;
if ( ! view . exists ) {
Buffer_Summary buffer = GET_COMP_BUFFER ( app ) ;
if ( buffer . exists ) {
view = open_special_note_view ( app ) ;
2016-09-17 00:03:09 +00:00
view_set_buffer ( app , & view , buffer . buffer_id , 0 ) ;
2016-09-01 19:40:25 +00:00
}
}
if ( view . exists ) {
2016-09-17 00:03:09 +00:00
set_active_view ( app , & view ) ;
2016-09-01 19:40:25 +00:00
}
}
2016-03-15 14:12:06 +00:00
// NOTE(allen|a4): scroll rule information
//
// The parameters:
// target_x, target_y
// This is where the view would like to be for the purpose of
// following the cursor, doing mouse wheel work, etc.
//
// scroll_x, scroll_y
// These are pointers to where the scrolling actually is. If you bind
// the scroll rule it is you have to update these in some way to move
// the actual location of the scrolling.
//
// view_id
// This corresponds to which view is computing it's new scrolling position.
// This id DOES correspond to the views that View_Summary contains.
// This will always be between 1 and 16 (0 is a null id).
// See below for an example of having state that carries across scroll udpates.
//
// is_new_target
// If the target of the view is different from the last target in either x or y
// this is true, otherwise it is false.
//
// The return:
// Should be true if and only if scroll_x or scroll_y are changed.
//
// Don't try to use the app pointer in a scroll rule, you're asking for trouble.
//
// If you don't bind scroll_rule, nothing bad will happen, yo will get default
// 4coder scrolling behavior.
//
struct Scroll_Velocity {
float x , y ;
} ;
Scroll_Velocity scroll_velocity_ [ 16 ] = { 0 } ;
Scroll_Velocity * scroll_velocity = scroll_velocity_ - 1 ;
2016-08-29 01:03:26 +00:00
static int32_t
2016-03-15 14:12:06 +00:00
smooth_camera_step ( float target , float * current , float * vel , float S , float T ) {
2016-08-29 01:03:26 +00:00
int32_t result = 0 ;
2016-03-15 14:12:06 +00:00
float curr = * current ;
float v = * vel ;
if ( curr ! = target ) {
if ( curr > target - .1f & & curr < target + .1f ) {
curr = target ;
v = 1.f ;
}
else {
float L = curr + T * ( target - curr ) ;
2016-08-29 01:03:26 +00:00
int32_t sign = ( target > curr ) - ( target < curr ) ;
2016-03-15 14:12:06 +00:00
float V = curr + sign * v ;
2016-08-29 01:03:26 +00:00
2016-03-15 14:12:06 +00:00
if ( sign > 0 ) curr = ( L < V ) ? ( L ) : ( V ) ;
else curr = ( L > V ) ? ( L ) : ( V ) ;
2016-08-29 01:03:26 +00:00
2016-03-15 14:12:06 +00:00
if ( curr = = V ) {
v * = S ;
}
}
2016-08-29 01:03:26 +00:00
2016-03-15 14:12:06 +00:00
* current = curr ;
* vel = v ;
result = 1 ;
}
2016-08-29 01:03:26 +00:00
return ( result ) ;
2016-03-15 14:12:06 +00:00
}
SCROLL_RULE_SIG ( smooth_scroll_rule ) {
Scroll_Velocity * velocity = scroll_velocity + view_id ;
2016-08-29 01:03:26 +00:00
int32_t result = 0 ;
2016-03-15 14:12:06 +00:00
if ( velocity - > x = = 0.f ) {
velocity - > x = 1.f ;
velocity - > y = 1.f ;
}
2016-12-08 17:16:50 +00:00
2016-03-31 17:13:40 +00:00
if ( smooth_camera_step ( target_y , scroll_y , & velocity - > y , 80.f , 1.f / 2.f ) ) {
2016-03-15 14:12:06 +00:00
result = 1 ;
}
2016-03-31 17:13:40 +00:00
if ( smooth_camera_step ( target_x , scroll_x , & velocity - > x , 80.f , 1.f / 2.f ) ) {
2016-03-15 14:12:06 +00:00
result = 1 ;
}
2016-12-08 17:16:50 +00:00
2016-03-15 14:12:06 +00:00
return ( result ) ;
}
2016-07-13 19:59:42 +00:00
// NOTE(allen|a4.0.9): All command calls can now go through this hook
// If this hook is not implemented a default behavior of calling the
// command is used. It is important to note that paste_next does not
// work without this hook.
2016-08-22 19:31:19 +00:00
// NOTE(allen|a4.0.10): As of this version the word_complete command
// also relies on this particular command caller hook.
2016-07-13 19:59:42 +00:00
COMMAND_CALLER_HOOK ( default_command_caller ) {
2016-09-17 00:03:09 +00:00
View_Summary view = get_active_view ( app , AccessAll ) ;
2016-07-13 19:59:42 +00:00
2016-12-14 16:09:54 +00:00
view_paste_index [ view . view_id ] . next_rewrite = 0 ;
2016-07-13 19:59:42 +00:00
exec_command ( app , cmd ) ;
2016-12-14 16:09:54 +00:00
view_paste_index [ view . view_id ] . rewrite = view_paste_index [ view . view_id ] . next_rewrite ;
2016-07-13 19:59:42 +00:00
return ( 0 ) ;
}
2016-12-24 21:09:53 +00:00
struct Config_Line {
Cpp_Token id_token ;
Cpp_Token subscript_token ;
Cpp_Token eq_token ;
Cpp_Token val_token ;
int32_t val_array_start ;
int32_t val_array_end ;
int32_t val_array_count ;
bool32 read_success ;
} ;
struct Config_Item {
Config_Line line ;
2016-12-26 22:49:01 +00:00
Cpp_Token_Array array ;
2016-12-24 21:09:53 +00:00
char * mem ;
String id ;
int32_t subscript_index ;
bool32 has_subscript ;
} ;
struct Config_Array_Reader {
2016-12-26 22:49:01 +00:00
Cpp_Token_Array array ;
2016-12-24 21:09:53 +00:00
char * mem ;
int32_t i ;
int32_t val_array_end ;
bool32 good ;
} ;
static Cpp_Token
read_config_token ( Cpp_Token_Array array , int32_t * i_ptr ) {
Cpp_Token token = { 0 } ;
int32_t i = * i_ptr ;
for ( ; i < array . count ; + + i ) {
Cpp_Token comment_token = array . tokens [ i ] ;
if ( comment_token . type ! = CPP_TOKEN_COMMENT ) {
break ;
}
}
if ( i < array . count ) {
token = array . tokens [ i ] ;
}
2016-12-26 22:49:01 +00:00
* i_ptr = i ;
2016-12-24 21:09:53 +00:00
return ( token ) ;
}
static Config_Line
read_config_line ( Cpp_Token_Array array , int32_t * i_ptr ) {
Config_Line config_line = { 0 } ;
int32_t i = * i_ptr ;
config_line . id_token = read_config_token ( array , & i ) ;
if ( config_line . id_token . type = = CPP_TOKEN_IDENTIFIER ) {
+ + i ;
if ( i < array . count ) {
Cpp_Token token = read_config_token ( array , & i ) ;
bool32 subscript_success = 1 ;
2016-12-26 22:49:01 +00:00
if ( token . type = = CPP_TOKEN_BRACKET_OPEN ) {
2016-12-24 21:09:53 +00:00
subscript_success = 0 ;
+ + i ;
if ( i < array . count ) {
config_line . subscript_token = read_config_token ( array , & i ) ;
if ( config_line . subscript_token . type = = CPP_TOKEN_INTEGER_CONSTANT ) {
+ + i ;
if ( i < array . count ) {
token = read_config_token ( array , & i ) ;
2016-12-26 22:49:01 +00:00
if ( token . type = = CPP_TOKEN_BRACKET_CLOSE ) {
2016-12-24 21:09:53 +00:00
+ + i ;
if ( i < array . count ) {
token = read_config_token ( array , & i ) ;
subscript_success = 1 ;
}
}
}
}
}
}
if ( subscript_success ) {
if ( token . type = = CPP_TOKEN_EQ ) {
config_line . eq_token = read_config_token ( array , & i ) ;
+ + i ;
if ( i < array . count ) {
Cpp_Token val_token = read_config_token ( array , & i ) ;
bool32 array_success = 1 ;
if ( val_token . type = = CPP_TOKEN_BRACE_OPEN ) {
array_success = 0 ;
+ + i ;
if ( i < array . count ) {
config_line . val_array_start = i ;
bool32 expecting_array_item = 1 ;
for ( ; i < array . count ; + + i ) {
Cpp_Token array_token = read_config_token ( array , & i ) ;
2016-12-26 22:49:01 +00:00
if ( array_token . size = = 0 ) {
break ;
}
if ( array_token . type = = CPP_TOKEN_BRACE_CLOSE ) {
2016-12-24 21:09:53 +00:00
config_line . val_array_end = i ;
array_success = 1 ;
break ;
}
else {
if ( array_token . type = = CPP_TOKEN_COMMA ) {
if ( ! expecting_array_item ) {
expecting_array_item = 1 ;
}
else {
break ;
}
}
else {
if ( expecting_array_item ) {
expecting_array_item = 0 ;
+ + config_line . val_array_count ;
}
}
}
}
}
}
if ( array_success ) {
config_line . val_token = val_token ;
+ + i ;
if ( i < array . count ) {
Cpp_Token semicolon_token = read_config_token ( array , & i ) ;
if ( semicolon_token . type = = CPP_TOKEN_SEMICOLON ) {
config_line . read_success = 1 ;
}
}
}
}
}
}
}
}
if ( ! config_line . read_success ) {
for ( ; i < array . count ; + + i ) {
Cpp_Token token = read_config_token ( array , & i ) ;
if ( token . type = = CPP_TOKEN_SEMICOLON ) {
break ;
}
}
}
* i_ptr = i ;
return ( config_line ) ;
}
static Config_Item
2016-12-26 22:49:01 +00:00
get_config_item ( Config_Line line , char * mem , Cpp_Token_Array array ) {
2016-12-24 21:09:53 +00:00
Config_Item item = { 0 } ;
item . line = line ;
2016-12-26 22:49:01 +00:00
item . array = array ;
2016-12-24 21:09:53 +00:00
item . mem = mem ;
2016-12-26 22:49:01 +00:00
if ( line . id_token . size ! = 0 ) {
item . id = make_string ( mem + line . id_token . start , line . id_token . size ) ;
}
2016-12-24 21:09:53 +00:00
if ( line . subscript_token . size ! = 0 ) {
String subscript_str = make_string ( mem + line . subscript_token . start , line . subscript_token . size ) ;
item . subscript_index = str_to_int_s ( subscript_str ) ;
item . has_subscript = 1 ;
}
return ( item ) ;
}
static bool32
config_var ( Config_Item item , char * var_name , int32_t * subscript , uint32_t token_type , void * var_out ) {
bool32 result = 0 ;
bool32 subscript_succes = 1 ;
if ( item . line . val_token . type = = token_type ) {
if ( ( var_name = = 0 & & item . id . size = = 0 ) | | match ( item . id , var_name ) ) {
if ( subscript ) {
if ( item . has_subscript ) {
* subscript = item . subscript_index ;
}
else {
subscript_succes = 0 ;
}
}
2016-12-26 22:49:01 +00:00
2016-12-24 21:09:53 +00:00
if ( subscript_succes ) {
if ( var_out ) {
switch ( token_type ) {
case CPP_TOKEN_BOOLEAN_CONSTANT :
{
* ( bool32 * ) var_out = ( item . mem [ item . line . val_token . start ] = = ' t ' ) ;
} break ;
case CPP_TOKEN_INTEGER_CONSTANT :
{
String val = make_string ( item . mem + item . line . val_token . start , item . line . val_token . size ) ;
* ( int32_t * ) var_out = str_to_int ( val ) ;
} break ;
case CPP_TOKEN_STRING_CONSTANT :
{
* ( String * ) var_out = make_string ( item . mem + item . line . val_token . start + 1 , item . line . val_token . size - 2 ) ;
} break ;
case CPP_TOKEN_BRACE_OPEN :
{
Config_Array_Reader * array_reader = ( Config_Array_Reader * ) var_out ;
2016-12-26 22:49:01 +00:00
array_reader - > array = item . array ;
2016-12-24 21:09:53 +00:00
array_reader - > mem = item . mem ;
array_reader - > i = item . line . val_array_start ;
array_reader - > val_array_end = item . line . val_array_end ;
array_reader - > good = 1 ;
} break ;
}
}
result = 1 ;
}
}
}
return ( result ) ;
}
static bool32
config_bool_var ( Config_Item item , char * var_name , int32_t * subscript , bool32 * var_out ) {
bool32 result = config_var ( item , var_name , subscript , CPP_TOKEN_BOOLEAN_CONSTANT , var_out ) ;
return ( result ) ;
}
static bool32
config_int_var ( Config_Item item , char * var_name , int32_t * subscript , int32_t * var_out ) {
bool32 result = config_var ( item , var_name , subscript , CPP_TOKEN_INTEGER_CONSTANT , var_out ) ;
return ( result ) ;
}
static bool32
config_string_var ( Config_Item item , char * var_name , int32_t * subscript , String * var_out ) {
bool32 result = config_var ( item , var_name , subscript , CPP_TOKEN_STRING_CONSTANT , var_out ) ;
return ( result ) ;
}
static bool32
config_array_var ( Config_Item item , char * var_name , int32_t * subscript , Config_Array_Reader * array_reader ) {
bool32 result = config_var ( item , var_name , subscript , CPP_TOKEN_BRACE_OPEN , array_reader ) ;
return ( result ) ;
}
static bool32
config_array_next_item ( Config_Array_Reader * array_reader , Config_Item * item ) {
2016-12-26 22:49:01 +00:00
bool32 result = 0 ;
2016-12-24 21:09:53 +00:00
2016-12-26 22:49:01 +00:00
for ( ; array_reader - > i < array_reader - > val_array_end ;
+ + array_reader - > i ) {
Cpp_Token array_token = read_config_token ( array_reader - > array , & array_reader - > i ) ;
if ( array_token . size = = 0 | | array_reader - > i > = array_reader - > val_array_end ) {
break ;
}
if ( array_token . type = = CPP_TOKEN_BRACE_CLOSE ) {
break ;
}
switch ( array_token . type ) {
case CPP_TOKEN_BOOLEAN_CONSTANT :
case CPP_TOKEN_INTEGER_CONSTANT :
case CPP_TOKEN_STRING_CONSTANT :
{
Config_Line line = { 0 } ;
line . val_token = array_token ;
line . read_success = 1 ;
* item = get_config_item ( line , array_reader - > mem , array_reader - > array ) ;
result = 1 ;
+ + array_reader - > i ;
goto doublebreak ;
} break ;
}
}
doublebreak : ;
2016-12-24 21:09:53 +00:00
2016-12-26 22:49:01 +00:00
array_reader - > good = result ;
2016-12-24 21:09:53 +00:00
return ( result ) ;
}
static bool32
config_array_good ( Config_Array_Reader * array_reader ) {
bool32 result = ( array_reader - > good ) ;
return ( result ) ;
}
2016-11-12 21:33:54 +00:00
// NOTE(allen|a4.0.12): A primordial config system (actually really hate this but it seems best at least right now... arg)
2016-10-28 14:11:56 +00:00
static bool32 enable_code_wrapping = 1 ;
2016-12-24 21:09:53 +00:00
static bool32 automatically_adjust_wrapping = 1 ;
2016-10-28 14:11:56 +00:00
static int32_t default_wrap_width = 672 ;
2016-11-12 21:33:54 +00:00
static int32_t default_min_base_width = 550 ;
2016-12-26 22:49:01 +00:00
static bool32 automatically_indent_text_on_save = 1 ;
2016-12-24 21:09:53 +00:00
static String default_theme_name = make_lit_string ( " 4coder " ) ;
static String default_font_name = make_lit_string ( " Liberation Sans " ) ;
2016-10-28 14:11:56 +00:00
# include <stdio.h>
2016-12-18 20:42:11 +00:00
static void
adjust_all_buffer_wrap_widths ( Application_Links * app , int32_t wrap_widths , int32_t min_base_width ) {
for ( Buffer_Summary buffer = get_buffer_first ( app , AccessAll ) ;
buffer . exists ;
get_buffer_next ( app , & buffer , AccessAll ) ) {
buffer_set_setting ( app , & buffer , BufferSetting_WrapPosition , wrap_widths ) ;
buffer_set_setting ( app , & buffer , BufferSetting_MinimumBaseWrapPosition , min_base_width ) ;
}
default_wrap_width = wrap_widths ;
default_min_base_width = min_base_width ;
}
2016-12-24 21:09:53 +00:00
static bool32
file_handle_dump ( Partition * part , FILE * file , char * * mem_ptr , int32_t * size_ptr ) {
bool32 success = 0 ;
fseek ( file , 0 , SEEK_END ) ;
int32_t size = ftell ( file ) ;
char * mem = ( char * ) push_block ( part , size + 1 ) ;
fseek ( file , 0 , SEEK_SET ) ;
int32_t check_size = ( int32_t ) fread ( mem , 1 , size , file ) ;
if ( check_size = = size ) {
mem [ size ] = 0 ;
success = 1 ;
}
* mem_ptr = mem ;
* size_ptr = size ;
return ( success ) ;
}
2016-10-28 14:11:56 +00:00
static void
process_config_file ( Application_Links * app ) {
2016-12-24 21:09:53 +00:00
Partition * part = & global_part ;
2016-10-28 14:11:56 +00:00
FILE * file = fopen ( " config.4coder " , " rb " ) ;
2016-12-14 16:09:54 +00:00
if ( ! file ) {
char space [ 256 ] ;
int32_t size = get_4ed_path ( app , space , sizeof ( space ) ) ;
String str = make_string_cap ( space , size , sizeof ( space ) ) ;
append_sc ( & str , " /config.4coder " ) ;
terminate_with_null ( & str ) ;
file = fopen ( str . str , " rb " ) ;
}
2016-10-28 14:11:56 +00:00
if ( file ) {
2016-12-24 21:09:53 +00:00
Temp_Memory temp = begin_temp_memory ( part ) ;
char * mem = 0 ;
int32_t size = 0 ;
bool32 file_read_success = file_handle_dump ( part , file , & mem , & size ) ;
if ( file_read_success ) {
2016-12-08 17:16:50 +00:00
fclose ( file ) ;
2016-10-28 14:11:56 +00:00
2016-12-08 17:16:50 +00:00
Cpp_Token_Array array ;
array . count = 0 ;
array . max_count = ( 1 < < 20 ) / sizeof ( Cpp_Token ) ;
array . tokens = push_array ( & global_part , Cpp_Token , array . max_count ) ;
Cpp_Lex_Data S = cpp_lex_data_init ( ) ;
Cpp_Lex_Result result = cpp_lex_step ( & S , mem , size + 1 , HAS_NULL_TERM , & array , NO_OUT_LIMIT ) ;
if ( result = = LexResult_Finished ) {
2016-12-18 20:42:11 +00:00
int32_t new_wrap_width = default_wrap_width ;
int32_t new_min_base_width = default_min_base_width ;
2016-12-08 17:16:50 +00:00
for ( int32_t i = 0 ; i < array . count ; + + i ) {
2016-12-24 21:09:53 +00:00
Config_Line config_line = read_config_line ( array , & i ) ;
if ( config_line . read_success ) {
2016-12-26 22:49:01 +00:00
Config_Item item = get_config_item ( config_line , mem , array ) ;
2016-12-24 21:09:53 +00:00
config_bool_var ( item , " enable_code_wrapping " , 0 , & enable_code_wrapping ) ;
config_bool_var ( item , " automatically_adjust_wrapping " , 0 , & automatically_adjust_wrapping ) ;
2016-12-26 22:49:01 +00:00
config_bool_var ( item , " automatically_indent_text_on_save " , 0 , & automatically_indent_text_on_save ) ;
2016-12-24 21:09:53 +00:00
config_int_var ( item , " default_wrap_width " , 0 , & new_wrap_width ) ;
config_int_var ( item , " default_min_base_width " , 0 , & new_min_base_width ) ;
config_string_var ( item , " default_theme_name " , 0 , & default_theme_name ) ;
config_string_var ( item , " default_font_name " , 0 , & default_font_name ) ;
2016-10-28 14:11:56 +00:00
}
}
2016-12-24 21:09:53 +00:00
adjust_all_buffer_wrap_widths ( app , new_wrap_width , new_min_base_width ) ;
}
}
end_temp_memory ( temp ) ;
}
else {
print_message ( app , literal ( " Did not find config.4coder, using default settings " ) ) ;
}
}
// NOTE(allen): Project system setup
2016-12-26 22:49:01 +00:00
static char * default_extensions [ ] = {
" cpp " ,
" hpp " ,
" c " ,
" h " ,
" cc "
} ;
struct Fkey_Command {
char command [ 128 ] ;
char out [ 128 ] ;
bool32 use_build_panel ;
} ;
struct Project {
char dir_space [ 256 ] ;
char * dir ;
int32_t dir_len ;
char extension_space [ 256 ] ;
char * extensions [ 94 ] ;
int32_t extension_count ;
Fkey_Command fkey_commands [ 16 ] ;
bool32 close_all_code_when_this_project_closes ;
bool32 close_all_files_when_project_opens ;
} ;
static Project null_project = { } ;
static Project current_project = { } ;
static void
set_project_extensions ( Project * project , String src ) {
int32_t mode = 0 ;
int32_t j = 0 , k = 0 ;
for ( int32_t i = 0 ; i < src . size ; + + i ) {
switch ( mode ) {
case 0 :
{
if ( src . str [ i ] = = ' . ' ) {
mode = 1 ;
project - > extensions [ k + + ] = & project - > extension_space [ j ] ;
}
} break ;
case 1 :
{
if ( src . str [ i ] = = ' . ' ) {
project - > extension_space [ j + + ] = 0 ;
project - > extensions [ k + + ] = & project - > extension_space [ j ] ;
}
else {
project - > extension_space [ j + + ] = src . str [ i ] ;
}
} break ;
}
}
project - > extension_space [ j + + ] = 0 ;
project - > extension_count = k ;
}
// TODO(allen): make this a string operation or a lexer operation or something
static void
interpret_escaped_string ( char * dst , String src ) {
int32_t mode = 0 ;
int32_t j = 0 ;
for ( int32_t i = 0 ; i < src . size ; + + i ) {
switch ( mode ) {
case 0 :
{
if ( src . str [ i ] = = ' \\ ' ) {
mode = 1 ;
}
else {
dst [ j + + ] = src . str [ i ] ;
}
} break ;
case 1 :
{
switch ( src . str [ i ] ) {
case ' \\ ' : { dst [ j + + ] = ' \\ ' ; mode = 0 ; } break ;
case ' n ' : { dst [ j + + ] = ' \n ' ; mode = 0 ; } break ;
case ' t ' : { dst [ j + + ] = ' \t ' ; mode = 0 ; } break ;
case ' " ' : { dst [ j + + ] = ' " ' ; mode = 0 ; } break ;
case ' 0 ' : { dst [ j + + ] = ' \0 ' ; mode = 0 ; } break ;
}
} break ;
}
}
dst [ j ] = 0 ;
}
static void
close_all_files_with_extension ( Application_Links * app , Partition * scratch_part , char * * extension_list , int32_t extension_count ) {
Temp_Memory temp = begin_temp_memory ( scratch_part ) ;
int32_t buffers_to_close_max = partition_remaining ( scratch_part ) / sizeof ( int32_t ) ;
int32_t * buffers_to_close = push_array ( scratch_part , int32_t , buffers_to_close_max ) ;
int32_t buffers_to_close_count = 0 ;
bool32 do_repeat = 0 ;
do {
buffers_to_close_count = 0 ;
do_repeat = 0 ;
uint32_t access = AccessAll ;
Buffer_Summary buffer = { 0 } ;
for ( buffer = get_buffer_first ( app , access ) ;
buffer . exists ;
get_buffer_next ( app , & buffer , access ) ) {
bool32 is_match = 1 ;
if ( extension_count > 0 ) {
String extension = file_extension ( make_string ( buffer . file_name , buffer . file_name_len ) ) ;
is_match = 0 ;
for ( int32_t i = 0 ; i < extension_count ; + + i ) {
if ( match ( extension , extension_list [ i ] ) ) {
is_match = 1 ;
break ;
}
}
}
if ( is_match ) {
if ( buffers_to_close_count > = buffers_to_close_max ) {
do_repeat = 1 ;
break ;
}
buffers_to_close [ buffers_to_close_count + + ] = buffer . buffer_id ;
}
}
for ( int32_t i = 0 ; i < buffers_to_close_count ; + + i ) {
kill_buffer ( app , buffer_identifier ( buffers_to_close [ i ] ) , true , 0 ) ;
}
}
while ( do_repeat ) ;
end_temp_memory ( temp ) ;
}
static void
open_all_files_with_extension ( Application_Links * app , Partition * scratch_part , char * * extension_list , int32_t extension_count ) {
Temp_Memory temp = begin_temp_memory ( scratch_part ) ;
int32_t max_size = partition_remaining ( scratch_part ) ;
char * memory = push_array ( scratch_part , char , max_size ) ;
String dir = make_string_cap ( memory , 0 , max_size ) ;
dir . size = directory_get_hot ( app , dir . str , dir . memory_size ) ;
int32_t dir_size = dir . size ;
// NOTE(allen|a3.4.4): Here we get the list of files in this directory.
// Notice that we free_file_list at the end.
File_List list = get_file_list ( app , dir . str , dir . size ) ;
for ( int32_t i = 0 ; i < list . count ; + + i ) {
File_Info * info = list . infos + i ;
if ( ! info - > folder ) {
bool32 is_match = 1 ;
if ( extension_count > 0 ) {
is_match = 0 ;
String extension = make_string_cap ( info - > filename , info - > filename_len , info - > filename_len + 1 ) ;
extension = file_extension ( extension ) ;
for ( int32_t j = 0 ; j < extension_count ; + + j ) {
if ( match ( extension , extension_list [ j ] ) ) {
is_match = 1 ;
break ;
}
}
if ( is_match ) {
// NOTE(allen): There's no way in the 4coder API to use relative
// paths at the moment, so everything should be full paths. Which is
// managable. Here simply set the dir string size back to where it
// was originally, so that new appends overwrite old ones.
dir . size = dir_size ;
append_sc ( & dir , info - > filename ) ;
create_buffer ( app , dir . str , dir . size , 0 ) ;
}
}
}
}
free_file_list ( app , list ) ;
end_temp_memory ( temp ) ;
}
static char * *
get_standard_code_extensions ( int32_t * extension_count_out ) {
char * * extension_list = default_extensions ;
int32_t extension_count = ArrayCount ( default_extensions ) ;
if ( current_project . dir ! = 0 ) {
extension_list = current_project . extensions ;
extension_count = current_project . extension_count ;
}
* extension_count_out = extension_count ;
return ( extension_list ) ;
}
// NOTE(allen|a4.0.14): open_all_code and close_all_code now use the extensions set in the loaded project. If there is no project loaded the extensions ".cpp.hpp.c.h.cc" are used.
CUSTOM_COMMAND_SIG ( open_all_code ) {
int32_t extension_count = 0 ;
char * * extension_list = get_standard_code_extensions ( & extension_count ) ;
open_all_files_with_extension ( app , & global_part , extension_list , extension_count ) ;
}
CUSTOM_COMMAND_SIG ( close_all_code ) {
int32_t extension_count = 0 ;
char * * extension_list = get_standard_code_extensions ( & extension_count ) ;
close_all_files_with_extension ( app , & global_part , extension_list , extension_count ) ;
}
2016-12-24 21:09:53 +00:00
CUSTOM_COMMAND_SIG ( load_project ) {
Partition * part = & global_part ;
char project_file_space [ 512 ] ;
String project_name = make_fixed_width_string ( project_file_space ) ;
project_name . size = directory_get_hot ( app , project_name . str , project_name . memory_size ) ;
if ( project_name . size > = project_name . memory_size ) {
project_name . size = 0 ;
}
if ( project_name . size ! = 0 ) {
2016-12-26 22:49:01 +00:00
int32_t original_size = project_name . size ;
append_sc ( & project_name , " project.4coder " ) ;
terminate_with_null ( & project_name ) ;
2016-12-24 21:09:53 +00:00
2016-12-26 22:49:01 +00:00
// TODO(allen): make sure we do nothing when this project is already open
FILE * file = fopen ( project_name . str , " rb " ) ;
if ( file ) {
project_name . size = original_size ;
terminate_with_null ( & project_name ) ;
Temp_Memory temp = begin_temp_memory ( part ) ;
2016-12-24 21:09:53 +00:00
2016-12-26 22:49:01 +00:00
char * mem = 0 ;
int32_t size = 0 ;
bool32 file_read_success = file_handle_dump ( part , file , & mem , & size ) ;
if ( file_read_success ) {
fclose ( file ) ;
Cpp_Token_Array array ;
array . count = 0 ;
array . max_count = ( 1 < < 20 ) / sizeof ( Cpp_Token ) ;
array . tokens = push_array ( & global_part , Cpp_Token , array . max_count ) ;
Cpp_Lex_Data S = cpp_lex_data_init ( ) ;
Cpp_Lex_Result result = cpp_lex_step ( & S , mem , size + 1 , HAS_NULL_TERM , & array , NO_OUT_LIMIT ) ;
if ( result = = LexResult_Finished ) {
// Clear out current project
if ( current_project . close_all_code_when_this_project_closes ) {
exec_command ( app , close_all_code ) ;
}
current_project = null_project ;
2016-12-24 21:09:53 +00:00
2016-12-26 22:49:01 +00:00
// Set new project directory
2016-12-24 21:09:53 +00:00
{
2016-12-26 22:49:01 +00:00
current_project . dir = current_project . dir_space ;
String str = make_fixed_width_string ( current_project . dir_space ) ;
copy ( & str , project_name ) ;
terminate_with_null ( & str ) ;
current_project . dir_len = str . size ;
2016-10-28 14:11:56 +00:00
}
2016-12-08 17:16:50 +00:00
2016-12-26 22:49:01 +00:00
// Read the settings from project.4coder
for ( int32_t i = 0 ; i < array . count ; + + i ) {
Config_Line config_line = read_config_line ( array , & i ) ;
if ( config_line . read_success ) {
Config_Item item = get_config_item ( config_line , mem , array ) ;
2016-12-24 21:09:53 +00:00
2016-12-26 22:49:01 +00:00
{
String str = { 0 } ;
if ( config_string_var ( item , " extensions " , 0 , & str ) ) {
if ( str . size < sizeof ( current_project . extension_space ) ) {
set_project_extensions ( & current_project , str ) ;
print_message ( app , str . str , str . size ) ;
print_message ( app , " \n " , 1 ) ;
2016-12-24 21:09:53 +00:00
}
2016-12-26 22:49:01 +00:00
else {
print_message ( app , literal ( " STRING TOO LONG! \n " ) ) ;
2016-12-24 21:09:53 +00:00
}
2016-12-26 22:49:01 +00:00
}
}
{
# if defined(_WIN32)
# define FKEY_COMMAND "fkey_command_win"
# elif defined(__linux__)
# define FKEY_COMMAND "fkey_command_linux"
# else
# error no project configuration names for this platform
# endif
2016-12-24 21:09:53 +00:00
2016-12-26 22:49:01 +00:00
int32_t index = 0 ;
Config_Array_Reader array_reader = { 0 } ;
if ( config_array_var ( item , FKEY_COMMAND , & index , & array_reader ) ) {
if ( index > = 1 & & index < = 16 ) {
Config_Item array_item = { 0 } ;
int32_t item_index = 0 ;
char space [ 256 ] ;
String msg = make_fixed_width_string ( space ) ;
append ( & msg , FKEY_COMMAND " [ " ) ;
append_int_to_str ( & msg , index ) ;
append ( & msg , " ] = { " ) ;
for ( config_array_next_item ( & array_reader , & array_item ) ;
config_array_good ( & array_reader ) ;
config_array_next_item ( & array_reader , & array_item ) ) {
if ( item_index > = 3 ) {
break ;
}
append ( & msg , " [ " ) ;
append_int_to_str ( & msg , item_index ) ;
append ( & msg , " ] = " ) ;
bool32 read_string = 0 ;
bool32 read_bool = 0 ;
char * dest_str = 0 ;
int32_t dest_str_size = 0 ;
bool32 * dest_bool = 0 ;
switch ( item_index ) {
case 0 :
{
dest_str = current_project . fkey_commands [ index - 1 ] . command ;
dest_str_size = sizeof ( current_project . fkey_commands [ index - 1 ] . command ) ;
read_string = 1 ;
} break ;
case 1 :
{
dest_str = current_project . fkey_commands [ index - 1 ] . out ;
dest_str_size = sizeof ( current_project . fkey_commands [ index - 1 ] . out ) ;
read_string = 1 ;
} break ;
case 2 :
{
dest_bool = & current_project . fkey_commands [ index - 1 ] . use_build_panel ;
read_bool = 1 ;
} break ;
}
if ( read_string ) {
if ( config_int_var ( array_item , 0 , 0 , 0 ) ) {
append ( & msg , " NULL, " ) ;
dest_str [ 0 ] = 0 ;
}
String str = { 0 } ;
if ( config_string_var ( array_item , 0 , 0 , & str ) ) {
if ( str . size < dest_str_size ) {
interpret_escaped_string ( dest_str , str ) ;
append ( & msg , dest_str ) ;
append ( & msg , " , " ) ;
}
else {
append ( & msg , " STRING TOO LONG!, " ) ;
}
}
2016-12-24 21:09:53 +00:00
}
2016-12-26 22:49:01 +00:00
if ( read_bool ) {
if ( config_bool_var ( array_item , 0 , 0 , dest_bool ) ) {
if ( dest_bool ) {
append ( & msg , " true, " ) ;
}
else {
append ( & msg , " false, " ) ;
}
}
2016-12-24 21:09:53 +00:00
}
2016-12-26 22:49:01 +00:00
item_index + + ;
}
append ( & msg , " } \n " ) ;
print_message ( app , msg . str , msg . size ) ;
}
}
2016-12-24 21:09:53 +00:00
}
2016-10-28 14:11:56 +00:00
}
}
2016-12-26 22:49:01 +00:00
if ( current_project . close_all_files_when_project_opens ) {
close_all_files_with_extension ( app , & global_part , 0 , 0 ) ;
2016-12-24 21:09:53 +00:00
}
2016-12-26 22:49:01 +00:00
// Open all project files
exec_command ( app , open_all_code ) ;
2016-10-28 14:11:56 +00:00
}
}
2016-12-26 22:49:01 +00:00
end_temp_memory ( temp ) ;
2016-12-08 17:16:50 +00:00
}
else {
2016-12-26 22:49:01 +00:00
char message_space [ 512 ] ;
String message = make_fixed_width_string ( message_space ) ;
append_sc ( & message , " Did not find project.4coder. " ) ;
if ( current_project . dir ! = 0 ) {
append_sc ( & message , " Continuing with: " ) ;
append_sc ( & message , current_project . dir ) ;
}
else {
append_sc ( & message , " Continuing without a project " ) ;
}
print_message ( app , message . str , message . size ) ;
2016-10-28 14:11:56 +00:00
}
2016-12-26 22:49:01 +00:00
}
else {
print_message ( app , literal ( " Failed trying to get project file name " ) ) ;
2016-10-28 14:11:56 +00:00
}
}
2016-12-26 22:49:01 +00:00
CUSTOM_COMMAND_SIG ( project_fkey_command ) {
User_Input input = get_command_input ( app ) ;
if ( input . type = = UserInputKey ) {
if ( input . key . keycode > = key_f1 & & input . key . keycode < = key_f16 ) {
int32_t ind = ( input . key . keycode - key_f1 ) ;
char * command = current_project . fkey_commands [ ind ] . command ;
char * out = current_project . fkey_commands [ ind ] . out ;
bool32 use_build_panel = current_project . fkey_commands [ ind ] . use_build_panel ;
if ( command [ 0 ] ! = 0 ) {
int32_t command_len = str_size ( command ) ;
View_Summary view_ = { 0 } ;
View_Summary * view = 0 ;
Buffer_Identifier buffer_id = { 0 } ;
uint32_t flags = 0 ;
bool32 set_fancy_font = 0 ;
if ( out [ 0 ] ! = 0 ) {
int32_t out_len = str_size ( out ) ;
buffer_id = buffer_identifier ( out , out_len ) ;
view = & view_ ;
if ( use_build_panel ) {
view_ = get_or_open_build_panel ( app ) ;
if ( match ( out , " *compilation* " ) ) {
set_fancy_font = 1 ;
}
}
else {
view_ = get_active_view ( app , AccessAll ) ;
}
prev_location = null_location ;
lock_jump_buffer ( out , out_len ) ;
}
else {
// TODO(allen): fix the exec_system_command call so it can take a null buffer_id.
buffer_id = buffer_identifier ( literal ( " *dump* " ) ) ;
}
exec_system_command ( app , view , buffer_id , current_project . dir , current_project . dir_len , command , command_len , flags ) ;
if ( set_fancy_font ) {
set_fancy_compilation_buffer_font ( app ) ;
}
}
}
}
2016-12-24 21:09:53 +00:00
}
2016-10-28 14:11:56 +00:00
2016-06-28 22:58:50 +00:00
# endif
2016-08-22 19:31:19 +00:00