Each buffer contains a lock that is used to prevent more than one thread from modifying the text, text properties or points within the buffer simultaneously. All of the exported editor functions (editor:insert-string, editor:move-point etc) claim this lock implicitly and are therefore atomic with respect to other such functions.
In situations where you want to make several changes as one atomic operation, use one of the macros editor:with-buffer-locked or editor:with-point-locked to lock the buffer for the duration of the operation. For example, if you want to delete the next character and replace it by a space:
(editor:with-buffer-locked ((editor:current-buffer))
(editor:delete-next-character-command nil)
(editor:insert-character (editor:current-point)
#\Space))
In addition, you sometimes want to examine the text in a buffer without changing it, but ensure that no other thread can modify it in the meantime. This can be achieved by locking the buffer using editor:with-buffer-locked or editor:with-point-locked and passing the
for-modification
argument as
nil
. For example, if you are computing the beginning and end of some portion of the text in a buffer and then performing some operation on that text, you may want to lock the buffer to ensure that no other threads can modify the text while your are processing it.
editor:with-buffer-locked (buffer
&key for-modification
check-file-modification
block-interrupts )
&body body => values
Evaluates body while holding the lock in buffer . At most one thread can lock a buffer at a time and the macro waits until it can claim the lock.
If
for-modification
is non-
nil
(the default), the contents of
buffer
can be modified by
body
. If
for-modification
is
nil
, the contents of
buffer
cannot be modified until
body
returns and trying to do so from within
body
will signal an error. If the buffer is read-only and
for-modification
is non-
nil
, then an
editor:editor-error
is signalled
The macro
editor:with-buffer-locked
can be used recursively, but if the outermost use passed
nil
as the value of
for-modification
, then inner uses cannot pass non-
nil
as the value of
for-modification
.
If
check-file-modification
is non-
nil
(the default) and the buffer is associated with a file and has not already been modified, then the modification time of the file is compared to the time that the file was last read. If the file is newer than the buffer, then the user is asked if they want to re-read the file into the buffer, and if they do then the file is re-read and the operations aborts. Otherwise, there is no check for the file being newer than the buffer.
If
block-interrupts
is non-
nil
, the body is evaluated with interrupts blocked. This is useful if the buffer may be modified by an interrupt function, or some interrupt function may end up waiting for another thread that may wait for the buffer lock, which would cause a deadlock. The default is not to block interrupts.
Note that using a non-
nil
value for
block-interrupts
is not the same as using the
without-interrupts
or
without-preemption
macros. It just stops the current thread from calling interrupt functions, so other threads might run while the body is being evaluated.
The values returned are those of body .
editor:with-point-locked (point
&key for-modification
check-file-modification
block-interrupts
errorp )
&body body => values
Evaluates body while holding the lock in the buffer that is associated with point . In addition, the macro checks that point is valid and this check is atomic with respect to calls to the function editor:delete-point. The values of for-modification , check-file-modification and block-interrupts have the same meanings as for editor:with-buffer-locked.
The value of
errorp
determines the behavior when
point
is not valid. If
errorp
is non-
nil
, an error is signaled, otherwise
nil
is returned without evaluating
body
. The point may be invalid because it does not reference any buffer (that is, it has been deleted), or because its buffer was changed by another thread while the current thread was attempting to lock the buffer.
The
values
returned are those of
body
, or
nil
when
errorp
is
nil
and
point
is not valid.