Mercurial > hg > xemacs-beta
annotate src/indent.c @ 5518:3cc7470ea71c
gnuclient: if TMPDIR was set and connect failed, try again with /tmp
2011-06-03 Aidan Kehoe <kehoea@parhasard.net>
* gnuslib.c (connect_to_unix_server):
Retry with /tmp as a directory in which to search for Unix sockets
if an attempt to connect with some other directory failed (which
may be because gnuclient and gnuserv don't share an environment
value for TMPDIR, or because gnuserv was compiled with USE_TMPDIR
turned off).
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Fri, 03 Jun 2011 18:40:57 +0100 |
parents | 8d29f1c4bb98 |
children | 56144c8593a8 |
rev | line source |
---|---|
428 | 1 /* Indentation functions. |
2 Copyright (C) 1995 Board of Trustees, University of Illinois. | |
3 Copyright (C) 1985, 1986, 1987, 1988, 1992, 1993, 1994, 1995 | |
826 | 4 Free Software Foundation, Inc. |
3025 | 5 Copyright (C) 2002, 2005 Ben Wing. |
428 | 6 |
7 This file is part of XEmacs. | |
8 | |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5047
diff
changeset
|
9 XEmacs is free software: you can redistribute it and/or modify it |
428 | 10 under the terms of the GNU General Public License as published by the |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5047
diff
changeset
|
11 Free Software Foundation, either version 3 of the License, or (at your |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5047
diff
changeset
|
12 option) any later version. |
428 | 13 |
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
17 for more details. | |
18 | |
19 You should have received a copy of the GNU General Public License | |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5047
diff
changeset
|
20 along with XEmacs. If not, see <http://www.gnu.org/licenses/>. */ |
428 | 21 |
22 /* This file has been Mule-ized. */ | |
23 | |
24 /* Synched up with: 19.30. Diverges significantly from FSF. */ | |
25 | |
26 | |
27 #include <config.h> | |
28 #include "lisp.h" | |
29 | |
30 #include "buffer.h" | |
31 #include "device.h" | |
32 #include "extents.h" | |
33 #include "faces.h" | |
34 #include "frame.h" | |
35 #include "glyphs.h" | |
36 #include "insdel.h" | |
37 #ifdef REGION_CACHE_NEEDS_WORK | |
38 #include "region-cache.h" | |
39 #endif | |
40 #include "window.h" | |
41 | |
42 /* Indentation can insert tabs if this is non-zero; | |
43 otherwise always uses spaces */ | |
44 int indent_tabs_mode; | |
45 | |
46 /* Avoid recalculation by remembering things in these variables. */ | |
47 | |
48 /* Last value returned by current_column. | |
49 | |
50 Some things set last_known_column_point to -1 | |
51 to mark the memoized value as invalid */ | |
52 static int last_known_column; | |
53 | |
54 /* Last buffer searched by current_column */ | |
55 static struct buffer *last_known_column_buffer; | |
56 | |
57 /* Value of point when current_column was called */ | |
665 | 58 static Charbpos last_known_column_point; |
428 | 59 |
60 /* Value of MODIFF when current_column was called */ | |
61 static int last_known_column_modified; | |
62 | |
665 | 63 static Charbpos |
64 last_visible_position (Charbpos pos, struct buffer *buf) | |
428 | 65 { |
66 Lisp_Object buffer; | |
67 Lisp_Object value; | |
68 | |
793 | 69 buffer = wrap_buffer (buf); |
2506 | 70 value = Fprevious_single_char_property_change (make_int (pos), Qinvisible, |
71 buffer, Qnil); | |
428 | 72 if (NILP (value)) |
73 return 0; /* no visible position found */ | |
74 else | |
75 /* #### bug bug bug!!! This will return the position of the beginning | |
76 of an invisible extent; this extent is very likely to be start-closed, | |
77 and thus the spaces inserted in `indent-to' will go inside the | |
78 invisible extent. | |
79 | |
80 Not sure what the correct solution is here. Rethink indent-to? */ | |
81 return XINT (value); | |
82 } | |
83 | |
84 #ifdef REGION_CACHE_NEEDS_WORK | |
85 | |
86 /* Allocate or free the width run cache, as requested by the current | |
87 state of current_buffer's cache_long_line_scans variable. */ | |
88 static void | |
89 width_run_cache_on_off (struct buffer *buf) | |
90 { | |
91 if (NILP (buf->cache_long_line_scans)) | |
92 { | |
93 /* It should be off. */ | |
94 if (buf->width_run_cache) | |
95 { | |
96 free_region_cache (buf->width_run_cache); | |
97 buf->width_run_cache = 0; | |
98 buf->width_table = Qnil; | |
99 } | |
100 } | |
101 else | |
102 { | |
103 /* It should be on. */ | |
104 if (buf->width_run_cache == 0) | |
105 { | |
106 buf->width_run_cache = new_region_cache (); | |
107 recompute_width_table (buf, buffer_display_table ()); | |
108 } | |
109 } | |
110 } | |
111 | |
112 #endif /* REGION_CACHE_NEEDS_WORK */ | |
113 | |
114 | |
115 /* Cancel any recorded value of the horizontal position. */ | |
116 | |
117 void | |
118 invalidate_current_column (void) | |
119 { | |
120 last_known_column_point = -1; | |
121 } | |
122 | |
123 int | |
665 | 124 column_at_point (struct buffer *buf, Charbpos init_pos, int cur_col) |
428 | 125 { |
126 int col; | |
127 int tab_seen; | |
128 int tab_width = XINT (buf->tab_width); | |
129 int post_tab; | |
665 | 130 Charbpos pos = init_pos; |
867 | 131 Ichar c; |
428 | 132 |
133 if (tab_width <= 0 || tab_width > 1000) tab_width = 8; | |
134 col = tab_seen = post_tab = 0; | |
135 | |
136 while (1) | |
137 { | |
138 if (pos <= BUF_BEGV (buf)) | |
139 break; | |
140 | |
141 pos--; | |
142 c = BUF_FETCH_CHAR (buf, pos); | |
143 if (c == '\t') | |
144 { | |
145 if (tab_seen) | |
146 col = ((col + tab_width) / tab_width) * tab_width; | |
147 | |
148 post_tab += col; | |
149 col = 0; | |
150 tab_seen = 1; | |
151 } | |
152 else if (c == '\n' || | |
153 (EQ (buf->selective_display, Qt) && c == '\r')) | |
154 break; | |
155 else | |
156 { | |
157 /* #### This needs updating to handle the new redisplay. */ | |
158 /* #### FSFmacs looks at ctl_arrow, display tables. | |
159 We need to do similar. */ | |
160 #if 0 | |
665 | 161 displayed_glyphs = glyphs_from_charbpos (sel_frame, buf, |
428 | 162 XWINDOW (selected_window), |
163 pos, dp, 0, col, 0, 0, 0); | |
164 col += (displayed_glyphs->columns | |
165 - (displayed_glyphs->begin_columns | |
166 + displayed_glyphs->end_columns)); | |
167 #else /* XEmacs */ | |
168 #ifdef MULE | |
867 | 169 col += XCHARSET_COLUMNS (ichar_charset (c)); |
428 | 170 #else |
171 col ++; | |
172 #endif /* MULE */ | |
173 #endif /* XEmacs */ | |
174 } | |
175 } | |
176 | |
177 if (tab_seen) | |
178 { | |
179 col = ((col + tab_width) / tab_width) * tab_width; | |
180 col += post_tab; | |
181 } | |
182 | |
183 if (cur_col) | |
184 { | |
185 last_known_column_buffer = buf; | |
186 last_known_column = col; | |
187 last_known_column_point = init_pos; | |
188 last_known_column_modified = BUF_MODIFF (buf); | |
189 } | |
190 | |
191 return col; | |
192 } | |
193 | |
194 int | |
793 | 195 string_column_at_point (Lisp_Object s, Charbpos init_pos, int tab_width) |
428 | 196 { |
197 int col; | |
198 int tab_seen; | |
199 int post_tab; | |
665 | 200 Charbpos pos = init_pos; |
867 | 201 Ichar c; |
428 | 202 |
203 if (tab_width <= 0 || tab_width > 1000) tab_width = 8; | |
204 col = tab_seen = post_tab = 0; | |
205 | |
206 while (1) | |
207 { | |
208 if (pos <= 0) | |
209 break; | |
210 | |
211 pos--; | |
867 | 212 c = string_ichar (s, pos); |
428 | 213 if (c == '\t') |
214 { | |
215 if (tab_seen) | |
216 col = ((col + tab_width) / tab_width) * tab_width; | |
217 | |
218 post_tab += col; | |
219 col = 0; | |
220 tab_seen = 1; | |
221 } | |
222 else if (c == '\n') | |
223 break; | |
224 else | |
225 #ifdef MULE | |
867 | 226 col += XCHARSET_COLUMNS (ichar_charset (c)); |
428 | 227 #else |
228 col ++; | |
229 #endif /* MULE */ | |
230 } | |
231 | |
232 if (tab_seen) | |
233 { | |
234 col = ((col + tab_width) / tab_width) * tab_width; | |
235 col += post_tab; | |
236 } | |
237 | |
238 return col; | |
239 } | |
240 | |
241 int | |
242 current_column (struct buffer *buf) | |
243 { | |
244 if (buf == last_known_column_buffer | |
245 && BUF_PT (buf) == last_known_column_point | |
246 && BUF_MODIFF (buf) == last_known_column_modified) | |
247 return last_known_column; | |
248 | |
249 return column_at_point (buf, BUF_PT (buf), 1); | |
250 } | |
251 | |
252 DEFUN ("current-column", Fcurrent_column, 0, 1, 0, /* | |
253 Return the horizontal position of point. Beginning of line is column 0. | |
254 This is calculated by adding together the widths of all the displayed | |
255 representations of the character between the start of the previous line | |
256 and point. (e.g. control characters will have a width of 2 or 4, tabs | |
257 will have a variable width.) | |
258 Ignores finite width of frame, which means that this function may return | |
259 values greater than (frame-width). | |
260 Whether the line is visible (if `selective-display' is t) has no effect; | |
261 however, ^M is treated as end of line when `selective-display' is t. | |
262 If BUFFER is nil, the current buffer is assumed. | |
263 */ | |
264 (buffer)) | |
265 { | |
266 return make_int (current_column (decode_buffer (buffer, 0))); | |
267 } | |
268 | |
269 | |
270 DEFUN ("indent-to", Findent_to, 1, 3, "NIndent to column: ", /* | |
271 Indent from point with tabs and spaces until COLUMN is reached. | |
444 | 272 Optional second argument MINIMUM says always do at least MINIMUM spaces |
273 even if that goes past COLUMN; by default, MINIMUM is zero. | |
428 | 274 If BUFFER is nil, the current buffer is assumed. |
275 */ | |
444 | 276 (column, minimum, buffer)) |
428 | 277 { |
278 /* This function can GC */ | |
279 int mincol; | |
280 int fromcol; | |
281 struct buffer *buf = decode_buffer (buffer, 0); | |
282 int tab_width = XINT (buf->tab_width); | |
665 | 283 Charbpos opoint = 0; |
428 | 284 |
444 | 285 CHECK_INT (column); |
428 | 286 if (NILP (minimum)) |
287 minimum = Qzero; | |
288 else | |
289 CHECK_INT (minimum); | |
290 | |
793 | 291 buffer = wrap_buffer (buf); |
428 | 292 |
293 fromcol = current_column (buf); | |
294 mincol = fromcol + XINT (minimum); | |
444 | 295 if (mincol < XINT (column)) mincol = XINT (column); |
428 | 296 |
297 if (fromcol == mincol) | |
298 return make_int (mincol); | |
299 | |
300 if (tab_width <= 0 || tab_width > 1000) tab_width = 8; | |
301 | |
302 if (!NILP (Fextent_at (make_int (BUF_PT (buf)), buffer, Qinvisible, | |
303 Qnil, Qnil))) | |
304 { | |
665 | 305 Charbpos last_visible = last_visible_position (BUF_PT (buf), buf); |
428 | 306 |
307 opoint = BUF_PT (buf); | |
308 if (last_visible >= BUF_BEGV (buf)) | |
309 BUF_SET_PT (buf, last_visible); | |
310 else | |
563 | 311 invalid_operation ("Visible portion of buffer not modifiable", Qunbound); |
428 | 312 } |
313 | |
314 if (indent_tabs_mode) | |
315 { | |
316 int n = mincol / tab_width - fromcol / tab_width; | |
317 if (n != 0) | |
318 { | |
319 Finsert_char (make_char ('\t'), make_int (n), Qnil, buffer); | |
320 | |
321 fromcol = (mincol / tab_width) * tab_width; | |
322 } | |
323 } | |
324 | |
325 Finsert_char (make_char (' '), make_int (mincol - fromcol), Qnil, buffer); | |
326 | |
327 last_known_column_buffer = buf; | |
328 last_known_column = mincol; | |
329 last_known_column_point = BUF_PT (buf); | |
330 last_known_column_modified = BUF_MODIFF (buf); | |
331 | |
332 /* Not in FSF: */ | |
333 if (opoint > 0) | |
334 BUF_SET_PT (buf, opoint); | |
335 | |
336 return make_int (mincol); | |
337 } | |
338 | |
339 int | |
826 | 340 byte_spaces_at_point (struct buffer *b, Bytebpos byte_pos) |
428 | 341 { |
826 | 342 Bytebpos byte_end = BYTE_BUF_ZV (b); |
428 | 343 int col = 0; |
867 | 344 Ichar c; |
428 | 345 int tab_width = XINT (b->tab_width); |
346 | |
347 if (tab_width <= 0 || tab_width > 1000) | |
348 tab_width = 8; | |
349 | |
826 | 350 while (byte_pos < byte_end && |
351 (c = BYTE_BUF_FETCH_CHAR (b, byte_pos), | |
428 | 352 (c == '\t' |
353 ? (col += tab_width - col % tab_width) | |
354 : (c == ' ' ? ++col : 0)))) | |
826 | 355 INC_BYTEBPOS (b, byte_pos); |
428 | 356 |
357 return col; | |
358 } | |
359 | |
360 | |
361 DEFUN ("current-indentation", Fcurrent_indentation, 0, 1, 0, /* | |
362 Return the indentation of the current line. | |
363 This is the horizontal position of the character | |
364 following any initial whitespace. | |
365 */ | |
366 (buffer)) | |
367 { | |
368 struct buffer *buf = decode_buffer (buffer, 0); | |
665 | 369 Charbpos pos = find_next_newline (buf, BUF_PT (buf), -1); |
428 | 370 |
793 | 371 buffer = wrap_buffer (buf); |
428 | 372 |
373 if (!NILP (Fextent_at (make_int (pos), buffer, Qinvisible, Qnil, Qnil))) | |
374 return Qzero; | |
375 | |
826 | 376 return make_int (byte_spaces_at_point (buf, charbpos_to_bytebpos (buf, pos))); |
428 | 377 } |
378 | |
379 | |
380 DEFUN ("move-to-column", Fmove_to_column, 1, 3, 0, /* | |
381 Move point to column COLUMN in the current line. | |
382 The column of a character is calculated by adding together the widths | |
383 as displayed of the previous characters in the line. | |
384 This function ignores line-continuation; | |
385 there is no upper limit on the column number a character can have | |
386 and horizontal scrolling has no effect. | |
387 | |
388 If specified column is within a character, point goes after that character. | |
389 If it's past end of line, point goes to end of line. | |
390 | |
3025 | 391 A value of `coerce' for the second (optional) argument FORCE means if |
428 | 392 COLUMN is in the middle of a tab character, change it to spaces. |
393 Any other non-nil value means the same, plus if the line is too short to | |
394 reach column COLUMN, then add spaces/tabs to get there. | |
395 | |
396 Returns the actual column that it moved to. | |
397 */ | |
398 (column, force, buffer)) | |
399 { | |
400 /* This function can GC */ | |
665 | 401 Charbpos pos; |
428 | 402 struct buffer *buf = decode_buffer (buffer, 0); |
403 int col = current_column (buf); | |
404 int goal; | |
665 | 405 Charbpos end; |
428 | 406 int tab_width = XINT (buf->tab_width); |
407 | |
408 int prev_col = 0; | |
867 | 409 Ichar c = 0; |
428 | 410 |
793 | 411 buffer = wrap_buffer (buf); |
428 | 412 if (tab_width <= 0 || tab_width > 1000) tab_width = 8; |
5307
c096d8051f89
Have NATNUMP give t for positive bignums; check limits appropriately.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5047
diff
changeset
|
413 |
c096d8051f89
Have NATNUMP give t for positive bignums; check limits appropriately.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5047
diff
changeset
|
414 check_integer_range (column, Qzero, make_integer (EMACS_INT_MAX)); |
428 | 415 goal = XINT (column); |
416 | |
417 retry: | |
418 pos = BUF_PT (buf); | |
419 end = BUF_ZV (buf); | |
420 | |
421 /* If we're starting past the desired column, | |
422 back up to beginning of line and scan from there. */ | |
423 if (col > goal) | |
424 { | |
425 pos = find_next_newline (buf, pos, -1); | |
426 col = 0; | |
427 } | |
428 | |
429 while (col < goal && pos < end) | |
430 { | |
431 c = BUF_FETCH_CHAR (buf, pos); | |
432 if (c == '\n') | |
433 break; | |
434 if (c == '\r' && EQ (buf->selective_display, Qt)) | |
435 break; | |
436 if (c == '\t') | |
437 { | |
438 prev_col = col; | |
439 col += tab_width; | |
440 col = col / tab_width * tab_width; | |
441 } | |
442 else | |
443 { | |
444 /* #### oh for the days of the complete new redisplay */ | |
445 /* #### FSFmacs looks at ctl_arrow, display tables. | |
446 We need to do similar. */ | |
447 #if 0 | |
665 | 448 displayed_glyphs = glyphs_from_charbpos (selected_frame (), |
428 | 449 buf, |
450 XWINDOW (Fselected_window (Qnil)), | |
451 pos, dp, 0, col, 0, 0, 0); | |
452 col += (displayed_glyphs->columns | |
453 - (displayed_glyphs->begin_columns | |
454 + displayed_glyphs->end_columns)); | |
455 #else /* XEmacs */ | |
456 #ifdef MULE | |
867 | 457 col += XCHARSET_COLUMNS (ichar_charset (c)); |
428 | 458 #else |
459 col ++; | |
460 #endif /* MULE */ | |
461 #endif /* XEmacs */ | |
462 } | |
463 | |
464 pos++; | |
465 } | |
466 | |
467 BUF_SET_PT (buf, pos); | |
468 | |
469 /* If a tab char made us overshoot, change it to spaces | |
470 and scan through it again. */ | |
471 if (!NILP (force) && col > goal && c == '\t' && prev_col < goal) | |
472 { | |
473 buffer_delete_range (buf, BUF_PT (buf) - 1, BUF_PT (buf), 0); | |
474 Findent_to (make_int (col - 1), Qzero, buffer); | |
475 buffer_insert_emacs_char (buf, ' '); | |
476 goto retry; | |
477 } | |
478 | |
479 /* If line ends prematurely, add space to the end. */ | |
480 if (col < goal && !NILP (force) && !EQ (force, Qcoerce)) | |
481 { | |
482 col = goal; | |
483 Findent_to (make_int (col), Qzero, buffer); | |
484 } | |
485 | |
486 last_known_column_buffer = buf; | |
487 last_known_column = col; | |
488 last_known_column_point = BUF_PT (buf); | |
489 last_known_column_modified = BUF_MODIFF (buf); | |
490 | |
491 return make_int (col); | |
492 } | |
493 | |
494 #if 0 /* #### OK boys, this function needs to be present, I think. | |
495 It was there before the 19.12 redisplay rewrite. */ | |
496 | |
826 | 497 DEFUN ("compute-motion", Fcompute_motion, 7, 7, 0, /* |
428 | 498 "Scan through the current buffer, calculating screen position. |
499 Scan the current buffer forward from offset FROM, | |
500 assuming it is at position FROMPOS--a cons of the form (HPOS . VPOS)-- | |
501 to position TO or position TOPOS--another cons of the form (HPOS . VPOS)-- | |
502 and return the ending buffer position and screen location. | |
503 | |
504 There are three additional arguments: | |
505 | |
506 WIDTH is the number of columns available to display text; | |
507 this affects handling of continuation lines. | |
508 This is usually the value returned by `window-width', less one (to allow | |
509 for the continuation glyph). | |
510 | |
511 OFFSETS is either nil or a cons cell (HSCROLL . TAB-OFFSET). | |
512 HSCROLL is the number of columns not being displayed at the left | |
513 margin; this is usually taken from a window's hscroll member. | |
514 TAB-OFFSET is the number of columns of the first tab that aren't | |
515 being displayed, perhaps because the line was continued within it. | |
516 If OFFSETS is nil, HSCROLL and TAB-OFFSET are assumed to be zero. | |
517 | |
518 WINDOW is the window to operate on. Currently this is used only to | |
519 find the display table. It does not matter what buffer WINDOW displays; | |
520 `compute-motion' always operates on the current buffer. | |
521 | |
522 The value is a list of five elements: | |
523 (POS HPOS VPOS PREVHPOS CONTIN) | |
524 POS is the buffer position where the scan stopped. | |
525 VPOS is the vertical position where the scan stopped. | |
526 HPOS is the horizontal position where the scan stopped. | |
527 | |
528 PREVHPOS is the horizontal position one character back from POS. | |
529 CONTIN is t if a line was continued after (or within) the previous character. | |
530 | |
531 For example, to find the buffer position of column COL of line LINE | |
532 of a certain window, pass the window's starting location as FROM | |
533 and the window's upper-left coordinates as FROMPOS. | |
534 Pass the buffer's (point-max) as TO, to limit the scan to the end of the | |
535 visible section of the buffer, and pass LINE and COL as TOPOS. | |
536 */ | |
537 (from, frompos, to, topos, width, offsets, window)) | |
538 { | |
665 | 539 Lisp_Object charbpos, hpos, vpos, prevhpos, contin; |
428 | 540 struct position *pos; |
541 int hscroll, tab_offset; | |
542 struct window *w = decode_window (window); | |
543 | |
544 CHECK_INT_COERCE_MARKER (from); | |
545 CHECK_CONS (frompos); | |
546 CHECK_INT (XCAR (frompos)); | |
547 CHECK_INT (XCDR (frompos)); | |
548 CHECK_INT_COERCE_MARKER (to); | |
549 CHECK_CONS (topos); | |
550 CHECK_INT (XCAR (topos)); | |
551 CHECK_INT (XCDR (topos)); | |
552 CHECK_INT (width); | |
553 if (!NILP (offsets)) | |
554 { | |
555 CHECK_CONS (offsets); | |
556 CHECK_INT (XCAR (offsets)); | |
557 CHECK_INT (XCDR (offsets)); | |
558 hscroll = XINT (XCAR (offsets)); | |
559 tab_offset = XINT (XCDR (offsets)); | |
560 } | |
561 else | |
562 hscroll = tab_offset = 0; | |
563 | |
564 pos = compute_motion (XINT (from), XINT (XCDR (frompos)), | |
565 XINT (XCAR (frompos)), | |
566 XINT (to), XINT (XCDR (topos)), | |
567 XINT (XCAR (topos)), | |
568 XINT (width), hscroll, tab_offset, w); | |
569 | |
793 | 570 charbpos = make_int (pos->charbpos); |
571 hpos = make_int (pos->hpos); | |
572 vpos = make_int (pos->vpos); | |
573 prevhpos = make_int (pos->prevhpos); | |
428 | 574 |
665 | 575 return list5 (charbpos, hpos, vpos, prevhpos, |
428 | 576 pos->contin ? Qt : Qnil); |
577 } | |
578 | |
579 #endif /* 0 */ | |
580 | |
581 /* Helper for vmotion_1 - compute vertical pixel motion between | |
582 START and END in the line start cache CACHE. This just sums | |
583 the line heights, including both the starting and ending lines. | |
584 */ | |
585 static int | |
586 vpix_motion (line_start_cache_dynarr *cache, int start, int end) | |
587 { | |
588 int i, vpix; | |
589 | |
590 assert (start <= end); | |
591 assert (start >= 0); | |
592 assert (end < Dynarr_length (cache)); | |
593 | |
594 vpix = 0; | |
595 for (i = start; i <= end; i++) | |
596 vpix += Dynarr_atp (cache, i)->height; | |
597 | |
598 return vpix; | |
599 } | |
600 | |
601 /***************************************************************************** | |
602 vmotion_1 | |
603 | |
604 Given a starting position ORIG, move point VTARGET lines in WINDOW. | |
605 Returns the new value for point. If the arg ret_vpos is not nil, it is | |
606 taken to be a pointer to an int and the number of lines actually moved is | |
607 returned in it. If the arg ret_vpix is not nil, it is taken to be a | |
608 pointer to an int and the vertical pixel height of the motion which | |
609 took place is returned in it. | |
610 ****************************************************************************/ | |
665 | 611 static Charbpos |
612 vmotion_1 (struct window *w, Charbpos orig, int vtarget, | |
428 | 613 int *ret_vpos, int *ret_vpix) |
614 { | |
615 struct buffer *b = XBUFFER (w->buffer); | |
616 int elt; | |
617 | |
618 elt = point_in_line_start_cache (w, orig, (vtarget < 0 | |
619 ? -vtarget | |
620 : vtarget)); | |
621 | |
622 /* #### This assertion must be true before the if statements are hit | |
623 but may possibly be wrong after the call to | |
624 point_in_line_start_cache if orig is outside of the visible | |
625 region of the buffer. Handle this. */ | |
626 assert (elt >= 0); | |
627 | |
628 /* Moving downward. */ | |
629 if (vtarget > 0) | |
630 { | |
631 int cur_line = Dynarr_length (w->line_start_cache) - 1 - elt; | |
665 | 632 Charbpos ret_pt; |
428 | 633 |
634 if (cur_line > vtarget) | |
635 cur_line = vtarget; | |
636 | |
637 /* The traditional FSF behavior is to return the end of buffer | |
638 position if we couldn't move far enough because we hit it. */ | |
639 if (cur_line < vtarget) | |
640 ret_pt = BUF_ZV (b); | |
641 else | |
642 ret_pt = Dynarr_atp (w->line_start_cache, cur_line + elt)->start; | |
643 | |
644 while (ret_pt > BUF_ZV (b) && cur_line > 0) | |
645 { | |
646 cur_line--; | |
647 ret_pt = Dynarr_atp (w->line_start_cache, cur_line + elt)->start; | |
648 } | |
649 | |
650 if (ret_vpos) *ret_vpos = cur_line; | |
651 if (ret_vpix) | |
652 *ret_vpix = vpix_motion (w->line_start_cache, elt, cur_line + elt); | |
653 return ret_pt; | |
654 } | |
655 else if (vtarget < 0) | |
656 { | |
657 if (elt < -vtarget) | |
658 { | |
659 if (ret_vpos) *ret_vpos = -elt; | |
660 if (ret_vpix) | |
661 *ret_vpix = vpix_motion (w->line_start_cache, 0, elt); | |
662 /* #### This should be BUF_BEGV (b), right? */ | |
4967 | 663 return Dynarr_begin (w->line_start_cache)->start; |
428 | 664 } |
665 else | |
666 { | |
667 if (ret_vpos) *ret_vpos = vtarget; | |
668 if (ret_vpix) | |
669 *ret_vpix = vpix_motion (w->line_start_cache, elt + vtarget, elt); | |
670 return Dynarr_atp (w->line_start_cache, elt + vtarget)->start; | |
671 } | |
672 } | |
673 else | |
674 { | |
675 /* No vertical motion requested so we just return the position | |
676 of the beginning of the current line. */ | |
677 if (ret_vpos) *ret_vpos = 0; | |
678 if (ret_vpix) | |
679 *ret_vpix = vpix_motion (w->line_start_cache, elt, elt); | |
680 | |
681 return Dynarr_atp (w->line_start_cache, elt)->start; | |
682 } | |
683 | |
1204 | 684 RETURN_NOT_REACHED(0); /* shut up compiler */ |
428 | 685 } |
686 | |
687 /***************************************************************************** | |
688 vmotion | |
689 | |
690 Given a starting position ORIG, move point VTARGET lines in WINDOW. | |
691 Returns the new value for point. If the arg ret_vpos is not nil, it is | |
692 taken to be a pointer to an int and the number of lines actually moved is | |
693 returned in it. | |
694 ****************************************************************************/ | |
665 | 695 Charbpos |
696 vmotion (struct window *w, Charbpos orig, int vtarget, int *ret_vpos) | |
428 | 697 { |
698 return vmotion_1 (w, orig, vtarget, ret_vpos, NULL); | |
699 } | |
700 | |
701 /* Helper for Fvertical_motion. | |
702 */ | |
703 static | |
704 Lisp_Object vertical_motion_1 (Lisp_Object lines, Lisp_Object window, | |
705 int pixels) | |
706 { | |
665 | 707 Charbpos charbpos; |
708 Charbpos orig; | |
428 | 709 int selected; |
710 int *vpos, *vpix; | |
711 int value=0; | |
712 struct window *w; | |
713 | |
714 if (NILP (window)) | |
715 window = Fselected_window (Qnil); | |
716 | |
717 CHECK_LIVE_WINDOW (window); | |
718 CHECK_INT (lines); | |
719 | |
720 selected = (EQ (window, Fselected_window (Qnil))); | |
721 | |
722 w = XWINDOW (window); | |
723 | |
724 orig = selected ? BUF_PT (XBUFFER (w->buffer)) | |
725 : marker_position (w->pointm[CURRENT_DISP]); | |
726 | |
727 vpos = pixels ? NULL : &value; | |
728 vpix = pixels ? &value : NULL; | |
729 | |
665 | 730 charbpos = vmotion_1 (w, orig, XINT (lines), vpos, vpix); |
428 | 731 |
732 /* Note that the buffer's point is set, not the window's point. */ | |
733 if (selected) | |
665 | 734 BUF_SET_PT (XBUFFER (w->buffer), charbpos); |
428 | 735 else |
736 set_marker_restricted (w->pointm[CURRENT_DISP], | |
665 | 737 make_int(charbpos), |
428 | 738 w->buffer); |
739 | |
740 return make_int (value); | |
741 } | |
742 | |
743 DEFUN ("vertical-motion", Fvertical_motion, 1, 3, 0, /* | |
744 Move to start of frame line LINES lines down. | |
745 If LINES is negative, this is moving up. | |
746 Optional second argument is WINDOW to move in, | |
747 the default is the selected window. | |
748 | |
749 Sets point to position found; this may be start of line | |
750 or just the start of a continuation line. | |
751 If optional third argument PIXELS is nil, returns number | |
752 of lines moved; may be closer to zero than LINES if beginning | |
753 or end of buffer was reached. If PIXELS is non-nil, the | |
754 vertical pixel height of the motion which took place is | |
755 returned instead of the actual number of lines moved. A | |
756 motion of zero lines returns the height of the current line. | |
757 | |
1268 | 758 NOTE NOTE NOTE: GNU Emacs/XEmacs difference. |
759 | |
760 What `vertical-motion' actually does is set WINDOW's buffer's point | |
761 if WINDOW is the selected window; else, it sets WINDOW's point. | |
762 This is unfortunately somewhat tricky to work with, and different | |
763 from GNU Emacs, which always uses the current buffer, not WINDOW's | |
764 buffer, always sets current buffer's point, and, from the | |
765 perspective of this function, temporarily makes WINDOW display | |
766 the current buffer if it wasn't already. | |
428 | 767 */ |
768 (lines, window, pixels)) | |
769 { | |
770 return vertical_motion_1 (lines, window, !NILP (pixels)); | |
771 } | |
772 | |
773 /* | |
774 * Like vmotion() but requested and returned movement is in pixels. | |
775 * HOW specifies the stopping condition. Positive means move at least | |
776 * PIXELS. Negative means at most. Zero means as close as possible. | |
777 */ | |
665 | 778 Charbpos |
779 vmotion_pixels (Lisp_Object window, Charbpos start, int pixels, int how, | |
428 | 780 int *motion) |
781 { | |
782 struct window *w; | |
665 | 783 Charbpos eobuf, bobuf; |
428 | 784 int defheight; |
785 int needed; | |
786 int line, next; | |
787 int remain, abspix, dirn; | |
788 int elt, nelt; | |
789 int i; | |
790 line_start_cache_dynarr *cache; | |
791 int previous = -1; | |
792 int lines; | |
793 | |
794 if (NILP (window)) | |
795 window = Fselected_window (Qnil); | |
796 | |
797 CHECK_LIVE_WINDOW (window); | |
798 w = XWINDOW (window); | |
799 | |
800 eobuf = BUF_ZV (XBUFFER (w->buffer)); | |
801 bobuf = BUF_BEGV (XBUFFER (w->buffer)); | |
802 | |
5047
07dcc7000bbf
put width before height consistently, fix a real bug found in the process
Ben Wing <ben@xemacs.org>
parents:
4998
diff
changeset
|
803 default_face_width_and_height (window, NULL, &defheight); |
428 | 804 |
805 /* guess num lines needed in line start cache + a few extra */ | |
806 abspix = abs (pixels); | |
807 needed = (abspix + defheight-1)/defheight + 3; | |
808 | |
809 dirn = (pixels >= 0) ? 1 : -1; | |
810 | |
811 while (1) | |
812 { | |
813 elt = point_in_line_start_cache (w, start, needed); | |
814 assert (elt >= 0); /* in the cache */ | |
815 | |
816 cache = w->line_start_cache; | |
817 nelt = Dynarr_length (cache); | |
818 | |
819 *motion = 0; | |
820 | |
821 if (pixels == 0) | |
822 /* No vertical motion requested so we just return the position | |
823 of the beginning of the current display line. */ | |
824 return Dynarr_atp (cache, elt)->start; | |
825 | |
826 if ((dirn < 0 && elt == 0 && | |
827 Dynarr_atp (cache, elt)->start <= bobuf) || | |
828 (dirn > 0 && elt == nelt-1 && | |
829 Dynarr_atp (cache, elt)->end >= eobuf)) | |
830 return Dynarr_atp (cache, elt)->start; | |
831 | |
832 remain = abspix; | |
833 for (i = elt; (dirn > 0) ? (i < nelt) : (i > 0); i += dirn) | |
834 { | |
835 /* cache line we're considering moving over */ | |
836 int ii = (dirn > 0) ? i : i-1; | |
837 | |
838 if (remain < 0) | |
839 return Dynarr_atp (cache, i)->start; | |
840 | |
841 line = Dynarr_atp (cache, ii)->height; | |
842 next = remain - line; | |
843 | |
844 /* is stopping condition satisfied? */ | |
845 if ((how > 0 && remain <= 0) || /* at least */ | |
846 (how < 0 && next < 0) || /* at most */ | |
847 (how == 0 && remain <= abs (next))) /* closest */ | |
848 return Dynarr_atp (cache, i)->start; | |
849 | |
850 /* moving down and nowhere left to go? */ | |
851 if (dirn > 0 && Dynarr_atp (cache, ii)->end >= eobuf) | |
852 return Dynarr_atp (cache, ii)->start; | |
853 | |
854 /* take the step */ | |
855 remain = next; | |
856 *motion += dirn * line; | |
857 | |
858 /* moving up and nowhere left to go? */ | |
859 if (dirn < 0 && Dynarr_atp (cache, ii)->start <= bobuf) | |
860 return Dynarr_atp (cache, ii)->start; | |
861 } | |
862 | |
863 /* get here => need more cache lines. try again. */ | |
864 assert (abs (*motion) > previous); /* progress? */ | |
865 previous = abs (*motion); | |
866 | |
867 lines = (pixels < 0) ? elt : (nelt - elt); | |
868 needed += (remain*lines + abspix-1)/abspix + 3; | |
869 } | |
870 | |
1204 | 871 RETURN_NOT_REACHED(0); /* shut up compiler */ |
428 | 872 } |
873 | |
874 DEFUN ("vertical-motion-pixels", Fvertical_motion_pixels, 1, 3, 0, /* | |
875 Move to start of frame line PIXELS vertical pixels down. | |
876 If PIXELS is negative, this is moving up. | |
877 The actual vertical motion in pixels is returned. | |
878 | |
879 Optional second argument is WINDOW to move in, | |
880 the default is the selected window. | |
881 | |
882 Optional third argument HOW specifies when to stop. A value | |
883 less than zero indicates that the motion should be no more | |
884 than PIXELS. A value greater than zero indicates that the | |
885 motion should be at least PIXELS. Any other value indicates | |
886 that the motion should be as close as possible to PIXELS. | |
887 */ | |
888 (pixels, window, how)) | |
889 { | |
665 | 890 Charbpos charbpos; |
891 Charbpos orig; | |
428 | 892 int selected; |
893 int motion; | |
894 int howto; | |
895 struct window *w; | |
896 | |
897 if (NILP (window)) | |
898 window = Fselected_window (Qnil); | |
899 | |
900 CHECK_LIVE_WINDOW (window); | |
901 CHECK_INT (pixels); | |
902 | |
903 selected = (EQ (window, Fselected_window (Qnil))); | |
904 | |
905 w = XWINDOW (window); | |
906 | |
907 orig = selected ? BUF_PT (XBUFFER (w->buffer)) | |
908 : marker_position (w->pointm[CURRENT_DISP]); | |
909 | |
910 howto = INTP (how) ? XINT (how) : 0; | |
911 | |
665 | 912 charbpos = vmotion_pixels (window, orig, XINT (pixels), howto, &motion); |
428 | 913 |
914 if (selected) | |
665 | 915 BUF_SET_PT (XBUFFER (w->buffer), charbpos); |
428 | 916 else |
917 set_marker_restricted (w->pointm[CURRENT_DISP], | |
665 | 918 make_int(charbpos), |
428 | 919 w->buffer); |
920 | |
921 return make_int (motion); | |
922 } | |
923 | |
924 | |
925 void | |
926 syms_of_indent (void) | |
927 { | |
928 DEFSUBR (Fcurrent_indentation); | |
929 DEFSUBR (Findent_to); | |
930 DEFSUBR (Fcurrent_column); | |
931 DEFSUBR (Fmove_to_column); | |
932 #if 0 /* #### */ | |
933 DEFSUBR (Fcompute_motion); | |
934 #endif | |
935 DEFSUBR (Fvertical_motion); | |
936 DEFSUBR (Fvertical_motion_pixels); | |
937 } | |
938 | |
939 void | |
940 vars_of_indent (void) | |
941 { | |
942 DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode /* | |
943 *Indentation can insert tabs if this is non-nil. | |
944 Setting this variable automatically makes it local to the current buffer. | |
945 */ ); | |
946 indent_tabs_mode = 1; | |
947 } |