view.h - ledit - Text editor (WIP)
HTML git clone git://lumidify.org/ledit.git (fast, but not encrypted)
HTML git clone https://lumidify.org/ledit.git (encrypted, but very slow)
HTML git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/ledit.git (over tor)
DIR Log
DIR Files
DIR Refs
DIR README
DIR LICENSE
---
view.h (18817B)
---
1 /*
2 * A view consists of a window and everything necessary for displaying
3 * the contents of the associated buffer in that window.
4 */
5
6 #ifndef _LEDIT_VIEW_H_
7 #define _LEDIT_VIEW_H_
8
9 #include <stddef.h>
10 #include "common.h"
11 #include "txtbuf.h"
12 #include "window.h"
13 #include "cache.h"
14 #include "uglycrap.h"
15
16 typedef struct ledit_view ledit_view;
17
18 #include "buffer.h"
19
20 enum action_type {
21 ACTION_NONE, /* pass next key to basic key handler */
22 ACTION_GRABKEY /* pass next key to given callback */
23 };
24
25 /* struct that is returned by key handlers to tell the
26 main event manager what key handler to call next */
27 struct action {
28 enum action_type type;
29 struct action (*callback)(ledit_view *view, unsigned int key_state, KeySym sym, char *buf, int n, int lang_index);
30 };
31
32 typedef struct {
33 ledit_view *view; /* parent view */
34 int w; /* width in pixels */
35 int h; /* height in pixels */
36 long y_offset; /* pixel offset starting at the top of the file */
37 size_t cache_pixmap_index; /* index of pixmap in cache, or -1 if not assigned */
38 size_t cache_layout_index; /* index of pango layout in cache, or -1 if not assigned */
39 int softlines; /* number of softlines - cached from PangoLayout */
40 size_t cursor_index; /* cursor index (for highlight in normal mode) */
41 char cursor_index_valid; /* whether cursor index is valid */
42 char cache_pixmap_valid; /* whether cache_pixmap_index is valid */
43 char cache_layout_valid; /* whether cache_layout_index is valid */
44 char dirty; /* whether line needs to be rendered before being drawn */
45 char text_dirty; /* whether the text in the PangoLayout needs to be
46 * updated before the layout is rendered */
47 char highlight_dirty; /* whether highlight (cursor or selection) needs to be
48 * updated still in the PangoLayout before rendering */
49 char h_dirty; /* whether height needs to be recalculated */
50 } ledit_view_line;
51
52 struct ledit_view {
53 ledit_buffer *buffer; /* parent buffer */
54 ledit_window *window; /* window showing this view */
55 ledit_cache *cache; /* cache for pixmaps and pango layouts */
56 ledit_view_line *lines; /* array of lines, stored as gap buffer */
57 char *lock_text; /* text to show if view is locked, i.e. no edits allowed */
58 /* current command type - used by key handler in keys_command.c */
59 command_mode cur_command_type;
60 struct action cur_action; /* current action to execute on key press */
61 size_t lines_cap; /* size of lines array */
62 size_t lines_gap; /* position of gap for line gap buffer */
63 size_t lines_num; /* number of lines */
64 size_t cur_line; /* current line */
65 size_t cur_index; /* current byte index in line */
66 long total_height; /* total pixel height of all lines */
67 long display_offset; /* current pixel offset of viewport */
68 ledit_range sel; /* current selection */
69 ledit_mode mode; /* current mode of this view */
70 char destroy; /* whether the view should be destroyed at the next possible time */
71 char selecting; /* whether user is currently selecting text with mouse */
72 char button2_pressed; /* whether button 2 (middle button) is pressed */
73 char sel_valid; /* whether there is currently a valid selection */
74 char redraw; /* whether something has changed so the view needs to be redrawn */
75 };
76
77 enum delete_mode {
78 DELETE_CHAR, /* delete an exact line and byte range */
79 DELETE_SOFTLINE, /* delete a range of complete softlines */
80 DELETE_HARDLINE /* delete a range of complete hardlines */
81 };
82
83 /*
84 * Set the mode of the view.
85 * This changes the mode group of the associated buffer's
86 * undo stack and changes the mode display in the window.
87 */
88 void view_set_mode(ledit_view *view, ledit_mode mode);
89
90 /*
91 * Create a view with associated buffer 'buffer'
92 * The initial mode, line, and byte position are given, respectively,
93 * by 'mode', 'line', and 'pos'.
94 */
95 ledit_view *view_create(ledit_buffer *buffer, ledit_mode mode, size_t line, size_t pos);
96
97 /*
98 * Lock a view.
99 * Views are locked for instance when substitution with confirmation is
100 * being performed in another view to avoid an inconsistent state.
101 * This currently only sets the lock text - commands using the view need
102 * to make sure to check that it isn't locked.
103 */
104 void view_lock(ledit_view *view, char *text);
105
106 /*
107 * Unlock a view.
108 */
109 void view_unlock(ledit_view *view);
110
111 /*
112 * Get the view line at the given index.
113 * The returned line is only valid until the next
114 * action that appends or deletes line entries.
115 * The macro is used in order to give better debug
116 * information when there is an error since so many
117 * functions call this one.
118 */
119 ledit_view_line *view_get_line_impl(ledit_view *view, size_t index, const char *file, int line, const char *func);
120 #define view_get_line(view, index) (view_get_line_impl((view), (index), __FILE__, __LINE__, __func__))
121
122 /*
123 * These notification functions are called by the buffer when text
124 * is changed in order to keep all views in sync.
125 */
126
127 /*
128 * Notify the view that 'len' bytes of text have been inserted at
129 * line 'line' and byte position 'index'.
130 * This marks the line as dirty, adjusts the cursor position, if it
131 * is on the same line, and sets the selection to just the current
132 * cursor position, if there was a valid selection.
133 * The line heights and offsets are not recalculated.
134 */
135 void view_notify_insert_text(ledit_view *view, size_t line, size_t index, size_t len);
136
137 /*
138 * Notify the view that 'len' bytes of text have been deleted
139 * starting at line 'line' and byte position 'index'.
140 * This marks the line as dirty, adjusts the cursor position, if it
141 * is on the same line, and sets the selection to just the current
142 * cursor position, if there was a valid selection.
143 * The line heights and offsets are not recalculated.
144 */
145 void view_notify_delete_text(ledit_view *view, size_t line, size_t index, size_t len);
146
147 /*
148 * Notify the view that a line has been appended after line 'line'.
149 * This adjusts the cursor position if necessary and sets the selection
150 * to just the current cursor position, if there was a valid selection.
151 * The line heights and offsets are not recalculated.
152 */
153 void view_notify_append_line(ledit_view *view, size_t line);
154
155 /*
156 * Notify the view that all lines from 'index1' to 'index2' (inclusive)
157 * have been deleted.
158 * This adjusts the cursor position if necessary and sets the selection
159 * to just the current cursor position, if there was a valid selection.
160 * The line heights and offsets are not recalculated.
161 */
162 void view_notify_delete_lines(ledit_view *view, size_t index1, size_t index2);
163
164 /*
165 * Destroy a view and its window.
166 */
167 void view_destroy(ledit_view *view);
168
169 /*
170 * Perform cleanup of global data.
171 */
172 void view_cleanup(void);
173
174 /*
175 * Set a cursor highlight on the character at line 'line' and
176 * byte position 'index'.
177 */
178 void view_set_line_cursor_attrs(ledit_view *view, size_t line, size_t index);
179
180 /*
181 * Remove cursor highlight from line 'line'.
182 */
183 void view_wipe_line_cursor_attrs(ledit_view *view, size_t line);
184
185 /*
186 * Recalculate the height of line 'line'.
187 * If it has changed, the offsets of all following lines are recalculated.
188 */
189 void view_recalc_line(ledit_view *view, size_t line);
190
191 /*
192 * Recalculate the height and offset of all lines starting at 'line'.
193 * If 'line' is 0, the offset is set to 0.
194 */
195 void view_recalc_from_line(ledit_view *view, size_t line);
196
197 /*
198 * Shortcut for recalculating all lines starting at 0.
199 */
200 void view_recalc_all_lines(ledit_view *view);
201
202 /*
203 * The cursor movement functions here logically belong to the buffer,
204 * but they use various unicode attributes that pango exposes, so
205 * they have to be here as long as no separate library for unicode
206 * processing is used.
207 */
208
209 /*
210 * Get the line and byte position of the cursor position 'num' positions
211 * after the position at line 'line' and byte position 'byte'. The new
212 * position is returned in 'line_ret' and 'byte_ret'.
213 * If multiline is non-zero, the new position may be on a different line.
214 * Otherwise, it is at most the length of the given line.
215 * A newline counts as one position.
216 */
217 void view_next_cursor_pos(
218 ledit_view *view,
219 size_t line, size_t byte,
220 int num, int multiline,
221 size_t *line_ret, size_t *byte_ret
222 );
223
224 /*
225 * Get the line and byte position of the cursor position 'num' positions
226 * before the position at line 'line' and byte position 'byte'. The new
227 * position is returned in 'line_ret' and 'byte_ret'.
228 * If multiline is non-zero, the new position may be on a different line.
229 * Otherwise, it is never earlier than position 0 on the given line.
230 * A newline counts as one position.
231 */
232 void view_prev_cursor_pos(
233 ledit_view *view,
234 size_t line, size_t byte,
235 int num, int multiline,
236 size_t *line_ret, size_t *byte_ret
237 );
238
239 /*
240 * The next 6 functions all return a line, a byte position, and a
241 * "real byte position". In the case of the "*prev*" functions, it
242 * is actually the same as the normal byte position (it is just
243 * returned to keep the interface the same), but in the case of the
244 * "*next*" functions, it can be different. For instance, when
245 * moving forward to the end of a word, the normal byte index will
246 * be before the last cursor of the word (i.e. the position of the
247 * cursor highlight in normal mode), while the real byte index is
248 * right after the word, so it can be used for deleting to the end
249 * of the word.
250 */
251
252 /*
253 * Words are defined by unicode semantics (as interpreted by pango),
254 * while bigwords are simply blocks of non-whitespace characters.
255 */
256
257 void view_next_word(
258 ledit_view *view, size_t line, size_t byte, int num_repeat,
259 size_t *line_ret, size_t *byte_ret, size_t *real_byte_ret
260 );
261 void view_next_word_end(
262 ledit_view *view, size_t line, size_t byte, int num_repeat,
263 size_t *line_ret, size_t *byte_ret, size_t *real_byte_ret
264 );
265 void view_next_bigword(
266 ledit_view *view, size_t line, size_t byte, int num_repeat,
267 size_t *line_ret, size_t *byte_ret, size_t *real_byte_ret
268 );
269 void view_next_bigword_end(
270 ledit_view *view, size_t line, size_t byte, int num_repeat,
271 size_t *line_ret, size_t *byte_ret, size_t *real_byte_ret
272 );
273 void view_prev_word(
274 ledit_view *view, size_t line, size_t byte, int num_repeat,
275 size_t *line_ret, size_t *byte_ret, size_t *real_byte_ret
276 );
277 void view_prev_bigword(
278 ledit_view *view, size_t line, size_t byte, int num_repeat,
279 size_t *line_ret, size_t *byte_ret, size_t *real_byte_ret
280 );
281
282 /*
283 * Get the byte position of the next non-whitespace character starting at
284 * 'byte' (including 'byte' itself), or the length of the line if there is
285 * no further non-whitespace character.
286 */
287 size_t view_line_next_non_whitespace(ledit_view *view, size_t line, size_t byte);
288
289 /*
290 * Get the byte boundary of the softline at line 'line' and byte position 'pos'.
291 */
292 void view_get_pos_softline_bounds(
293 ledit_view *view, size_t line, size_t pos,
294 size_t *start_byte_ret, size_t *end_byte_ret
295 );
296
297 /*
298 * Get the byte boundary of the softline with index 'softline'
299 * in the hardline 'line'.
300 */
301 void view_get_softline_bounds(
302 ledit_view *view, size_t line, int softline,
303 size_t *start_byte_ret, size_t *end_byte_ret
304 );
305
306 /*
307 * Get the number of softlines in line 'line'.
308 */
309 int view_get_softline_count(ledit_view *view, size_t line);
310
311 /*
312 * Get the softline index at hardline 'line' and byte position 'pos'.
313 */
314 int view_pos_to_softline(ledit_view *view, size_t line, size_t pos);
315
316 /*
317 * Get the pixel position and height of the cursor on hardline 'line'
318 * at byte position 'pos'.
319 */
320 void view_get_cursor_pixel_pos(ledit_view *view, size_t line, size_t pos, int *x_ret, int *y_ret, int *h_ret);
321
322 /*
323 * Get the byte index of the cursor if it is moved visually 'movement'
324 * positions from the position as line 'line' and byte position 'pos',
325 * where a negative number is to the left and a positive number to the
326 * right.
327 * If 'prev_index_ret' is not NULL, the previous valid cursor position
328 * is written to it - this is used in normal mode to move back one
329 * position if the cursor is at the end of the line. For some reason,
330 * using 'view_get_legal_normal_pos' doesn't work here. I still need
331 * to figure out why.
332 */
333 size_t view_move_cursor_visually(ledit_view *view, size_t line, size_t pos, int movement, size_t *prev_index_ret);
334
335 /*
336 * Convert a line index and byte position to an x position and softline
337 * index. The x position is in pango units, not pixels.
338 * In normal mode, the middle of the character is returned instead of the
339 * beginning.
340 */
341 void view_pos_to_x_softline(ledit_view *view, size_t line, size_t pos, int *x_ret, int *softline_ret);
342
343 /*
344 * Convert a line index, softline index, and x position (in pango units,
345 * not pixels) to a byte position.
346 * In insert mode, the returned byte position is the closest cursor
347 * position. In normal mode, it is simply the beginning of the character
348 * (or, rather, grapheme) that the x position was on, regardless of where
349 * on that character the position was.
350 */
351 size_t view_x_softline_to_pos(ledit_view *view, size_t line, int x, int softline);
352
353 /*
354 * Get a legal normal mode position, i.e. move back one cursor position
355 * if 'pos' is at the very end of the line.
356 */
357 size_t view_get_legal_normal_pos(ledit_view *view, size_t line, size_t pos);
358
359 /*
360 * Delete a range according to a delete_mode.
361 * The line and byte indeces do not need to be sorted (in fact, they often
362 * shouldn't be, as shown in the next sentence).
363 * If 'delmode' is DELETE_HARDLINE or DELETE_SOFTLINE, 'line_index1' and
364 * 'byte_index1' are used to determine where the cursor should be after
365 * the deletion. This new position is written to 'new_line_ret' and
366 * 'new_byte_ret'.
367 * If 'delmode' is DELETE_SOFTLINE, the byte indeces are additionally used
368 * to determine which softlines the range bounds are on.
369 * Both line deletion modes make sure that there is at least one line left
370 * in the buffer afterwards, although it may have its text deleted.
371 * If 'delmode' is DELETE_CHAR, the exact specified range is deleted, and
372 * the new line and byte are simply the beginning of the range.
373 * The deleted text is written to 'text_ret'.
374 * In normal mode, the new cursor index is always at a valid normal mode
375 * position.
376 * All return arguments may be NULL.
377 * The deletion is added to the undo stack with 'start_undo_group'
378 * specifying whether a new undo group should be started.
379 * The start cursor position for the undo stack is taken directly from
380 * the view's current position. The end cursor position is the same as
381 * what is returned in 'new_line_ret' and 'new_byte_ret', except that it
382 * is set before calling 'view_get_legal_normal_pos'.
383 * If different cursor positions are needed, call
384 * 'undo_change_last_cur_range' afterwards.
385 * This function does not recalculate the line heights or offsets.
386 */
387 void view_delete_range_base(
388 ledit_view *view,
389 enum delete_mode delmode, int start_undo_group,
390 size_t line_index1, size_t byte_index1,
391 size_t line_index2, size_t byte_index2,
392 size_t *new_line_ret, size_t *new_byte_ret,
393 txtbuf *text_ret
394 );
395
396 /*
397 * Same as 'view_delete_range_base', but the line heights and offsets of
398 * all views are recalculated afterwards.
399 */
400 void view_delete_range(
401 ledit_view *view,
402 enum delete_mode delmode, int start_undo_group,
403 size_t line_index1, size_t byte_index1,
404 size_t line_index2, size_t byte_index2,
405 size_t *new_line_ret, size_t *new_byte_ret,
406 txtbuf *text_ret
407 );
408
409 /*
410 * Resize the size of the textview, i.e. resize the line widths
411 * and update all scrolling related data.
412 * 'data' is the view, but is given as a void pointer so the
413 * function can be used as a callback.
414 */
415 void view_resize_textview(void *data);
416
417 /*
418 * Scroll to the given pixel offset.
419 * The given offset is sanity-checked so new illegal positions can result.
420 */
421 void view_scroll(ledit_view *view, long new_offset);
422
423 /*
424 * Get the position nearest to 'line' and 'byte' that is currently shown
425 * on screen.
426 */
427 void view_get_nearest_legal_pos(
428 ledit_view *view,
429 size_t line, size_t byte,
430 /*int snap_to_nearest, int snap_middle, FIXME: take these parameters */
431 size_t *line_ret, size_t *byte_ret
432 );
433
434 /*
435 * Convert pixel coordinates to line and byte indeces. The pixel coordinates
436 * are relative to the current textview.
437 * If 'snap_to_nearest' is set, but grapheme boundary nearest to the position
438 * is returned. Otherwise, the start position of the grapheme under the position
439 * is returned.
440 */
441 void view_xy_to_line_byte(ledit_view *view, int x, int y, int snap_to_nearest, size_t *line_ret, size_t *byte_ret);
442
443 /*
444 * Scroll so that the given cursor position is at the very top of the view.
445 * Note that this may not be entirely true since the final position is
446 * sanity-checked to be within the scroll bounds.
447 */
448 void view_scroll_to_pos_top(ledit_view *view, size_t line, size_t byte);
449
450 /*
451 * Scroll so that the given cursor position is at the very bottom of the view.
452 * Note that this may not be entirely true since the final position is
453 * sanity-checked to be within the scroll bounds.
454 */
455 void view_scroll_to_pos_bottom(ledit_view *view, size_t line, size_t byte);
456
457 /*
458 * Scroll so that the current cursor position is visible on screen.
459 */
460 void view_ensure_cursor_shown(ledit_view *view);
461
462 /*
463 * Clear the selection.
464 */
465 void view_wipe_selection(ledit_view *view);
466
467 /*
468 * Set the selection to the given range.
469 * The range does not need to be sorted.
470 */
471 void view_set_selection(ledit_view *view, size_t line1, size_t byte1, size_t line2, size_t byte2);
472
473 /*
474 * Redraw the view.
475 * This only redraws if the redraw bit of the view or window are set.
476 * This should all be set automatically.
477 */
478 void view_redraw(ledit_view *view, size_t lang_index);
479 /* FIXME: kind of ugly to pass lang_index here, but the window needs it - maybe store centrally somewhere? */
480
481 /*
482 * Perform up to num undo steps.
483 * The cursor position of the view is set to the stored position
484 * in the undo stack.
485 * The line heights and offsets are recalculated.
486 */
487 void view_undo(ledit_view *view, int num);
488
489 /*
490 * Perform up to num redo steps.
491 * The cursor position of the view is set to the stored position
492 * in the undo stack.
493 * The line heights and offsets are recalculated.
494 */
495 void view_redo(ledit_view *view, int num);
496
497 /*
498 * Paste the X11 clipboard at the current cursor position.
499 */
500 void view_paste_clipboard(ledit_view *view);
501
502 /*
503 * Paste the X11 primary selection at the current cursor position.
504 */
505 void view_paste_primary(ledit_view *view);
506
507 #endif