2017-01-23 06:19:43 +00:00
|
|
|
/*
|
|
|
|
4coder_search.cpp - Commands that search accross buffers including word complete,
|
|
|
|
and list all locations.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// TOP
|
|
|
|
|
|
|
|
//
|
|
|
|
// Search Iteration Systems
|
|
|
|
//
|
|
|
|
|
2016-07-12 18:20:06 +00:00
|
|
|
static void
|
2019-06-01 23:58:28 +00:00
|
|
|
search_key_alloc(Heap *heap, Search_Key *key, umem *size, i32 count){
|
|
|
|
count = clamp_top(count, ArrayCount(key->words));
|
2017-11-29 23:00:14 +00:00
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
umem min_size = 0x7FFFFFFF;
|
|
|
|
umem total_size = 0;
|
|
|
|
for (i32 i = 0; i < count; ++i){
|
2017-11-29 23:00:14 +00:00
|
|
|
total_size += size[i];
|
|
|
|
if (min_size > size[i]){
|
|
|
|
min_size = size[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key->base == 0){
|
2019-06-01 23:58:28 +00:00
|
|
|
umem max_base_size = total_size*2;
|
|
|
|
key->base = heap_array(heap, u8, (i32)max_base_size);
|
2017-11-29 23:00:14 +00:00
|
|
|
key->base_size = max_base_size;
|
2016-07-12 18:20:06 +00:00
|
|
|
}
|
2017-11-29 23:00:14 +00:00
|
|
|
else if (key->base_size < total_size){
|
2019-06-01 23:58:28 +00:00
|
|
|
umem max_base_size = total_size*2;
|
2018-08-18 08:16:52 +00:00
|
|
|
heap_free(heap, key->base);
|
2019-06-01 23:58:28 +00:00
|
|
|
key->base = heap_array(heap, u8, (i32)max_base_size);
|
2017-11-29 23:00:14 +00:00
|
|
|
key->base_size = max_base_size;
|
2016-07-12 18:20:06 +00:00
|
|
|
}
|
2017-11-29 23:00:14 +00:00
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
u8 *char_ptr = key->base;
|
|
|
|
for (i32 i = 0; i < count; ++i){
|
|
|
|
key->words[i].str = char_ptr;
|
|
|
|
key->words[i].size = 0;
|
|
|
|
#if 0
|
2017-11-29 23:00:14 +00:00
|
|
|
key->words[i].str = char_ptr;
|
|
|
|
key->words[i].size = 0;
|
|
|
|
key->words[i].memory_size = size[i];
|
2019-06-01 23:58:28 +00:00
|
|
|
#endif
|
2017-11-29 23:00:14 +00:00
|
|
|
char_ptr += size[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
key->count = count;
|
|
|
|
key->min_size = min_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
search_iter_init(Search_Iter *iter, Search_Key key){
|
|
|
|
iter->key = key;
|
2016-07-12 18:20:06 +00:00
|
|
|
iter->i = 0;
|
|
|
|
iter->range_initialized = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-06-01 23:58:28 +00:00
|
|
|
search_set_init(Heap *heap, Search_Set *set, i32 range_count){
|
2016-07-12 18:20:06 +00:00
|
|
|
if (set->ranges == 0){
|
2019-06-01 23:58:28 +00:00
|
|
|
i32 max = range_count*2;
|
2018-08-18 08:16:52 +00:00
|
|
|
set->ranges = heap_array(heap, Search_Range, max);
|
2016-07-12 18:20:06 +00:00
|
|
|
set->max = max;
|
|
|
|
}
|
|
|
|
else if (set->max < range_count){
|
2019-06-01 23:58:28 +00:00
|
|
|
i32 max = range_count*2;
|
2018-08-18 08:16:52 +00:00
|
|
|
heap_free(heap, set->ranges);
|
|
|
|
set->ranges = heap_array(heap, Search_Range, max);
|
2016-07-12 18:20:06 +00:00
|
|
|
set->max = max;
|
|
|
|
}
|
|
|
|
set->count = range_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-06-01 23:58:28 +00:00
|
|
|
search_hits_table_alloc(Heap *heap, Table *hits, i32 table_size){
|
2016-07-12 18:20:06 +00:00
|
|
|
void *mem = 0;
|
2019-06-01 23:58:28 +00:00
|
|
|
i32 mem_size = table_required_mem_size(table_size, sizeof(Offset_String));
|
2016-07-12 18:20:06 +00:00
|
|
|
if (hits->hash_array == 0){
|
2018-08-18 08:16:52 +00:00
|
|
|
mem = heap_allocate(heap, mem_size);
|
2016-07-12 18:20:06 +00:00
|
|
|
}
|
|
|
|
else{
|
2018-08-18 08:16:52 +00:00
|
|
|
heap_free(heap, hits->hash_array);
|
|
|
|
mem = heap_allocate(heap, mem_size);
|
2016-07-12 18:20:06 +00:00
|
|
|
}
|
|
|
|
table_init_memory(hits, mem, table_size, sizeof(Offset_String));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-06-01 23:58:28 +00:00
|
|
|
search_hits_init(Heap *heap, Table *hits, String_Space *str, i32 table_size, i32 str_size){
|
2016-07-12 18:20:06 +00:00
|
|
|
if (hits->hash_array == 0){
|
2018-08-18 08:16:52 +00:00
|
|
|
search_hits_table_alloc(heap, hits, table_size);
|
2016-07-12 18:20:06 +00:00
|
|
|
}
|
|
|
|
else{
|
2019-06-01 23:58:28 +00:00
|
|
|
i32 mem_size = table_required_mem_size(table_size, sizeof(Offset_String));
|
2018-08-18 08:16:52 +00:00
|
|
|
heap_free(heap, hits->hash_array);
|
|
|
|
void *mem = heap_allocate(heap, mem_size);
|
2016-07-12 18:20:06 +00:00
|
|
|
table_init_memory(hits, mem, table_size, sizeof(Offset_String));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (str->space == 0){
|
2018-08-18 08:16:52 +00:00
|
|
|
str->space = heap_array(heap, char, str_size);
|
2016-07-12 18:20:06 +00:00
|
|
|
str->max = str_size;
|
|
|
|
}
|
|
|
|
else if (str->max < str_size){
|
2018-08-18 08:16:52 +00:00
|
|
|
heap_free(heap, str->space);
|
|
|
|
str->space = heap_array(heap, char, str_size);
|
2016-07-12 18:20:06 +00:00
|
|
|
str->max = str_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
str->pos = str->new_pos = 0;
|
|
|
|
table_clear(hits);
|
|
|
|
}
|
|
|
|
|
2017-11-29 23:00:14 +00:00
|
|
|
//
|
|
|
|
// Table Operations
|
|
|
|
//
|
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
static b32
|
|
|
|
search_hit_add(Heap *heap, Table *hits, String_Space *space, char *str, i32 len){
|
|
|
|
b32 result = false;
|
2017-01-23 06:19:43 +00:00
|
|
|
Assert(len != 0);
|
2016-07-12 18:20:06 +00:00
|
|
|
Offset_String ostring = strspace_append(space, str, len);
|
|
|
|
if (ostring.size == 0){
|
2019-06-01 23:58:28 +00:00
|
|
|
i32 new_size = space->max*2;
|
2016-07-12 18:20:06 +00:00
|
|
|
if (new_size < space->max + len){
|
|
|
|
new_size = space->max + len;
|
|
|
|
}
|
2018-08-18 08:16:52 +00:00
|
|
|
char *new_space = heap_array(heap, char, new_size);
|
|
|
|
memcpy(new_space, space->space, space->new_pos);
|
|
|
|
heap_free(heap, space->space);
|
|
|
|
space->space = new_space;
|
2016-07-12 18:20:06 +00:00
|
|
|
ostring = strspace_append(space, str, len);
|
|
|
|
}
|
|
|
|
|
2017-01-23 06:19:43 +00:00
|
|
|
Assert(ostring.size != 0);
|
2016-07-12 18:20:06 +00:00
|
|
|
|
|
|
|
if (table_at_capacity(hits)){
|
2018-11-20 08:18:54 +00:00
|
|
|
Table new_hits = {};
|
2018-08-18 08:16:52 +00:00
|
|
|
search_hits_table_alloc(heap, &new_hits, hits->max*2);
|
2016-07-12 18:20:06 +00:00
|
|
|
table_clear(&new_hits);
|
|
|
|
table_rehash(hits, &new_hits, space->space, tbl_offset_string_hash, tbl_offset_string_compare);
|
2018-08-18 08:16:52 +00:00
|
|
|
heap_free(heap, hits->hash_array);
|
2016-07-12 18:20:06 +00:00
|
|
|
*hits = new_hits;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!table_add(hits, &ostring, space->space, tbl_offset_string_hash, tbl_offset_string_compare)){
|
|
|
|
result = true;
|
|
|
|
strspace_keep_prev(space);
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
strspace_discard_prev(space);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
static b32
|
|
|
|
search_hit_add(Heap *heap, Table *hits, String_Space *space, String_Const_u8 string){
|
|
|
|
return(search_hit_add(heap, hits, space, (char*)string.str, (i32)string.size));
|
|
|
|
}
|
|
|
|
|
2017-11-29 23:00:14 +00:00
|
|
|
//
|
|
|
|
// Search Key Checking
|
|
|
|
//
|
|
|
|
|
|
|
|
static void
|
2019-06-01 23:58:28 +00:00
|
|
|
seek_potential_match(Application_Links *app, Search_Range *range, Search_Key key, Search_Match *result, Seek_Potential_Match_Direction direction, i32 start_pos, i32 end_pos){
|
2019-02-26 23:08:42 +00:00
|
|
|
b32 case_insensitive = ((range->flags & SearchFlag_CaseInsensitive) != 0);
|
|
|
|
b32 forward = (direction == SeekPotentialMatch_Forward);
|
2017-11-29 23:00:14 +00:00
|
|
|
#define OptFlag(b,f) ((b)?(f):(0))
|
|
|
|
Buffer_Seek_String_Flags flags = 0
|
|
|
|
| OptFlag(case_insensitive, BufferSeekString_CaseInsensitive)
|
|
|
|
| OptFlag(!forward, BufferSeekString_Backward);
|
2019-04-02 20:06:49 +00:00
|
|
|
result->buffer = range->buffer;
|
2017-11-29 23:00:14 +00:00
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
i32 best_pos = -1;
|
2017-11-29 23:00:14 +00:00
|
|
|
if (forward){
|
|
|
|
best_pos = end_pos;
|
|
|
|
}
|
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
for (i32 i = 0; i < key.count; ++i){
|
|
|
|
String_Const_u8 word = key.words[i];
|
|
|
|
i32 new_pos = -1;
|
|
|
|
buffer_seek_string(app, result->buffer, start_pos, end_pos, range->start, word, &new_pos, flags);
|
2017-11-29 23:00:14 +00:00
|
|
|
|
2017-12-01 19:13:36 +00:00
|
|
|
if (new_pos >= 0){
|
2017-11-29 23:00:14 +00:00
|
|
|
if (forward){
|
|
|
|
if (new_pos < best_pos){
|
|
|
|
best_pos = new_pos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
if (new_pos > best_pos){
|
|
|
|
best_pos = new_pos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result->start = best_pos;
|
|
|
|
}
|
|
|
|
|
2019-04-02 20:06:49 +00:00
|
|
|
static i32
|
2019-06-01 23:58:28 +00:00
|
|
|
buffer_seek_alpha_numeric_end(Application_Links *app, Buffer_ID buffer_id, i32 pos){
|
2016-07-12 18:20:06 +00:00
|
|
|
char space[1024];
|
2018-11-20 08:18:54 +00:00
|
|
|
Stream_Chunk chunk = {};
|
2019-04-02 20:06:49 +00:00
|
|
|
if (init_stream_chunk(&chunk, app, buffer_id, pos, space, sizeof(space))){
|
2019-06-01 23:58:28 +00:00
|
|
|
i32 still_looping = true;
|
2016-07-12 18:20:06 +00:00
|
|
|
do{
|
2017-03-23 19:15:33 +00:00
|
|
|
for (; pos < chunk.end; ++pos){
|
2019-02-26 23:30:08 +00:00
|
|
|
u8 at_pos = (u8)chunk.data[pos];
|
2019-06-01 23:58:28 +00:00
|
|
|
if (!character_is_alpha_numeric_unicode(at_pos)) goto double_break;
|
2016-07-12 18:20:06 +00:00
|
|
|
}
|
|
|
|
still_looping = forward_stream_chunk(&chunk);
|
|
|
|
}while(still_looping);
|
|
|
|
}
|
|
|
|
double_break:;
|
|
|
|
return(pos);
|
|
|
|
}
|
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
static i32
|
|
|
|
match_check(Application_Links *app, Search_Range *range, i32 *pos, Search_Match *result_ptr, Search_Key key){
|
|
|
|
i32 result_code = FindResult_None;
|
2016-07-12 18:20:06 +00:00
|
|
|
|
|
|
|
Search_Match result = *result_ptr;
|
2019-06-01 23:58:28 +00:00
|
|
|
i32 end_pos = range->start + range->size;
|
2016-07-12 18:20:06 +00:00
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
i32 type = (range->flags & SearchFlag_MatchMask);
|
2017-11-29 23:00:14 +00:00
|
|
|
result.match_word_index = -1;
|
2016-07-18 18:36:53 +00:00
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
for (i32 i = 0; i < key.count; ++i){
|
|
|
|
String_Const_u8 word = key.words[i];
|
2017-11-29 23:00:14 +00:00
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
i32 found_match = FindResult_None;
|
2017-11-29 23:00:14 +00:00
|
|
|
switch (type){
|
|
|
|
case SearchFlag_MatchWholeWord:
|
|
|
|
{
|
2019-06-01 23:58:28 +00:00
|
|
|
u8 prev = ' ';
|
|
|
|
if (character_is_alpha_numeric(string_get_character(word, 0))){
|
2019-04-02 20:06:49 +00:00
|
|
|
prev = buffer_get_char(app, result.buffer, result.start - 1);
|
2017-11-29 23:00:14 +00:00
|
|
|
}
|
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
if (!character_is_alpha_numeric(prev)){
|
|
|
|
result.end = result.start + (i32)word.size;
|
2017-11-29 23:00:14 +00:00
|
|
|
if (result.end <= end_pos){
|
2019-06-01 23:58:28 +00:00
|
|
|
u8 next = ' ';
|
|
|
|
if (character_is_alpha_numeric_unicode(string_get_character(word, word.size - 1))){
|
2019-04-02 20:06:49 +00:00
|
|
|
next = buffer_get_char(app, result.buffer, result.end);
|
2017-11-29 23:00:14 +00:00
|
|
|
}
|
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
if (!character_is_alpha_numeric_unicode(next)){
|
2017-11-29 23:00:14 +00:00
|
|
|
result.found_match = true;
|
|
|
|
found_match = FindResult_FoundMatch;
|
|
|
|
}
|
2016-07-18 18:36:53 +00:00
|
|
|
}
|
2017-11-29 23:00:14 +00:00
|
|
|
else{
|
|
|
|
found_match = FindResult_PastEnd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}break;
|
|
|
|
|
|
|
|
case SearchFlag_MatchWordPrefix:
|
|
|
|
{
|
2019-06-01 23:58:28 +00:00
|
|
|
u8 prev = buffer_get_char(app, result.buffer, result.start - 1);
|
|
|
|
if (!character_is_alpha_numeric_unicode(prev)){
|
2019-04-02 20:06:49 +00:00
|
|
|
result.end = buffer_seek_alpha_numeric_end(app, result.buffer, result.start);
|
2017-11-29 23:00:14 +00:00
|
|
|
if (result.end <= end_pos){
|
2016-07-18 18:36:53 +00:00
|
|
|
result.found_match = true;
|
|
|
|
found_match = FindResult_FoundMatch;
|
|
|
|
}
|
2017-11-29 23:00:14 +00:00
|
|
|
else{
|
|
|
|
found_match = FindResult_PastEnd;
|
|
|
|
}
|
2016-07-18 18:36:53 +00:00
|
|
|
}
|
2017-11-29 23:00:14 +00:00
|
|
|
}break;
|
|
|
|
|
|
|
|
case SearchFlag_MatchSubstring:
|
|
|
|
{
|
2019-06-01 23:58:28 +00:00
|
|
|
result.end = result.start + (i32)word.size;
|
2016-07-18 18:36:53 +00:00
|
|
|
if (result.end <= end_pos){
|
2016-07-12 18:20:06 +00:00
|
|
|
result.found_match = true;
|
|
|
|
found_match = FindResult_FoundMatch;
|
|
|
|
}
|
2016-07-18 18:36:53 +00:00
|
|
|
else{
|
|
|
|
found_match = FindResult_PastEnd;
|
|
|
|
}
|
2017-11-29 23:00:14 +00:00
|
|
|
}break;
|
|
|
|
}
|
2016-07-18 18:36:53 +00:00
|
|
|
|
2017-11-29 23:00:14 +00:00
|
|
|
if (found_match == FindResult_FoundMatch){
|
|
|
|
result_code = FindResult_FoundMatch;
|
|
|
|
result.match_word_index = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (found_match == FindResult_PastEnd){
|
|
|
|
result_code = FindResult_PastEnd;
|
|
|
|
}
|
2016-07-12 18:20:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
*result_ptr = result;
|
|
|
|
|
2017-11-29 23:00:14 +00:00
|
|
|
return(result_code);
|
2016-07-12 18:20:06 +00:00
|
|
|
}
|
|
|
|
|
2017-11-29 23:00:14 +00:00
|
|
|
//
|
|
|
|
// Find Next Match
|
|
|
|
//
|
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
static i32
|
|
|
|
search_front_to_back(Application_Links *app, Search_Range *range, Search_Key key, i32 *pos, Search_Match *result){
|
|
|
|
i32 found_match = FindResult_None;
|
2017-11-29 23:00:14 +00:00
|
|
|
for (;found_match == FindResult_None;){
|
|
|
|
found_match = FindResult_None;
|
2016-07-12 18:20:06 +00:00
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
i32 end_pos = range->start + range->size;
|
2017-11-29 23:00:14 +00:00
|
|
|
if (*pos + key.min_size < end_pos){
|
2019-06-01 23:58:28 +00:00
|
|
|
i32 start_pos = *pos;
|
2017-11-29 23:00:14 +00:00
|
|
|
if (start_pos < range->start){
|
|
|
|
start_pos = range->start;
|
|
|
|
}
|
|
|
|
|
|
|
|
seek_potential_match(app, range, key, result, SeekPotentialMatch_Forward, start_pos, end_pos);
|
|
|
|
|
|
|
|
if (result->start < end_pos){
|
|
|
|
*pos = result->start + 1;
|
|
|
|
found_match = match_check(app, range, pos, result, key);
|
|
|
|
if (found_match == FindResult_FoundMatch){
|
|
|
|
*pos = result->end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
found_match = FindResult_PastEnd;
|
|
|
|
*pos = end_pos + 1;
|
2016-07-12 18:20:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
found_match = FindResult_PastEnd;
|
|
|
|
*pos = end_pos + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return(found_match);
|
|
|
|
}
|
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
static i32
|
|
|
|
search_back_to_front(Application_Links *app, Search_Range *range, Search_Key key, i32 *pos, Search_Match *result){
|
|
|
|
i32 found_match = FindResult_None;
|
2016-07-12 18:20:06 +00:00
|
|
|
for (;found_match == FindResult_None;){
|
2017-11-29 23:00:14 +00:00
|
|
|
found_match = FindResult_None;
|
|
|
|
if (*pos > range->start){
|
2019-06-01 23:58:28 +00:00
|
|
|
i32 start_pos = *pos;
|
2017-11-29 23:00:14 +00:00
|
|
|
|
|
|
|
seek_potential_match(app, range, key, result, SeekPotentialMatch_Backward, start_pos, 0);
|
|
|
|
|
|
|
|
if (result->start >= range->start){
|
|
|
|
*pos = result->start - 1;
|
|
|
|
found_match = match_check(app, range, pos, result, key);
|
|
|
|
if (found_match == FindResult_FoundMatch){
|
2019-06-01 23:58:28 +00:00
|
|
|
*pos = result->start - (i32)key.words[result->match_word_index].size;
|
2017-11-29 23:00:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
found_match = FindResult_PastEnd;
|
2016-07-12 18:20:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
found_match = FindResult_PastEnd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return(found_match);
|
|
|
|
}
|
|
|
|
|
2017-11-29 23:00:14 +00:00
|
|
|
static void
|
|
|
|
search_iter_next_range(Search_Iter *it){
|
|
|
|
++it->i;
|
|
|
|
it->pos = 0;
|
|
|
|
it->back_pos = 0;
|
|
|
|
it->range_initialized = 0;
|
2016-07-12 18:20:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static Search_Match
|
|
|
|
search_next_match(Application_Links *app, Search_Set *set, Search_Iter *it_ptr){
|
2018-11-20 08:18:54 +00:00
|
|
|
Search_Match result = {};
|
2016-07-12 18:20:06 +00:00
|
|
|
Search_Iter iter = *it_ptr;
|
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
i32 count = set->count;
|
2017-12-02 18:04:56 +00:00
|
|
|
for (;iter.i < count;){
|
2016-07-12 18:20:06 +00:00
|
|
|
Search_Range *range = set->ranges + iter.i;
|
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
i32 find_result = FindResult_None;
|
2016-07-12 18:20:06 +00:00
|
|
|
|
|
|
|
if (!iter.range_initialized){
|
|
|
|
iter.range_initialized = true;
|
|
|
|
switch (range->type){
|
|
|
|
case SearchRange_BackToFront:
|
|
|
|
{
|
2017-12-02 18:04:56 +00:00
|
|
|
iter.back_pos = range->start + range->size-1;
|
2016-07-12 18:20:06 +00:00
|
|
|
}break;
|
|
|
|
|
|
|
|
case SearchRange_Wave:
|
|
|
|
{
|
|
|
|
iter.back_pos = range->mid_start-1;
|
|
|
|
iter.pos = range->mid_start + range->mid_size;
|
|
|
|
}break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (range->type){
|
|
|
|
case SearchRange_FrontToBack:
|
|
|
|
{
|
2017-11-29 23:00:14 +00:00
|
|
|
find_result = search_front_to_back(app, range, iter.key, &iter.pos, &result);
|
2016-07-12 18:20:06 +00:00
|
|
|
}break;
|
|
|
|
|
|
|
|
case SearchRange_BackToFront:
|
|
|
|
{
|
2017-11-29 23:00:14 +00:00
|
|
|
find_result = search_back_to_front(app, range, iter.key, &iter.back_pos, &result);
|
2016-07-12 18:20:06 +00:00
|
|
|
}break;
|
|
|
|
|
|
|
|
case SearchRange_Wave:
|
|
|
|
{
|
2018-11-20 08:18:54 +00:00
|
|
|
Search_Match forward_match = {};
|
|
|
|
Search_Match backward_match = {};
|
2016-07-12 18:20:06 +00:00
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
i32 forward_result = FindResult_PastEnd;
|
|
|
|
i32 backward_result = FindResult_PastEnd;
|
2016-07-12 18:20:06 +00:00
|
|
|
|
|
|
|
if (iter.pos < range->start + range->size){
|
2017-11-29 23:00:14 +00:00
|
|
|
forward_result = search_front_to_back(app, range, iter.key, &iter.pos, &forward_match);
|
2016-07-12 18:20:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (iter.back_pos > range->start){
|
2017-11-29 23:00:14 +00:00
|
|
|
backward_result = search_back_to_front(app, range, iter.key, &iter.back_pos, &backward_match);
|
2016-07-12 18:20:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (forward_result == FindResult_FoundMatch){
|
|
|
|
if (backward_result == FindResult_FoundMatch){
|
|
|
|
find_result = FindResult_FoundMatch;
|
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
i32 forward_start = range->mid_start + range->mid_size;
|
|
|
|
i32 forward_distance = (forward_match.start - forward_start);
|
|
|
|
i32 backward_distance = (range->mid_start - backward_match.end);
|
2016-07-12 18:20:06 +00:00
|
|
|
|
|
|
|
if (backward_distance < forward_distance){
|
|
|
|
iter.pos = forward_match.start;
|
|
|
|
result = backward_match;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
iter.back_pos = backward_match.start;
|
|
|
|
result = forward_match;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
find_result = FindResult_FoundMatch;
|
|
|
|
result = forward_match;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
if (backward_result == FindResult_FoundMatch){
|
|
|
|
find_result = FindResult_FoundMatch;
|
|
|
|
result = backward_match;
|
|
|
|
--iter.pos;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
find_result = FindResult_PastEnd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (find_result == FindResult_FoundMatch){
|
|
|
|
goto double_break;
|
|
|
|
}
|
|
|
|
else if (find_result == FindResult_PastEnd){
|
|
|
|
search_iter_next_range(&iter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
double_break:;
|
|
|
|
|
|
|
|
*it_ptr = iter;
|
|
|
|
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
|
2017-01-23 06:19:43 +00:00
|
|
|
//
|
|
|
|
// Generic Search All Buffers
|
|
|
|
//
|
|
|
|
|
|
|
|
static void
|
2019-06-01 23:58:28 +00:00
|
|
|
initialize_generic_search_all_buffers(Application_Links *app, Heap *heap, String_Const_u8 *strings, i32 count, Search_Range_Flag match_flags, Buffer_ID *skip_buffers, i32 skip_buffer_count, Search_Set *set, Search_Iter *iter){
|
|
|
|
block_zero_struct(set);
|
|
|
|
block_zero_struct(iter);
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2018-11-20 08:18:54 +00:00
|
|
|
Search_Key key = {};
|
2019-06-01 23:58:28 +00:00
|
|
|
umem sizes[ArrayCount(key.words)] = {};
|
|
|
|
count = clamp_top(count, ArrayCount(key.words));
|
2019-04-02 20:06:49 +00:00
|
|
|
for (i32 i = 0; i < count; ++i){
|
2017-11-29 23:00:14 +00:00
|
|
|
sizes[i] = strings[i].size;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(allen): Why on earth am I allocating these separately in this case? Upgrade to just use the string array on the stack!
|
2019-06-01 23:58:28 +00:00
|
|
|
// NOTE(allen): ?? What did that TODO mean!?
|
2018-08-18 08:16:52 +00:00
|
|
|
search_key_alloc(heap, &key, sizes, count);
|
2019-04-02 20:06:49 +00:00
|
|
|
for (i32 i = 0; i < count; ++i){
|
2019-06-01 23:58:28 +00:00
|
|
|
key.words[i].size = strings[i].size;
|
|
|
|
block_copy(key.words[i].str, strings[i].str, strings[i].size);
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
|
|
|
|
2017-11-29 23:00:14 +00:00
|
|
|
search_iter_init(iter, key);
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2019-04-02 20:06:49 +00:00
|
|
|
i32 buffer_count = get_buffer_count(app);
|
2018-08-18 08:16:52 +00:00
|
|
|
search_set_init(heap, set, buffer_count);
|
2017-11-29 23:00:14 +00:00
|
|
|
|
|
|
|
Search_Range *ranges = set->ranges;
|
|
|
|
|
2019-04-02 20:06:49 +00:00
|
|
|
View_ID view = 0;
|
|
|
|
get_active_view(app, AccessProtected, &view);
|
|
|
|
Buffer_ID buffer = 0;
|
|
|
|
view_get_buffer(app, view, AccessProtected, &buffer);
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2019-04-02 20:06:49 +00:00
|
|
|
i32 j = 0;
|
|
|
|
if (buffer_exists(app, buffer)){
|
2019-02-26 23:08:42 +00:00
|
|
|
b32 skip = false;
|
2019-04-02 20:06:49 +00:00
|
|
|
for (i32 i = 0; i < skip_buffer_count; ++i){
|
|
|
|
if (buffer == skip_buffers[i]){
|
2017-11-29 23:00:14 +00:00
|
|
|
skip = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!skip){
|
2017-12-02 18:04:56 +00:00
|
|
|
ranges[j].type = SearchRange_FrontToBack;
|
|
|
|
ranges[j].flags = match_flags;
|
2019-04-02 20:06:49 +00:00
|
|
|
ranges[j].buffer = buffer;
|
2017-12-02 18:04:56 +00:00
|
|
|
ranges[j].start = 0;
|
2019-04-02 20:06:49 +00:00
|
|
|
buffer_get_size(app, buffer, &ranges[j].size);
|
2017-12-02 18:04:56 +00:00
|
|
|
++j;
|
2017-11-29 23:00:14 +00:00
|
|
|
}
|
|
|
|
}
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2019-04-02 20:06:49 +00:00
|
|
|
Buffer_ID buffer_it = 0;
|
|
|
|
for (get_buffer_next(app, 0, AccessAll, &buffer_it);
|
|
|
|
buffer_exists(app, buffer_it);
|
|
|
|
get_buffer_next(app, buffer_it, AccessAll, &buffer_it)){
|
|
|
|
if (buffer_it == buffer){
|
2017-12-02 18:04:56 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-02-26 23:08:42 +00:00
|
|
|
b32 skip = false;
|
2019-04-02 20:06:49 +00:00
|
|
|
for (i32 i = 0; i < skip_buffer_count; ++i){
|
|
|
|
if (buffer_it == skip_buffers[i]){
|
2017-12-02 18:04:56 +00:00
|
|
|
skip = true;
|
|
|
|
break;
|
2017-11-29 23:00:14 +00:00
|
|
|
}
|
2017-12-02 18:04:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!skip){
|
2019-04-05 02:03:36 +00:00
|
|
|
if (!buffer_has_name_with_star(app, buffer_it)){
|
2017-12-02 18:04:56 +00:00
|
|
|
ranges[j].type = SearchRange_FrontToBack;
|
|
|
|
ranges[j].flags = match_flags;
|
2019-04-02 20:06:49 +00:00
|
|
|
ranges[j].buffer = buffer_it;
|
2017-12-02 18:04:56 +00:00
|
|
|
ranges[j].start = 0;
|
2019-04-02 20:06:49 +00:00
|
|
|
buffer_get_size(app, buffer_it, &ranges[j].size);
|
2017-12-02 18:04:56 +00:00
|
|
|
++j;
|
2017-11-29 23:00:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-12-02 18:04:56 +00:00
|
|
|
|
2017-11-29 23:00:14 +00:00
|
|
|
set->count = j;
|
|
|
|
}
|
|
|
|
|
2018-05-11 20:46:26 +00:00
|
|
|
////////////////////////////////
|
2017-11-29 23:00:14 +00:00
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
static String_Const_u8 search_name = string_u8_litexpr("*search*");
|
2019-04-02 20:06:49 +00:00
|
|
|
|
2017-11-29 23:00:14 +00:00
|
|
|
static void
|
2019-06-01 23:58:28 +00:00
|
|
|
list__parameters_buffer(Application_Links *app, Heap *heap,
|
|
|
|
String_Const_u8 *strings, i32 count, Search_Range_Flag match_flags,
|
2019-02-24 07:22:16 +00:00
|
|
|
Buffer_ID search_buffer_id){
|
2019-06-01 23:58:28 +00:00
|
|
|
Arena *scratch = context_get_arena(app);
|
|
|
|
|
2019-04-01 03:05:48 +00:00
|
|
|
// Setup the search buffer for 'init' mode
|
2019-04-02 20:06:49 +00:00
|
|
|
buffer_set_setting(app, search_buffer_id, BufferSetting_ReadOnly, true);
|
|
|
|
buffer_set_setting(app, search_buffer_id, BufferSetting_RecordsHistory, false);
|
2019-02-12 03:03:49 +00:00
|
|
|
|
2017-11-29 23:00:14 +00:00
|
|
|
// Initialize a generic search all buffers
|
2018-11-20 08:18:54 +00:00
|
|
|
Search_Set set = {};
|
|
|
|
Search_Iter iter = {};
|
2019-04-02 20:06:49 +00:00
|
|
|
initialize_generic_search_all_buffers(app, heap, strings, count, match_flags, &search_buffer_id, 1, &set, &iter);
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2017-11-29 23:00:14 +00:00
|
|
|
// List all locations into search buffer
|
2019-06-01 23:58:28 +00:00
|
|
|
Temp_Memory all_temp = begin_temp(scratch);
|
2019-02-22 12:43:12 +00:00
|
|
|
|
2019-04-02 20:06:49 +00:00
|
|
|
// Setup buffered output
|
2019-06-01 23:58:28 +00:00
|
|
|
Cursor buffering_cursor = make_cursor(push_array(scratch, u8, KB(64)), KB(64));
|
|
|
|
Buffer_Insertion out = begin_buffer_insertion_at_buffered(app, search_buffer_id, 0, &buffering_cursor);
|
|
|
|
|
2019-04-02 20:06:49 +00:00
|
|
|
|
2018-09-07 22:39:33 +00:00
|
|
|
Buffer_ID prev_match_id = 0;
|
2019-02-26 23:08:42 +00:00
|
|
|
b32 no_matches = true;
|
2017-11-29 23:00:14 +00:00
|
|
|
for (Search_Match match = search_next_match(app, &set, &iter);
|
|
|
|
match.found_match;
|
|
|
|
match = search_next_match(app, &set, &iter)){
|
2018-11-20 08:18:54 +00:00
|
|
|
Partial_Cursor word_pos = {};
|
2019-04-02 20:06:49 +00:00
|
|
|
if (buffer_compute_cursor(app, match.buffer, seek_pos(match.start), &word_pos)){
|
|
|
|
if (prev_match_id != match.buffer){
|
2018-09-07 22:39:33 +00:00
|
|
|
if (prev_match_id != 0){
|
2019-06-01 23:58:28 +00:00
|
|
|
insertc(&out, '\n');
|
2018-09-07 22:39:33 +00:00
|
|
|
}
|
2019-04-02 20:06:49 +00:00
|
|
|
prev_match_id = match.buffer;
|
2018-09-07 22:39:33 +00:00
|
|
|
}
|
2019-02-22 12:43:12 +00:00
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
Temp_Memory line_temp = begin_temp(scratch);
|
2019-06-02 03:07:57 +00:00
|
|
|
String_Const_u8 file_name = push_buffer_file_name(app, scratch, match.buffer);
|
|
|
|
String_Const_u8 full_line_str = push_buffer_line(app, scratch, match.buffer, word_pos.line);
|
2019-06-01 23:58:28 +00:00
|
|
|
if (full_line_str.size > 0){
|
|
|
|
String_Const_u8 line_str = string_skip_chop_whitespace(full_line_str);
|
|
|
|
insertf(&out, "%.*s:%d:%d: %.*s\n", string_expand(file_name), word_pos.line, word_pos.character, string_expand(line_str));
|
2019-02-22 12:43:12 +00:00
|
|
|
}
|
2019-06-01 23:58:28 +00:00
|
|
|
end_temp(line_temp);
|
2019-02-22 12:43:12 +00:00
|
|
|
|
2018-09-07 22:39:33 +00:00
|
|
|
no_matches = false;
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-07 22:39:33 +00:00
|
|
|
if (no_matches){
|
2019-06-01 23:58:28 +00:00
|
|
|
insert_string(&out, string_u8_litexpr("no matches\n"));
|
2018-09-07 22:39:33 +00:00
|
|
|
}
|
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
end_buffer_insertion(&out);
|
2019-02-22 12:43:12 +00:00
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
end_temp(all_temp);
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2018-09-08 01:36:42 +00:00
|
|
|
// Lock *search* as the jump buffer
|
2019-06-01 23:58:28 +00:00
|
|
|
lock_jump_buffer(search_name);
|
2019-02-24 07:22:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-06-01 23:58:28 +00:00
|
|
|
list__parameters(Application_Links *app, Heap *heap, String_Const_u8 *strings, i32 count, Search_Range_Flag match_flags, View_ID default_target_view){
|
2019-02-24 07:22:16 +00:00
|
|
|
// Open the search buffer
|
2019-06-01 23:58:28 +00:00
|
|
|
Buffer_ID search_buffer_id = create_or_switch_to_buffer_and_clear_by_name(app, search_name, default_target_view);
|
|
|
|
list__parameters_buffer(app, heap, strings, count, match_flags, search_buffer_id);
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
|
|
|
|
2018-05-11 20:46:26 +00:00
|
|
|
static void
|
2019-06-01 23:58:28 +00:00
|
|
|
list_single__parameters(Application_Links *app, Heap *heap, String_Const_u8 str, b32 substrings, b32 case_insensitive, View_ID default_target_view){
|
2018-05-11 20:46:26 +00:00
|
|
|
Search_Range_Flag flags = 0;
|
|
|
|
if (substrings){
|
|
|
|
flags |= SearchFlag_MatchSubstring;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
flags |= SearchFlag_MatchWholeWord;
|
|
|
|
}
|
|
|
|
if (case_insensitive){
|
|
|
|
flags |= SearchFlag_CaseInsensitive;
|
|
|
|
}
|
2019-06-01 23:58:28 +00:00
|
|
|
list__parameters(app, heap, &str, 1, flags, default_target_view);
|
2018-05-11 20:46:26 +00:00
|
|
|
}
|
2017-11-29 23:00:14 +00:00
|
|
|
|
2018-05-11 20:46:26 +00:00
|
|
|
static void
|
2019-06-01 23:58:28 +00:00
|
|
|
list_query__parameters(Application_Links *app, Heap *heap, b32 substrings, b32 case_insensitive, View_ID default_target_view){
|
2018-05-11 20:46:26 +00:00
|
|
|
char space[1024];
|
2019-06-01 23:58:28 +00:00
|
|
|
String_Const_u8 str = get_query_string(app, "List Locations For: ", space, sizeof(space));
|
2018-09-07 22:39:33 +00:00
|
|
|
if (str.size > 0){
|
2019-06-01 23:58:28 +00:00
|
|
|
list_single__parameters(app, heap, str, substrings, case_insensitive, default_target_view);
|
2018-05-11 20:46:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-06-01 23:58:28 +00:00
|
|
|
list_identifier__parameters(Application_Links *app, Heap *heap, b32 substrings, b32 case_insensitive, View_ID default_target_view){
|
2019-04-07 17:36:24 +00:00
|
|
|
View_ID view = 0;
|
|
|
|
get_active_view(app, AccessProtected, &view);
|
2019-04-04 08:25:16 +00:00
|
|
|
Buffer_ID buffer = 0;
|
2019-04-07 17:36:24 +00:00
|
|
|
view_get_buffer(app, view, AccessProtected, &buffer);
|
|
|
|
if (buffer != 0){
|
|
|
|
i32 pos = 0;
|
|
|
|
view_get_cursor_pos(app, view, &pos);
|
2019-06-01 23:58:28 +00:00
|
|
|
Scratch_Block scratch(app);
|
|
|
|
String_Const_u8 str = get_token_or_word_under_pos(app, scratch, buffer, pos);
|
2019-04-04 08:25:16 +00:00
|
|
|
if (str.size > 0){
|
2019-06-01 23:58:28 +00:00
|
|
|
list_single__parameters(app, heap, str, substrings, case_insensitive, default_target_view);
|
2019-04-04 08:25:16 +00:00
|
|
|
}
|
2018-05-11 20:46:26 +00:00
|
|
|
}
|
|
|
|
}
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2017-11-29 23:00:14 +00:00
|
|
|
static void
|
2019-06-01 23:58:28 +00:00
|
|
|
list_selected_range__parameters(Application_Links *app, Heap *heap, b32 substrings, b32 case_insensitive, View_ID default_target_view){
|
2019-04-07 17:36:24 +00:00
|
|
|
View_ID view = 0;
|
|
|
|
get_active_view(app, AccessProtected, &view);
|
2019-06-01 23:58:28 +00:00
|
|
|
Arena *scratch = context_get_arena(app);
|
|
|
|
Temp_Memory temp = begin_temp(scratch);
|
2019-06-02 03:07:57 +00:00
|
|
|
String_Const_u8 str = push_string_in_view_range(app, scratch, view);
|
2018-09-07 22:39:33 +00:00
|
|
|
if (str.size > 0){
|
2019-06-01 23:58:28 +00:00
|
|
|
list_single__parameters(app, heap, str, substrings, case_insensitive, default_target_view);
|
2018-05-11 20:46:26 +00:00
|
|
|
}
|
2019-06-01 23:58:28 +00:00
|
|
|
end_temp(temp);
|
2018-05-11 20:46:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-06-01 23:58:28 +00:00
|
|
|
list_type_definition__parameters(Application_Links *app, Heap *heap, String_Const_u8 str, View_ID default_target_view){
|
|
|
|
Arena *scratch = context_get_arena(app);
|
|
|
|
Temp_Memory temp = begin_temp(scratch);
|
2018-05-11 20:46:26 +00:00
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
String_Const_u8 match_strings[9];
|
2019-04-02 20:06:49 +00:00
|
|
|
i32 i = 0;
|
2019-06-01 23:58:28 +00:00
|
|
|
match_strings[i++] = (string_u8_pushf(scratch, "struct %.*s{" , string_expand(str)));
|
|
|
|
match_strings[i++] = (string_u8_pushf(scratch, "struct %.*s\n{", string_expand(str)));
|
|
|
|
match_strings[i++] = (string_u8_pushf(scratch, "struct %.*s {" , string_expand(str)));
|
|
|
|
match_strings[i++] = (string_u8_pushf(scratch, "union %.*s{" , string_expand(str)));
|
|
|
|
match_strings[i++] = (string_u8_pushf(scratch, "union %.*s\n{" , string_expand(str)));
|
|
|
|
match_strings[i++] = (string_u8_pushf(scratch, "union %.*s {" , string_expand(str)));
|
|
|
|
match_strings[i++] = (string_u8_pushf(scratch, "enum %.*s{" , string_expand(str)));
|
|
|
|
match_strings[i++] = (string_u8_pushf(scratch, "enum %.*s\n{" , string_expand(str)));
|
|
|
|
match_strings[i++] = (string_u8_pushf(scratch, "enum %.*s {" , string_expand(str)));
|
2018-05-11 20:46:26 +00:00
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
list__parameters(app, heap, match_strings, ArrayCount(match_strings), 0, default_target_view);
|
2017-11-29 23:00:14 +00:00
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
end_temp(temp);
|
2017-11-29 23:00:14 +00:00
|
|
|
}
|
|
|
|
|
2018-05-11 20:46:26 +00:00
|
|
|
////////////////////////////////
|
|
|
|
|
2017-11-15 23:57:21 +00:00
|
|
|
CUSTOM_COMMAND_SIG(list_all_locations)
|
|
|
|
CUSTOM_DOC("Queries the user for a string and lists all exact case-sensitive matches found in all open buffers.")
|
|
|
|
{
|
2019-04-07 17:36:24 +00:00
|
|
|
View_ID target_view = get_next_view_after_active(app, AccessAll);
|
2019-06-01 23:58:28 +00:00
|
|
|
list_query__parameters(app, &global_heap, false, false, target_view);
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
|
|
|
|
2017-11-15 23:57:21 +00:00
|
|
|
CUSTOM_COMMAND_SIG(list_all_substring_locations)
|
|
|
|
CUSTOM_DOC("Queries the user for a string and lists all case-sensitive substring matches found in all open buffers.")
|
|
|
|
{
|
2019-04-07 17:36:24 +00:00
|
|
|
View_ID target_view = get_next_view_after_active(app, AccessAll);
|
2019-06-01 23:58:28 +00:00
|
|
|
list_query__parameters(app, &global_heap, true, false, target_view);
|
2018-05-26 07:49:37 +00:00
|
|
|
}
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2017-11-15 23:57:21 +00:00
|
|
|
CUSTOM_COMMAND_SIG(list_all_locations_case_insensitive)
|
|
|
|
CUSTOM_DOC("Queries the user for a string and lists all exact case-insensitive matches found in all open buffers.")
|
|
|
|
{
|
2019-04-07 17:36:24 +00:00
|
|
|
View_ID target_view = get_next_view_after_active(app, AccessAll);
|
2019-06-01 23:58:28 +00:00
|
|
|
list_query__parameters(app, &global_heap, false, true, target_view);
|
2018-05-26 07:49:37 +00:00
|
|
|
}
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2017-11-15 23:57:21 +00:00
|
|
|
CUSTOM_COMMAND_SIG(list_all_substring_locations_case_insensitive)
|
|
|
|
CUSTOM_DOC("Queries the user for a string and lists all case-insensitive substring matches found in all open buffers.")
|
|
|
|
{
|
2019-04-07 17:36:24 +00:00
|
|
|
View_ID target_view = get_next_view_after_active(app, AccessAll);
|
2019-06-01 23:58:28 +00:00
|
|
|
list_query__parameters(app, &global_heap, true, true, target_view);
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
|
|
|
|
2017-11-15 23:57:21 +00:00
|
|
|
CUSTOM_COMMAND_SIG(list_all_locations_of_identifier)
|
|
|
|
CUSTOM_DOC("Reads a token or word under the cursor and lists all exact case-sensitive mathces in all open buffers.")
|
|
|
|
{
|
2019-04-07 17:36:24 +00:00
|
|
|
View_ID target_view = get_next_view_after_active(app, AccessAll);
|
2019-06-01 23:58:28 +00:00
|
|
|
list_identifier__parameters(app, &global_heap, false, false, target_view);
|
2017-02-12 23:04:50 +00:00
|
|
|
}
|
|
|
|
|
2017-11-15 23:57:21 +00:00
|
|
|
CUSTOM_COMMAND_SIG(list_all_locations_of_identifier_case_insensitive)
|
|
|
|
CUSTOM_DOC("Reads a token or word under the cursor and lists all exact case-insensitive mathces in all open buffers.")
|
|
|
|
{
|
2019-04-07 17:36:24 +00:00
|
|
|
View_ID target_view = get_next_view_after_active(app, AccessAll);
|
2019-06-01 23:58:28 +00:00
|
|
|
list_identifier__parameters(app, &global_heap, false, true, target_view);
|
2017-11-21 18:25:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CUSTOM_COMMAND_SIG(list_all_locations_of_selection)
|
|
|
|
CUSTOM_DOC("Reads the string in the selected range and lists all exact case-sensitive mathces in all open buffers.")
|
|
|
|
{
|
2019-04-07 17:36:24 +00:00
|
|
|
View_ID target_view = get_next_view_after_active(app, AccessAll);
|
2019-06-01 23:58:28 +00:00
|
|
|
list_selected_range__parameters(app, &global_heap, false, false, target_view);
|
2017-11-21 18:25:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CUSTOM_COMMAND_SIG(list_all_locations_of_selection_case_insensitive)
|
|
|
|
CUSTOM_DOC("Reads the string in the selected range and lists all exact case-insensitive mathces in all open buffers.")
|
|
|
|
{
|
2019-04-07 17:36:24 +00:00
|
|
|
View_ID target_view = get_next_view_after_active(app, AccessAll);
|
2019-06-01 23:58:28 +00:00
|
|
|
list_selected_range__parameters(app, &global_heap, false, true, target_view);
|
2018-05-11 20:46:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CUSTOM_COMMAND_SIG(list_all_locations_of_type_definition)
|
|
|
|
CUSTOM_DOC("Queries user for string, lists all locations of strings that appear to define a type whose name matches the input string.")
|
|
|
|
{
|
|
|
|
char space[1024];
|
2019-06-01 23:58:28 +00:00
|
|
|
String_Const_u8 str = get_query_string(app, "List Definitions For: ", space, sizeof(space));
|
2018-09-07 22:39:33 +00:00
|
|
|
if (str.size > 0){
|
2019-04-07 17:36:24 +00:00
|
|
|
View_ID target_view = get_next_view_after_active(app, AccessAll);
|
2019-06-01 23:58:28 +00:00
|
|
|
list_type_definition__parameters(app, &global_heap, str, target_view);
|
2018-05-26 07:49:37 +00:00
|
|
|
}
|
2018-05-11 20:46:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CUSTOM_COMMAND_SIG(list_all_locations_of_type_definition_of_identifier)
|
|
|
|
CUSTOM_DOC("Reads a token or word under the cursor and lists all locations of strings that appear to define a type whose name matches it.")
|
|
|
|
{
|
2019-04-07 17:36:24 +00:00
|
|
|
View_ID target_view = 0;
|
|
|
|
get_active_view(app, AccessProtected, &target_view);
|
2019-04-04 08:25:16 +00:00
|
|
|
Buffer_ID buffer = 0;
|
2019-04-07 17:36:24 +00:00
|
|
|
view_get_buffer(app, target_view, AccessProtected, &buffer);
|
|
|
|
i32 pos = 0;
|
|
|
|
view_get_cursor_pos(app, target_view, &pos);
|
2019-06-01 23:58:28 +00:00
|
|
|
Scratch_Block scratch(app);
|
|
|
|
String_Const_u8 str = get_token_or_word_under_pos(app, scratch, buffer, pos);
|
2018-09-07 22:39:33 +00:00
|
|
|
if (str.size > 0){
|
2019-04-07 17:36:24 +00:00
|
|
|
target_view = get_next_view_after_active(app, AccessAll);
|
2019-06-01 23:58:28 +00:00
|
|
|
list_type_definition__parameters(app, &global_heap, str, target_view);
|
2018-05-11 20:46:26 +00:00
|
|
|
}
|
2017-11-21 18:25:19 +00:00
|
|
|
}
|
|
|
|
|
2017-11-29 23:00:14 +00:00
|
|
|
|
2017-01-23 06:19:43 +00:00
|
|
|
//
|
|
|
|
// Word Complete Command
|
|
|
|
//
|
|
|
|
|
2018-11-20 08:18:54 +00:00
|
|
|
static Word_Complete_State complete_state = {};
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2017-11-15 23:57:21 +00:00
|
|
|
CUSTOM_COMMAND_SIG(word_complete)
|
|
|
|
CUSTOM_DOC("Iteratively tries completing the word to the left of the cursor with other words in open buffers that have the same prefix string.")
|
|
|
|
{
|
2019-04-07 17:36:24 +00:00
|
|
|
View_ID view = 0;
|
|
|
|
get_active_view(app, AccessOpen, &view);
|
2019-04-05 02:03:36 +00:00
|
|
|
Buffer_ID buffer = 0;
|
2019-04-07 17:36:24 +00:00
|
|
|
if (view_get_buffer(app, view, AccessOpen, &buffer)){
|
2019-04-02 20:06:49 +00:00
|
|
|
i32 do_init = false;
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
Managed_Scope scope = 0;
|
|
|
|
view_get_managed_scope(app, view, &scope);
|
2018-08-11 00:42:15 +00:00
|
|
|
|
2019-02-27 05:49:35 +00:00
|
|
|
u64 rewrite = 0;
|
2018-09-07 22:39:33 +00:00
|
|
|
managed_variable_get(app, scope, view_rewrite_loc, &rewrite);
|
2018-06-23 03:03:58 +00:00
|
|
|
if (rewrite != RewriteWordComplete){
|
2017-01-23 06:19:43 +00:00
|
|
|
do_init = true;
|
|
|
|
}
|
2018-09-07 22:39:33 +00:00
|
|
|
managed_variable_set(app, scope, view_next_rewrite_loc, RewriteWordComplete);
|
2017-01-23 06:19:43 +00:00
|
|
|
if (!complete_state.initialized){
|
|
|
|
do_init = true;
|
|
|
|
}
|
|
|
|
|
2019-04-02 20:06:49 +00:00
|
|
|
i32 word_end = 0;
|
|
|
|
i32 word_start = 0;
|
|
|
|
i32 cursor_pos = 0;
|
2019-06-01 23:58:28 +00:00
|
|
|
umem size = 0;
|
2017-01-23 06:19:43 +00:00
|
|
|
|
|
|
|
if (do_init){
|
2017-03-23 19:15:33 +00:00
|
|
|
// NOTE(allen): Get the range where the
|
|
|
|
// partial word is written.
|
2019-04-07 17:36:24 +00:00
|
|
|
word_end = 0;
|
|
|
|
view_get_cursor_pos(app, view, &word_end);
|
2017-01-23 06:19:43 +00:00
|
|
|
word_start = word_end;
|
|
|
|
cursor_pos = word_end - 1;
|
|
|
|
|
|
|
|
char space[1024];
|
2018-11-20 08:18:54 +00:00
|
|
|
Stream_Chunk chunk = {};
|
2019-04-05 02:03:36 +00:00
|
|
|
if (init_stream_chunk(&chunk, app, buffer, cursor_pos, space, sizeof(space))){
|
2019-04-02 20:06:49 +00:00
|
|
|
i32 still_looping = true;
|
2017-01-23 06:19:43 +00:00
|
|
|
do{
|
2017-03-23 19:15:33 +00:00
|
|
|
for (; cursor_pos >= chunk.start; --cursor_pos){
|
2019-06-01 23:58:28 +00:00
|
|
|
u8 c = chunk.data[cursor_pos];
|
|
|
|
if (character_is_alpha_unicode(c)){
|
2017-01-23 06:19:43 +00:00
|
|
|
word_start = cursor_pos;
|
|
|
|
}
|
2019-06-01 23:58:28 +00:00
|
|
|
else if (!character_is_base10(c)){
|
2017-01-23 06:19:43 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-11-29 23:00:14 +00:00
|
|
|
// NOTE(allen): Initialize the search iterator with the partial word.
|
2017-01-23 06:19:43 +00:00
|
|
|
complete_state.initialized = true;
|
2018-11-20 08:18:54 +00:00
|
|
|
Search_Key key = {};
|
2018-08-18 08:16:52 +00:00
|
|
|
search_key_alloc(&global_heap, &key, &size, 1);
|
2019-06-01 23:58:28 +00:00
|
|
|
buffer_read_range(app, buffer, word_start, word_end, (char*)key.words[0].str);
|
2017-11-29 23:00:14 +00:00
|
|
|
key.words[0].size = size;
|
|
|
|
|
|
|
|
search_iter_init(&complete_state.iter, key);
|
2017-01-23 06:19:43 +00:00
|
|
|
|
|
|
|
// NOTE(allen): Initialize the set of ranges to be searched.
|
2019-04-02 20:06:49 +00:00
|
|
|
i32 buffer_count = get_buffer_count(app);
|
2018-08-18 08:16:52 +00:00
|
|
|
search_set_init(&global_heap, &complete_state.set, buffer_count);
|
2017-01-23 06:19:43 +00:00
|
|
|
|
|
|
|
Search_Range *ranges = complete_state.set.ranges;
|
|
|
|
ranges[0].type = SearchRange_Wave;
|
|
|
|
ranges[0].flags = SearchFlag_MatchWordPrefix;
|
2019-04-05 02:03:36 +00:00
|
|
|
ranges[0].buffer = buffer;
|
2017-01-23 06:19:43 +00:00
|
|
|
ranges[0].start = 0;
|
2019-04-05 02:03:36 +00:00
|
|
|
buffer_get_size(app, buffer, &ranges[0].size);
|
2017-01-23 06:19:43 +00:00
|
|
|
ranges[0].mid_start = word_start;
|
2019-06-01 23:58:28 +00:00
|
|
|
ranges[0].mid_size = (i32)size;
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2019-04-05 02:03:36 +00:00
|
|
|
Buffer_ID buffer_it = 0;
|
|
|
|
|
2019-04-02 20:06:49 +00:00
|
|
|
i32 j = 1;
|
2019-04-05 02:03:36 +00:00
|
|
|
for (get_buffer_next(app, 0, AccessAll, &buffer_it);
|
|
|
|
buffer_it != 0;
|
|
|
|
get_buffer_next(app, buffer_it, AccessAll, &buffer_it)){
|
|
|
|
if (buffer != buffer_it){
|
2017-01-23 06:19:43 +00:00
|
|
|
ranges[j].type = SearchRange_FrontToBack;
|
|
|
|
ranges[j].flags = SearchFlag_MatchWordPrefix;
|
2019-04-05 02:03:36 +00:00
|
|
|
ranges[j].buffer = buffer_it;
|
2017-01-23 06:19:43 +00:00
|
|
|
ranges[j].start = 0;
|
2019-04-05 02:03:36 +00:00
|
|
|
buffer_get_size(app, buffer_it, &ranges[j].size);
|
2017-01-23 06:19:43 +00:00
|
|
|
++j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
complete_state.set.count = j;
|
|
|
|
|
|
|
|
// NOTE(allen): Initialize the search hit table.
|
2018-08-18 08:16:52 +00:00
|
|
|
search_hits_init(&global_heap, &complete_state.hits, &complete_state.str, 100, (4 << 10));
|
2019-06-01 23:58:28 +00:00
|
|
|
String_Const_u8 word = complete_state.iter.key.words[0];
|
|
|
|
search_hit_add(&global_heap, &complete_state.hits, &complete_state.str, word);
|
2017-01-23 06:19:43 +00:00
|
|
|
|
|
|
|
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;
|
2019-06-01 23:58:28 +00:00
|
|
|
size = (i32)complete_state.iter.key.words[0].size;
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE(allen): Iterate through matches.
|
|
|
|
if (size > 0){
|
|
|
|
for (;;){
|
2019-04-02 20:06:49 +00:00
|
|
|
i32 match_size = 0;
|
2017-11-29 23:00:14 +00:00
|
|
|
Search_Match match = search_next_match(app, &complete_state.set, &complete_state.iter);
|
2017-01-23 06:19:43 +00:00
|
|
|
|
|
|
|
if (match.found_match){
|
2017-03-23 19:15:33 +00:00
|
|
|
match_size = match.end - match.start;
|
2019-06-01 23:58:28 +00:00
|
|
|
Arena *scratch = context_get_arena(app);
|
|
|
|
Scratch_Block temp_auto_closer(scratch);
|
|
|
|
char *spare = push_array(scratch, char, match_size);
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2019-04-02 20:06:49 +00:00
|
|
|
buffer_read_range(app, match.buffer, match.start, match.end, spare);
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2018-08-18 08:16:52 +00:00
|
|
|
if (search_hit_add(&global_heap, &complete_state.hits, &complete_state.str, spare, match_size)){
|
2019-06-01 23:58:28 +00:00
|
|
|
buffer_replace_range(app, buffer, make_range(word_start, word_end), SCu8(spare, match_size));
|
2019-04-07 17:36:24 +00:00
|
|
|
view_set_cursor(app, view, seek_pos(word_start + match_size), true);
|
2017-01-23 06:19:43 +00:00
|
|
|
|
|
|
|
complete_state.word_end = word_start + match_size;
|
|
|
|
complete_state.set.ranges[0].mid_size = match_size;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
complete_state.iter.pos = 0;
|
|
|
|
complete_state.iter.i = 0;
|
|
|
|
|
2018-08-18 08:16:52 +00:00
|
|
|
search_hits_init(&global_heap, &complete_state.hits, &complete_state.str, 100, (4 << 10));
|
2019-06-01 23:58:28 +00:00
|
|
|
String_Const_u8 word = complete_state.iter.key.words[0];
|
|
|
|
search_hit_add(&global_heap, &complete_state.hits, &complete_state.str, word);
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
match_size = (i32)word.size;
|
|
|
|
buffer_replace_range(app, buffer, make_range(word_start, word_end), word);
|
2019-04-07 17:36:24 +00:00
|
|
|
view_set_cursor(app, view, seek_pos(word_start + match_size), true);
|
2017-01-23 06:19:43 +00:00
|
|
|
|
|
|
|
complete_state.word_end = word_start + match_size;
|
|
|
|
complete_state.set.ranges[0].mid_size = match_size;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// BOTTOM
|
|
|
|
|