Lisp_Object Fset_buffer ();
void set_buffer_internal ();
+void set_buffer_internal_1 ();
static void call_overlay_mod_hooks ();
+static void swap_out_buffer_local_variables ();
/* Alist of all buffer names vs the buffers. */
/* This used to be a variable, but is no longer,
/* List of functions to call before changing an unmodified buffer. */
Lisp_Object Vfirst_change_hook;
+
Lisp_Object Qfirst_change_hook;
+Lisp_Object Qbefore_change_functions;
+Lisp_Object Qafter_change_functions;
Lisp_Object Qfundamental_mode, Qmode_class, Qpermanent_local;
Lisp_Object Qoverlayp;
-Lisp_Object Qpriority, Qwindow, Qevaporate;
+Lisp_Object Qpriority, Qwindow, Qevaporate, Qbefore_string, Qafter_string;
Lisp_Object Qmodification_hooks;
Lisp_Object Qinsert_in_front_hooks;
return Qnil;
}
+Lisp_Object
+get_truename_buffer (filename)
+ register Lisp_Object filename;
+{
+ register Lisp_Object tail, buf, tem;
+
+ for (tail = Vbuffer_alist; CONSP (tail); tail = XCONS (tail)->cdr)
+ {
+ buf = Fcdr (XCONS (tail)->car);
+ if (!BUFFERP (buf)) continue;
+ if (!STRINGP (XBUFFER (buf)->file_truename)) continue;
+ tem = Fstring_equal (XBUFFER (buf)->file_truename, filename);
+ if (!NILP (tem))
+ return buf;
+ }
+ return Qnil;
+}
+
/* Incremented for each buffer created, to assign the buffer number. */
int buffer_count;
DEFUN ("make-indirect-buffer",
Fmake_indirect_buffer, Smake_indirect_buffer, 2, 2,
- "BMake indirect buffer (to buffer): \nbName of indirect buffer: ",
+ "bMake indirect buffer (to buffer): \nBName of indirect buffer: ",
"Create and return an indirect buffer for buffer BASE, named NAME.\n\
BASE should be an existing buffer (or buffer name).\n\
NAME should be a string which is not the name of an existing buffer.")
/* If buffer becoming modified, lock the file.
If buffer becoming unmodified, unlock the file. */
- fn = current_buffer->filename;
+ fn = current_buffer->file_truename;
if (!NILP (fn))
{
already = SAVE_MODIFF < MODIFF;
return Fget_buffer_create (build_string ("*scratch*"));
}
\f
-DEFUN ("buffer-disable-undo", Fbuffer_disable_undo, Sbuffer_disable_undo, 0, 1,
-0,
+DEFUN ("buffer-disable-undo", Fbuffer_disable_undo, Sbuffer_disable_undo,
+ 0, 1, "",
"Make BUFFER stop keeping undo information.\n\
No argument or nil as argument means do this for the current buffer.")
(buffer)
b = XBUFFER (buf);
+ /* Avoid trouble for buffer already dead. */
+ if (NILP (b->name))
+ return Qnil;
+
/* Query if the buffer is still modified. */
if (INTERACTIVE && !NILP (b->filename)
&& BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
GCPRO1 (buf);
for (other = all_buffers; other; other = other->next)
- if (other->base_buffer == b)
+ /* all_buffers contains dead buffers too;
+ don't re-kill them. */
+ if (other->base_buffer == b && !NILP (other->name))
{
Lisp_Object buf;
XSETBUFFER (buf, other);
internal_delete_file (b->auto_save_file_name);
}
- if (! b->base_buffer)
+ if (b->base_buffer)
{
- /* Unchain all markers of this buffer
+ /* Unchain all markers that belong to this indirect buffer.
+ Don't unchain the markers that belong to the base buffer
+ or its other indirect buffers. */
+ for (tem = BUF_MARKERS (b); !NILP (tem); )
+ {
+ Lisp_Object next;
+ m = XMARKER (tem);
+ next = m->chain;
+ if (m->buffer == b)
+ unchain_marker (tem);
+ tem = next;
+ }
+ }
+ else
+ {
+ /* Unchain all markers of this buffer and its indirect buffers.
and leave them pointing nowhere. */
- for (tem = BUF_MARKERS (b); !EQ (tem, Qnil); )
+ for (tem = BUF_MARKERS (b); !NILP (tem); )
{
m = XMARKER (tem);
m->buffer = 0;
/* Perhaps we should explicitly free the interval tree here... */
}
+ /* Reset the local variables, so that this buffer's local values
+ won't be protected from GC. They would be protected
+ if they happened to remain encached in their symbols.
+ This gets rid of them for certain. */
+ swap_out_buffer_local_variables (b);
+ reset_buffer_local_variables (b);
+
b->name = Qnil;
BLOCK_INPUT;
return buf;
}
\f
-/* Set the current buffer to b */
+/* Set the current buffer to B. */
void
set_buffer_internal (b)
return;
windows_or_buffers_changed = 1;
+ set_buffer_internal_1 (b);
+}
+
+/* Set the current buffer to B, and do not set windows_or_buffers_changed.
+ This is used by redisplay. */
+
+void
+set_buffer_internal_1 (b)
+ register struct buffer *b;
+{
+ register struct buffer *old_buf;
+ register Lisp_Object tail, valcontents;
+ Lisp_Object tem;
+
+ if (current_buffer == b)
+ return;
+
old_buf = current_buffer;
current_buffer = b;
last_known_column_point = -1; /* invalidate indentation cache */
}
/* Switch to buffer B temporarily for redisplay purposes.
- This avoids certain things thatdon't need to be done within redisplay. */
+ This avoids certain things that don't need to be done within redisplay. */
void
set_buffer_temp (b)
call1 (Vrun_hooks, intern ("change-major-mode-hook"));
oalist = current_buffer->local_var_alist;
- /* Make sure no local variables remain set up with this buffer
- for their current values. */
+ /* Make sure none of the bindings in oalist
+ remain swapped in, in their symbols. */
- for (alist = oalist; !NILP (alist); alist = XCONS (alist)->cdr)
- {
- sym = XCONS (XCONS (alist)->car)->car;
-
- /* Need not do anything if some other buffer's binding is now encached. */
- tem = XCONS (XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->cdr)->car;
- if (XBUFFER (tem) == current_buffer)
- {
- /* Symbol is set up for this buffer's old local value.
- Set it up for the current buffer with the default value. */
-
- tem = XCONS (XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->cdr)->cdr;
- /* Store the symbol's current value into the alist entry
- it is currently set up for. This is so that, if the
- local is marked permanent, and we make it local again below,
- we don't lose the value. */
- XCONS (XCONS (tem)->car)->cdr
- = do_symval_forwarding (XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->car);
- /* Switch to the symbol's default-value alist entry. */
- XCONS (tem)->car = tem;
- /* Mark it as current for the current buffer. */
- XCONS (XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->cdr)->car
- = Fcurrent_buffer ();
- /* Store the current value into any forwarding in the symbol. */
- store_symval_forwarding (sym, XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->car,
- XCONS (tem)->cdr);
- }
- }
+ swap_out_buffer_local_variables (current_buffer);
/* Actually eliminate all local bindings of this buffer. */
return Qnil;
}
+
+/* Make sure no local variables remain set up with buffer B
+ for their current values. */
+
+static void
+swap_out_buffer_local_variables (b)
+ struct buffer *b;
+{
+ Lisp_Object oalist, alist, sym, tem, buffer;
+
+ XSETBUFFER (buffer, b);
+ oalist = b->local_var_alist;
+
+ for (alist = oalist; !NILP (alist); alist = XCONS (alist)->cdr)
+ {
+ sym = XCONS (XCONS (alist)->car)->car;
+
+ /* Need not do anything if some other buffer's binding is now encached. */
+ tem = XCONS (XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->cdr)->car;
+ if (XBUFFER (tem) == current_buffer)
+ {
+ /* Symbol is set up for this buffer's old local value.
+ Set it up for the current buffer with the default value. */
+
+ tem = XCONS (XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->cdr)->cdr;
+ /* Store the symbol's current value into the alist entry
+ it is currently set up for. This is so that, if the
+ local is marked permanent, and we make it local again
+ later in Fkill_all_local_variables, we don't lose the value. */
+ XCONS (XCONS (tem)->car)->cdr
+ = do_symval_forwarding (XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->car);
+ /* Switch to the symbol's default-value alist entry. */
+ XCONS (tem)->car = tem;
+ /* Mark it as current for buffer B. */
+ XCONS (XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->cdr)->car
+ = buffer;
+ /* Store the current value into any forwarding in the symbol. */
+ store_symval_forwarding (sym, XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->car,
+ XCONS (tem)->cdr);
+ }
+ }
+}
\f
/* Find all the overlays in the current buffer that contain position POS.
Return the number found, and store them in a vector in *VEC_PTR.
Store in *LEN_PTR the size allocated for the vector.
Store in *NEXT_PTR the next position after POS where an overlay starts,
or ZV if there are no more overlays.
- Store in *PREV_PTR the previous position after POS where an overlay ends,
+ Store in *PREV_PTR the previous position before POS where an overlay ends,
or BEGV if there are no previous overlays.
NEXT_PTR and/or PREV_PTR may be 0, meaning don't store that info.
*prev_ptr = prev;
return idx;
}
+\f
+/* Find all the overlays in the current buffer that overlap the range BEG-END
+ or are empty at BEG.
+
+ Return the number found, and store them in a vector in *VEC_PTR.
+ Store in *LEN_PTR the size allocated for the vector.
+ Store in *NEXT_PTR the next position after POS where an overlay starts,
+ or ZV if there are no more overlays.
+ Store in *PREV_PTR the previous position before POS where an overlay ends,
+ or BEGV if there are no previous overlays.
+ NEXT_PTR and/or PREV_PTR may be 0, meaning don't store that info.
+
+ *VEC_PTR and *LEN_PTR should contain a valid vector and size
+ when this function is called.
+
+ If EXTEND is non-zero, we make the vector bigger if necessary.
+ If EXTEND is zero, we never extend the vector,
+ and we store only as many overlays as will fit.
+ But we still return the total number of overlays. */
+
+int
+overlays_in (beg, end, extend, vec_ptr, len_ptr, next_ptr, prev_ptr)
+ int beg, end;
+ int extend;
+ Lisp_Object **vec_ptr;
+ int *len_ptr;
+ int *next_ptr;
+ int *prev_ptr;
+{
+ Lisp_Object tail, overlay, ostart, oend, result;
+ int idx = 0;
+ int len = *len_ptr;
+ Lisp_Object *vec = *vec_ptr;
+ int next = ZV;
+ int prev = BEGV;
+ int inhibit_storing = 0;
+
+ for (tail = current_buffer->overlays_before;
+ GC_CONSP (tail);
+ tail = XCONS (tail)->cdr)
+ {
+ int startpos, endpos;
+
+ overlay = XCONS (tail)->car;
+
+ ostart = OVERLAY_START (overlay);
+ oend = OVERLAY_END (overlay);
+ endpos = OVERLAY_POSITION (oend);
+ if (endpos < beg)
+ {
+ if (prev < endpos)
+ prev = endpos;
+ break;
+ }
+ startpos = OVERLAY_POSITION (ostart);
+ /* Count an interval if it either overlaps the range
+ or is empty at the start of the range. */
+ if ((beg < endpos && startpos < end)
+ || (startpos == endpos && beg == endpos))
+ {
+ if (idx == len)
+ {
+ /* The supplied vector is full.
+ Either make it bigger, or don't store any more in it. */
+ if (extend)
+ {
+ *len_ptr = len *= 2;
+ vec = (Lisp_Object *) xrealloc (vec, len * sizeof (Lisp_Object));
+ *vec_ptr = vec;
+ }
+ else
+ inhibit_storing = 1;
+ }
+
+ if (!inhibit_storing)
+ vec[idx] = overlay;
+ /* Keep counting overlays even if we can't return them all. */
+ idx++;
+ }
+ else if (startpos < next)
+ next = startpos;
+ }
+
+ for (tail = current_buffer->overlays_after;
+ GC_CONSP (tail);
+ tail = XCONS (tail)->cdr)
+ {
+ int startpos, endpos;
+
+ overlay = XCONS (tail)->car;
+ ostart = OVERLAY_START (overlay);
+ oend = OVERLAY_END (overlay);
+ startpos = OVERLAY_POSITION (ostart);
+ if (end < startpos)
+ {
+ if (startpos < next)
+ next = startpos;
+ break;
+ }
+ endpos = OVERLAY_POSITION (oend);
+ /* Count an interval if it either overlaps the range
+ or is empty at the start of the range. */
+ if ((beg < endpos && startpos < end)
+ || (startpos == endpos && beg == endpos))
+ {
+ if (idx == len)
+ {
+ if (extend)
+ {
+ *len_ptr = len *= 2;
+ vec = (Lisp_Object *) xrealloc (vec, len * sizeof (Lisp_Object));
+ *vec_ptr = vec;
+ }
+ else
+ inhibit_storing = 1;
+ }
+
+ if (!inhibit_storing)
+ vec[idx] = overlay;
+ idx++;
+ }
+ else if (endpos < beg && endpos > prev)
+ prev = endpos;
+ }
+
+ if (next_ptr)
+ *next_ptr = next;
+ if (prev_ptr)
+ *prev_ptr = prev;
+ return idx;
+}
+\f
/* Fast function to just test if we're at an overlay boundary. */
int
overlay_touches_p (pos)
return (noverlays);
}
\f
+struct sortstr
+{
+ Lisp_Object string, string2;
+ int size;
+ int priority;
+};
+
+struct sortstrlist
+{
+ struct sortstr *buf; /* An array that expands as needed; never freed. */
+ int size; /* Allocated length of that array. */
+ int used; /* How much of the array is currently in use. */
+ int bytes; /* Total length of the strings in buf. */
+};
+
+/* Buffers for storing information about the overlays touching a given
+ position. These could be automatic variables in overlay_strings, but
+ it's more efficient to hold onto the memory instead of repeatedly
+ allocating and freeing it. */
+static struct sortstrlist overlay_heads, overlay_tails;
+static char *overlay_str_buf;
+
+/* Allocated length of overlay_str_buf. */
+static int overlay_str_len;
+
+/* A comparison function suitable for passing to qsort. */
+static int
+cmp_for_strings (as1, as2)
+ char *as1, *as2;
+{
+ struct sortstr *s1 = (struct sortstr *)as1;
+ struct sortstr *s2 = (struct sortstr *)as2;
+ if (s1->size != s2->size)
+ return s2->size - s1->size;
+ if (s1->priority != s2->priority)
+ return s1->priority - s2->priority;
+ return 0;
+}
+
+static void
+record_overlay_string (ssl, str, str2, pri, size)
+ struct sortstrlist *ssl;
+ Lisp_Object str, str2, pri;
+ int size;
+{
+ if (ssl->used == ssl->size)
+ {
+ if (ssl->buf)
+ ssl->size *= 2;
+ else
+ ssl->size = 5;
+ ssl->buf = ((struct sortstr *)
+ xrealloc (ssl->buf, ssl->size * sizeof (struct sortstr)));
+ }
+ ssl->buf[ssl->used].string = str;
+ ssl->buf[ssl->used].string2 = str2;
+ ssl->buf[ssl->used].size = size;
+ ssl->buf[ssl->used].priority = (INTEGERP (pri) ? XINT (pri) : 0);
+ ssl->used++;
+ ssl->bytes += XSTRING (str)->size;
+ if (STRINGP (str2))
+ ssl->bytes += XSTRING (str2)->size;
+}
+
+/* Return the concatenation of the strings associated with overlays that
+ begin or end at POS, ignoring overlays that are specific to a window
+ other than W. The strings are concatenated in the appropriate order:
+ shorter overlays nest inside longer ones, and higher priority inside
+ lower. Normally all of the after-strings come first, but zero-sized
+ overlays have their after-strings ride along with the before-strings
+ because it would look strange to print them inside-out.
+
+ Returns the string length, and stores the contents indirectly through
+ PSTR, if that variable is non-null. The string may be overwritten by
+ subsequent calls. */
+int
+overlay_strings (pos, w, pstr)
+ int pos;
+ struct window *w;
+ char **pstr;
+{
+ Lisp_Object ov, overlay, window, str;
+ int startpos, endpos;
+
+ overlay_heads.used = overlay_heads.bytes = 0;
+ overlay_tails.used = overlay_tails.bytes = 0;
+ for (ov = current_buffer->overlays_before; CONSP (ov); ov = XCONS (ov)->cdr)
+ {
+ overlay = XCONS (ov)->car;
+ if (!OVERLAYP (overlay))
+ abort ();
+
+ startpos = OVERLAY_POSITION (OVERLAY_START (overlay));
+ endpos = OVERLAY_POSITION (OVERLAY_END (overlay));
+ if (endpos < pos)
+ break;
+ if (endpos != pos && startpos != pos)
+ continue;
+ window = Foverlay_get (overlay, Qwindow);
+ if (WINDOWP (window) && XWINDOW (window) != w)
+ continue;
+ if (startpos == pos
+ && (str = Foverlay_get (overlay, Qbefore_string), STRINGP (str)))
+ record_overlay_string (&overlay_heads, str,
+ (startpos == endpos
+ ? Foverlay_get (overlay, Qafter_string)
+ : Qnil),
+ Foverlay_get (overlay, Qpriority),
+ endpos - startpos);
+ else if (endpos == pos
+ && (str = Foverlay_get (overlay, Qafter_string), STRINGP (str)))
+ record_overlay_string (&overlay_tails, str, Qnil,
+ Foverlay_get (overlay, Qpriority),
+ endpos - startpos);
+ }
+ for (ov = current_buffer->overlays_after; CONSP (ov); ov = XCONS (ov)->cdr)
+ {
+ overlay = XCONS (ov)->car;
+ if (!OVERLAYP (overlay))
+ abort ();
+
+ startpos = OVERLAY_POSITION (OVERLAY_START (overlay));
+ endpos = OVERLAY_POSITION (OVERLAY_END (overlay));
+ if (startpos > pos)
+ break;
+ if (endpos != pos && startpos != pos)
+ continue;
+ window = Foverlay_get (overlay, Qwindow);
+ if (WINDOWP (window) && XWINDOW (window) != w)
+ continue;
+ if (startpos == pos
+ && (str = Foverlay_get (overlay, Qbefore_string), STRINGP (str)))
+ record_overlay_string (&overlay_heads, str,
+ (startpos == endpos
+ ? Foverlay_get (overlay, Qafter_string)
+ : Qnil),
+ Foverlay_get (overlay, Qpriority),
+ endpos - startpos);
+ else if (endpos == pos
+ && (str = Foverlay_get (overlay, Qafter_string), STRINGP (str)))
+ record_overlay_string (&overlay_tails, str, Qnil,
+ Foverlay_get (overlay, Qpriority),
+ endpos - startpos);
+ }
+ if (overlay_tails.used > 1)
+ qsort (overlay_tails.buf, overlay_tails.used, sizeof (struct sortstr),
+ cmp_for_strings);
+ if (overlay_heads.used > 1)
+ qsort (overlay_heads.buf, overlay_heads.used, sizeof (struct sortstr),
+ cmp_for_strings);
+ if (overlay_heads.bytes || overlay_tails.bytes)
+ {
+ Lisp_Object tem;
+ int i;
+ char *p;
+ int total = overlay_heads.bytes + overlay_tails.bytes;
+
+ if (total > overlay_str_len)
+ overlay_str_buf = (char *)xrealloc (overlay_str_buf,
+ overlay_str_len = total);
+ p = overlay_str_buf;
+ for (i = overlay_tails.used; --i >= 0;)
+ {
+ tem = overlay_tails.buf[i].string;
+ bcopy (XSTRING (tem)->data, p, XSTRING (tem)->size);
+ p += XSTRING (tem)->size;
+ }
+ for (i = 0; i < overlay_heads.used; ++i)
+ {
+ tem = overlay_heads.buf[i].string;
+ bcopy (XSTRING (tem)->data, p, XSTRING (tem)->size);
+ p += XSTRING (tem)->size;
+ tem = overlay_heads.buf[i].string2;
+ if (STRINGP (tem))
+ {
+ bcopy (XSTRING (tem)->data, p, XSTRING (tem)->size);
+ p += XSTRING (tem)->size;
+ }
+ }
+ if (p != overlay_str_buf + total)
+ abort ();
+ if (pstr)
+ *pstr = overlay_str_buf;
+ return total;
+ }
+ return 0;
+}
+\f
/* Shift overlays in BUF's overlay lists, to center the lists at POS. */
void
XSETFASTINT (buf->overlay_center, pos);
}
+void
+adjust_overlays_for_insert (pos, length)
+ int pos;
+ int length;
+{
+ /* After an insertion, the lists are still sorted properly,
+ but we may need to update the value of the overlay center. */
+ if (XFASTINT (current_buffer->overlay_center) >= pos)
+ XSETFASTINT (current_buffer->overlay_center,
+ XFASTINT (current_buffer->overlay_center) + length);
+}
+
+void
+adjust_overlays_for_delete (pos, length)
+ int pos;
+ int length;
+{
+ if (XFASTINT (current_buffer->overlay_center) < pos)
+ /* The deletion was to our right. No change needed; the before- and
+ after-lists are still consistent. */
+ ;
+ else if (XFASTINT (current_buffer->overlay_center) > pos + length)
+ /* The deletion was to our left. We need to adjust the center value
+ to account for the change in position, but the lists are consistent
+ given the new value. */
+ XSETFASTINT (current_buffer->overlay_center,
+ XFASTINT (current_buffer->overlay_center) - length);
+ else
+ /* We're right in the middle. There might be things on the after-list
+ that now belong on the before-list. Recentering will move them,
+ and also update the center point. */
+ recenter_overlay_lists (current_buffer, pos);
+}
+
/* Fix up overlays that were garbled as a result of permuting markers
in the range START through END. Any overlay with at least one
endpoint in this range will need to be unlinked from the overlay
end = Fset_marker (Fmake_marker (), end, buffer);
overlay = allocate_misc ();
- XMISC (overlay)->type = Lisp_Misc_Overlay;
+ XMISCTYPE (overlay) = Lisp_Misc_Overlay;
XOVERLAY (overlay)->start = beg;
XOVERLAY (overlay)->end = end;
XOVERLAY (overlay)->plist = Qnil;
/* Redisplay where the overlay is going to be. */
redisplay_region (b, XINT (beg), XINT (end));
-
- /* Don't limit redisplay to the selected window. */
- windows_or_buffers_changed = 1;
}
else
/* Redisplay the area the overlay has just left, or just enclosed. */
/* Put all the overlays we want in a vector in overlay_vec.
Store the length in len. */
- noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len, NULL, NULL);
+ noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len,
+ (int *) 0, (int *) 0);
+
+ /* Make a list of them all. */
+ result = Flist (noverlays, overlay_vec);
+
+ xfree (overlay_vec);
+ return result;
+}
+
+DEFUN ("overlays-in", Foverlays_in, Soverlays_in, 2, 2, 0,
+ "Return a list of the overlays that overlap the region BEG ... END.\n\
+Overlap means that at least one character is contained within the overlay\n\
+and also contained within the specified region.\n\
+Empty overlays are included in the result if they are located at BEG\n\
+or between BEG and END.")
+ (beg, end)
+ Lisp_Object beg, end;
+{
+ int noverlays;
+ Lisp_Object *overlay_vec;
+ int len;
+ Lisp_Object result;
+
+ CHECK_NUMBER_COERCE_MARKER (beg, 0);
+ CHECK_NUMBER_COERCE_MARKER (end, 0);
+
+ len = 10;
+ overlay_vec = (Lisp_Object *) xmalloc (len * sizeof (Lisp_Object));
+
+ /* Put all the overlays we want in a vector in overlay_vec.
+ Store the length in len. */
+ noverlays = overlays_in (XINT (beg), XINT (end), 1, &overlay_vec, &len,
+ (int *) 0, (int *) 0);
/* Make a list of them all. */
result = Flist (noverlays, overlay_vec);
/* Put all the overlays we want in a vector in overlay_vec.
Store the length in len.
endpos gets the position where the next overlay starts. */
- noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len, &endpos, NULL);
+ noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len,
+ &endpos, (int *) 0);
/* If any of these overlays ends before endpos,
use its ending point instead. */
DEFUN ("previous-overlay-change", Fprevious_overlay_change,
Sprevious_overlay_change, 1, 1, 0,
"Return the previous position before POS where an overlay starts or ends.\n\
-If there are no more overlay boundaries after POS, return (point-min).")
+If there are no more overlay boundaries before POS, return (point-min).")
(pos)
Lisp_Object pos;
{
Lisp_Object *overlay_vec;
int len;
int i;
+ Lisp_Object tail;
CHECK_NUMBER_COERCE_MARKER (pos, 0);
len = 10;
overlay_vec = (Lisp_Object *) xmalloc (len * sizeof (Lisp_Object));
+ /* At beginning of buffer, we know the answer;
+ avoid bug subtracting 1 below. */
+ if (XINT (pos) == BEGV)
+ return pos;
+
/* Put all the overlays we want in a vector in overlay_vec.
Store the length in len.
prevpos gets the position of an overlay end. */
- noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len, NULL, &prevpos);
+ noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len,
+ (int *) 0, &prevpos);
- /* If any of these overlays starts before endpos,
+ /* If any of these overlays starts after prevpos,
maybe use its starting point instead. */
for (i = 0; i < noverlays; i++)
{
prevpos = ostartpos;
}
+ /* If any overlay ends at pos, consider its starting point too. */
+ for (tail = current_buffer->overlays_before;
+ GC_CONSP (tail);
+ tail = XCONS (tail)->cdr)
+ {
+ Lisp_Object overlay, ostart;
+ int ostartpos;
+
+ overlay = XCONS (tail)->car;
+
+ ostart = OVERLAY_START (overlay);
+ ostartpos = OVERLAY_POSITION (ostart);
+ if (ostartpos > prevpos && ostartpos < XINT (pos))
+ prevpos = ostartpos;
+ }
+
xfree (overlay_vec);
return make_number (prevpos);
}
return value;
}
\f
+/* Subroutine of report_overlay_modification. */
+
+/* Lisp vector holding overlay hook functions to call.
+ Vector elements come in pairs.
+ Each even-index element is a list of hook functions.
+ The following odd-index element is the overlay they came from.
+
+ Before the buffer change, we fill in this vector
+ as we call overlay hook functions.
+ After the buffer change, we get the functions to call from this vector.
+ This way we always call the same functions before and after the change. */
+static Lisp_Object last_overlay_modification_hooks;
+
+/* Number of elements actually used in last_overlay_modification_hooks. */
+static int last_overlay_modification_hooks_used;
+
+/* Add one functionlist/overlay pair
+ to the end of last_overlay_modification_hooks. */
+
+static void
+add_overlay_mod_hooklist (functionlist, overlay)
+ Lisp_Object functionlist, overlay;
+{
+ int oldsize = XVECTOR (last_overlay_modification_hooks)->size;
+
+ if (last_overlay_modification_hooks_used == oldsize)
+ {
+ Lisp_Object old;
+ old = last_overlay_modification_hooks;
+ last_overlay_modification_hooks
+ = Fmake_vector (make_number (oldsize * 2), Qnil);
+ bcopy (XVECTOR (last_overlay_modification_hooks)->contents,
+ XVECTOR (old)->contents,
+ sizeof (Lisp_Object) * oldsize);
+ }
+ XVECTOR (last_overlay_modification_hooks)->contents[last_overlay_modification_hooks_used++] = functionlist;
+ XVECTOR (last_overlay_modification_hooks)->contents[last_overlay_modification_hooks_used++] = overlay;
+}
+\f
/* Run the modification-hooks of overlays that include
any part of the text in START to END.
- Run the insert-before-hooks of overlay starting at END,
+ If this change is an insertion, also
+ run the insert-before-hooks of overlay starting at END,
and the insert-after-hooks of overlay ending at START.
This is called both before and after the modification.
AFTER is nonzero when we call after the modification.
- ARG1, ARG2, ARG3 are arguments to pass to the hook functions. */
+ ARG1, ARG2, ARG3 are arguments to pass to the hook functions.
+ When AFTER is nonzero, they are the start position,
+ the position after the inserted new text,
+ and the length of deleted or replaced old text. */
void
report_overlay_modification (start, end, after, arg1, arg2, arg3)
Lisp_Object arg1, arg2, arg3;
{
Lisp_Object prop, overlay, tail;
- int insertion = EQ (start, end);
+ /* 1 if this change is an insertion. */
+ int insertion = (after ? XFASTINT (arg3) == 0 : EQ (start, end));
int tail_copied;
struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
tail = Qnil;
GCPRO5 (overlay, tail, arg1, arg2, arg3);
+ if (after)
+ {
+ /* Call the functions recorded in last_overlay_modification_hooks
+ rather than scanning the overlays again.
+ First copy the vector contents, in case some of these hooks
+ do subsequent modification of the buffer. */
+ int size = last_overlay_modification_hooks_used;
+ Lisp_Object *copy = (Lisp_Object *) alloca (size * sizeof (Lisp_Object));
+ int i;
+
+ bcopy (XVECTOR (last_overlay_modification_hooks)->contents,
+ copy, size * sizeof (Lisp_Object));
+ gcpro1.var = copy;
+ gcpro1.nvars = size;
+
+ for (i = 0; i < size;)
+ {
+ Lisp_Object prop, overlay;
+ prop = copy[i++];
+ overlay = copy[i++];
+ call_overlay_mod_hooks (prop, overlay, after, arg1, arg2, arg3);
+ }
+ UNGCPRO;
+ return;
+ }
+
+ /* We are being called before a change.
+ Scan the overlays to find the functions to call. */
+ last_overlay_modification_hooks_used = 0;
tail_copied = 0;
for (tail = current_buffer->overlays_before;
CONSP (tail);
if (XFASTINT (start) > endpos)
break;
startpos = OVERLAY_POSITION (ostart);
- if (XFASTINT (end) == startpos && insertion)
+ if (insertion && (XFASTINT (start) == startpos
+ || XFASTINT (end) == startpos))
{
prop = Foverlay_get (overlay, Qinsert_in_front_hooks);
if (!NILP (prop))
call_overlay_mod_hooks (prop, overlay, after, arg1, arg2, arg3);
}
}
- if (XFASTINT (start) == endpos && insertion)
+ if (insertion && (XFASTINT (start) == endpos
+ || XFASTINT (end) == endpos))
{
prop = Foverlay_get (overlay, Qinsert_behind_hooks);
if (!NILP (prop))
endpos = OVERLAY_POSITION (oend);
if (XFASTINT (end) < startpos)
break;
- if (XFASTINT (end) == startpos && insertion)
+ if (insertion && (XFASTINT (start) == startpos
+ || XFASTINT (end) == startpos))
{
prop = Foverlay_get (overlay, Qinsert_in_front_hooks);
if (!NILP (prop))
call_overlay_mod_hooks (prop, overlay, after, arg1, arg2, arg3);
}
}
- if (XFASTINT (start) == endpos && insertion)
+ if (insertion && (XFASTINT (start) == endpos
+ || XFASTINT (end) == endpos))
{
prop = Foverlay_get (overlay, Qinsert_behind_hooks);
if (!NILP (prop))
Lisp_Object arg1, arg2, arg3;
{
struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+
GCPRO4 (list, arg1, arg2, arg3);
+ if (! after)
+ add_overlay_mod_hooklist (list, overlay);
+
while (!NILP (list))
{
if (NILP (arg3))
if (endpos < pos)
break;
if (endpos == pos && OVERLAY_POSITION (OVERLAY_START (overlay)) == pos
- && Foverlay_get (overlay, Qevaporate))
+ && ! NILP (Foverlay_get (overlay, Qevaporate)))
hit_list = Fcons (overlay, hit_list);
}
else
if (startpos > pos)
break;
if (startpos == pos && OVERLAY_POSITION (OVERLAY_END (overlay)) == pos
- && Foverlay_get (overlay, Qevaporate))
+ && ! NILP (Foverlay_get (overlay, Qevaporate)))
hit_list = Fcons (overlay, hit_list);
}
for (; CONSP (hit_list); hit_list = XCONS (hit_list)->cdr)
buffer_defaults.file_format = Qnil;
buffer_defaults.overlays_before = Qnil;
buffer_defaults.overlays_after = Qnil;
- XSETFASTINT (buffer_defaults.overlay_center, 1);
+ XSETFASTINT (buffer_defaults.overlay_center, BEG);
XSETFASTINT (buffer_defaults.tab_width, 8);
buffer_defaults.truncate_lines = Qnil;
{
extern Lisp_Object Qdisabled;
+ staticpro (&last_overlay_modification_hooks);
+ last_overlay_modification_hooks
+ = Fmake_vector (make_number (10), Qnil);
+
staticpro (&Vbuffer_defaults);
staticpro (&Vbuffer_local_symbols);
staticpro (&Qfundamental_mode);
staticpro (&Qprotected_field);
staticpro (&Qpermanent_local);
staticpro (&Qkill_buffer_hook);
+ Qoverlayp = intern ("overlayp");
staticpro (&Qoverlayp);
Qevaporate = intern ("evaporate");
staticpro (&Qevaporate);
- staticpro (&Qmodification_hooks);
Qmodification_hooks = intern ("modification-hooks");
- staticpro (&Qinsert_in_front_hooks);
+ staticpro (&Qmodification_hooks);
Qinsert_in_front_hooks = intern ("insert-in-front-hooks");
- staticpro (&Qinsert_behind_hooks);
+ staticpro (&Qinsert_in_front_hooks);
Qinsert_behind_hooks = intern ("insert-behind-hooks");
- staticpro (&Qget_file_buffer);
+ staticpro (&Qinsert_behind_hooks);
Qget_file_buffer = intern ("get-file-buffer");
+ staticpro (&Qget_file_buffer);
Qpriority = intern ("priority");
staticpro (&Qpriority);
Qwindow = intern ("window");
staticpro (&Qwindow);
-
- Qoverlayp = intern ("overlayp");
+ Qbefore_string = intern ("before-string");
+ staticpro (&Qbefore_string);
+ Qafter_string = intern ("after-string");
+ staticpro (&Qafter_string);
+ Qfirst_change_hook = intern ("first-change-hook");
+ staticpro (&Qfirst_change_hook);
+ Qbefore_change_functions = intern ("before-change-functions");
+ staticpro (&Qbefore_change_functions);
+ Qafter_change_functions = intern ("after-change-functions");
+ staticpro (&Qafter_change_functions);
Fput (Qprotected_field, Qerror_conditions,
Fcons (Qprotected_field, Fcons (Qerror, Qnil)));
DEFVAR_PER_BUFFER ("buffer-file-truename", ¤t_buffer->file_truename,
make_number (Lisp_String),
- "Truename of file visited in current buffer, or nil if not visiting a file.\n\
-The truename of a file is calculated by `file-truename'.\n\
+ "Abbreviated truename of file visited in current buffer, or nil if none.\n\
+The truename of a file is calculated by `file-truename'\n\
+and then abbreviated with `abbreviate-file-name'.\n\
Each buffer has its own value of this variable.");
DEFVAR_PER_BUFFER ("buffer-auto-save-file-name",
"A list of functions to call before changing a buffer which is unmodified.\n\
The functions are run using the `run-hooks' function.");
Vfirst_change_hook = Qnil;
- Qfirst_change_hook = intern ("first-change-hook");
- staticpro (&Qfirst_change_hook);
#if 0 /* The doc string is too long for some compilers,
but make-docfile can find it in this comment. */
"List of undo entries in current buffer.\n\
Recent changes come first; older changes follow newer.\n\
\n\
-An entry (START . END) represents an insertion which begins at\n\
-position START and ends at position END.\n\
+An entry (BEG . END) represents an insertion which begins at\n\
+position BEG and ends at position END.\n\
\n\
An entry (TEXT . POSITION) represents the deletion of the string TEXT\n\
from (abs POSITION). If POSITION is positive, point was at the front\n\
if it has a non-nil `invisible' property.\n\
If the value is a list, a text character is invisible if its `invisible'\n\
property is an element in that list.\n\
-If an element is a cons cell of the for (PROP . ELLIPSIS),\n\
-then characters with property value PROP is invisible,\n\
+If an element is a cons cell of the form (PROP . ELLIPSIS),\n\
+then characters with property value PROP are invisible,\n\
and they have an ellipsis as well if ELLIPSIS is non-nil.");
DEFVAR_LISP ("transient-mark-mode", &Vtransient_mark_mode,
defsubr (&Soverlay_buffer);
defsubr (&Soverlay_properties);
defsubr (&Soverlays_at);
+ defsubr (&Soverlays_in);
defsubr (&Snext_overlay_change);
defsubr (&Sprevious_overlay_change);
defsubr (&Soverlay_recenter);