aboutsummaryrefslogtreecommitdiffstats
path: root/build/4coder_byp/4coder_vim/4coder_vim_hooks.cpp
blob: f90a16d5b190d8e2aefe9626eb9581f25ccf51b9 (plain) (blame)
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
CUSTOM_COMMAND_SIG(vim_view_input_handler)
CUSTOM_DOC("Input consumption loop for vim behavior")
{
	Scratch_Block scratch(app);
	default_input_handler_init(app, scratch);

	View_ID view = get_this_ctx_view(app, Access_Always);
	Managed_Scope scope = view_get_managed_scope(app, view);

	for(;;){
		User_Input input = get_next_input(app, EventPropertyGroup_Any, 0);
		if(input.abort){ break; }

#if VIM_USE_BOTTOM_LISTER
		// Clicking on lister items outside of original view panel is a hack
		if(vim_lister_view_id != 0 && view != vim_lister_view_id){
			view_set_active(app, vim_lister_view_id);
			leave_current_input_unhandled(app);
			continue;
		}
#endif

		ProfileScopeNamed(app, "before view input", view_input_profile);

		// NOTE(allen): Mouse Suppression
		Event_Property event_properties = get_event_properties(&input.event);
		if((suppressing_mouse && (event_properties & EventPropertyGroup_AnyMouseEvent) != 0)){
			continue;
		}

		if(vim_handle_input(app, &input.event)){
			vim_cursor_blink = 0;
			continue;
		}

		// NOTE(allen): Get binding
		if(implicit_map_function == 0){
			implicit_map_function = default_implicit_map;
		}
		Implicit_Map_Result map_result = implicit_map_function(app, 0, 0, &input.event);
		if(map_result.command == 0){
			leave_current_input_unhandled(app);
			continue;
		}

		if(!(event_properties & EventPropertyGroup_AnyMouseEvent) && input.event.kind != InputEventKind_None){
			vim_keystroke_text.size = 0;
			vim_cursor_blink = 0;
		}

		// NOTE(allen): Run the command and pre/post command stuff
		default_pre_command(app, scope);
		ProfileCloseNow(view_input_profile);

		map_result.command(app);

		ProfileScope(app, "after view input");
		default_post_command(app, scope);
	}
}

// TODO(BYP): Reorganize and move this somewhere better
VIM_COMMAND_SIG(vim_insert_command){
	vim_state.mode = VIM_Normal;
	vim_state.chord_resolved = false;

	Scratch_Block scratch(app);
	default_input_handler_init(app, scratch);

	View_ID view = get_this_ctx_view(app, Access_Always);
	Managed_Scope scope = view_get_managed_scope(app, view);

	while(!vim_state.chord_resolved){
		vim_set_bottom_text(string_u8_litexpr("-- INSERT NORMAL --"));

		// Basically another view_input handling/mapping
		User_Input input = get_next_input(app, EventPropertyGroup_Any, EventProperty_Escape);
		if(input.abort){ break; }

		Event_Property event_properties = get_event_properties(&input.event);
		if((suppressing_mouse && (event_properties & EventPropertyGroup_AnyMouseEvent) != 0)){
			continue;
		}

		if(vim_handle_input(app, &input.event)){
			vim_cursor_blink = 0;
			continue;
		}

		if(implicit_map_function == 0){
			implicit_map_function = default_implicit_map;
		}
		Implicit_Map_Result map_result = implicit_map_function(app, 0, 0, &input.event);
		if(map_result.command == 0){
			leave_current_input_unhandled(app);
			continue;
		}

		if(!(event_properties & EventPropertyGroup_AnyMouseEvent) && input.event.kind != InputEventKind_None){
			vim_keystroke_text.size = 0;
			vim_cursor_blink = 0;
		}

		default_pre_command(app, scope);
		map_result.command(app);
		default_post_command(app, scope);
	}

	vim_reset_bottom_text();
	vim_state.mode = VIM_Insert;
}

function void
vim_file_save(Application_Links *app, Buffer_ID buffer_id){
	Scratch_Block scratch(app);
	String_Const_u8 unique_name = push_buffer_unique_name(app, scratch, buffer_id);
	i64 line_count = buffer_get_line_count(app, buffer_id);
	i64 bytes = buffer_get_size(app, buffer_id);
	String_Const_u8 msg = push_stringf(scratch, "\"%.*s\"  %dL, %dC written", string_expand(unique_name), line_count, bytes);
	vim_set_bottom_text(msg);
}

BUFFER_HOOK_SIG(vim_file_save_hook){
	default_file_save(app, buffer_id);
	vim_file_save(app, buffer_id);
	return 0;
}

function void vim_set_file_register(Application_Links *app, Buffer_ID buffer){
	Scratch_Block scratch(app);
	String_Const_u8 unique_name = push_buffer_unique_name(app, scratch, buffer);
	Vim_Register *reg = &vim_registers.file;
	b32 valid = vim_register_copy(reg, unique_name);
	if(!valid){ return; }
	vim_update_registers(app);
}

