summaryrefslogtreecommitdiff
path: root/examples/dte/screen-window.c
blob: aa3a96fa96f94d11f98b12db101f3ddcee86ef03 (plain)
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
#include "screen.h"

static void print_separator(Window *window, void *ud)
{
    Terminal *term = ud;
    TermOutputBuffer *obuf = &term->obuf;
    if (window->x + window->w == term->width) {
        return;
    }
    for (int y = 0, h = window->h; y < h; y++) {
        term_move_cursor(obuf, window->x + window->w, window->y + y);
        term_add_byte(obuf, '|');
    }
}

static void update_separators(Terminal *term, const ColorScheme *colors, const Frame *frame)
{
    set_builtin_color(term, colors, BC_STATUSLINE);
    frame_for_each_window(frame, print_separator, term);
}

static void update_line_numbers(Terminal *term, const ColorScheme *colors, Window *window, bool force)
{
    const View *view = window->view;
    size_t lines = view->buffer->nl;
    int x = window->x;

    calculate_line_numbers(window);
    long first = view->vy + 1;
    long last = MIN(view->vy + window->edit_h, lines);

    if (
        !force
        && window->line_numbers.first == first
        && window->line_numbers.last == last
    ) {
        return;
    }

    window->line_numbers.first = first;
    window->line_numbers.last = last;

    TermOutputBuffer *obuf = &term->obuf;
    char buf[DECIMAL_STR_MAX(unsigned long) + 1];
    size_t width = window->line_numbers.width;
    BUG_ON(width > sizeof(buf));
    BUG_ON(width < LINE_NUMBERS_MIN_WIDTH);
    term_output_reset(term, window->x, window->w, 0);
    set_builtin_color(term, colors, BC_LINENUMBER);

    for (int y = 0, h = window->edit_h, edit_y = window->edit_y; y < h; y++) {
        unsigned long line = view->vy + y + 1;
        memset(buf, ' ', width);
        if (line <= lines) {
            size_t i = width - 2;
            do {
                buf[i--] = (line % 10) + '0';
            } while (line /= 10);
        }
        term_move_cursor(obuf, x, edit_y + y);
        term_add_bytes(obuf, buf, width);
    }
}

static void update_window_full(Window *window, void* UNUSED_ARG(data))
{
    EditorState *e = window->editor;
    View *view = window->view;
    view_update_cursor_x(view);
    view_update_cursor_y(view);
    view_update(view, e->options.scroll_margin);
    if (e->options.tab_bar) {
        print_tabbar(&e->terminal, &e->colors, window);
    }
    if (e->options.show_line_numbers) {
        update_line_numbers(&e->terminal, &e->colors, window, true);
    }
    update_range(e, view, view->vy, view->vy + window->edit_h);
    update_status_line(window);
}

void update_all_windows(EditorState *e)
{
    update_window_sizes(&e->terminal, e->root_frame);
    frame_for_each_window(e->root_frame, update_window_full, NULL);
    update_separators(&e->terminal, &e->colors, e->root_frame);
}

static void update_window(EditorState *e, Window *window)
{
    if (e->options.tab_bar && window->update_tabbar) {
        print_tabbar(&e->terminal, &e->colors, window);
    }

    const View *view = window->view;
    if (e->options.show_line_numbers) {
        // Force updating lines numbers if all lines changed
        bool force = (view->buffer->changed_line_max == LONG_MAX);
        update_line_numbers(&e->terminal, &e->colors, window, force);
    }

    long y1 = MAX(view->buffer->changed_line_min, view->vy);
    long y2 = MIN(view->buffer->changed_line_max, view->vy + window->edit_h - 1);
    update_range(e, view, y1, y2 + 1);
    update_status_line(window);
}

// Update all visible views containing this buffer
void update_buffer_windows(EditorState *e, const Buffer *buffer)
{
    const View *current_view = e->view;
    for (size_t i = 0, n = buffer->views.count; i < n; i++) {
        View *view = buffer->views.ptrs[i];
        if (view != view->window->view) {
            // Not visible
            continue;
        }
        if (view != current_view) {
            // Restore cursor
            view->cursor.blk = BLOCK(view->buffer->blocks.next);
            block_iter_goto_offset(&view->cursor, view->saved_cursor_offset);

            // These have already been updated for current view
            view_update_cursor_x(view);
            view_update_cursor_y(view);
            view_update(view, e->options.scroll_margin);
        }
        update_window(e, view->window);
    }
}