diff --git a/command.c b/command.c index ceec50f3..360341fb 100644 --- a/command.c +++ b/command.c @@ -2043,10 +2043,10 @@ public void commands(void) if (number > 0) shift_count = number; else - number = (shift_count > 0) ? - shift_count : sc_width / 2; + number = (shift_count > 0) ? shift_count : sc_width / 2; if (number > hshift) number = hshift; + pos_rehead(); hshift -= number; screen_trashed = 1; break; @@ -2058,8 +2058,8 @@ public void commands(void) if (number > 0) shift_count = number; else - number = (shift_count > 0) ? - shift_count : sc_width / 2; + number = (shift_count > 0) ? shift_count : sc_width / 2; + pos_rehead(); hshift += number; screen_trashed = 1; break; @@ -2068,6 +2068,7 @@ public void commands(void) /* * Shift view left to margin. */ + pos_rehead(); hshift = 0; screen_trashed = 1; break; @@ -2076,6 +2077,7 @@ public void commands(void) /* * Shift view right to view rightmost char on screen. */ + pos_rehead(); hshift = rrshift(); screen_trashed = 1; break; diff --git a/line.c b/line.c index e3e57804..eab288dc 100644 --- a/line.c +++ b/line.c @@ -1329,7 +1329,7 @@ public void null_line(void) * lines which are not split for screen width. * {{ This is supposed to be more efficient than forw_line(). }} */ -public POSITION forw_raw_line(POSITION curr_pos, char **linep, int *line_lenp) +public POSITION forw_raw_line_len(POSITION curr_pos, int read_len, char **linep, int *line_lenp) { int n; int c; @@ -1360,6 +1360,11 @@ public POSITION forw_raw_line(POSITION curr_pos, char **linep, int *line_lenp) } } linebuf.buf[n++] = c; + if (read_len >= 0 && n >= read_len) + { + new_pos = ch_tell(); + break; + } c = ch_forw_get(); } linebuf.buf[n] = '\0'; @@ -1370,6 +1375,11 @@ public POSITION forw_raw_line(POSITION curr_pos, char **linep, int *line_lenp) return (new_pos); } +public POSITION forw_raw_line(POSITION curr_pos, char **linep, int *line_lenp) +{ + return forw_raw_line_len(curr_pos, -1, linep, line_lenp); +} + /* * Analogous to back_line(), but deals with "raw lines". * {{ This is supposed to be more efficient than back_line(). }} diff --git a/optfunc.c b/optfunc.c index a3bdd0da..450e2567 100644 --- a/optfunc.c +++ b/optfunc.c @@ -312,6 +312,19 @@ public void opt_ks(int type, char *s) #endif /* HAVE_LESSKEYSRC */ #endif /* USERFILE */ +/* + * Handler for -S option. + */ +public void opt__S(int type, char *s) +{ + switch (type) + { + case TOGGLE: + pos_rehead(); + break; + } +} + #if TAGS /* * Handler for -t option. diff --git a/opttbl.c b/opttbl.c index 3261b7ec..f2efbab1 100644 --- a/opttbl.c +++ b/opttbl.c @@ -393,7 +393,7 @@ static struct loption option[] = } }, { 'S', &S__optname, - BOOL|REPAINT, OPT_OFF, &chopline, NULL, + BOOL|REPAINT, OPT_OFF, &chopline, opt__S, { "Fold long lines", "Chop long lines", diff --git a/position.c b/position.c index c0f86614..d2fda467 100644 --- a/position.c +++ b/position.c @@ -26,6 +26,9 @@ static int table_size = 0; extern int sc_width, sc_height; extern int header_lines; +extern int screen_trashed; +extern int hshift; +extern int chopline; /* * Return the starting file position of a line displayed on the screen. @@ -236,3 +239,73 @@ public int sindex_from_sline(int sline) */ return (sline-1); } + +/* + * Given a line that starts at linepos, + * and the character at byte offset choff into that line, + * return the number of characters (not bytes) between the + * beginning of the line and the first byte of the choff character. + */ +static int pos_shift(POSITION linepos, int choff) +{ + char *line; + int line_len; + POSITION pos; + int cvt_ops; + int cvt_len; + int *chpos; + char *cline; + + pos = forw_raw_line_len(linepos, choff, &line, &line_len); + if (pos == NULL_POSITION || line_len != choff) + return -1; + cvt_ops = get_cvt_ops(0); + cvt_len = cvt_length(line_len, cvt_ops); + chpos = cvt_alloc_chpos(cvt_len); + cline = (char *) ecalloc(1, line_len); + cvt_text(cline, line, chpos, &line_len, cvt_ops); + free(cline); + free(chpos); + return line_len; +} + +/* + * Return the position of the first char of the line containing tpos. + * Thus if tpos is the first char of its line, just return tpos. + */ +static POSITION beginning_of_line(POSITION tpos) +{ + ch_seek(tpos); + while (ch_tell() != ch_zero()) + { + int ch = ch_back_get(); + if (ch == '\n') + { + (void) ch_forw_get(); + break; + } + } + return ch_tell(); +} + +/* + * When viewing long lines, it may be that the first char in the top screen + * line is not the first char in its (file) line (the table is "beheaded"). + * (The top line on the screen is the only one that can be in this state.) + * This function sets that entry to the position of the first char in the line. + */ +public void pos_rehead(void) +{ + POSITION linepos; + POSITION tpos = table[TOP]; + if (!chopline) + return; + if (tpos == NULL_POSITION) + return; + linepos = beginning_of_line(tpos); + if (linepos == tpos) + return; + table[TOP] = linepos; + hshift = pos_shift(linepos, tpos - linepos); + screen_trashed = 1; +} diff --git a/search.c b/search.c index 0c02c32c..cf8722e8 100644 --- a/search.c +++ b/search.c @@ -210,7 +210,7 @@ public void init_search(void) /* * Determine which text conversions to perform before pattern matching. */ -static int get_cvt_ops(int search_type) +public int get_cvt_ops(int search_type) { int ops = 0; @@ -580,7 +580,7 @@ static void shift_visible(int start_off, int end_off) int swidth = sc_width - line_pfx_width(); if (start_off >= hshift && end_off < hshift + swidth) return; /* already visible */ - hshift = (end_off < swidth) ? 0 : start_off < found_shift ? 0 : start_off - found_shift; + hshift = (end_off < swidth) ? 0 : (start_off < found_shift) ? 0 : (start_off - found_shift); screen_trashed = 1; }