Tickets #3250, #3256: rewrite mcview's rendering and scrolling

Major rewrite of mcview's parts responsible for rendering and scrolling the contents:
  * no more partial lines at the top and failure to scroll when Up or Down
    is pressed;
  * better handling of CJK characters;
  * handle combining accents;
  * improved nroff support;
  * more conventional scrolling behavior at the end of the file.

Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
This commit is contained in:
Egmont Koblinger 2014-09-14 00:42:46 +02:00 committed by Andrew Borodin
parent 4f6d1d1d95
commit bcb09f6ac4
13 changed files with 1124 additions and 505 deletions

View File

@ -64,6 +64,7 @@ Egmont Koblinger <egmont@gmail.com>
Support of extended mouse clicks beyond 223 column
Support of bracketed paste mode of xterm
(http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Bracketed%20Paste%20Mode)
Rewritten viewer
Erwin van Eijk <wabbit@corner.iaf.nl>

View File

@ -3,6 +3,7 @@ noinst_LTLIBRARIES = libmcviewer.la
libmcviewer_la_SOURCES = \
actions_cmd.c \
ascii.c \
coord_cache.c \
datasource.c \
dialogs.c \
@ -16,7 +17,6 @@ libmcviewer_la_SOURCES = \
mcviewer.h \
move.c \
nroff.c \
plain.c \
search.c
AM_CPPFLAGS = -I$(top_srcdir) $(GLIB_CFLAGS) $(PCRE_CPPFLAGS)

View File

@ -510,6 +510,8 @@ mcview_execute_cmd (mcview_t * view, unsigned long command)
break;
case CK_Bookmark:
view->dpy_start = view->marks[view->marker];
view->dpy_paragraph_skip_lines = 0; /* TODO: remember this value in the marker? */
view->dpy_wrap_dirty = TRUE;
view->dirty++;
break;
#ifdef HAVE_CHARSET
@ -592,6 +594,7 @@ mcview_adjust_size (WDialog * h)
widget_set_size (WIDGET (view), 0, 0, LINES - 1, COLS);
widget_set_size (WIDGET (b), LINES - 1, 0, 1, COLS);
view->dpy_wrap_dirty = TRUE;
mcview_compute_areas (view);
mcview_update_bytes_per_line (view);
}

