summaryrefslogtreecommitdiff
path: root/examples/dte/view.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/dte/view.c')
-rw-r--r--examples/dte/view.c178
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);
+}