1 /* Copyright (c) 1994, 1995 Free Software Foundation, Inc.
2 Copyright (c) 1995 Sun Microsystems, Inc.
3 Copyright (c) 1995, 1996, 2000 Ben Wing.
5 This file is part of SXEmacs
7 SXEmacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 SXEmacs 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.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 /* Synched up with: Not in FSF. */
23 /* This file has been Mule-ized. */
25 /* Written by Ben Wing <ben@xemacs.org>.
27 [Originally written by some people at Lucid.
29 Start/end-open stuff added by John Rose (john.rose@eng.sun.com).
30 Rewritten from scratch by Ben Wing, December 1994.] */
34 Extents are regions over a buffer, with a start and an end position
35 denoting the region of the buffer included in the extent. In
36 addition, either end can be closed or open, meaning that the endpoint
37 is or is not logically included in the extent. Insertion of a character
38 at a closed endpoint causes the character to go inside the extent;
39 insertion at an open endpoint causes the character to go outside.
41 Extent endpoints are stored using memory indices (see insdel.c),
42 to minimize the amount of adjusting that needs to be done when
43 characters are inserted or deleted.
45 (Formerly, extent endpoints at the gap could be either before or
46 after the gap, depending on the open/closedness of the endpoint.
47 The intent of this was to make it so that insertions would
48 automatically go inside or out of extents as necessary with no
49 further work needing to be done. It didn't work out that way,
50 however, and just ended up complexifying and buggifying all the
53 Extents are compared using memory indices. There are two orderings
54 for extents and both orders are kept current at all times. The normal
55 or "display" order is as follows:
57 Extent A is "less than" extent B, that is, earlier in the display order,
58 if: A-start < B-start,
59 or if: A-start = B-start, and A-end > B-end
61 So if two extents begin at the same position, the larger of them is the
62 earlier one in the display order (EXTENT_LESS is true).
64 For the e-order, the same thing holds: Extent A is "less than" extent B
65 in e-order, that is, later in the buffer,
67 or if: A-end = B-end, and A-start > B-start
69 So if two extents end at the same position, the smaller of them is the
70 earlier one in the e-order (EXTENT_E_LESS is true).
72 The display order and the e-order are complementary orders: any
73 theorem about the display order also applies to the e-order if you
74 swap all occurrences of "display order" and "e-order", "less than"
75 and "greater than", and "extent start" and "extent end".
77 Extents can be zero-length, and will end up that way if their endpoints
78 are explicitly set that way or if their detachable property is nil
79 and all the text in the extent is deleted. (The exception is open-open
80 zero-length extents, which are barred from existing because there is
81 no sensible way to define their properties. Deletion of the text in
82 an open-open extent causes it to be converted into a closed-open
83 extent.) Zero-length extents are primarily used to represent
84 annotations, and behave as follows:
86 1) Insertion at the position of a zero-length extent expands the extent
87 if both endpoints are closed; goes after the extent if it is closed-open;
88 and goes before the extent if it is open-closed.
90 2) Deletion of a character on a side of a zero-length extent whose
91 corresponding endpoint is closed causes the extent to be detached if
92 it is detachable; if the extent is not detachable or the corresponding
93 endpoint is open, the extent remains in the buffer, moving as necessary.
95 Note that closed-open, non-detachable zero-length extents behave exactly
96 like markers and that open-closed, non-detachable zero-length extents
97 behave like the "point-type" marker in Mule.
99 #### The following information is wrong in places.
101 More about the different orders:
102 --------------------------------
104 The extents in a buffer are ordered by "display order" because that
105 is that order that the redisplay mechanism needs to process them in.
106 The e-order is an auxiliary ordering used to facilitate operations
107 over extents. The operations that can be performed on the ordered
108 list of extents in a buffer are
110 1) Locate where an extent would go if inserted into the list.
111 2) Insert an extent into the list.
112 3) Remove an extent from the list.
113 4) Map over all the extents that overlap a range.
115 (4) requires being able to determine the first and last extents
116 that overlap a range.
118 NOTE: "overlap" is used as follows:
120 -- two ranges overlap if they have at least one point in common.
121 Whether the endpoints are open or closed makes a difference here.
122 -- a point overlaps a range if the point is contained within the
123 range; this is equivalent to treating a point P as the range
125 -- In the case of an *extent* overlapping a point or range, the
126 extent is normally treated as having closed endpoints. This
127 applies consistently in the discussion of stacks of extents
128 and such below. Note that this definition of overlap is not
129 necessarily consistent with the extents that `map-extents'
130 maps over, since `map-extents' sometimes pays attention to
131 whether the endpoints of an extents are open or closed.
132 But for our purposes, it greatly simplifies things to treat
133 all extents as having closed endpoints.
135 First, define >, <, <=, etc. as applied to extents to mean
136 comparison according to the display order. Comparison between an
137 extent E and an index I means comparison between E and the range
139 Also define e>, e<, e<=, etc. to mean comparison according to the
141 For any range R, define R(0) to be the starting index of the range
142 and R(1) to be the ending index of the range.
143 For any extent E, define E(next) to be the extent directly following
144 E, and E(prev) to be the extent directly preceding E. Assume
145 E(next) and E(prev) can be determined from E in constant time.
146 (This is because we store the extent list as a doubly linked
148 Similarly, define E(e-next) and E(e-prev) to be the extents
149 directly following and preceding E in the e-order.
154 Let F be the first extent overlapping R.
155 Let L be the last extent overlapping R.
157 Theorem 1: R(1) lies between L and L(next), i.e. L <= R(1) < L(next).
159 This follows easily from the definition of display order. The
160 basic reason that this theorem applies is that the display order
161 sorts by increasing starting index.
163 Therefore, we can determine L just by looking at where we would
164 insert R(1) into the list, and if we know F and are moving forward
165 over extents, we can easily determine when we've hit L by comparing
166 the extent we're at to R(1).
168 Theorem 2: F(e-prev) e< [1, R(0)] e<= F.
170 This is the analog of Theorem 1, and applies because the e-order
171 sorts by increasing ending index.
173 Therefore, F can be found in the same amount of time as operation (1),
174 i.e. the time that it takes to locate where an extent would go if
175 inserted into the e-order list.
177 If the lists were stored as balanced binary trees, then operation (1)
178 would take logarithmic time, which is usually quite fast. However,
179 currently they're stored as simple doubly-linked lists, and instead
180 we do some caching to try to speed things up.
182 Define a "stack of extents" (or "SOE") as the set of extents
183 (ordered in the display order) that overlap an index I, together with
184 the SOE's "previous" extent, which is an extent that precedes I in
185 the e-order. (Hopefully there will not be very many extents between
186 I and the previous extent.)
190 Let I be an index, let S be the stack of extents on I, let F be
191 the first extent in S, and let P be S's previous extent.
193 Theorem 3: The first extent in S is the first extent that overlaps
196 Proof: Any extent that overlaps [I, J] but does not include I must
197 have a start index > I, and thus be greater than any extent in S.
199 Therefore, finding the first extent that overlaps a range R is the
200 same as finding the first extent that overlaps R(0).
202 Theorem 4: Let I2 be an index such that I2 > I, and let F2 be the
203 first extent that overlaps I2. Then, either F2 is in S or F2 is
204 greater than any extent in S.
206 Proof: If F2 does not include I then its start index is greater
207 than I and thus it is greater than any extent in S, including F.
208 Otherwise, F2 includes I and thus is in S, and thus F2 >= F.
217 #include "ui/device.h"
220 #include "ui/faces.h"
221 #include "ui/frame.h"
222 #include "ui/glyphs.h"
223 #include "ui/insdel.h"
224 #include "ui/keymap.h"
227 #include "ui/redisplay.h"
228 #include "ui/gutter.h"
230 /* ------------------------------- */
232 /* ------------------------------- */
234 /* Note that this object is not extent-specific and should perhaps be
235 moved into another file. */
237 typedef struct gap_array_marker_s *gap_array_marker_t;
238 typedef struct gap_array_s *gap_array_t;
240 /* Holds a marker that moves as elements in the array are inserted and
241 deleted, similar to standard markers. */
243 struct gap_array_marker_s {
245 gap_array_marker_t next;
248 /* Holds a "gap array", which is an array of elements with a gap located
249 in it. Insertions and deletions with a high degree of locality
250 are very fast, essentially in constant time. Array positions as
251 used and returned in the gap array functions are independent of
260 gap_array_marker_t markers;
263 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
264 static gap_array_marker_t gap_array_marker_freelist;
267 /* Convert a "memory position" (i.e. taking the gap into account) into
268 the address of the element at (i.e. after) that position. "Memory
269 positions" are only used internally and are of type Memind.
270 "Array positions" are used externally and are of type int. */
271 #define GAP_ARRAY_MEMEL_ADDR(ga, memel) ((ga)->array + (ga)->elsize*(memel))
273 /* Number of elements currently in a gap array */
274 #define GAP_ARRAY_NUM_ELS(ga) ((ga)->numels)
276 #define GAP_ARRAY_ARRAY_TO_MEMORY_POS(ga, pos) \
277 ((pos) <= (ga)->gap ? (pos) : (pos) + (ga)->gapsize)
279 #define GAP_ARRAY_MEMORY_TO_ARRAY_POS(ga, pos) \
280 ((pos) <= (ga)->gap ? (pos) : (pos) - (ga)->gapsize)
282 /* Convert an array position into the address of the element at
283 (i.e. after) that position. */
284 #define GAP_ARRAY_EL_ADDR(ga, pos) \
286 ? GAP_ARRAY_MEMEL_ADDR(ga, pos) \
287 : GAP_ARRAY_MEMEL_ADDR(ga, (pos) + (ga)->gapsize))
289 /* ------------------------------- */
291 /* ------------------------------- */
293 typedef struct extent_list_marker_s *extent_list_marker_t;
294 typedef struct extent_list_s *extent_list_t;
296 struct extent_list_marker_s {
297 gap_array_marker_t m;
299 extent_list_marker_t next;
302 struct extent_list_s {
305 extent_list_marker_t markers;
308 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
309 static extent_list_marker_t extent_list_marker_freelist;
312 #define EXTENT_LESS_VALS(e,st,nd) \
313 ((extent_start (e) < (st)) || \
314 ((extent_start (e) == (st)) && \
315 (extent_end (e) > (nd))))
317 #define EXTENT_EQUAL_VALS(e,st,nd) \
318 ((extent_start (e) == (st)) && \
319 (extent_end (e) == (nd)))
321 #define EXTENT_LESS_EQUAL_VALS(e,st,nd) \
322 ((extent_start (e) < (st)) || \
323 ((extent_start (e) == (st)) && \
324 (extent_end (e) >= (nd))))
326 /* Is extent E1 less than extent E2 in the display order? */
327 #define EXTENT_LESS(e1,e2) \
328 EXTENT_LESS_VALS (e1, extent_start (e2), extent_end (e2))
330 /* Is extent E1 equal to extent E2? */
331 #define EXTENT_EQUAL(e1,e2) \
332 EXTENT_EQUAL_VALS (e1, extent_start (e2), extent_end (e2))
334 /* Is extent E1 less than or equal to extent E2 in the display order? */
335 #define EXTENT_LESS_EQUAL(e1,e2) \
336 EXTENT_LESS_EQUAL_VALS (e1, extent_start (e2), extent_end (e2))
338 #define EXTENT_E_LESS_VALS(e,st,nd) \
339 ((extent_end (e) < (nd)) || \
340 ((extent_end (e) == (nd)) && \
341 (extent_start (e) > (st))))
343 #define EXTENT_E_LESS_EQUAL_VALS(e,st,nd) \
344 ((extent_end (e) < (nd)) || \
345 ((extent_end (e) == (nd)) && \
346 (extent_start (e) >= (st))))