1038
src/viewer/ascii.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -152,7 +152,7 @@ mcview_get_ptr_file (mcview_t * view, off_t byte_index)
/* --------------------------------------------------------------------------------------------- */
int
mcview_get_utf (mcview_t * view, off_t byte_index, int *char_width, gboolean * result)
mcview_get_utf (mcview_t * view, off_t byte_index, int *bytes_consumed, gboolean * result)
{
gchar *str = NULL;
int res = -1;
@ -160,7 +160,7 @@ mcview_get_utf (mcview_t * view, off_t byte_index, int *char_width, gboolean * r
gchar *next_ch = NULL;
gchar utf8buf[UTF8_CHAR_LEN + 1];
*char_width = 0;
*bytes_consumed = 0;
*result = FALSE;
switch (view->datasource)
@ -206,7 +206,7 @@ mcview_get_utf (mcview_t * view, off_t byte_index, int *char_width, gboolean * r
if (res < 0)
{
ch = *str;
*char_width = 1;
*bytes_consumed = 1;
}
else
{
@ -214,7 +214,7 @@ mcview_get_utf (mcview_t * view, off_t byte_index, int *char_width, gboolean * r
/* Calculate UTF-8 char width */
next_ch = g_utf8_next_char (str);
if (next_ch)
*char_width = next_ch - str;
*bytes_consumed = next_ch - str;
else
return 0;
}

View File

@ -251,10 +251,6 @@ mcview_display (mcview_t * view)
{
mcview_display_hex (view);
}
else if (view->text_nroff_mode)
{
mcview_display_nroff (view);
}
else
{
mcview_display_text (view);

View File

@ -87,6 +87,18 @@ typedef struct
coord_cache_entry_t **cache;
} coord_cache_t;
/* TODO: find a better name. This is not actually a "state machine",
* but a "state machine's state", but that sounds silly.
* Could be parser_state, formatter_state... */
typedef struct
{
off_t offset; /* The file offset at which this is the state. */
off_t unwrapped_column; /* Columns if the paragraph wasn't wrapped, */
/* used for positioning TABs in wrapped lines */
gboolean nroff_underscore_is_underlined; /* whether _\b_ is underlined rather than bold */
gboolean print_lonely_combining; /* whether lonely combining marks are printed on a dotted circle */
} mcview_state_machine_t;
struct mcview_nroff_struct;
struct mcview_struct
@ -144,8 +156,12 @@ struct mcview_struct
/* Display information */
gboolean active; /* Active or not in QuickView mode */
screen_dimen dpy_frame_size; /* Size of the frame surrounding the real viewer */
off_t dpy_start; /* Offset of the displayed data */
off_t dpy_start; /* Offset of the displayed data (start of the paragraph in non-hex mode) */
off_t dpy_end; /* Offset after the displayed data */
off_t dpy_paragraph_skip_lines; /* Extra lines to skip in wrap mode */
mcview_state_machine_t dpy_state_top; /* Parser-formatter state at the topmost visible line in wrap mode */
mcview_state_machine_t dpy_state_bottom; /* Parser-formatter state after the bottomvisible line in wrap mode */
gboolean dpy_wrap_dirty; /* dpy_state_top needs to be recomputed */
off_t dpy_text_column; /* Number of skipped columns in non-wrap
* text mode */
off_t hex_cursor; /* Hexview cursor position in file */
@ -156,6 +172,8 @@ struct mcview_struct
struct area ruler_area; /* Where the ruler is displayed */
struct area data_area; /* Where the data is displayed */
ssize_t force_max; /* Force a max offset, or -1 */
int dirty; /* Number of skipped updates */
gboolean dpy_bbar_dirty; /* Does the button bar need to be updated? */
@ -223,6 +241,14 @@ cb_ret_t mcview_callback (Widget * w, Widget * sender, widget_msg_t msg, int par
cb_ret_t mcview_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm,
void *data);
/* ascii.c: */
void mcview_display_text (mcview_t *);
void mcview_state_machine_init (mcview_state_machine_t *, off_t);
void mcview_ascii_move_down (mcview_t *, off_t);
void mcview_ascii_move_up (mcview_t *, off_t);
void mcview_ascii_moveto_bol (mcview_t *);
void mcview_ascii_moveto_eol (mcview_t *);
/* coord_cache.c: */
coord_cache_t *coord_cache_new (void);
void coord_cache_free (coord_cache_t * cache);
@ -312,9 +338,7 @@ void mcview_place_cursor (mcview_t *);
void mcview_moveto_match (mcview_t *);
/* nroff.c: */
void mcview_display_nroff (mcview_t * view);
int mcview__get_nroff_real_len (mcview_t * view, off_t, off_t p);
mcview_nroff_t *mcview_nroff_seq_new_num (mcview_t * view, off_t p);
mcview_nroff_t *mcview_nroff_seq_new (mcview_t * view);
void mcview_nroff_seq_free (mcview_nroff_t **);
@ -322,10 +346,6 @@ nroff_type_t mcview_nroff_seq_info (mcview_nroff_t *);
int mcview_nroff_seq_next (mcview_nroff_t *);
int mcview_nroff_seq_prev (mcview_nroff_t *);
/* plain.c: */
void mcview_display_text (mcview_t *);
/* search.c: */
mc_search_cbret_t mcview_search_cmd_callback (const void *user_data, gsize char_offset,
int *current_char);

View File

@ -106,9 +106,8 @@ mcview_toggle_magic_mode (mcview_t * view)
void
mcview_toggle_wrap_mode (mcview_t * view)
{
if (view->text_wrap_mode)
view->dpy_start = mcview_bol (view, view->dpy_start, 0);
view->text_wrap_mode = !view->text_wrap_mode;
view->dpy_wrap_dirty = TRUE;
view->dpy_bbar_dirty = TRUE;
view->dirty++;
}
@ -120,6 +119,7 @@ mcview_toggle_nroff_mode (mcview_t * view)
{
view->text_nroff_mode = !view->text_nroff_mode;
mcview_altered_nroff_flag = 1;
view->dpy_wrap_dirty = TRUE;
view->dpy_bbar_dirty = TRUE;
view->dirty++;
}
@ -144,6 +144,8 @@ mcview_toggle_hex_mode (mcview_t * view)
widget_want_cursor (WIDGET (view), FALSE);
}
mcview_altered_hex_mode = 1;
view->dpy_paragraph_skip_lines = 0;
view->dpy_wrap_dirty = TRUE;
view->dpy_bbar_dirty = TRUE;
view->dirty++;
}
@ -170,6 +172,10 @@ mcview_init (mcview_t * view)
view->coord_cache = NULL;
view->dpy_start = 0;
view->dpy_paragraph_skip_lines = 0;
mcview_state_machine_init (&view->dpy_state_top, 0);
view->dpy_wrap_dirty = FALSE;
view->force_max = -1;
view->dpy_text_column = 0;
view->dpy_end = 0;
view->hex_cursor = 0;
@ -281,6 +287,7 @@ mcview_set_codeset (mcview_t * view)
view->converter = conv;
}
view->utf8 = (gboolean) str_isutf8 (cp_id);
view->dpy_wrap_dirty = TRUE;
}
#else
(void) view;
@ -333,7 +340,7 @@ mcview_bol (mcview_t * view, off_t current, off_t limit)
if (c == '\r')
current--;
}
while (current > 0 && current >= limit)
while (current > 0 && current > limit)
{
if (!mcview_get_byte (view, current - 1, &c))
break;

View File

@ -406,6 +406,10 @@ mcview_load (mcview_t * view, const char *command, const char *file, int start_l
finish:
view->command = g_strdup (command);
view->dpy_start = 0;
view->dpy_paragraph_skip_lines = 0;
mcview_state_machine_init (&view->dpy_state_top, 0);
view->dpy_wrap_dirty = FALSE;
view->force_max = -1;
view->search_start = 0;
view->search_end = 0;
view->dpy_text_column = 0;
@ -425,7 +429,10 @@ mcview_load (mcview_t * view, const char *command, const char *file, int start_l
else
new_offset = min (new_offset, max_offset);
if (!view->hex_mode)
{
view->dpy_start = mcview_bol (view, new_offset, 0);
view->dpy_wrap_dirty = TRUE;
}
else
{
view->dpy_start = new_offset - new_offset % view->bytes_per_line;

View File

@ -83,6 +83,8 @@ mcview_scroll_to_cursor (mcview_t * view)
if (cursor < topleft)
topleft = mcview_offset_rounddown (cursor, bytes);
view->dpy_start = topleft;
view->dpy_paragraph_skip_lines = 0;
view->dpy_wrap_dirty = TRUE;
}
}
@ -107,8 +109,6 @@ mcview_movement_fixups (mcview_t * view, gboolean reset_search)
void
mcview_move_up (mcview_t * view, off_t lines)
{
off_t new_offset;
if (view->hex_mode)
{
off_t bytes = lines * view->bytes_per_line;
@ -116,7 +116,11 @@ mcview_move_up (mcview_t * view, off_t lines)
{
view->hex_cursor -= bytes;
if (view->hex_cursor < view->dpy_start)
{
view->dpy_start = mcview_offset_doz (view->dpy_start, bytes);
view->dpy_paragraph_skip_lines = 0;
view->dpy_wrap_dirty = TRUE;
}
}
else
{
@ -125,46 +129,7 @@ mcview_move_up (mcview_t * view, off_t lines)
}
else
{
off_t i;
for (i = 0; i < lines; i++)
{
if (view->dpy_start == 0)
break;
if (view->text_wrap_mode)
{
new_offset = mcview_bol (view, view->dpy_start, view->dpy_start - (off_t) 1);
/* check if dpy_start == BOL or not (then new_offset = dpy_start - 1,
* no need to check more) */
if (new_offset == view->dpy_start)
{
size_t last_row_length;
new_offset = mcview_bol (view, new_offset - 1, 0);
last_row_length = (view->dpy_start - new_offset) % view->data_area.width;
if (last_row_length != 0)
{
/* if dpy_start == BOL in wrapped mode, find BOL of previous line
* and move down all but the last rows */
new_offset = view->dpy_start - (off_t) last_row_length;
}
}
else
{
/* if dpy_start != BOL in wrapped mode, just move one row up;
* no need to check if > 0 as there is at least exactly one wrap
* between dpy_start and BOL */
new_offset = view->dpy_start - (off_t) view->data_area.width;
}
view->dpy_start = new_offset;
}
else
{
/* if unwrapped -> current BOL equals dpy_start, just find BOL of previous line */
new_offset = view->dpy_start - 1;
view->dpy_start = mcview_bol (view, new_offset, 0);
}
}
mcview_ascii_move_up (view, lines);
}
mcview_movement_fixups (view, TRUE);
}
@ -186,51 +151,16 @@ mcview_move_down (mcview_t * view, off_t lines)
{
view->hex_cursor += view->bytes_per_line;
if (lines != 1)
{
view->dpy_start += view->bytes_per_line;
view->dpy_paragraph_skip_lines = 0;
view->dpy_wrap_dirty = TRUE;
}
}
}
else
{
off_t new_offset = 0;
if (view->dpy_end - view->dpy_start > last_byte - view->dpy_end)
{
while (lines-- > 0)
{
if (view->text_wrap_mode)
view->dpy_end =
mcview_eol (view, view->dpy_end,
view->dpy_end + (off_t) view->data_area.width);
else
view->dpy_end = mcview_eol (view, view->dpy_end, last_byte);
if (view->text_wrap_mode)
new_offset =
mcview_eol (view, view->dpy_start,
view->dpy_start + (off_t) view->data_area.width);
else
new_offset = mcview_eol (view, view->dpy_start, last_byte);
if (new_offset < last_byte)
view->dpy_start = new_offset;
if (view->dpy_end >= last_byte)
break;
}
}
else
{
off_t i;
for (i = 0; i < lines && new_offset < last_byte; i++)
{
if (view->text_wrap_mode)
new_offset =
mcview_eol (view, view->dpy_start,
view->dpy_start + (off_t) view->data_area.width);
else
new_offset = mcview_eol (view, view->dpy_start, last_byte);
if (new_offset < last_byte)
view->dpy_start = new_offset;
}
}
mcview_ascii_move_down (view, lines);
}
mcview_movement_fixups (view, TRUE);
}
@ -255,9 +185,8 @@ mcview_move_left (mcview_t * view, off_t columns)
if (old_cursor > 0 || view->hexedit_lownibble)
view->hexedit_lownibble = !view->hexedit_lownibble;
}
else
else if (!view->text_wrap_mode)
view->dpy_text_column = mcview_offset_doz (view->dpy_text_column, columns);
mcview_movement_fixups (view, FALSE);
}
@ -284,7 +213,7 @@ mcview_move_right (mcview_t * view, off_t columns)
if (old_cursor < last_byte || !view->hexedit_lownibble)
view->hexedit_lownibble = !view->hexedit_lownibble;
}
else
else if (!view->text_wrap_mode)
{
view->dpy_text_column += columns;
}
@ -297,6 +226,8 @@ void
mcview_moveto_top (mcview_t * view)
{
view->dpy_start = 0;
view->dpy_paragraph_skip_lines = 0;
mcview_state_machine_init (&view->dpy_state_top, 0);
view->hex_cursor = 0;
view->dpy_text_column = 0;
mcview_movement_fixups (view, TRUE);
@ -326,6 +257,8 @@ mcview_moveto_bottom (mcview_t * view)
const off_t datalines = view->data_area.height;
view->dpy_start = filesize;
view->dpy_paragraph_skip_lines = 0;
view->dpy_wrap_dirty = TRUE;
mcview_move_up (view, datalines);
}
}
@ -338,12 +271,12 @@ mcview_moveto_bol (mcview_t * view)
if (view->hex_mode)
{
view->hex_cursor -= view->hex_cursor % view->bytes_per_line;
view->dpy_text_column = 0;
}
else if (!view->text_wrap_mode)
else
{
view->dpy_start = mcview_bol (view, view->dpy_start, 0);
mcview_ascii_moveto_bol (view);
}
view->dpy_text_column = 0;
mcview_movement_fixups (view, TRUE);
}
@ -370,43 +303,7 @@ mcview_moveto_eol (mcview_t * view)
}
else
{
off_t eol;
bol = mcview_bol (view, view->dpy_start, 0);
eol = mcview_eol (view, view->dpy_start, mcview_get_filesize (view));
#ifdef HAVE_CHARSET
if (view->utf8)
{
char *str = NULL;
switch (view->datasource)
{
case DS_STDIO_PIPE:
case DS_VFS_PIPE:
str = mcview_get_ptr_growing_buffer (view, bol);
break;
case DS_FILE:
str = mcview_get_ptr_file (view, bol);
break;
case DS_STRING:
str = mcview_get_ptr_string (view, bol);
break;
case DS_NONE:
break;
}
if (str != NULL && eol > bol)
view->dpy_text_column = g_utf8_strlen (str, eol - bol);
else
view->dpy_text_column = eol - bol;
}
else
#endif /* HAVE_CHARSET */
if (eol > bol)
view->dpy_text_column = eol - bol;
view->dpy_text_column =
mcview_offset_doz (view->dpy_text_column, (off_t) view->data_area.width);
mcview_ascii_moveto_eol (view);
}
mcview_movement_fixups (view, FALSE);
}
@ -420,10 +317,14 @@ mcview_moveto_offset (mcview_t * view, off_t offset)
{
view->hex_cursor = offset;
view->dpy_start = offset - offset % view->bytes_per_line;
view->dpy_paragraph_skip_lines = 0;
view->dpy_wrap_dirty = TRUE;
}
else
{
view->dpy_start = offset;
view->dpy_paragraph_skip_lines = 0;
view->dpy_wrap_dirty = TRUE;
}
mcview_movement_fixups (view, TRUE);
}
@ -494,9 +395,15 @@ mcview_moveto_match (mcview_t * view)
view->hexedit_lownibble = FALSE;
view->dpy_start = view->search_start - view->search_start % view->bytes_per_line;
view->dpy_end = view->search_end - view->search_end % view->bytes_per_line;
view->dpy_paragraph_skip_lines = 0;
view->dpy_wrap_dirty = TRUE;
}
else
{
view->dpy_start = mcview_bol (view, view->search_start, 0);
view->dpy_paragraph_skip_lines = 0;
view->dpy_wrap_dirty = TRUE;
}
mcview_scroll_to_cursor (view);
view->dirty++;

