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