summaryrefslogtreecommitdiff
path: root/src/buffer.h
blob: 7a7fb84709adfae9a3967bdd56b9686a221ada6e (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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>

#include "command.h"
#include "text.h"
#include "window.h"

struct keymap;
struct command_list;

/**
 * Margins where buffer text should not be
 */
struct margin {
  uint32_t left;
  uint32_t right;
  uint32_t top;
  uint32_t bottom;
};

/** Callback for line rendering hooks */
typedef void (*line_render_cb)(struct text_chunk *line_data, uint32_t line,
                               struct command_list *commands, void *userdata);

/**
 * A line render hook
 *
 * A callback paired with userdata
 */
struct line_render_hook {
  line_render_cb callback;
  void *userdata;
};

/**
 * Result of updating a buffer hook
 */
struct update_hook_result {
  /** Desired margins for this hook */
  struct margin margins;

  /** Hook to be added to rendering of buffer lines */
  struct line_render_hook line_render_hook;
};

/** Buffer update hook callback function */
typedef struct update_hook_result (*update_hook_cb)(
    struct buffer *buffer, struct command_list *commands, uint32_t width,
    uint32_t height, uint64_t frame_time, void *userdata);

/**
 * A buffer update hook.
 *
 * Can be used to implement custom behavior on top of a buffer. Used for
 * minibuffer, line numbers, modeline etc.
 */
struct update_hook {
  /** Callback function */
  update_hook_cb callback;

  /** Optional userdata to pass to the callback function unmodified */
  void *userdata;
};

/**
 * A set of update hooks
 */
struct update_hooks {
  /** The update hooks */
  struct update_hook hooks[32];

  /** The number of update hooks */
  uint32_t nhooks;
};

struct buffer_location {
  uint32_t line;
  uint32_t col;
};

/**
 * A buffer of text that can be modified, read from and written to disk.
 *
 * This is the central data structure of dged and most other behavior is
 * implemented on top of it.
 */
struct buffer {

  /** Buffer name */
  char *name;
  /** Associated filename, this is where the buffer will be saved to */
  char *filename;

  /** Text data structure */
  struct text *text;

  /** Location of dot (cursor) */
  struct buffer_location dot;

  /** Location of mark (where a selection starts) */
  struct buffer_location mark;

  /** True if the start of a selection has been set */
  bool mark_set;

  /** Buffer-local keymaps in reverse priority order */
  struct keymap *keymaps;

  /** Number of buffer-local keymaps */
  uint32_t nkeymaps;

  /** Maximum number of keymaps */
  uint32_t nkeymaps_max;

  /** Current buffer scroll position */
  struct buffer_location scroll;

  /** Buffer update hooks */
  struct update_hooks update_hooks;
};

struct buffer buffer_create(char *name, bool modeline);
void buffer_destroy(struct buffer *buffer);

uint32_t buffer_keymaps(struct buffer *buffer, struct keymap **keymaps_out);
void buffer_add_keymap(struct buffer *buffer, struct keymap *keymap);

int buffer_add_text(struct buffer *buffer, uint8_t *text, uint32_t nbytes);
void buffer_clear(struct buffer *buffer);
bool buffer_is_empty(struct buffer *buffer);

void buffer_kill_line(struct buffer *buffer);
void buffer_forward_delete_char(struct buffer *buffer);
void buffer_backward_delete_char(struct buffer *buffer);
void buffer_backward_char(struct buffer *buffer);
void buffer_backward_word(struct buffer *buffer);
void buffer_forward_char(struct buffer *buffer);
void buffer_forward_word(struct buffer *buffer);
void buffer_backward_line(struct buffer *buffer);
void buffer_forward_line(struct buffer *buffer);
void buffer_end_of_line(struct buffer *buffer);
void buffer_beginning_of_line(struct buffer *buffer);
void buffer_newline(struct buffer *buffer);
void buffer_indent(struct buffer *buffer);

void buffer_goto_beginning(struct buffer *buffer);
void buffer_goto_end(struct buffer *buffer);

void buffer_set_mark(struct buffer *buffer);
void buffer_clear_mark(struct buffer *buffer);
void buffer_set_mark_at(struct buffer *buffer, uint32_t line, uint32_t col);

void buffer_copy(struct buffer *buffer);
void buffer_paste(struct buffer *buffer);
void buffer_paste_older(struct buffer *buffer);
void buffer_cut(struct buffer *buffer);

struct text_chunk buffer_get_line(struct buffer *buffer, uint32_t line);

uint32_t buffer_add_update_hook(struct buffer *buffer, update_hook_cb hook,
                                void *userdata);

struct buffer buffer_from_file(char *filename);
void buffer_to_file(struct buffer *buffer);
void buffer_write_to(struct buffer *buffer, const char *filename);

void buffer_update(struct buffer *buffer, uint32_t width, uint32_t height,
                   struct command_list *commands, uint64_t frame_time,
                   uint32_t *relline, uint32_t *relcol);

// commands
#define BUFFER_WRAPCMD(fn)                                                     \
  static int32_t fn##_cmd(struct command_ctx ctx, int argc,                    \
                          const char *argv[]) {                                \
    fn(ctx.active_window->buffer);                                             \
    return 0;                                                                  \
  }

