1049 lines
38 KiB
C++
1049 lines
38 KiB
C++
|
/*
|
||
|
// YEET SHEET. By Luke Perkin. luke@locogame.co.uk
|
||
|
// Header comment last edited 21st 03/2021
|
||
|
//
|
||
|
// "yeet" regions of text into a seperate buffer called a "yeet sheet".
|
||
|
// The yeet sheet will be kept in sync with any text changes.
|
||
|
// This allows you to have multiple portals into various files in your codebase.
|
||
|
//
|
||
|
// == IMPLEMENTATION ==
|
||
|
// @include "4coder_loco_yeets.cpp" in your custom layer.
|
||
|
//
|
||
|
// > loco_render_buffer(Application_Links *app, View_ID view_id, Face_ID face_id, Buffer_ID buffer, Text_Layout_ID text_layout_id, Rect_f32 rect, Frame_Info frame_info)
|
||
|
// Call this is your custom layer's "render" hook.
|
||
|
//
|
||
|
// > loco_on_buffer_edit(Application_Links *app, Buffer_ID buffer_id, Range_i64 old_range, Range_i64 new_range)
|
||
|
// Call this in your custom layer's "on buffer edit" hook.
|
||
|
//
|
||
|
// > loco_yeet_on_buffer_end(Application_Links *app, Buffer_ID buffer_id)
|
||
|
// Call this in your custom layer's "on buffer end" hook.
|
||
|
//
|
||
|
// == COMMANDS ==
|
||
|
// The main command you will want to bind to a key is the yeet range command:
|
||
|
// > loco_yeet_selected_range_or_jump
|
||
|
// That will yeet the selected range, or if the cursor is already inside a yeet range, jump to the location
|
||
|
// in the yeet buffer, or vice versa.
|
||
|
//
|
||
|
// > loco_yeet_surrounding_function
|
||
|
// Selects the surrounding function then yeets it.
|
||
|
//
|
||
|
// > loco_yeet_tag
|
||
|
// Queries user for a string then searches all open buffers for that string
|
||
|
// as a comment tag (i.e. "// @tag") and yeets the scope it precedes.
|
||
|
//
|
||
|
// > loco_yeet_clear
|
||
|
// Clears all current yeets.
|
||
|
//
|
||
|
// > loco_yeet_reset_all
|
||
|
// Clears all yeets in all slots, also remove the markers from the original buffers.
|
||
|
//
|
||
|
// > loco_yeet_remove_marker_pair
|
||
|
// Removes a single 'yeet', whatever one the cursor is currently inside.
|
||
|
//
|
||
|
// > loco_save_snapshot_1
|
||
|
// > loco_save_snapshot_2
|
||
|
// > loco_save_snapshot_3
|
||
|
// Saves the current collection of yeets to a slot.
|
||
|
// Note that these do not persist if you close the editor.
|
||
|
//
|
||
|
// > loco_load_yeet_snapshot_1
|
||
|
// > loco_load_yeet_snapshot_2
|
||
|
// > loco_load_yeet_snapshot_3
|
||
|
// Loads a yeet snapshot into the yeet buffer.
|
||
|
//
|
||
|
// > loco_jump_between_yeet
|
||
|
// Will attempt to jump to the corresponding location in the linked buffer.
|
||
|
//
|
||
|
// == CONFIG ==
|
||
|
// There are currently a few global variables below, their variable names are self-explanatory.
|
||
|
//
|
||
|
*/
|
||
|
CUSTOM_ID(attachment, loco_marker_handle);
|
||
|
CUSTOM_ID(attachment, loco_marker_pair_handle);
|
||
|
|
||
|
//--TYPES
|
||
|
|
||
|
// @yeettype
|
||
|
struct Loco_Marker_Pair
|
||
|
{
|
||
|
i32 start_marker_idx;
|
||
|
i32 end_marker_idx;
|
||
|
i32 yeet_start_marker_idx;
|
||
|
i32 yeet_end_marker_idx;
|
||
|
Buffer_ID buffer;
|
||
|
};
|
||
|
|
||
|
// @yeettype
|
||
|
struct Loco_Yeets
|
||
|
{
|
||
|
Loco_Marker_Pair pairs[1024];
|
||
|
i32 pairs_count;
|
||
|
};
|
||
|
|
||
|
// @yeettype
|
||
|
struct Loco_Yeets_Snapshots
|
||
|
{
|
||
|
Loco_Yeets snapshots[3];
|
||
|
i32 snapshots_count;
|
||
|
};
|
||
|
|
||
|
//--GLOBALS
|
||
|
|
||
|
global bool loco_yeet_make_yeet_buffer_active_on_yeet = false;
|
||
|
global bool loco_yeet_show_highlight_ranges = true;
|
||
|
global bool loco_yeet_show_source_comment = true;
|
||
|
global FColor loco_yeet_source_comment_color = fcolor_change_alpha(f_green, 0.35f);
|
||
|
global FColor loco_yeet_highlight_start_color = fcolor_argb(0.f, 1.f, 0.f, 0.06f);
|
||
|
global FColor loco_yeet_highlight_end_color = fcolor_argb(0.f, 0.f, 1.f, 0.05f);
|
||
|
|
||
|
global Loco_Yeets_Snapshots yeets_snapshots = {};
|
||
|
|
||
|
// This is set to true when editing either buffer so you don't get
|
||
|
// infinite echoes of syncronization.
|
||
|
global bool lock_yeet_buffer = false;
|
||
|
|
||
|
// Set this to true to also delete the markers in the original buffer.
|
||
|
// I've left this at false because we might want to store different
|
||
|
// 'collections' of yeeted functions, switch between them would
|
||
|
// be as simple as saving a snapshot of the Loco_Yeets structure.
|
||
|
global bool loco_yeets_delete_og_markers = false;
|
||
|
|
||
|
//--IMPLEMENTATIONS
|
||
|
|
||
|
//~
|
||
|
static Buffer_ID
|
||
|
loco_get_yeet_buffer(Application_Links *app)
|
||
|
{
|
||
|
String_Const_u8 yeet_name = string_u8_litexpr("*yeet*");
|
||
|
Buffer_ID yeet_buffer = get_buffer_by_name(app, yeet_name, Access_Always);
|
||
|
if (!buffer_exists(app, yeet_buffer))
|
||
|
{
|
||
|
yeet_buffer = create_buffer(app, yeet_name, BufferCreate_AlwaysNew);
|
||
|
buffer_set_setting(app, yeet_buffer, BufferSetting_Unimportant, true);
|
||
|
}
|
||
|
return yeet_buffer;
|
||
|
}
|
||
|
|
||
|
//~ @marker @buffer
|
||
|
static Marker*
|
||
|
loco_get_buffer_markers(Application_Links *app, Arena *arena, Buffer_ID buffer_id, i32* count)
|
||
|
{
|
||
|
// Adds a certain thing.
|
||
|
Managed_Scope scope = buffer_get_managed_scope(app, buffer_id);
|
||
|
Managed_Object* markers_obj = scope_attachment(app, scope, loco_marker_handle, Managed_Object);
|
||
|
*count = managed_object_get_item_count(app, *markers_obj);
|
||
|
Marker* markers = push_array(arena, Marker, *count);
|
||
|
managed_object_load_data(app, *markers_obj, 0, *count, markers);
|
||
|
return markers;
|
||
|
}
|
||
|
|
||
|
//~ @marker @buffer @overwrite
|
||
|
static void
|
||
|
loco_overwrite_buffer_markers(Application_Links *app, Arena *arena, Buffer_ID buffer_id, Marker* markers, i32 count)
|
||
|
{
|
||
|
Managed_Scope scope = buffer_get_managed_scope(app, buffer_id);
|
||
|
Managed_Object* markers_obj = scope_attachment(app, scope, loco_marker_handle, Managed_Object);
|
||
|
managed_object_free(app, *markers_obj);
|
||
|
*markers_obj = alloc_buffer_markers_on_buffer(
|
||
|
app,
|
||
|
buffer_id,
|
||
|
count,
|
||
|
&scope
|
||
|
);
|
||
|
managed_object_store_data(app, *markers_obj, 0, count, markers);
|
||
|
}
|
||
|
|
||
|
//~ @overwrite
|
||
|
static void
|
||
|
loco_overwrite_yeets(Application_Links *app, Buffer_ID yeet_buffer, Loco_Yeets* yeets)
|
||
|
{
|
||
|
Managed_Scope yeet_scope = buffer_get_managed_scope(app, yeet_buffer);
|
||
|
Managed_Object* pair_obj = scope_attachment(app, yeet_scope, loco_marker_pair_handle, Managed_Object);
|
||
|
|
||
|
i32 count = managed_object_get_item_count(app, *pair_obj);
|
||
|
if (count == 0)
|
||
|
{
|
||
|
*pair_obj = alloc_managed_memory_in_scope(
|
||
|
app, yeet_scope, sizeof(Loco_Yeets), 1);
|
||
|
}
|
||
|
|
||
|
managed_object_store_data(app, *pair_obj, 0, 1, yeets);
|
||
|
}
|
||
|
|
||
|
//~ @buffer
|
||
|
static Loco_Yeets
|
||
|
loco_get_buffer_yeets(Application_Links *app, Buffer_ID buffer_id)
|
||
|
{
|
||
|
Managed_Scope scope = buffer_get_managed_scope(app, buffer_id);
|
||
|
Managed_Object* man_obj = scope_attachment(app, scope, loco_marker_pair_handle, Managed_Object);
|
||
|
Loco_Yeets yeets = {};
|
||
|
managed_object_load_data(app, *man_obj, 0, 1, &yeets);
|
||
|
return yeets;
|
||
|
}
|
||
|
|
||
|
//~ @marker @append
|
||
|
// Append an array of markers to the buffer's managed objects.
|
||
|
static i32
|
||
|
loco_append_markers(Application_Links *app, Buffer_ID buffer_id, Marker* new_markers, i32 count)
|
||
|
{
|
||
|
Managed_Scope scope;
|
||
|
scope = buffer_get_managed_scope(app, buffer_id);
|
||
|
Scratch_Block scratch(app);
|
||
|
|
||
|
Temp_Memory marker_temp = begin_temp(scratch);
|
||
|
Managed_Object* markers_obj = scope_attachment(app, scope, loco_marker_handle, Managed_Object);
|
||
|
i32 marker_count = managed_object_get_item_count(app, *markers_obj);
|
||
|
Marker* old_markers = push_array(scratch, Marker, marker_count);
|
||
|
|
||
|
managed_object_load_data(app, *markers_obj, 0, marker_count, old_markers);
|
||
|
managed_object_free(app, *markers_obj);
|
||
|
|
||
|
*markers_obj = alloc_buffer_markers_on_buffer(
|
||
|
app,
|
||
|
buffer_id,
|
||
|
marker_count + count,
|
||
|
&scope
|
||
|
);
|
||
|
managed_object_store_data(app, *markers_obj, 0, marker_count, old_markers);
|
||
|
managed_object_store_data(app, *markers_obj, marker_count, count, new_markers);
|
||
|
end_temp(marker_temp);
|
||
|
|
||
|
return marker_count;
|
||
|
}
|
||
|
|
||
|
//~ @marker @range
|
||
|
// Pass in a buffer and a range of indices into a Marker array, this will retrieve the Markers
|
||
|
// array from its scope. Use loco_make_range_from_markers if you already have the Markers.
|
||
|
static Range_i64
|
||
|
loco_get_marker_range(Application_Links *app, Buffer_ID buffer_id, i32 start_idx, i32 end_idx)
|
||
|
{
|
||
|
Scratch_Block scratch(app);
|
||
|
i32 count = 0;
|
||
|
Marker* markers = loco_get_buffer_markers(app, scratch, buffer_id, &count);
|
||
|
if (markers != 0)
|
||
|
{
|
||
|
i64 start = markers[start_idx].pos;
|
||
|
i64 end = markers[end_idx].pos;
|
||
|
return Ii64(start, end);
|
||
|
}
|
||
|
return Ii64(0, 0);
|
||
|
}
|
||
|
|
||
|
//~ @marker @range
|
||
|
// Pass in an array of Markers and a range of indices to that array and this outputs
|
||
|
// a Range of character positions.
|
||
|
static Range_i64
|
||
|
loco_make_range_from_markers(Marker* markers, i32 start_idx, i32 end_idx)
|
||
|
{
|
||
|
i64 start = markers[start_idx].pos;
|
||
|
i64 end = markers[end_idx].pos;
|
||
|
return Ii64(start, end);
|
||
|
}
|
||
|
|
||
|
//~
|
||
|
static void
|
||
|
loco_delete_marker_pair(Application_Links *app, Buffer_ID yeet_buffer, Loco_Yeets *yeets, i32 i)
|
||
|
{
|
||
|
Scratch_Block scratch(app);
|
||
|
|
||
|
// Swap delete pairs.
|
||
|
Loco_Marker_Pair pair = yeets->pairs[i];
|
||
|
yeets->pairs[i] = yeets->pairs[yeets->pairs_count-1];
|
||
|
yeets->pairs_count -= 1;
|
||
|
Loco_Marker_Pair &new_pair = yeets->pairs[i];
|
||
|
|
||
|
// Need to swap out the indices too
|
||
|
// becuase we've swapped deleted the markers so their index has changed.
|
||
|
if (loco_yeets_delete_og_markers && new_pair.buffer == pair.buffer)
|
||
|
{
|
||
|
new_pair.start_marker_idx = pair.start_marker_idx;
|
||
|
new_pair.end_marker_idx = pair.end_marker_idx;
|
||
|
}
|
||
|
// Always need to set the yeet_marker indices.
|
||
|
new_pair.yeet_start_marker_idx = pair.yeet_start_marker_idx;
|
||
|
new_pair.yeet_end_marker_idx = pair.yeet_end_marker_idx;
|
||
|
|
||
|
// Swap delete yeet markers.
|
||
|
i32 yeet_marker_count = 0;
|
||
|
Marker* yeet_markers = loco_get_buffer_markers(app, scratch, yeet_buffer, &yeet_marker_count);
|
||
|
yeet_markers[pair.yeet_start_marker_idx] = yeet_markers[yeet_marker_count - 2];
|
||
|
yeet_markers[pair.yeet_end_marker_idx] = yeet_markers[yeet_marker_count - 1];
|
||
|
yeet_marker_count -= 2;
|
||
|
|
||
|
// Swap delete og markers.
|
||
|
if (loco_yeets_delete_og_markers)
|
||
|
{
|
||
|
i32 og_marker_count = 0;
|
||
|
Marker* og_markers = loco_get_buffer_markers(app, scratch, pair.buffer, &og_marker_count);
|
||
|
og_markers[pair.start_marker_idx] = og_markers[og_marker_count - 2];
|
||
|
og_markers[pair.end_marker_idx] = og_markers[og_marker_count - 1];
|
||
|
og_marker_count -= 2;
|
||
|
loco_overwrite_buffer_markers(app, scratch, pair.buffer, og_markers, og_marker_count);
|
||
|
}
|
||
|
|
||
|
// Store markers in memory.
|
||
|
loco_overwrite_buffer_markers(app, scratch, yeet_buffer, yeet_markers, yeet_marker_count);
|
||
|
loco_overwrite_yeets(app, yeet_buffer, yeets);
|
||
|
|
||
|
Range_i64 yeet_range = loco_make_range_from_markers(yeet_markers, pair.yeet_start_marker_idx, pair.yeet_end_marker_idx);
|
||
|
|
||
|
String_Const_u8 empty_str = string_u8_litexpr("");
|
||
|
buffer_replace_range(app, yeet_buffer, yeet_range, empty_str);
|
||
|
}
|
||
|
|
||
|
//~ @buffer @edit
|
||
|
static void
|
||
|
loco_on_yeet_buffer_edit(Application_Links *app, Buffer_ID buffer_id, Range_i64 old_range, Range_i64 new_range)
|
||
|
{
|
||
|
|
||
|
Scratch_Block scratch(app);
|
||
|
Loco_Yeets yeets = loco_get_buffer_yeets(app, buffer_id);
|
||
|
i32 yeet_markers_count = 0;
|
||
|
Marker* yeet_markers = loco_get_buffer_markers(app, scratch, buffer_id, &yeet_markers_count);
|
||
|
for (size_t i = 0; i < yeets.pairs_count; i++)
|
||
|
{
|
||
|
Loco_Marker_Pair& pair = yeets.pairs[i];
|
||
|
if (!buffer_exists(app, pair.buffer)) continue;
|
||
|
|
||
|
Range_i64 yeet_range = loco_make_range_from_markers(yeet_markers, pair.yeet_start_marker_idx, pair.yeet_end_marker_idx);
|
||
|
if (old_range.min > yeet_range.min && new_range.max < yeet_range.max)
|
||
|
{
|
||
|
// User edited inside a yeet block.
|
||
|
Scratch_Block og_scratch(app);
|
||
|
i32 og_markers_count = 0;
|
||
|
Marker* og_markers = loco_get_buffer_markers(app, og_scratch, pair.buffer, &og_markers_count);
|
||
|
Range_i64 og_range = loco_make_range_from_markers(og_markers, pair.start_marker_idx, pair.end_marker_idx);
|
||
|
String_Const_u8 string = push_buffer_range(app, og_scratch, buffer_id, yeet_range);
|
||
|
buffer_replace_range(
|
||
|
app,
|
||
|
pair.buffer,
|
||
|
og_range,
|
||
|
string
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//~ @buffer @edit
|
||
|
static void
|
||
|
loco_on_original_buffer_edit(Application_Links *app, Buffer_ID buffer_id, Range_i64 old_range, Range_i64 new_range)
|
||
|
{
|
||
|
|
||
|
// Get the yeet buffer.
|
||
|
Buffer_ID yeet_buffer = loco_get_yeet_buffer(app);
|
||
|
if (!buffer_exists(app, yeet_buffer) || buffer_id == yeet_buffer) return;
|
||
|
|
||
|
// Check if this buffer exists in the yeet list.
|
||
|
Loco_Yeets yeets = loco_get_buffer_yeets(app, yeet_buffer);
|
||
|
bool exists_in_yeets = false;
|
||
|
for (i32 i = 0; i < yeets.pairs_count; i++)
|
||
|
{
|
||
|
if (yeets.pairs[i].buffer == buffer_id)
|
||
|
{
|
||
|
exists_in_yeets = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (!exists_in_yeets) return;
|
||
|
|
||
|
// Get yeet list and markers for both buffers.
|
||
|
Scratch_Block scratch(app);
|
||
|
i32 yeet_markers_count = 0;
|
||
|
Marker* yeet_markers = loco_get_buffer_markers(app, scratch, yeet_buffer, &yeet_markers_count);
|
||
|
i32 og_markers_count = 0;
|
||
|
Marker* og_markers = loco_get_buffer_markers(app, scratch, buffer_id, &og_markers_count);
|
||
|
for (i32 i = 0; i < yeets.pairs_count; i++)
|
||
|
{
|
||
|
Loco_Marker_Pair pair = yeets.pairs[i];
|
||
|
if (pair.buffer != buffer_id) continue;
|
||
|
Range_i64 og_range = loco_make_range_from_markers(
|
||
|
og_markers, pair.start_marker_idx, pair.end_marker_idx);
|
||
|
if (old_range.min > og_range.min && new_range.max < og_range.max)
|
||
|
{
|
||
|
// User edited inside an original buffer block.
|
||
|
Range_i64 yeet_range = loco_make_range_from_markers(
|
||
|
yeet_markers, pair.yeet_start_marker_idx, pair.yeet_end_marker_idx);
|
||
|
String_Const_u8 string = push_buffer_range(app, scratch, buffer_id, og_range);
|
||
|
buffer_replace_range(
|
||
|
app,
|
||
|
yeet_buffer,
|
||
|
yeet_range,
|
||
|
string
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//~ @api @buffer @edit
|
||
|
api(LOCO) void
|
||
|
loco_on_buffer_edit(Application_Links *app, Buffer_ID buffer_id, Range_i64 old_range, Range_i64 new_range)
|
||
|
{
|
||
|
Buffer_ID yeet_buffer = get_buffer_by_name(app, string_u8_litexpr("*yeet*"), Access_Always);
|
||
|
if (buffer_id == yeet_buffer)
|
||
|
{
|
||
|
if (!lock_yeet_buffer)
|
||
|
{
|
||
|
lock_yeet_buffer = true;
|
||
|
loco_on_yeet_buffer_edit(app, buffer_id, old_range, new_range);
|
||
|
lock_yeet_buffer = false;
|
||
|
}
|
||
|
}
|
||
|
else if (!lock_yeet_buffer)
|
||
|
{
|
||
|
lock_yeet_buffer = true;
|
||
|
loco_on_original_buffer_edit(app, buffer_id, old_range, new_range);
|
||
|
lock_yeet_buffer = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//~ @api @buffer @render
|
||
|
api(LOCO) void
|
||
|
loco_render_buffer(Application_Links *app, View_ID view_id, Face_ID face_id,
|
||
|
Buffer_ID buffer, Text_Layout_ID text_layout_id,
|
||
|
Rect_f32 rect, Frame_Info frame_info)
|
||
|
{
|
||
|
String_Const_u8 name = string_u8_litexpr("*yeet*");
|
||
|
Buffer_ID yeet_buffer = get_buffer_by_name(app, name, Access_Always);
|
||
|
if (!buffer_exists(app, yeet_buffer)) return;
|
||
|
Loco_Yeets yeets = loco_get_buffer_yeets(app, yeet_buffer);
|
||
|
|
||
|
if (buffer == yeet_buffer && loco_yeet_show_source_comment)
|
||
|
{
|
||
|
Scratch_Block scratch(app);
|
||
|
i32 markers_count = 0;
|
||
|
Marker* markers = loco_get_buffer_markers(app, scratch, yeet_buffer, &markers_count);
|
||
|
f32 line_height = get_view_line_height(app, view_id);
|
||
|
FColor comment_color = loco_yeet_source_comment_color;
|
||
|
for (i32 i = 0; i < yeets.pairs_count; i++)
|
||
|
{
|
||
|
Loco_Marker_Pair pair = yeets.pairs[i];
|
||
|
if (!buffer_exists(app, pair.buffer)) continue;
|
||
|
|
||
|
Range_i64 og_range = loco_get_marker_range(
|
||
|
app, pair.buffer, pair.start_marker_idx, pair.end_marker_idx);
|
||
|
i64 start_line = get_line_number_from_pos(app, pair.buffer, og_range.min);
|
||
|
i64 end_line = get_line_number_from_pos(app, pair.buffer, og_range.max);
|
||
|
Fancy_Line line = {};
|
||
|
String_Const_u8 unique_name = push_buffer_unique_name(app, scratch, pair.buffer);
|
||
|
push_fancy_string(scratch, &line, fcolor_zero(), unique_name);
|
||
|
push_fancy_stringf(scratch, &line, fcolor_zero(), " - Lines: %3.lld - %3.lld", start_line, end_line);
|
||
|
i64 start_pos = markers[pair.yeet_start_marker_idx].pos;
|
||
|
Rect_f32 start_rect = text_layout_character_on_screen(app, text_layout_id, start_pos);
|
||
|
Vec2_f32 comment_pos = { start_rect.x0 + 0, start_rect.y0 - line_height };
|
||
|
draw_fancy_line(app, face_id, comment_color, &line, comment_pos);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (loco_yeet_show_highlight_ranges)
|
||
|
{
|
||
|
FColor start_color = loco_yeet_highlight_start_color;
|
||
|
FColor end_color = loco_yeet_highlight_end_color;
|
||
|
for (i32 i = 0; i < yeets.pairs_count; i++)
|
||
|
{
|
||
|
Loco_Marker_Pair pair = yeets.pairs[i];
|
||
|
Range_i64 range = {};
|
||
|
if (pair.buffer == buffer || buffer == yeet_buffer)
|
||
|
{
|
||
|
if (buffer == yeet_buffer)
|
||
|
{
|
||
|
range = loco_get_marker_range(app, buffer, pair.yeet_start_marker_idx, pair.yeet_end_marker_idx);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
range = loco_get_marker_range(app, buffer, pair.start_marker_idx, pair.end_marker_idx);
|
||
|
}
|
||
|
i64 start_line_number = get_line_number_from_pos(app, buffer, range.min);
|
||
|
draw_line_highlight(
|
||
|
app,
|
||
|
text_layout_id,
|
||
|
start_line_number,
|
||
|
start_color);
|
||
|
i64 end_line_number = get_line_number_from_pos(app, buffer, range.max);
|
||
|
draw_line_highlight(
|
||
|
app,
|
||
|
text_layout_id,
|
||
|
end_line_number,
|
||
|
end_color);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//~ @api @buffer
|
||
|
api(LOCO) void
|
||
|
loco_on_buffer_end(Application_Links *app, Buffer_ID buffer_id)
|
||
|
{
|
||
|
Buffer_ID yeet_buffer = loco_get_yeet_buffer(app);
|
||
|
Loco_Yeets yeets = loco_get_buffer_yeets(app, yeet_buffer);
|
||
|
for (i32 i = yeets.pairs_count - 1; i >= 0; i--)
|
||
|
{
|
||
|
if (yeets.pairs[i].buffer == buffer_id)
|
||
|
{
|
||
|
loco_delete_marker_pair(app, yeet_buffer, &yeets, i);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//~
|
||
|
static bool
|
||
|
loco_is_cursor_inside_yeet(Application_Links *app, i64 cursor_pos, i64 *out_dst_cursor_pos, Buffer_ID *out_dst_buffer)
|
||
|
{
|
||
|
View_ID view = get_active_view(app, Access_Always);
|
||
|
Buffer_ID buffer = view_get_buffer(app, view, Access_Always);
|
||
|
Buffer_ID yeet_buffer = loco_get_yeet_buffer(app);
|
||
|
bool is_yeet_buffer = (buffer == yeet_buffer);
|
||
|
Loco_Yeets yeets = loco_get_buffer_yeets(app, yeet_buffer);
|
||
|
|
||
|
for (i32 i = 0; i < yeets.pairs_count; i++)
|
||
|
{
|
||
|
Loco_Marker_Pair pair = yeets.pairs[i];
|
||
|
Buffer_ID src_buf = is_yeet_buffer ? yeet_buffer : pair.buffer;
|
||
|
i32 src_start = is_yeet_buffer ? pair.yeet_start_marker_idx : pair.start_marker_idx;
|
||
|
i32 src_end = is_yeet_buffer ? pair.yeet_end_marker_idx : pair.end_marker_idx;
|
||
|
Range_i64 src_range = loco_get_marker_range(app, src_buf, src_start, src_end);
|
||
|
bool is_cursor_inside = (cursor_pos >= src_range.min && cursor_pos <= src_range.max);
|
||
|
if (is_cursor_inside)
|
||
|
{
|
||
|
Buffer_ID dst_buf = !is_yeet_buffer ? yeet_buffer : pair.buffer;
|
||
|
i32 dst_start = !is_yeet_buffer ? pair.yeet_start_marker_idx : pair.start_marker_idx;
|
||
|
i32 dst_end = !is_yeet_buffer ? pair.yeet_end_marker_idx : pair.end_marker_idx;
|
||
|
Range_i64 dst_range = loco_get_marker_range(app, dst_buf, dst_start, dst_end);
|
||
|
if (out_dst_cursor_pos != 0)
|
||
|
{
|
||
|
*out_dst_cursor_pos = dst_range.min + (cursor_pos - src_range.min);
|
||
|
}
|
||
|
if (out_dst_buffer != 0)
|
||
|
{
|
||
|
*out_dst_buffer = dst_buf;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//~ @jump @buffer
|
||
|
static void
|
||
|
loco_jump_to_buffer(Application_Links *app, Buffer_ID dst_buffer, i64 dst_cursor)
|
||
|
{
|
||
|
View_ID view = get_next_view_after_active(app, Access_Always);
|
||
|
view_set_buffer(app, view, dst_buffer, 0);
|
||
|
view_set_active(app, view);
|
||
|
view_set_cursor_and_preferred_x(app, view, seek_pos(dst_cursor));
|
||
|
if (auto_center_after_jumps)
|
||
|
{
|
||
|
center_view(app);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//~ @jump
|
||
|
static bool
|
||
|
loco_try_jump_between_yeet_pair(Application_Links *app)
|
||
|
{
|
||
|
View_ID view = get_active_view(app, Access_Always);
|
||
|
i64 cursor_pos = view_get_cursor_pos(app, view);
|
||
|
i64 dst_cursor_pos = 0;
|
||
|
Buffer_ID dst_buffer = 0;
|
||
|
bool success = loco_is_cursor_inside_yeet(app, cursor_pos, &dst_cursor_pos, &dst_buffer);
|
||
|
if (success)
|
||
|
{
|
||
|
loco_jump_to_buffer(app, dst_buffer, dst_cursor_pos);
|
||
|
}
|
||
|
return success;
|
||
|
}
|
||
|
|
||
|
//~ @buffer
|
||
|
// Copies text region from one buffer to another buffer (appends to end)
|
||
|
// Returns the insertion region in the dest buffer.
|
||
|
static Range_i64
|
||
|
loco_copy_buffer_text_to_buffer(Application_Links *app,
|
||
|
Arena * arena,
|
||
|
Buffer_ID src_buffer,
|
||
|
Buffer_ID dst_buffer,
|
||
|
Range_i64 src_range)
|
||
|
{
|
||
|
// Copy range string from original buffer.
|
||
|
String_Const_u8 copy_string = push_buffer_range(app, arena, src_buffer, src_range);
|
||
|
|
||
|
// Find dest buffer pos to start insertion.
|
||
|
i64 dst_insert_start = (i64)buffer_get_size(app, dst_buffer);
|
||
|
|
||
|
// Insert range to yeet buffer.
|
||
|
lock_yeet_buffer = true;
|
||
|
Buffer_Insertion insert = begin_buffer_insertion_at_buffered(app, dst_buffer, dst_insert_start, arena, KB(16));
|
||
|
insertc(&insert, '\n');
|
||
|
insert_string(&insert, copy_string);
|
||
|
insertc(&insert, '\n');
|
||
|
insertc(&insert, '\n');
|
||
|
end_buffer_insertion(&insert);
|
||
|
lock_yeet_buffer = false;
|
||
|
|
||
|
// Find dest end buffer pos.
|
||
|
i64 dst_insert_end = (i64)buffer_get_size(app, dst_buffer);
|
||
|
|
||
|
// +1 to ignore start newline.
|
||
|
// -2 to ignore the two end newlines.
|
||
|
return Ii64(dst_insert_start + 1, dst_insert_end - 2);
|
||
|
}
|
||
|
|
||
|
//~ @marker @append
|
||
|
// Append two markers that sit and the start and end of a range.
|
||
|
static i32
|
||
|
loco_append_marker_range(Application_Links *app, Buffer_ID buffer, Range_i64 range)
|
||
|
{
|
||
|
Marker markers[2];
|
||
|
markers[0].pos = range.min;
|
||
|
markers[0].lean_right = false;
|
||
|
markers[1].pos = range.max;
|
||
|
markers[1].lean_right = true;
|
||
|
return loco_append_markers(app, buffer, markers, 2);
|
||
|
}
|
||
|
|
||
|
//~ @snapshot
|
||
|
static void
|
||
|
loco_save_yeet_snapshot_to_slot(Application_Links *app, i32 slot)
|
||
|
{
|
||
|
Buffer_ID yeet_buffer = loco_get_yeet_buffer(app);
|
||
|
Loco_Yeets yeets = loco_get_buffer_yeets(app, yeet_buffer);
|
||
|
yeets_snapshots.snapshots[slot] = yeets;
|
||
|
}
|
||
|
|
||
|
//~ @snapshot
|
||
|
static void
|
||
|
loco_load_yeet_snapshot_from_slot(Application_Links *app, i32 slot)
|
||
|
{
|
||
|
Buffer_ID yeet_buffer = loco_get_yeet_buffer(app);
|
||
|
loco_yeet_clear(app);
|
||
|
Loco_Yeets unsorted_yeets = yeets_snapshots.snapshots[slot];
|
||
|
|
||
|
Scratch_Block scratch(app);
|
||
|
|
||
|
// Sort the pairs by the yeet_buffer marker index.
|
||
|
Sort_Pair_i32* yeet_sorter = push_array(scratch, Sort_Pair_i32, unsorted_yeets.pairs_count);
|
||
|
for (i32 i = 0; i < unsorted_yeets.pairs_count; i += 1){
|
||
|
yeet_sorter[i].index = i;
|
||
|
yeet_sorter[i].key = unsorted_yeets.pairs[i].yeet_start_marker_idx;
|
||
|
}
|
||
|
sort_pairs_by_key(yeet_sorter, unsorted_yeets.pairs_count);
|
||
|
|
||
|
Loco_Yeets yeets = {};
|
||
|
yeets.pairs_count = unsorted_yeets.pairs_count;
|
||
|
for (i32 i = 0; i < unsorted_yeets.pairs_count; i += 1) {
|
||
|
yeets.pairs[i] = unsorted_yeets.pairs[yeet_sorter[i].index];
|
||
|
}
|
||
|
|
||
|
// Delete all mentions of buffers that no longer exist.
|
||
|
for (i32 i = yeets.pairs_count - 1; i >= 0; i--)
|
||
|
{
|
||
|
if (!buffer_exists(app, yeets.pairs[i].buffer))
|
||
|
{
|
||
|
// Swap delete.
|
||
|
yeets.pairs[i] = yeets.pairs[yeets.pairs_count-1];
|
||
|
yeets.pairs_count -= 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Insert the text into the yeet_buffer.
|
||
|
for (i32 i = 0; i < yeets.pairs_count; i++)
|
||
|
{
|
||
|
Loco_Marker_Pair pair = yeets.pairs[i];
|
||
|
Range_i64 og_range = loco_get_marker_range(app, pair.buffer, pair.start_marker_idx, pair.end_marker_idx);
|
||
|
Range_i64 insertion_range = loco_copy_buffer_text_to_buffer(app, scratch, pair.buffer, yeet_buffer, og_range);
|
||
|
loco_append_marker_range(app, yeet_buffer, insertion_range);
|
||
|
}
|
||
|
|
||
|
loco_overwrite_yeets(app, yeet_buffer, &yeets);
|
||
|
|
||
|
// Show the yeet buffer in opposite view if not in yeet view already.
|
||
|
View_ID view = get_active_view(app, Access_Always);
|
||
|
Buffer_ID buffer = view_get_buffer(app, view, Access_Always);
|
||
|
if (buffer != yeet_buffer)
|
||
|
{
|
||
|
View_ID yeet_view = get_next_view_after_active(app, Access_Always);
|
||
|
view_set_buffer(app, yeet_view, yeet_buffer, 0);
|
||
|
view_set_cursor_and_preferred_x(app, yeet_view, seek_pos(0));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//~ @buffer
|
||
|
static void
|
||
|
loco_yeet_buffer_range(Application_Links *app, Buffer_ID buffer, Range_i64 range)
|
||
|
{
|
||
|
Buffer_ID yeet_buffer = loco_get_yeet_buffer(app);
|
||
|
if (buffer == yeet_buffer || loco_is_cursor_inside_yeet(app, range.min, 0, 0))
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
i32 old_marker_idx = loco_append_marker_range(app, buffer, range);
|
||
|
|
||
|
// Copy range string from original buffer.
|
||
|
Scratch_Block scratch(app);
|
||
|
|
||
|
Range_i64 insertion_range = loco_copy_buffer_text_to_buffer(app, scratch, buffer, yeet_buffer, range);
|
||
|
|
||
|
i32 old_yeet_marker_idx = loco_append_marker_range(app, yeet_buffer, insertion_range);
|
||
|
|
||
|
// Show the yeet buffer in opposite view.
|
||
|
View_ID yeet_view = get_next_view_after_active(app, Access_Always);
|
||
|
view_set_buffer(app, yeet_view, yeet_buffer, 0);
|
||
|
view_set_cursor_and_preferred_x(app, yeet_view, seek_pos(insertion_range.min));
|
||
|
if (loco_yeet_make_yeet_buffer_active_on_yeet)
|
||
|
{
|
||
|
view_set_active(app, yeet_view);
|
||
|
}
|
||
|
|
||
|
// add marker pair to yeet table.
|
||
|
Managed_Scope yeet_scope = buffer_get_managed_scope(app, yeet_buffer);
|
||
|
Managed_Object* pair_obj = scope_attachment(app, yeet_scope, loco_marker_pair_handle, Managed_Object);
|
||
|
Loco_Yeets yeets = {};
|
||
|
if (!managed_object_load_data(app, *pair_obj, 0, 1, &yeets))
|
||
|
{
|
||
|
yeets.pairs_count = 0;
|
||
|
*pair_obj = alloc_managed_memory_in_scope(app, yeet_scope, sizeof(Loco_Yeets), 1);
|
||
|
}
|
||
|
Loco_Marker_Pair& pair = yeets.pairs[yeets.pairs_count++];
|
||
|
pair.buffer = buffer;
|
||
|
pair.start_marker_idx = old_marker_idx;
|
||
|
pair.end_marker_idx = old_marker_idx + 1;
|
||
|
pair.yeet_start_marker_idx = old_yeet_marker_idx;
|
||
|
pair.yeet_end_marker_idx = old_yeet_marker_idx + 1;
|
||
|
managed_object_store_data(app, *pair_obj, 0, 1, &yeets);
|
||
|
}
|
||
|
|
||
|
//~ @command
|
||
|
CUSTOM_COMMAND_SIG(loco_jump_between_yeet)
|
||
|
CUSTOM_DOC("Jumps from the yeet sheet to the original buffer or vice versa.")
|
||
|
{
|
||
|
loco_try_jump_between_yeet_pair(app);
|
||
|
}
|
||
|
|
||
|
//~ @command
|
||
|
CUSTOM_COMMAND_SIG(loco_yeet_selected_range_or_jump)
|
||
|
CUSTOM_DOC("Yeets some code into a yeet buffer.")
|
||
|
{
|
||
|
View_ID view = get_active_view(app, Access_Always);
|
||
|
Buffer_ID buffer = view_get_buffer(app, view, Access_Always);
|
||
|
Range_i64 range = get_view_range(app, view);
|
||
|
|
||
|
// The "or jump" part.
|
||
|
if (loco_try_jump_between_yeet_pair(app))
|
||
|
return;
|
||
|
|
||
|
loco_yeet_buffer_range(app, buffer, range);
|
||
|
}
|
||
|
|
||
|
//~ @command
|
||
|
CUSTOM_COMMAND_SIG(loco_yeet_surrounding_function)
|
||
|
CUSTOM_DOC("Selects the surrounding function scope and yeets it.")
|
||
|
{
|
||
|
View_ID view = get_active_view(app, Access_ReadVisible);
|
||
|
Buffer_ID buffer = view_get_buffer(app, view, Access_ReadVisible);
|
||
|
// Select the surrounding {} braces.
|
||
|
i64 pos = view_get_cursor_pos(app, view);
|
||
|
Range_i64 range = {};
|
||
|
if (find_surrounding_nest(app, buffer, pos, FindNest_Scope, &range)){
|
||
|
for (;;){
|
||
|
pos = range.min;
|
||
|
if (!find_surrounding_nest(app, buffer, pos, FindNest_Scope, &range)){
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
i64 start_line = get_line_number_from_pos(app, buffer, range.min);
|
||
|
start_line -= 2;
|
||
|
if (start_line < 1) start_line = 1;
|
||
|
range = Ii64(get_line_start_pos(app, buffer, start_line), range.max);
|
||
|
select_scope(app, view, range);
|
||
|
}
|
||
|
// yeet it.
|
||
|
loco_yeet_selected_range_or_jump(app);
|
||
|
}
|
||
|
|
||
|
//~ @command
|
||
|
CUSTOM_COMMAND_SIG(loco_yeet_clear)
|
||
|
CUSTOM_DOC("Clears all yeets.")
|
||
|
{
|
||
|
Buffer_ID yeet_buffer = loco_get_yeet_buffer(app);
|
||
|
|
||
|
Loco_Yeets yeets = loco_get_buffer_yeets(app, yeet_buffer);
|
||
|
if (loco_yeets_delete_og_markers)
|
||
|
{
|
||
|
for (i32 i = 0; i < yeets.pairs_count; i++)
|
||
|
{
|
||
|
Managed_Scope scope = buffer_get_managed_scope(app, yeets.pairs[i].buffer);
|
||
|
Managed_Object* markers_obj = scope_attachment(
|
||
|
app, scope, loco_marker_handle, Managed_Object);
|
||
|
managed_object_free(app, *markers_obj);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
{
|
||
|
Managed_Scope scope = buffer_get_managed_scope(app, yeet_buffer);
|
||
|
Managed_Object* markers_obj = scope_attachment(app, scope, loco_marker_handle, Managed_Object);
|
||
|
managed_object_free(app, *markers_obj);
|
||
|
Managed_Object* pair_obj = scope_attachment(app, scope, loco_marker_pair_handle, Managed_Object);
|
||
|
managed_object_free(app, *pair_obj);
|
||
|
}
|
||
|
|
||
|
clear_buffer(app, yeet_buffer);
|
||
|
}
|
||
|
|
||
|
//~ @command
|
||
|
CUSTOM_COMMAND_SIG(loco_yeet_reset_all)
|
||
|
CUSTOM_DOC("Clears all yeets in all snapshots, also clears all the markers.")
|
||
|
{
|
||
|
bool cache_delete_og_markers = loco_yeets_delete_og_markers;
|
||
|
loco_yeets_delete_og_markers = true;
|
||
|
loco_load_yeet_snapshot_from_slot(app, 0);
|
||
|
loco_yeet_clear(app);
|
||
|
loco_load_yeet_snapshot_from_slot(app, 1);
|
||
|
loco_yeet_clear(app);
|
||
|
loco_load_yeet_snapshot_from_slot(app, 2);
|
||
|
loco_yeet_clear(app);
|
||
|
loco_yeets_delete_og_markers = cache_delete_og_markers;
|
||
|
loco_load_yeet_snapshot_from_slot(app, 0);
|
||
|
yeets_snapshots = {};
|
||
|
}
|
||
|
|
||
|
//~ @command
|
||
|
CUSTOM_COMMAND_SIG(loco_yeet_remove_marker_pair)
|
||
|
CUSTOM_DOC("Removes the marker pair the cursor is currently inside.")
|
||
|
{
|
||
|
|
||
|
Buffer_ID yeet_buffer = loco_get_yeet_buffer(app);
|
||
|
View_ID view = get_active_view(app, Access_Always);
|
||
|
Buffer_ID buffer = view_get_buffer(app, view, Access_Always);
|
||
|
i64 cursor_pos = view_get_cursor_pos(app, view);
|
||
|
if (!loco_is_cursor_inside_yeet(app, cursor_pos, 0, 0)) return;
|
||
|
|
||
|
// If we're in the original buffer,
|
||
|
// try to jump to the relative location in the yeet before.
|
||
|
// That way I just keep the one branch of logic for deleting
|
||
|
// from the yeet buffer only.
|
||
|
View_ID cached_view = view;
|
||
|
if (buffer != yeet_buffer)
|
||
|
{
|
||
|
loco_try_jump_between_yeet_pair(app);
|
||
|
view = get_active_view(app, Access_Always);
|
||
|
buffer = view_get_buffer(app, view, Access_Always);
|
||
|
}
|
||
|
|
||
|
if (buffer == yeet_buffer)
|
||
|
{
|
||
|
Scratch_Block scratch(app);
|
||
|
Range_i64 range = get_view_range(app, view);
|
||
|
Loco_Yeets yeets = loco_get_buffer_yeets(app, yeet_buffer);
|
||
|
i32 yeet_marker_count = 0;
|
||
|
Marker* yeet_markers = loco_get_buffer_markers(app, scratch, yeet_buffer, &yeet_marker_count);
|
||
|
for (i32 i = yeets.pairs_count - 1; i >= 0; i--)
|
||
|
{
|
||
|
Loco_Marker_Pair pair = yeets.pairs[i];
|
||
|
Range_i64 yeet_range = loco_make_range_from_markers(
|
||
|
yeet_markers, pair.yeet_start_marker_idx, pair.yeet_end_marker_idx);
|
||
|
if (range.max > yeet_range.min && range.max < yeet_range.max)
|
||
|
{
|
||
|
loco_delete_marker_pair(app, yeet_buffer, &yeets, i);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
view_set_active(app, cached_view);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//--SNAPSHOTS
|
||
|
|
||
|
//~ @command @snapshot
|
||
|
CUSTOM_COMMAND_SIG(loco_save_yeet_snapshot_1)
|
||
|
CUSTOM_DOC("Save yeets snapshot to slot 1.")
|
||
|
{
|
||
|
loco_save_yeet_snapshot_to_slot(app, 0);
|
||
|
}
|
||
|
|
||
|
//~ @command @snapshot
|
||
|
CUSTOM_COMMAND_SIG(loco_save_yeet_snapshot_2)
|
||
|
CUSTOM_DOC("Save yeets snapshot to slot 2.")
|
||
|
{
|
||
|
loco_save_yeet_snapshot_to_slot(app, 1);
|
||
|
}
|
||
|
|
||
|
//~ @command @snapshot
|
||
|
CUSTOM_COMMAND_SIG(loco_save_yeet_snapshot_3)
|
||
|
CUSTOM_DOC("Save yeets snapshot to slot 3.")
|
||
|
{
|
||
|
loco_save_yeet_snapshot_to_slot(app, 2);
|
||
|
}
|
||
|
|
||
|
//~ @command @snapshot
|
||
|
CUSTOM_COMMAND_SIG(loco_load_yeet_snapshot_1)
|
||
|
CUSTOM_DOC("Load yeets snapshot from slot 1.")
|
||
|
{
|
||
|
loco_load_yeet_snapshot_from_slot(app, 0);
|
||
|
}
|
||
|
|
||
|
//~ @command @snapshot
|
||
|
CUSTOM_COMMAND_SIG(loco_load_yeet_snapshot_2)
|
||
|
CUSTOM_DOC("Load yeets snapshot from slot 2.")
|
||
|
{
|
||
|
loco_load_yeet_snapshot_from_slot(app, 1);
|
||
|
}
|
||
|
|
||
|
//~ @command @snapshot
|
||
|
CUSTOM_COMMAND_SIG(loco_load_yeet_snapshot_3)
|
||
|
CUSTOM_DOC("Load yeets snapshot from slot 3.")
|
||
|
{
|
||
|
loco_load_yeet_snapshot_from_slot(app, 2);
|
||
|
}
|
||
|
|
||
|
//--CATEGORIES
|
||
|
|
||
|
// @yeettags @yeettype
|
||
|
enum Loco_Yeet_Tags_Parse_State
|
||
|
{
|
||
|
Loco_Tag_PState_Looking_For_Tag,
|
||
|
Loco_Tag_PState_Reading_Word,
|
||
|
Loco_Tag_PState_End_Of_Word,
|
||
|
Loco_Tag_PState_Looking_For_Comment,
|
||
|
Loco_Tag_PState_Looking_For_Scope_Start,
|
||
|
Loco_Tag_PState_Looking_For_Scope_End
|
||
|
};
|
||
|
|
||
|
// @yeettags @yeettype
|
||
|
struct Loco_Yeet_Tag_Range
|
||
|
{
|
||
|
Range_i64 range;
|
||
|
};
|
||
|
|
||
|
//~ @yeettags
|
||
|
static void
|
||
|
loco_yeet_all_scopes_with_tag(Application_Links *app, Buffer_ID buffer, String_Const_u8 tag_name)
|
||
|
{
|
||
|
Token_Array token_arr = get_token_array_from_buffer(app, buffer);
|
||
|
if (token_arr.tokens == 0) return;
|
||
|
|
||
|
Scratch_Block scratch(app);
|
||
|
Token_Iterator_Array it = token_iterator_index(buffer, &token_arr, 0);
|
||
|
Loco_Yeet_Tag_Range tag_ranges[1024];
|
||
|
u64 tag_ranges_count = 0;
|
||
|
Loco_Yeet_Tags_Parse_State root_parse_state = Loco_Tag_PState_Looking_For_Comment;
|
||
|
u64 scope_enter_count = 0;
|
||
|
|
||
|
for(Token* tok = token_it_read(&it);
|
||
|
tok != 0;
|
||
|
tok = token_it_read(&it))
|
||
|
{
|
||
|
if (HasFlag(tok->flags, TokenBaseFlag_PreprocessorBody))
|
||
|
{
|
||
|
if (!token_it_inc_non_whitespace(&it)) break;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (tok->sub_kind == TokenCppKind_LineComment && root_parse_state == Loco_Tag_PState_Looking_For_Comment)
|
||
|
{
|
||
|
String_Const_u8 tok_str = push_buffer_range(app, scratch, buffer, Ii64(tok));
|
||
|
Loco_Yeet_Tags_Parse_State parse_state = Loco_Tag_PState_Looking_For_Tag;
|
||
|
i64 tag_start = 0;
|
||
|
i64 tag_end = 0;
|
||
|
bool found_tag = false;
|
||
|
|
||
|
for (u64 i = 0; i <= tok_str.size; i++)
|
||
|
{
|
||
|
u8 c = (i < tok_str.size) ? tok_str.str[i] : 0;
|
||
|
switch(parse_state)
|
||
|
{
|
||
|
case Loco_Tag_PState_Looking_For_Tag: {
|
||
|
if (c == '@')
|
||
|
{
|
||
|
parse_state = Loco_Tag_PState_Reading_Word;
|
||
|
tag_start = i+1;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case Loco_Tag_PState_Reading_Word: {
|
||
|
bool is_lower_alpha = (c >= 'a' && c <= 'z');
|
||
|
bool is_upper_alpha = (c >= 'A' && c <= 'Z');
|
||
|
bool is_numeric = (c >= '0' && c <= '9');
|
||
|
bool is_alphanumeric = (is_lower_alpha || is_upper_alpha || is_numeric);
|
||
|
if (!is_alphanumeric)
|
||
|
{
|
||
|
parse_state = Loco_Tag_PState_End_Of_Word;
|
||
|
tag_end = i;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (parse_state == Loco_Tag_PState_End_Of_Word)
|
||
|
{
|
||
|
parse_state = Loco_Tag_PState_Looking_For_Tag;
|
||
|
String_Const_u8 sub = string_substring(tok_str, Ii64(tag_start, tag_end));
|
||
|
if (string_match(sub, tag_name))
|
||
|
{
|
||
|
found_tag = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (found_tag)
|
||
|
{
|
||
|
root_parse_state = Loco_Tag_PState_Looking_For_Scope_Start;
|
||
|
tag_ranges[tag_ranges_count].range.min = tok->pos;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (tok->sub_kind == TokenCppKind_BraceOp)
|
||
|
{
|
||
|
if (root_parse_state == Loco_Tag_PState_Looking_For_Scope_Start)
|
||
|
{
|
||
|
scope_enter_count = 1;
|
||
|
root_parse_state = Loco_Tag_PState_Looking_For_Scope_End;
|
||
|
}
|
||
|
else if (root_parse_state == Loco_Tag_PState_Looking_For_Scope_End)
|
||
|
{
|
||
|
scope_enter_count += 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (tok->sub_kind == TokenCppKind_BraceCl && root_parse_state == Loco_Tag_PState_Looking_For_Scope_End)
|
||
|
{
|
||
|
scope_enter_count -= 1;
|
||
|
if (scope_enter_count == 0)
|
||
|
{
|
||
|
root_parse_state = Loco_Tag_PState_Looking_For_Comment;
|
||
|
tag_ranges[tag_ranges_count].range.max = tok->pos+1;
|
||
|
tag_ranges_count += 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!token_it_inc_non_whitespace(&it)) break;
|
||
|
}
|
||
|
|
||
|
for (u64 i = 0; i < tag_ranges_count; i++)
|
||
|
{
|
||
|
loco_yeet_buffer_range(app, buffer, tag_ranges[i].range);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//--TAG-COMMANDS
|
||
|
|
||
|
// @command @yeettags
|
||
|
CUSTOM_COMMAND_SIG(loco_yeet_tag)
|
||
|
CUSTOM_DOC("Find all locations of a comment tag (//@tag) in all buffers and yeet the scope they precede.")
|
||
|
{
|
||
|
Scratch_Block scratch(app);
|
||
|
u8 *space = push_array(scratch, u8, KB(1));
|
||
|
String_Const_u8 tag_name = get_query_string(app, "Yeet Tag: ", space, KB(1));
|
||
|
Buffer_ID yeet_buffer = loco_get_yeet_buffer(app);
|
||
|
for (Buffer_ID buffer = get_buffer_next(app, 0, Access_ReadWriteVisible);
|
||
|
buffer != 0;
|
||
|
buffer = get_buffer_next(app, buffer, Access_ReadWriteVisible))
|
||
|
{
|
||
|
if (buffer == yeet_buffer) continue;
|
||
|
|
||
|
loco_yeet_all_scopes_with_tag(app, buffer, tag_name);
|
||
|
}
|
||
|
}
|
||
|
|