aboutsummaryrefslogtreecommitdiff
path: root/contrib/less/input.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/less/input.c')
-rw-r--r--contrib/less/input.c215
1 files changed, 173 insertions, 42 deletions
diff --git a/contrib/less/input.c b/contrib/less/input.c
index f57c9e3403f2..0e021e1d05e1 100644
--- a/contrib/less/input.c
+++ b/contrib/less/input.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1984-2021 Mark Nudelman
+ * Copyright (C) 1984-2023 Mark Nudelman
*
* You may distribute under the terms of either the GNU General Public
* License or the Less License, as specified in the README file.
@@ -20,12 +20,12 @@
#include "less.h"
extern int squeeze;
-extern int chopline;
extern int hshift;
extern int quit_if_one_screen;
extern int sigs;
extern int ignore_eoi;
extern int status_col;
+extern int wordwrap;
extern POSITION start_attnpos;
extern POSITION end_attnpos;
#if HILITE_SEARCH
@@ -35,24 +35,63 @@ extern int show_attn;
#endif
/*
+ * Set the status column.
+ * base Position of first char in line.
+ * disp First visible char.
+ * Different than base_pos if line is shifted.
+ * edisp Last visible char.
+ * eol End of line. Normally the newline.
+ * Different than edisp if line is chopped.
+ */
+static void init_status_col(POSITION base_pos, POSITION disp_pos, POSITION edisp_pos, POSITION eol_pos)
+{
+ int hl_before = (chop_line() && disp_pos != NULL_POSITION) ?
+ is_hilited_attr(base_pos, disp_pos, TRUE, NULL) : 0;
+ int hl_after = (chop_line()) ?
+ is_hilited_attr(edisp_pos, eol_pos, TRUE, NULL) : 0;
+ int attr;
+ char ch;
+
+ if (hl_before && hl_after)
+ {
+ attr = hl_after;
+ ch = '=';
+ } else if (hl_before)
+ {
+ attr = hl_before;
+ ch = '<';
+ } else if (hl_after)
+ {
+ attr = hl_after;
+ ch = '>';
+ } else
+ {
+ attr = is_hilited_attr(base_pos, eol_pos, TRUE, NULL);
+ ch = '*';
+ }
+ if (attr)
+ set_status_col(ch, attr);
+}
+
+/*
* Get the next line.
* A "current" position is passed and a "new" position is returned.
* The current position is the position of the first character of
* a line. The new position is the position of the first character
* of the NEXT line. The line obtained is the line starting at curr_pos.
*/
- public POSITION
-forw_line_seg(curr_pos, get_segpos)
- POSITION curr_pos;
- int get_segpos;
+public POSITION forw_line_seg(POSITION curr_pos, int skipeol, int rscroll, int nochop)
{
POSITION base_pos;
POSITION new_pos;
+ POSITION edisp_pos;
int c;
int blankline;
int endline;
int chopped;
int backchars;
+ POSITION wrap_pos;
+ int skipped_leading;
get_forw_line:
if (curr_pos == NULL_POSITION)
@@ -123,6 +162,15 @@ get_forw_line:
if (backchars > 0)
{
pshift_all();
+ if (wordwrap && (c == ' ' || c == '\t'))
+ {
+ do
+ {
+ new_pos++;
+ c = ch_forw_get();
+ } while (c == ' ' || c == '\t');
+ backchars = 1;
+ }
new_pos -= backchars;
while (--backchars >= 0)
(void) ch_back_get();
@@ -141,6 +189,8 @@ get_forw_line:
return (NULL_POSITION);
}
blankline = (c == '\n' || c == '\r');
+ wrap_pos = NULL_POSITION;
+ skipped_leading = FALSE;
/*
* Read each character in the line and append to the line buffer.
@@ -160,12 +210,13 @@ get_forw_line:
*/
backchars = pflushmbc();
new_pos = ch_tell();
- if (backchars > 0 && !chopline && hshift == 0)
+ if (backchars > 0 && (nochop || !chop_line()) && hshift == 0)
{
new_pos -= backchars + 1;
endline = FALSE;
} else
endline = TRUE;
+ edisp_pos = new_pos;
break;
}
if (c != '\r')
@@ -182,9 +233,10 @@ get_forw_line:
* is too long to print in the screen width.
* End the line here.
*/
- if ((chopline || hshift > 0) && !get_segpos)
+ if (skipeol)
{
/* Read to end of line. */
+ edisp_pos = ch_tell();
do
{
if (ABORT_SIGS())
@@ -200,11 +252,50 @@ get_forw_line:
chopped = TRUE;
} else
{
- new_pos = ch_tell() - backchars;
+ if (!wordwrap)
+ new_pos = ch_tell() - backchars;
+ else
+ {
+ /*
+ * We're word-wrapping, so go back to the last space.
+ * However, if it's the space itself that couldn't fit,
+ * simply ignore it and any subsequent spaces.
+ */
+ if (c == ' ' || c == '\t')
+ {
+ do
+ {
+ new_pos = ch_tell();
+ c = ch_forw_get();
+ } while (c == ' ' || c == '\t');
+ if (c == '\r')
+ c = ch_forw_get();
+ if (c == '\n')
+ new_pos = ch_tell();
+ } else if (wrap_pos == NULL_POSITION)
+ new_pos = ch_tell() - backchars;
+ else
+ {
+ new_pos = wrap_pos;
+ loadc();
+ }
+ }
endline = FALSE;
}
break;
}
+ if (wordwrap)
+ {
+ if (c == ' ' || c == '\t')
+ {
+ if (skipped_leading)
+ {
+ wrap_pos = ch_tell();
+ savec();
+ }
+ } else
+ skipped_leading = TRUE;
+ }
c = ch_forw_get();
}
@@ -215,7 +306,7 @@ get_forw_line:
pappend(' ', ch_tell()-1);
}
#endif
- pdone(endline, chopped, 1);
+ pdone(endline, rscroll && chopped, 1);
#if HILITE_SEARCH
if (is_filtered(base_pos))
@@ -227,13 +318,8 @@ get_forw_line:
curr_pos = new_pos;
goto get_forw_line;
}
-
if (status_col)
- {
- int attr = is_hilited_attr(base_pos, ch_tell()-1, 1, NULL);
- if (attr)
- set_status_col('*', attr);
- }
+ init_status_col(base_pos, line_position(), edisp_pos, new_pos);
#endif
if (squeeze && blankline)
@@ -257,11 +343,10 @@ get_forw_line:
return (new_pos);
}
- public POSITION
-forw_line(curr_pos)
- POSITION curr_pos;
+public POSITION forw_line(POSITION curr_pos)
{
- return forw_line_seg(curr_pos, FALSE);
+
+ return forw_line_seg(curr_pos, (chop_line() || hshift > 0), TRUE, FALSE);
}
/*
@@ -271,15 +356,18 @@ forw_line(curr_pos)
* a line. The new position is the position of the first character
* of the PREVIOUS line. The line obtained is the one starting at new_pos.
*/
- public POSITION
-back_line(curr_pos)
- POSITION curr_pos;
+public POSITION back_line(POSITION curr_pos)
{
- POSITION new_pos, begin_new_pos, base_pos;
+ POSITION base_pos;
+ POSITION new_pos;
+ POSITION edisp_pos;
+ POSITION begin_new_pos;
int c;
int endline;
int chopped;
int backchars;
+ POSITION wrap_pos;
+ int skipped_leading;
get_back_line:
if (curr_pos == NULL_POSITION || curr_pos <= ch_zero())
@@ -381,11 +469,13 @@ get_back_line:
prewind();
plinestart(new_pos);
loop:
+ wrap_pos = NULL_POSITION;
+ skipped_leading = FALSE;
begin_new_pos = new_pos;
(void) ch_seek(new_pos);
chopped = FALSE;
- do
+ for (;;)
{
c = ch_forw_get();
if (c == EOI || ABORT_SIGS())
@@ -397,12 +487,13 @@ get_back_line:
if (c == '\n')
{
backchars = pflushmbc();
- if (backchars > 0 && !chopline && hshift == 0)
+ if (backchars > 0 && !chop_line() && hshift == 0)
{
backchars++;
goto shift;
}
endline = TRUE;
+ edisp_pos = new_pos;
break;
}
backchars = pappend(c, ch_tell()-1);
@@ -413,23 +504,70 @@ get_back_line:
* reached our curr_pos yet. Discard the line
* and start a new one.
*/
- if (chopline || hshift > 0)
+ if (chop_line() || hshift > 0)
{
endline = TRUE;
chopped = TRUE;
quit_if_one_screen = FALSE;
+ edisp_pos = new_pos;
break;
}
shift:
- pshift_all();
- while (backchars-- > 0)
+ if (!wordwrap)
{
- (void) ch_back_get();
- new_pos--;
+ pshift_all();
+ new_pos -= backchars;
+ } else
+ {
+ if (c == ' ' || c == '\t')
+ {
+ for (;;)
+ {
+ c = ch_forw_get();
+ if (c == ' ' || c == '\t')
+ new_pos++;
+ else
+ {
+ if (c == '\r')
+ {
+ c = ch_forw_get();
+ if (c == '\n')
+ new_pos++;
+ }
+ if (c == '\n')
+ new_pos++;
+ break;
+ }
+ }
+ if (new_pos >= curr_pos)
+ break;
+ pshift_all();
+ } else
+ {
+ pshift_all();
+ if (wrap_pos == NULL_POSITION)
+ new_pos -= backchars;
+ else
+ new_pos = wrap_pos;
+ }
}
goto loop;
}
- } while (new_pos < curr_pos);
+ if (wordwrap)
+ {
+ if (c == ' ' || c == '\t')
+ {
+ if (skipped_leading)
+ wrap_pos = new_pos;
+ } else
+ skipped_leading = TRUE;
+ }
+ if (new_pos >= curr_pos)
+ {
+ edisp_pos = new_pos;
+ break;
+ }
+ }
pdone(endline, chopped, 0);
@@ -443,13 +581,8 @@ get_back_line:
curr_pos = begin_new_pos;
goto get_back_line;
}
-
- if (status_col && curr_pos > 0)
- {
- int attr = is_hilited_attr(base_pos, curr_pos-1, 1, NULL);
- if (attr)
- set_status_col('*', attr);
- }
+ if (status_col)
+ init_status_col(base_pos, line_position(), edisp_pos, new_pos);
#endif
return (begin_new_pos);
@@ -458,9 +591,7 @@ get_back_line:
/*
* Set attnpos.
*/
- public void
-set_attnpos(pos)
- POSITION pos;
+public void set_attnpos(POSITION pos)
{
int c;