function void
vim_view_change_buffer(Application_Links *app, View_ID view_id, Buffer_ID old_buffer_id, Buffer_ID new_buffer_id){
	vim_set_file_register(app, new_buffer_id);
}

function void
vim_begin_buffer_inner(Application_Links *app, Buffer_ID buffer_id){
	Managed_Scope scope = buffer_get_managed_scope(app, buffer_id);
	Vim_Prev_Visual *prev_visual = scope_attachment(app, scope, vim_buffer_prev_visual, Vim_Prev_Visual);
	prev_visual->cursor_pos = prev_visual->mark_pos = 0;

	i64 *marks = (i64 *)managed_scope_get_attachment(app, scope, vim_buffer_marks, 26*sizeof(i64));
	block_fill_u64(marks, 26*sizeof(i64), max_u64);

	b32 *wrap_lines_ptr = scope_attachment(app, scope, buffer_wrap_lines, b32);
	*wrap_lines_ptr = false;
}

BUFFER_HOOK_SIG(vim_begin_buffer){
	//default_begin_buffer(app, buffer_id);
	fold_begin_buffer_hook(app, buffer_id);
	vim_begin_buffer_inner(app, buffer_id);
	return 0;
}

#define exp_interp(cur, nxt, dt, rate) (cur += (((nxt) - (cur))*(1.f - powf(rate, dt))))

function void
vim_animate_filebar(Application_Links *app, Frame_Info frame_info){
#if VIM_DO_ANIMATE
	exp_interp(vim_cur_filebar_offset, vim_nxt_filebar_offset, frame_info.animation_dt, 1e-14f);
	if(!near_zero(vim_cur_filebar_offset - vim_nxt_filebar_offset, 0.5f)){
		animate_in_n_milliseconds(app, 0);
	}else{
		vim_cur_filebar_offset = vim_nxt_filebar_offset;
	}
#else
	vim_cur_filebar_offset = vim_nxt_filebar_offset;
#endif
}


function void
vim_animate_cursor(Application_Links *app, Frame_Info frame_info){
#if VIM_DO_ANIMATE
	exp_interp(vim_cur_cursor_pos, vim_nxt_cursor_pos, frame_info.animation_dt, 1e-14f);
	if(!near_zero(vim_cur_cursor_pos - vim_nxt_cursor_pos, 0.5f)){
		animate_in_n_milliseconds(app, 0);
	}else{
		vim_cur_cursor_pos = vim_nxt_cursor_pos;
	}
#else
	vim_cur_cursor_pos = vim_nxt_cursor_pos;
#endif
}

BUFFER_EDIT_RANGE_SIG(vim_buffer_edit_range){
	default_buffer_edit_range(app, buffer_id, new_range, old_cursor_range);
	fold_buffer_edit_range_inner(app, buffer_id, new_range, old_cursor_range);
	// TODO(BYP): Update marks here as well
	return 0;
}

function void
vim_tick(Application_Links *app, Frame_Info frame_info){
	code_index_update_tick(app);
	if(tick_all_fade_ranges(app, frame_info.animation_dt)){
		animate_in_n_milliseconds(app, 0);
	}

	vim_animate_filebar(app, frame_info);
	vim_animate_cursor(app, frame_info);
#if VIM_DO_ANIMATE
	vim_cursor_blink += frame_info.animation_dt;
#endif

	fold_tick(app, frame_info);

	b32 enable_virtual_whitespace = def_get_config_b32(vars_save_string_lit("enable_virtual_whitespace"));
	if(enable_virtual_whitespace != def_enable_virtual_whitespace){
		def_enable_virtual_whitespace = enable_virtual_whitespace;
		clear_all_layouts(app);
	}
}

CUSTOM_COMMAND_SIG(vim_try_exit)
CUSTOM_DOC("Vim command for responding to a try-exit event")
{
	User_Input input = get_current_input(app);
	if(match_core_code(&input, CoreCode_TryExit)){
		b32 do_exit = true;
		if(!allow_immediate_close_without_checking_for_changes){
			b32 has_unsaved_changes = false;
			for(Buffer_ID buffer = get_buffer_next(app, 0, Access_Always);
				buffer;
				buffer = get_buffer_next(app, buffer, Access_Always))
			{
				Dirty_State dirty = buffer_get_dirty_state(app, buffer);
				if(HasFlag(dirty, DirtyState_UnsavedChanges)){
					has_unsaved_changes = true;
					break;
				}
			}
			if(has_unsaved_changes){
				View_ID view = get_active_view(app, Access_Always);
				do_exit = vim_do_4coder_close_user_check(app, view);
			}
		}
		if(do_exit){
			hard_exit(app);
		}
	}
}