Re: [PG-devel] Improvement of pg-protected-undo

2010-08-02 Thread David Aspinall

Dear Erik,

I replied off-list, but see you have subscribed here too.

For other developers: this welcome improvement has been added to PG CVS 
head now.  Please feel free to send any more improvements/fixes for PG 
4.0, which should at last be released this summer.


 - David

___
ProofGeneral-devel mailing list
ProofGeneral-devel@inf.ed.ac.uk
http://lists.inf.ed.ac.uk/mailman/listinfo/proofgeneral-devel

--
The University of Edinburgh is a charitable body, registered in
Scotland, with registration number SC005336.



[PG-devel] Improvement of pg-protected-undo

2010-08-02 Thread Erik Martin-Dorel

Dear Proof General developers,

I use extensively Coq/ProofGeneral for Emacs and I am delighted to be
able to use this wonderful tool within my favorite editor.

I have been thinking for a few days of a way to fix and improve the
`pg-protected-undo' function.

Indeed, the current implementation of pg-protected-undo which forces
undo-in-region has several bugs and/or drawbacks:

- if the size of the forced region is empty, it breaks the locked region
  all the same;

- undo should be possible in the comments of the locked region (I have
  just seen it is already reported by bug #294);

- since undo-in-region is forced, we cannot actually perform any
  custom undo-in-region any more, and it also seems to obstruct redo;

- finally, "repetition" [when arg > 1] seems not to work properly.


I propose the enclosed Elisp code which should provide the following features:

- a safe undo function
  that calls the Emacs original `undo' if there is no locked region,
  else uses two auxiliary functions to get the "next undo elt" and check
  it won't affect the locked region;

- if this is the case, it proposes the user (via y-or-n-p) to retract,
  or do it silently if `proof-allow-undo-in-read-only' is non-nil
  (thus it does not break the locked region, even if
  `proof-allow-undo-in-read-only' holds);

- but the next undo/redo is always allowed if it will edit a comment;

- "custom undo in region" that could be performed by GNU Emacs undo is
  still available,

- as well as "repetition" according to the given prefix argument.

Kind regards,

Erik.

PS: I tested the code with:
  Coq 8.2pl2
  ProofGeneral 4.0pre100709
  GNU Emacs 23.2.1

--
Érik Martin-Dorel
PhD student, ENS de Lyon, LIP
erik.martin-do...@ens-lyon.org
http://perso.ens-lyon.fr/erik.martin-dorel/
;;; Copyright (c) 2010 Erik Martin-Dorel, ENS de Lyon.
;;
;; Attempt to improve `pg-protected-undo' with the help of some
;; auxiliary functions `pg-protected-undo-1' and `next-undo-elt'
;;

(defun pg-protected-undo (&optional arg)
  "Provides all features of `undo' and avoids breaking the locked region.

It performs each of the desired undos thanks to `pg-protected-undo-1'
which checks that these operations will not affect the locked region.
If this is the case, it proposes the user to retract, or do it
silently if `proof-allow-undo-in-read-only' is non-nil.

Moreover, undo/redo is allowed in comments located in the locked region."
  (interactive "*P")
  (if (or (not proof-locked-span)
  (equal (proof-queue-or-locked-end) (point-min)))
  (undo arg)
(let ((repeat ; Allow the user to perform successive undos at once
   (if (numberp arg)
   (prefix-numeric-value arg) ; arg is a raw prefix argument
 1))
  (newarg ; Allow the user to limit the undo to the current region
   (and
;; this Boolean expression is necessary to match
;; the behavior of GNU Emacs undo function
(or (region-active-p) (and arg (not (numberp arg
(> (region-end) (region-beginning)
  (while (> repeat 0)
(pg-protected-undo-1 newarg) ; do some safe undos step by step
(setq last-command 'undo) ; need for this assignment meanwhile
(decf repeat)

(defun pg-protected-undo-1 (arg)
  "This function is intended to be called by `pg-protected-undo'.

It performs a single undo/redo after checking that this operation
will not affect the locked region.
If this is the case, it proposes the user to retract, or do it
silently if `proof-allow-undo-in-read-only' is non-nil.

The flag ARG is passed to functions `undo' and `next-undo-elt'.
It should be a non-numeric value saying whether an undo-in-region
behavior is expected."
;; Note that if ARG is non-nil, (> (region-end) (region-beginning)) must hold,
;; at least for the first call from the loop of `pg-protected-undo'.
  (setq arg (and arg (not (numberp arg ; ensure arg is boolean
  (if (or (not proof-locked-span)
  (equal (proof-queue-or-locked-end) (point-min))) ; required test
  (undo arg)
(let* ((next (next-undo-elt arg))
   (delta (undo-delta next))  ; can be '(0 . 0) if next is nil
   (beg (car delta))
   (end (max beg (- beg (cdr delta) ; Key computation
  (when (and next (> beg 0) ; the "next undo elt" exists
 (> (proof-queue-or-locked-end) beg)
 (not (and  ; Allow undo in comments
   (proof-inside-comment beg) (proof-inside-comment end
(if (or proof-allow-undo-in-read-only
(y-or-n-p "Next undo will modify read-only region, retract? "))
(proof-retract-before-change beg end)
  (when (eq last-command 'undo) (setq this-command 'undo))
  ;; now we can stop the function without breaking possible undo chains
  (error
   "Cannot undo without retracting to the appropriate position.")))
  (undo arg

(defun next-undo