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
|
#include "minibuffer.h"
#include "display.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
static struct minibuffer g_minibuffer = {0};
void minibuffer_init(uint32_t row) {
g_minibuffer.buffer = malloc(4096);
g_minibuffer.capacity = 4096;
g_minibuffer.nbytes = 0;
g_minibuffer.row = row;
g_minibuffer.dirty = false;
}
void minibuffer_destroy() {
free(g_minibuffer.buffer);
g_minibuffer.capacity = 0;
g_minibuffer.dirty = false;
}
struct minibuffer_update minibuffer_update(alloc_fn frame_alloc) {
// TODO: multiline
if (g_minibuffer.nbytes == 0 && !g_minibuffer.dirty) {
return (struct minibuffer_update){.cmds = NULL, .ncmds = 0};
}
struct timespec current;
clock_gettime(CLOCK_MONOTONIC, ¤t);
if (current.tv_sec < g_minibuffer.expires.tv_sec) {
struct render_cmd *cmds =
(struct render_cmd *)frame_alloc(sizeof(struct render_cmd));
cmds[0].col = 0;
cmds[0].row = g_minibuffer.row;
cmds[0].data = g_minibuffer.buffer;
cmds[0].len = g_minibuffer.nbytes;
g_minibuffer.dirty = false;
return (struct minibuffer_update){
.cmds = cmds,
.ncmds = 1,
};
} else {
g_minibuffer.nbytes = 0;
g_minibuffer.dirty = false;
// send a clear draw command
struct render_cmd *cmds =
(struct render_cmd *)frame_alloc(sizeof(struct render_cmd));
cmds[0].col = 0;
cmds[0].row = g_minibuffer.row;
cmds[0].data = NULL;
cmds[0].len = 0;
return (struct minibuffer_update){
.cmds = cmds,
.ncmds = 1,
};
}
}
void echo(uint32_t timeout, const char *fmt, va_list args) {
size_t nbytes =
vsnprintf((char *)g_minibuffer.buffer, g_minibuffer.capacity, fmt, args);
// vsnprintf returns how many characters it would have wanted to write in case
// of overflow
g_minibuffer.nbytes =
nbytes > g_minibuffer.capacity ? g_minibuffer.capacity : nbytes;
g_minibuffer.dirty = true;
clock_gettime(CLOCK_MONOTONIC, &g_minibuffer.expires);
g_minibuffer.expires.tv_sec += timeout;
}
void minibuffer_echo(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
echo(1000, fmt, args);
va_end(args);
}
void minibuffer_echo_timeout(uint32_t timeout, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
echo(timeout, fmt, args);
va_end(args);
}
bool minibuffer_displaying() { return g_minibuffer.nbytes > 0; }
void minibuffer_clear() { g_minibuffer.expires.tv_nsec = 0; }
|