"Fossies" - the Fresh Open Source Software Archive

Member "tmux-3.2a/grid-reader.c" (10 Jun 2021, 9276 Bytes) of package /linux/misc/tmux-3.2a.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "grid-reader.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.2_vs_3.2a.

    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
   41 grid_reader_line_length(struct grid_reader *gr)
   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) {
   59         grid_reader_cursor_start_of_line(gr, 0);
   60         grid_reader_cursor_down(gr);
   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)) {
   87         grid_reader_cursor_up(gr);
   88         grid_reader_cursor_end_of_line(gr, 0, 0);
   89     } else if (gr->cx > 0)
   90         gr->cx--;
   91 }
   92 
   93 /* Move cursor down one line. */
   94 void
   95 grid_reader_cursor_down(struct grid_reader *gr)
   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
  111 grid_reader_cursor_up(struct grid_reader *gr)
  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
  127 grid_reader_cursor_start_of_line(struct grid_reader *gr, int wrap)
  128 {
  129     if (wrap) {
  130         while (gr->cy > 0 &&
  131             grid_get_line(gr->gd, gr->cy - 1)->flags &
  132                 GRID_LINE_WRAPPED)
  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 &
  147             GRID_LINE_WRAPPED)
  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;
  197                 grid_reader_cursor_start_of_line(gr, 0);
  198                 grid_reader_cursor_down(gr);
  199 
  200                 if (grid_get_line(gr->gd, gr->cy)->flags &
  201                     GRID_LINE_WRAPPED)
  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;
  241                 grid_reader_cursor_start_of_line(gr, 0);
  242                 grid_reader_cursor_down(gr);
  243 
  244                 if (grid_get_line(gr->gd, gr->cy)->flags &
  245                     GRID_LINE_WRAPPED)
  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;
  273                 grid_reader_cursor_up(gr);
  274                 grid_reader_cursor_end_of_line(gr, 0, 0);
  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 &
  296               GRID_LINE_WRAPPED)
  297                 break;
  298             grid_reader_cursor_up(gr);
  299             grid_reader_cursor_end_of_line(gr, 0, 1);
  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
  342 grid_reader_cursor_jump_back(struct grid_reader *gr, const struct utf8_data *jc)
  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
  371 grid_reader_cursor_back_to_indentation(struct grid_reader *gr)
  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;
  379     grid_reader_cursor_start_of_line(gr, 1);
  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 }