ledit

Text editor (WIP)
git clone git://lumidify.org/ledit.git (fast, but not encrypted)
git clone https://lumidify.org/ledit.git (encrypted, but very slow)
git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/ledit.git (over tor)
Log | Files | Refs | README | 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