Mercurial > emacs
annotate src/cm.c @ 69478:e8bb5df2ba7a
Add index entries around each paragraph rather than depend on entries
from beginning of node. Doing so ensures that index entries are less
likely to be forgotten if text is cut and pasted, and are necessary
anyway if the references are on a separate page. It seems that
makeinfo is now (v. 4.8) only producing one index entry per node, so
there is no longer any excuse not to. Use subheading instead of
heading. The incorrect use of heading produced very large fonts in
Info--as large as the main heading.
(From Bill Wohler): MH-E never did appear in Emacs 21--MH-E versions 6
and 7 appeared *around* the time of these Emacs releases.
author | Bill Wohler <wohler@newt.com> |
---|---|
date | Wed, 15 Mar 2006 00:26:12 +0000 |
parents | 3bd95f4f2941 |
children | e90d04cd455a b98066f4aa10 c5406394f567 |
rev | line source |
---|---|
484 | 1 /* Cursor motion subroutines for GNU Emacs. |
64770
a0d1312ede66
Update years in copyright notice; nfc.
Thien-Thi Nguyen <ttn@gnuvola.org>
parents:
64084
diff
changeset
|
2 Copyright (C) 1985, 1995, 2002, 2003, 2004, |
68651
3bd95f4f2941
Update years in copyright notice; nfc.
Thien-Thi Nguyen <ttn@gnuvola.org>
parents:
64770
diff
changeset
|
3 2005, 2006 Free Software Foundation, Inc. |
484 | 4 based primarily on public domain code written by Chris Torek |
5 | |
6 This file is part of GNU Emacs. | |
7 | |
8 GNU Emacs is free software; you can redistribute it and/or modify | |
9 it under the terms of the GNU General Public License as published by | |
7107 | 10 the Free Software Foundation; either version 2, or (at your option) |
484 | 11 any later version. |
12 | |
13 GNU Emacs is distributed in the hope that it will be useful, | |
14 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 GNU General Public License for more details. | |
17 | |
18 You should have received a copy of the GNU General Public License | |
19 along with GNU Emacs; see the file COPYING. If not, write to | |
64084 | 20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
21 Boston, MA 02110-1301, USA. */ | |
484 | 22 |
23 | |
4696
1fc792473491
Include <config.h> instead of "config.h".
Roland McGrath <roland@gnu.org>
parents:
484
diff
changeset
|
24 #include <config.h> |
484 | 25 #include <stdio.h> |
26 #include "cm.h" | |
27 #include "termhooks.h" | |
28 | |
33672
a94852aef620
Don't try to include termcap.h; see comment there.
Gerd Moellmann <gerd@gnu.org>
parents:
30915
diff
changeset
|
29 /* For now, don't try to include termcap.h. On some systems, |
a94852aef620
Don't try to include termcap.h; see comment there.
Gerd Moellmann <gerd@gnu.org>
parents:
30915
diff
changeset
|
30 configure finds a non-standard termcap.h that the main build |
a94852aef620
Don't try to include termcap.h; see comment there.
Gerd Moellmann <gerd@gnu.org>
parents:
30915
diff
changeset
|
31 won't find. */ |
a94852aef620
Don't try to include termcap.h; see comment there.
Gerd Moellmann <gerd@gnu.org>
parents:
30915
diff
changeset
|
32 |
a94852aef620
Don't try to include termcap.h; see comment there.
Gerd Moellmann <gerd@gnu.org>
parents:
30915
diff
changeset
|
33 #if defined HAVE_TERMCAP_H && 0 |
25734
0242362bb1fe
(toplevel) [HAVE_TERMCAP_H]: Include termcap.h.
Gerd Moellmann <gerd@gnu.org>
parents:
25333
diff
changeset
|
34 #include <termcap.h> |
30915
10dd42348df3
[HAVE_TERMCAP_H]: Include <termcap.h>.
Dave Love <fx@gnu.org>
parents:
29909
diff
changeset
|
35 #else |
10dd42348df3
[HAVE_TERMCAP_H]: Include <termcap.h>.
Dave Love <fx@gnu.org>
parents:
29909
diff
changeset
|
36 extern void tputs P_ ((const char *, int, int (*)(int))); |
10dd42348df3
[HAVE_TERMCAP_H]: Include <termcap.h>.
Dave Love <fx@gnu.org>
parents:
29909
diff
changeset
|
37 extern char *tgoto P_ ((const char *, int, int)); |
25734
0242362bb1fe
(toplevel) [HAVE_TERMCAP_H]: Include termcap.h.
Gerd Moellmann <gerd@gnu.org>
parents:
25333
diff
changeset
|
38 #endif |
0242362bb1fe
(toplevel) [HAVE_TERMCAP_H]: Include termcap.h.
Gerd Moellmann <gerd@gnu.org>
parents:
25333
diff
changeset
|
39 |
484 | 40 #define BIG 9999 /* 9999 good on VAXen. For 16 bit machines |
41 use about 2000.... */ | |
42 | |
43 extern char *BC, *UP; | |
44 | |
45 int cost; /* sums up costs */ | |
46 | |
47 /* ARGSUSED */ | |
21514 | 48 int |
484 | 49 evalcost (c) |
50 char c; | |
51 { | |
52 cost++; | |
8985
2825665b8352
(evalcost, cmputc): They now return their arguments.
Richard M. Stallman <rms@gnu.org>
parents:
7107
diff
changeset
|
53 return c; |
484 | 54 } |
55 | |
21514 | 56 int |
484 | 57 cmputc (c) |
58 char c; | |
59 { | |
60 if (termscript) | |
61 fputc (c & 0177, termscript); | |
62 putchar (c & 0177); | |
8985
2825665b8352
(evalcost, cmputc): They now return their arguments.
Richard M. Stallman <rms@gnu.org>
parents:
7107
diff
changeset
|
63 return c; |
484 | 64 } |
65 | |
66 /* NEXT TWO ARE DONE WITH MACROS */ | |
67 #if 0 | |
68 /* | |
69 * Assume the cursor is at row row, column col. Normally used only after | |
70 * clearing the screen, when the cursor is at (0, 0), but what the heck, | |
71 * let's let the guy put it anywhere. | |
72 */ | |
73 | |
74 static | |
75 at (row, col) { | |
76 curY = row; | |
77 curX = col; | |
78 } | |
79 | |
80 /* | |
81 * Add n columns to the current cursor position. | |
82 */ | |
83 | |
84 static | |
85 addcol (n) { | |
86 curX += n; | |
87 | |
88 /* | |
89 * If cursor hit edge of screen, what happened? | |
90 * N.B.: DO NOT!! write past edge of screen. If you do, you | |
91 * deserve what you get. Furthermore, on terminals with | |
92 * autowrap (but not magicwrap), don't write in the last column | |
93 * of the last line. | |
94 */ | |
95 | |
96 if (curX == Wcm.cm_cols) { | |
97 /* | |
98 * Well, if magicwrap, still there, past the edge of the | |
99 * screen (!). If autowrap, on the col 0 of the next line. | |
100 * Otherwise on last column. | |
101 */ | |
102 | |
103 if (Wcm.cm_magicwrap) | |
104 ; /* "limbo" */ | |
105 else if (Wcm.cm_autowrap) { | |
106 curX = 0; | |
107 curY++; /* Beware end of screen! */ | |
108 } | |
109 else | |
110 curX--; | |
111 } | |
112 } | |
113 #endif | |
114 | |
115 /* | |
10437 | 116 * Terminals with magicwrap (xn) don't all behave identically. |
117 * The VT100 leaves the cursor in the last column but will wrap before | |
118 * printing the next character. I hear that the Concept terminal does | |
119 * the wrap immediately but ignores the next newline it sees. And some | |
120 * terminals just have buggy firmware, and think that the cursor is still | |
121 * in limbo if we use direct cursor addressing from the phantom column. | |
122 * The only guaranteed safe thing to do is to emit a CRLF immediately | |
123 * after we reach the last column; this takes us to a known state. | |
124 */ | |
125 void | |
126 cmcheckmagic () | |
127 { | |
128 if (curX == FrameCols) | |
129 { | |
130 if (!MagicWrap || curY >= FrameRows - 1) | |
131 abort (); | |
132 if (termscript) | |
133 putc ('\r', termscript); | |
134 putchar ('\r'); | |
135 if (termscript) | |
136 putc ('\n', termscript); | |
137 putchar ('\n'); | |
138 curX = 0; | |
139 curY++; | |
140 } | |
141 } | |
142 | |
143 | |
144 /* | |
484 | 145 * (Re)Initialize the cost factors, given the output speed of the terminal |
146 * in the variable ospeed. (Note: this holds B300, B9600, etc -- ie stuff | |
147 * out of <sgtty.h>.) | |
148 */ | |
149 | |
21514 | 150 void |
484 | 151 cmcostinit () |
152 { | |
153 char *p; | |
154 | |
155 #define COST(x,e) (x ? (cost = 0, tputs (x, 1, e), cost) : BIG) | |
156 #define CMCOST(x,e) ((x == 0) ? BIG : (p = tgoto(x, 0, 0), COST(p ,e))) | |
157 | |
158 Wcm.cc_up = COST (Wcm.cm_up, evalcost); | |
159 Wcm.cc_down = COST (Wcm.cm_down, evalcost); | |
160 Wcm.cc_left = COST (Wcm.cm_left, evalcost); | |
161 Wcm.cc_right = COST (Wcm.cm_right, evalcost); | |
162 Wcm.cc_home = COST (Wcm.cm_home, evalcost); | |
163 Wcm.cc_cr = COST (Wcm.cm_cr, evalcost); | |
164 Wcm.cc_ll = COST (Wcm.cm_ll, evalcost); | |
165 Wcm.cc_tab = Wcm.cm_tabwidth ? COST (Wcm.cm_tab, evalcost) : BIG; | |
166 | |
167 /* | |
168 * These last three are actually minimum costs. When (if) they are | |
169 * candidates for the least-cost motion, the real cost is computed. | |
170 * (Note that "0" is the assumed to generate the minimum cost. | |
171 * While this is not necessarily true, I have yet to see a terminal | |
172 * for which is not; all the terminals that have variable-cost | |
173 * cursor motion seem to take straight numeric values. --ACT) | |
174 */ | |
175 | |
176 Wcm.cc_abs = CMCOST (Wcm.cm_abs, evalcost); | |
177 Wcm.cc_habs = CMCOST (Wcm.cm_habs, evalcost); | |
178 Wcm.cc_vabs = CMCOST (Wcm.cm_vabs, evalcost); | |
179 | |
180 #undef CMCOST | |
181 #undef COST | |
182 } | |
183 | |
184 /* | |
185 * Calculate the cost to move from (srcy, srcx) to (dsty, dstx) using | |
186 * up and down, and left and right, motions, and tabs. If doit is set | |
187 * actually perform the motion. | |
188 */ | |
189 | |
21514 | 190 static int |
484 | 191 calccost (srcy, srcx, dsty, dstx, doit) |
48318
5c1be14cbcac
(calccost, cmgoto): Declare all args (per C99).
Dave Love <fx@gnu.org>
parents:
33672
diff
changeset
|
192 int srcy, srcx, dsty, dstx, doit; |
484 | 193 { |
194 register int deltay, | |
195 deltax, | |
196 c, | |
197 totalcost; | |
198 int ntabs, | |
199 n2tabs, | |
200 tabx, | |
201 tab2x, | |
202 tabcost; | |
203 register char *p; | |
204 | |
205 /* If have just wrapped on a terminal with xn, | |
206 don't believe the cursor position: give up here | |
207 and force use of absolute positioning. */ | |
208 | |
209 if (curX == Wcm.cm_cols) | |
210 goto fail; | |
211 | |
212 totalcost = 0; | |
213 if ((deltay = dsty - srcy) == 0) | |
214 goto x; | |
215 if (deltay < 0) | |
216 p = Wcm.cm_up, c = Wcm.cc_up, deltay = -deltay; | |
217 else | |
218 p = Wcm.cm_down, c = Wcm.cc_down; | |
219 if (c == BIG) { /* caint get thar from here */ | |
220 if (doit) | |
221 printf ("OOPS"); | |
222 return c; | |
223 } | |
224 totalcost = c * deltay; | |
225 if (doit) | |
226 while (--deltay >= 0) | |
227 tputs (p, 1, cmputc); | |
49600
23a1cea22d13
Trailing whitespace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48318
diff
changeset
|
228 x: |
484 | 229 if ((deltax = dstx - srcx) == 0) |
230 goto done; | |
231 if (deltax < 0) { | |
232 p = Wcm.cm_left, c = Wcm.cc_left, deltax = -deltax; | |
233 goto dodelta; /* skip all the tab junk */ | |
234 } | |
235 /* Tabs (the toughie) */ | |
236 if (Wcm.cc_tab >= BIG || !Wcm.cm_usetabs) | |
237 goto olddelta; /* forget it! */ | |
238 | |
49600
23a1cea22d13
Trailing whitespace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48318
diff
changeset
|
239 /* |
484 | 240 * ntabs is # tabs towards but not past dstx; n2tabs is one more |
241 * (ie past dstx), but this is only valid if that is not past the | |
242 * right edge of the screen. We can check that at the same time | |
243 * as we figure out where we would be if we use the tabs (which | |
244 * we will put into tabx (for ntabs) and tab2x (for n2tabs)). | |
245 */ | |
246 | |
247 ntabs = (deltax + srcx % Wcm.cm_tabwidth) / Wcm.cm_tabwidth; | |
248 n2tabs = ntabs + 1; | |
249 tabx = (srcx / Wcm.cm_tabwidth + ntabs) * Wcm.cm_tabwidth; | |
250 tab2x = tabx + Wcm.cm_tabwidth; | |
251 | |
252 if (tab2x >= Wcm.cm_cols) /* too far (past edge) */ | |
253 n2tabs = 0; | |
254 | |
49600
23a1cea22d13
Trailing whitespace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48318
diff
changeset
|
255 /* |
484 | 256 * Now set tabcost to the cost for using ntabs, and c to the cost |
257 * for using n2tabs, then pick the minimum. | |
258 */ | |
259 | |
260 /* cost for ntabs + cost for right motion */ | |
261 tabcost = ntabs ? ntabs * Wcm.cc_tab + (dstx - tabx) * Wcm.cc_right | |
262 : BIG; | |
263 | |
264 /* cost for n2tabs + cost for left motion */ | |
265 c = n2tabs ? n2tabs * Wcm.cc_tab + (tab2x - dstx) * Wcm.cc_left | |
266 : BIG; | |
267 | |
268 if (c < tabcost) /* then cheaper to overshoot & back up */ | |
269 ntabs = n2tabs, tabcost = c, tabx = tab2x; | |
270 | |
271 if (tabcost >= BIG) /* caint use tabs */ | |
272 goto newdelta; | |
273 | |
49600
23a1cea22d13
Trailing whitespace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48318
diff
changeset
|
274 /* |
484 | 275 * See if tabcost is less than just moving right |
276 */ | |
277 | |
278 if (tabcost < (deltax * Wcm.cc_right)) { | |
279 totalcost += tabcost; /* use the tabs */ | |
280 if (doit) | |
281 while (--ntabs >= 0) | |
282 tputs (Wcm.cm_tab, 1, cmputc); | |
283 srcx = tabx; | |
284 } | |
285 | |
49600
23a1cea22d13
Trailing whitespace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48318
diff
changeset
|
286 /* |
484 | 287 * Now might as well just recompute the delta. |
288 */ | |
289 | |
49600
23a1cea22d13
Trailing whitespace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48318
diff
changeset
|
290 newdelta: |
484 | 291 if ((deltax = dstx - srcx) == 0) |
292 goto done; | |
49600
23a1cea22d13
Trailing whitespace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48318
diff
changeset
|
293 olddelta: |
484 | 294 if (deltax > 0) |
295 p = Wcm.cm_right, c = Wcm.cc_right; | |
296 else | |
297 p = Wcm.cm_left, c = Wcm.cc_left, deltax = -deltax; | |
298 | |
49600
23a1cea22d13
Trailing whitespace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48318
diff
changeset
|
299 dodelta: |
484 | 300 if (c == BIG) { /* caint get thar from here */ |
301 fail: | |
302 if (doit) | |
303 printf ("OOPS"); | |
304 return BIG; | |
305 } | |
306 totalcost += c * deltax; | |
307 if (doit) | |
308 while (--deltax >= 0) | |
309 tputs (p, 1, cmputc); | |
49600
23a1cea22d13
Trailing whitespace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48318
diff
changeset
|
310 done: |
484 | 311 return totalcost; |
312 } | |
313 | |
314 #if 0 | |
315 losecursor () | |
316 { | |
317 curY = -1; | |
318 } | |
319 #endif | |
320 | |
321 #define USEREL 0 | |
322 #define USEHOME 1 | |
323 #define USELL 2 | |
324 #define USECR 3 | |
325 | |
21514 | 326 void |
484 | 327 cmgoto (row, col) |
48318
5c1be14cbcac
(calccost, cmgoto): Declare all args (per C99).
Dave Love <fx@gnu.org>
parents:
33672
diff
changeset
|
328 int row, col; |
484 | 329 { |
330 int homecost, | |
331 crcost, | |
332 llcost, | |
333 relcost, | |
334 directcost; | |
335 int use; | |
336 char *p, | |
337 *dcm; | |
338 | |
339 /* First the degenerate case */ | |
340 if (row == curY && col == curX) /* already there */ | |
341 return; | |
342 | |
343 if (curY >= 0 && curX >= 0) | |
344 { | |
345 /* We may have quick ways to go to the upper-left, bottom-left, | |
346 * start-of-line, or start-of-next-line. Or it might be best to | |
347 * start where we are. Examine the options, and pick the cheapest. | |
348 */ | |
349 | |
350 relcost = calccost (curY, curX, row, col, 0); | |
351 use = USEREL; | |
352 if ((homecost = Wcm.cc_home) < BIG) | |
353 homecost += calccost (0, 0, row, col, 0); | |
354 if (homecost < relcost) | |
355 relcost = homecost, use = USEHOME; | |
356 if ((llcost = Wcm.cc_ll) < BIG) | |
357 llcost += calccost (Wcm.cm_rows - 1, 0, row, col, 0); | |
358 if (llcost < relcost) | |
359 relcost = llcost, use = USELL; | |
360 if ((crcost = Wcm.cc_cr) < BIG) { | |
361 if (Wcm.cm_autolf) | |
362 if (curY + 1 >= Wcm.cm_rows) | |
363 crcost = BIG; | |
364 else | |
365 crcost += calccost (curY + 1, 0, row, col, 0); | |
366 else | |
367 crcost += calccost (curY, 0, row, col, 0); | |
368 } | |
369 if (crcost < relcost) | |
370 relcost = crcost, use = USECR; | |
371 directcost = Wcm.cc_abs, dcm = Wcm.cm_abs; | |
372 if (row == curY && Wcm.cc_habs < BIG) | |
373 directcost = Wcm.cc_habs, dcm = Wcm.cm_habs; | |
374 else if (col == curX && Wcm.cc_vabs < BIG) | |
375 directcost = Wcm.cc_vabs, dcm = Wcm.cm_vabs; | |
376 } | |
377 else | |
378 { | |
379 directcost = 0, relcost = 100000; | |
380 dcm = Wcm.cm_abs; | |
381 } | |
382 | |
49600
23a1cea22d13
Trailing whitespace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48318
diff
changeset
|
383 /* |
484 | 384 * In the following comparison, the = in <= is because when the costs |
385 * are the same, it looks nicer (I think) to move directly there. | |
386 */ | |
387 if (directcost <= relcost) | |
388 { | |
389 /* compute REAL direct cost */ | |
390 cost = 0; | |
391 p = dcm == Wcm.cm_habs ? tgoto (dcm, row, col) : | |
392 tgoto (dcm, col, row); | |
393 tputs (p, 1, evalcost); | |
394 if (cost <= relcost) | |
395 { /* really is cheaper */ | |
396 tputs (p, 1, cmputc); | |
397 curY = row, curX = col; | |
398 return; | |
399 } | |
400 } | |
401 | |
402 switch (use) | |
403 { | |
49600
23a1cea22d13
Trailing whitespace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48318
diff
changeset
|
404 case USEHOME: |
484 | 405 tputs (Wcm.cm_home, 1, cmputc); |
406 curY = 0, curX = 0; | |
407 break; | |
408 | |
49600
23a1cea22d13
Trailing whitespace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48318
diff
changeset
|
409 case USELL: |
484 | 410 tputs (Wcm.cm_ll, 1, cmputc); |
411 curY = Wcm.cm_rows - 1, curX = 0; | |
412 break; | |
413 | |
49600
23a1cea22d13
Trailing whitespace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48318
diff
changeset
|
414 case USECR: |
484 | 415 tputs (Wcm.cm_cr, 1, cmputc); |
416 if (Wcm.cm_autolf) | |
417 curY++; | |
418 curX = 0; | |
419 break; | |
420 } | |
421 | |
422 (void) calccost (curY, curX, row, col, 1); | |
423 curY = row, curX = col; | |
424 } | |
425 | |
426 /* Clear out all terminal info. | |
427 Used before copying into it the info on the actual terminal. | |
428 */ | |
429 | |
21514 | 430 void |
484 | 431 Wcm_clear () |
432 { | |
433 bzero (&Wcm, sizeof Wcm); | |
434 UP = 0; | |
435 BC = 0; | |
436 } | |
437 | |
438 /* | |
439 * Initialized stuff | |
440 * Return 0 if can do CM. | |
441 * Return -1 if cannot. | |
442 * Return -2 if size not specified. | |
443 */ | |
444 | |
21514 | 445 int |
484 | 446 Wcm_init () |
447 { | |
448 #if 0 | |
449 if (Wcm.cm_abs && !Wcm.cm_ds) | |
450 return 0; | |
451 #endif | |
452 if (Wcm.cm_abs) | |
453 return 0; | |
454 /* Require up and left, and, if no absolute, down and right */ | |
455 if (!Wcm.cm_up || !Wcm.cm_left) | |
456 return - 1; | |
457 if (!Wcm.cm_abs && (!Wcm.cm_down || !Wcm.cm_right)) | |
458 return - 1; | |
459 /* Check that we know the size of the screen.... */ | |
460 if (Wcm.cm_rows <= 0 || Wcm.cm_cols <= 0) | |
461 return - 2; | |
462 return 0; | |
463 } | |
52401 | 464 |
465 /* arch-tag: bcf64c02-00f6-44ef-94b6-c56eab5b3dc4 | |
466 (do not change this comment) */ |