diff options
| author | Vincent Belaïche | 2012-11-09 06:48:05 +0100 |
|---|---|---|
| committer | Vincent Belaïche | 2012-11-09 06:48:05 +0100 |
| commit | 93a66b3a3d1b1d19da6d3e759ebe4b9192c70efc (patch) | |
| tree | 35c63f86419899ea7c50cc220cba17376ffd712b | |
| parent | 57618ecf3358e49ab3c380330e82ca8d2078cc63 (diff) | |
| download | emacs-93a66b3a3d1b1d19da6d3e759ebe4b9192c70efc.tar.gz emacs-93a66b3a3d1b1d19da6d3e759ebe4b9192c70efc.zip | |
* ses.el: Use hash map for getting named cells coordinates.
symbol to coordinate mapping is made by symbol property
`ses-cell'. This means that the same mapping is done for all SES
sheets. That is good enough for cells with standard A1 names, but
not for named cell. So a hash map is added for those
latter.
(defconst ses-localvars): added local variable ses--named-cell-hashmap
(ses-sym-rowcol): Use hashmap for named cell.
(ses-is-cell-sym-p): New defun.
(ses-decode-cell-symbol): New defun.
(ses-create-cell-variable): Add cell to hashmap when name is not A1-like.
(ses-rename-cell): Check that cell new name is not already in
spreadsheet with the use of ses-is-cell-sym-p
(ses-rename-cell): Use hash map for named cells, but accept also
renaming back to A1-like.
| -rw-r--r-- | lisp/ChangeLog | 17 | ||||
| -rw-r--r-- | lisp/ses.el | 92 |
2 files changed, 87 insertions, 22 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index f0af63ac094..d7cb2143d36 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,20 @@ | |||
| 1 | 2012-11-09 Vincent Belaïche <vincentb1@users.sourceforge.net> | ||
| 2 | |||
| 3 | * ses.el: symbol to coordinate mapping is made by symbol property | ||
| 4 | `ses-cell'. This means that the same mapping is done for all SES | ||
| 5 | sheets. That is good enough for cells with standard A1 names, but | ||
| 6 | not for named cell. So a hash map is added for those | ||
| 7 | latter. | ||
| 8 | (defconst ses-localvars): added local variable ses--named-cell-hashmap | ||
| 9 | (ses-sym-rowcol): Use hashmap for named cell. | ||
| 10 | (ses-is-cell-sym-p): New defun. | ||
| 11 | (ses-decode-cell-symbol): New defun. | ||
| 12 | (ses-create-cell-variable): Add cell to hashmap when name is not A1-like. | ||
| 13 | (ses-rename-cell): Check that cell new name is not already in | ||
| 14 | spreadsheet with the use of ses-is-cell-sym-p | ||
| 15 | (ses-rename-cell): Use hash map for named cells, but accept also | ||
| 16 | renaming back to A1-like. | ||
| 17 | |||
| 1 | 2012-11-09 Stefan Monnier <monnier@iro.umontreal.ca> | 18 | 2012-11-09 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 19 | ||
| 3 | * emacs-lisp/advice.el: Use new dynamic docstrings. | 20 | * emacs-lisp/advice.el: Use new dynamic docstrings. |
diff --git a/lisp/ses.el b/lisp/ses.el index 7cdac74e310..27b906d22e3 100644 --- a/lisp/ses.el +++ b/lisp/ses.el | |||
| @@ -278,6 +278,7 @@ default printer and then modify its output.") | |||
| 278 | ses--default-printer | 278 | ses--default-printer |
| 279 | ses--deferred-narrow ses--deferred-recalc | 279 | ses--deferred-narrow ses--deferred-recalc |
| 280 | ses--deferred-write ses--file-format | 280 | ses--deferred-write ses--file-format |
| 281 | ses--named-cell-hashmap | ||
| 281 | (ses--header-hscroll . -1) ; Flag for "initial recalc needed" | 282 | (ses--header-hscroll . -1) ; Flag for "initial recalc needed" |
| 282 | ses--header-row ses--header-string ses--linewidth | 283 | ses--header-row ses--header-string ses--linewidth |
| 283 | ses--numcols ses--numrows ses--symbolic-formulas | 284 | ses--numcols ses--numrows ses--symbolic-formulas |
| @@ -511,9 +512,22 @@ PROPERTY-NAME." | |||
| 511 | `(aref ses--col-printers ,col)) | 512 | `(aref ses--col-printers ,col)) |
| 512 | 513 | ||
| 513 | (defmacro ses-sym-rowcol (sym) | 514 | (defmacro ses-sym-rowcol (sym) |
| 514 | "From a cell-symbol SYM, gets the cons (row . col). A1 => (0 . 0). | 515 | "From a cell-symbol SYM, gets the cons (row . col). A1 => (0 . 0). Result |
| 515 | Result is nil if SYM is not a symbol that names a cell." | 516 | is nil if SYM is not a symbol that names a cell." |
| 516 | `(and (symbolp ,sym) (get ,sym 'ses-cell))) | 517 | `(let ((rc (and (symbolp ,sym) (get ,sym 'ses-cell)))) |
| 518 | (if (eq rc :ses-named) | ||
| 519 | (gethash ,sym ses--named-cell-hashmap) | ||
| 520 | rc))) | ||
| 521 | |||
| 522 | (defun ses-is-cell-sym-p (sym) | ||
| 523 | "Check whether SYM point at a cell of this spread sheet." | ||
| 524 | (let ((rowcol (get sym 'ses-cell))) | ||
| 525 | (and rowcol | ||
| 526 | (if (eq rowcol :ses-named) | ||
| 527 | (and ses--named-cell-hashmap (gethash sym ses--named-cell-hashmap)) | ||
| 528 | (and (< (car rowcol) ses--numrows) | ||
| 529 | (< (cdr rowcol) ses--numcols) | ||
| 530 | (eq (ses-cell-symbol (car rowcol) (cdr rowcol)) sym)))))) | ||
| 517 | 531 | ||
| 518 | (defmacro ses-cell (sym value formula printer references) | 532 | (defmacro ses-cell (sym value formula printer references) |
| 519 | "Load a cell SYM from the spreadsheet file. Does not recompute VALUE from | 533 | "Load a cell SYM from the spreadsheet file. Does not recompute VALUE from |
| @@ -682,6 +696,28 @@ for this spreadsheet." | |||
| 682 | "Produce a symbol that names the cell (ROW,COL). (0,0) => 'A1." | 696 | "Produce a symbol that names the cell (ROW,COL). (0,0) => 'A1." |
| 683 | (intern (concat (ses-column-letter col) (number-to-string (1+ row))))) | 697 | (intern (concat (ses-column-letter col) (number-to-string (1+ row))))) |
| 684 | 698 | ||
| 699 | (defun ses-decode-cell-symbol (str) | ||
| 700 | "Decode a symbol \"A1\" => (0,0). Returns `nil' if STR is not a | ||
| 701 | canonical cell name. Does not save match data." | ||
| 702 | (let (case-fold-search) | ||
| 703 | (and (string-match "\\`\\([A-Z]+\\)\\([0-9]+\\)\\'" str) | ||
| 704 | (let* ((col-str (match-string-no-properties 1 str)) | ||
| 705 | (col 0) | ||
| 706 | (col-offset 0) | ||
| 707 | (col-base 1) | ||
| 708 | (col-idx (1- (length col-str))) | ||
| 709 | (row (1- (string-to-number (match-string-no-properties 2 str))))) | ||
| 710 | (and (>= row 0) | ||
| 711 | (progn | ||
| 712 | (while | ||
| 713 | (progn | ||
| 714 | (setq col (+ col (* (- (aref col-str col-idx) ?A) col-base)) | ||
| 715 | col-base (* col-base 26) | ||
| 716 | col-idx (1- col-idx)) | ||
| 717 | (and (>= col-idx 0) | ||
| 718 | (setq col (+ col col-base))))) | ||
| 719 | (cons row col))))))) | ||
| 720 | |||
| 685 | (defun ses-create-cell-variable-range (minrow maxrow mincol maxcol) | 721 | (defun ses-create-cell-variable-range (minrow maxrow mincol maxcol) |
| 686 | "Create buffer-local variables for cells. This is undoable." | 722 | "Create buffer-local variables for cells. This is undoable." |
| 687 | (push `(apply ses-destroy-cell-variable-range ,minrow ,maxrow ,mincol ,maxcol) | 723 | (push `(apply ses-destroy-cell-variable-range ,minrow ,maxrow ,mincol ,maxcol) |
| @@ -704,7 +740,11 @@ row and column of the cell, with numbering starting from 0. | |||
| 704 | Return nil in case of failure." | 740 | Return nil in case of failure." |
| 705 | (unless (local-variable-p sym) | 741 | (unless (local-variable-p sym) |
| 706 | (make-local-variable sym) | 742 | (make-local-variable sym) |
| 707 | (put sym 'ses-cell (cons row col)))) | 743 | (if (let (case-fold-search) (string-match "\\`[A-Z]+[0-9]+\\'" (symbol-name sym))) |
| 744 | (put sym 'ses-cell (cons row col)) | ||
| 745 | (put sym 'ses-cell :ses-named) | ||
| 746 | (setq ses--named-cell-hashmap (or ses--named-cell-hashmap (make-hash-table :test 'eq))) | ||
| 747 | (puthash sym (cons row col) ses--named-cell-hashmap)))) | ||
| 708 | 748 | ||
| 709 | ;; We do not delete the ses-cell properties for the cell-variables, in | 749 | ;; We do not delete the ses-cell properties for the cell-variables, in |
| 710 | ;; case a formula that refers to this cell is in the kill-ring and is | 750 | ;; case a formula that refers to this cell is in the kill-ring and is |
| @@ -3211,27 +3251,36 @@ highlighted range in the spreadsheet." | |||
| 3211 | (defun ses-rename-cell (new-name &optional cell) | 3251 | (defun ses-rename-cell (new-name &optional cell) |
| 3212 | "Rename current cell." | 3252 | "Rename current cell." |
| 3213 | (interactive "*SEnter new name: ") | 3253 | (interactive "*SEnter new name: ") |
| 3214 | (and (local-variable-p new-name) | 3254 | (or |
| 3215 | (ses-sym-rowcol new-name) | 3255 | (and (local-variable-p new-name) |
| 3216 | ;; this test is needed because ses-cell property of deleted cells | 3256 | (ses-is-cell-sym-p new-name) |
| 3217 | ;; is not deleted in case of subsequent undo | 3257 | (error "Already a cell name")) |
| 3218 | (memq new-name ses--renamed-cell-symb-list) | 3258 | (and (boundp new-name) |
| 3219 | (error "Already a cell name")) | 3259 | (null (yes-or-no-p (format "`%S' is already bound outside this buffer, continue? " |
| 3220 | (and (boundp new-name) | 3260 | new-name))) |
| 3221 | (null (yes-or-no-p (format "`%S' is already bound outside this buffer, continue? " | 3261 | (error "Already a bound cell name"))) |
| 3222 | new-name))) | 3262 | (let* (curcell |
| 3223 | (error "Already a bound cell name")) | 3263 | (sym (if (ses-cell-p cell) |
| 3224 | (let* ((sym (if (ses-cell-p cell) | ||
| 3225 | (ses-cell-symbol cell) | 3264 | (ses-cell-symbol cell) |
| 3226 | (setq cell nil) | 3265 | (setq cell nil |
| 3266 | curcell t) | ||
| 3227 | (ses-check-curcell) | 3267 | (ses-check-curcell) |
| 3228 | ses--curcell)) | 3268 | ses--curcell)) |
| 3229 | (rowcol (ses-sym-rowcol sym)) | 3269 | (rowcol (ses-sym-rowcol sym)) |
| 3230 | (row (car rowcol)) | 3270 | (row (car rowcol)) |
| 3231 | (col (cdr rowcol))) | 3271 | (col (cdr rowcol)) |
| 3232 | (setq cell (or cell (ses-get-cell row col))) | 3272 | new-rowcol old-name) |
| 3233 | (push `(ses-rename-cell ,(ses-cell-symbol cell) ,cell) buffer-undo-list) | 3273 | (setq cell (or cell (ses-get-cell row col)) |
| 3234 | (put new-name 'ses-cell rowcol) | 3274 | old-name (ses-cell-symbol cell) |
| 3275 | new-rowcol (ses-decode-cell-symbol (symbol-name new-name))) | ||
| 3276 | (if new-rowcol | ||
| 3277 | (if (equal new-rowcol rowcol) | ||
| 3278 | (put new-name 'ses-cell rowcol) | ||
| 3279 | (error "Not a valid name for this cell location")) | ||
| 3280 | (setq ses--named-cell-hashmap (or ses--named-cell-hashmap (make-hash-table :test 'eq))) | ||
| 3281 | (put new-name 'ses-cell :ses-named) | ||
| 3282 | (puthash new-name rowcol ses--named-cell-hashmap)) | ||
| 3283 | (push `(ses-rename-cell ,old-name ,cell) buffer-undo-list) | ||
| 3235 | ;; replace name by new name in formula of cells refering to renamed cell | 3284 | ;; replace name by new name in formula of cells refering to renamed cell |
| 3236 | (dolist (ref (ses-cell-references cell)) | 3285 | (dolist (ref (ses-cell-references cell)) |
| 3237 | (let* ((x (ses-sym-rowcol ref)) | 3286 | (let* ((x (ses-sym-rowcol ref)) |
| @@ -3251,9 +3300,8 @@ highlighted range in the spreadsheet." | |||
| 3251 | (push new-name ses--renamed-cell-symb-list) | 3300 | (push new-name ses--renamed-cell-symb-list) |
| 3252 | (set new-name (symbol-value sym)) | 3301 | (set new-name (symbol-value sym)) |
| 3253 | (aset cell 0 new-name) | 3302 | (aset cell 0 new-name) |
| 3254 | (put sym 'ses-cell nil) | ||
| 3255 | (makunbound sym) | 3303 | (makunbound sym) |
| 3256 | (setq sym new-name) | 3304 | (and curcell (setq ses--curcell new-name)) |
| 3257 | (let* ((pos (point)) | 3305 | (let* ((pos (point)) |
| 3258 | (inhibit-read-only t) | 3306 | (inhibit-read-only t) |
| 3259 | (col (current-column)) | 3307 | (col (current-column)) |