aboutsummaryrefslogtreecommitdiffstats
path: root/doc/lispref/text.texi
diff options
context:
space:
mode:
Diffstat (limited to 'doc/lispref/text.texi')
-rw-r--r--doc/lispref/text.texi148
1 files changed, 148 insertions, 0 deletions
diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi
index 18f0ee88fe5..8774801f41f 100644
--- a/doc/lispref/text.texi
+++ b/doc/lispref/text.texi
@@ -6375,3 +6375,151 @@ hooks during a series of changes (typically for performance reasons),
6375use @code{combine-change-calls} or @code{combine-after-change-calls} 6375use @code{combine-change-calls} or @code{combine-after-change-calls}
6376instead. 6376instead.
6377@end defvar 6377@end defvar
6378
6379@node Tracking changes
6380@subsection Tracking changes
6381@cindex track-changes
6382@cindex change tracker
6383
6384Using @code{before-change-functions} and @code{after-change-functions}
6385can be difficult in practice because of a number of pitfalls, such as
6386the fact that the two calls are not always properly paired, or some
6387calls may be missing, either because some Emacs primitives failed to
6388properly pair them or because of incorrect use of
6389@code{inhibit-modification-hooks}. Furthermore,
6390many restrictions apply to those hook functions, such as the fact that
6391they basically should never modify the current buffer, nor use an
6392operation that may block, and they proceed quickly because
6393some commands may call these hooks a large number of times.
6394
6395The Track-Changes library fundamentally provides an alternative API,
6396built on top of those hooks. Compared to @code{after-change-functions},
6397the first important difference is that, instead of providing the bounds
6398of the change and the previous length, it provides the bounds of the
6399change and the actual previous content of that region. The need to
6400extract information from the original contents of the buffer is one of
6401the main reasons why some packages need to use both
6402@code{before-change-functions} and @code{after-change-functions} and
6403then try to match them up.
6404
6405The second difference is that it decouples the notification of a change
6406from the act of processing it, and it automatically combines into
6407a single change operation all the changes that occur between the first
6408change and the actual processing. This makes it natural and easy to
6409process the changes at a larger granularity, such as once per command,
6410and eliminates most of the restrictions that apply to the usual change
6411hook functions, making it possible to use blocking operations or to
6412modify the buffer.
6413
6414To start tracking changes, you have to call
6415@code{track-changes-register}, passing it a @var{signal} function as
6416argument. This returns a tracker @var{id} which is used to identify
6417your change tracker to the other functions of the library.
6418When the buffer is modified, the library calls the @var{signal}
6419function to inform you of that change and immediately starts
6420accumulating subsequent changes into a single combined change.
6421The @var{signal} function serves only to warn that a modification
6422occurred but does not receive a description of the change. Also the
6423library will not call it again until after you retrieved the change.
6424
6425To retrieve changes, you need to call @code{track-changes-fetch}, which
6426provides you with the bounds of the changes accumulated since the
6427last call, as well as the previous content of that region. It also
6428``re-arms'' the @var{signal} function so that the library will call it
6429again after the next buffer modification.
6430
6431@defun track-changes-register signal &key nobefore disjoint immediate
6432This function creates a new @dfn{change tracker}. Change trackers are kept
6433abstract, so we refer to them as mere identities, and the function thus
6434returns the tracker's @var{id}.
6435
6436@var{signal} is a function that the library will call to notify of
6437a change. It will sometimes call it with a single argument and
6438sometimes with two. Upon the first change to the buffer since this
6439tracker last called @code{track-changes-fetch}, the library calls this
6440@var{signal} function with a single argument holding the @var{id} of
6441the tracker.
6442
6443By default, the call to the @var{signal} function does not happen
6444immediately, but is instead postponed with a 0 seconds timer
6445(@pxref{Timers}). This is usually desired to make sure the @var{signal}
6446function is not called too frequently and runs in a permissive context,
6447freeing the client from performance concerns or worries about which
6448operations might be problematic. If a client wants to have more
6449control, they can provide a non-@code{nil} value as the @var{immediate}
6450argument in which case the library calls the @var{signal} function
6451directly from @code{after-change-functions}. Beware that it means that
6452the @var{signal} function has to be careful not to modify the buffer or
6453use operations that may block.
6454
6455If you're not interested in the actual previous content of the buffer,
6456but are using this library only for its ability to combine many small
6457changes into a larger one and to delay the processing to a more
6458convenient time, you can specify a non-@code{nil} value for the
6459@var{nobefore} argument. In that case, @code{track-change-fetch}
6460provides you only with the length of the previous content, just like
6461@code{after-change-functions}. It also allows the library to save
6462some work.
6463
6464While you may like to accumulate many small changes into larger ones,
6465you may not want to do that if the changes are too far apart. If you
6466specify a non-@code{nil} value for the @var{disjoint} argument, the library
6467will let you know when a change is about to occur ``far'' from the
6468currently pending ones by calling the @var{signal} function right away,
6469passing it two arguments this time: the @var{id} of the tracker, and the
6470number of characters that separates the upcoming change from the
6471already pending changes. This in itself does not prevent combining this
6472new change with the previous ones, so if you think the upcoming change
6473is indeed too far, you need to call @code{track-change-fetch}
6474right away.
6475Beware that when the @var{signal} function is called because of
6476a disjoint change, this happens directly from
6477@code{before-change-functions}, so the usual restrictions apply about
6478modifying the buffer or using operations that may block.
6479@end defun
6480
6481@defun track-changes-fetch id func
6482This is the function that lets you find out what has changed in the
6483buffer. By providing the tracker @var{id} you let the library figure
6484out which changes have already been seen by your tracker. Instead of
6485returning a description of the changes, @code{track-changes-fetch} calls
6486the @var{func} function with that description in the form of
64873 arguments: @var{beg}, @var{end}, and @var{before}, where
6488@code{@var{beg}..@var{end}} delimit the region that was modified and
6489@var{before} describes the previous content of that region.
6490Usually @var{before} is a string containing the previous text of the
6491modified region, but if you specified a non-@code{nil} @var{nobefore} argument
6492to @code{track-changes-register}, then it is replaced by the number of
6493characters of that previous text.
6494
6495In case no changes occurred since the last call,
6496@code{track-changes-fetch} simply does not call @var{func} and returns
6497@code{nil}. If changes did occur, it calls @var{func} and returns the value
6498returned by @var{func}. But note that @var{func} is called just once
6499regardless of how many changes occurred: those are summarized into
6500a single @var{beg}/@var{end}/@var{before} triplet.
6501
6502In some cases, the library is not properly notified of all changes,
6503for example because of a bug in the low-level C code or because of an
6504improper use of @code{inhibit-modification-hooks}. When it detects such
6505a problem, @var{func} receives a @code{@var{beg}..@var{end}} region
6506which covers the whole buffer and the @var{before} argument is the
6507symbol @code{error} to indicate that the library was unable to determine
6508what was changed.
6509
6510Once @var{func} finishes, @code{track-changes-fetch} re-enables the
6511@var{signal} function so that it will be called the next time a change
6512occurs. This is the reason why it calls @var{func} instead of returning
6513a description: it lets you process the change without worrying about the
6514risk that the @var{signal} function gets triggered in the middle of it,
6515because the @var{signal} is re-enabled only after @var{func} finishes.
6516@end defun
6517
6518@defun track-changes-unregister id
6519This function tells the library that the tracker @var{id} does not need
6520to know about buffer changes any more. Most clients will never want to
6521stop tracking changes, but for clients such as minor modes, it is
6522important to call this function when the minor mode is disabled,
6523otherwise the tracker will keep accumulating changes and consume more
6524and more resources.
6525@end defun