aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Belaïche2016-01-20 08:28:06 +0100
committerVincent Belaïche2016-01-20 08:28:06 +0100
commitbadcd38aa86ed7973f2be2743c405710973a0bdd (patch)
treec335dc4a3819bc2060dd5ed1c5dd814bf7568c62
parentde8c5f9db50a22ef5640bb83c0c7c755b78be895 (diff)
downloademacs-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.el136
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
451PROP is the symbol identifying the property/value pair. PLIST may
452be 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:
1498Sets `ses-relocate-return' to `delete' if cell-references were removed." 1538Sets `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
1535at (STARTROW,STARTCOL) are being shifted by (ROWINCR,COLINCR). Result is the 1575at (STARTROW,STARTCOL) are being shifted by (ROWINCR,COLINCR). Result is the
1536new range, or nil if the entire range is deleted. If new rows are being added 1576new range, or nil if the entire range is deleted. If new rows are being added
1537just beyond the end of a row range, or new columns just beyond a column range, 1577just 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)))