1 /* 2 * Copyright (C) 1984-2015 Mark Nudelman 3 * 4 * You may distribute under the terms of either the GNU General Public 5 * License or the Less License, as specified in the README file. 6 * 7 * For more information, see the README file. 8 */ 9 10 11 /* 12 * Primitives for displaying the file on the screen, 13 * scrolling either forward or backward. 14 */ 15 16 #include "less.h" 17 #include "position.h" 18 19 public int screen_trashed; 20 public int squished; 21 public int no_back_scroll = 0; 22 public int forw_prompt; 23 public int same_pos_bell = 1; 24 25 extern int sigs; 26 extern int top_scroll; 27 extern int quiet; 28 extern int sc_width, sc_height; 29 extern int plusoption; 30 extern int forw_scroll; 31 extern int back_scroll; 32 extern int ignore_eoi; 33 extern int clear_bg; 34 extern int final_attr; 35 extern int oldbot; 36 #if HILITE_SEARCH 37 extern int size_linebuf; 38 extern int hilite_search; 39 extern int status_col; 40 #endif 41 #if TAGS 42 extern char *tagoption; 43 #endif 44 45 /* 46 * Sound the bell to indicate user is trying to move past end of file. 47 */ 48 static void 49 eof_bell() 50 { 51 if (quiet == NOT_QUIET) 52 bell(); 53 else 54 vbell(); 55 } 56 57 /* 58 * Check to see if the end of file is currently displayed. 59 */ 60 public int 61 eof_displayed() 62 { 63 POSITION pos; 64 65 if (ignore_eoi) 66 return (0); 67 68 if (ch_length() == NULL_POSITION) 69 /* 70 * If the file length is not known, 71 * we can't possibly be displaying EOF. 72 */ 73 return (0); 74 75 /* 76 * If the bottom line is empty, we are at EOF. 77 * If the bottom line ends at the file length, 78 * we must be just at EOF. 79 */ 80 pos = position(BOTTOM_PLUS_ONE); 81 return (pos == NULL_POSITION || pos == ch_length()); 82 } 83 84 /* 85 * Check to see if the entire file is currently displayed. 86 */ 87 public int 88 entire_file_displayed() 89 { 90 POSITION pos; 91 92 /* Make sure last line of file is displayed. */ 93 if (!eof_displayed()) 94 return (0); 95 96 /* Make sure first line of file is displayed. */ 97 pos = position(0); 98 return (pos == NULL_POSITION || pos == 0); 99 } 100 101 /* 102 * If the screen is "squished", repaint it. 103 * "Squished" means the first displayed line is not at the top 104 * of the screen; this can happen when we display a short file 105 * for the first time. 106 */ 107 public void 108 squish_check() 109 { 110 if (!squished) 111 return; 112 squished = 0; 113 repaint(); 114 } 115 116 /* 117 * Display n lines, scrolling forward, 118 * starting at position pos in the input file. 119 * "force" means display the n lines even if we hit end of file. 120 * "only_last" means display only the last screenful if n > screen size. 121 * "nblank" is the number of blank lines to draw before the first 122 * real line. If nblank > 0, the pos must be NULL_POSITION. 123 * The first real line after the blanks will start at ch_zero(). 124 */ 125 public void 126 forw(n, pos, force, only_last, nblank) 127 register int n; 128 POSITION pos; 129 int force; 130 int only_last; 131 int nblank; 132 { 133 int nlines = 0; 134 int do_repaint; 135 static int first_time = 1; 136 137 squish_check(); 138 139 /* 140 * do_repaint tells us not to display anything till the end, 141 * then just repaint the entire screen. 142 * We repaint if we are supposed to display only the last 143 * screenful and the request is for more than a screenful. 144 * Also if the request exceeds the forward scroll limit 145 * (but not if the request is for exactly a screenful, since 146 * repainting itself involves scrolling forward a screenful). 147 */ 148 do_repaint = (only_last && n > sc_height-1) || 149 (forw_scroll >= 0 && n > forw_scroll && n != sc_height-1); 150 151 #if HILITE_SEARCH 152 if (hilite_search == OPT_ONPLUS || is_filtering() || status_col) { 153 prep_hilite(pos, pos + 4*size_linebuf, ignore_eoi ? 1 : -1); 154 pos = next_unfiltered(pos); 155 } 156 #endif 157 158 if (!do_repaint) 159 { 160 if (top_scroll && n >= sc_height - 1 && pos != ch_length()) 161 { 162 /* 163 * Start a new screen. 164 * {{ This is not really desirable if we happen 165 * to hit eof in the middle of this screen, 166 * but we don't yet know if that will happen. }} 167 */ 168 pos_clear(); 169 add_forw_pos(pos); 170 force = 1; 171 clear(); 172 home(); 173 } 174 175 if (pos != position(BOTTOM_PLUS_ONE) || empty_screen()) 176 { 177 /* 178 * This is not contiguous with what is 179 * currently displayed. Clear the screen image 180 * (position table) and start a new screen. 181 */ 182 pos_clear(); 183 add_forw_pos(pos); 184 force = 1; 185 if (top_scroll) 186 { 187 clear(); 188 home(); 189 } else if (!first_time) 190 { 191 putstr("...skipping...\n"); 192 } 193 } 194 } 195 196 while (--n >= 0) 197 { 198 /* 199 * Read the next line of input. 200 */ 201 if (nblank > 0) 202 { 203 /* 204 * Still drawing blanks; don't get a line 205 * from the file yet. 206 * If this is the last blank line, get ready to 207 * read a line starting at ch_zero() next time. 208 */ 209 if (--nblank == 0) 210 pos = ch_zero(); 211 } else 212 { 213 /* 214 * Get the next line from the file. 215 */ 216 pos = forw_line(pos); 217 #if HILITE_SEARCH 218 pos = next_unfiltered(pos); 219 #endif 220 if (pos == NULL_POSITION) 221 { 222 /* 223 * End of file: stop here unless the top line 224 * is still empty, or "force" is true. 225 * Even if force is true, stop when the last 226 * line in the file reaches the top of screen. 227 */ 228 if (!force && position(TOP) != NULL_POSITION) 229 break; 230 if (!empty_lines(0, 0) && 231 !empty_lines(1, 1) && 232 empty_lines(2, sc_height-1)) 233 break; 234 } 235 } 236 /* 237 * Add the position of the next line to the position table. 238 * Display the current line on the screen. 239 */ 240 add_forw_pos(pos); 241 nlines++; 242 if (do_repaint) 243 continue; 244 /* 245 * If this is the first screen displayed and 246 * we hit an early EOF (i.e. before the requested 247 * number of lines), we "squish" the display down 248 * at the bottom of the screen. 249 * But don't do this if a + option or a -t option 250 * was given. These options can cause us to 251 * start the display after the beginning of the file, 252 * and it is not appropriate to squish in that case. 253 */ 254 if (first_time && pos == NULL_POSITION && !top_scroll && 255 #if TAGS 256 tagoption == NULL && 257 #endif 258 !plusoption) 259 { 260 squished = 1; 261 continue; 262 } 263 put_line(); 264 #if 0 265 /* {{ 266 * Can't call clear_eol here. The cursor might be at end of line 267 * on an ignaw terminal, so clear_eol would clear the last char 268 * of the current line instead of all of the next line. 269 * If we really need to do this on clear_bg terminals, we need 270 * to find a better way. 271 * }} 272 */ 273 if (clear_bg && apply_at_specials(final_attr) != AT_NORMAL) 274 { 275 /* 276 * Writing the last character on the last line 277 * of the display may have scrolled the screen. 278 * If we were in standout mode, clear_bg terminals 279 * will fill the new line with the standout color. 280 * Now we're in normal mode again, so clear the line. 281 */ 282 clear_eol(); 283 } 284 #endif 285 forw_prompt = 1; 286 } 287 288 if (nlines == 0 && same_pos_bell) 289 eof_bell(); 290 else if (do_repaint) 291 repaint(); 292 first_time = 0; 293 (void) currline(BOTTOM); 294 } 295 296 /* 297 * Display n lines, scrolling backward. 298 */ 299 public void 300 back(n, pos, force, only_last) 301 register int n; 302 POSITION pos; 303 int force; 304 int only_last; 305 { 306 int nlines = 0; 307 int do_repaint; 308 309 squish_check(); 310 do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1)); 311 #if HILITE_SEARCH 312 if (hilite_search == OPT_ONPLUS || is_filtering() || status_col) { 313 prep_hilite((pos < 3*size_linebuf) ? 0 : pos - 3*size_linebuf, pos, -1); 314 } 315 #endif 316 while (--n >= 0) 317 { 318 /* 319 * Get the previous line of input. 320 */ 321 #if HILITE_SEARCH 322 pos = prev_unfiltered(pos); 323 #endif 324 325 pos = back_line(pos); 326 if (pos == NULL_POSITION) 327 { 328 /* 329 * Beginning of file: stop here unless "force" is true. 330 */ 331 if (!force) 332 break; 333 } 334 /* 335 * Add the position of the previous line to the position table. 336 * Display the line on the screen. 337 */ 338 add_back_pos(pos); 339 nlines++; 340 if (!do_repaint) 341 { 342 home(); 343 add_line(); 344 put_line(); 345 } 346 } 347 348 if (nlines == 0 && same_pos_bell) 349 eof_bell(); 350 else if (do_repaint) 351 repaint(); 352 else if (!oldbot) 353 lower_left(); 354 (void) currline(BOTTOM); 355 } 356 357 /* 358 * Display n more lines, forward. 359 * Start just after the line currently displayed at the bottom of the screen. 360 */ 361 public void 362 forward(n, force, only_last) 363 int n; 364 int force; 365 int only_last; 366 { 367 POSITION pos; 368 369 if (get_quit_at_eof() && eof_displayed() && !(ch_getflags() & CH_HELPFILE)) 370 { 371 /* 372 * If the -e flag is set and we're trying to go 373 * forward from end-of-file, go on to the next file. 374 */ 375 if (edit_next(1)) 376 quit(QUIT_OK); 377 return; 378 } 379 380 pos = position(BOTTOM_PLUS_ONE); 381 if (pos == NULL_POSITION && (!force || empty_lines(2, sc_height-1))) 382 { 383 if (ignore_eoi) 384 { 385 /* 386 * ignore_eoi is to support A_F_FOREVER. 387 * Back up until there is a line at the bottom 388 * of the screen. 389 */ 390 if (empty_screen()) 391 pos = ch_zero(); 392 else 393 { 394 do 395 { 396 back(1, position(TOP), 1, 0); 397 pos = position(BOTTOM_PLUS_ONE); 398 } while (pos == NULL_POSITION); 399 } 400 } else 401 { 402 eof_bell(); 403 return; 404 } 405 } 406 forw(n, pos, force, only_last, 0); 407 } 408 409 /* 410 * Display n more lines, backward. 411 * Start just before the line currently displayed at the top of the screen. 412 */ 413 public void 414 backward(n, force, only_last) 415 int n; 416 int force; 417 int only_last; 418 { 419 POSITION pos; 420 421 pos = position(TOP); 422 if (pos == NULL_POSITION && (!force || position(BOTTOM) == 0)) 423 { 424 eof_bell(); 425 return; 426 } 427 back(n, pos, force, only_last); 428 } 429 430 /* 431 * Get the backwards scroll limit. 432 * Must call this function instead of just using the value of 433 * back_scroll, because the default case depends on sc_height and 434 * top_scroll, as well as back_scroll. 435 */ 436 public int 437 get_back_scroll() 438 { 439 if (no_back_scroll) 440 return (0); 441 if (back_scroll >= 0) 442 return (back_scroll); 443 if (top_scroll) 444 return (sc_height - 2); 445 return (10000); /* infinity */ 446 } 447