View File

@ -1,6 +1,6 @@
/*
Internal file viewer for the Midnight Commander
Function for nroff-like view
Functions for searching in nroff-like view
Copyright (C) 1994-2014
Free Software Foundation, Inc.
@ -91,162 +91,6 @@ mcview_nroff_get_char (mcview_nroff_t * nroff, int *ret_val, off_t nroff_index)
/*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */
void
mcview_display_nroff (mcview_t * view)
{
const screen_dimen left = view->data_area.left;
const screen_dimen top = view->data_area.top;
const screen_dimen width = view->data_area.width;
const screen_dimen height = view->data_area.height;
screen_dimen row, col;
off_t from;
int cw = 1;
int c;
int c_prev = 0;
int c_next = 0;
mcview_display_clean (view);
mcview_display_ruler (view);
/* Find the first displayable changed byte */
from = view->dpy_start;
tty_setcolor (VIEW_NORMAL_COLOR);
for (row = 0, col = 0; row < height;)
{
#ifdef HAVE_CHARSET
if (view->utf8)
{
gboolean read_res = TRUE;
c = mcview_get_utf (view, from, &cw, &read_res);
if (!read_res)
break;
}
else
#endif
{
if (!mcview_get_byte (view, from, &c))
break;
}
from++;
if (cw > 1)
from += cw - 1;
if (c == '\b')
{
if (from > 1)
{
#ifdef HAVE_CHARSET
if (view->utf8)
{
gboolean read_res;
c_next = mcview_get_utf (view, from, &cw, &read_res);
}
else
#endif
mcview_get_byte (view, from, &c_next);
}
if (g_unichar_isprint (c_prev) && g_unichar_isprint (c_next)
&& (c_prev == c_next || c_prev == '_' || (c_prev == '+' && c_next == 'o')))
{
if (col == 0)
{
if (row == 0)
{
/* We're inside an nroff character sequence at the
* beginning of the screen -- just skip the
* backspace and continue with the next character. */
continue;
}
row--;
col = width;
}
col--;
if (c_prev == '_'
&& (c_next != '_' || mcview_count_backspaces (view, from + 1) == 1))
tty_setcolor (VIEW_UNDERLINED_COLOR);
else
tty_setcolor (VIEW_BOLD_COLOR);
continue;
}
}
if ((c == '\n') || (col >= width && view->text_wrap_mode))
{
col = 0;
row++;
if (c == '\n' || row >= height)
continue;
}
if (c == '\r')
{
mcview_get_byte_indexed (view, from, 1, &c);
if (c == '\r' || c == '\n')
continue;
col = 0;
row++;
continue;
}
if (c == '\t')
{
off_t line, column;
mcview_offset_to_coord (view, &line, &column, from);
col += (option_tab_spacing - col % option_tab_spacing);
if (view->text_wrap_mode && col >= width && width != 0)
{
row += col / width;
col %= width;
}
continue;
}
if (view->search_start <= from && from < view->search_end)
{
tty_setcolor (SELECTED_COLOR);
}
c_prev = c;
if ((off_t) col >= view->dpy_text_column
&& (off_t) col - view->dpy_text_column < (off_t) width)
{
widget_move (view, top + row, left + ((off_t) col - view->dpy_text_column));
#ifdef HAVE_CHARSET
if (mc_global.utf8_display)
{
if (!view->utf8)
{
c = convert_from_8bit_to_utf_c ((unsigned char) c, view->converter);
}
if (!g_unichar_isprint (c))
c = '.';
}
else if (view->utf8)
c = convert_from_utf_to_current_c (c, view->converter);
else
c = convert_to_display_c (c);
#endif
tty_print_anychar (c);
}
col++;
#ifdef HAVE_CHARSET
if (view->utf8)
{
if (g_unichar_iswide (c))
col++;
else if (g_unichar_iszerowidth (c))
col--;
}
#endif
tty_setcolor (VIEW_NORMAL_COLOR);
}
view->dpy_end = from;
}
/* --------------------------------------------------------------------------------------------- */
int
mcview__get_nroff_real_len (mcview_t * view, off_t start, off_t length)
{

View File

@ -1,204 +0,0 @@
/*
Internal file viewer for the Midnight Commander
Function for plain view
Copyright (C) 1994-2014
Free Software Foundation, Inc.
Written by:
Miguel de Icaza, 1994, 1995, 1998
Janne Kukonlehto, 1994, 1995
Jakub Jelinek, 1995
Joseph M. Hinkle, 1996
Norbert Warmuth, 1997
Pavel Machek, 1998
Roland Illig <roland.illig@gmx.de>, 2004, 2005
Slava Zanko <slavazanko@google.com>, 2009
Andrew Borodin <aborodin@vmail.ru>, 2009-2014
Ilia Maslakov <il.smind@gmail.com>, 2009
This file is part of the Midnight Commander.
The Midnight Commander is free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of the License,
or (at your option) any later version.
The Midnight Commander is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "lib/global.h"
#include "lib/tty/tty.h"
#include "lib/skin.h"
#include "lib/util.h" /* is_printable() */
#ifdef HAVE_CHARSET
#include "lib/charsets.h"
#endif
#include "src/setup.h" /* option_tab_spacing */
#include "internal.h"
/*** global variables ****************************************************************************/
/*** file scope macro definitions ****************************************************************/
/*** file scope type declarations ****************************************************************/
/*** file scope variables ************************************************************************/
/*** file scope functions ************************************************************************/
/* --------------------------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------------------------- */
/*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */
void
mcview_display_text (mcview_t * view)
{
const screen_dimen left = view->data_area.left;
const screen_dimen top = view->data_area.top;
const screen_dimen width = view->data_area.width;
const screen_dimen height = view->data_area.height;
screen_dimen row = 0, col = 0;
off_t from;
int cw = 1;
int c, prev_ch = 0;
gboolean last_row = TRUE;
mcview_display_clean (view);
mcview_display_ruler (view);
/* Find the first displayable changed byte */
from = view->dpy_start;
while (row < height)
{
#ifdef HAVE_CHARSET
if (view->utf8)
{
gboolean read_res = TRUE;
c = mcview_get_utf (view, from, &cw, &read_res);
if (!read_res)
break;
}
else
#endif
if (!mcview_get_byte (view, from, &c))
break;
last_row = FALSE;
from++;
if (cw > 1)
from += cw - 1;
if (c != '\n' && prev_ch == '\r')
{
if (++row >= height)
break;
col = 0;
/* tty_print_anychar ('\n'); */
}
prev_ch = c;
if (c == '\r')
continue;
if (c == '\n')
{
col = 0;
row++;
continue;
}
if (col >= width && view->text_wrap_mode)
{
col = 0;
if (++row >= height)
break;
}
if (c == '\t')
{
col += (option_tab_spacing - col % option_tab_spacing);
if (view->text_wrap_mode && col >= width && width != 0)
{
row += col / width;
col %= width;
}
continue;
}
if (view->search_start <= from && from < view->search_end)
tty_setcolor (SELECTED_COLOR);
else
tty_setcolor (VIEW_NORMAL_COLOR);
if (((off_t) col >= view->dpy_text_column)
&& ((off_t) col - view->dpy_text_column < (off_t) width))
{
widget_move (view, top + row, left + ((off_t) col - view->dpy_text_column));
#ifdef HAVE_CHARSET
if (mc_global.utf8_display)
{
if (!view->utf8)
c = convert_from_8bit_to_utf_c ((unsigned char) c, view->converter);
if (!g_unichar_isprint (c))
c = '.';
}
else if (view->utf8)
c = convert_from_utf_to_current_c (c, view->converter);
else
{
c = convert_to_display_c (c);
if (!is_printable (c))
c = '.';
}
#else /* HAVE_CHARSET */
if (!is_printable (c))
c = '.';
#endif /* HAVE_CHARSET */
tty_print_anychar (c);
}
col++;
#ifdef HAVE_CHARSET
if (view->utf8)
{
if (g_unichar_iswide (c))
col++;
else if (g_unichar_iszerowidth (c))
col--;
}
#endif
}
view->dpy_end = from;
if (mcview_show_eof != NULL && mcview_show_eof[0] != '\0')
{
if (last_row && mcview_get_byte (view, from - 1, &c) && c != '\n')
row--;
while (++row < height)
{
widget_move (view, top + row, left);
tty_print_string (mcview_show_eof);
}
}
}
/* --------------------------------------------------------------------------------------------- */

Binary file not shown.