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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
|
/*
4coder_miblo_numbers.cpp - Commands for so called "Miblo Number Operations" which involve incrementing
and decrementing various forms of number as numerical objects despite being encoded as text objects.
*/
// TOP
struct Miblo_Number_Info{
Range_i64 range;
i64 x;
};
static b32
get_numeric_at_cursor(Application_Links *app, Buffer_ID buffer, i64 pos, Miblo_Number_Info *info){
b32 result = false;
Range_i64 range = enclose_pos_base10(app, buffer, pos);
if (range_size(range) > 0){
Scratch_Block scratch(app);
String_Const_u8 str = push_buffer_range(app, scratch, buffer, range);
if (str.size > 0){
info->range = range;
info->x = string_to_integer(str, 10);
result = true;
}
}
return(result);
}
CUSTOM_COMMAND_SIG(miblo_increment_basic)
CUSTOM_DOC("Increment an integer under the cursor by one.")
{
View_ID view = get_active_view(app, Access_ReadWriteVisible);
Buffer_ID buffer = view_get_buffer(app, view, Access_ReadWriteVisible);
i64 pos = view_get_cursor_pos(app, view);
Miblo_Number_Info number = {};
if (get_numeric_at_cursor(app, buffer, pos, &number)){
Scratch_Block scratch(app);
String_Const_u8 str = push_u8_stringf(scratch, "%d", number.x + 1);
buffer_replace_range(app, buffer, number.range, str);
view_set_cursor_and_preferred_x(app, view, seek_pos(number.range.start + str.size - 1));
}
}
CUSTOM_COMMAND_SIG(miblo_decrement_basic)
CUSTOM_DOC("Decrement an integer under the cursor by one.")
{
View_ID view = get_active_view(app, Access_ReadWriteVisible);
Buffer_ID buffer = view_get_buffer(app, view, Access_ReadWriteVisible);
i64 pos = view_get_cursor_pos(app, view);
Miblo_Number_Info number = {};
if (get_numeric_at_cursor(app, buffer, pos, &number)){
Scratch_Block scratch(app);
String_Const_u8 str = push_u8_stringf(scratch, "%d", number.x - 1);
buffer_replace_range(app, buffer, number.range, str);
view_set_cursor_and_preferred_x(app, view, seek_pos(number.range.start + str.size - 1));
}
}
// NOTE(allen): miblo time stamp format
// (h+:)?m?m:ss
struct Miblo_Timestamp{
i32 second;
i32 minute;
i32 hour;
};
static Miblo_Timestamp null_miblo_timestamp = {};
enum{
MIBLO_SECOND,
MIBLO_MINUTE,
MIBLO_HOUR
};
static Miblo_Timestamp
increment_timestamp(Miblo_Timestamp t, i32 type, i32 amt){
Miblo_Timestamp r = t;
switch (type){
case MIBLO_SECOND: /* CASE second */
r.second += amt;
// 1. Modulo r.second into [0,59]
// 2. What is thrown away by (1) store in amt, divide by 60, round down even when negative.
amt = 0;
if (r.second < 0){
i32 pos_second = -r.second;
amt = -((pos_second + 59)/60);
r.second = 60 - (pos_second % 60);
}
else if (r.second >= 60){
amt = r.second/60;
r.second = (r.second % 60);
}
case MIBLO_MINUTE: /* CASE minute */
r.minute += amt;
// 1. Modulo r.minute into [0,59]
// 2. What is thrown away by (1) store in amt, divide by 60, round down even when negative.
amt = 0;
if (r.minute < 0){
i32 pos_minute = -r.minute;
amt = -((pos_minute + 59)/60);
r.minute = 60 - (pos_minute % 60);
}
else if (r.minute >= 60){
amt = r.minute/60;
r.minute = (r.minute % 60);
}
case MIBLO_HOUR: /* CASE hour */
r.hour += amt;
if (r.hour < 0){
r.second = 0;
r.minute = 0;
r.hour = 0;
}
}
return(r);
}
static String_Const_u8
timestamp_to_string(Arena *arena, Miblo_Timestamp t){
List_String_Const_u8 list = {};
if (t.hour > 0){
string_list_pushf(arena, &list, "%d:", t.hour);
}
i32 minute = clamp_bot(0, t.minute);
string_list_pushf(arena, &list, "%02d:", minute);
i32 second = clamp_bot(0, t.second);
string_list_pushf(arena, &list, "%02d", second);
String_Const_u8 str = string_list_flatten(arena, list);
return(str);
}
struct Miblo_Timestamp_Info{
Range_i64 range;
Miblo_Timestamp time;
};
static b32
get_timestamp_at_cursor(Application_Links *app, Buffer_ID buffer, i64 pos, Miblo_Timestamp_Info *info){
b32 result = false;
Scratch_Block scratch(app);
Range_i64 time_stamp_range = enclose_pos_base10_colon(app, buffer, pos);
if (range_size(time_stamp_range) > 0){
String_Const_u8 string = push_buffer_range(app, scratch, buffer, time_stamp_range);
if (string.size > 0){
i32 count_colons = 0;
for (u64 i = 0; i < string.size; ++i){
if (string.str[i] == ':'){
count_colons += 1;
}
}
if (count_colons == 1 || count_colons == 2){
Miblo_Timestamp t = {};
b32 success = false;
Range_i64 number[3];
i32 k = 0;
number[0].min = 0;
for (i64 i = 0; i < (i64)string.size; i += 1){
if (string.str[i] == ':'){
number[k].max = i;
k += 1;
number[k].min = i + 1;
}
}
number[k].max = (i64)string.size;
if (count_colons == 2){
String_Const_u8 hour_str = string_substring(string, number[0]);
t.hour = (i32)string_to_integer(hour_str, 10);
if (range_size(number[1]) == 2){
String_Const_u8 minute_str = string_substring(string, number[1]);
t.minute = (i32)string_to_integer(minute_str, 10);
if (range_size(number[2]) == 2){
String_Const_u8 second_str = string_substring(string, number[2]);
t.second = (i32)string_to_integer(second_str, 10);
success = true;
}
}
}
else{
if (range_size(number[0]) == 2 || range_size(number[0]) == 1){
String_Const_u8 minute_str = string_substring(string, number[0]);
t.minute = (i32)string_to_integer(minute_str, 10);
if (range_size(number[1]) == 2){
String_Const_u8 second_str = string_substring(string, number[1]);
t.second = (i32)string_to_integer(second_str, 10);
success = true;
}
}
}
if (success){
info->range = time_stamp_range;
info->time = t;
result = true;
}
}
}
}
return(result);
}
static void
miblo_time_stamp_alter(Application_Links *app, i32 unit_type, i32 amt){
View_ID view = get_active_view(app, Access_ReadWriteVisible);
Buffer_ID buffer = view_get_buffer(app, view, Access_ReadWriteVisible);
i64 pos = view_get_cursor_pos(app, view);
Miblo_Timestamp_Info timestamp = {};
if (get_timestamp_at_cursor(app, buffer, pos, ×tamp)){
Scratch_Block scratch(app);
Miblo_Timestamp inc_timestamp = increment_timestamp(timestamp.time, unit_type, amt);
String_Const_u8 str = timestamp_to_string(scratch, inc_timestamp);
buffer_replace_range(app, buffer, timestamp.range, str);
view_set_cursor_and_preferred_x(app, view, seek_pos(timestamp.range.start + str.size - 1));
}
}
CUSTOM_COMMAND_SIG(miblo_increment_time_stamp)
CUSTOM_DOC("Increment a time stamp under the cursor by one second. (format [m]m:ss or h:mm:ss")
{
miblo_time_stamp_alter(app, MIBLO_SECOND, 1);
}
CUSTOM_COMMAND_SIG(miblo_decrement_time_stamp)
CUSTOM_DOC("Decrement a time stamp under the cursor by one second. (format [m]m:ss or h:mm:ss")
{
miblo_time_stamp_alter(app, MIBLO_SECOND, -1);
}
CUSTOM_COMMAND_SIG(miblo_increment_time_stamp_minute)
CUSTOM_DOC("Increment a time stamp under the cursor by one minute. (format [m]m:ss or h:mm:ss")
{
miblo_time_stamp_alter(app, MIBLO_MINUTE, 1);
}
CUSTOM_COMMAND_SIG(miblo_decrement_time_stamp_minute)
CUSTOM_DOC("Decrement a time stamp under the cursor by one minute. (format [m]m:ss or h:mm:ss")
{
miblo_time_stamp_alter(app, MIBLO_MINUTE, -1);
}
// BOTTOM
|