tmux  3.2a
About: tmux is a terminal multiplexer that lets you switch easily between several programs in one terminal.
  Fossies Dox: tmux-3.2a.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

grid-reader.c
Go to the documentation of this file.
1 /* $OpenBSD$ */
2 
3 /*
4  * Copyright (c) 2020 Anindya Mukherjee <anindya49@hotmail.com>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include "tmux.h"
20 #include <string.h>
21 
22 /* Initialise virtual cursor. */
23 void
24 grid_reader_start(struct grid_reader *gr, struct grid *gd, u_int cx, u_int cy)
25 {
26  gr->gd = gd;
27  gr->cx = cx;
28  gr->cy = cy;
29 }
30 
31 /* Get cursor position from reader. */
32 void
33 grid_reader_get_cursor(struct grid_reader *gr, u_int *cx, u_int *cy)
34 {
35  *cx = gr->cx;
36  *cy = gr->cy;
37 }
38 
39 /* Get length of line containing the cursor. */
40 u_int
42 {
43  return (grid_line_length(gr->gd, gr->cy));
44 }
45 
46 /* Move cursor forward one position. */
47 void
48 grid_reader_cursor_right(struct grid_reader *gr, int wrap, int all)
49 {
50  u_int px;
51  struct grid_cell gc;
52 
53  if (all)
54  px = gr->gd->sx;
55  else
56  px = grid_reader_line_length(gr);
57 
58  if (wrap && gr->cx >= px && gr->cy < gr->gd->hsize + gr->gd->sy - 1) {
61  } else if (gr->cx < px) {
62  gr->cx++;
63  while (gr->cx < px) {
64  grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
65  if (~gc.flags & GRID_FLAG_PADDING)
66  break;
67  gr->cx++;
68  }
69  }
70 }
71 
72 /* Move cursor back one position. */
73 void
74 grid_reader_cursor_left(struct grid_reader *gr, int wrap)
75 {
76  struct grid_cell gc;
77 
78  while (gr->cx > 0) {
79  grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
80  if (~gc.flags & GRID_FLAG_PADDING)
81  break;
82  gr->cx--;
83  }
84  if (gr->cx == 0 && gr->cy > 0 &&
85  (wrap ||
86  grid_get_line(gr->gd, gr->cy - 1)->flags & GRID_LINE_WRAPPED)) {
89  } else if (gr->cx > 0)
90  gr->cx--;
91 }
92 
93 /* Move cursor down one line. */
94 void
96 {
97  struct grid_cell gc;
98 
99  if (gr->cy < gr->gd->hsize + gr->gd->sy - 1)
100  gr->cy++;
101  while (gr->cx > 0) {
102  grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
103  if (~gc.flags & GRID_FLAG_PADDING)
104  break;
105  gr->cx--;
106  }
107 }
108 
109 /* Move cursor up one line. */
110 void
112 {
113  struct grid_cell gc;
114 
115  if (gr->cy > 0)
116  gr->cy--;
117  while (gr->cx > 0) {
118  grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
119  if (~gc.flags & GRID_FLAG_PADDING)
120  break;
121  gr->cx--;
122  }
123 }
124 
125 /* Move cursor to the start of the line. */
126 void
128 {
129  if (wrap) {
130  while (gr->cy > 0 &&
131  grid_get_line(gr->gd, gr->cy - 1)->flags &
133  gr->cy--;
134  }
135  gr->cx = 0;
136 }
137 
138 /* Move cursor to the end of the line. */
139 void
140 grid_reader_cursor_end_of_line(struct grid_reader *gr, int wrap, int all)
141 {
142  u_int yy;
143 
144  if (wrap) {
145  yy = gr->gd->hsize + gr->gd->sy - 1;
146  while (gr->cy < yy && grid_get_line(gr->gd, gr->cy)->flags &
148  gr->cy++;
149  }
150  if (all)
151  gr->cx = gr->gd->sx;
152  else
153  gr->cx = grid_reader_line_length(gr);
154 }
155 
156 /* Check if character under cursor is in set. */
157 int
158 grid_reader_in_set(struct grid_reader *gr, const char *set)
159 {
160  struct grid_cell gc;
161 
162  grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
163  if (gc.flags & GRID_FLAG_PADDING)
164  return (0);
165  return (utf8_cstrhas(set, &gc.data));
166 }
167 
168 /* Move cursor to the start of the next word. */
169 void
170 grid_reader_cursor_next_word(struct grid_reader *gr, const char *separators)
171 {
172  u_int xx, yy;
173  int expected = 0;
174 
175  /* Do not break up wrapped words. */
176  if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED)
177  xx = gr->gd->sx - 1;
178  else
179  xx = grid_reader_line_length(gr);
180  yy = gr->gd->hsize + gr->gd->sy - 1;
181 
182  /*
183  * If we started inside a word, skip over word characters. Then skip
184  * over separators till the next word.
185  *
186  * expected is initially set to 0 for the former and then 1 for the
187  * latter. It is finally set to 0 when the beginning of the next word is
188  * found.
189  */
190  do {
191  while (gr->cx > xx ||
192  grid_reader_in_set(gr, separators) == expected) {
193  /* Move down if we are past the end of the line. */
194  if (gr->cx > xx) {
195  if (gr->cy == yy)
196  return;
199 
200  if (grid_get_line(gr->gd, gr->cy)->flags &
202  xx = gr->gd->sx - 1;
203  else
204  xx = grid_reader_line_length(gr);
205  } else
206  gr->cx++;
207  }
208  expected = !expected;
209  } while (expected == 1);
210 }
211 
212 /* Move cursor to the end of the next word. */
213 void
214 grid_reader_cursor_next_word_end(struct grid_reader *gr, const char *separators)
215 {
216  u_int xx, yy;
217  int expected = 1;
218 
219  /* Do not break up wrapped words. */
220  if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED)
221  xx = gr->gd->sx - 1;
222  else
223  xx = grid_reader_line_length(gr);
224  yy = gr->gd->hsize + gr->gd->sy - 1;
225 
226  /*
227  * If we started on a separator, skip over separators. Then skip over
228  * word characters till the next separator.
229  *
230  * expected is initially set to 1 for the former and then 1 for the
231  * latter. It is finally set to 1 when the end of the next word is
232  * found.
233  */
234  do {
235  while (gr->cx > xx ||
236  grid_reader_in_set(gr, separators) == expected) {
237  /* Move down if we are past the end of the line. */
238  if (gr->cx > xx) {
239  if (gr->cy == yy)
240  return;
243 
244  if (grid_get_line(gr->gd, gr->cy)->flags &
246  xx = gr->gd->sx - 1;
247  else
248  xx = grid_reader_line_length(gr);
249  } else
250  gr->cx++;
251  }
252  expected = !expected;
253  } while (expected == 0);
254 }
255 
256 /* Move to the previous place where a word begins. */
257 void
258 grid_reader_cursor_previous_word(struct grid_reader *gr, const char *separators,
259  int already)
260 {
261  int oldx, oldy, r;
262 
263  /* Move back to the previous word character. */
264  if (already || grid_reader_in_set(gr, separators)) {
265  for (;;) {
266  if (gr->cx > 0) {
267  gr->cx--;
268  if (!grid_reader_in_set(gr, separators))
269  break;
270  } else {
271  if (gr->cy == 0)
272  return;
275 
276  /* Stop if separator at EOL. */
277  if (gr->cx > 0) {
278  oldx = gr->cx;
279  gr->cx--;
280  r = grid_reader_in_set(gr, separators);
281  gr->cx = oldx;
282  if (r)
283  break;
284  }
285  }
286  }
287  }
288 
289  /* Move back to the beginning of this word. */
290  do {
291  oldx = gr->cx;
292  oldy = gr->cy;
293  if (gr->cx == 0) {
294  if (gr->cy == 0 ||
295  ~grid_get_line(gr->gd, gr->cy - 1)->flags &
297  break;
300  }
301  if (gr->cx > 0)
302  gr->cx--;
303  } while (!grid_reader_in_set(gr, separators));
304  gr->cx = oldx;
305  gr->cy = oldy;
306 }
307 
308 /* Jump forward to character. */
309 int
310 grid_reader_cursor_jump(struct grid_reader *gr, const struct utf8_data *jc)
311 {
312  struct grid_cell gc;
313  u_int px, py, xx, yy;
314 
315  px = gr->cx;
316  yy = gr->gd->hsize + gr->gd->sy - 1;
317 
318  for (py = gr->cy; py <= yy; py++) {
319  xx = grid_line_length(gr->gd, py);
320  while (px < xx) {
321  grid_get_cell(gr->gd, px, py, &gc);
322  if (!(gc.flags & GRID_FLAG_PADDING) &&
323  gc.data.size == jc->size &&
324  memcmp(gc.data.data, jc->data, gc.data.size) == 0) {
325  gr->cx = px;
326  gr->cy = py;
327  return 1;
328  }
329  px++;
330  }
331 
332  if (py == yy ||
333  !(grid_get_line(gr->gd, py)->flags & GRID_LINE_WRAPPED))
334  return 0;
335  px = 0;
336  }
337  return 0;
338 }
339 
340 /* Jump back to character. */
341 int
343 {
344  struct grid_cell gc;
345  u_int px, py, xx;
346 
347  xx = gr->cx + 1;
348 
349  for (py = gr->cy + 1; py > 0; py--) {
350  for (px = xx; px > 0; px--) {
351  grid_get_cell(gr->gd, px - 1, py - 1, &gc);
352  if (!(gc.flags & GRID_FLAG_PADDING) &&
353  gc.data.size == jc->size &&
354  memcmp(gc.data.data, jc->data, gc.data.size) == 0) {
355  gr->cx = px - 1;
356  gr->cy = py - 1;
357  return 1;
358  }
359  }
360 
361  if (py == 1 ||
362  !(grid_get_line(gr->gd, py - 2)->flags & GRID_LINE_WRAPPED))
363  return 0;
364  xx = grid_line_length(gr->gd, py - 2);
365  }
366  return 0;
367 }
368 
369 /* Jump back to the first non-blank character of the line. */
370 void
372 {
373  struct grid_cell gc;
374  u_int px, py, xx, yy, oldx, oldy;
375 
376  yy = gr->gd->hsize + gr->gd->sy - 1;
377  oldx = gr->cx;
378  oldy = gr->cy;
380 
381  for (py = gr->cy; py <= yy; py++) {
382  xx = grid_line_length(gr->gd, py);
383  for (px = 0; px < xx; px++) {
384  grid_get_cell(gr->gd, px, py, &gc);
385  if (gc.data.size != 1 || *gc.data.data != ' ') {
386  gr->cx = px;
387  gr->cy = py;
388  return;
389  }
390  }
391  if (~grid_get_line(gr->gd, py)->flags & GRID_LINE_WRAPPED)
392  break;
393  }
394  gr->cx = oldx;
395  gr->cy = oldy;
396 }
u_int grid_reader_line_length(struct grid_reader *gr)
Definition: grid-reader.c:41
void grid_reader_get_cursor(struct grid_reader *gr, u_int *cx, u_int *cy)
Definition: grid-reader.c:33
void grid_reader_cursor_end_of_line(struct grid_reader *gr, int wrap, int all)
Definition: grid-reader.c:140
void grid_reader_cursor_back_to_indentation(struct grid_reader *gr)
Definition: grid-reader.c:371
int grid_reader_cursor_jump_back(struct grid_reader *gr, const struct utf8_data *jc)
Definition: grid-reader.c:342
int grid_reader_in_set(struct grid_reader *gr, const char *set)
Definition: grid-reader.c:158
void grid_reader_cursor_right(struct grid_reader *gr, int wrap, int all)
Definition: grid-reader.c:48
void grid_reader_cursor_up(struct grid_reader *gr)
Definition: grid-reader.c:111
int grid_reader_cursor_jump(struct grid_reader *gr, const struct utf8_data *jc)
Definition: grid-reader.c:310
void grid_reader_cursor_next_word(struct grid_reader *gr, const char *separators)
Definition: grid-reader.c:170
void grid_reader_cursor_down(struct grid_reader *gr)
Definition: grid-reader.c:95
void grid_reader_cursor_left(struct grid_reader *gr, int wrap)
Definition: grid-reader.c:74
void grid_reader_cursor_previous_word(struct grid_reader *gr, const char *separators, int already)
Definition: grid-reader.c:258
void grid_reader_cursor_next_word_end(struct grid_reader *gr, const char *separators)
Definition: grid-reader.c:214
void grid_reader_start(struct grid_reader *gr, struct grid *gd, u_int cx, u_int cy)
Definition: grid-reader.c:24
void grid_reader_cursor_start_of_line(struct grid_reader *gr, int wrap)
Definition: grid-reader.c:127
void grid_get_cell(struct grid *gd, u_int px, u_int py, struct grid_cell *gc)
Definition: grid.c:529
struct grid_line * grid_get_line(struct grid *gd, u_int line)
Definition: grid.c:181
u_int grid_line_length(struct grid *gd, u_int py)
Definition: grid.c:1414
u_char flags
Definition: tmux.h:691
struct utf8_data data
Definition: tmux.h:689
int flags
Definition: tmux.h:730
u_int cy
Definition: tmux.h:752
struct grid * gd
Definition: tmux.h:750
u_int cx
Definition: tmux.h:751
Definition: tmux.h:734
u_int hsize
Definition: tmux.h:742
u_int sy
Definition: tmux.h:739
u_int sx
Definition: tmux.h:738
u_char data[21]
Definition: tmux.h:629
u_char size
Definition: tmux.h:632
#define GRID_FLAG_PADDING
Definition: tmux.h:676
int utf8_cstrhas(const char *, const struct utf8_data *)
Definition: utf8.c:584
#define GRID_LINE_WRAPPED
Definition: tmux.h:683