diff options
Diffstat (limited to 'examples/dte/view.c')
| -rw-r--r-- | examples/dte/view.c | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/examples/dte/view.c b/examples/dte/view.c new file mode 100644 index 0000000..cc259c0 --- /dev/null +++ b/examples/dte/view.c @@ -0,0 +1,178 @@ +#include "view.h" +#include "buffer.h" +#include "indent.h" +#include "util/ascii.h" +#include "util/debug.h" +#include "util/str-util.h" +#include "util/utf8.h" +#include "window.h" + +void view_update_cursor_y(View *view) +{ + Buffer *buffer = view->buffer; + Block *blk; + size_t nl = 0; + block_for_each(blk, &buffer->blocks) { + if (blk == view->cursor.blk) { + nl += count_nl(blk->data, view->cursor.offset); + view->cy = nl; + return; + } + nl += blk->nl; + } + BUG("unreachable"); +} + +void view_update_cursor_x(View *view) +{ + StringView line; + const unsigned int tw = view->buffer->options.tab_width; + const size_t cx = fetch_this_line(&view->cursor, &line); + long cx_char = 0; + long w = 0; + + for (size_t idx = 0; idx < cx; cx_char++) { + CodePoint u = line.data[idx++]; + if (likely(u < 0x80)) { + if (likely(!ascii_iscntrl(u))) { + w++; + } else if (u == '\t') { + w = next_indent_width(w, tw); + } else { + w += 2; + } + } else { + idx--; + u = u_get_nonascii(line.data, line.length, &idx); + w += u_char_width(u); + } + } + + view->cx = cx; + view->cx_char = cx_char; + view->cx_display = w; +} + +static bool view_is_cursor_visible(const View *v) +{ + return v->cy < v->vy || v->cy > v->vy + v->window->edit_h - 1; +} + +static void view_center_to_cursor(View *v) +{ + size_t lines = v->buffer->nl; + Window *window = v->window; + unsigned int hh = window->edit_h / 2; + + if (window->edit_h >= lines || v->cy < hh) { + v->vy = 0; + return; + } + + v->vy = v->cy - hh; + if (v->vy + window->edit_h > lines) { + // -1 makes one ~ line visible so that you know where the EOF is + v->vy -= v->vy + window->edit_h - lines - 1; + } +} + +static void view_update_vx(View *v) +{ + Window *window = v->window; + unsigned int c = 8; + + if (v->cx_display - v->vx >= window->edit_w) { + v->vx = (v->cx_display - window->edit_w + c) / c * c; + } + if (v->cx_display < v->vx) { + v->vx = v->cx_display / c * c; + } +} + +static void view_update_vy(View *v, unsigned int scroll_margin) +{ + Window *window = v->window; + int margin = window_get_scroll_margin(window, scroll_margin); + long max_y = v->vy + window->edit_h - 1 - margin; + + if (v->cy < v->vy + margin) { + v->vy = MAX(v->cy - margin, 0); + } else if (v->cy > max_y) { + v->vy += v->cy - max_y; + max_y = v->buffer->nl - window->edit_h + 1; + if (v->vy > max_y && max_y >= 0) { + v->vy = max_y; + } + } +} + +void view_update(View *v, unsigned int scroll_margin) +{ + view_update_vx(v); + if (v->force_center || (v->center_on_scroll && view_is_cursor_visible(v))) { + view_center_to_cursor(v); + } else { + view_update_vy(v, scroll_margin); + } + v->force_center = false; + v->center_on_scroll = false; +} + +long view_get_preferred_x(View *v) +{ + if (v->preferred_x < 0) { + view_update_cursor_x(v); + v->preferred_x = v->cx_display; + } + return v->preferred_x; +} + +bool view_can_close(const View *view) +{ + const Buffer *buffer = view->buffer; + return !buffer_modified(buffer) || buffer->views.count > 1; +} + +StringView view_do_get_word_under_cursor(const View *view, size_t *offset_in_line) +{ + StringView line; + size_t si = fetch_this_line(&view->cursor, &line); + while (si < line.length) { + size_t i = si; + if (u_is_word_char(u_get_char(line.data, line.length, &i))) { + break; + } + si = i; + } + + if (si == line.length) { + *offset_in_line = 0; + return string_view(NULL, 0); + } + + size_t ei = si; + while (si > 0) { + size_t i = si; + if (!u_is_word_char(u_prev_char(line.data, &i))) { + break; + } + si = i; + } + + while (ei < line.length) { + size_t i = ei; + if (!u_is_word_char(u_get_char(line.data, line.length, &i))) { + break; + } + ei = i; + } + + *offset_in_line = si; + return string_view(line.data + si, ei - si); +} + +StringView view_get_word_under_cursor(const View *view) +{ + size_t offset_in_line; + return view_do_get_word_under_cursor(view, &offset_in_line); +} |