BUFFER_WRAPCMD(buffer_kill_line);
BUFFER_WRAPCMD(buffer_forward_delete_char);
BUFFER_WRAPCMD(buffer_backward_delete_char);
BUFFER_WRAPCMD(buffer_backward_char);
BUFFER_WRAPCMD(buffer_backward_word);
BUFFER_WRAPCMD(buffer_forward_char);
BUFFER_WRAPCMD(buffer_forward_word);
BUFFER_WRAPCMD(buffer_backward_line);
BUFFER_WRAPCMD(buffer_forward_line);
BUFFER_WRAPCMD(buffer_end_of_line);
BUFFER_WRAPCMD(buffer_beginning_of_line);
BUFFER_WRAPCMD(buffer_newline);
BUFFER_WRAPCMD(buffer_indent);
BUFFER_WRAPCMD(buffer_to_file);
BUFFER_WRAPCMD(buffer_set_mark);
BUFFER_WRAPCMD(buffer_clear_mark);
BUFFER_WRAPCMD(buffer_copy);
BUFFER_WRAPCMD(buffer_cut);
BUFFER_WRAPCMD(buffer_paste);
BUFFER_WRAPCMD(buffer_paste_older);
BUFFER_WRAPCMD(buffer_goto_beginning);
BUFFER_WRAPCMD(buffer_goto_end);

static struct command BUFFER_COMMANDS[] = {
    {.name = "kill-line", .fn = buffer_kill_line_cmd},
    {.name = "delete-char", .fn = buffer_forward_delete_char_cmd},
    {.name = "backward-delete-char", .fn = buffer_backward_delete_char_cmd},
    {.name = "backward-char", .fn = buffer_backward_char_cmd},
    {.name = "backward-word", .fn = buffer_backward_word_cmd},
    {.name = "forward-char", .fn = buffer_forward_char_cmd},
    {.name = "forward-word", .fn = buffer_forward_word_cmd},
    {.name = "backward-line", .fn = buffer_backward_line_cmd},
    {.name = "forward-line", .fn = buffer_forward_line_cmd},
    {.name = "end-of-line", .fn = buffer_end_of_line_cmd},
    {.name = "beginning-of-line", .fn = buffer_beginning_of_line_cmd},
    {.name = "newline", .fn = buffer_newline_cmd},
    {.name = "indent", .fn = buffer_indent_cmd},
    {.name = "buffer-write-to-file", .fn = buffer_to_file_cmd},
    {.name = "set-mark", .fn = buffer_set_mark_cmd},
    {.name = "clear-mark", .fn = buffer_clear_mark_cmd},
    {.name = "copy", .fn = buffer_copy_cmd},
    {.name = "cut", .fn = buffer_cut_cmd},
    {.name = "paste", .fn = buffer_paste_cmd},
    {.name = "paste-older", .fn = buffer_paste_older_cmd},
    {.name = "goto-beginning", .fn = buffer_goto_beginning_cmd},
    {.name = "goto-end", .fn = buffer_goto_end_cmd},
};