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