mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-15 10:30:25 -08:00
AWG for markers
This commit is contained in:
parent
f7725d85f3
commit
f5700862ab
22 changed files with 736 additions and 406 deletions
53
src/alloc.c
53
src/alloc.c
|
|
@ -30,6 +30,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#endif
|
||||
|
||||
#include "lisp.h"
|
||||
#include "marker.h"
|
||||
#include "bignum.h"
|
||||
#include "dispextern.h"
|
||||
#include "intervals.h"
|
||||
|
|
@ -4031,45 +4032,6 @@ build_overlay (bool front_advance, bool rear_advance,
|
|||
return overlay;
|
||||
}
|
||||
|
||||
DEFUN ("make-marker", Fmake_marker, Smake_marker, 0, 0, 0,
|
||||
doc: /* Return a newly allocated marker which does not point at any place. */)
|
||||
(void)
|
||||
{
|
||||
struct Lisp_Marker *p = ALLOCATE_PLAIN_PSEUDOVECTOR (struct Lisp_Marker,
|
||||
PVEC_MARKER);
|
||||
p->buffer = 0;
|
||||
p->bytepos = 0;
|
||||
p->charpos = 0;
|
||||
p->next = NULL;
|
||||
p->insertion_type = 0;
|
||||
p->need_adjustment = 0;
|
||||
return make_lisp_ptr (p, Lisp_Vectorlike);
|
||||
}
|
||||
|
||||
/* Return a newly allocated marker which points into BUF
|
||||
at character position CHARPOS and byte position BYTEPOS. */
|
||||
|
||||
Lisp_Object
|
||||
build_marker (struct buffer *buf, ptrdiff_t charpos, ptrdiff_t bytepos)
|
||||
{
|
||||
/* No dead buffers here. */
|
||||
eassert (BUFFER_LIVE_P (buf));
|
||||
|
||||
/* Every character is at least one byte. */
|
||||
eassert (charpos <= bytepos);
|
||||
|
||||
struct Lisp_Marker *m = ALLOCATE_PLAIN_PSEUDOVECTOR (struct Lisp_Marker,
|
||||
PVEC_MARKER);
|
||||
m->buffer = buf;
|
||||
m->charpos = charpos;
|
||||
m->bytepos = bytepos;
|
||||
m->insertion_type = 0;
|
||||
m->need_adjustment = 0;
|
||||
m->next = BUF_MARKERS (buf);
|
||||
BUF_MARKERS (buf) = m;
|
||||
return make_lisp_ptr (m, Lisp_Vectorlike);
|
||||
}
|
||||
|
||||
|
||||
/* Return a newly created vector or string with specified arguments as
|
||||
elements. If all the arguments are characters that can fit
|
||||
|
|
@ -7836,15 +7798,11 @@ sweep_symbols (void)
|
|||
static void
|
||||
unchain_dead_markers (struct buffer *buffer)
|
||||
{
|
||||
struct Lisp_Marker *this, **prev = &BUF_MARKERS (buffer);
|
||||
|
||||
while ((this = *prev))
|
||||
if (vectorlike_marked_p (&this->header))
|
||||
prev = &this->next;
|
||||
else
|
||||
MARKERS_DO_ALL (it, BUF_ALL_MARKERS (current_buffer))
|
||||
if (!vectorlike_marked_p (&it.m->header))
|
||||
{
|
||||
this->buffer = NULL;
|
||||
*prev = this->next;
|
||||
markers_kill (it.t, it.m);
|
||||
it.m->buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -8287,7 +8245,6 @@ N should be nonnegative. */);
|
|||
defsubr (&Smake_string);
|
||||
defsubr (&Smake_bool_vector);
|
||||
defsubr (&Smake_symbol);
|
||||
defsubr (&Smake_marker);
|
||||
defsubr (&Smake_finalizer);
|
||||
defsubr (&Spurecopy);
|
||||
defsubr (&Sgarbage_collect);
|
||||
|
|
|
|||
67
src/buffer.c
67
src/buffer.c
|
|
@ -30,6 +30,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#include <verify.h>
|
||||
|
||||
#include "lisp.h"
|
||||
#include "marker.h"
|
||||
#include "intervals.h"
|
||||
#include "process.h"
|
||||
#include "systime.h"
|
||||
|
|
@ -660,8 +661,8 @@ even if it is dead. The return value is never nil. */)
|
|||
reset_buffer (b);
|
||||
reset_buffer_local_variables (b, 1);
|
||||
|
||||
BUF_ALL_MARKERS (b) = markers_new (4); /* Initial room for 4 markers. */
|
||||
bset_mark (b, Fmake_marker ());
|
||||
BUF_MARKERS (b) = NULL;
|
||||
|
||||
/* Put this in the alist of all live buffers. */
|
||||
XSETBUFFER (buffer, b);
|
||||
|
|
@ -2069,16 +2070,13 @@ cleaning up all windows currently displaying the buffer to be killed. */)
|
|||
/* 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. */
|
||||
struct Lisp_Marker **mp = &BUF_MARKERS (b);
|
||||
while ((m = *mp))
|
||||
MARKERS_DO_ALL (it, BUF_ALL_MARKERS (b))
|
||||
{
|
||||
if (m->buffer == b)
|
||||
if (it.m->buffer == b)
|
||||
{
|
||||
m->buffer = NULL;
|
||||
*mp = m->next;
|
||||
markers_kill (it.t, it.m);
|
||||
it.m->buffer = NULL;
|
||||
}
|
||||
else
|
||||
mp = &m->next;
|
||||
}
|
||||
/* Intervals should be owned by the base buffer (Bug#16502). */
|
||||
i = buffer_intervals (b);
|
||||
|
|
@ -2093,14 +2091,10 @@ cleaning up all windows currently displaying the buffer to be killed. */)
|
|||
{
|
||||
/* Unchain all markers of this buffer and its indirect buffers.
|
||||
and leave them pointing nowhere. */
|
||||
for (m = BUF_MARKERS (b); m; )
|
||||
{
|
||||
struct Lisp_Marker *next = m->next;
|
||||
m->buffer = 0;
|
||||
m->next = NULL;
|
||||
m = next;
|
||||
}
|
||||
BUF_MARKERS (b) = NULL;
|
||||
MARKERS_DO_ALL (it, BUF_ALL_MARKERS (b))
|
||||
it.m->buffer = NULL;
|
||||
xfree (BUF_ALL_MARKERS (b));
|
||||
BUF_ALL_MARKERS (b) = NULL;
|
||||
set_buffer_intervals (b, NULL);
|
||||
|
||||
/* Perhaps we should explicitly free the interval tree here... */
|
||||
|
|
@ -2624,21 +2618,20 @@ results, see Info node `(elisp)Swapping Text'. */)
|
|||
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;
|
||||
MARKERS_DO_ALL (it, BUF_ALL_MARKERS (current_buffer))
|
||||
if (it.m->buffer == other_buffer)
|
||||
it.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;
|
||||
eassert (!it.m->buffer);
|
||||
MARKERS_DO_ALL (it, BUF_ALL_MARKERS (other_buffer))
|
||||
if (it.m->buffer == current_buffer)
|
||||
it.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);
|
||||
eassert (!it.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
|
||||
|
|
@ -2701,7 +2694,6 @@ If the multibyte flag was really changed, undo information of the
|
|||
current buffer is cleared. */)
|
||||
(Lisp_Object flag)
|
||||
{
|
||||
struct Lisp_Marker *tail, *markers;
|
||||
Lisp_Object btail, other;
|
||||
ptrdiff_t begv, zv;
|
||||
bool narrowed = (BEG != BEGV || Z != ZV);
|
||||
|
|
@ -2719,9 +2711,6 @@ current buffer is cleared. */)
|
|||
instead. */
|
||||
bset_undo_list (current_buffer, Qt);
|
||||
|
||||
/* If the cached position is for this buffer, clear it out. */
|
||||
clear_charpos_cache (current_buffer);
|
||||
|
||||
if (NILP (flag))
|
||||
begv = BEGV_BYTE, zv = ZV_BYTE;
|
||||
else
|
||||
|
|
@ -2750,9 +2739,8 @@ current buffer is cleared. */)
|
|||
GPT = GPT_BYTE;
|
||||
TEMP_SET_PT_BOTH (PT_BYTE, PT_BYTE);
|
||||
|
||||
|
||||
for (tail = BUF_MARKERS (current_buffer); tail; tail = tail->next)
|
||||
tail->charpos = tail->bytepos;
|
||||
MARKERS_DO_ALL (it, BUF_ALL_MARKERS (current_buffer))
|
||||
it.m->charpos = it.m->bytepos;
|
||||
|
||||
/* Convert multibyte form of 8-bit characters to unibyte. */
|
||||
pos = BEG;
|
||||
|
|
@ -2902,25 +2890,24 @@ current buffer is cleared. */)
|
|||
TEMP_SET_PT_BOTH (position, byte);
|
||||
}
|
||||
|
||||
tail = markers = BUF_MARKERS (current_buffer);
|
||||
|
||||
struct Lisp_Markers *t = BUF_ALL_MARKERS (current_buffer);
|
||||
/* This prevents BYTE_TO_CHAR (that is, buf_bytepos_to_charpos) from
|
||||
getting confused by the markers that have not yet been updated.
|
||||
It is also a signal that it should never create a marker. */
|
||||
BUF_MARKERS (current_buffer) = NULL;
|
||||
BUF_ALL_MARKERS (current_buffer) = NULL;
|
||||
|
||||
for (; tail; tail = tail->next)
|
||||
MARKERS_DO_ALL (it, t)
|
||||
{
|
||||
tail->bytepos = advance_to_char_boundary (tail->bytepos);
|
||||
tail->charpos = BYTE_TO_CHAR (tail->bytepos);
|
||||
it.m->bytepos = advance_to_char_boundary (it.m->bytepos);
|
||||
it.m->charpos = BYTE_TO_CHAR (it.m->bytepos);
|
||||
}
|
||||
|
||||
/* Make sure no markers were put on the chain
|
||||
while the chain value was incorrect. */
|
||||
if (BUF_MARKERS (current_buffer))
|
||||
if (BUF_ALL_MARKERS (current_buffer))
|
||||
emacs_abort ();
|
||||
|
||||
BUF_MARKERS (current_buffer) = markers;
|
||||
BUF_ALL_MARKERS (current_buffer) = t;
|
||||
|
||||
/* Do this last, so it can calculate the new correspondences
|
||||
between chars and bytes. */
|
||||
|
|
|
|||
15
src/buffer.h
15
src/buffer.h
|
|
@ -25,6 +25,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
|
||||
#include "character.h"
|
||||
#include "lisp.h"
|
||||
#include "marker.h"
|
||||
#include "itree.h"
|
||||
|
||||
INLINE_HEADER_BEGIN
|
||||
|
|
@ -138,8 +139,8 @@ enum { BEG = 1, BEG_BYTE = BEG };
|
|||
/* Compaction count. */
|
||||
#define BUF_COMPACT(buf) ((buf)->text->compact)
|
||||
|
||||
/* Marker chain of buffer. */
|
||||
#define BUF_MARKERS(buf) ((buf)->text->markers)
|
||||
/* Table of all markers of buffer. */
|
||||
#define BUF_ALL_MARKERS(buf) ((buf)->text->all_markers)
|
||||
|
||||
#define BUF_UNCHANGED_MODIFIED(buf) \
|
||||
((buf)->text->unchanged_modified)
|
||||
|
|
@ -271,14 +272,8 @@ struct buffer_text
|
|||
/* Properties of this buffer's text. */
|
||||
INTERVAL intervals;
|
||||
|
||||
/* The markers that refer to this buffer.
|
||||
This is actually a single marker ---
|
||||
successive elements in its marker `chain'
|
||||
are the other markers referring to this buffer.
|
||||
This is a singly linked unordered list, which means that it's
|
||||
very cheap to add a marker to the list and it's also very cheap
|
||||
to move a marker within a buffer. */
|
||||
struct Lisp_Marker *markers;
|
||||
/* The table of all the markers that refer to this buffer. */
|
||||
struct Lisp_Markers *all_markers;
|
||||
|
||||
/* Usually false. Temporarily true in decode_coding_gap to
|
||||
prevent Fgarbage_collect from shrinking the gap and losing
|
||||
|
|
|
|||
61
src/coding.c
61
src/coding.c
|
|
@ -290,6 +290,7 @@ encode_coding_XXX (struct coding_system *coding)
|
|||
#endif /* HAVE_WCHAR_H */
|
||||
|
||||
#include "lisp.h"
|
||||
#include "marker.h"
|
||||
#include "character.h"
|
||||
#include "buffer.h"
|
||||
#include "charset.h"
|
||||
|
|
@ -8114,13 +8115,11 @@ decode_coding_object (struct coding_system *coding,
|
|||
move_gap_both (from, from_byte);
|
||||
if (BASE_EQ (src_object, dst_object))
|
||||
{
|
||||
struct Lisp_Marker *tail;
|
||||
|
||||
for (tail = BUF_MARKERS (current_buffer); tail; tail = tail->next)
|
||||
MARKERS_DO_ALL (it, BUF_ALL_MARKERS (current_buffer))
|
||||
{
|
||||
tail->need_adjustment
|
||||
= tail->charpos == (tail->insertion_type ? from : to);
|
||||
need_marker_adjustment |= tail->need_adjustment;
|
||||
it.m->need_adjustment
|
||||
= it.m->charpos == (it.m->insertion_type ? from : to);
|
||||
need_marker_adjustment |= it.m->need_adjustment;
|
||||
}
|
||||
saved_pt = PT, saved_pt_byte = PT_BYTE;
|
||||
TEMP_SET_PT_BOTH (from, from_byte);
|
||||
|
|
@ -8246,23 +8245,21 @@ decode_coding_object (struct coding_system *coding,
|
|||
|
||||
if (need_marker_adjustment)
|
||||
{
|
||||
struct Lisp_Marker *tail;
|
||||
|
||||
for (tail = BUF_MARKERS (current_buffer); tail; tail = tail->next)
|
||||
if (tail->need_adjustment)
|
||||
MARKERS_DO_ALL (it, BUF_ALL_MARKERS (current_buffer))
|
||||
if (it.m->need_adjustment)
|
||||
{
|
||||
tail->need_adjustment = 0;
|
||||
if (tail->insertion_type)
|
||||
it.m->need_adjustment = 0;
|
||||
if (it.m->insertion_type)
|
||||
{
|
||||
tail->bytepos = from_byte;
|
||||
tail->charpos = from;
|
||||
it.m->bytepos = from_byte;
|
||||
it.m->charpos = from;
|
||||
}
|
||||
else
|
||||
{
|
||||
tail->bytepos = from_byte + coding->produced;
|
||||
tail->charpos
|
||||
it.m->bytepos = from_byte + coding->produced;
|
||||
it.m->charpos
|
||||
= (NILP (BVAR (current_buffer, enable_multibyte_characters))
|
||||
? tail->bytepos : from + coding->produced_char);
|
||||
? it.m->bytepos : from + coding->produced_char);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8334,15 +8331,13 @@ encode_coding_object (struct coding_system *coding,
|
|||
bool same_buffer = false;
|
||||
if (BASE_EQ (src_object, dst_object) && BUFFERP (src_object))
|
||||
{
|
||||
struct Lisp_Marker *tail;
|
||||
|
||||
same_buffer = true;
|
||||
|
||||
for (tail = BUF_MARKERS (XBUFFER (src_object)); tail; tail = tail->next)
|
||||
MARKERS_DO_ALL (it, BUF_ALL_MARKERS (XBUFFER (src_object)))
|
||||
{
|
||||
tail->need_adjustment
|
||||
= tail->charpos == (tail->insertion_type ? from : to);
|
||||
need_marker_adjustment |= tail->need_adjustment;
|
||||
it.m->need_adjustment
|
||||
= it.m->charpos == (it.m->insertion_type ? from : to);
|
||||
need_marker_adjustment |= it.m->need_adjustment;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -8501,23 +8496,21 @@ encode_coding_object (struct coding_system *coding,
|
|||
|
||||
if (need_marker_adjustment)
|
||||
{
|
||||
struct Lisp_Marker *tail;
|
||||
|
||||
for (tail = BUF_MARKERS (current_buffer); tail; tail = tail->next)
|
||||
if (tail->need_adjustment)
|
||||
MARKERS_DO_ALL (it, BUF_ALL_MARKERS (current_buffer))
|
||||
if (it.m->need_adjustment)
|
||||
{
|
||||
tail->need_adjustment = 0;
|
||||
if (tail->insertion_type)
|
||||
it.m->need_adjustment = 0;
|
||||
if (it.m->insertion_type)
|
||||
{
|
||||
tail->bytepos = from_byte;
|
||||
tail->charpos = from;
|
||||
it.m->bytepos = from_byte;
|
||||
it.m->charpos = from;
|
||||
}
|
||||
else
|
||||
{
|
||||
tail->bytepos = from_byte + coding->produced;
|
||||
tail->charpos
|
||||
it.m->bytepos = from_byte + coding->produced;
|
||||
it.m->charpos
|
||||
= (NILP (BVAR (current_buffer, enable_multibyte_characters))
|
||||
? tail->bytepos : from + coding->produced_char);
|
||||
? it.m->bytepos : from + coding->produced_char);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#endif
|
||||
|
||||
#include "lisp.h"
|
||||
#include "marker.h"
|
||||
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
|
|
@ -4384,7 +4385,6 @@ transpose_markers (ptrdiff_t start1, ptrdiff_t end1,
|
|||
ptrdiff_t start2_byte, ptrdiff_t end2_byte)
|
||||
{
|
||||
register ptrdiff_t amt1, amt1_byte, amt2, amt2_byte, diff, diff_byte, mpos;
|
||||
register struct Lisp_Marker *marker;
|
||||
|
||||
/* Update point as if it were a marker. */
|
||||
if (PT < start1)
|
||||
|
|
@ -4419,31 +4419,46 @@ transpose_markers (ptrdiff_t start1, ptrdiff_t end1,
|
|||
amt1_byte = (end2_byte - start2_byte) + (start2_byte - end1_byte);
|
||||
amt2_byte = (end1_byte - start1_byte) + (start2_byte - end1_byte);
|
||||
|
||||
for (marker = BUF_MARKERS (current_buffer); marker; marker = marker->next)
|
||||
/* We move markers around here in a way that affects their ordering.
|
||||
We can't do that from within the MARKERS_DO_ALL, so we use an auxiliary
|
||||
table 't' to record markers we need to reinsert later. */
|
||||
struct Lisp_Markers *t = BUF_ALL_MARKERS (current_buffer);
|
||||
struct Lisp_Markers *taux = markers_new (4);
|
||||
MARKERS_DO_ALL (it, t)
|
||||
{
|
||||
mpos = marker->bytepos;
|
||||
mpos = it.m->bytepos;
|
||||
if (mpos >= start1_byte && mpos < end2_byte)
|
||||
{
|
||||
markers_kill (it.t, it.m);
|
||||
if (mpos < end1_byte)
|
||||
mpos += amt1_byte;
|
||||
else if (mpos < start2_byte)
|
||||
mpos += diff_byte;
|
||||
else
|
||||
mpos -= amt2_byte;
|
||||
marker->bytepos = mpos;
|
||||
}
|
||||
mpos = marker->charpos;
|
||||
if (mpos >= start1 && mpos < end2)
|
||||
{
|
||||
it.m->bytepos = mpos;
|
||||
|
||||
mpos = it.m->charpos;
|
||||
eassert (mpos >= start1 && mpos < end2);
|
||||
if (mpos < end1)
|
||||
mpos += amt1;
|
||||
else if (mpos < start2)
|
||||
mpos += diff;
|
||||
else
|
||||
mpos -= amt2;
|
||||
it.m->charpos = mpos;
|
||||
|
||||
markers_add (taux, it.m);
|
||||
}
|
||||
marker->charpos = mpos;
|
||||
}
|
||||
MARKERS_DO_ALL (it, taux)
|
||||
{
|
||||
struct Lisp_Markers *tnew = markers_add (t, it.m);
|
||||
/* There should always be enough space, so it should always
|
||||
return the same table. */
|
||||
eassert (tnew == t);
|
||||
}
|
||||
free (taux);
|
||||
}
|
||||
|
||||
DEFUN ("transpose-regions", Ftranspose_regions, Stranspose_regions, 4, 5,
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#include <math.h>
|
||||
|
||||
#include "lisp.h"
|
||||
#include "marker.h"
|
||||
#include "bignum.h"
|
||||
#include "character.h"
|
||||
#include "coding.h"
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#include <config.h>
|
||||
|
||||
#include "lisp.h"
|
||||
#include "marker.h"
|
||||
#include "character.h"
|
||||
#include "buffer.h"
|
||||
#include "category.h"
|
||||
|
|
|
|||
108
src/insdel.c
108
src/insdel.c
|
|
@ -23,6 +23,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#include <intprops.h>
|
||||
|
||||
#include "lisp.h"
|
||||
#include "marker.h"
|
||||
#include "composite.h"
|
||||
#include "intervals.h"
|
||||
#include "character.h"
|
||||
|
|
@ -228,11 +229,12 @@ adjust_suspend_auto_hscroll (ptrdiff_t from, ptrdiff_t to)
|
|||
if (WINDOWP (selected_window))
|
||||
{
|
||||
struct window *w = XWINDOW (selected_window);
|
||||
ptrdiff_t old_point;
|
||||
|
||||
if (BUFFERP (w->contents)
|
||||
&& XBUFFER (w->contents) == current_buffer
|
||||
&& XMARKER (w->old_pointm)->charpos >= from
|
||||
&& XMARKER (w->old_pointm)->charpos <= to)
|
||||
&& (old_point = marker_position (w->old_pointm),
|
||||
from <= old_point && old_point <= to))
|
||||
w->suspend_auto_hscroll = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -249,29 +251,9 @@ void
|
|||
adjust_markers_for_delete (ptrdiff_t from, ptrdiff_t from_byte,
|
||||
ptrdiff_t to, ptrdiff_t to_byte)
|
||||
{
|
||||
struct Lisp_Marker *m;
|
||||
ptrdiff_t charpos;
|
||||
|
||||
adjust_suspend_auto_hscroll (from, to);
|
||||
for (m = BUF_MARKERS (current_buffer); m; m = m->next)
|
||||
{
|
||||
charpos = m->charpos;
|
||||
eassert (charpos <= Z);
|
||||
|
||||
/* If the marker is after the deletion,
|
||||
relocate by number of chars / bytes deleted. */
|
||||
if (charpos > to)
|
||||
{
|
||||
m->charpos -= to - from;
|
||||
m->bytepos -= to_byte - from_byte;
|
||||
}
|
||||
/* Here's the case where a marker is inside text being deleted. */
|
||||
else if (charpos > from)
|
||||
{
|
||||
m->charpos = from;
|
||||
m->bytepos = from_byte;
|
||||
}
|
||||
}
|
||||
markers_adjust_for_delete (BUF_ALL_MARKERS (current_buffer),
|
||||
from, from_byte, to, to_byte);
|
||||
adjust_overlays_for_delete (from, to - from);
|
||||
}
|
||||
|
||||
|
|
@ -288,30 +270,9 @@ void
|
|||
adjust_markers_for_insert (ptrdiff_t from, ptrdiff_t from_byte,
|
||||
ptrdiff_t to, ptrdiff_t to_byte, bool before_markers)
|
||||
{
|
||||
struct Lisp_Marker *m;
|
||||
ptrdiff_t nchars = to - from;
|
||||
ptrdiff_t nbytes = to_byte - from_byte;
|
||||
|
||||
adjust_suspend_auto_hscroll (from, to);
|
||||
for (m = BUF_MARKERS (current_buffer); m; m = m->next)
|
||||
{
|
||||
eassert (m->bytepos >= m->charpos
|
||||
&& m->bytepos - m->charpos <= Z_BYTE - Z);
|
||||
|
||||
if (m->bytepos == from_byte)
|
||||
{
|
||||
if (m->insertion_type || before_markers)
|
||||
{
|
||||
m->bytepos = to_byte;
|
||||
m->charpos = to;
|
||||
}
|
||||
}
|
||||
else if (m->bytepos > from_byte)
|
||||
{
|
||||
m->bytepos += nbytes;
|
||||
m->charpos += nchars;
|
||||
}
|
||||
}
|
||||
markers_adjust_for_insert (BUF_ALL_MARKERS (current_buffer),
|
||||
from, from_byte, to, to_byte, before_markers);
|
||||
adjust_overlays_for_insert (from, to - from, before_markers);
|
||||
}
|
||||
|
||||
|
|
@ -343,31 +304,11 @@ adjust_markers_for_replace (ptrdiff_t from, ptrdiff_t from_byte,
|
|||
ptrdiff_t old_chars, ptrdiff_t old_bytes,
|
||||
ptrdiff_t new_chars, ptrdiff_t new_bytes)
|
||||
{
|
||||
register struct Lisp_Marker *m;
|
||||
ptrdiff_t prev_to_byte = from_byte + old_bytes;
|
||||
ptrdiff_t diff_chars = new_chars - old_chars;
|
||||
ptrdiff_t diff_bytes = new_bytes - old_bytes;
|
||||
|
||||
adjust_suspend_auto_hscroll (from, from + old_chars);
|
||||
|
||||
/* FIXME: When OLD_CHARS is 0, this "replacement" is really just an
|
||||
insertion, but the behavior we provide here in that case is that of
|
||||
`insert-before-markers` rather than that of `insert`.
|
||||
Maybe not a bug, but not a feature either. */
|
||||
for (m = BUF_MARKERS (current_buffer); m; m = m->next)
|
||||
{
|
||||
if (m->bytepos >= prev_to_byte)
|
||||
{
|
||||
m->charpos += diff_chars;
|
||||
m->bytepos += diff_bytes;
|
||||
}
|
||||
else if (m->bytepos > from_byte)
|
||||
{
|
||||
m->charpos = from;
|
||||
m->bytepos = from_byte;
|
||||
}
|
||||
}
|
||||
|
||||
markers_adjust_for_replace (BUF_ALL_MARKERS (current_buffer),
|
||||
from, from_byte, old_chars, old_bytes,
|
||||
new_chars, new_bytes);
|
||||
check_markers ();
|
||||
|
||||
adjust_overlays_for_insert (from + old_chars, new_chars, true);
|
||||
|
|
@ -415,36 +356,33 @@ adjust_markers_bytepos (ptrdiff_t from, ptrdiff_t from_byte,
|
|||
{
|
||||
/* Make sure each affected marker's bytepos is equal to
|
||||
its charpos. */
|
||||
for (m = BUF_MARKERS (current_buffer); m; m = m->next)
|
||||
MARKERS_DO_ALL (it, BUF_ALL_MARKERS (current_buffer))
|
||||
{
|
||||
if (m->bytepos > from_byte
|
||||
&& (to_z || m->bytepos <= to_byte))
|
||||
m->bytepos = m->charpos;
|
||||
if (it.m->bytepos > from_byte
|
||||
&& (to_z || it.m->bytepos <= to_byte))
|
||||
it.m->bytepos = it.m->charpos;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (m = BUF_MARKERS (current_buffer); m; m = m->next)
|
||||
MARKERS_DO_ALL (it, BUF_ALL_MARKERS (current_buffer))
|
||||
{
|
||||
/* Recompute each affected marker's bytepos. */
|
||||
if (m->bytepos > from_byte
|
||||
&& (to_z || m->bytepos <= to_byte))
|
||||
if (it.m->bytepos > from_byte
|
||||
&& (to_z || it.m->bytepos <= to_byte))
|
||||
{
|
||||
if (m->charpos < beg
|
||||
&& beg - m->charpos > m->charpos - from)
|
||||
if (it.m->charpos < beg
|
||||
&& beg - it.m->charpos > it.m->charpos - from)
|
||||
{
|
||||
beg = from;
|
||||
begbyte = from_byte;
|
||||
}
|
||||
m->bytepos = count_bytes (beg, begbyte, m->charpos);
|
||||
beg = m->charpos;
|
||||
begbyte = m->bytepos;
|
||||
it.m->bytepos = count_bytes (beg, begbyte, it.m->charpos);
|
||||
beg = it.m->charpos;
|
||||
begbyte = it.m->bytepos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure cached charpos/bytepos is invalid. */
|
||||
clear_charpos_cache (current_buffer);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
|
||||
#include <intprops.h>
|
||||
#include "lisp.h"
|
||||
#include "marker.h"
|
||||
#include "intervals.h"
|
||||
#include "buffer.h"
|
||||
#include "puresize.h"
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#include <sys/stat.h>
|
||||
|
||||
#include "lisp.h"
|
||||
#include "marker.h"
|
||||
#include "coding.h"
|
||||
#include "termchar.h"
|
||||
#include "termopts.h"
|
||||
|
|
|
|||
60
src/lisp.h
60
src/lisp.h
|
|
@ -2828,50 +2828,6 @@ knuth_hash (hash_hash_t hash, unsigned bits)
|
|||
return wide_product >> (32 - bits);
|
||||
}
|
||||
|
||||
|
||||
struct Lisp_Marker
|
||||
{
|
||||
union vectorlike_header header;
|
||||
|
||||
/* This is the buffer that the marker points into, or 0 if it points nowhere.
|
||||
Note: a chain of markers can contain markers pointing into different
|
||||
buffers (the chain is per buffer_text rather than per buffer, so it's
|
||||
shared between indirect buffers). */
|
||||
/* This is used for (other than NULL-checking):
|
||||
- Fmarker_buffer
|
||||
- Fset_marker: check eq(oldbuf, newbuf) to avoid unchain+rechain.
|
||||
- unchain_marker: to find the list from which to unchain.
|
||||
- Fkill_buffer: to only unchain the markers of current indirect buffer.
|
||||
*/
|
||||
struct buffer *buffer;
|
||||
|
||||
/* This flag is temporarily used in the functions
|
||||
decode/encode_coding_object to record that the marker position
|
||||
must be adjusted after the conversion. */
|
||||
bool_bf need_adjustment : 1;
|
||||
/* True means normal insertion at the marker's position
|
||||
leaves the marker after the inserted text. */
|
||||
bool_bf insertion_type : 1;
|
||||
|
||||
/* The remaining fields are meaningless in a marker that
|
||||
does not point anywhere. */
|
||||
|
||||
/* For markers that point somewhere,
|
||||
this is used to chain of all the markers in a given buffer.
|
||||
The chain does not preserve markers from garbage collection;
|
||||
instead, markers are removed from the chain when freed by GC. */
|
||||
/* We could remove it and use an array in buffer_text instead.
|
||||
That would also allow us to preserve it ordered. */
|
||||
struct Lisp_Marker *next;
|
||||
/* This is the char position where the marker points. */
|
||||
ptrdiff_t charpos;
|
||||
/* This is the byte position.
|
||||
It's mostly used as a charpos<->bytepos cache (i.e. it's not directly
|
||||
used to implement the functionality of markers, but rather to (ab)use
|
||||
markers as a cache for char<->byte mappings). */
|
||||
ptrdiff_t bytepos;
|
||||
} GCALIGNED_STRUCT;
|
||||
|
||||
struct Lisp_Overlay
|
||||
/* An overlay's real data content is:
|
||||
- plist
|
||||
|
|
@ -5000,22 +4956,6 @@ extern void init_buffer_once (void);
|
|||
extern void init_buffer (void);
|
||||
extern void syms_of_buffer (void);
|
||||
|
||||
/* Defined in marker.c. */
|
||||
|
||||
extern ptrdiff_t marker_position (Lisp_Object);
|
||||
extern ptrdiff_t marker_byte_position (Lisp_Object);
|
||||
extern void clear_charpos_cache (struct buffer *);
|
||||
extern ptrdiff_t buf_charpos_to_bytepos (struct buffer *, ptrdiff_t);
|
||||
extern ptrdiff_t buf_bytepos_to_charpos (struct buffer *, ptrdiff_t);
|
||||
extern void detach_marker (Lisp_Object);
|
||||
extern void unchain_marker (struct Lisp_Marker *);
|
||||
extern Lisp_Object set_marker_restricted (Lisp_Object, Lisp_Object, Lisp_Object);
|
||||
extern Lisp_Object set_marker_both (Lisp_Object, Lisp_Object, ptrdiff_t, ptrdiff_t);
|
||||
extern Lisp_Object set_marker_restricted_both (Lisp_Object, Lisp_Object,
|
||||
ptrdiff_t, ptrdiff_t);
|
||||
extern Lisp_Object build_marker (struct buffer *, ptrdiff_t, ptrdiff_t);
|
||||
extern void syms_of_marker (void);
|
||||
|
||||
/* Defined in fileio.c. */
|
||||
|
||||
extern Lisp_Object file_name_directory (Lisp_Object);
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#include <math.h>
|
||||
#include <stat-time.h>
|
||||
#include "lisp.h"
|
||||
#include "marker.h"
|
||||
#include "dispextern.h"
|
||||
#include "intervals.h"
|
||||
#include "character.h"
|
||||
|
|
|
|||
557
src/marker.c
557
src/marker.c
|
|
@ -26,9 +26,52 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#endif
|
||||
|
||||
#include "lisp.h"
|
||||
#include "marker.h"
|
||||
#include "character.h"
|
||||
#include "buffer.h"
|
||||
#include "window.h"
|
||||
#include "stdlib.h"
|
||||
|
||||
#ifdef ABSTRACT_LISP_MARKER
|
||||
struct Lisp_Marker
|
||||
{
|
||||
union vectorlike_header header;
|
||||
|
||||
/* This is the buffer that the marker points into, or 0 if it points nowhere.
|
||||
Note: a chain of markers can contain markers pointing into different
|
||||
buffers (the chain is per buffer_text rather than per buffer, so it's
|
||||
shared between indirect buffers). */
|
||||
/* This is used for (other than NULL-checking):
|
||||
- Fmarker_buffer
|
||||
- Fset_marker: check eq(oldbuf, newbuf) to avoid unchain+rechain.
|
||||
- unchain_marker: to find the list from which to unchain.
|
||||
- Fkill_buffer: to only unchain the markers of current indirect buffer.
|
||||
*/
|
||||
struct buffer *buffer;
|
||||
|
||||
/* This flag is temporarily used in the functions
|
||||
decode/encode_coding_object to record that the marker position
|
||||
must be adjusted after the conversion. */
|
||||
bool_bf need_adjustment : 1;
|
||||
/* True means normal insertion at the marker's position
|
||||
leaves the marker after the inserted text. */
|
||||
bool_bf insertion_type : 1;
|
||||
/* True means that this is a chars<->bytes conversion cache entry
|
||||
rather than a true marker. */
|
||||
bool_bf cache : 1;
|
||||
|
||||
/* The remaining fields are meaningless in a marker that
|
||||
does not point anywhere. */
|
||||
|
||||
/* This is the char position where the marker points. */
|
||||
ptrdiff_t charpos;
|
||||
/* This is the byte position.
|
||||
It's mostly used as a charpos<->bytepos cache (i.e. it's not directly
|
||||
used to implement the functionality of markers, but rather to (ab)use
|
||||
markers as a cache for char<->byte mappings). */
|
||||
ptrdiff_t bytepos;
|
||||
} GCALIGNED_STRUCT;
|
||||
#endif
|
||||
|
||||
/* Record one cached position found recently by
|
||||
buf_charpos_to_bytepos or buf_bytepos_to_charpos. */
|
||||
|
|
@ -38,6 +81,306 @@ static ptrdiff_t cached_bytepos;
|
|||
static struct buffer *cached_buffer;
|
||||
static modiff_count cached_modiff;
|
||||
|
||||
/*****************************************************************/
|
||||
/* Set of markers represented as a sorted array-with-gap (AWG). */
|
||||
/*****************************************************************/
|
||||
|
||||
typedef unsigned int m_index_t;
|
||||
|
||||
struct Lisp_Markers
|
||||
{
|
||||
m_index_t size;
|
||||
m_index_t gap_beg;
|
||||
m_index_t gap_end;
|
||||
struct Lisp_Marker *markers[FLEXIBLE_ARRAY_MEMBER];
|
||||
};
|
||||
|
||||
static void
|
||||
markers_sanity_check (struct Lisp_Markers *t)
|
||||
{
|
||||
eassert (t->markers);
|
||||
eassert (t->size > 0);
|
||||
eassert (t->gap_beg >= 0);
|
||||
eassert (t->gap_beg <= t->gap_end);
|
||||
eassert (t->gap_end <= t->size);
|
||||
|
||||
m_index_t i;
|
||||
ptrdiff_t lastpos = BEG;
|
||||
for (i = 0; i < t->size; i++)
|
||||
{
|
||||
if (i == t->gap_beg)
|
||||
{
|
||||
for (; i < t->gap_end; i++)
|
||||
eassert (t->markers[i] == NULL);
|
||||
if (i == t->size)
|
||||
break;
|
||||
}
|
||||
eassert (t->markers[i]->buffer);
|
||||
/* eassert (BUF_ALL_MARKERS (t->markers[i]->buffer) == t); */
|
||||
eassert (t->markers[i]->charpos >= lastpos);
|
||||
lastpos = t->markers[i]->charpos;
|
||||
}
|
||||
}
|
||||
|
||||
#define DEFINE_SEARCH_FUN(funname, thepos) \
|
||||
static m_index_t \
|
||||
funname (struct Lisp_Markers *t, ptrdiff_t thepos) \
|
||||
{ \
|
||||
m_index_t bot, top; \
|
||||
markers_sanity_check (t); \
|
||||
/* See whether to search before or after the gap. */ \
|
||||
if (t->gap_beg >= 1 && t->markers[t->gap_beg - 1]->thepos >= thepos) \
|
||||
(bot = 0, top = t->gap_beg); \
|
||||
else \
|
||||
(bot = t->gap_end, top = t->size); \
|
||||
\
|
||||
/* Binary search. */ \
|
||||
while (bot < top) \
|
||||
{ \
|
||||
m_index_t mid = bot + ((top - bot) / 2); \
|
||||
eassert (mid < top); \
|
||||
if (t->markers[mid]->thepos >= thepos) \
|
||||
top = mid; \
|
||||
else \
|
||||
bot = mid + 1; \
|
||||
} \
|
||||
eassert (bot == top); \
|
||||
eassert (bot == t->size || t->markers[bot]->thepos >= thepos); \
|
||||
eassert ((bot == t->gap_end ? t->gap_beg : bot) == 0 \
|
||||
|| t->markers[(bot == t->gap_end ? t->gap_beg : bot)-1]->thepos \
|
||||
< thepos); \
|
||||
return bot; \
|
||||
}
|
||||
|
||||
/* Return the best approximation of the index in the AWG
|
||||
corresponding to a given charpos or bytepos. */
|
||||
DEFINE_SEARCH_FUN (markers_search_charpos, charpos);
|
||||
DEFINE_SEARCH_FUN (markers_search_bytepos, bytepos);
|
||||
|
||||
/* Return the index in the AWG where the marker M is found.
|
||||
This function presumes that M is indeed in the AWG. */
|
||||
static m_index_t
|
||||
markers_search_marker (struct Lisp_Markers *t, struct Lisp_Marker *m)
|
||||
{
|
||||
m_index_t beg = markers_search_charpos (t, m->charpos);
|
||||
eassert (t->markers[beg]->charpos == m->charpos);
|
||||
while (t->markers[beg] != m)
|
||||
{
|
||||
beg = (beg == t->gap_beg - 1) ? t->gap_end : beg + 1;
|
||||
eassert (t->markers[beg]->charpos == m->charpos);
|
||||
}
|
||||
return beg;
|
||||
}
|
||||
|
||||
static void
|
||||
markers_move_gap (struct Lisp_Markers *t, m_index_t new_beg)
|
||||
{
|
||||
m_index_t old_beg = t->gap_beg;
|
||||
m_index_t old_end = t->gap_end;
|
||||
eassert (new_beg <= t->gap_beg || new_beg >= t->gap_end);
|
||||
if (new_beg > old_beg)
|
||||
new_beg = old_beg + (new_beg - old_end);
|
||||
if (old_beg == new_beg)
|
||||
return;
|
||||
else if (new_beg > old_beg)
|
||||
memmove (&t->markers[old_beg], &t->markers[old_end],
|
||||
(new_beg - old_beg) * sizeof (struct Lisp_Marker *));
|
||||
else
|
||||
{
|
||||
m_index_t size = old_beg - new_beg;
|
||||
memmove (&t->markers[old_end - size], &t->markers[new_beg],
|
||||
size * sizeof (struct Lisp_Marker *));
|
||||
}
|
||||
t->gap_beg = new_beg;
|
||||
t->gap_end = new_beg + (old_end - old_beg);
|
||||
/* FIME: Get rid of it? */
|
||||
memset (&t->markers[new_beg], 0,
|
||||
(old_end - old_beg) * sizeof (struct Lisp_Marker *));
|
||||
markers_sanity_check (t);
|
||||
}
|
||||
|
||||
static void
|
||||
markers_move_gap_to_charpos (struct Lisp_Markers *t, ptrdiff_t charpos)
|
||||
{
|
||||
m_index_t i = markers_search_charpos (t, charpos);
|
||||
markers_move_gap (t, i);
|
||||
eassert (t->gap_beg == 0
|
||||
|| t->markers[t->gap_beg - 1]->charpos < charpos);
|
||||
eassert (t->gap_end == t->size
|
||||
|| t->markers[t->gap_end]->charpos >= charpos);
|
||||
}
|
||||
|
||||
void
|
||||
markers_kill (struct Lisp_Markers *t, struct Lisp_Marker *m)
|
||||
{
|
||||
m_index_t i = markers_search_marker (t, m);
|
||||
if (i < t->gap_beg)
|
||||
{
|
||||
markers_move_gap (t, i + 1);
|
||||
eassert (t->gap_beg == i + 1);
|
||||
t->gap_beg = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
markers_move_gap (t, i);
|
||||
eassert (t->gap_end == i);
|
||||
t->gap_end = i + 1;
|
||||
}
|
||||
eassert (t->markers[i] == m);
|
||||
t->markers[i] = NULL;
|
||||
markers_sanity_check (t);
|
||||
}
|
||||
|
||||
static struct Lisp_Markers *
|
||||
markers_grow (struct Lisp_Markers *t)
|
||||
{
|
||||
eassert (t->gap_beg == t->gap_end);
|
||||
m_index_t oldsize = t->size;
|
||||
m_index_t increment = max (2, oldsize / 2);
|
||||
m_index_t newsize = oldsize + increment;
|
||||
if (newsize < oldsize) /* Overflow! */
|
||||
/* This can happen only if you have ~4G markers, in which case the
|
||||
algorithmic complexity of the code in this file should make Emacs
|
||||
unusable anyway. */
|
||||
error ("Table of markers full!");
|
||||
struct Lisp_Marker **oldmarkers = t->markers;
|
||||
struct Lisp_Markers *newt
|
||||
= xmalloc (sizeof (struct Lisp_Markers)
|
||||
+ newsize * sizeof (struct Lisp_Marker *));
|
||||
struct Lisp_Marker **newmarkers = newt->markers;
|
||||
memcpy (newmarkers, oldmarkers, oldsize * sizeof (struct Lisp_Marker *));
|
||||
memset (&newmarkers[oldsize], 0, increment * sizeof (struct Lisp_Marker *));
|
||||
xfree (t);
|
||||
newt->size = newsize;
|
||||
newt->gap_beg = oldsize;
|
||||
newt->gap_end = newsize;
|
||||
markers_sanity_check (newt);
|
||||
return newt;
|
||||
}
|
||||
|
||||
struct Lisp_Markers *
|
||||
markers_add (struct Lisp_Markers *t, struct Lisp_Marker *m)
|
||||
{
|
||||
if (t->gap_beg == t->gap_end)
|
||||
t = markers_grow (t);
|
||||
markers_move_gap_to_charpos (t, m->charpos);
|
||||
t->markers[t->gap_beg++] = m;
|
||||
markers_sanity_check (t);
|
||||
return t;
|
||||
}
|
||||
|
||||
void
|
||||
markers_adjust_for_insert (struct Lisp_Markers *t,
|
||||
ptrdiff_t from, ptrdiff_t from_byte,
|
||||
ptrdiff_t to, ptrdiff_t to_byte,
|
||||
bool before_markers)
|
||||
{
|
||||
markers_move_gap_to_charpos (t, from);
|
||||
m_index_t i = t->gap_end;
|
||||
m_index_t size = t->size;
|
||||
ptrdiff_t charoffset = to - from;
|
||||
ptrdiff_t byteoffset = to_byte - from_byte;
|
||||
/* FIXME: This can mess up ordering because we move some but not
|
||||
all markers at 'from'. */
|
||||
for (; i < size && t->markers[i]->charpos == from; i++)
|
||||
if (t->markers[i]->insertion_type)
|
||||
{
|
||||
t->markers[i]->charpos += charoffset;
|
||||
t->markers[i]->bytepos += byteoffset;
|
||||
}
|
||||
for (; i < size; i++)
|
||||
{
|
||||
t->markers[i]->charpos += charoffset;
|
||||
t->markers[i]->bytepos += byteoffset;
|
||||
}
|
||||
markers_sanity_check (t);
|
||||
}
|
||||
|
||||
void
|
||||
markers_adjust_for_replace (struct Lisp_Markers *t,
|
||||
ptrdiff_t from, ptrdiff_t from_byte,
|
||||
ptrdiff_t old_chars, ptrdiff_t old_bytes,
|
||||
ptrdiff_t new_chars, ptrdiff_t new_bytes)
|
||||
{
|
||||
eassert (old_chars > 0);
|
||||
markers_move_gap_to_charpos (t, from);
|
||||
m_index_t i = t->gap_end;
|
||||
m_index_t size = t->size;
|
||||
ptrdiff_t prev_to = from + old_chars;
|
||||
for (; i < size && t->markers[i]->charpos < prev_to; i++)
|
||||
{
|
||||
t->markers[i]->charpos = from;
|
||||
t->markers[i]->bytepos = from_byte;
|
||||
}
|
||||
ptrdiff_t charoffset = new_chars - old_chars;
|
||||
ptrdiff_t byteoffset = new_bytes - old_bytes;
|
||||
for (; i < size; i++)
|
||||
{
|
||||
t->markers[i]->charpos += charoffset;
|
||||
t->markers[i]->bytepos += byteoffset;
|
||||
}
|
||||
markers_sanity_check (t);
|
||||
}
|
||||
|
||||
void
|
||||
markers_adjust_for_delete (struct Lisp_Markers *t,
|
||||
ptrdiff_t from, ptrdiff_t from_byte,
|
||||
ptrdiff_t to, ptrdiff_t to_byte)
|
||||
{
|
||||
eassert (to > from);
|
||||
markers_adjust_for_replace (t, from, from_byte,
|
||||
to - from, to_byte - from_byte,
|
||||
0, 0);
|
||||
}
|
||||
|
||||
bool
|
||||
markers_full_p (struct Lisp_Markers *t)
|
||||
{
|
||||
return t->gap_beg == t->gap_end;
|
||||
}
|
||||
|
||||
struct Lisp_Markers *
|
||||
markers_new (unsigned int size)
|
||||
{
|
||||
struct Lisp_Markers *t = xmalloc (sizeof (struct Lisp_Markers)
|
||||
+ size * sizeof (struct Lisp_Marker *));
|
||||
t->size = size;
|
||||
t->gap_beg = 0;
|
||||
t->gap_end = size;
|
||||
memset (t->markers, 0, size * sizeof (struct Lisp_Marker *));
|
||||
return t;
|
||||
}
|
||||
|
||||
struct markers__iterator
|
||||
{
|
||||
struct Lisp_Markers *t;
|
||||
m_index_t i;
|
||||
ptrdiff_t to;
|
||||
};
|
||||
|
||||
struct markers_iterator
|
||||
markers_iterator_all (struct Lisp_Markers *t)
|
||||
{
|
||||
struct markers_iterator it = { .t = t, .i = t->gap_beg ? 0 : t->gap_end };
|
||||
it.m = it.i < t->size ? t->markers[it.i] : NULL;
|
||||
return it;
|
||||
}
|
||||
|
||||
void
|
||||
markers_iterator_next (struct markers_iterator *it)
|
||||
{
|
||||
it->i++;
|
||||
if (it->i == it->t->gap_beg)
|
||||
it->i = it->t->gap_end;
|
||||
it->m = it->i < it->t->size ? it->t->markers[it->i] : NULL;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************/
|
||||
/* Older set of markers as an unsorted linked list */
|
||||
/***********************************************************/
|
||||
|
||||
|
||||
/* Juanma Barranquero <lekktu@gmail.com> reported ~3x increased
|
||||
bootstrap time when byte_char_debug_check is enabled; so this
|
||||
is never turned on by --enable-checking configure option. */
|
||||
|
|
@ -139,6 +482,13 @@ CHECK_MARKER (Lisp_Object x)
|
|||
CHECK_TYPE (MARKERP (x), Qmarkerp, x);
|
||||
}
|
||||
|
||||
static void
|
||||
cache_bytechar (struct buffer *buf, ptrdiff_t charpos, ptrdiff_t bytepos)
|
||||
{
|
||||
Lisp_Object m = build_marker (buf, charpos, bytepos);
|
||||
XMARKER (m)->cache = true;
|
||||
}
|
||||
|
||||
/* When converting bytes from/to chars, we look through the list of
|
||||
markers to try and find a good starting point (since markers keep
|
||||
track of both bytepos and charpos at the same time).
|
||||
|
|
@ -159,14 +509,12 @@ CHECK_MARKER (Lisp_Object x)
|
|||
The asymptotic behavior is still poor, tho, so in largish buffers with many
|
||||
overlays (e.g. 300KB and 30K overlays), it can still be a bottleneck. */
|
||||
#define BYTECHAR_DISTANCE_INITIAL 50
|
||||
#define BYTECHAR_DISTANCE_INCREMENT 50
|
||||
|
||||
/* Return the byte position corresponding to CHARPOS in B. */
|
||||
|
||||
ptrdiff_t
|
||||
buf_charpos_to_bytepos (struct buffer *b, ptrdiff_t charpos)
|
||||
{
|
||||
struct Lisp_Marker *tail;
|
||||
ptrdiff_t best_above, best_above_byte;
|
||||
ptrdiff_t best_below, best_below_byte;
|
||||
ptrdiff_t distance = BYTECHAR_DISTANCE_INITIAL;
|
||||
|
|
@ -202,16 +550,24 @@ buf_charpos_to_bytepos (struct buffer *b, ptrdiff_t charpos)
|
|||
if (b == cached_buffer && BUF_MODIFF (b) == cached_modiff)
|
||||
CONSIDER (cached_charpos, cached_bytepos);
|
||||
|
||||
for (tail = BUF_MARKERS (b);
|
||||
/* If we are down to a range of DISTANCE chars,
|
||||
don't bother checking any other markers;
|
||||
scan the intervening chars directly now. */
|
||||
tail && !(best_above - charpos < distance
|
||||
|| charpos - best_below < distance);
|
||||
tail = tail->next,
|
||||
distance += BYTECHAR_DISTANCE_INCREMENT)
|
||||
CONSIDER (tail->charpos, tail->bytepos);
|
||||
|
||||
if (!(best_above - charpos < distance
|
||||
|| charpos - best_below < distance))
|
||||
{
|
||||
struct Lisp_Markers *t = BUF_ALL_MARKERS (b);
|
||||
m_index_t i = markers_search_charpos (t, charpos);
|
||||
if (i < t->size)
|
||||
{
|
||||
struct Lisp_Marker *m = t->markers[i];
|
||||
CONSIDER (m->charpos, m->bytepos);
|
||||
}
|
||||
if (i == t->gap_end)
|
||||
i = t->gap_beg;
|
||||
if (i > 0)
|
||||
{
|
||||
struct Lisp_Marker *m = t->markers[i - 1];
|
||||
CONSIDER (m->charpos, m->bytepos);
|
||||
}
|
||||
}
|
||||
/* We get here if we did not exactly hit one of the known places.
|
||||
We have one known above and one known below.
|
||||
Scan, counting characters, from whichever one is closer. */
|
||||
|
|
@ -231,7 +587,7 @@ buf_charpos_to_bytepos (struct buffer *b, ptrdiff_t charpos)
|
|||
cache the correspondence by creating a marker here.
|
||||
It will last until the next GC. */
|
||||
if (record)
|
||||
build_marker (b, best_below, best_below_byte);
|
||||
cache_bytechar (b, best_below, best_below_byte);
|
||||
|
||||
byte_char_debug_check (b, best_below, best_below_byte);
|
||||
|
||||
|
|
@ -240,6 +596,7 @@ buf_charpos_to_bytepos (struct buffer *b, ptrdiff_t charpos)
|
|||
cached_charpos = best_below;
|
||||
cached_bytepos = best_below_byte;
|
||||
|
||||
eassert (best_below_byte >= charpos);
|
||||
return best_below_byte;
|
||||
}
|
||||
else
|
||||
|
|
@ -256,7 +613,7 @@ buf_charpos_to_bytepos (struct buffer *b, ptrdiff_t charpos)
|
|||
cache the correspondence by creating a marker here.
|
||||
It will last until the next GC. */
|
||||
if (record)
|
||||
build_marker (b, best_above, best_above_byte);
|
||||
cache_bytechar (b, best_above, best_above_byte);
|
||||
|
||||
byte_char_debug_check (b, best_above, best_above_byte);
|
||||
|
||||
|
|
@ -265,6 +622,7 @@ buf_charpos_to_bytepos (struct buffer *b, ptrdiff_t charpos)
|
|||
cached_charpos = best_above;
|
||||
cached_bytepos = best_above_byte;
|
||||
|
||||
eassert (best_above_byte >= charpos);
|
||||
return best_above_byte;
|
||||
}
|
||||
}
|
||||
|
|
@ -319,7 +677,6 @@ buf_charpos_to_bytepos (struct buffer *b, ptrdiff_t charpos)
|
|||
ptrdiff_t
|
||||
buf_bytepos_to_charpos (struct buffer *b, ptrdiff_t bytepos)
|
||||
{
|
||||
struct Lisp_Marker *tail;
|
||||
ptrdiff_t best_above, best_above_byte;
|
||||
ptrdiff_t best_below, best_below_byte;
|
||||
ptrdiff_t distance = BYTECHAR_DISTANCE_INITIAL;
|
||||
|
|
@ -350,15 +707,24 @@ buf_bytepos_to_charpos (struct buffer *b, ptrdiff_t bytepos)
|
|||
if (b == cached_buffer && BUF_MODIFF (b) == cached_modiff)
|
||||
CONSIDER (cached_bytepos, cached_charpos);
|
||||
|
||||
for (tail = BUF_MARKERS (b);
|
||||
/* If we are down to a range of DISTANCE bytes,
|
||||
don't bother checking any other markers;
|
||||
scan the intervening chars directly now. */
|
||||
tail && !(best_above_byte - bytepos < distance
|
||||
|| bytepos - best_below_byte < distance);
|
||||
tail = tail->next,
|
||||
distance += BYTECHAR_DISTANCE_INCREMENT)
|
||||
CONSIDER (tail->bytepos, tail->charpos);
|
||||
if (!(best_above_byte - bytepos < distance
|
||||
|| bytepos - best_below_byte < distance))
|
||||
{
|
||||
struct Lisp_Markers *t = BUF_ALL_MARKERS (b);
|
||||
m_index_t i = markers_search_bytepos (t, bytepos);
|
||||
if (i < t->size)
|
||||
{
|
||||
struct Lisp_Marker *m = t->markers[i];
|
||||
CONSIDER (m->bytepos, m->charpos);
|
||||
}
|
||||
if (i == t->gap_end)
|
||||
i = t->gap_beg;
|
||||
if (i > 0)
|
||||
{
|
||||
struct Lisp_Marker *m = t->markers[i - 1];
|
||||
CONSIDER (m->bytepos, m->charpos);
|
||||
}
|
||||
}
|
||||
|
||||
/* We get here if we did not exactly hit one of the known places.
|
||||
We have one known above and one known below.
|
||||
|
|
@ -379,8 +745,8 @@ buf_bytepos_to_charpos (struct buffer *b, ptrdiff_t bytepos)
|
|||
It will last until the next GC.
|
||||
But don't do it if BUF_MARKERS is nil;
|
||||
that is a signal from Fset_buffer_multibyte. */
|
||||
if (record && BUF_MARKERS (b))
|
||||
build_marker (b, best_below, best_below_byte);
|
||||
if (record && BUF_ALL_MARKERS (b))
|
||||
cache_bytechar (b, best_below, best_below_byte);
|
||||
|
||||
byte_char_debug_check (b, best_below, best_below_byte);
|
||||
|
||||
|
|
@ -389,6 +755,7 @@ buf_bytepos_to_charpos (struct buffer *b, ptrdiff_t bytepos)
|
|||
cached_charpos = best_below;
|
||||
cached_bytepos = best_below_byte;
|
||||
|
||||
eassert (best_below <= bytepos);
|
||||
return best_below;
|
||||
}
|
||||
else
|
||||
|
|
@ -406,8 +773,8 @@ buf_bytepos_to_charpos (struct buffer *b, ptrdiff_t bytepos)
|
|||
It will last until the next GC.
|
||||
But don't do it if BUF_MARKERS is nil;
|
||||
that is a signal from Fset_buffer_multibyte. */
|
||||
if (record && BUF_MARKERS (b))
|
||||
build_marker (b, best_above, best_above_byte);
|
||||
if (record && BUF_ALL_MARKERS (b))
|
||||
cache_bytechar (b, best_above, best_above_byte);
|
||||
|
||||
byte_char_debug_check (b, best_above, best_above_byte);
|
||||
|
||||
|
|
@ -416,6 +783,7 @@ buf_bytepos_to_charpos (struct buffer *b, ptrdiff_t bytepos)
|
|||
cached_charpos = best_above;
|
||||
cached_bytepos = best_above_byte;
|
||||
|
||||
eassert (best_above <= bytepos);
|
||||
return best_above;
|
||||
}
|
||||
}
|
||||
|
|
@ -480,16 +848,14 @@ attach_marker (struct Lisp_Marker *m, struct buffer *b,
|
|||
else
|
||||
eassert (charpos <= bytepos);
|
||||
|
||||
if (m->buffer)
|
||||
markers_kill (BUF_ALL_MARKERS (m->buffer), m);
|
||||
|
||||
m->charpos = charpos;
|
||||
m->bytepos = bytepos;
|
||||
m->buffer = b;
|
||||
|
||||
if (m->buffer != b)
|
||||
{
|
||||
unchain_marker (m);
|
||||
m->buffer = b;
|
||||
m->next = BUF_MARKERS (b);
|
||||
BUF_MARKERS (b) = m;
|
||||
}
|
||||
BUF_ALL_MARKERS (b) = markers_add (BUF_ALL_MARKERS (b), m);
|
||||
}
|
||||
|
||||
/* If BUFFER is nil, return current buffer pointer. Next, check
|
||||
|
|
@ -525,55 +891,19 @@ set_marker_internal (Lisp_Object marker, Lisp_Object position,
|
|||
|
||||
/* Optimize the special case where we are copying the position of
|
||||
an existing marker, and MARKER is already in the same buffer. */
|
||||
else if (MARKERP (position) && b == XMARKER (position)->buffer
|
||||
&& b == m->buffer)
|
||||
else if (MARKERP (position) && b == XMARKER (position)->buffer)
|
||||
{
|
||||
m->bytepos = XMARKER (position)->bytepos;
|
||||
m->charpos = XMARKER (position)->charpos;
|
||||
attach_marker (m, b, XMARKER (position)->charpos,
|
||||
XMARKER (position)->bytepos);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
register ptrdiff_t charpos, bytepos;
|
||||
|
||||
/* Do not use CHECK_FIXNUM_COERCE_MARKER because we
|
||||
don't want to call buf_charpos_to_bytepos if POSITION
|
||||
is a marker and so we know the bytepos already. */
|
||||
if (FIXNUMP (position))
|
||||
{
|
||||
#if EMACS_INT_MAX > PTRDIFF_MAX
|
||||
/* A --with-wide-int build. */
|
||||
EMACS_INT cpos = XFIXNUM (position);
|
||||
if (cpos > PTRDIFF_MAX)
|
||||
cpos = PTRDIFF_MAX;
|
||||
charpos = cpos;
|
||||
bytepos = -1;
|
||||
#else
|
||||
charpos = XFIXNUM (position), bytepos = -1;
|
||||
#endif
|
||||
}
|
||||
else if (MARKERP (position))
|
||||
{
|
||||
charpos = XMARKER (position)->charpos;
|
||||
bytepos = XMARKER (position)->bytepos;
|
||||
}
|
||||
else
|
||||
wrong_type_argument (Qinteger_or_marker_p, position);
|
||||
|
||||
ptrdiff_t charpos = fix_position (position);
|
||||
charpos = clip_to_bounds
|
||||
(restricted ? BUF_BEGV (b) : BUF_BEG (b), charpos,
|
||||
restricted ? BUF_ZV (b) : BUF_Z (b));
|
||||
/* Don't believe BYTEPOS if it comes from a different buffer,
|
||||
since that buffer might have a very different correspondence
|
||||
between character and byte positions. */
|
||||
if (bytepos == -1
|
||||
|| !(MARKERP (position) && XMARKER (position)->buffer == b))
|
||||
bytepos = buf_charpos_to_bytepos (b, charpos);
|
||||
else
|
||||
bytepos = clip_to_bounds
|
||||
(restricted ? BUF_BEGV_BYTE (b) : BUF_BEG_BYTE (b),
|
||||
bytepos, restricted ? BUF_ZV_BYTE (b) : BUF_Z_BYTE (b));
|
||||
|
||||
ptrdiff_t bytepos = buf_charpos_to_bytepos (b, charpos);
|
||||
attach_marker (m, b, charpos, bytepos);
|
||||
}
|
||||
|
||||
|
|
@ -674,6 +1004,7 @@ set_marker_restricted_both (Lisp_Object marker, Lisp_Object buffer,
|
|||
void
|
||||
detach_marker (Lisp_Object marker)
|
||||
{
|
||||
/* FIXME: Roundabout way to call `unchain_marker`. */
|
||||
Fset_marker (marker, Qnil, Qnil);
|
||||
}
|
||||
|
||||
|
|
@ -687,34 +1018,11 @@ unchain_marker (register struct Lisp_Marker *marker)
|
|||
|
||||
if (b)
|
||||
{
|
||||
register struct Lisp_Marker *tail, **prev;
|
||||
|
||||
/* No dead buffers here. */
|
||||
eassert (BUFFER_LIVE_P (b));
|
||||
|
||||
markers_kill (BUF_ALL_MARKERS (b), marker);
|
||||
marker->buffer = NULL;
|
||||
prev = &BUF_MARKERS (b);
|
||||
|
||||
for (tail = BUF_MARKERS (b); tail; prev = &tail->next, tail = *prev)
|
||||
if (marker == tail)
|
||||
{
|
||||
if (*prev == BUF_MARKERS (b))
|
||||
{
|
||||
/* Deleting first marker from the buffer's chain. Crash
|
||||
if new first marker in chain does not say it belongs
|
||||
to the same buffer, or at least that they have the same
|
||||
base buffer. */
|
||||
if (tail->next && b->text != tail->next->buffer->text)
|
||||
emacs_abort ();
|
||||
}
|
||||
*prev = tail->next;
|
||||
/* We have removed the marker from the chain;
|
||||
no need to scan the rest of the chain. */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Error if marker was not in it's chain. */
|
||||
eassert (tail != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -794,6 +1102,45 @@ If TYPE is nil, it means the marker stays behind when you insert text at it. */
|
|||
return type;
|
||||
}
|
||||
|
||||
DEFUN ("make-marker", Fmake_marker, Smake_marker, 0, 0, 0,
|
||||
doc: /* Return a newly allocated marker which does not point at any place. */)
|
||||
(void)
|
||||
{
|
||||
struct Lisp_Marker *p = ALLOCATE_PLAIN_PSEUDOVECTOR (struct Lisp_Marker,
|
||||
PVEC_MARKER);
|
||||
p->buffer = 0;
|
||||
p->bytepos = 0;
|
||||
p->charpos = 0;
|
||||
p->insertion_type = false;
|
||||
p->need_adjustment = false;
|
||||
p->cache = false;
|
||||
return make_lisp_ptr (p, Lisp_Vectorlike);
|
||||
}
|
||||
|
||||
/* Return a newly allocated marker which points into BUF
|
||||
at character position CHARPOS and byte position BYTEPOS. */
|
||||
|
||||
Lisp_Object
|
||||
build_marker (struct buffer *buf, ptrdiff_t charpos, ptrdiff_t bytepos)
|
||||
{
|
||||
/* No dead buffers here. */
|
||||
eassert (BUFFER_LIVE_P (buf));
|
||||
|
||||
/* Every character is at least one byte. */
|
||||
eassert (charpos <= bytepos);
|
||||
|
||||
struct Lisp_Marker *m = ALLOCATE_PLAIN_PSEUDOVECTOR (struct Lisp_Marker,
|
||||
PVEC_MARKER);
|
||||
m->buffer = buf;
|
||||
m->charpos = charpos;
|
||||
m->bytepos = bytepos;
|
||||
m->insertion_type = false;
|
||||
m->need_adjustment = false;
|
||||
m->cache = false;
|
||||
BUF_ALL_MARKERS (buf) = markers_add (BUF_ALL_MARKERS (buf), m);
|
||||
return make_lisp_ptr (m, Lisp_Vectorlike);
|
||||
}
|
||||
|
||||
#ifdef MARKER_DEBUG
|
||||
|
||||
/* For debugging -- count the markers in buffer BUF. */
|
||||
|
|
@ -801,13 +1148,8 @@ If TYPE is nil, it means the marker stays behind when you insert text at it. */
|
|||
int
|
||||
count_markers (struct buffer *buf)
|
||||
{
|
||||
int total = 0;
|
||||
struct Lisp_Marker *tail;
|
||||
|
||||
for (tail = BUF_MARKERS (buf); tail; tail = tail->next)
|
||||
total++;
|
||||
|
||||
return total;
|
||||
struct Lisp_Markers *t = BUF_ALL_MARKERS (current_buffer);
|
||||
return t->size - (t->gap_end - t->gap_beg);
|
||||
}
|
||||
|
||||
/* For debugging -- recompute the bytepos corresponding
|
||||
|
|
@ -833,6 +1175,7 @@ verify_bytepos (ptrdiff_t charpos)
|
|||
void
|
||||
syms_of_marker (void)
|
||||
{
|
||||
defsubr (&Smake_marker);
|
||||
defsubr (&Smarker_position);
|
||||
defsubr (&Smarker_last_position);
|
||||
defsubr (&Smarker_buffer);
|
||||
|
|
|
|||
105
src/marker.h
Normal file
105
src/marker.h
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
#ifndef EMACS_MARKER_H
|
||||
#define EMACS_MARKER_H
|
||||
|
||||
#include "lisp.h"
|
||||
|
||||
#ifndef ABSTRACT_LISP_MARKER
|
||||
struct Lisp_Marker
|
||||
{
|
||||
union vectorlike_header header;
|
||||
|
||||
/* This is the buffer that the marker points into, or 0 if it points nowhere.
|
||||
Note: a chain of markers can contain markers pointing into different
|
||||
buffers (the chain is per buffer_text rather than per buffer, so it's
|
||||
shared between indirect buffers). */
|
||||
/* This is used for (other than NULL-checking):
|
||||
- Fmarker_buffer
|
||||
- Fset_marker: check eq(oldbuf, newbuf) to avoid unchain+rechain.
|
||||
- unchain_marker: to find the list from which to unchain.
|
||||
- Fkill_buffer: to only unchain the markers of current indirect buffer.
|
||||
*/
|
||||
struct buffer *buffer;
|
||||
|
||||
/* This flag is temporarily used in the functions
|
||||
decode/encode_coding_object to record that the marker position
|
||||
must be adjusted after the conversion. */
|
||||
bool_bf need_adjustment : 1;
|
||||
/* True means normal insertion at the marker's position
|
||||
leaves the marker after the inserted text. */
|
||||
bool_bf insertion_type : 1;
|
||||
/* True means that this is a chars<->bytes conversion cache entry
|
||||
rather than a true marker. */
|
||||
bool_bf cache : 1;
|
||||
|
||||
/* The remaining fields are meaningless in a marker that
|
||||
does not point anywhere. */
|
||||
|
||||
/* This is the char position where the marker points. */
|
||||
ptrdiff_t charpos;
|
||||
/* This is the byte position.
|
||||
It's mostly used as a charpos<->bytepos cache (i.e. it's not directly
|
||||
used to implement the functionality of markers, but rather to (ab)use
|
||||
markers as a cache for char<->byte mappings). */
|
||||
ptrdiff_t bytepos;
|
||||
} GCALIGNED_STRUCT;
|
||||
#endif
|
||||
|
||||
struct Lisp_Markers;
|
||||
|
||||
extern bool markers_full_p (struct Lisp_Markers *t);
|
||||
extern struct Lisp_Markers *markers_new (unsigned int size);
|
||||
extern void markers_kill (struct Lisp_Markers *t, struct Lisp_Marker *m);
|
||||
extern struct Lisp_Markers *markers_add (struct Lisp_Markers *t,
|
||||
struct Lisp_Marker *m);
|
||||
extern void markers_adjust_for_insert (struct Lisp_Markers *t,
|
||||
ptrdiff_t from, ptrdiff_t from_byte,
|
||||
ptrdiff_t to, ptrdiff_t to_byte,
|
||||
bool before_markers);
|
||||
extern void markers_adjust_for_replace
|
||||
(struct Lisp_Markers *t,
|
||||
ptrdiff_t from, ptrdiff_t from_byte,
|
||||
ptrdiff_t old_chars, ptrdiff_t old_bytes,
|
||||
ptrdiff_t new_chars, ptrdiff_t new_bytes);
|
||||
extern void markers_adjust_for_delete (struct Lisp_Markers *t,
|
||||
ptrdiff_t from, ptrdiff_t from_byte,
|
||||
ptrdiff_t to, ptrdiff_t to_byte);
|
||||
|
||||
|
||||
|
||||
struct markers_iterator
|
||||
{
|
||||
struct Lisp_Markers *t;
|
||||
struct Lisp_Marker *m;
|
||||
unsigned int i;
|
||||
};
|
||||
|
||||
extern struct markers_iterator markers_iterator_all (struct Lisp_Markers *t);
|
||||
extern void markers_iterator_next (struct markers_iterator *it);
|
||||
|
||||
#define MARKERS_DO_ALL(it, t) \
|
||||
for (struct markers_iterator it = markers_iterator_all (t); \
|
||||
it.m; markers_iterator_next (&it))
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
extern void clear_charpos_cache (struct buffer *b);
|
||||
extern ptrdiff_t buf_charpos_to_bytepos (struct buffer *b, ptrdiff_t charpos);
|
||||
extern ptrdiff_t buf_bytepos_to_charpos (struct buffer *b, ptrdiff_t bytepos);
|
||||
extern Lisp_Object set_marker_restricted (Lisp_Object marker,
|
||||
Lisp_Object position,
|
||||
Lisp_Object buffer);
|
||||
extern Lisp_Object set_marker_both (Lisp_Object marker, Lisp_Object buffer,
|
||||
ptrdiff_t charpos, ptrdiff_t bytepos);
|
||||
extern Lisp_Object set_marker_restricted_both (Lisp_Object marker,
|
||||
Lisp_Object buffer,
|
||||
ptrdiff_t charpos,
|
||||
ptrdiff_t bytepos);
|
||||
extern void detach_marker (Lisp_Object marker);
|
||||
extern void unchain_marker (register struct Lisp_Marker *marker);
|
||||
extern ptrdiff_t marker_position (Lisp_Object marker);
|
||||
extern ptrdiff_t marker_byte_position (Lisp_Object marker);
|
||||
extern Lisp_Object build_marker (struct buffer *buf, ptrdiff_t charpos,
|
||||
ptrdiff_t bytepos);
|
||||
extern void syms_of_marker (void);
|
||||
|
||||
#endif
|
||||
|
|
@ -38,6 +38,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#include "frame.h"
|
||||
#include "intervals.h"
|
||||
#include "lisp.h"
|
||||
#include "marker.h"
|
||||
#include "pdumper.h"
|
||||
#include "window.h"
|
||||
#include "sysstdio.h"
|
||||
|
|
@ -2116,8 +2117,6 @@ dump_marker (struct dump_context *ctx, const struct Lisp_Marker *marker)
|
|||
{
|
||||
dump_field_lv_rawptr (ctx, out, marker, &marker->buffer,
|
||||
Lisp_Vectorlike, WEIGHT_NORMAL);
|
||||
dump_field_lv_rawptr (ctx, out, marker, &marker->next,
|
||||
Lisp_Vectorlike, WEIGHT_STRONG);
|
||||
DUMP_FIELD_COPY (out, marker, charpos);
|
||||
DUMP_FIELD_COPY (out, marker, bytepos);
|
||||
}
|
||||
|
|
@ -2166,6 +2165,46 @@ dump_interval_node (struct dump_context *ctx, struct itree_node *node)
|
|||
return offset;
|
||||
}
|
||||
|
||||
/*****************/
|
||||
/* FIXME: YUCK!! */
|
||||
/*****************/
|
||||
typedef unsigned int m_index_t;
|
||||
struct Lisp_Markers
|
||||
{
|
||||
m_index_t size;
|
||||
m_index_t gap_beg;
|
||||
m_index_t gap_end;
|
||||
struct Lisp_Marker *markers[FLEXIBLE_ARRAY_MEMBER];
|
||||
};
|
||||
|
||||
|
||||
static dump_off
|
||||
dump_markers (struct dump_context *ctx, const struct Lisp_Markers *t)
|
||||
{
|
||||
ptrdiff_t bytesize = (sizeof (struct Lisp_Markers)
|
||||
+ t->size * sizeof (struct Lisp_Marker *));
|
||||
struct Lisp_Markers *out = malloc (bytesize);
|
||||
dump_object_start (ctx, out, bytesize);
|
||||
DUMP_FIELD_COPY (out, t, size);
|
||||
DUMP_FIELD_COPY (out, t, gap_beg);
|
||||
DUMP_FIELD_COPY (out, t, gap_end);
|
||||
for (m_index_t i = 0; i < t->size; i++)
|
||||
if (t->markers[i])
|
||||
dump_field_fixup_later (ctx, out, t, &t->markers[i]);
|
||||
dump_off offset = dump_object_finish (ctx, out, bytesize);
|
||||
free (out);
|
||||
for (m_index_t i = 0; i < t->size; i++)
|
||||
{
|
||||
struct Lisp_Marker *m = t->markers[i];
|
||||
if (m)
|
||||
dump_remember_fixup_ptr_raw
|
||||
(ctx,
|
||||
offset + dump_offsetof (struct Lisp_Markers, markers[i]),
|
||||
dump_marker (ctx, m));
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static dump_off
|
||||
dump_overlay (struct dump_context *ctx, const struct Lisp_Overlay *overlay)
|
||||
{
|
||||
|
|
@ -2861,8 +2900,7 @@ dump_buffer (struct dump_context *ctx, const struct buffer *in_buffer)
|
|||
DUMP_FIELD_COPY (out, buffer, own_text.overlay_unchanged_modified);
|
||||
if (buffer->own_text.intervals)
|
||||
dump_field_fixup_later (ctx, out, buffer, &buffer->own_text.intervals);
|
||||
dump_field_lv_rawptr (ctx, out, buffer, &buffer->own_text.markers,
|
||||
Lisp_Vectorlike, WEIGHT_NORMAL);
|
||||
dump_field_fixup_later (ctx, out, buffer, &buffer->own_text.all_markers);
|
||||
DUMP_FIELD_COPY (out, buffer, own_text.inhibit_shrinking);
|
||||
DUMP_FIELD_COPY (out, buffer, own_text.redisplay);
|
||||
}
|
||||
|
|
@ -2921,11 +2959,18 @@ dump_buffer (struct dump_context *ctx, const struct buffer *in_buffer)
|
|||
dump_field_lv (ctx, out, buffer, &buffer->undo_list_,
|
||||
WEIGHT_STRONG);
|
||||
dump_off offset = finish_dump_pvec (ctx, &out->header);
|
||||
if (!buffer->base_buffer && buffer->own_text.intervals)
|
||||
dump_remember_fixup_ptr_raw
|
||||
(ctx,
|
||||
offset + dump_offsetof (struct buffer, own_text.intervals),
|
||||
dump_interval_tree (ctx, buffer->own_text.intervals, 0));
|
||||
if (!buffer->base_buffer)
|
||||
{
|
||||
if (buffer->own_text.intervals)
|
||||
dump_remember_fixup_ptr_raw
|
||||
(ctx,
|
||||
offset + dump_offsetof (struct buffer, own_text.intervals),
|
||||
dump_interval_tree (ctx, buffer->own_text.intervals, 0));
|
||||
dump_remember_fixup_ptr_raw
|
||||
(ctx,
|
||||
offset + dump_offsetof (struct buffer, own_text.all_markers),
|
||||
dump_markers (ctx, buffer->own_text.all_markers));
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#include "sysstdio.h"
|
||||
|
||||
#include "lisp.h"
|
||||
#include "marker.h"
|
||||
#include "character.h"
|
||||
#include "coding.h"
|
||||
#include "buffer.h"
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#include <fcntl.h>
|
||||
|
||||
#include "lisp.h"
|
||||
#include "marker.h"
|
||||
|
||||
/* Only MS-DOS does not define `subprocesses'. */
|
||||
#ifdef subprocesses
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "lisp.h"
|
||||
#include "marker.h"
|
||||
#include "character.h"
|
||||
#include "buffer.h"
|
||||
#include "syntax.h"
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#include <config.h>
|
||||
|
||||
#include "textconv.h"
|
||||
#include "marker.h"
|
||||
#include "buffer.h"
|
||||
#include "syntax.h"
|
||||
#include "blockinput.h"
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#include <config.h>
|
||||
|
||||
#include "lisp.h"
|
||||
#include "marker.h"
|
||||
#include "buffer.h"
|
||||
#include "keyboard.h"
|
||||
|
||||
|
|
@ -128,9 +129,9 @@ record_marker_adjustments (ptrdiff_t from, ptrdiff_t to)
|
|||
{
|
||||
prepare_record ();
|
||||
|
||||
for (struct Lisp_Marker *m = BUF_MARKERS (current_buffer); m; m = m->next)
|
||||
MARKERS_DO_ALL (it, BUF_ALL_MARKERS (current_buffer))
|
||||
{
|
||||
ptrdiff_t charpos = m->charpos;
|
||||
ptrdiff_t charpos = it.m->charpos;
|
||||
eassert (charpos <= Z);
|
||||
|
||||
if (from <= charpos && charpos <= to)
|
||||
|
|
@ -142,11 +143,11 @@ record_marker_adjustments (ptrdiff_t from, ptrdiff_t to)
|
|||
insertion_type t markers will automatically move forward
|
||||
upon re-inserting the deleted text, so we have to arrange
|
||||
for them to move backward to the correct position. */
|
||||
ptrdiff_t adjustment = (m->insertion_type ? to : from) - charpos;
|
||||
ptrdiff_t adjustment = (it.m->insertion_type ? to : from) - charpos;
|
||||
|
||||
if (adjustment)
|
||||
{
|
||||
Lisp_Object marker = make_lisp_ptr (m, Lisp_Vectorlike);
|
||||
Lisp_Object marker = make_lisp_ptr (it.m, Lisp_Vectorlike);
|
||||
bset_undo_list
|
||||
(current_buffer,
|
||||
Fcons (Fcons (marker, make_fixnum (adjustment)),
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#endif
|
||||
|
||||
#include "lisp.h"
|
||||
#include "marker.h"
|
||||
#include "buffer.h"
|
||||
#include "keyboard.h"
|
||||
#include "keymap.h"
|
||||
|
|
|
|||
|
|
@ -471,6 +471,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#include <math.h>
|
||||
|
||||
#include "lisp.h"
|
||||
#include "marker.h"
|
||||
#include "atimer.h"
|
||||
#include "composite.h"
|
||||
#include "keyboard.h"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue