diff options
| author | Vincent Belaïche | 2016-01-20 08:28:06 +0100 |
|---|---|---|
| committer | Vincent Belaïche | 2016-01-20 08:28:06 +0100 |
| commit | badcd38aa86ed7973f2be2743c405710973a0bdd (patch) | |
| tree | c335dc4a3819bc2060dd5ed1c5dd814bf7568c62 | |
| parent | de8c5f9db50a22ef5640bb83c0c7c755b78be895 (diff) | |
| download | emacs-badcd38aa86ed7973f2be2743c405710973a0bdd.tar.gz emacs-badcd38aa86ed7973f2be2743c405710973a0bdd.zip | |
Correct a whole bunch of bugs coming with renamed cell relocation.
* lisp/ses.el (ses-localvars): rename variable
`ses--renamed-cell-symb-list' into `ses--in-killing-named-cell-list'
and adjust the comment about it.
(ses-plist-delq): new defun.
(ses--ses-buffer-list): new defvar.
(ses--unbind-cell-name): new defun.
(ses-relocate-symbol): Do not relocate symbol when it is a named cell.
(ses-relocate-formula): Undo change of
2011-12-27T19:30:39Z!vincentb1@users.sourceforge.net that was
preventing relocation for named cell --- now doing this is delegated
to function `ses-relocate-symbol'.
(ses-relocate-range): In docstring, undo change of
2016-01-03T07:31:52Z!johnw@newartisans.com, `ses-range' must remain
lower case as it is not a variable.
(ses-relocate-all): Cell name relocation : 1) check that cell is a
renamed cell by testing `ses-cell' property to :ses-named, rather than
comparing name to corresponding standard name. Set rowcol of renamed
cell into the hashmap --- `ses-cell' property must not be used for
that as the same name can be used for different locations in different
SES sheets ; 2) use `local-variable-if-set-p' rather than `boundp' and
`local-variable-p' to check if cell name is already in use in this
sheet or needs initialisation.
(ses-relocate-all): Cell value relocation : 1) like for name
relocation use the `ses-cell' property rather than comparing actual
name to corresponding standard name. 2) Correct bug introduced in
2011-12-27T19:30:39Z!vincentb1@users.sourceforge.net, as the test was
made the other way round than the intention --- ie value relocation
was disabled for standard cell, not for renamed cell as was the
intention.
(ses-relocate-all): Add loop for unbinding deleted renamed cells
names.
(ses-killbuffer-hook): new defun.
(ses-mode): Add the ses--ses-buffer-list maintenance mechanism ---
kill buffer hook, plus pushing current buffer if new in list.
(ses-delete-row, ses-delete-column): Collect deleted renamed cells
into `ses--in-killing-named-cell-list'.
(ses-rename-cell): Remove update of variable
`ses--renamed-cell-symb-list', this variable is renamed to
`ses--in-killing-named-cell-list', and its setting is done in
functions `ses-delete-row' and , `ses-delete-column' now.
(ses-rename-cell): Change correction of
2015-12-30T23:10:37Z!vincentb1@users.sourceforge.net concerning
computation of the range over which `cursor-intangible' property was
to be updated. This correction was ok for non spilling cells, but not
for cells spilling over following blank cells. Simply use
`next-single-property-change' rather than computing the end column
from column widths.
| -rw-r--r-- | lisp/ses.el | 136 |
1 files changed, 105 insertions, 31 deletions
diff --git a/lisp/ses.el b/lisp/ses.el index e2abd7426f6..7647a5519ad 100644 --- a/lisp/ses.el +++ b/lisp/ses.el | |||
| @@ -302,9 +302,9 @@ default printer and then modify its output.") | |||
| 302 | ses--numcols ses--numrows ses--symbolic-formulas | 302 | ses--numcols ses--numrows ses--symbolic-formulas |
| 303 | ses--data-marker ses--params-marker (ses--Dijkstra-attempt-nb . 0) | 303 | ses--data-marker ses--params-marker (ses--Dijkstra-attempt-nb . 0) |
| 304 | ses--Dijkstra-weight-bound | 304 | ses--Dijkstra-weight-bound |
| 305 | ;; This list is useful to speed-up clean-up of symbols when | 305 | ;; This list is useful for clean-up of symbols when an area |
| 306 | ;; an area containing renamed cell is deleted. | 306 | ;; containing renamed cell is deleted. |
| 307 | ses--renamed-cell-symb-list | 307 | ses--in-killing-named-cell-list |
| 308 | ;; Global variables that we override | 308 | ;; Global variables that we override |
| 309 | next-line-add-newlines transient-mark-mode) | 309 | next-line-add-newlines transient-mark-mode) |
| 310 | "Buffer-local variables used by SES.")) | 310 | "Buffer-local variables used by SES.")) |
| @@ -445,6 +445,44 @@ is nil if SYM is not a symbol that names a cell." | |||
| 445 | (and (consp rowcol) | 445 | (and (consp rowcol) |
| 446 | (ses-get-cell (car rowcol) (cdr rowcol))))))) | 446 | (ses-get-cell (car rowcol) (cdr rowcol))))))) |
| 447 | 447 | ||
| 448 | (defun ses-plist-delq (plist prop) | ||
| 449 | "Return PLIST after deletion of proprerty/value pair. | ||
| 450 | |||
| 451 | PROP is the symbol identifying the property/value pair. PLIST may | ||
| 452 | be modified by border effect." | ||
| 453 | (cond | ||
| 454 | ((null plist) nil) | ||
| 455 | ((eq (car plist) prop) (cddr plist)) | ||
| 456 | (t (let* ((plist-1 (cdr plist)) | ||
| 457 | (plist-2 (cdr plist-1))) | ||
| 458 | (setcdr plist-1 (ses-plist-delq plist-2 prop)) | ||
| 459 | plist)))) | ||
| 460 | |||
| 461 | (defvar ses--ses-buffer-list nil "A list of buffers containing a SES spreadsheet.") | ||
| 462 | |||
| 463 | (defun ses--unbind-cell-name (name) | ||
| 464 | "Make NAME non longer a renamed cell name." | ||
| 465 | (remhash name ses--named-cell-hashmap) | ||
| 466 | (kill-local-variable name) | ||
| 467 | ;; remove symbol property 'ses-cell from symbol NAME, unless this | ||
| 468 | ;; symbol is also a renamed cell name in another SES buffer. | ||
| 469 | (let (used-elsewhere (buffer-list ses--ses-buffer-list) buf) | ||
| 470 | (while buffer-list | ||
| 471 | (setq buf (pop buffer-list)) | ||
| 472 | (cond | ||
| 473 | ((eq buf (current-buffer))) | ||
| 474 | ;; This case should not happen, some SES buffer has been | ||
| 475 | ;; killed without the ses-killbuffer-hook being called. | ||
| 476 | ((null (buffer-live-p buf)) | ||
| 477 | ;; Silently repair ses--ses-buffer-list | ||
| 478 | (setq ses--ses-buffer-list (delq buf ses--ses-buffer-list))) | ||
| 479 | (t | ||
| 480 | (with-current-buffer buf | ||
| 481 | (when (gethash name ses--named-cell-hashmap) | ||
| 482 | (setq used-elsewhere t | ||
| 483 | buffer-list nil)))))) | ||
| 484 | (unless used-elsewhere | ||
| 485 | (setplist name (ses-plist-delq (symbol-plist name) 'ses-cell))) )) | ||
| 448 | 486 | ||
| 449 | (defmacro ses--letref (vars place &rest body) | 487 | (defmacro ses--letref (vars place &rest body) |
| 450 | (declare (indent 2) (debug (sexp form &rest body))) | 488 | (declare (indent 2) (debug (sexp form &rest body))) |
| @@ -1480,8 +1518,10 @@ by (ROWINCR,COLINCR)." | |||
| 1480 | col (+ col colincr)) | 1518 | col (+ col colincr)) |
| 1481 | (if (and (>= row startrow) (>= col startcol) | 1519 | (if (and (>= row startrow) (>= col startcol) |
| 1482 | (< row ses--numrows) (< col ses--numcols)) | 1520 | (< row ses--numrows) (< col ses--numcols)) |
| 1483 | ;;Relocate this variable | 1521 | ;;Relocate this variable, unless it is a named cell |
| 1484 | (ses-create-cell-symbol row col) | 1522 | (if (eq (get sym 'ses-cell) :ses-named) |
| 1523 | sym | ||
| 1524 | (ses-create-cell-symbol row col)) | ||
| 1485 | ;;Delete reference to a deleted cell | 1525 | ;;Delete reference to a deleted cell |
| 1486 | nil)))) | 1526 | nil)))) |
| 1487 | 1527 | ||
| @@ -1498,11 +1538,11 @@ removed. Example: | |||
| 1498 | Sets `ses-relocate-return' to `delete' if cell-references were removed." | 1538 | Sets `ses-relocate-return' to `delete' if cell-references were removed." |
| 1499 | (let (rowcol result) | 1539 | (let (rowcol result) |
| 1500 | (if (or (atom formula) (eq (car formula) 'quote)) | 1540 | (if (or (atom formula) (eq (car formula) 'quote)) |
| 1501 | (if (and (setq rowcol (ses-sym-rowcol formula)) | 1541 | (if (setq rowcol (ses-sym-rowcol formula)) |
| 1502 | (string-match-p "\\`[A-Z]+[0-9]+\\'" (symbol-name formula))) | ||
| 1503 | (ses-relocate-symbol formula rowcol | 1542 | (ses-relocate-symbol formula rowcol |
| 1504 | startrow startcol rowincr colincr) | 1543 | startrow startcol rowincr colincr) |
| 1505 | formula) ; Pass through as-is. | 1544 | ;; Constants pass through as-is. |
| 1545 | formula) | ||
| 1506 | (dolist (cur formula) | 1546 | (dolist (cur formula) |
| 1507 | (setq rowcol (ses-sym-rowcol cur)) | 1547 | (setq rowcol (ses-sym-rowcol cur)) |
| 1508 | (cond | 1548 | (cond |
| @@ -1531,7 +1571,7 @@ Sets `ses-relocate-return' to `delete' if cell-references were removed." | |||
| 1531 | (nreverse result)))) | 1571 | (nreverse result)))) |
| 1532 | 1572 | ||
| 1533 | (defun ses-relocate-range (range startrow startcol rowincr colincr) | 1573 | (defun ses-relocate-range (range startrow startcol rowincr colincr) |
| 1534 | "Relocate one RANGE, of the form (SES-RANGE MIN MAX). Cells starting | 1574 | "Relocate one RANGE, of the form (ses-range MIN MAX). Cells starting |
| 1535 | at (STARTROW,STARTCOL) are being shifted by (ROWINCR,COLINCR). Result is the | 1575 | at (STARTROW,STARTCOL) are being shifted by (ROWINCR,COLINCR). Result is the |
| 1536 | new range, or nil if the entire range is deleted. If new rows are being added | 1576 | new range, or nil if the entire range is deleted. If new rows are being added |
| 1537 | just beyond the end of a row range, or new columns just beyond a column range, | 1577 | just beyond the end of a row range, or new columns just beyond a column range, |
| @@ -1637,14 +1677,15 @@ to each symbol." | |||
| 1637 | sym | 1677 | sym |
| 1638 | (>= xrow 0) | 1678 | (>= xrow 0) |
| 1639 | (>= xcol 0) | 1679 | (>= xcol 0) |
| 1640 | (null (eq sym | 1680 | ;; the following could also be tested as |
| 1641 | (ses-create-cell-symbol xrow xcol)))) | 1681 | ;; (null (eq sym (ses-create-cell-symbol xrow xcol))) |
| 1682 | (eq (get sym 'ses-cell) :ses-named)) | ||
| 1642 | ;; This is a renamed cell, do not update the cell | 1683 | ;; This is a renamed cell, do not update the cell |
| 1643 | ;; name, but just update the coordinate property. | 1684 | ;; name, but just update the coordinate property. |
| 1644 | (put sym 'ses-cell (cons row col)) | 1685 | (puthash sym (cons row col) ses--named-cell-hashmap) |
| 1645 | (ses-set-cell row col 'symbol | 1686 | (ses-set-cell row col 'symbol |
| 1646 | (setq sym (ses-create-cell-symbol row col))) | 1687 | (setq sym (ses-create-cell-symbol row col))) |
| 1647 | (unless (and (boundp sym) (local-variable-p sym)) | 1688 | (unless (local-variable-if-set-p sym) |
| 1648 | (set (make-local-variable sym) nil) | 1689 | (set (make-local-variable sym) nil) |
| 1649 | (put sym 'ses-cell (cons row col)))))) ))) | 1690 | (put sym 'ses-cell (cons row col)))))) ))) |
| 1650 | ;; Relocate the cell values. | 1691 | ;; Relocate the cell values. |
| @@ -1659,16 +1700,22 @@ to each symbol." | |||
| 1659 | (setq mycol (+ col mincol) | 1700 | (setq mycol (+ col mincol) |
| 1660 | xrow (- myrow rowincr) | 1701 | xrow (- myrow rowincr) |
| 1661 | xcol (- mycol colincr)) | 1702 | xcol (- mycol colincr)) |
| 1662 | (let ((sym (ses-cell-symbol myrow mycol)) | 1703 | (let ((sym (ses-cell-symbol myrow mycol))) |
| 1663 | (xsym (ses-create-cell-symbol xrow xcol))) | 1704 | ;; We don't need to relocate value for renamed cells, as they keep the same |
| 1664 | ;; Make the value relocation only when if the cell is not | 1705 | ;; symbol. |
| 1665 | ;; a renamed cell. Otherwise this is not needed. | 1706 | (unless (eq (get sym 'ses-cell) :ses-named) |
| 1666 | (and (eq sym xsym) | 1707 | (ses-set-cell myrow mycol 'value |
| 1667 | (ses-set-cell myrow mycol 'value | 1708 | (if (and (< xrow ses--numrows) (< xcol ses--numcols)) |
| 1668 | (if (and (< xrow ses--numrows) (< xcol ses--numcols)) | 1709 | (ses-cell-value xrow xcol) |
| 1669 | (ses-cell-value xrow xcol) | 1710 | ;; Cell is off the end of the array. |
| 1670 | ;;Cell is off the end of the array | 1711 | (symbol-value (ses-create-cell-symbol xrow xcol)))))))) |
| 1671 | (symbol-value xsym)))))))) | 1712 | (when ses--in-killing-named-cell-list |
| 1713 | (message "Unbinding killed named cell symbols...") | ||
| 1714 | (setq ses-start-time (float-time)) | ||
| 1715 | (while ses--in-killing-named-cell-list | ||
| 1716 | (ses--time-check "Unbinding killed named cell symbols... (%d left)" (length ses--in-killing-named-cell-list)) | ||
| 1717 | (ses--unbind-cell-name (pop ses--in-killing-named-cell-list)) ) | ||
| 1718 | (message nil)) ) | ||
| 1672 | 1719 | ||
| 1673 | ((and (wholenump rowincr) (wholenump colincr)) | 1720 | ((and (wholenump rowincr) (wholenump colincr)) |
| 1674 | ;; Insertion of rows and/or columns. Run the loop backwards. | 1721 | ;; Insertion of rows and/or columns. Run the loop backwards. |
| @@ -1926,6 +1973,11 @@ Delete overlays, remove special text properties." | |||
| 1926 | (unless was-modified | 1973 | (unless was-modified |
| 1927 | (restore-buffer-modified-p nil)))) | 1974 | (restore-buffer-modified-p nil)))) |
| 1928 | 1975 | ||
| 1976 | (defun ses-killbuffer-hook () | ||
| 1977 | "Hook when the current buffer is killed." | ||
| 1978 | (setq ses--ses-buffer-list (delq (current-buffer) ses--ses-buffer-list))) | ||
| 1979 | |||
| 1980 | |||
| 1929 | ;;;###autoload | 1981 | ;;;###autoload |
| 1930 | (defun ses-mode () | 1982 | (defun ses-mode () |
| 1931 | "Major mode for Simple Emacs Spreadsheet. | 1983 | "Major mode for Simple Emacs Spreadsheet. |
| @@ -1980,6 +2032,8 @@ formula: | |||
| 1980 | ;; calculation). | 2032 | ;; calculation). |
| 1981 | indent-tabs-mode nil) | 2033 | indent-tabs-mode nil) |
| 1982 | (1value (add-hook 'change-major-mode-hook 'ses-cleanup nil t)) | 2034 | (1value (add-hook 'change-major-mode-hook 'ses-cleanup nil t)) |
| 2035 | (1value (add-hook 'kill-buffer-hook 'ses-killbuffer-hook nil t)) | ||
| 2036 | (cl-pushnew (current-buffer) ses--ses-buffer-list :test 'eq) | ||
| 1983 | ;; This makes revert impossible if the buffer is read-only. | 2037 | ;; This makes revert impossible if the buffer is read-only. |
| 1984 | ;; (1value (add-hook 'before-revert-hook 'ses-cleanup nil t)) | 2038 | ;; (1value (add-hook 'before-revert-hook 'ses-cleanup nil t)) |
| 1985 | (setq header-line-format '(:eval (progn | 2039 | (setq header-line-format '(:eval (progn |
| @@ -2626,6 +2680,20 @@ With prefix, deletes COUNT rows starting from the current one." | |||
| 2626 | ;;Delete lines from cell data area | 2680 | ;;Delete lines from cell data area |
| 2627 | (ses-goto-data row 0) | 2681 | (ses-goto-data row 0) |
| 2628 | (ses-delete-line (* count (1+ ses--numcols))) | 2682 | (ses-delete-line (* count (1+ ses--numcols))) |
| 2683 | ;; Collect named cells in the deleted rows, in order to clean the | ||
| 2684 | ;; symbols out of the named cell hash map, once the deletion is | ||
| 2685 | ;; complete | ||
| 2686 | (unless (null ses--in-killing-named-cell-list) | ||
| 2687 | (warn "Internal error, `ses--in-killing-named-cell-list' should be nil, but is equal to %S" | ||
| 2688 | ses--in-killing-named-cell-list) | ||
| 2689 | (setq ses--in-killing-named-cell-list nil)) | ||
| 2690 | (dotimes-with-progress-reporter (nrow count) | ||
| 2691 | "Collecting named cell in deleted rows..." | ||
| 2692 | (dotimes (col ses--numcols) | ||
| 2693 | (let* ((row (+ row nrow)) | ||
| 2694 | (sym (ses-cell-symbol row col))) | ||
| 2695 | (and (eq (get sym 'ses-cell) :ses-named) | ||
| 2696 | (push sym ses--in-killing-named-cell-list))))) | ||
| 2629 | ;;Relocate variables and formulas | 2697 | ;;Relocate variables and formulas |
| 2630 | (ses-set-with-undo 'ses--cells (ses-vector-delete ses--cells row count)) | 2698 | (ses-set-with-undo 'ses--cells (ses-vector-delete ses--cells row count)) |
| 2631 | (ses-relocate-all row 0 (- count) 0) | 2699 | (ses-relocate-all row 0 (- count) 0) |
| @@ -2723,10 +2791,22 @@ With prefix, deletes COUNT columns starting from the current one." | |||
| 2723 | (ses-begin-change) | 2791 | (ses-begin-change) |
| 2724 | (ses-set-parameter 'ses--numcols (- ses--numcols count)) | 2792 | (ses-set-parameter 'ses--numcols (- ses--numcols count)) |
| 2725 | (ses-adjust-print-width col (- width)) | 2793 | (ses-adjust-print-width col (- width)) |
| 2794 | ;; Prepare collecting named cells in the deleted columns, in order | ||
| 2795 | ;; to clean the symbols out of the named cell hash map, once the | ||
| 2796 | ;; deletion is complete | ||
| 2797 | (unless (null ses--in-killing-named-cell-list) | ||
| 2798 | (warn "Internal error, `ses--in-killing-named-cell-list' should be nil, but is equal to %S" | ||
| 2799 | ses--in-killing-named-cell-list) | ||
| 2800 | (setq ses--in-killing-named-cell-list nil)) | ||
| 2726 | (dotimes-with-progress-reporter (row ses--numrows) "Deleting column..." | 2801 | (dotimes-with-progress-reporter (row ses--numrows) "Deleting column..." |
| 2727 | ;;Delete lines from cell data area | 2802 | ;;Delete lines from cell data area |
| 2728 | (ses-goto-data row col) | 2803 | (ses-goto-data row col) |
| 2729 | (ses-delete-line count) | 2804 | (ses-delete-line count) |
| 2805 | ;; Collect named cells in the deleted columns within this row | ||
| 2806 | (dotimes (ncol count) | ||
| 2807 | (let ((sym (ses-cell-symbol row (+ col ncol)))) | ||
| 2808 | (and (eq (get sym 'ses-cell) :ses-named) | ||
| 2809 | (push sym ses--in-killing-named-cell-list)))) | ||
| 2730 | ;;Delete cells. Check if deletion area begins or ends with a skip. | 2810 | ;;Delete cells. Check if deletion area begins or ends with a skip. |
| 2731 | (if (or (eq (ses-cell-value row col) '*skip*) | 2811 | (if (or (eq (ses-cell-value row col) '*skip*) |
| 2732 | (and (< col ses--numcols) | 2812 | (and (< col ses--numcols) |
| @@ -3403,8 +3483,7 @@ highlighted range in the spreadsheet." | |||
| 3403 | (setf (ses-cell-references xcell) | 3483 | (setf (ses-cell-references xcell) |
| 3404 | (cons new-name (delq sym | 3484 | (cons new-name (delq sym |
| 3405 | (ses-cell-references xcell)))))) | 3485 | (ses-cell-references xcell)))))) |
| 3406 | (push new-name ses--renamed-cell-symb-list) | 3486 | (set (make-local-variable new-name) (symbol-value sym)) |
| 3407 | (set new-name (symbol-value sym)) | ||
| 3408 | (setf (ses-cell--symbol cell) new-name) | 3487 | (setf (ses-cell--symbol cell) new-name) |
| 3409 | (makunbound sym) | 3488 | (makunbound sym) |
| 3410 | (and curcell (setq ses--curcell new-name)) | 3489 | (and curcell (setq ses--curcell new-name)) |
| @@ -3412,12 +3491,7 @@ highlighted range in the spreadsheet." | |||
| 3412 | (or curcell (ses-goto-print row col)) | 3491 | (or curcell (ses-goto-print row col)) |
| 3413 | (let* ((pos (point)) | 3492 | (let* ((pos (point)) |
| 3414 | (inhibit-read-only t) | 3493 | (inhibit-read-only t) |
| 3415 | (end (progn | 3494 | (end (next-single-property-change pos 'cursor-intangible))) |
| 3416 | (move-to-column (+ (current-column) (ses-col-width col))) | ||
| 3417 | (if (eolp) | ||
| 3418 | (+ pos (ses-col-width col) 1) | ||
| 3419 | (forward-char) | ||
| 3420 | (point))))) | ||
| 3421 | (put-text-property pos end 'cursor-intangible new-name))) | 3495 | (put-text-property pos end 'cursor-intangible new-name))) |
| 3422 | ;; Update the cell name in the mode-line. | 3496 | ;; Update the cell name in the mode-line. |
| 3423 | (force-mode-line-update))) | 3497 | (force-mode-line-update))) |