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