Blame


1 65d9b3ca 2021-03-14 op /*
2 65d9b3ca 2021-03-14 op * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
3 65d9b3ca 2021-03-14 op *
4 65d9b3ca 2021-03-14 op * Permission to use, copy, modify, and distribute this software for any
5 65d9b3ca 2021-03-14 op * purpose with or without fee is hereby granted, provided that the above
6 65d9b3ca 2021-03-14 op * copyright notice and this permission notice appear in all copies.
7 65d9b3ca 2021-03-14 op *
8 65d9b3ca 2021-03-14 op * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 65d9b3ca 2021-03-14 op * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 65d9b3ca 2021-03-14 op * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 65d9b3ca 2021-03-14 op * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 65d9b3ca 2021-03-14 op * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 65d9b3ca 2021-03-14 op * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 65d9b3ca 2021-03-14 op * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 65d9b3ca 2021-03-14 op */
16 65d9b3ca 2021-03-14 op
17 65d9b3ca 2021-03-14 op #include "telescope.h"
18 65d9b3ca 2021-03-14 op
19 65d9b3ca 2021-03-14 op #include <stdlib.h>
20 65d9b3ca 2021-03-14 op #include <string.h>
21 65d9b3ca 2021-03-14 op
22 65d9b3ca 2021-03-14 op /*
23 65d9b3ca 2021-03-14 op * Text wrapping
24 65d9b3ca 2021-03-14 op * =============
25 65d9b3ca 2021-03-14 op *
26 65d9b3ca 2021-03-14 op * There's a simple text wrapping algorithm.
27 65d9b3ca 2021-03-14 op *
28 65d9b3ca 2021-03-14 op * 1. if it's a line in a pre-formatted block:
29 65d9b3ca 2021-03-14 op * a. hard wrap.
30 65d9b3ca 2021-03-14 op * b. repeat
31 676fba6f 2021-03-21 op * 2. otherwise advance the line char by char.
32 676fba6f 2021-03-21 op * 3. when ending the space, split the line at the last occurrence of
33 676fba6f 2021-03-21 op * a "word separator" (i.e. " \t-") or at point if none.
34 65d9b3ca 2021-03-14 op * 4. repeat
35 65d9b3ca 2021-03-14 op *
36 65d9b3ca 2021-03-14 op */
37 65d9b3ca 2021-03-14 op
38 65d9b3ca 2021-03-14 op static int
39 2ba66cea 2021-03-22 op push_line(struct window *window, const struct line *l, const char *buf, size_t len, int cont)
40 65d9b3ca 2021-03-14 op {
41 65d9b3ca 2021-03-14 op struct vline *vl;
42 65d9b3ca 2021-03-14 op
43 2ba66cea 2021-03-22 op window->line_max++;
44 65d9b3ca 2021-03-14 op
45 65d9b3ca 2021-03-14 op if ((vl = calloc(1, sizeof(*vl))) == NULL)
46 65d9b3ca 2021-03-14 op return 0;
47 65d9b3ca 2021-03-14 op
48 65d9b3ca 2021-03-14 op if (len != 0 && (vl->line = calloc(1, len+1)) == NULL) {
49 65d9b3ca 2021-03-14 op free(vl);
50 65d9b3ca 2021-03-14 op return 0;
51 65d9b3ca 2021-03-14 op }
52 65d9b3ca 2021-03-14 op
53 65d9b3ca 2021-03-14 op vl->parent = l;
54 65d9b3ca 2021-03-14 op if (len != 0)
55 65d9b3ca 2021-03-14 op memcpy(vl->line, buf, len);
56 65d9b3ca 2021-03-14 op vl->flags = cont;
57 65d9b3ca 2021-03-14 op
58 2ba66cea 2021-03-22 op if (TAILQ_EMPTY(&window->head))
59 2ba66cea 2021-03-22 op TAILQ_INSERT_HEAD(&window->head, vl, vlines);
60 65d9b3ca 2021-03-14 op else
61 2ba66cea 2021-03-22 op TAILQ_INSERT_TAIL(&window->head, vl, vlines);
62 65d9b3ca 2021-03-14 op return 1;
63 65d9b3ca 2021-03-14 op }
64 65d9b3ca 2021-03-14 op
65 65d9b3ca 2021-03-14 op /*
66 65d9b3ca 2021-03-14 op * Build a list of visual line by wrapping the given line, assuming
67 65d9b3ca 2021-03-14 op * that when printed will have a leading prefix prfx.
68 65d9b3ca 2021-03-14 op */
69 676fba6f 2021-03-21 op int
70 2ba66cea 2021-03-22 op wrap_text(struct window *window, const char *prfx, struct line *l, size_t width)
71 65d9b3ca 2021-03-14 op {
72 676fba6f 2021-03-21 op const char *separators = " \t-";
73 676fba6f 2021-03-21 op const char *start, *end, *line, *lastsep, *lastchar;
74 676fba6f 2021-03-21 op uint32_t cp = 0, state = 0;
75 676fba6f 2021-03-21 op size_t cur, prfxwidth, w;
76 676fba6f 2021-03-21 op int cont;
77 65d9b3ca 2021-03-14 op
78 676fba6f 2021-03-21 op if ((line = l->line) == NULL)
79 2ba66cea 2021-03-22 op return push_line(window, l, NULL, 0, 0);
80 65d9b3ca 2021-03-14 op
81 676fba6f 2021-03-21 op prfxwidth = utf8_swidth(prfx);
82 676fba6f 2021-03-21 op cur = prfxwidth;
83 676fba6f 2021-03-21 op start = line;
84 676fba6f 2021-03-21 op lastsep = NULL;
85 676fba6f 2021-03-21 op lastchar = line;
86 676fba6f 2021-03-21 op cont = 0;
87 676fba6f 2021-03-21 op for (; *line; line++) {
88 676fba6f 2021-03-21 op if (utf8_decode(&state, &cp, *line))
89 676fba6f 2021-03-21 op continue;
90 676fba6f 2021-03-21 op w = utf8_chwidth(cp);
91 676fba6f 2021-03-21 op if (cur + w >= width -1) {
92 676fba6f 2021-03-21 op end = lastsep == NULL
93 676fba6f 2021-03-21 op ? utf8_next_cp((char*)lastchar)
94 676fba6f 2021-03-21 op : utf8_next_cp((char*)lastsep);
95 2ba66cea 2021-03-22 op if (!push_line(window, l, start, end - start, cont))
96 676fba6f 2021-03-21 op return 0;
97 676fba6f 2021-03-21 op cont = 1;
98 676fba6f 2021-03-21 op start = end;
99 676fba6f 2021-03-21 op cur = prfxwidth + utf8_swidth_between(start, lastchar);
100 676fba6f 2021-03-21 op } else {
101 676fba6f 2021-03-21 op if (strchr(separators, *line) != NULL)
102 676fba6f 2021-03-21 op lastsep = line;
103 65d9b3ca 2021-03-14 op }
104 65d9b3ca 2021-03-14 op
105 676fba6f 2021-03-21 op lastchar = utf8_prev_cp(line, l->line);
106 676fba6f 2021-03-21 op cur += w;
107 65d9b3ca 2021-03-14 op }
108 65d9b3ca 2021-03-14 op
109 2ba66cea 2021-03-22 op return push_line(window, l, start, line - start, cont);
110 65d9b3ca 2021-03-14 op }
111 65d9b3ca 2021-03-14 op
112 65d9b3ca 2021-03-14 op int
113 2ba66cea 2021-03-22 op hardwrap_text(struct window *window, struct line *l, size_t width)
114 65d9b3ca 2021-03-14 op {
115 676fba6f 2021-03-21 op const char *line, *start, *lastchar;
116 65d9b3ca 2021-03-14 op int cont;
117 676fba6f 2021-03-21 op uint32_t state = 0, cp = 0;
118 676fba6f 2021-03-21 op size_t cur, w;
119 65d9b3ca 2021-03-14 op
120 676fba6f 2021-03-21 op if ((line = l->line) == NULL)
121 2ba66cea 2021-03-22 op return push_line(window, l, NULL, 0, 0);
122 166712b4 2021-03-14 op
123 676fba6f 2021-03-21 op start = line;
124 676fba6f 2021-03-21 op lastchar = line;
125 676fba6f 2021-03-21 op cont = 0;
126 676fba6f 2021-03-21 op cur = 0;
127 676fba6f 2021-03-21 op for (; *line; line++) {
128 676fba6f 2021-03-21 op if (utf8_decode(&state, &cp, *line))
129 676fba6f 2021-03-21 op continue;
130 676fba6f 2021-03-21 op w = utf8_chwidth(cp);
131 676fba6f 2021-03-21 op if (cur + w >= width) {
132 2ba66cea 2021-03-22 op if (!push_line(window, l, start, lastchar - start, cont))
133 676fba6f 2021-03-21 op return 0;
134 676fba6f 2021-03-21 op cont = 1;
135 676fba6f 2021-03-21 op cur = 0;
136 676fba6f 2021-03-21 op start = lastchar;
137 676fba6f 2021-03-21 op }
138 65d9b3ca 2021-03-14 op
139 676fba6f 2021-03-21 op lastchar = utf8_prev_cp(line, l->line);
140 676fba6f 2021-03-21 op cur += w;
141 65d9b3ca 2021-03-14 op }
142 65d9b3ca 2021-03-14 op
143 2ba66cea 2021-03-22 op return push_line(window, l, start, line - start, cont);
144 65d9b3ca 2021-03-14 op }