-
Notifications
You must be signed in to change notification settings - Fork 4
/
4coder_vim_block.cpp
214 lines (173 loc) · 8.55 KB
/
4coder_vim_block.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
function Rect_f32
vim_get_rel_block_rect(Application_Links *app, View_ID view, Buffer_ID buffer, Range_i64 range, i64 line){
Vec2_f32 p0 = view_relative_xy_of_pos(app, view, line, range.min);
Vec2_f32 p1 = view_relative_xy_of_pos(app, view, line, range.max);
return Rf32(Min(p0.x, p1.x), Min(p0.y, p1.y), Max(p0.x, p1.x), Max(p0.y, p1.y));
}
function Rect_f32
vim_get_abs_block_rect(Application_Links *app, View_ID view, Buffer_ID buffer, Text_Layout_ID text_layout_id, Range_i64 range){
Range_i64 visible_range = text_layout_get_visible_range(app, text_layout_id);
i64 rel_pos = range.min;
if(!range_contains(visible_range, rel_pos)){ rel_pos = range.max; }
if(!range_contains(visible_range, rel_pos)){ rel_pos = scan(app, boundary_alpha_numeric, buffer, Scan_Forward, visible_range.min); }
if(!range_contains(visible_range, rel_pos)){ return Rect_f32{}; } // This is nearly impossible to hit... nearly
i64 line = get_line_number_from_pos(app, buffer, rel_pos);
Vec2_f32 rel_p = view_relative_xy_of_pos(app, view, line, rel_pos);
Rect_f32 rel_rect = text_layout_character_on_screen(app, text_layout_id, rel_pos);
Vec2_f32 offset0 = rel_p - rel_rect.p0;
Vec2_f32 offset1 = rel_p - rel_rect.p1;
Rect_f32 min_rect, max_rect;
if(range_contains(visible_range, range.min)){
min_rect = text_layout_character_on_screen(app, text_layout_id, range.min);
}else{
Vec2_f32 min_p = view_relative_xy_of_pos(app, view, line, range.min);
min_rect = Rf32(min_p - offset0, min_p - offset1);
}
if(range_contains(visible_range, range.max)){
max_rect = text_layout_character_on_screen(app, text_layout_id, range.max);
}else{
Vec2_f32 max_p = view_relative_xy_of_pos(app, view, line, range.max);
max_rect = Rf32(max_p - offset0, max_p - offset1);
}
return rect_union(min_rect, max_rect);
}
function void
vim_block_copy(Application_Links *app, View_ID view, Buffer_ID buffer, Range_i64 range, Vim_Register *reg){
if(reg->flags & REGISTER_ReadOnly){
vim_state.chord_resolved = bitmask_2;
Scratch_Block scratch(app);
vim_set_bottom_text(push_stringf(scratch, "Register %c is Read Only", vim_get_register_char(reg)));
return;
}
reg->edit_type = EDIT_Block;
reg->flags |= (REGISTER_Set|REGISTER_Updated);
print_message(app, string_u8_litexpr("Block copy\n"));
i64 line_min = get_line_number_from_pos(app, buffer, range.min);
i64 line_max = get_line_number_from_pos(app, buffer, range.max);
Rect_f32 block_rect = vim_get_rel_block_rect(app, view, buffer, range, line_min);
f32 line_advance = rect_height(block_rect)/f32(Max(1, line_max-line_min));
f32 wid = rect_width(block_rect);
u64 size = 0;
for(i64 i=line_max; i>=line_min; i--){
Vec2_f32 min_point = block_rect.p0 + V2f32(0, line_advance*(i-line_min));
Vec2_f32 max_point = min_point + V2f32(wid,0);
i64 min_pos = view_pos_at_relative_xy(app, view, line_min, min_point);
i64 max_pos = view_pos_at_relative_xy(app, view, line_min, max_point)+1;
size += (max_pos - min_pos) + 1;
}
b32 valid = true;
if(size >= reg->data.cap){ valid = vim_realloc_string(®->data, size); }
if(!valid){ return; }
Scratch_Block scratch(app);
reg->data.size = 0;
for(i64 i=line_max; i>=line_min; i--){
Vec2_f32 min_point = block_rect.p0 + V2f32(0, line_advance*(i-line_min));
Vec2_f32 max_point = min_point + V2f32(wid,0);
i64 min_pos = view_pos_at_relative_xy(app, view, line_min, min_point);
i64 max_pos = view_pos_at_relative_xy(app, view, line_min, max_point)+1;
Range_i64 line_range = Ii64(min_pos, max_pos);
buffer_read_range(app, buffer, line_range, reg->data.str + reg->data.size);
buffer_post_fade(app, buffer, 0.667f, line_range, fcolor_resolve(fcolor_id(defcolor_paste)));
reg->data.size += (max_pos - min_pos) + 1;
reg->data.str[reg->data.size-1] = '\n';
}
}
function void
vim_block_paste(Application_Links *app, View_ID view, Buffer_ID buffer, Vim_Register *reg){
i64 cursor_pos = view_get_cursor_pos(app, view);
History_Group group = history_group_begin(app, buffer);
i64 line_min = get_line_number_from_pos(app, buffer, cursor_pos);
i64 line_max = line_min-1;
foreach(i,reg->data.size){ line_max += reg->data.str[i] == '\n'; }
// TODO(BYP): Still doesn't handle empty lines gracefully
Range_i64 range = Ii64(cursor_pos, buffer_compute_cursor(app, buffer, seek_line_col(line_max, 0)).pos);
Rect_f32 block_rect = vim_get_rel_block_rect(app, view, buffer, range, line_min);
//f32 line_advance = get_face_metrics(app, get_face_id(app, buffer)).line_height - 0.01f;
f32 line_advance = rect_height(block_rect)/f32(Max(1, line_max-line_min));
f32 wid = rect_width(block_rect);
Range_i64 substring = {};
substring.max = -1;
for(i64 i=line_max; i>=line_min; i--){
Vec2_f32 point = block_rect.p0 + V2f32(wid, line_advance*(i-line_min));
i64 pos = view_pos_at_relative_xy(app, view, line_min, point);
b32 valid=true;
substring.min = substring.max + 1;
while(reg->data.str[++substring.max] != '\n'){
if(substring.max >= i64(reg->data.size)){ valid=false; break; }
}
if(!valid){ break; }
Range_i64 sub = substring;
//sub.max += (line_is_valid_and_blank(app, buffer, i));
//pos -= (line_is_valid_and_blank(app, buffer, i));
buffer_replace_range(app, buffer, Ii64(pos), string_substring(reg->data.string, sub));
ARGB_Color argb = fcolor_resolve(fcolor_id(defcolor_paste));
buffer_post_fade(app, buffer, 0.667f, Ii64_size(pos, range_size(sub)), argb);
}
history_group_end(group);
vim_default_register();
}
function void
vim_block_edit(Application_Links *app, View_ID view, Buffer_ID buffer, Range_i64 range){
Vim_Params *params = &vim_state.params;
if(params->request == REQUEST_Yank ||
params->request == REQUEST_Change ||
params->request == REQUEST_Delete)
{
if(vim_state.params.selected_reg){
vim_block_copy(app, view, buffer, range, vim_state.params.selected_reg);
vim_update_registers(app);
vim_state.params.selected_reg = 0;
}
if(params->request == REQUEST_Yank){ return; }
}
History_Group group = history_group_begin(app, buffer);
i64 line_min = get_line_number_from_pos(app, buffer, range.min);
i64 line_max = get_line_number_from_pos(app, buffer, range.max);
Rect_f32 block_rect = vim_get_rel_block_rect(app, view, buffer, range, line_min);
f32 line_advance = rect_height(block_rect)/f32(Max(1, line_max-line_min));
f32 wid = rect_width(block_rect);
block_rect = rect_inner(block_rect, -0.1f);
for(i64 i=line_max; i>=line_min; i--){
if(line_is_valid_and_blank(app, buffer, i)){ continue; }
Vec2_f32 min_point = block_rect.p0 + V2f32(0, line_advance*(i-line_min));
Vec2_f32 max_point = min_point + V2f32(wid,0);
i64 min_pos = view_pos_at_relative_xy(app, view, line_min, min_point);
i64 max_pos = view_pos_at_relative_xy(app, view, line_min, max_point);
Vec2_f32 min_p = view_relative_xy_of_pos(app, view, line_min, min_pos);
Vec2_f32 max_p = view_relative_xy_of_pos(app, view, line_min, max_pos);
if(!rect_contains_point(block_rect, min_p) || !rect_contains_point(block_rect, max_p)){ continue; }
Range_i64 line_range = Ii64(min_pos, max_pos+1);
vim_request_vtable[params->request](app, view, buffer, line_range);
}
history_group_end(group);
}
function void
vim_visual_insert_char(Application_Links *app, View_ID view, Buffer_ID buffer, u8 character){
History_Group group = history_group_begin(app, buffer);
Range_i64 range = get_view_range(app, view);
i64 line_min = get_line_number_from_pos(app, buffer, range.min);
i64 line_max = get_line_number_from_pos(app, buffer, range.max);
Rect_f32 block_rect = vim_get_rel_block_rect(app, view, buffer, range, line_min);
f32 line_advance = rect_height(block_rect)/f32(Max(1, line_max-line_min));
f32 wid = rect_width(block_rect);
f32 x_off = vim_visual_insert_after*wid;
for(i64 i=line_max; i>=line_min; i--){
if(line_is_valid_and_blank(app, buffer, i) && i != line_min && i != line_max){ continue; }
Vec2_f32 point = block_rect.p0 + V2f32(x_off, line_advance*(i-line_min));
i64 pos = view_pos_at_relative_xy(app, view, line_min, point);
buffer_replace_range(app, buffer, Ii64(pos + vim_visual_insert_after), SCu8(&character,1));
}
i64 cursor_pos = view_get_cursor_pos(app, view);
i64 mark_pos = view_get_mark_pos(app, view);
Vec2_f32 top_point = block_rect.p0 + V2f32(x_off, 0.f);
Vec2_f32 bot_point = block_rect.p0 + V2f32(x_off, rect_height(block_rect));
i64 top_pos = view_pos_at_relative_xy(app, view, line_min, top_point);
i64 bot_pos = view_pos_at_relative_xy(app, view, line_min, bot_point);
if(cursor_pos == top_pos || cursor_pos == bot_pos){
view_set_cursor(app, view, seek_pos(cursor_pos+1));
}
if(mark_pos == top_pos || mark_pos == bot_pos){
view_set_mark(app, view, seek_pos(mark_pos+1));
}
history_group_end(group);
}