diff options
Diffstat (limited to 'contrib/less/input.c')
-rw-r--r-- | contrib/less/input.c | 215 |
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; |