mirror of
https://github.com/tmux/tmux.git
synced 2024-11-18 10:28:54 +00:00
304 lines
7.1 KiB
C
304 lines
7.1 KiB
C
|
/* $OpenBSD$ */
|
||
|
|
||
|
/*
|
||
|
* Copyright (c) 2020 Anindya Mukherjee <anindya49@hotmail.com>
|
||
|
*
|
||
|
* Permission to use, copy, modify, and distribute this software for any
|
||
|
* purpose with or without fee is hereby granted, provided that the above
|
||
|
* copyright notice and this permission notice appear in all copies.
|
||
|
*
|
||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||
|
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||
|
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||
|
*/
|
||
|
|
||
|
#include "tmux.h"
|
||
|
|
||
|
/* Initialise virtual cursor. */
|
||
|
void
|
||
|
grid_reader_start(struct grid_reader *gr, struct grid *gd, u_int cx, u_int cy)
|
||
|
{
|
||
|
gr->gd = gd;
|
||
|
gr->cx = cx;
|
||
|
gr->cy = cy;
|
||
|
}
|
||
|
|
||
|
/* Get cursor position from reader. */
|
||
|
void
|
||
|
grid_reader_get_cursor(struct grid_reader *gr, u_int *cx, u_int *cy)
|
||
|
{
|
||
|
*cx = gr->cx;
|
||
|
*cy = gr->cy;
|
||
|
}
|
||
|
|
||
|
/* Get length of line containing the cursor. */
|
||
|
u_int
|
||
|
grid_reader_line_length(struct grid_reader *gr)
|
||
|
{
|
||
|
return (grid_line_length(gr->gd, gr->cy));
|
||
|
}
|
||
|
|
||
|
/* Move cursor forward one position. */
|
||
|
void
|
||
|
grid_reader_cursor_right(struct grid_reader *gr, int wrap, int all)
|
||
|
{
|
||
|
u_int px;
|
||
|
struct grid_cell gc;
|
||
|
|
||
|
if (all)
|
||
|
px = gr->gd->sx;
|
||
|
else
|
||
|
px = grid_reader_line_length(gr);
|
||
|
|
||
|
if (wrap && gr->cx >= px && gr->cy < gr->gd->hsize + gr->gd->sy - 1) {
|
||
|
grid_reader_cursor_start_of_line(gr, 0);
|
||
|
grid_reader_cursor_down(gr);
|
||
|
} else if (gr->cx < px) {
|
||
|
gr->cx++;
|
||
|
while (gr->cx < px) {
|
||
|
grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
|
||
|
if (~gc.flags & GRID_FLAG_PADDING)
|
||
|
break;
|
||
|
gr->cx++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Move cursor back one position. */
|
||
|
void
|
||
|
grid_reader_cursor_left(struct grid_reader *gr)
|
||
|
{
|
||
|
struct grid_cell gc;
|
||
|
|
||
|
while (gr->cx > 0) {
|
||
|
grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
|
||
|
if (~gc.flags & GRID_FLAG_PADDING)
|
||
|
break;
|
||
|
gr->cx--;
|
||
|
}
|
||
|
if (gr->cx == 0 && gr->cy > 0) {
|
||
|
grid_reader_cursor_up(gr);
|
||
|
grid_reader_cursor_end_of_line(gr, 0, 0);
|
||
|
} else if (gr->cx > 0)
|
||
|
gr->cx--;
|
||
|
}
|
||
|
|
||
|
/* Move cursor down one line. */
|
||
|
void
|
||
|
grid_reader_cursor_down(struct grid_reader *gr)
|
||
|
{
|
||
|
struct grid_cell gc;
|
||
|
|
||
|
if (gr->cy < gr->gd->hsize + gr->gd->sy - 1)
|
||
|
gr->cy++;
|
||
|
while (gr->cx > 0) {
|
||
|
grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
|
||
|
if (~gc.flags & GRID_FLAG_PADDING)
|
||
|
break;
|
||
|
gr->cx--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Move cursor up one line. */
|
||
|
void
|
||
|
grid_reader_cursor_up(struct grid_reader *gr)
|
||
|
{
|
||
|
struct grid_cell gc;
|
||
|
|
||
|
if (gr->cy > 0)
|
||
|
gr->cy--;
|
||
|
while (gr->cx > 0) {
|
||
|
grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
|
||
|
if (~gc.flags & GRID_FLAG_PADDING)
|
||
|
break;
|
||
|
gr->cx--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Move cursor to the start of the line. */
|
||
|
void
|
||
|
grid_reader_cursor_start_of_line(struct grid_reader *gr, int wrap)
|
||
|
{
|
||
|
if (wrap) {
|
||
|
while (gr->cy > 0 &&
|
||
|
grid_get_line(gr->gd, gr->cy - 1)->flags &
|
||
|
GRID_LINE_WRAPPED)
|
||
|
gr->cy--;
|
||
|
}
|
||
|
gr->cx = 0;
|
||
|
}
|
||
|
|
||
|
/* Move cursor to the end of the line. */
|
||
|
void
|
||
|
grid_reader_cursor_end_of_line(struct grid_reader *gr, int wrap, int all)
|
||
|
{
|
||
|
u_int yy;
|
||
|
|
||
|
if (wrap) {
|
||
|
yy = gr->gd->hsize + gr->gd->sy - 1;
|
||
|
while (gr->cy < yy && grid_get_line(gr->gd, gr->cy)->flags &
|
||
|
GRID_LINE_WRAPPED)
|
||
|
gr->cy++;
|
||
|
}
|
||
|
if (all)
|
||
|
gr->cx = gr->gd->sx;
|
||
|
else
|
||
|
gr->cx = grid_reader_line_length(gr);
|
||
|
}
|
||
|
|
||
|
/* Check if character under cursor is in set. */
|
||
|
int
|
||
|
grid_reader_in_set(struct grid_reader *gr, const char *set)
|
||
|
{
|
||
|
struct grid_cell gc;
|
||
|
|
||
|
grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
|
||
|
if (gc.flags & GRID_FLAG_PADDING)
|
||
|
return (0);
|
||
|
return (utf8_cstrhas(set, &gc.data));
|
||
|
}
|
||
|
|
||
|
/* Move cursor to the start of the next word. */
|
||
|
void
|
||
|
grid_reader_cursor_next_word(struct grid_reader *gr, const char *separators)
|
||
|
{
|
||
|
u_int xx, yy;
|
||
|
int expected = 0;
|
||
|
|
||
|
/* Do not break up wrapped words. */
|
||
|
if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED)
|
||
|
xx = grid_reader_line_length(gr) - 1;
|
||
|
else
|
||
|
xx = grid_reader_line_length(gr);
|
||
|
yy = gr->gd->hsize + gr->gd->sy - 1;
|
||
|
|
||
|
/*
|
||
|
* If we started inside a word, skip over word characters. Then skip
|
||
|
* over separators till the next word.
|
||
|
*
|
||
|
* expected is initially set to 0 for the former and then 1 for the
|
||
|
* latter. It is finally set to 0 when the beginning of the next word is
|
||
|
* found.
|
||
|
*/
|
||
|
do {
|
||
|
while (gr->cx > xx ||
|
||
|
grid_reader_in_set(gr, separators) == expected) {
|
||
|
/* Move down if we are past the end of the line. */
|
||
|
if (gr->cx > xx) {
|
||
|
if (gr->cy == yy)
|
||
|
return;
|
||
|
grid_reader_cursor_start_of_line(gr, 0);
|
||
|
grid_reader_cursor_down(gr);
|
||
|
|
||
|
if (grid_get_line(gr->gd, gr->cy)->flags &
|
||
|
GRID_LINE_WRAPPED)
|
||
|
xx = grid_reader_line_length(gr) - 1;
|
||
|
else
|
||
|
xx = grid_reader_line_length(gr);
|
||
|
} else
|
||
|
gr->cx++;
|
||
|
}
|
||
|
expected = !expected;
|
||
|
} while (expected == 1);
|
||
|
}
|
||
|
|
||
|
/* Move cursor to the end of the next word. */
|
||
|
void
|
||
|
grid_reader_cursor_next_word_end(struct grid_reader *gr, const char *separators)
|
||
|
{
|
||
|
u_int xx, yy;
|
||
|
int expected = 1;
|
||
|
|
||
|
/* Do not break up wrapped words. */
|
||
|
if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED)
|
||
|
xx = grid_reader_line_length(gr) - 1;
|
||
|
else
|
||
|
xx = grid_reader_line_length(gr);
|
||
|
yy = gr->gd->hsize + gr->gd->sy - 1;
|
||
|
|
||
|
/*
|
||
|
* If we started on a separator, skip over separators. Then skip over
|
||
|
* word characters till the next separator.
|
||
|
*
|
||
|
* expected is initially set to 1 for the former and then 1 for the
|
||
|
* latter. It is finally set to 1 when the end of the next word is
|
||
|
* found.
|
||
|
*/
|
||
|
do {
|
||
|
while (gr->cx > xx ||
|
||
|
grid_reader_in_set(gr, separators) == expected) {
|
||
|
/* Move down if we are past the end of the line. */
|
||
|
if (gr->cx > xx) {
|
||
|
if (gr->cy == yy)
|
||
|
return;
|
||
|
grid_reader_cursor_start_of_line(gr, 0);
|
||
|
grid_reader_cursor_down(gr);
|
||
|
|
||
|
if (grid_get_line(gr->gd, gr->cy)->flags &
|
||
|
GRID_LINE_WRAPPED)
|
||
|
xx = grid_reader_line_length(gr) - 1;
|
||
|
else
|
||
|
xx = grid_reader_line_length(gr);
|
||
|
} else
|
||
|
gr->cx++;
|
||
|
}
|
||
|
expected = !expected;
|
||
|
} while (expected == 0);
|
||
|
}
|
||
|
|
||
|
/* Move to the previous place where a word begins. */
|
||
|
void
|
||
|
grid_reader_cursor_previous_word(struct grid_reader *gr, const char *separators,
|
||
|
int already)
|
||
|
{
|
||
|
int oldx, oldy, r;
|
||
|
|
||
|
/* Move back to the previous word character. */
|
||
|
if (already || grid_reader_in_set(gr, separators)) {
|
||
|
for (;;) {
|
||
|
if (gr->cx > 0) {
|
||
|
gr->cx--;
|
||
|
if (!grid_reader_in_set(gr, separators))
|
||
|
break;
|
||
|
} else {
|
||
|
if (gr->cy == 0)
|
||
|
return;
|
||
|
grid_reader_cursor_up(gr);
|
||
|
grid_reader_cursor_end_of_line(gr, 0, 0);
|
||
|
|
||
|
/* Stop if separator at EOL. */
|
||
|
if (gr->cx > 0) {
|
||
|
oldx = gr->cx;
|
||
|
gr->cx--;
|
||
|
r = grid_reader_in_set(gr, separators);
|
||
|
gr->cx = oldx;
|
||
|
if (r)
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Move back to the beginning of this word. */
|
||
|
do {
|
||
|
oldx = gr->cx;
|
||
|
oldy = gr->cy;
|
||
|
if (gr->cx == 0) {
|
||
|
if (gr->cy == 0 ||
|
||
|
~grid_get_line(gr->gd, gr->cy - 1)->flags &
|
||
|
GRID_LINE_WRAPPED)
|
||
|
break;
|
||
|
grid_reader_cursor_up(gr);
|
||
|
grid_reader_cursor_end_of_line(gr, 0, 0);
|
||
|
}
|
||
|
if (gr->cx > 0)
|
||
|
gr->cx--;
|
||
|
} while (!grid_reader_in_set(gr, separators));
|
||
|
gr->cx = oldx;
|
||
|
gr->cy = oldy;
|
||
|
}
|