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