Function: buffer-swap-text
buffer-swap-text is a function defined in buffer.c.
Signature
(buffer-swap-text BUFFER)
Documentation
Swap the text between current buffer and BUFFER.
Using this function from save-excursion might produce surprising
results, see Info node (elisp)Swapping Text.
Probably introduced at or before Emacs version 23.1.
Source Code
// Defined in /usr/src/emacs/src/buffer.c
// Skipping highlighting due to helpful-max-highlight.
{
struct buffer *other_buffer;
CHECK_BUFFER (buffer);
other_buffer = XBUFFER (buffer);
if (!BUFFER_LIVE_P (other_buffer))
error ("Cannot swap a dead buffer's text");
/* Actually, it probably works just fine.
* if (other_buffer == current_buffer)
* error ("Cannot swap a buffer's text with itself"); */
/* Actually, this may be workable as well, tho probably only if they're
*both* indirect. */
if (other_buffer->base_buffer
|| current_buffer->base_buffer)
error ("Cannot swap indirect buffers's text");
{ /* This is probably harder to make work. */
Lisp_Object tail, other;
FOR_EACH_LIVE_BUFFER (tail, other)
if (XBUFFER (other)->base_buffer == other_buffer
|| XBUFFER (other)->base_buffer == current_buffer)
error ("One of the buffers to swap has indirect buffers");
}
#define swapfield(field, type) \
do { \
type tmp##field = other_buffer->field; \
other_buffer->field = current_buffer->field; \
current_buffer->field = tmp##field; \
} while (0)
#define swapfield_(field, type) \
do { \
type tmp##field = BVAR (other_buffer, field); \
bset_##field (other_buffer, BVAR (current_buffer, field)); \
bset_##field (current_buffer, tmp##field); \
} while (0)
swapfield (own_text, struct buffer_text);
eassert (current_buffer->text == ¤t_buffer->own_text);
eassert (other_buffer->text == &other_buffer->own_text);
#ifdef REL_ALLOC
r_alloc_reset_variable ((void **) ¤t_buffer->own_text.beg,
(void **) &other_buffer->own_text.beg);
r_alloc_reset_variable ((void **) &other_buffer->own_text.beg,
(void **) ¤t_buffer->own_text.beg);
#endif /* REL_ALLOC */
swapfield (pt, ptrdiff_t);
swapfield (pt_byte, ptrdiff_t);
swapfield (begv, ptrdiff_t);
swapfield (begv_byte, ptrdiff_t);
swapfield (zv, ptrdiff_t);
swapfield (zv_byte, ptrdiff_t);
eassert (!current_buffer->base_buffer);
eassert (!other_buffer->base_buffer);
swapfield (indirections, ptrdiff_t);
current_buffer->clip_changed = 1; other_buffer->clip_changed = 1;
swapfield (newline_cache, struct region_cache *);
swapfield (width_run_cache, struct region_cache *);
swapfield (bidi_paragraph_cache, struct region_cache *);
current_buffer->prevent_redisplay_optimizations_p = 1;
other_buffer->prevent_redisplay_optimizations_p = 1;
swapfield (long_line_optimizations_p, bool_bf);
swapfield_ (undo_list, Lisp_Object);
swapfield_ (mark, Lisp_Object);
swapfield_ (mark_active, Lisp_Object); /* Belongs with the `mark'. */
swapfield_ (enable_multibyte_characters, Lisp_Object);
swapfield_ (bidi_display_reordering, Lisp_Object);
swapfield_ (bidi_paragraph_direction, Lisp_Object);
swapfield_ (bidi_paragraph_separate_re, Lisp_Object);
swapfield_ (bidi_paragraph_start_re, Lisp_Object);
/* FIXME: Not sure what we should do with these *_marker fields.
Hopefully they're just nil anyway. */
swapfield_ (pt_marker, Lisp_Object);
swapfield_ (begv_marker, Lisp_Object);
swapfield_ (zv_marker, Lisp_Object);
bset_point_before_scroll (current_buffer, Qnil);
bset_point_before_scroll (other_buffer, Qnil);
modiff_incr (¤t_buffer->text->modiff, 1);
modiff_incr (&other_buffer->text->modiff, 1);
modiff_incr (¤t_buffer->text->chars_modiff, 1);
modiff_incr (&other_buffer->text->chars_modiff, 1);
modiff_incr (¤t_buffer->text->overlay_modiff, 1);
modiff_incr (&other_buffer->text->overlay_modiff, 1);
current_buffer->text->beg_unchanged = current_buffer->text->gpt;
current_buffer->text->end_unchanged = current_buffer->text->gpt;
other_buffer->text->beg_unchanged = other_buffer->text->gpt;
other_buffer->text->end_unchanged = other_buffer->text->gpt;
swap_buffer_overlays (current_buffer, other_buffer);
{
struct Lisp_Marker *m;
for (m = BUF_MARKERS (current_buffer); m; m = m->next)
if (m->buffer == other_buffer)
m->buffer = current_buffer;
else
/* Since there's no indirect buffer in sight, markers on
BUF_MARKERS(buf) should either be for `buf' or dead. */
eassert (!m->buffer);
for (m = BUF_MARKERS (other_buffer); m; m = m->next)
if (m->buffer == current_buffer)
m->buffer = other_buffer;
else
/* Since there's no indirect buffer in sight, markers on
BUF_MARKERS(buf) should either be for `buf' or dead. */
eassert (!m->buffer);
}
{ /* Some of the C code expects that both window markers of a
live window points to that window's buffer. So since we
just swapped the markers between the two buffers, we need
to undo the effect of this swap for window markers. */
Lisp_Object w = selected_window, ws = Qnil;
Lisp_Object buf1, buf2;
XSETBUFFER (buf1, current_buffer); XSETBUFFER (buf2, other_buffer);
while (NILP (Fmemq (w, ws)))
{
ws = Fcons (w, ws);
if (MARKERP (XWINDOW (w)->pointm)
&& (BASE_EQ (XWINDOW (w)->contents, buf1)
|| BASE_EQ (XWINDOW (w)->contents, buf2)))
Fset_marker (XWINDOW (w)->pointm,
make_fixnum
(BUF_BEGV (XBUFFER (XWINDOW (w)->contents))),
XWINDOW (w)->contents);
/* Blindly copied from pointm part. */
if (MARKERP (XWINDOW (w)->old_pointm)
&& (BASE_EQ (XWINDOW (w)->contents, buf1)
|| BASE_EQ (XWINDOW (w)->contents, buf2)))
Fset_marker (XWINDOW (w)->old_pointm,
make_fixnum
(BUF_BEGV (XBUFFER (XWINDOW (w)->contents))),
XWINDOW (w)->contents);
if (MARKERP (XWINDOW (w)->start)
&& (BASE_EQ (XWINDOW (w)->contents, buf1)
|| BASE_EQ (XWINDOW (w)->contents, buf2)))
Fset_marker (XWINDOW (w)->start,
make_fixnum
(XBUFFER (XWINDOW (w)->contents)->last_window_start),
XWINDOW (w)->contents);
w = Fnext_window (w, Qt, Qt);
}
}
if (current_buffer->text->intervals)
(eassert (BASE_EQ (current_buffer->text->intervals->up.obj, buffer)),
XSETBUFFER (current_buffer->text->intervals->up.obj, current_buffer));
if (other_buffer->text->intervals)
(eassert (BASE_EQ (other_buffer->text->intervals->up.obj,
Fcurrent_buffer ())),
XSETBUFFER (other_buffer->text->intervals->up.obj, other_buffer));
return Qnil;
}