Manual pages: mcmcdiffmceditmcview

root/src/editor/editdraw.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. printwstr
  2. format_character_code
  3. status_string
  4. edit_status_fullscreen
  5. edit_status_window
  6. edit_draw_frame
  7. edit_draw_window_icons
  8. print_to_widget
  9. edit_draw_this_line
  10. edit_draw_this_char
  11. render_edit_text
  12. edit_render
  13. edit_status
  14. edit_scroll_screen_over_cursor
  15. edit_render_keypress

   1 /*
   2    Editor text drawing.
   3 
   4    Copyright (C) 1996-2025
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Paul Sheer, 1996, 1997
   9    Andrew Borodin <aborodin@vmail.ru> 2012-2022
  10    Slava Zanko <slavazanko@gmail.com>, 2013
  11 
  12    This file is part of the Midnight Commander.
  13 
  14    The Midnight Commander is free software: you can redistribute it
  15    and/or modify it under the terms of the GNU General Public License as
  16    published by the Free Software Foundation, either version 3 of the License,
  17    or (at your option) any later version.
  18 
  19    The Midnight Commander is distributed in the hope that it will be useful,
  20    but WITHOUT ANY WARRANTY; without even the implied warranty of
  21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22    GNU General Public License for more details.
  23 
  24    You should have received a copy of the GNU General Public License
  25    along with this program.  If not, see <https://www.gnu.org/licenses/>.
  26  */
  27 
  28 /** \file
  29  *  \brief Source: editor text drawing
  30  *  \author Paul Sheer
  31  *  \date 1996, 1997
  32  */
  33 
  34 #include <config.h>
  35 #include <stdlib.h>
  36 #include <stdio.h>
  37 #include <stdarg.h>
  38 #include <sys/types.h>
  39 #include <unistd.h>
  40 #include <string.h>
  41 #include <ctype.h>
  42 #include <sys/stat.h>
  43 
  44 #include "lib/global.h"
  45 #include "lib/tty/tty.h"  // tty_printf()
  46 #include "lib/tty/key.h"  // is_idle()
  47 #include "lib/skin.h"
  48 #include "lib/strutil.h"  // utf string functions
  49 #include "lib/util.h"     // is_printable()
  50 #include "lib/widget.h"
  51 #include "lib/charsets.h"
  52 
  53 #include "edit-impl.h"
  54 #include "editwidget.h"
  55 
  56 /*** global variables ****************************************************************************/
  57 
  58 /*** file scope macro definitions ****************************************************************/
  59 
  60 #define MAX_LINE_LEN 1024
  61 
  62 /* Text styles */
  63 #define MOD_ABNORMAL                  (1 << 8)
  64 #define MOD_BOLD                      (1 << 9)
  65 #define MOD_MARKED                    (1 << 10)
  66 #define MOD_CURSOR                    (1 << 11)
  67 #define MOD_WHITESPACE                (1 << 12)
  68 
  69 #define edit_move(x, y)               widget_gotoyx (edit, y, x);
  70 
  71 #define key_pending(x)                (!is_idle ())
  72 
  73 #define EDITOR_MINIMUM_TERMINAL_WIDTH 30
  74 
  75 /*** file scope type declarations ****************************************************************/
  76 
  77 typedef struct
  78 {
  79     unsigned int ch;
  80     unsigned int style;
  81 } line_s;
  82 
  83 /*** forward declarations (file scope functions) *************************************************/
  84 
  85 /*** file scope variables ************************************************************************/
  86 
  87 /*** file scope functions ************************************************************************/
  88 
  89 static inline void
  90 printwstr (const char *s, int len)
     /* [previous][next][first][last][top][bottom][index][help]  */
  91 {
  92     if (len > 0)
  93         tty_printf ("%-*.*s", len, len, s);
  94 }
  95 
  96 /* --------------------------------------------------------------------------------------------- */
  97 
  98 #define CHAR_CODE_BUF_SIZE BUF_TINY
  99 
 100 static char *
 101 format_character_code (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 102 {
 103     char *buf;
 104 
 105     buf = g_malloc (CHAR_CODE_BUF_SIZE);
 106 
 107     if (edit->buffer.curs1 >= edit->buffer.size)
 108         strncpy (buf, "<EOF>   ", CHAR_CODE_BUF_SIZE);
 109     else if (edit->utf8)
 110     {
 111         unsigned int cur_utf;
 112         int char_length = 0;
 113 
 114         cur_utf = edit_buffer_get_utf (&edit->buffer, edit->buffer.curs1, &char_length);
 115         if (char_length > 0)
 116             if (cur_utf < 128)
 117                 g_snprintf (buf, CHAR_CODE_BUF_SIZE, "%3u 0x%02X", cur_utf, cur_utf);
 118             else
 119             {
 120                 char uplus[CHAR_CODE_BUF_SIZE];
 121                 g_snprintf (uplus, CHAR_CODE_BUF_SIZE, "U+%04X", cur_utf);
 122                 g_snprintf (buf, CHAR_CODE_BUF_SIZE, "%8s", uplus);
 123             }
 124         else
 125         {
 126             // cursor is over some invalid UTF-8 fragment
 127             cur_utf = edit_buffer_get_current_byte (&edit->buffer);
 128             g_snprintf (buf, CHAR_CODE_BUF_SIZE, "%3u 0x%02X", cur_utf, cur_utf);
 129         }
 130     }
 131     else
 132     {
 133         unsigned int cur_byte;
 134 
 135         cur_byte = edit_buffer_get_current_byte (&edit->buffer);
 136         g_snprintf (buf, CHAR_CODE_BUF_SIZE, "%3u 0x%02X", cur_byte, cur_byte);
 137     }
 138 
 139     return buf;
 140 }
 141 
 142 #undef CHAR_CODE_BUF_SIZE
 143 
 144 /* --------------------------------------------------------------------------------------------- */
 145 
 146 static inline void
 147 status_string (WEdit *edit, char *s, int w)
     /* [previous][next][first][last][top][bottom][index][help]  */
 148 {
 149     char *character_code;
 150 
 151     character_code = format_character_code (edit);
 152 
 153     // The field lengths just prevent the status line from shortening too much
 154     if (edit_options.simple_statusbar)
 155         g_snprintf (s, w, "%c%c%c%c %3ld %5ld/%ld %6ld/%ld [%s] %s",
 156                     edit->mark1 != edit->mark2 ? (edit->column_highlight ? 'C' : 'B') : '-',  //
 157                     edit->modified != 0 ? 'M' : '-',                                          //
 158                     macro_index < 0 ? '-' : 'R',                                              //
 159                     edit->overwrite == 0 ? '-' : 'O',                                         //
 160                     edit->curs_col + edit->over_col,                                          //
 161                     edit->buffer.curs_line + 1,                                               //
 162                     edit->buffer.lines + 1,                                                   //
 163                     (long) edit->buffer.curs1,                                                //
 164                     (long) edit->buffer.size,                                                 //
 165                     character_code,
 166                     mc_global.source_codepage >= 0 ? get_codepage_id (mc_global.source_codepage)
 167                                                    : "");
 168     else
 169         g_snprintf (s, w, "[%c%c%c%c] %2ld L:[%3ld+%2ld %3ld/%3ld] *(%-4ld/%4ldb) [%s]  %s",
 170                     edit->mark1 != edit->mark2 ? (edit->column_highlight ? 'C' : 'B') : '-',  //
 171                     edit->modified != 0 ? 'M' : '-',                                          //
 172                     macro_index < 0 ? '-' : 'R',                                              //
 173                     edit->overwrite == 0 ? '-' : 'O',                                         //
 174                     edit->curs_col + edit->over_col,                                          //
 175                     edit->start_line + 1,                                                     //
 176                     edit->curs_row,                                                           //
 177                     edit->buffer.curs_line + 1,                                               //
 178                     edit->buffer.lines + 1,                                                   //
 179                     (long) edit->buffer.curs1,                                                //
 180                     (long) edit->buffer.size,                                                 //
 181                     character_code,
 182                     mc_global.source_codepage >= 0 ? get_codepage_id (mc_global.source_codepage)
 183                                                    : "");
 184 
 185     g_free (character_code);
 186 }
 187 
 188 /* --------------------------------------------------------------------------------------------- */
 189 /**
 190  * Draw the status line at the top of the screen for fullscreen editor window.
 191  *
 192  * @param edit  editor object
 193  * @param color color pair
 194  */
 195 
 196 static inline void
 197 edit_status_fullscreen (WEdit *edit, int color)
     /* [previous][next][first][last][top][bottom][index][help]  */
 198 {
 199     Widget *h = WIDGET (WIDGET (edit)->owner);
 200     const int w = h->rect.cols;
 201     const int gap = 3;        // between the filename and the status
 202     const int right_gap = 5;  // at the right end of the screen
 203     const int preferred_fname_len = 16;
 204     char *status;
 205     size_t status_size;
 206     int status_len;
 207     const char *fname = "";
 208     int fname_len;
 209 
 210     status_size = w + 1;
 211     status = g_malloc (status_size);
 212     status_string (edit, status, status_size);
 213     status_len = (int) str_term_width1 (status);
 214 
 215     if (edit->filename_vpath != NULL)
 216     {
 217         fname = vfs_path_get_last_path_str (edit->filename_vpath);
 218 
 219         if (!edit_options.state_full_filename)
 220             fname = x_basename (fname);
 221     }
 222 
 223     fname_len = str_term_width1 (fname);
 224     if (fname_len < preferred_fname_len)
 225         fname_len = preferred_fname_len;
 226 
 227     if (fname_len + gap + status_len + right_gap >= w)
 228     {
 229         if (preferred_fname_len + gap + status_len + right_gap >= w)
 230             fname_len = preferred_fname_len;
 231         else
 232             fname_len = w - (gap + status_len + right_gap);
 233         fname = str_trunc (fname, fname_len);
 234     }
 235 
 236     widget_gotoyx (h, 0, 0);
 237     tty_setcolor (color);
 238     printwstr (fname, fname_len + gap);
 239     printwstr (status, w - (fname_len + gap));
 240 
 241     if (edit_options.simple_statusbar && w > EDITOR_MINIMUM_TERMINAL_WIDTH)
 242     {
 243         int percent;
 244 
 245         percent = edit_buffer_calc_percent (&edit->buffer, edit->buffer.curs1);
 246         widget_gotoyx (h, 0, w - 6 - 6);
 247         tty_printf (" %3d%%", percent);
 248     }
 249 
 250     g_free (status);
 251 }
 252 
 253 /* --------------------------------------------------------------------------------------------- */
 254 /**
 255  * Draw status line for editor window if window is not in fullscreen mode.
 256  *
 257  * @param edit editor object
 258  */
 259 
 260 static inline void
 261 edit_status_window (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 262 {
 263     Widget *w = WIDGET (edit);
 264     int y, x;
 265     int cols = w->rect.cols;
 266 
 267     tty_setcolor (STATUSBAR_COLOR);
 268 
 269     if (cols > 5)
 270     {
 271         const char *fname;
 272 
 273         if (edit->filename_vpath != NULL)
 274         {
 275             fname = vfs_path_get_last_path_str (edit->filename_vpath);
 276 
 277             if (!edit_options.state_full_filename)
 278                 fname = x_basename (fname);
 279         }
 280         else
 281             fname = _ ("NoName");
 282 
 283         edit_move (2, 0);
 284         tty_printf ("[%s]", str_term_trim (fname, w->rect.cols - 8 - 6));
 285     }
 286 
 287     tty_getyx (&y, &x);
 288     x -= w->rect.x;
 289     x += 4;
 290     if (x + 6 <= cols - 2 - 6)
 291     {
 292         edit_move (x, 0);
 293         tty_printf ("[%c%c%c%c]",
 294                     edit->mark1 != edit->mark2 ? (edit->column_highlight ? 'C' : 'B') : '-',
 295                     edit->modified != 0 ? 'M' : '-', macro_index < 0 ? '-' : 'R',
 296                     edit->overwrite == 0 ? '-' : 'O');
 297     }
 298 
 299     if (cols > 30)
 300     {
 301         edit_move (2, w->rect.lines - 1);
 302         tty_printf ("%3ld %5ld/%ld %6ld/%ld", edit->curs_col + edit->over_col,
 303                     edit->buffer.curs_line + 1, edit->buffer.lines + 1, (long) edit->buffer.curs1,
 304                     (long) edit->buffer.size);
 305     }
 306 
 307     /*
 308      * If we are at the end of file, print <EOF>,
 309      * otherwise print the current character as is (if printable),
 310      * as decimal and as hex.
 311      */
 312     if (cols > 42)
 313     {
 314         char *character_code;
 315 
 316         edit_move (32, w->rect.lines - 1);
 317         character_code = format_character_code (edit);
 318         tty_printf ("[%s]", character_code);
 319         g_free (character_code);
 320     }
 321 }
 322 
 323 /* --------------------------------------------------------------------------------------------- */
 324 /**
 325  * Draw a frame around edit area.
 326  *
 327  * @param edit   editor object
 328  * @param color  color pair
 329  * @param active TRUE if editor object is focused
 330  */
 331 
 332 static inline void
 333 edit_draw_frame (const WEdit *edit, int color, gboolean active)
     /* [previous][next][first][last][top][bottom][index][help]  */
 334 {
 335     const Widget *w = CONST_WIDGET (edit);
 336 
 337     // draw a frame around edit area
 338     tty_setcolor (color);
 339     // draw double frame for active window if skin supports that
 340     tty_draw_box (w->rect.y, w->rect.x, w->rect.lines, w->rect.cols, !active);
 341     // draw a drag marker
 342     if (edit->drag_state == MCEDIT_DRAG_NONE)
 343     {
 344         tty_setcolor (EDITOR_FRAME_DRAG);
 345         widget_gotoyx (w, w->rect.lines - 1, w->rect.cols - 1);
 346         tty_print_char (mc_tty_frm[MC_TTY_FRM_RIGHTBOTTOM]);
 347     }
 348 }
 349 
 350 /* --------------------------------------------------------------------------------------------- */
 351 /**
 352  * Draw a window control buttons.
 353  *
 354  * @param edit  editor object
 355  * @param color color pair
 356  */
 357 
 358 static inline void
 359 edit_draw_window_icons (const WEdit *edit, int color)
     /* [previous][next][first][last][top][bottom][index][help]  */
 360 {
 361     const Widget *w = CONST_WIDGET (edit);
 362     char tmp[17];
 363 
 364     tty_setcolor (color);
 365     if (edit->fullscreen != 0)
 366         widget_gotoyx (w->owner, 0, WIDGET (w->owner)->rect.cols - 6);
 367     else
 368         widget_gotoyx (w, 0, w->rect.cols - 8);
 369     g_snprintf (tmp, sizeof (tmp), "[%s][%s]", edit_window_state_char, edit_window_close_char);
 370     tty_print_string (tmp);
 371 }
 372 
 373 /* --------------------------------------------------------------------------------------------- */
 374 
 375 static inline void
 376 print_to_widget (WEdit *edit, long row, int start_col, int start_col_real, long end_col,
     /* [previous][next][first][last][top][bottom][index][help]  */
 377                  line_s line[], char *status, int bookmarked)
 378 {
 379     Widget *w = WIDGET (edit);
 380     line_s *p;
 381     int x, x1, y, cols_to_skip;
 382     int i;
 383     int wrap_start;
 384     int len;
 385 
 386     x = start_col_real;
 387     x1 = start_col + EDIT_TEXT_HORIZONTAL_OFFSET + edit_options.line_state_width;
 388     y = row + EDIT_TEXT_VERTICAL_OFFSET;
 389     cols_to_skip = abs (x);
 390 
 391     if (edit->fullscreen == 0)
 392     {
 393         x1++;
 394         y++;
 395     }
 396 
 397     tty_setcolor (EDITOR_NORMAL_COLOR);
 398     if (bookmarked != 0)
 399         tty_setcolor (bookmarked);
 400 
 401     len = end_col + 1 - start_col;
 402     wrap_start = edit_options.word_wrap_line_length + edit->start_col;
 403 
 404     if (len > 0 && w->rect.y + y >= 0)
 405     {
 406         if (!edit_options.show_right_margin || wrap_start > end_col)
 407             tty_draw_hline (w->rect.y + y, w->rect.x + x1, ' ', len);
 408         else if (wrap_start < 0)
 409         {
 410             tty_setcolor (EDITOR_RIGHT_MARGIN_COLOR);
 411             tty_draw_hline (w->rect.y + y, w->rect.x + x1, ' ', len);
 412         }
 413         else
 414         {
 415             if (wrap_start > 0)
 416                 tty_draw_hline (w->rect.y + y, w->rect.x + x1, ' ', wrap_start);
 417 
 418             len -= wrap_start;
 419             if (len > 0)
 420             {
 421                 tty_setcolor (EDITOR_RIGHT_MARGIN_COLOR);
 422                 tty_draw_hline (w->rect.y + y, w->rect.x + x1 + wrap_start, ' ', len);
 423             }
 424         }
 425     }
 426 
 427     if (edit_options.line_state)
 428     {
 429         tty_setcolor (LINE_STATE_COLOR);
 430 
 431         for (i = 0; i < LINE_STATE_WIDTH; i++)
 432         {
 433             edit_move (x1 + i - edit_options.line_state_width, y);
 434             if (status[i] == '\0')
 435                 status[i] = ' ';
 436             tty_print_char (status[i]);
 437         }
 438     }
 439 
 440     edit_move (x1, y);
 441 
 442     i = 1;
 443     for (p = line; p->ch != 0; p++)
 444     {
 445         int style;
 446         unsigned int textchar;
 447 
 448         if (cols_to_skip != 0)
 449         {
 450             cols_to_skip--;
 451             continue;
 452         }
 453 
 454         style = p->style & 0xFF00;
 455         textchar = p->ch;
 456 
 457         if ((style & MOD_WHITESPACE) != 0)
 458         {
 459             if ((style & MOD_MARKED) == 0)
 460                 tty_setcolor (EDITOR_WHITESPACE_COLOR);
 461             else
 462             {
 463                 textchar = ' ';
 464                 tty_setcolor (EDITOR_MARKED_COLOR);
 465             }
 466         }
 467         else if ((style & MOD_BOLD) != 0)
 468             tty_setcolor (EDITOR_BOLD_COLOR);
 469         else if ((style & MOD_MARKED) != 0)
 470             tty_setcolor (EDITOR_MARKED_COLOR);
 471         else if ((style & MOD_ABNORMAL) != 0)
 472             tty_setcolor (EDITOR_NONPRINTABLE_COLOR);
 473         else
 474             tty_lowlevel_setcolor (p->style >> 16);
 475 
 476         if (edit_options.show_right_margin)
 477         {
 478             if (i > edit_options.word_wrap_line_length + edit->start_col)
 479                 tty_setcolor (EDITOR_RIGHT_MARGIN_COLOR);
 480             i++;
 481         }
 482 
 483         tty_print_anychar (textchar);
 484     }
 485 }
 486 
 487 /* --------------------------------------------------------------------------------------------- */
 488 /** b is a pointer to the beginning of the line */
 489 
 490 static void
 491 edit_draw_this_line (WEdit *edit, off_t b, long row, long start_col, long end_col)
     /* [previous][next][first][last][top][bottom][index][help]  */
 492 {
 493     Widget *w = WIDGET (edit);
 494     line_s line[MAX_LINE_LEN];
 495     line_s *p = line;
 496     off_t q;
 497     int col, start_col_real;
 498     int abn_style;
 499     int book_mark = 0;
 500     char line_stat[LINE_STATE_WIDTH + 1] = "\0";
 501 
 502     if (row > w->rect.lines - 1 - EDIT_TEXT_VERTICAL_OFFSET - 2 * (edit->fullscreen != 0 ? 0 : 1))
 503         return;
 504 
 505     if (book_mark_query_color (edit, edit->start_line + row, BOOK_MARK_COLOR))
 506         book_mark = BOOK_MARK_COLOR;
 507     else if (book_mark_query_color (edit, edit->start_line + row, BOOK_MARK_FOUND_COLOR))
 508         book_mark = BOOK_MARK_FOUND_COLOR;
 509 
 510     if (book_mark != 0)
 511         abn_style = book_mark << 16;
 512     else
 513         abn_style = MOD_ABNORMAL;
 514 
 515     end_col -= EDIT_TEXT_HORIZONTAL_OFFSET + edit_options.line_state_width;
 516     if (edit->fullscreen == 0)
 517     {
 518         end_col--;
 519         if (w->rect.x + w->rect.cols <= WIDGET (w->owner)->rect.cols)
 520             end_col--;
 521     }
 522 
 523     q = edit_move_forward3 (edit, b, start_col - edit->start_col, 0);
 524     col = (int) edit_move_forward3 (edit, b, 0, q);
 525     start_col_real = col + edit->start_col;
 526 
 527     if (edit_options.line_state)
 528     {
 529         long cur_line;
 530 
 531         cur_line = edit->start_line + row;
 532         if (cur_line <= edit->buffer.lines)
 533             g_snprintf (line_stat, sizeof (line_stat), "%7ld ", cur_line + 1);
 534         else
 535         {
 536             memset (line_stat, ' ', LINE_STATE_WIDTH);
 537             line_stat[LINE_STATE_WIDTH] = '\0';
 538         }
 539 
 540         if (book_mark_query_color (edit, cur_line, BOOK_MARK_COLOR))
 541             g_snprintf (line_stat, 2, "*");
 542     }
 543 
 544     if (col <= -(edit->start_col + 16))
 545         start_col_real = start_col = 0;
 546     else
 547     {
 548         off_t m1 = 0, m2 = 0;
 549 
 550         eval_marks (edit, &m1, &m2);
 551 
 552         if (row <= edit->buffer.lines - edit->start_line)
 553         {
 554             off_t tws = 0;
 555 
 556             if (edit_options.visible_tws && tty_use_colors ())
 557                 for (tws = edit_buffer_get_eol (&edit->buffer, b); tws > b; tws--)
 558                 {
 559                     unsigned int c;
 560 
 561                     c = edit_buffer_get_byte (&edit->buffer, tws - 1);
 562                     if (!whitespace (c))
 563                         break;
 564                 }
 565 
 566             while (col <= end_col - edit->start_col)
 567             {
 568                 int char_length = 1;
 569                 unsigned int c;
 570                 gboolean wide_width_char = FALSE;
 571                 gboolean control_char = FALSE;
 572                 gboolean printable;
 573 
 574                 p->ch = 0;
 575                 p->style = q == edit->buffer.curs1 ? MOD_CURSOR : 0;
 576 
 577                 if (q >= m1 && q < m2)
 578                 {
 579                     if (!edit->column_highlight)
 580                         p->style |= MOD_MARKED;
 581                     else
 582                     {
 583                         long x, cl;
 584 
 585                         x = (long) edit_move_forward3 (edit, b, 0, q);
 586                         cl = MIN (edit->column1, edit->column2);
 587                         if (x >= cl)
 588                         {
 589                             cl = MAX (edit->column1, edit->column2);
 590                             if (x < cl)
 591                                 p->style |= MOD_MARKED;
 592                         }
 593                     }
 594                 }
 595 
 596                 if (q == edit->bracket)
 597                     p->style |= MOD_BOLD;
 598                 if (q >= edit->found_start && q < (off_t) (edit->found_start + edit->found_len))
 599                     p->style |= MOD_BOLD;
 600 
 601                 if (edit->utf8)
 602                     c = edit_buffer_get_utf (&edit->buffer, q, &char_length);
 603                 else
 604                     c = edit_buffer_get_byte (&edit->buffer, q);
 605 
 606                 // we don't use bg for mc - fg contains both
 607                 if (book_mark != 0)
 608                     p->style |= book_mark << 16;
 609                 else
 610                 {
 611                     int color;
 612 
 613                     color = edit_get_syntax_color (edit, q);
 614                     p->style |= color << 16;
 615                 }
 616 
 617                 switch (c)
 618                 {
 619                 case '\n':
 620                     col = end_col - edit->start_col + 1;  // quit
 621                     break;
 622 
 623                 case '\t':
 624                 {
 625                     int tab_over;
 626                     int i;
 627 
 628                     i = TAB_SIZE - ((int) col % TAB_SIZE);
 629                     tab_over = (end_col - edit->start_col) - (col + i - 1);
 630                     if (tab_over < 0)
 631                         i += tab_over;
 632                     col += i;
 633                     if ((edit_options.visible_tabs || (edit_options.visible_tws && q >= tws))
 634                         && enable_show_tabs_tws && tty_use_colors ())
 635                     {
 636                         int style;
 637 
 638                         if ((p->style & MOD_MARKED) != 0)
 639                             style = p->style;
 640                         else if (book_mark != 0)
 641                             style = c | (book_mark << 16);
 642                         else
 643                             style = p->style | MOD_WHITESPACE;
 644                         if (i > 2)
 645                         {
 646                             p->ch = '<';
 647                             p->style = style;
 648                             p++;
 649                             while (--i > 1)
 650                             {
 651                                 p->ch = '-';
 652                                 p->style = style;
 653                                 p++;
 654                             }
 655                             p->ch = '>';
 656                             p->style = style;
 657                             p++;
 658                         }
 659                         else if (i > 1)
 660                         {
 661                             p->ch = '<';
 662                             p->style = style;
 663                             p++;
 664                             p->ch = '>';
 665                             p->style = style;
 666                             p++;
 667                         }
 668                         else
 669                         {
 670                             p->ch = '>';
 671                             p->style = style;
 672                             p++;
 673                         }
 674                     }
 675                     else if (edit_options.visible_tws && q >= tws && enable_show_tabs_tws
 676                              && tty_use_colors ())
 677                     {
 678                         p->ch = '.';
 679                         p->style |= MOD_WHITESPACE;
 680 
 681                         const int style = p->style & ~MOD_CURSOR;
 682 
 683                         p++;
 684                         while (--i != 0)
 685                         {
 686                             p->ch = ' ';
 687                             p->style = style;
 688                             p++;
 689                         }
 690                     }
 691                     else
 692                     {
 693                         p->ch |= ' ';
 694 
 695                         const int style = p->style & ~MOD_CURSOR;
 696 
 697                         p++;
 698                         while (--i != 0)
 699                         {
 700                             p->ch = ' ';
 701                             p->style = style;
 702                             p++;
 703                         }
 704                     }
 705                 }
 706                 break;
 707 
 708                 case ' ':
 709                     if (edit_options.visible_tws && q >= tws && enable_show_tabs_tws
 710                         && tty_use_colors ())
 711                     {
 712                         p->ch = '.';
 713                         p->style |= MOD_WHITESPACE;
 714                         p++;
 715                         col++;
 716                         break;
 717                     }
 718                     MC_FALLTHROUGH;
 719 
 720                 default:
 721                     if (mc_global.utf8_display)
 722                     {
 723                         if (!edit->utf8)
 724                             c = convert_from_8bit_to_utf_c ((unsigned char) c, edit->converter);
 725                         else if (g_unichar_iswide (c))
 726                         {
 727                             wide_width_char = TRUE;
 728                             col++;
 729                         }
 730                     }
 731                     else if (edit->utf8)
 732                         c = convert_from_utf_to_current_c (c, edit->converter);
 733                     else
 734                         c = convert_to_display_c (c);
 735 
 736                     // Caret notation for control characters
 737                     if (c < 32)
 738                     {
 739                         p->ch = '^';
 740                         p->style = abn_style;
 741                         p++;
 742                         p->ch = c + 0x40;
 743                         p->style = abn_style;
 744                         p++;
 745                         col += 2;
 746                         control_char = TRUE;
 747                         break;
 748                     }
 749                     if (c == 127)
 750                     {
 751                         p->ch = '^';
 752                         p->style = abn_style;
 753                         p++;
 754                         p->ch = '?';
 755                         p->style = abn_style;
 756                         p++;
 757                         col += 2;
 758                         control_char = TRUE;
 759                         break;
 760                     }
 761 
 762                     if (edit->utf8)
 763                     {
 764                         if (mc_global.utf8_display)
 765                             // c is gunichar
 766                             printable = g_unichar_isprint (c);
 767                         else
 768                             // c was gunichar; now c is 8-bit char converted from gunichar
 769                             printable = is_printable (c);
 770                     }
 771                     else
 772                         // c is 8-bit char
 773                         printable = is_printable (c);
 774 
 775                     if (printable)
 776                         p->ch = c;
 777                     else
 778                     {
 779                         p->ch = '.';
 780                         p->style = abn_style;
 781                     }
 782                     p++;
 783                     col++;
 784                     break;
 785                 }  // case
 786 
 787                 q++;
 788                 if (char_length > 1)
 789                     q += char_length - 1;
 790 
 791                 if (col > (end_col - edit->start_col + 1))
 792                 {
 793                     if (wide_width_char)
 794                     {
 795                         p--;
 796                         break;
 797                     }
 798                     if (control_char)
 799                     {
 800                         p -= 2;
 801                         break;
 802                     }
 803                 }
 804             }
 805         }
 806     }
 807 
 808     p->ch = 0;
 809 
 810     print_to_widget (edit, row, start_col, start_col_real, end_col, line, line_stat, book_mark);
 811 }
 812 
 813 /* --------------------------------------------------------------------------------------------- */
 814 
 815 static inline void
 816 edit_draw_this_char (WEdit *edit, off_t curs, long row, long start_column, long end_column)
     /* [previous][next][first][last][top][bottom][index][help]  */
 817 {
 818     off_t b;
 819 
 820     b = edit_buffer_get_bol (&edit->buffer, curs);
 821     edit_draw_this_line (edit, b, row, start_column, end_column);
 822 }
 823 
 824 /* --------------------------------------------------------------------------------------------- */
 825 /** cursor must be in screen for other than REDRAW_PAGE passed in force */
 826 
 827 static inline void
 828 render_edit_text (WEdit *edit, long start_row, long start_column, long end_row, long end_column)
     /* [previous][next][first][last][top][bottom][index][help]  */
 829 {
 830     static long prev_curs_row = 0;
 831     static off_t prev_curs = 0;
 832 
 833     Widget *we = WIDGET (edit);
 834     Widget *wh = WIDGET (we->owner);
 835     WRect *w = &we->rect;
 836 
 837     int force = edit->force;
 838     int y1, x1, y2, x2;
 839     int last_line, last_column;
 840 
 841     // draw only visible region
 842 
 843     last_line = wh->rect.y + wh->rect.lines - 1;
 844 
 845     y1 = w->y;
 846     if (y1 > last_line - 1)  // buttonbar
 847         return;
 848 
 849     last_column = wh->rect.x + wh->rect.cols - 1;
 850 
 851     x1 = w->x;
 852     if (x1 > last_column)
 853         return;
 854 
 855     y2 = w->y + w->lines - 1;
 856     if (y2 < wh->rect.y + 1)  // menubar
 857         return;
 858 
 859     x2 = w->x + w->cols - 1;
 860     if (x2 < wh->rect.x)
 861         return;
 862 
 863     if ((force & REDRAW_IN_BOUNDS) == 0)
 864     {
 865         // !REDRAW_IN_BOUNDS means to ignore bounds and redraw whole rows
 866         // draw only visible region
 867 
 868         if (y2 <= last_line - 1)  // buttonbar
 869             end_row = w->lines - 1;
 870         else if (y1 >= wh->rect.y + 1)  // menubar
 871             end_row = wh->rect.lines - 1 - y1 - 1;
 872         else
 873             end_row = start_row + wh->rect.lines - 1 - 1;
 874 
 875         if (x2 <= last_column)
 876             end_column = w->cols - 1;
 877         else if (x1 >= wh->rect.x)
 878             end_column = wh->rect.cols - 1 - x1;
 879         else
 880             end_column = start_column + wh->rect.cols - 1;
 881     }
 882 
 883     /*
 884      * If the position of the page has not moved then we can draw the cursor
 885      * character only.  This will prevent line flicker when using arrow keys.
 886      */
 887     if ((force & REDRAW_CHAR_ONLY) == 0 || (force & REDRAW_PAGE) != 0)
 888     {
 889         long row = 0;
 890         long b;
 891 
 892         if ((force & REDRAW_PAGE) != 0)
 893         {
 894             b = edit_buffer_get_forward_offset (&edit->buffer, edit->start_display, start_row, 0);
 895             for (row = start_row; row <= end_row; row++)
 896             {
 897                 if (key_pending (edit))
 898                     return;
 899                 edit_draw_this_line (edit, b, row, start_column, end_column);
 900                 b = edit_buffer_get_forward_offset (&edit->buffer, b, 1, 0);
 901             }
 902         }
 903         else
 904         {
 905             long curs_row = edit->curs_row;
 906 
 907             if ((force & REDRAW_BEFORE_CURSOR) != 0 && start_row < curs_row)
 908             {
 909                 long upto;
 910 
 911                 b = edit->start_display;
 912                 upto = MIN (curs_row - 1, end_row);
 913                 for (row = start_row; row <= upto; row++)
 914                 {
 915                     if (key_pending (edit))
 916                         return;
 917                     edit_draw_this_line (edit, b, row, start_column, end_column);
 918                     b = edit_buffer_get_forward_offset (&edit->buffer, b, 1, 0);
 919                 }
 920             }
 921 
 922             //          if (force & REDRAW_LINE)          ---> default
 923             b = edit_buffer_get_current_bol (&edit->buffer);
 924             if (curs_row >= start_row && curs_row <= end_row)
 925             {
 926                 if (key_pending (edit))
 927                     return;
 928                 edit_draw_this_line (edit, b, curs_row, start_column, end_column);
 929             }
 930 
 931             if ((force & REDRAW_AFTER_CURSOR) != 0 && end_row > curs_row)
 932             {
 933                 b = edit_buffer_get_forward_offset (&edit->buffer, b, 1, 0);
 934                 for (row = MAX (curs_row + 1, start_row); row <= end_row; row++)
 935                 {
 936                     if (key_pending (edit))
 937                         return;
 938                     edit_draw_this_line (edit, b, row, start_column, end_column);
 939                     b = edit_buffer_get_forward_offset (&edit->buffer, b, 1, 0);
 940                 }
 941             }
 942 
 943             if ((force & REDRAW_LINE_ABOVE) != 0 && curs_row >= 1)
 944             {
 945                 row = curs_row - 1;
 946                 b = edit_buffer_get_current_bol (&edit->buffer);
 947                 b = edit_buffer_get_backward_offset (&edit->buffer, b, 1);
 948                 if (row >= start_row && row <= end_row)
 949                 {
 950                     if (key_pending (edit))
 951                         return;
 952                     edit_draw_this_line (edit, b, row, start_column, end_column);
 953                 }
 954             }
 955 
 956             if ((force & REDRAW_LINE_BELOW) != 0 && row < w->lines - 1)
 957             {
 958                 row = curs_row + 1;
 959                 b = edit_buffer_get_current_bol (&edit->buffer);
 960                 b = edit_buffer_get_forward_offset (&edit->buffer, b, 1, 0);
 961                 if (row >= start_row && row <= end_row)
 962                 {
 963                     if (key_pending (edit))
 964                         return;
 965                     edit_draw_this_line (edit, b, row, start_column, end_column);
 966                 }
 967             }
 968         }
 969     }
 970     else if (prev_curs_row < edit->curs_row)
 971     {
 972         // with the new text highlighting, we must draw from the top down
 973         edit_draw_this_char (edit, prev_curs, prev_curs_row, start_column, end_column);
 974         edit_draw_this_char (edit, edit->buffer.curs1, edit->curs_row, start_column, end_column);
 975     }
 976     else
 977     {
 978         edit_draw_this_char (edit, edit->buffer.curs1, edit->curs_row, start_column, end_column);
 979         edit_draw_this_char (edit, prev_curs, prev_curs_row, start_column, end_column);
 980     }
 981 
 982     edit->force = 0;
 983 
 984     prev_curs_row = edit->curs_row;
 985     prev_curs = edit->buffer.curs1;
 986 }
 987 
 988 /* --------------------------------------------------------------------------------------------- */
 989 
 990 static inline void
 991 edit_render (WEdit *edit, int page, int row_start, int col_start, int row_end, int col_end)
     /* [previous][next][first][last][top][bottom][index][help]  */
 992 {
 993     if (page != 0)  // if it was an expose event, 'page' would be set
 994         edit->force |= REDRAW_PAGE | REDRAW_IN_BOUNDS;
 995 
 996     render_edit_text (edit, row_start, col_start, row_end, col_end);
 997 
 998     /*
 999      * edit->force != 0 means a key was pending and the redraw
1000      * was halted, so next time we must redraw everything in case stuff
1001      * was left undrawn from a previous key press.
1002      */
1003     if (edit->force != 0)
1004         edit->force |= REDRAW_PAGE;
1005 }
1006 
1007 /* --------------------------------------------------------------------------------------------- */
1008 /*** public functions ****************************************************************************/
1009 /* --------------------------------------------------------------------------------------------- */
1010 
1011 void
1012 edit_status (WEdit *edit, gboolean active)
     /* [previous][next][first][last][top][bottom][index][help]  */
1013 {
1014     int color;
1015 
1016     if (edit->fullscreen != 0)
1017     {
1018         color = STATUSBAR_COLOR;
1019         edit_status_fullscreen (edit, color);
1020     }
1021     else
1022     {
1023         color = edit->drag_state != MCEDIT_DRAG_NONE ? EDITOR_FRAME_DRAG
1024             : active                                 ? EDITOR_FRAME_ACTIVE
1025                                                      : EDITOR_FRAME;
1026         edit_draw_frame (edit, color, active);
1027         edit_status_window (edit);
1028     }
1029 
1030     edit_draw_window_icons (edit, color);
1031 }
1032 
1033 /* --------------------------------------------------------------------------------------------- */
1034 
1035 /** this scrolls the text so that cursor is on the screen */
1036 void
1037 edit_scroll_screen_over_cursor (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1038 {
1039     WRect *w = &WIDGET (edit)->rect;
1040 
1041     long p;
1042     long outby;
1043     int b_extreme, t_extreme, l_extreme, r_extreme;
1044 
1045     if (w->lines <= 0 || w->cols <= 0)
1046         return;
1047 
1048     rect_resize (w, -EDIT_TEXT_VERTICAL_OFFSET,
1049                  -(EDIT_TEXT_HORIZONTAL_OFFSET + edit_options.line_state_width));
1050 
1051     if (edit->fullscreen == 0)
1052         rect_grow (w, -1, -1);
1053 
1054     r_extreme = EDIT_RIGHT_EXTREME;
1055     l_extreme = EDIT_LEFT_EXTREME;
1056     b_extreme = EDIT_BOTTOM_EXTREME;
1057     t_extreme = EDIT_TOP_EXTREME;
1058     if (edit->found_len != 0)
1059     {
1060         b_extreme = MAX (w->lines / 4, b_extreme);
1061         t_extreme = MAX (w->lines / 4, t_extreme);
1062     }
1063     if (b_extreme + t_extreme + 1 > w->lines)
1064     {
1065         int n;
1066 
1067         n = b_extreme + t_extreme;
1068         if (n == 0)
1069             n = 1;
1070         b_extreme = (b_extreme * (w->lines - 1)) / n;
1071         t_extreme = (t_extreme * (w->lines - 1)) / n;
1072     }
1073     if (l_extreme + r_extreme + 1 > w->cols)
1074     {
1075         int n;
1076 
1077         n = l_extreme + r_extreme;
1078         if (n == 0)
1079             n = 1;
1080         l_extreme = (l_extreme * (w->cols - 1)) / n;
1081         r_extreme = (r_extreme * (w->cols - 1)) / n;
1082     }
1083     p = edit_get_col (edit) + edit->over_col;
1084     edit_update_curs_row (edit);
1085     outby = p + edit->start_col - w->cols + 1 + (r_extreme + edit->found_len);
1086     if (outby > 0)
1087         edit_scroll_right (edit, outby);
1088     outby = l_extreme - p - edit->start_col;
1089     if (outby > 0)
1090         edit_scroll_left (edit, outby);
1091     p = edit->curs_row;
1092     outby = p - w->lines + 1 + b_extreme;
1093     if (outby > 0)
1094         edit_scroll_downward (edit, outby);
1095     outby = t_extreme - p;
1096     if (outby > 0)
1097         edit_scroll_upward (edit, outby);
1098     edit_update_curs_row (edit);
1099 
1100     rect_resize (w, EDIT_TEXT_VERTICAL_OFFSET,
1101                  EDIT_TEXT_HORIZONTAL_OFFSET + edit_options.line_state_width);
1102     if (edit->fullscreen == 0)
1103         rect_grow (w, 1, 1);
1104 }
1105 
1106 /* --------------------------------------------------------------------------------------------- */
1107 
1108 void
1109 edit_render_keypress (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1110 {
1111     edit_render (edit, 0, 0, 0, 0, 0);
1112 }
1113 
1114 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */