diff options
| author | Stefan Monnier | 2014-06-15 00:10:40 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2014-06-15 00:10:40 -0400 |
| commit | df5703a00d610a89fa6bc1da906228907b36b5d8 (patch) | |
| tree | 037d32ed58ad5c713baa21d64632c94c5d4a7839 | |
| parent | e52868b16f33eb31cbe912f1ebc98136c5743238 (diff) | |
| download | emacs-df5703a00d610a89fa6bc1da906228907b36b5d8.tar.gz emacs-df5703a00d610a89fa6bc1da906228907b36b5d8.zip | |
* lisp/ses.el: Miscellaneous cleanups; use lexical-binding; avoid add-to-list.
(ses-localvars): Remove ses--local-printer-list, unused.
(ses--metaprogramming): New macro. Use it to defvar variables.
(ses-set-localvars): Simplify.
(ses--locprn, ses-cell): Use defstruct. Change ses-cell's
property-list into an alist.
(ses-locprn-get-compiled, ses-locprn-compiled-aset)
(ses-locprn-get-def, ses-locprn-def-aset, ses-locprn-get-number):
Remove; use defstruct accessors/setters instead.
(ses-cell-formula-aset, ses-cell-printer-aset)
(ses-cell-references-aset): Remove, use setf instead.
(ses--alist-get): New function.
(ses-cell-property): Rename from ses-cell-property-get and rewrite.
Use an alist instead of a plist and don't do move-to-front since the
list is always short.
(ses-cell-property-get-fun, ses-cell-property-delq-fun)
(ses-cell-property-set-fun, ses-cell-property-set)
(ses-cell-property-pop-fun, ses-cell-property-get-handle)
(ses-cell-property-handle-car, ses-cell-property-handle-setcar): Remove.
(ses--letref): New macro.
(ses-cell-property-pop): Rewrite.
(ses--cell): Rename from ses-cell and make it into a function.
Make `formula' fallback on `value' if nil.
(ses--local-printer): Rename from ses-local-printer and make it into
a function.
(ses-set-cell): Turn it into a macro so finding the accessor from the
field name is done at compile time.
(ses-repair-cell-reference-all): Test presence of `sym' rather than
`ref' before adding `sym' to :ses-repair-reference.
(ses-calculate-cell): Use ses--letref rather than
ses-cell-property-get-handle.
(ses-write-cells): Use a single prin1-to-string.
(ses-setter-with-undo): New function.
(ses-aset-with-undo, ses-set-with-undo): Rewrite using it.
(ses-unset-with-undo): Remove.
(ses-load): Prefer apply' over `eval'.
(ses-read-printer, ses-set-column-width): Use standard "(default
foo)" format.
| -rw-r--r-- | lisp/ChangeLog | 42 | ||||
| -rw-r--r-- | lisp/ses.el | 742 |
2 files changed, 375 insertions, 409 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 8cb58bde25c..c243c6ea3ef 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,45 @@ | |||
| 1 | 2014-06-15 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * ses.el: Miscellaneous cleanups; use lexical-binding; avoid | ||
| 4 | add-to-list. | ||
| 5 | (ses-localvars): Remove ses--local-printer-list, unused. | ||
| 6 | (ses--metaprogramming): New macro. Use it to defvar variables. | ||
| 7 | (ses-set-localvars): Simplify. | ||
| 8 | (ses--locprn, ses-cell): Use defstruct. Change ses-cell's | ||
| 9 | property-list into an alist. | ||
| 10 | (ses-locprn-get-compiled, ses-locprn-compiled-aset) | ||
| 11 | (ses-locprn-get-def, ses-locprn-def-aset, ses-locprn-get-number): | ||
| 12 | Remove; use defstruct accessors/setters instead. | ||
| 13 | (ses-cell-formula-aset, ses-cell-printer-aset) | ||
| 14 | (ses-cell-references-aset): Remove, use setf instead. | ||
| 15 | (ses--alist-get): New function. | ||
| 16 | (ses-cell-property): Rename from ses-cell-property-get and rewrite. | ||
| 17 | Use an alist instead of a plist and don't do move-to-front since the | ||
| 18 | list is always short. | ||
| 19 | (ses-cell-property-get-fun, ses-cell-property-delq-fun) | ||
| 20 | (ses-cell-property-set-fun, ses-cell-property-set) | ||
| 21 | (ses-cell-property-pop-fun, ses-cell-property-get-handle) | ||
| 22 | (ses-cell-property-handle-car, ses-cell-property-handle-setcar): Remove. | ||
| 23 | (ses--letref): New macro. | ||
| 24 | (ses-cell-property-pop): Rewrite. | ||
| 25 | (ses--cell): Rename from ses-cell and make it into a function. | ||
| 26 | Make `formula' fallback on `value' if nil. | ||
| 27 | (ses--local-printer): Rename from ses-local-printer and make it into | ||
| 28 | a function. | ||
| 29 | (ses-set-cell): Turn it into a macro so finding the accessor from the | ||
| 30 | field name is done at compile time. | ||
| 31 | (ses-repair-cell-reference-all): Test presence of `sym' rather than | ||
| 32 | `ref' before adding `sym' to :ses-repair-reference. | ||
| 33 | (ses-calculate-cell): Use ses--letref rather than | ||
| 34 | ses-cell-property-get-handle. | ||
| 35 | (ses-write-cells): Use a single prin1-to-string. | ||
| 36 | (ses-setter-with-undo): New function. | ||
| 37 | (ses-aset-with-undo, ses-set-with-undo): Rewrite using it. | ||
| 38 | (ses-unset-with-undo): Remove. | ||
| 39 | (ses-load): Prefer apply' over `eval'. | ||
| 40 | (ses-read-printer, ses-set-column-width): Use standard "(default | ||
| 41 | foo)" format. | ||
| 42 | |||
| 1 | 2014-06-15 Glenn Morris <rgm@gnu.org> | 43 | 2014-06-15 Glenn Morris <rgm@gnu.org> |
| 2 | 44 | ||
| 3 | * Makefile.in (leim, semantic): Use `make -C' rather than `cd && make'. | 45 | * Makefile.in (leim, semantic): Use `make -C' rather than `cd && make'. |
diff --git a/lisp/ses.el b/lisp/ses.el index c7c39e0a5eb..a4f5609575d 100644 --- a/lisp/ses.el +++ b/lisp/ses.el | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | ;;; ses.el -- Simple Emacs Spreadsheet -*- coding: utf-8 -*- | 1 | ;;; ses.el -- Simple Emacs Spreadsheet -*- lexical-binding:t -*- |
| 2 | 2 | ||
| 3 | ;; Copyright (C) 2002-2014 Free Software Foundation, Inc. | 3 | ;; Copyright (C) 2002-2014 Free Software Foundation, Inc. |
| 4 | 4 | ||
| @@ -282,10 +282,6 @@ default printer and then modify its output.") | |||
| 282 | ses--col-widths ses--curcell ses--curcell-overlay | 282 | ses--col-widths ses--curcell ses--curcell-overlay |
| 283 | ses--default-printer | 283 | ses--default-printer |
| 284 | (ses--local-printer-hashmap . :hashmap) | 284 | (ses--local-printer-hashmap . :hashmap) |
| 285 | ;; the list is there to remember the order of local printers like there | ||
| 286 | ;; are written to the SES filen which service the hashmap does not | ||
| 287 | ;; provide. | ||
| 288 | ses--local-printer-list | ||
| 289 | (ses--numlocprn . 0); count of local printers | 285 | (ses--numlocprn . 0); count of local printers |
| 290 | ses--deferred-narrow ses--deferred-recalc | 286 | ses--deferred-narrow ses--deferred-recalc |
| 291 | ses--deferred-write ses--file-format | 287 | ses--deferred-write ses--file-format |
| @@ -300,8 +296,12 @@ default printer and then modify its output.") | |||
| 300 | ses--renamed-cell-symb-list | 296 | ses--renamed-cell-symb-list |
| 301 | ;; Global variables that we override | 297 | ;; Global variables that we override |
| 302 | mode-line-process next-line-add-newlines transient-mark-mode) | 298 | mode-line-process next-line-add-newlines transient-mark-mode) |
| 303 | "Buffer-local variables used by SES.") | 299 | "Buffer-local variables used by SES.")) |
| 304 | 300 | ||
| 301 | (defmacro ses--metaprogramming (exp) (declare (debug t)) (eval exp t)) | ||
| 302 | (ses--metaprogramming | ||
| 303 | `(progn ,@(mapcar (lambda (x) `(defvar ,(or (car-safe x) x))) ses-localvars))) | ||
| 304 | |||
| 305 | (defun ses-set-localvars () | 305 | (defun ses-set-localvars () |
| 306 | "Set buffer-local and initialize some SES variables." | 306 | "Set buffer-local and initialize some SES variables." |
| 307 | (dolist (x ses-localvars) | 307 | (dolist (x ses-localvars) |
| @@ -313,20 +313,10 @@ default printer and then modify its output.") | |||
| 313 | ((integerp (cdr x)) | 313 | ((integerp (cdr x)) |
| 314 | (set (make-local-variable (car x)) (cdr x))) | 314 | (set (make-local-variable (car x)) (cdr x))) |
| 315 | ((eq (cdr x) :hashmap) | 315 | ((eq (cdr x) :hashmap) |
| 316 | (set (make-local-variable (car x)) | 316 | (set (make-local-variable (car x)) (make-hash-table :test 'eq))) |
| 317 | (if (boundp (car x)) | ||
| 318 | (let ((xv (symbol-value (car x)))) | ||
| 319 | (if (hash-table-p xv) | ||
| 320 | (clrhash xv) | ||
| 321 | (warn "Unexpected value of symbol %S, should be a hash table" x) | ||
| 322 | (make-hash-table :test 'eq))) | ||
| 323 | (make-hash-table :test 'eq)))) | ||
| 324 | (t (error "Unexpected initializer `%S' in list `ses-localvars' for entry %S" | 317 | (t (error "Unexpected initializer `%S' in list `ses-localvars' for entry %S" |
| 325 | (cdr x) (car x)) ) )) | 318 | (cdr x) (car x)) ) )) |
| 326 | (t (error "Unexpected elements `%S' in list `ses-localvars'" x)))))) | 319 | (t (error "Unexpected elements `%S' in list `ses-localvars'" x))))) |
| 327 | |||
| 328 | (eval-when-compile ; silence compiler | ||
| 329 | (ses-set-localvars)) | ||
| 330 | 320 | ||
| 331 | ;;; This variable is documented as being permitted in file-locals: | 321 | ;;; This variable is documented as being permitted in file-locals: |
| 332 | (put 'ses--symbolic-formulas 'safe-local-variable 'consp) | 322 | (put 'ses--symbolic-formulas 'safe-local-variable 'consp) |
| @@ -381,186 +371,115 @@ when to emit a progress message.") | |||
| 381 | 371 | ||
| 382 | (defmacro ses-get-cell (row col) | 372 | (defmacro ses-get-cell (row col) |
| 383 | "Return the cell structure that stores information about cell (ROW,COL)." | 373 | "Return the cell structure that stores information about cell (ROW,COL)." |
| 374 | (declare (debug t)) | ||
| 384 | `(aref (aref ses--cells ,row) ,col)) | 375 | `(aref (aref ses--cells ,row) ,col)) |
| 385 | 376 | ||
| 386 | ;; We might want to use defstruct here, but cells are explicitly used as | 377 | (cl-defstruct (ses-cell |
| 387 | ;; arrays in ses-set-cell, so we'd need to fix this first. --Stef | 378 | (:constructor nil) |
| 388 | (defsubst ses-make-cell (&optional symbol formula printer references | 379 | (:constructor ses-make-cell |
| 389 | property-list) | 380 | (&optional symbol formula printer references)) |
| 390 | (vector symbol formula printer references property-list)) | 381 | (:copier nil) |
| 391 | 382 | ;; This is treated as an 4-elem array in various places. | |
| 392 | (defsubst ses-make-local-printer-info (def &optional compiled-def number) | 383 | ;; Mostly in ses-set-cell. |
| 393 | (let ((v (vector def | 384 | (:type vector) ;Not named. |
| 394 | (or compiled-def (ses-local-printer-compile def)) | 385 | (:conc-name ses-cell--)) |
| 395 | (or number ses--numlocprn) | 386 | symbol formula printer references properties) |
| 396 | nil))) | 387 | |
| 397 | (push v ses--local-printer-list) | 388 | (cl-defstruct (ses--locprn |
| 398 | (aset v 3 ses--local-printer-list) | 389 | (:constructor) |
| 399 | v)) | 390 | (:constructor ses-make-local-printer-info |
| 400 | 391 | (def &optional (compiled (ses-local-printer-compile def)) | |
| 401 | (defmacro ses-locprn-get-compiled (locprn) | 392 | (number ses--numlocprn)))) |
| 402 | `(aref ,locprn 1)) | 393 | def |
| 403 | 394 | compiled | |
| 404 | (defmacro ses-locprn-compiled-aset (locprn compiled) | 395 | number |
| 405 | `(aset ,locprn 1 ,compiled)) | 396 | local-printer-list) |
| 406 | |||
| 407 | (defmacro ses-locprn-get-def (locprn) | ||
| 408 | `(aref ,locprn 0)) | ||
| 409 | |||
| 410 | (defmacro ses-locprn-def-aset (locprn def) | ||
| 411 | `(aset ,locprn 0 ,def)) | ||
| 412 | |||
| 413 | (defmacro ses-locprn-get-number (locprn) | ||
| 414 | `(aref ,locprn 2)) | ||
| 415 | 397 | ||
| 416 | (defmacro ses-cell-symbol (row &optional col) | 398 | (defmacro ses-cell-symbol (row &optional col) |
| 417 | "From a CELL or a pair (ROW,COL), get the symbol that names the local-variable holding its value. (0,0) => A1." | 399 | "From a CELL or a pair (ROW,COL), get the symbol that names the local-variable holding its value. (0,0) => A1." |
| 418 | `(aref ,(if col `(ses-get-cell ,row ,col) row) 0)) | 400 | (declare (debug t)) |
| 401 | `(ses-cell--symbol ,(if col `(ses-get-cell ,row ,col) row))) | ||
| 419 | (put 'ses-cell-symbol 'safe-function t) | 402 | (put 'ses-cell-symbol 'safe-function t) |
| 420 | 403 | ||
| 421 | (defmacro ses-cell-formula (row &optional col) | 404 | (defmacro ses-cell-formula (row &optional col) |
| 422 | "From a CELL or a pair (ROW,COL), get the function that computes its value." | 405 | "From a CELL or a pair (ROW,COL), get the function that computes its value." |
| 423 | `(aref ,(if col `(ses-get-cell ,row ,col) row) 1)) | 406 | (declare (debug t)) |
| 424 | 407 | `(ses-cell--formula ,(if col `(ses-get-cell ,row ,col) row))) | |
| 425 | (defmacro ses-cell-formula-aset (cell formula) | ||
| 426 | "From a CELL set the function that computes its value." | ||
| 427 | `(aset ,cell 1 ,formula)) | ||
| 428 | 408 | ||
| 429 | (defmacro ses-cell-printer (row &optional col) | 409 | (defmacro ses-cell-printer (row &optional col) |
| 430 | "From a CELL or a pair (ROW,COL), get the function that prints its value." | 410 | "From a CELL or a pair (ROW,COL), get the function that prints its value." |
| 431 | `(aref ,(if col `(ses-get-cell ,row ,col) row) 2)) | 411 | (declare (debug t)) |
| 432 | 412 | `(ses-cell--printer ,(if col `(ses-get-cell ,row ,col) row))) | |
| 433 | (defmacro ses-cell-printer-aset (cell printer) | ||
| 434 | "From a CELL set the printer that prints its value." | ||
| 435 | `(aset ,cell 2 ,printer)) | ||
| 436 | 413 | ||
| 437 | (defmacro ses-cell-references (row &optional col) | 414 | (defmacro ses-cell-references (row &optional col) |
| 438 | "From a CELL or a pair (ROW,COL), get the list of symbols for cells whose | 415 | "From a CELL or a pair (ROW,COL), get the list of symbols for cells whose |
| 439 | functions refer to its value." | 416 | functions refer to its value." |
| 440 | `(aref ,(if col `(ses-get-cell ,row ,col) row) 3)) | 417 | (declare (debug t)) |
| 441 | 418 | `(ses-cell--references ,(if col `(ses-get-cell ,row ,col) row))) | |
| 442 | (defmacro ses-cell-references-aset (cell references) | ||
| 443 | "From a CELL set the list REFERENCES of symbols for cells the | ||
| 444 | function of which refer to its value." | ||
| 445 | `(aset ,cell 3 ,references)) | ||
| 446 | 419 | ||
| 447 | (defun ses-cell-p (cell) | 420 | (defun ses-cell-p (cell) |
| 448 | "Return non `nil' is CELL is a cell of current buffer." | 421 | "Return non-nil if CELL is a cell of current buffer." |
| 449 | (and (vectorp cell) | 422 | (and (vectorp cell) |
| 450 | (= (length cell) 5) | 423 | (= (length cell) 5) |
| 451 | (eq cell (let ((rowcol (ses-sym-rowcol (ses-cell-symbol cell)))) | 424 | (eq cell (let ((rowcol (ses-sym-rowcol (ses-cell-symbol cell)))) |
| 452 | (and (consp rowcol) | 425 | (and (consp rowcol) |
| 453 | (ses-get-cell (car rowcol) (cdr rowcol))))))) | 426 | (ses-get-cell (car rowcol) (cdr rowcol))))))) |
| 454 | 427 | ||
| 455 | (defun ses-cell-property-get-fun (property-name cell) | 428 | |
| 456 | ;; To speed up property fetching, each time a property is found it is placed | 429 | (defun ses--alist-get (key alist &optional remove) |
| 457 | ;; in the first position. This way, after the first get, the full property | 430 | "Get the value associated to KEY in ALIST." |
| 458 | ;; list needs to be scanned only when the property does not exist for that | 431 | (declare |
| 459 | ;; cell. | 432 | (gv-expander |
| 460 | (let* ((plist (aref cell 4)) | 433 | (lambda (do) |
| 461 | (ret (plist-member plist property-name))) | 434 | (macroexp-let2 macroexp-copyable-p k key |
| 462 | (if ret | 435 | (gv-letplace (getter setter) alist |
| 463 | ;; Property was found. | 436 | (macroexp-let2 nil p `(assq ,k ,getter) |
| 464 | (let ((val (cadr ret))) | 437 | (funcall do `(cdr ,p) |
| 465 | (if (eq ret plist) | 438 | (lambda (v) |
| 466 | ;; Property found is already in the first position, so just return | 439 | (let ((set-exp |
| 467 | ;; its value. | 440 | `(if ,p (setcdr ,p ,v) |
| 468 | val | 441 | ,(funcall setter |
| 469 | ;; Property is not in the first position, the following will move it | 442 | `(cons (setq ,p (cons ,k ,v)) |
| 470 | ;; there before returning its value. | 443 | ,getter))))) |
| 471 | (let ((next (cddr ret))) | 444 | (cond |
| 472 | (if next | 445 | ((null remove) set-exp) |
| 473 | (progn | 446 | ((null v) |
| 474 | (setcdr ret (cdr next)) | 447 | `(if ,p ,(funcall setter `(delq ,p ,getter)))) |
| 475 | (setcar ret (car next))) | 448 | (t |
| 476 | (setcdr (last plist 1) nil))) | 449 | `(cond |
| 477 | (aset cell 4 | 450 | (,v ,set-exp) |
| 478 | `(,property-name ,val ,@plist)) | 451 | (,p ,(funcall setter |
| 479 | val))))) | 452 | `(delq ,p ,getter))))))))))))))) |
| 480 | 453 | (ignore remove) ;;Silence byte-compiler. | |
| 481 | (defmacro ses-cell-property-get (property-name row &optional col) | 454 | (cdr (assoc key alist))) |
| 482 | "Get property named PROPERTY-NAME from a CELL or a pair (ROW,COL). | 455 | |
| 456 | (defmacro ses--letref (vars place &rest body) | ||
| 457 | (declare (indent 2) (debug (sexp form &rest body))) | ||
| 458 | (gv-letplace (getter setter) place | ||
| 459 | `(cl-macrolet ((,(nth 0 vars) () ',getter) | ||
| 460 | (,(nth 1 vars) (v) (funcall ,setter v))) | ||
| 461 | ,@body))) | ||
| 462 | |||
| 463 | (defmacro ses-cell-property (property-name row &optional col) | ||
| 464 | "Get property named PROPERTY-NAME from a CELL or a pair (ROW,COL). | ||
| 483 | 465 | ||
| 484 | When COL is omitted, CELL=ROW is a cell object. When COL is | 466 | When COL is omitted, CELL=ROW is a cell object. When COL is |
| 485 | present ROW and COL are the integer coordinates of the cell of | 467 | present ROW and COL are the integer coordinates of the cell of |
| 486 | interest." | 468 | interest." |
| 487 | (declare (debug t)) | 469 | (declare (debug t)) |
| 488 | `(ses-cell-property-get-fun | 470 | `(ses--alist-get ,property-name |
| 489 | ,property-name | 471 | (ses-cell--properties |
| 490 | ,(if col `(ses-get-cell ,row ,col) row))) | 472 | ,(if col `(ses-get-cell ,row ,col) row)))) |
| 491 | |||
| 492 | (defun ses-cell-property-delq-fun (property-name cell) | ||
| 493 | (let ((ret (plist-get (aref cell 4) property-name))) | ||
| 494 | (if ret | ||
| 495 | (setcdr ret (cddr ret))))) | ||
| 496 | |||
| 497 | (defun ses-cell-property-set-fun (property-name property-val cell) | ||
| 498 | (let* ((plist (aref cell 4)) | ||
| 499 | (ret (plist-member plist property-name))) | ||
| 500 | (if ret | ||
| 501 | (setcar (cdr ret) property-val) | ||
| 502 | (aset cell 4 `(,property-name ,property-val ,@plist))))) | ||
| 503 | |||
| 504 | (defmacro ses-cell-property-set (property-name property-value row &optional col) | ||
| 505 | "From a CELL or a pair (ROW,COL), set the property value of | ||
| 506 | the corresponding cell with name PROPERTY-NAME to PROPERTY-VALUE." | ||
| 507 | (if property-value | ||
| 508 | `(ses-cell-property-set-fun ,property-name ,property-value | ||
| 509 | ,(if col `(ses-get-cell ,row ,col) row)) | ||
| 510 | `(ses-cell-property-delq-fun ,property-name | ||
| 511 | ,(if col `(ses-get-cell ,row ,col) row)))) | ||
| 512 | |||
| 513 | (defun ses-cell-property-pop-fun (property-name cell) | ||
| 514 | (let* ((plist (aref cell 4)) | ||
| 515 | (ret (plist-member plist property-name))) | ||
| 516 | (if ret | ||
| 517 | (prog1 (cadr ret) | ||
| 518 | (let ((next (cddr ret))) | ||
| 519 | (if next | ||
| 520 | (progn | ||
| 521 | (setcdr ret (cdr next)) | ||
| 522 | (setcar ret (car next))) | ||
| 523 | (if (eq plist ret) | ||
| 524 | (aset cell 4 nil) | ||
| 525 | (setcdr (last plist 2) nil)))))))) | ||
| 526 | |||
| 527 | 473 | ||
| 528 | (defmacro ses-cell-property-pop (property-name row &optional col) | 474 | (defmacro ses-cell-property-pop (property-name row &optional col) |
| 529 | "From a CELL or a pair (ROW,COL), get and remove the property value of | 475 | "From a CELL or a pair (ROW,COL), get and remove the property value of |
| 530 | the corresponding cell with name PROPERTY-NAME." | 476 | the corresponding cell with name PROPERTY-NAME." |
| 531 | `(ses-cell-property-pop-fun ,property-name | 477 | `(ses--letref (pget pset) |
| 532 | ,(if col `(ses-get-cell ,row ,col) row))) | 478 | (ses--alist-get ,property-name |
| 533 | 479 | (ses-cell--properties | |
| 534 | (defun ses-cell-property-get-handle-fun (property-name cell) | 480 | ,(if col `(ses-get-cell ,row ,col) row)) |
| 535 | (let* ((plist (aref cell 4)) | 481 | t) |
| 536 | (ret (plist-member plist property-name))) | 482 | (prog1 (pget) (pset nil)))) |
| 537 | (if ret | ||
| 538 | (if (eq ret plist) | ||
| 539 | (cdr ret) | ||
| 540 | (let ((val (cadr ret)) | ||
| 541 | (next (cddr ret))) | ||
| 542 | (if next | ||
| 543 | (progn | ||
| 544 | (setcdr ret (cdr next)) | ||
| 545 | (setcar ret (car next))) | ||
| 546 | (setcdr (last plist 2) nil)) | ||
| 547 | (setq ret (cons val plist)) | ||
| 548 | (aset cell 4 (cons property-name ret)) | ||
| 549 | ret)) | ||
| 550 | (setq ret (cons nil plist)) | ||
| 551 | (aset cell 4 (cons property-name ret)) | ||
| 552 | ret))) | ||
| 553 | |||
| 554 | (defmacro ses-cell-property-get-handle (property-name row &optional col) | ||
| 555 | "From a CELL or a pair (ROW,COL), get a cons cell whose car is | ||
| 556 | the property value of the corresponding cell property with name | ||
| 557 | PROPERTY-NAME." | ||
| 558 | `(ses-cell-property-get-handle-fun ,property-name | ||
| 559 | ,(if col `(ses-get-cell ,row ,col) row))) | ||
| 560 | |||
| 561 | |||
| 562 | (defalias 'ses-cell-property-handle-car 'car) | ||
| 563 | (defalias 'ses-cell-property-handle-setcar 'setcar) | ||
| 564 | 483 | ||
| 565 | (defmacro ses-cell-value (row &optional col) | 484 | (defmacro ses-cell-value (row &optional col) |
| 566 | "From a CELL or a pair (ROW,COL), get the current value for that cell." | 485 | "From a CELL or a pair (ROW,COL), get the current value for that cell." |
| @@ -592,14 +511,14 @@ is nil if SYM is not a symbol that names a cell." | |||
| 592 | (< (cdr rowcol) ses--numcols) | 511 | (< (cdr rowcol) ses--numcols) |
| 593 | (eq (ses-cell-symbol (car rowcol) (cdr rowcol)) sym)))))) | 512 | (eq (ses-cell-symbol (car rowcol) (cdr rowcol)) sym)))))) |
| 594 | 513 | ||
| 595 | (defmacro ses-cell (sym value formula printer references) | 514 | (defun ses--cell (sym value formula printer references) |
| 596 | "Load a cell SYM from the spreadsheet file. Does not recompute VALUE from | 515 | "Load a cell SYM from the spreadsheet file. Does not recompute VALUE from |
| 597 | FORMULA, does not reprint using PRINTER, does not check REFERENCES. This is a | 516 | FORMULA, does not reprint using PRINTER, does not check REFERENCES. |
| 598 | macro to prevent propagate-on-load viruses. Safety-checking for FORMULA and | 517 | Safety-checking for FORMULA and PRINTER are deferred until first use." |
| 599 | PRINTER are deferred until first use." | ||
| 600 | (let ((rowcol (ses-sym-rowcol sym))) | 518 | (let ((rowcol (ses-sym-rowcol sym))) |
| 601 | (ses-formula-record formula) | 519 | (ses-formula-record formula) |
| 602 | (ses-printer-record printer) | 520 | (ses-printer-record printer) |
| 521 | (unless formula (setq formula value)) | ||
| 603 | (or (atom formula) | 522 | (or (atom formula) |
| 604 | (eq safe-functions t) | 523 | (eq safe-functions t) |
| 605 | (setq formula `(ses-safe-formula ,formula))) | 524 | (setq formula `(ses-safe-formula ,formula))) |
| @@ -607,11 +526,9 @@ PRINTER are deferred until first use." | |||
| 607 | (stringp printer) | 526 | (stringp printer) |
| 608 | (eq safe-functions t) | 527 | (eq safe-functions t) |
| 609 | (setq printer `(ses-safe-printer ,printer))) | 528 | (setq printer `(ses-safe-printer ,printer))) |
| 610 | (aset (aref ses--cells (car rowcol)) | 529 | (setf (ses-get-cell (car rowcol) (cdr rowcol)) |
| 611 | (cdr rowcol) | ||
| 612 | (ses-make-cell sym formula printer references))) | 530 | (ses-make-cell sym formula printer references))) |
| 613 | (set sym value) | 531 | (set sym value)) |
| 614 | sym) | ||
| 615 | 532 | ||
| 616 | (defun ses-local-printer-compile (printer) | 533 | (defun ses-local-printer-compile (printer) |
| 617 | "Convert local printer function into faster printer | 534 | "Convert local printer function into faster printer |
| @@ -622,18 +539,18 @@ definition." | |||
| 622 | `(lambda (x) (format ,printer x))) | 539 | `(lambda (x) (format ,printer x))) |
| 623 | (t (error "Invalid printer %S" printer)))) | 540 | (t (error "Invalid printer %S" printer)))) |
| 624 | 541 | ||
| 625 | (defmacro ses-local-printer (printer-name printer-def) | 542 | (defun ses--local-printer (name def) |
| 626 | "Define a local printer with name PRINTER-NAME and definition | 543 | "Define a local printer with name NAME and definition DEF. |
| 627 | PRINTER-DEF. Return the printer info." | 544 | Return the printer info." |
| 628 | (or | 545 | (or |
| 629 | (and (symbolp printer-name) | 546 | (and (symbolp name) |
| 630 | (ses-printer-validate printer-def)) | 547 | (ses-printer-validate def)) |
| 631 | (error "Invalid local printer definition")) | 548 | (error "Invalid local printer definition")) |
| 632 | (and (gethash printer-name ses--local-printer-hashmap) | 549 | (and (gethash name ses--local-printer-hashmap) |
| 633 | (error "Duplicate printer definition %S" printer-name)) | 550 | (error "Duplicate printer definition %S" name)) |
| 634 | (add-to-list 'ses-read-printer-history (symbol-name printer-name)) | 551 | (add-to-list 'ses-read-printer-history (symbol-name name)) |
| 635 | (puthash printer-name | 552 | (puthash name |
| 636 | (ses-make-local-printer-info (ses-safe-printer printer-def)) | 553 | (ses-make-local-printer-info (ses-safe-printer def)) |
| 637 | ses--local-printer-hashmap)) | 554 | ses--local-printer-hashmap)) |
| 638 | 555 | ||
| 639 | (defmacro ses-column-widths (widths) | 556 | (defmacro ses-column-widths (widths) |
| @@ -704,9 +621,11 @@ variables `minrow', `maxrow', `mincol', and `maxcol'." | |||
| 704 | (defmacro 1value (form) | 621 | (defmacro 1value (form) |
| 705 | "For code-coverage testing, indicate that FORM is expected to always have | 622 | "For code-coverage testing, indicate that FORM is expected to always have |
| 706 | the same value." | 623 | the same value." |
| 624 | (declare (debug t)) | ||
| 707 | form) | 625 | form) |
| 708 | (defmacro noreturn (form) | 626 | (defmacro noreturn (form) |
| 709 | "For code-coverage testing, indicate that FORM will always signal an error." | 627 | "For code-coverage testing, indicate that FORM will always signal an error." |
| 628 | (declare (debug t)) | ||
| 710 | form) | 629 | form) |
| 711 | 630 | ||
| 712 | 631 | ||
| @@ -753,7 +672,7 @@ is a vector--if a symbol, the new vector is assigned as the symbol's value." | |||
| 753 | (and (symbolp printer) (gethash printer ses--local-printer-hashmap)) | 672 | (and (symbolp printer) (gethash printer ses--local-printer-hashmap)) |
| 754 | (functionp printer) | 673 | (functionp printer) |
| 755 | (and (stringp (car-safe printer)) (not (cdr printer))) | 674 | (and (stringp (car-safe printer)) (not (cdr printer))) |
| 756 | (error "Invalid printer function")) | 675 | (error "Invalid printer function %S" printer)) |
| 757 | printer) | 676 | printer) |
| 758 | 677 | ||
| 759 | (defun ses-printer-record (printer) | 678 | (defun ses-printer-record (printer) |
| @@ -785,20 +704,22 @@ for this spreadsheet." | |||
| 785 | (intern (concat (ses-column-letter col) (number-to-string (1+ row))))) | 704 | (intern (concat (ses-column-letter col) (number-to-string (1+ row))))) |
| 786 | 705 | ||
| 787 | (defun ses-decode-cell-symbol (str) | 706 | (defun ses-decode-cell-symbol (str) |
| 788 | "Decode a symbol \"A1\" => (0,0). Returns `nil' if STR is not a | 707 | "Decode a symbol \"A1\" => (0,0). Return nil if STR is not a |
| 789 | canonical cell name. Does not save match data." | 708 | canonical cell name." |
| 790 | (let (case-fold-search) | 709 | (let (case-fold-search) |
| 791 | (and (string-match "\\`\\([A-Z]+\\)\\([0-9]+\\)\\'" str) | 710 | (and (string-match "\\`\\([A-Z]+\\)\\([0-9]+\\)\\'" str) |
| 792 | (let* ((col-str (match-string-no-properties 1 str)) | 711 | (let* ((col-str (match-string-no-properties 1 str)) |
| 793 | (col 0) | 712 | (col 0) |
| 794 | (col-base 1) | 713 | (col-base 1) |
| 795 | (col-idx (1- (length col-str))) | 714 | (col-idx (1- (length col-str))) |
| 796 | (row (1- (string-to-number (match-string-no-properties 2 str))))) | 715 | (row (1- (string-to-number |
| 716 | (match-string-no-properties 2 str))))) | ||
| 797 | (and (>= row 0) | 717 | (and (>= row 0) |
| 798 | (progn | 718 | (progn |
| 799 | (while | 719 | (while |
| 800 | (progn | 720 | (progn |
| 801 | (setq col (+ col (* (- (aref col-str col-idx) ?A) col-base)) | 721 | (setq col (+ col (* (- (aref col-str col-idx) ?A) |
| 722 | col-base)) | ||
| 802 | col-base (* col-base 26) | 723 | col-base (* col-base 26) |
| 803 | col-idx (1- col-idx)) | 724 | col-idx (1- col-idx)) |
| 804 | (and (>= col-idx 0) | 725 | (and (>= col-idx 0) |
| @@ -872,21 +793,34 @@ and (eval ARG) and reset `ses-start-time' to the current time." | |||
| 872 | ;; The cells | 793 | ;; The cells |
| 873 | ;;---------------------------------------------------------------------------- | 794 | ;;---------------------------------------------------------------------------- |
| 874 | 795 | ||
| 875 | (defun ses-set-cell (row col field val) | 796 | (defmacro ses-set-cell (row col field val) |
| 876 | "Install VAL as the contents for field FIELD (named by a quoted symbol) of | 797 | "Install VAL as the contents for field FIELD (named by a quoted symbol) of |
| 877 | cell (ROW,COL). This is undoable. The cell's data will be updated through | 798 | cell (ROW,COL). This is undoable. The cell's data will be updated through |
| 878 | `post-command-hook'." | 799 | `post-command-hook'." |
| 879 | (let ((cell (ses-get-cell row col)) | 800 | `(let ((row ,row) |
| 880 | (elt (plist-get '(value t symbol 0 formula 1 printer 2 references 3) | 801 | (col ,col) |
| 881 | field)) | 802 | (val ,val)) |
| 882 | change) | 803 | (let* ((cell (ses-get-cell row col)) |
| 883 | (or elt (signal 'args-out-of-range nil)) | 804 | (change |
| 884 | (setq change (if (eq elt t) | 805 | ,(let ((field (eval field t))) |
| 885 | (ses-set-with-undo (ses-cell-symbol cell) val) | 806 | (if (eq field 'value) |
| 886 | (ses-aset-with-undo cell elt val))) | 807 | `(ses-set-with-undo (ses-cell-symbol cell) val) |
| 887 | (if change | 808 | ;; (let* ((slots (get 'ses-cell 'cl-struct-slots)) |
| 888 | (add-to-list 'ses--deferred-write (cons row col)))) | 809 | ;; (slot (or (assq field slots) |
| 889 | nil) ; Make coverage-tester happy. | 810 | ;; (error "Unknown field %S" field))) |
| 811 | ;; (idx (- (length slots) | ||
| 812 | ;; (length (memq slot slots))))) | ||
| 813 | ;; `(ses-aset-with-undo cell ,idx val)) | ||
| 814 | (let ((getter (intern-soft (format "ses-cell--%s" field)))) | ||
| 815 | `(ses-setter-with-undo | ||
| 816 | (eval-when-compile | ||
| 817 | (cons #',getter | ||
| 818 | (lambda (newval cell) | ||
| 819 | (setf (,getter cell) newval)))) | ||
| 820 | val cell)))))) | ||
| 821 | (if change | ||
| 822 | (add-to-list 'ses--deferred-write (cons row col)))) | ||
| 823 | nil)) ; Make coverage-tester happy. | ||
| 890 | 824 | ||
| 891 | (defun ses-cell-set-formula (row col formula) | 825 | (defun ses-cell-set-formula (row col formula) |
| 892 | "Store a new formula for (ROW . COL) and enqueue the cell for | 826 | "Store a new formula for (ROW . COL) and enqueue the cell for |
| @@ -901,7 +835,7 @@ means Emacs will crash if FORMULA contains a circular list." | |||
| 901 | (newref (ses-formula-references formula)) | 835 | (newref (ses-formula-references formula)) |
| 902 | (inhibit-quit t) | 836 | (inhibit-quit t) |
| 903 | x xrow xcol) | 837 | x xrow xcol) |
| 904 | (add-to-list 'ses--deferred-recalc sym) | 838 | (cl-pushnew sym ses--deferred-recalc) |
| 905 | ;;Delete old references from this cell. Skip the ones that are also | 839 | ;;Delete old references from this cell. Skip the ones that are also |
| 906 | ;;in the new list. | 840 | ;;in the new list. |
| 907 | (dolist (ref oldref) | 841 | (dolist (ref oldref) |
| @@ -932,11 +866,11 @@ means Emacs will crash if FORMULA contains a circular list." | |||
| 932 | (dotimes (col ses--numcols) | 866 | (dotimes (col ses--numcols) |
| 933 | (let ((references (ses-cell-property-pop :ses-repair-reference | 867 | (let ((references (ses-cell-property-pop :ses-repair-reference |
| 934 | row col))) | 868 | row col))) |
| 935 | (when references | 869 | (when references |
| 936 | (push (list | 870 | (push (list (ses-cell-symbol row col) |
| 937 | (ses-cell-symbol row col) | 871 | :corrupt-property |
| 938 | :corrupt-property | 872 | references) |
| 939 | references) errors))))) | 873 | errors))))) |
| 940 | 874 | ||
| 941 | ;; Step 2, build new. | 875 | ;; Step 2, build new. |
| 942 | (dotimes (row ses--numrows) | 876 | (dotimes (row ses--numrows) |
| @@ -946,21 +880,17 @@ means Emacs will crash if FORMULA contains a circular list." | |||
| 946 | (formula (ses-cell-formula cell)) | 880 | (formula (ses-cell-formula cell)) |
| 947 | (new-ref (ses-formula-references formula))) | 881 | (new-ref (ses-formula-references formula))) |
| 948 | (dolist (ref new-ref) | 882 | (dolist (ref new-ref) |
| 949 | (let* ((rowcol (ses-sym-rowcol ref)) | 883 | (let ((rowcol (ses-sym-rowcol ref))) |
| 950 | (h (ses-cell-property-get-handle :ses-repair-reference | 884 | (cl-pushnew sym (ses-cell-property :ses-repair-reference |
| 951 | (car rowcol) (cdr rowcol)))) | 885 | (car rowcol) |
| 952 | (unless (memq ref (ses-cell-property-handle-car h)) | 886 | (cdr rowcol)))))))) |
| 953 | (ses-cell-property-handle-setcar | ||
| 954 | h | ||
| 955 | (cons sym | ||
| 956 | (ses-cell-property-handle-car h))))))))) | ||
| 957 | 887 | ||
| 958 | ;; Step 3, overwrite with check. | 888 | ;; Step 3, overwrite with check. |
| 959 | (dotimes (row ses--numrows) | 889 | (dotimes (row ses--numrows) |
| 960 | (dotimes (col ses--numcols) | 890 | (dotimes (col ses--numcols) |
| 961 | (let* ((cell (ses-get-cell row col)) | 891 | (let* ((cell (ses-get-cell row col)) |
| 962 | (irrelevant (ses-cell-references cell)) | 892 | (irrelevant (ses-cell-references cell)) |
| 963 | (new-ref (ses-cell-property-pop :ses-repair-reference cell)) | 893 | (new-ref (ses-cell-property-pop :ses-repair-reference cell)) |
| 964 | missing) | 894 | missing) |
| 965 | (dolist (ref new-ref) | 895 | (dolist (ref new-ref) |
| 966 | (if (memq ref irrelevant) | 896 | (if (memq ref irrelevant) |
| @@ -973,7 +903,7 @@ means Emacs will crash if FORMULA contains a circular list." | |||
| 973 | ,@(and irrelevant (list :irrelevant irrelevant))) | 903 | ,@(and irrelevant (list :irrelevant irrelevant))) |
| 974 | errors))))) | 904 | errors))))) |
| 975 | (if errors | 905 | (if errors |
| 976 | (warn "---------------------------------------------------------------- | 906 | (warn "---------------------------------------------------------------- |
| 977 | Some references were corrupted. | 907 | Some references were corrupted. |
| 978 | 908 | ||
| 979 | The following is a list where each element ELT is such | 909 | The following is a list where each element ELT is such |
| @@ -1004,12 +934,7 @@ the old and FORCE is nil." | |||
| 1004 | (let ((oldval (ses-cell-value cell)) | 934 | (let ((oldval (ses-cell-value cell)) |
| 1005 | (formula (ses-cell-formula cell)) | 935 | (formula (ses-cell-formula cell)) |
| 1006 | newval | 936 | newval |
| 1007 | this-cell-Dijkstra-attempt-h | 937 | this-cell-Dijkstra-attempt+1) |
| 1008 | this-cell-Dijkstra-attempt | ||
| 1009 | this-cell-Dijkstra-attempt+1 | ||
| 1010 | ref-cell-Dijkstra-attempt-h | ||
| 1011 | ref-cell-Dijkstra-attempt | ||
| 1012 | ref-rowcol) | ||
| 1013 | (when (eq (car-safe formula) 'ses-safe-formula) | 938 | (when (eq (car-safe formula) 'ses-safe-formula) |
| 1014 | (setq formula (ses-safe-formula (cadr formula))) | 939 | (setq formula (ses-safe-formula (cadr formula))) |
| 1015 | (ses-set-cell row col 'formula formula)) | 940 | (ses-set-cell row col 'formula formula)) |
| @@ -1025,46 +950,42 @@ the old and FORCE is nil." | |||
| 1025 | (setq newval '*skip*)) | 950 | (setq newval '*skip*)) |
| 1026 | (catch 'cycle | 951 | (catch 'cycle |
| 1027 | (when (or force (not (eq newval oldval))) | 952 | (when (or force (not (eq newval oldval))) |
| 1028 | (add-to-list 'ses--deferred-write (cons row col)) ; In case force=t. | 953 | (cl-pushnew (cons row col) ses--deferred-write :test #'equal) ; In case force=t. |
| 1029 | (setq this-cell-Dijkstra-attempt-h | 954 | (ses--letref (pget pset) |
| 1030 | (ses-cell-property-get-handle :ses-Dijkstra-attempt cell); | 955 | (ses-cell-property :ses-Dijkstra-attempt cell) |
| 1031 | this-cell-Dijkstra-attempt | 956 | (let ((this-cell-Dijkstra-attempt (pget))) |
| 1032 | (ses-cell-property-handle-car this-cell-Dijkstra-attempt-h)) | 957 | (if (null this-cell-Dijkstra-attempt) |
| 1033 | (if (null this-cell-Dijkstra-attempt) | 958 | (pset |
| 1034 | (ses-cell-property-handle-setcar | 959 | (setq this-cell-Dijkstra-attempt |
| 1035 | this-cell-Dijkstra-attempt-h | 960 | (cons ses--Dijkstra-attempt-nb 0))) |
| 1036 | (setq this-cell-Dijkstra-attempt | 961 | (unless (= ses--Dijkstra-attempt-nb |
| 1037 | (cons ses--Dijkstra-attempt-nb 0))) | 962 | (car this-cell-Dijkstra-attempt)) |
| 1038 | (unless (= ses--Dijkstra-attempt-nb | 963 | (setcar this-cell-Dijkstra-attempt ses--Dijkstra-attempt-nb) |
| 1039 | (car this-cell-Dijkstra-attempt)) | 964 | (setcdr this-cell-Dijkstra-attempt 0))) |
| 1040 | (setcar this-cell-Dijkstra-attempt ses--Dijkstra-attempt-nb) | 965 | (setq this-cell-Dijkstra-attempt+1 |
| 1041 | (setcdr this-cell-Dijkstra-attempt 0))) | 966 | (1+ (cdr this-cell-Dijkstra-attempt))))) |
| 1042 | (setq this-cell-Dijkstra-attempt+1 | ||
| 1043 | (1+ (cdr this-cell-Dijkstra-attempt))) | ||
| 1044 | (ses-set-cell row col 'value newval) | 967 | (ses-set-cell row col 'value newval) |
| 1045 | (dolist (ref (ses-cell-references cell)) | 968 | (dolist (ref (ses-cell-references cell)) |
| 1046 | (add-to-list 'ses--deferred-recalc ref) | 969 | (cl-pushnew ref ses--deferred-recalc) |
| 1047 | (setq ref-rowcol (ses-sym-rowcol ref) | 970 | (ses--letref (pget pset) |
| 1048 | ref-cell-Dijkstra-attempt-h | 971 | (let ((ref-rowcol (ses-sym-rowcol ref))) |
| 1049 | (ses-cell-property-get-handle | 972 | (ses-cell-property |
| 1050 | :ses-Dijkstra-attempt | 973 | :ses-Dijkstra-attempt |
| 1051 | (car ref-rowcol) (cdr ref-rowcol)) | 974 | (car ref-rowcol) (cdr ref-rowcol))) |
| 1052 | ref-cell-Dijkstra-attempt | 975 | (let ((ref-cell-Dijkstra-attempt (pget))) |
| 1053 | (ses-cell-property-handle-car ref-cell-Dijkstra-attempt-h)) | 976 | |
| 1054 | 977 | (if (null ref-cell-Dijkstra-attempt) | |
| 1055 | (if (null ref-cell-Dijkstra-attempt) | 978 | (pset |
| 1056 | (ses-cell-property-handle-setcar | 979 | (setq ref-cell-Dijkstra-attempt |
| 1057 | ref-cell-Dijkstra-attempt-h | 980 | (cons ses--Dijkstra-attempt-nb |
| 1058 | (setq ref-cell-Dijkstra-attempt | 981 | this-cell-Dijkstra-attempt+1))) |
| 1059 | (cons ses--Dijkstra-attempt-nb | 982 | (if (= (car ref-cell-Dijkstra-attempt) ses--Dijkstra-attempt-nb) |
| 1060 | this-cell-Dijkstra-attempt+1))) | 983 | (setcdr ref-cell-Dijkstra-attempt |
| 1061 | (if (= (car ref-cell-Dijkstra-attempt) ses--Dijkstra-attempt-nb) | 984 | (max (cdr ref-cell-Dijkstra-attempt) |
| 1062 | (setcdr ref-cell-Dijkstra-attempt | 985 | this-cell-Dijkstra-attempt+1)) |
| 1063 | (max (cdr ref-cell-Dijkstra-attempt) | 986 | (setcar ref-cell-Dijkstra-attempt ses--Dijkstra-attempt-nb) |
| 1064 | this-cell-Dijkstra-attempt+1)) | 987 | (setcdr ref-cell-Dijkstra-attempt |
| 1065 | (setcar ref-cell-Dijkstra-attempt ses--Dijkstra-attempt-nb) | 988 | this-cell-Dijkstra-attempt+1))))) |
| 1066 | (setcdr ref-cell-Dijkstra-attempt | ||
| 1067 | this-cell-Dijkstra-attempt+1))) | ||
| 1068 | 989 | ||
| 1069 | (when (> this-cell-Dijkstra-attempt+1 ses--Dijkstra-weight-bound) | 990 | (when (> this-cell-Dijkstra-attempt+1 ses--Dijkstra-weight-bound) |
| 1070 | ;; Update print of this cell. | 991 | ;; Update print of this cell. |
| @@ -1123,7 +1044,7 @@ if the cell's value is unchanged and FORCE is nil." | |||
| 1123 | (when (or (memq ref curlist) | 1044 | (when (or (memq ref curlist) |
| 1124 | (memq ref ses--deferred-recalc)) | 1045 | (memq ref ses--deferred-recalc)) |
| 1125 | ;; This cell refers to another that isn't done yet | 1046 | ;; This cell refers to another that isn't done yet |
| 1126 | (add-to-list 'ses--deferred-recalc this-sym) | 1047 | (cl-pushnew this-sym ses--deferred-recalc :test #'equal) |
| 1127 | (throw 'ref t))))) | 1048 | (throw 'ref t))))) |
| 1128 | ;; ses-update-cells is called from post-command-hook, so | 1049 | ;; ses-update-cells is called from post-command-hook, so |
| 1129 | ;; inhibit-quit is implicitly bound to t. | 1050 | ;; inhibit-quit is implicitly bound to t. |
| @@ -1132,7 +1053,7 @@ if the cell's value is unchanged and FORCE is nil." | |||
| 1132 | (error "Quit")) | 1053 | (error "Quit")) |
| 1133 | (ses-calculate-cell (car this-rowcol) (cdr this-rowcol) force))) | 1054 | (ses-calculate-cell (car this-rowcol) (cdr this-rowcol) force))) |
| 1134 | (dolist (ref ses--deferred-recalc) | 1055 | (dolist (ref ses--deferred-recalc) |
| 1135 | (add-to-list 'nextlist ref))) | 1056 | (cl-pushnew ref nextlist :test #'equal))) |
| 1136 | (when ses--deferred-recalc | 1057 | (when ses--deferred-recalc |
| 1137 | ;; Just couldn't finish these. | 1058 | ;; Just couldn't finish these. |
| 1138 | (dolist (x ses--deferred-recalc) | 1059 | (dolist (x ses--deferred-recalc) |
| @@ -1251,7 +1172,8 @@ preceding cell has spilled over." | |||
| 1251 | ((< len width) | 1172 | ((< len width) |
| 1252 | ;; Fill field to length with spaces. | 1173 | ;; Fill field to length with spaces. |
| 1253 | (setq len (make-string (- width len) ?\s) | 1174 | (setq len (make-string (- width len) ?\s) |
| 1254 | text (if (eq ses-call-printer-return t) | 1175 | text (if (or (stringp value) |
| 1176 | (eq ses-call-printer-return t)) | ||
| 1255 | (concat text len) | 1177 | (concat text len) |
| 1256 | (concat len text)))) | 1178 | (concat len text)))) |
| 1257 | ((> len width) | 1179 | ((> len width) |
| @@ -1352,7 +1274,7 @@ printer signaled one (and \"%s\" is used as the default printer), else nil." | |||
| 1352 | (or (and (symbolp printer) | 1274 | (or (and (symbolp printer) |
| 1353 | (let ((locprn (gethash printer ses--local-printer-hashmap))) | 1275 | (let ((locprn (gethash printer ses--local-printer-hashmap))) |
| 1354 | (and locprn | 1276 | (and locprn |
| 1355 | (ses-locprn-get-compiled locprn)))) | 1277 | (ses--locprn-compiled locprn)))) |
| 1356 | printer) | 1278 | printer) |
| 1357 | (or value ""))) | 1279 | (or value ""))) |
| 1358 | (if (stringp value) | 1280 | (if (stringp value) |
| @@ -1440,7 +1362,8 @@ undoable. Return nil when there was no change, and non nil otherwise." | |||
| 1440 | (ses-widen) | 1362 | (ses-widen) |
| 1441 | (goto-char ses--params-marker) | 1363 | (goto-char ses--params-marker) |
| 1442 | (forward-line (plist-get ses-paramlines-plist 'ses--numlocprn )) | 1364 | (forward-line (plist-get ses-paramlines-plist 'ses--numlocprn )) |
| 1443 | (insert (format (plist-get ses-paramfmt-plist 'ses--numlocprn) ses--numlocprn) | 1365 | (insert (format (plist-get ses-paramfmt-plist 'ses--numlocprn) |
| 1366 | ses--numlocprn) | ||
| 1444 | ?\n) | 1367 | ?\n) |
| 1445 | t) ))) | 1368 | t) ))) |
| 1446 | 1369 | ||
| @@ -1492,24 +1415,17 @@ Newlines in the data are escaped." | |||
| 1492 | (setq formula (cadr formula))) | 1415 | (setq formula (cadr formula))) |
| 1493 | (if (eq (car-safe printer) 'ses-safe-printer) | 1416 | (if (eq (car-safe printer) 'ses-safe-printer) |
| 1494 | (setq printer (cadr printer))) | 1417 | (setq printer (cadr printer))) |
| 1495 | ;; This is noticeably faster than (format "%S %S %S %S %S") | 1418 | (setq text (prin1-to-string |
| 1496 | (setq text (concat "(ses-cell " | 1419 | ;; We could shorten it to (ses-cell SYM VAL) when |
| 1497 | (symbol-name sym) | 1420 | ;; the other parameters are nil, but in practice most |
| 1498 | " " | 1421 | ;; cells have non-nil `references', so it's |
| 1499 | (prin1-to-string (symbol-value sym)) | 1422 | ;; rather pointless. |
| 1500 | " " | 1423 | `(ses-cell ,sym |
| 1501 | (prin1-to-string formula) | 1424 | ,(symbol-value sym) |
| 1502 | " " | 1425 | ,(unless (equal formula (symbol-value sym)) |
| 1503 | (prin1-to-string printer) | 1426 | formula) |
| 1504 | " " | 1427 | ,printer |
| 1505 | (if (atom (ses-cell-references cell)) | 1428 | ,(ses-cell-references cell)))) |
| 1506 | "nil" | ||
| 1507 | (concat "(" | ||
| 1508 | (mapconcat 'symbol-name | ||
| 1509 | (ses-cell-references cell) | ||
| 1510 | " ") | ||
| 1511 | ")")) | ||
| 1512 | ")")) | ||
| 1513 | (ses-goto-data row col) | 1429 | (ses-goto-data row col) |
| 1514 | (delete-region (point) (line-end-position)) | 1430 | (delete-region (point) (line-end-position)) |
| 1515 | (insert text))) | 1431 | (insert text))) |
| @@ -1526,8 +1442,8 @@ refers to. For recursive calls, RESULT-SO-FAR is the list being | |||
| 1526 | constructed, or t to get a wrong-type-argument error when the | 1442 | constructed, or t to get a wrong-type-argument error when the |
| 1527 | first reference is found." | 1443 | first reference is found." |
| 1528 | (if (ses-sym-rowcol formula) | 1444 | (if (ses-sym-rowcol formula) |
| 1529 | ;;Entire formula is one symbol | 1445 | ;; Entire formula is one symbol. |
| 1530 | (add-to-list 'result-so-far formula) | 1446 | (cl-pushnew formula result-so-far :test #'equal) |
| 1531 | (if (consp formula) | 1447 | (if (consp formula) |
| 1532 | (cond | 1448 | (cond |
| 1533 | ((eq (car formula) 'ses-range) | 1449 | ((eq (car formula) 'ses-range) |
| @@ -1535,7 +1451,7 @@ first reference is found." | |||
| 1535 | (cdr (funcall 'macroexpand | 1451 | (cdr (funcall 'macroexpand |
| 1536 | (list 'ses-range (nth 1 formula) | 1452 | (list 'ses-range (nth 1 formula) |
| 1537 | (nth 2 formula))))) | 1453 | (nth 2 formula))))) |
| 1538 | (add-to-list 'result-so-far cur))) | 1454 | (cl-pushnew cur result-so-far :test #'equal))) |
| 1539 | ((null (eq (car formula) 'quote)) | 1455 | ((null (eq (car formula) 'quote)) |
| 1540 | ;;Recursive call for subformulas | 1456 | ;;Recursive call for subformulas |
| 1541 | (dolist (cur formula) | 1457 | (dolist (cur formula) |
| @@ -1704,8 +1620,8 @@ to each symbol." | |||
| 1704 | ;; This cell referred to a cell that's been deleted or is no | 1620 | ;; This cell referred to a cell that's been deleted or is no |
| 1705 | ;; longer part of the range. We can't fix that now because | 1621 | ;; longer part of the range. We can't fix that now because |
| 1706 | ;; reference lists cells have been partially updated. | 1622 | ;; reference lists cells have been partially updated. |
| 1707 | (add-to-list 'ses--deferred-recalc | 1623 | (cl-pushnew (ses-create-cell-symbol row col) |
| 1708 | (ses-create-cell-symbol row col))) | 1624 | ses--deferred-recalc :test #'equal)) |
| 1709 | (setq newval (ses-relocate-formula (ses-cell-references mycell) | 1625 | (setq newval (ses-relocate-formula (ses-cell-references mycell) |
| 1710 | minrow mincol rowincr colincr)) | 1626 | minrow mincol rowincr colincr)) |
| 1711 | (ses-set-cell row col 'references newval) | 1627 | (ses-set-cell row col 'references newval) |
| @@ -1795,36 +1711,30 @@ to each symbol." | |||
| 1795 | (insert-and-inherit "X") | 1711 | (insert-and-inherit "X") |
| 1796 | (delete-region (1- (point)) (point)))) | 1712 | (delete-region (1- (point)) (point)))) |
| 1797 | 1713 | ||
| 1798 | (defun ses-set-with-undo (sym newval) | 1714 | (defun ses-setter-with-undo (accessors newval &rest args) |
| 1799 | "Like set, but undoable. Result is t if value has changed." | 1715 | "Set a field/variable and record it so it can be undone. |
| 1800 | ;; We try to avoid adding redundant entries to the undo list, but this is | 1716 | Result is non-nil if field/variable has changed." |
| 1801 | ;; unavoidable for strings because equal ignores text properties and there's | 1717 | (let ((oldval (apply (car accessors) args))) |
| 1802 | ;; no easy way to get the whole property list to see if it's different! | 1718 | (unless (equal-including-properties oldval newval) |
| 1803 | (unless (and (boundp sym) | 1719 | (push `(apply ses-setter-with-undo ,accessors ,oldval ,@args) |
| 1804 | (equal (symbol-value sym) newval) | 1720 | buffer-undo-list) |
| 1805 | (not (stringp newval))) | 1721 | (apply (cdr accessors) newval args) |
| 1806 | (push (if (boundp sym) | 1722 | t))) |
| 1807 | `(apply ses-set-with-undo ,sym ,(symbol-value sym)) | ||
| 1808 | `(apply ses-unset-with-undo ,sym)) | ||
| 1809 | buffer-undo-list) | ||
| 1810 | (set sym newval) | ||
| 1811 | t)) | ||
| 1812 | |||
| 1813 | (defun ses-unset-with-undo (sym) | ||
| 1814 | "Set SYM to be unbound. This is undoable." | ||
| 1815 | (when (1value (boundp sym)) ; Always bound, except after a programming error. | ||
| 1816 | (push `(apply ses-set-with-undo ,sym ,(symbol-value sym)) buffer-undo-list) | ||
| 1817 | (makunbound sym))) | ||
| 1818 | 1723 | ||
| 1819 | (defun ses-aset-with-undo (array idx newval) | 1724 | (defun ses-aset-with-undo (array idx newval) |
| 1820 | "Like `aset', but undoable. | 1725 | (ses-setter-with-undo (eval-when-compile |
| 1821 | Result is t if element has changed." | 1726 | (cons #'aref |
| 1822 | (unless (equal (aref array idx) newval) | 1727 | (lambda (newval array idx) (aset array idx newval)))) |
| 1823 | (push `(apply ses-aset-with-undo ,array ,idx | 1728 | newval array idx)) |
| 1824 | ,(aref array idx)) buffer-undo-list) | ||
| 1825 | (aset array idx newval) | ||
| 1826 | t)) | ||
| 1827 | 1729 | ||
| 1730 | (defun ses-set-with-undo (sym newval) | ||
| 1731 | (ses-setter-with-undo | ||
| 1732 | (eval-when-compile | ||
| 1733 | (cons (lambda (sym) (if (boundp sym) (symbol-value sym) :ses--unbound)) | ||
| 1734 | (lambda (newval sym) (if (eq newval :ses--unbound) | ||
| 1735 | (makunbound sym) | ||
| 1736 | (set sym newval))))) | ||
| 1737 | newval sym)) | ||
| 1828 | 1738 | ||
| 1829 | ;;---------------------------------------------------------------------------- | 1739 | ;;---------------------------------------------------------------------------- |
| 1830 | ;; Startup for major mode | 1740 | ;; Startup for major mode |
| @@ -1890,11 +1800,11 @@ Does not execute cell formulas or print functions." | |||
| 1890 | (forward-line (* ses--numrows (1+ ses--numcols))) | 1800 | (forward-line (* ses--numrows (1+ ses--numcols))) |
| 1891 | (let ((numlocprn ses--numlocprn)) | 1801 | (let ((numlocprn ses--numlocprn)) |
| 1892 | (setq ses--numlocprn 0) | 1802 | (setq ses--numlocprn 0) |
| 1893 | (dotimes (lp numlocprn) | 1803 | (dotimes (_ numlocprn) |
| 1894 | (let ((x (read (current-buffer)))) | 1804 | (let ((x (read (current-buffer)))) |
| 1895 | (or (and (looking-at-p "\n") | 1805 | (or (and (looking-at-p "\n") |
| 1896 | (eq (car-safe x) 'ses-local-printer) | 1806 | (eq (car-safe x) 'ses-local-printer) |
| 1897 | (eval x)) | 1807 | (apply #'ses--local-printer (cdr x))) |
| 1898 | (error "local printer-def error")) | 1808 | (error "local printer-def error")) |
| 1899 | (setq ses--numlocprn (1+ ses--numlocprn)))))) | 1809 | (setq ses--numlocprn (1+ ses--numlocprn)))))) |
| 1900 | ;; Load cell definitions. | 1810 | ;; Load cell definitions. |
| @@ -1906,7 +1816,7 @@ Does not execute cell formulas or print functions." | |||
| 1906 | (eq (car-safe x) 'ses-cell) | 1816 | (eq (car-safe x) 'ses-cell) |
| 1907 | (ses-create-cell-variable sym row col)) | 1817 | (ses-create-cell-variable sym row col)) |
| 1908 | (error "Cell-def error")) | 1818 | (error "Cell-def error")) |
| 1909 | (eval x))) | 1819 | (apply #'ses--cell (cdr x)))) |
| 1910 | (or (looking-at-p "\n\n") | 1820 | (or (looking-at-p "\n\n") |
| 1911 | (error "Missing blank line between rows"))) | 1821 | (error "Missing blank line between rows"))) |
| 1912 | ;; Skip local printer function declaration --- that were already loaded. | 1822 | ;; Skip local printer function declaration --- that were already loaded. |
| @@ -2067,7 +1977,8 @@ formula: | |||
| 2067 | ;; calculation). | 1977 | ;; calculation). |
| 2068 | indent-tabs-mode nil) | 1978 | indent-tabs-mode nil) |
| 2069 | (1value (add-hook 'change-major-mode-hook 'ses-cleanup nil t)) | 1979 | (1value (add-hook 'change-major-mode-hook 'ses-cleanup nil t)) |
| 2070 | (1value (add-hook 'before-revert-hook 'ses-cleanup nil t)) | 1980 | ;; This makes revert impossible if the buffer is read-only. |
| 1981 | ;; (1value (add-hook 'before-revert-hook 'ses-cleanup nil t)) | ||
| 2071 | (setq header-line-format '(:eval (progn | 1982 | (setq header-line-format '(:eval (progn |
| 2072 | (when (/= (window-hscroll) | 1983 | (when (/= (window-hscroll) |
| 2073 | ses--header-hscroll) | 1984 | ses--header-hscroll) |
| @@ -2251,7 +2162,7 @@ print area if NONARROW is nil." | |||
| 2251 | (delete-region (point-min) (point)) | 2162 | (delete-region (point-min) (point)) |
| 2252 | ;; Insert all blank lines before printing anything, so ses-print-cell can | 2163 | ;; Insert all blank lines before printing anything, so ses-print-cell can |
| 2253 | ;; find the data area when inserting or deleting *skip* values for cells. | 2164 | ;; find the data area when inserting or deleting *skip* values for cells. |
| 2254 | (dotimes (row ses--numrows) | 2165 | (dotimes (_ ses--numrows) |
| 2255 | (insert-and-inherit ses--blank-line)) | 2166 | (insert-and-inherit ses--blank-line)) |
| 2256 | (dotimes-with-progress-reporter (row ses--numrows) "Reprinting..." | 2167 | (dotimes-with-progress-reporter (row ses--numrows) "Reprinting..." |
| 2257 | (if (eq (ses-cell-value row 0) '*skip*) | 2168 | (if (eq (ses-cell-value row 0) '*skip*) |
| @@ -2283,9 +2194,10 @@ to are recalculated first." | |||
| 2283 | (when | 2194 | (when |
| 2284 | (setq cur-rowcol (ses-sym-rowcol ses--curcell) | 2195 | (setq cur-rowcol (ses-sym-rowcol ses--curcell) |
| 2285 | sig (progn | 2196 | sig (progn |
| 2286 | (ses-cell-property-set :ses-Dijkstra-attempt | 2197 | (setf (ses-cell-property :ses-Dijkstra-attempt |
| 2287 | (cons ses--Dijkstra-attempt-nb 0) | 2198 | (car cur-rowcol) |
| 2288 | (car cur-rowcol) (cdr cur-rowcol) ) | 2199 | (cdr cur-rowcol)) |
| 2200 | (cons ses--Dijkstra-attempt-nb 0)) | ||
| 2289 | (ses-calculate-cell (car cur-rowcol) (cdr cur-rowcol) t))) | 2201 | (ses-calculate-cell (car cur-rowcol) (cdr cur-rowcol) t))) |
| 2290 | (nconc sig (list (ses-cell-symbol (car cur-rowcol) | 2202 | (nconc sig (list (ses-cell-symbol (car cur-rowcol) |
| 2291 | (cdr cur-rowcol))))) | 2203 | (cdr cur-rowcol))))) |
| @@ -2298,14 +2210,14 @@ to are recalculated first." | |||
| 2298 | ;; The t causes an error if the cell has references. If no | 2210 | ;; The t causes an error if the cell has references. If no |
| 2299 | ;; references, the t will be the result value. | 2211 | ;; references, the t will be the result value. |
| 2300 | (1value (ses-formula-references (ses-cell-formula row col) t)) | 2212 | (1value (ses-formula-references (ses-cell-formula row col) t)) |
| 2301 | (ses-cell-property-set :ses-Dijkstra-attempt | 2213 | (setf (ses-cell-property :ses-Dijkstra-attempt row col) |
| 2302 | (cons ses--Dijkstra-attempt-nb 0) | 2214 | (cons ses--Dijkstra-attempt-nb 0)) |
| 2303 | row col) | ||
| 2304 | (when (setq sig (ses-calculate-cell row col t)) | 2215 | (when (setq sig (ses-calculate-cell row col t)) |
| 2305 | (nconc sig (list (ses-cell-symbol row col))))) | 2216 | (nconc sig (list (ses-cell-symbol row col))))) |
| 2306 | (wrong-type-argument | 2217 | (wrong-type-argument |
| 2307 | ;; The formula contains a reference. | 2218 | ;; The formula contains a reference. |
| 2308 | (add-to-list 'ses--deferred-recalc (ses-cell-symbol row col)))))) | 2219 | (cl-pushnew (ses-cell-symbol row col) ses--deferred-recalc |
| 2220 | :test #'equal))))) | ||
| 2309 | ;; Do the update now, so we can force recalculation. | 2221 | ;; Do the update now, so we can force recalculation. |
| 2310 | (let ((x ses--deferred-recalc)) | 2222 | (let ((x ses--deferred-recalc)) |
| 2311 | (setq ses--deferred-recalc nil) | 2223 | (setq ses--deferred-recalc nil) |
| @@ -2380,7 +2292,7 @@ to are recalculated first." | |||
| 2380 | (insert ses-initial-file-trailer) | 2292 | (insert ses-initial-file-trailer) |
| 2381 | (goto-char (point-min))) | 2293 | (goto-char (point-min))) |
| 2382 | ;; Create a blank display area. | 2294 | ;; Create a blank display area. |
| 2383 | (dotimes (row ses--numrows) | 2295 | (dotimes (_ ses--numrows) |
| 2384 | (insert ses--blank-line)) | 2296 | (insert ses--blank-line)) |
| 2385 | (insert ses-print-data-boundary) | 2297 | (insert ses-print-data-boundary) |
| 2386 | (backward-char (1- (length ses-print-data-boundary))) | 2298 | (backward-char (1- (length ses-print-data-boundary))) |
| @@ -2450,16 +2362,23 @@ cell formula was unsafe and user declined confirmation." | |||
| 2450 | (barf-if-buffer-read-only) | 2362 | (barf-if-buffer-read-only) |
| 2451 | (list (car rowcol) | 2363 | (list (car rowcol) |
| 2452 | (cdr rowcol) | 2364 | (cdr rowcol) |
| 2453 | (read-from-minibuffer | 2365 | (if (equal initial "\"") |
| 2454 | (format "Cell %s: " ses--curcell) | 2366 | (progn |
| 2455 | (cons (if (equal initial "\"") "\"\"" | 2367 | (if (not (stringp curval)) (setq curval nil)) |
| 2456 | (if (equal initial "(") "()" initial)) 2) | 2368 | (read-string (if curval |
| 2457 | ses-mode-edit-map | 2369 | (format "String Cell %s (default %s): " |
| 2458 | t ; Convert to Lisp object. | 2370 | ses--curcell curval) |
| 2459 | 'ses-read-cell-history | 2371 | (format "String Cell %s: " ses--curcell)) |
| 2460 | (prin1-to-string (if (eq (car-safe curval) 'ses-safe-formula) | 2372 | nil 'ses-read-string-history curval)) |
| 2461 | (cadr curval) | 2373 | (read-from-minibuffer |
| 2462 | curval)))))) | 2374 | (format "Cell %s: " ses--curcell) |
| 2375 | (cons (if (equal initial "(") "()" initial) 2) | ||
| 2376 | ses-mode-edit-map | ||
| 2377 | t ; Convert to Lisp object. | ||
| 2378 | 'ses-read-cell-history | ||
| 2379 | (prin1-to-string (if (eq (car-safe curval) 'ses-safe-formula) | ||
| 2380 | (cadr curval) | ||
| 2381 | curval))))))) | ||
| 2463 | (when (ses-edit-cell row col newval) | 2382 | (when (ses-edit-cell row col newval) |
| 2464 | (ses-command-hook) ; Update cell widths before movement. | 2383 | (ses-command-hook) ; Update cell widths before movement. |
| 2465 | (dolist (x ses-after-entry-functions) | 2384 | (dolist (x ses-after-entry-functions) |
| @@ -2492,7 +2411,7 @@ With prefix, deletes several cells." | |||
| 2492 | (1value (ses-clear-cell-backward (- count))) | 2411 | (1value (ses-clear-cell-backward (- count))) |
| 2493 | (ses-check-curcell) | 2412 | (ses-check-curcell) |
| 2494 | (ses-begin-change) | 2413 | (ses-begin-change) |
| 2495 | (dotimes (x count) | 2414 | (dotimes (_ count) |
| 2496 | (ses-set-curcell) | 2415 | (ses-set-curcell) |
| 2497 | (let ((rowcol (ses-sym-rowcol ses--curcell))) | 2416 | (let ((rowcol (ses-sym-rowcol ses--curcell))) |
| 2498 | (or rowcol (signal 'end-of-buffer nil)) | 2417 | (or rowcol (signal 'end-of-buffer nil)) |
| @@ -2507,7 +2426,7 @@ cells." | |||
| 2507 | (1value (ses-clear-cell-forward (- count))) | 2426 | (1value (ses-clear-cell-forward (- count))) |
| 2508 | (ses-check-curcell 'end) | 2427 | (ses-check-curcell 'end) |
| 2509 | (ses-begin-change) | 2428 | (ses-begin-change) |
| 2510 | (dotimes (x count) | 2429 | (dotimes (_ count) |
| 2511 | (backward-char 1) ; Will signal 'beginning-of-buffer if appropriate. | 2430 | (backward-char 1) ; Will signal 'beginning-of-buffer if appropriate. |
| 2512 | (ses-set-curcell) | 2431 | (ses-set-curcell) |
| 2513 | (let ((rowcol (ses-sym-rowcol ses--curcell))) | 2432 | (let ((rowcol (ses-sym-rowcol ses--curcell))) |
| @@ -2526,7 +2445,7 @@ canceled." | |||
| 2526 | (barf-if-buffer-read-only) | 2445 | (barf-if-buffer-read-only) |
| 2527 | (if (eq default t) | 2446 | (if (eq default t) |
| 2528 | (setq default "") | 2447 | (setq default "") |
| 2529 | (setq prompt (format "%s [currently %S]: " | 2448 | (setq prompt (format "%s (default %S): " |
| 2530 | (substring prompt 0 -2) | 2449 | (substring prompt 0 -2) |
| 2531 | default))) | 2450 | default))) |
| 2532 | (let ((new (read-from-minibuffer prompt | 2451 | (let ((new (read-from-minibuffer prompt |
| @@ -2557,21 +2476,20 @@ one argument, or a symbol that names a function of one argument. In the | |||
| 2557 | latter two cases, the function's result should be either a string (will be | 2476 | latter two cases, the function's result should be either a string (will be |
| 2558 | right-justified) or a list of one string (will be left-justified)." | 2477 | right-justified) or a list of one string (will be left-justified)." |
| 2559 | (interactive | 2478 | (interactive |
| 2560 | (let ((default t) | 2479 | (let ((default t)) |
| 2561 | x) | ||
| 2562 | (ses-check-curcell 'range) | 2480 | (ses-check-curcell 'range) |
| 2563 | ;;Default is none if not all cells in range have same printer | 2481 | ;;Default is none if not all cells in range have same printer |
| 2564 | (catch 'ses-read-cell-printer | 2482 | (catch 'ses-read-cell-printer |
| 2565 | (ses-dorange ses--curcell | 2483 | (ses-dorange ses--curcell |
| 2566 | (setq x (ses-cell-printer row col)) | 2484 | (let ((x (ses-cell-printer row col))) |
| 2567 | (if (eq (car-safe x) 'ses-safe-printer) | 2485 | (if (eq (car-safe x) 'ses-safe-printer) |
| 2568 | (setq x (cadr x))) | 2486 | (setq x (cadr x))) |
| 2569 | (if (eq default t) | 2487 | (if (eq default t) |
| 2570 | (setq default x) | 2488 | (setq default x) |
| 2571 | (unless (equal default x) | 2489 | (unless (equal default x) |
| 2572 | ;;Range contains differing printer functions | 2490 | ;;Range contains differing printer functions |
| 2573 | (setq default t) | 2491 | (setq default t) |
| 2574 | (throw 'ses-read-cell-printer t))))) | 2492 | (throw 'ses-read-cell-printer t)))))) |
| 2575 | (list (ses-read-printer (format "Cell %S printer: " ses--curcell) | 2493 | (list (ses-read-printer (format "Cell %S printer: " ses--curcell) |
| 2576 | default)))) | 2494 | default)))) |
| 2577 | (unless (eq newval t) | 2495 | (unless (eq newval t) |
| @@ -2850,7 +2768,7 @@ inserts a new row if at bottom of print area. Repeat COUNT times." | |||
| 2850 | (list col | 2768 | (list col |
| 2851 | (if current-prefix-arg | 2769 | (if current-prefix-arg |
| 2852 | (prefix-numeric-value current-prefix-arg) | 2770 | (prefix-numeric-value current-prefix-arg) |
| 2853 | (read-from-minibuffer (format "Column %s width [currently %d]: " | 2771 | (read-from-minibuffer (format "Column %s width (default %d): " |
| 2854 | (ses-column-letter col) | 2772 | (ses-column-letter col) |
| 2855 | (ses-col-width col)) | 2773 | (ses-col-width col)) |
| 2856 | nil ; No initial contents. | 2774 | nil ; No initial contents. |
| @@ -3089,9 +3007,9 @@ cons of ROW and COL). Treat plain symbols as strings unless ARG is a list." | |||
| 3089 | ;; Invalid sexp --- leave it as a string. | 3007 | ;; Invalid sexp --- leave it as a string. |
| 3090 | (setq val (substring text from to))) | 3008 | (setq val (substring text from to))) |
| 3091 | ((and (car val) (symbolp (car val))) | 3009 | ((and (car val) (symbolp (car val))) |
| 3092 | (if (consp arg) | 3010 | (setq val (if (consp arg) |
| 3093 | (setq val (list 'quote (car val))) ; Keep symbol. | 3011 | (list 'quote (car val)) ; Keep symbol. |
| 3094 | (setq val (substring text from to)))) ; Treat symbol as text. | 3012 | (substring text from to)))) ; Treat symbol as text. |
| 3095 | (t | 3013 | (t |
| 3096 | (setq val (car val)))) | 3014 | (setq val (car val)))) |
| 3097 | (let ((row (car rowcol)) | 3015 | (let ((row (car rowcol)) |
| @@ -3437,29 +3355,31 @@ highlighted range in the spreadsheet." | |||
| 3437 | (if (equal new-rowcol rowcol) | 3355 | (if (equal new-rowcol rowcol) |
| 3438 | (put new-name 'ses-cell rowcol) | 3356 | (put new-name 'ses-cell rowcol) |
| 3439 | (error "Not a valid name for this cell location")) | 3357 | (error "Not a valid name for this cell location")) |
| 3440 | (setq ses--named-cell-hashmap (or ses--named-cell-hashmap (make-hash-table :test 'eq))) | 3358 | (setq ses--named-cell-hashmap |
| 3359 | (or ses--named-cell-hashmap (make-hash-table :test 'eq))) | ||
| 3441 | (put new-name 'ses-cell :ses-named) | 3360 | (put new-name 'ses-cell :ses-named) |
| 3442 | (puthash new-name rowcol ses--named-cell-hashmap)) | 3361 | (puthash new-name rowcol ses--named-cell-hashmap)) |
| 3443 | (push `(ses-rename-cell ,old-name ,cell) buffer-undo-list) | 3362 | (push `(ses-rename-cell ,old-name ,cell) buffer-undo-list) |
| 3444 | ;; replace name by new name in formula of cells refering to renamed cell | 3363 | ;; Replace name by new name in formula of cells refering to renamed cell. |
| 3445 | (dolist (ref (ses-cell-references cell)) | 3364 | (dolist (ref (ses-cell-references cell)) |
| 3446 | (let* ((x (ses-sym-rowcol ref)) | 3365 | (let* ((x (ses-sym-rowcol ref)) |
| 3447 | (xcell (ses-get-cell (car x) (cdr x)))) | 3366 | (xcell (ses-get-cell (car x) (cdr x)))) |
| 3448 | (ses-cell-formula-aset xcell | 3367 | (setf (ses-cell-formula xcell) |
| 3449 | (ses-replace-name-in-formula | 3368 | (ses-replace-name-in-formula |
| 3450 | (ses-cell-formula xcell) | 3369 | (ses-cell-formula xcell) |
| 3451 | sym | 3370 | sym |
| 3452 | new-name)))) | 3371 | new-name)))) |
| 3453 | ;; replace name by new name in reference list of cells to which renamed cell refers to | 3372 | ;; Replace name by new name in reference list of cells to which renamed |
| 3373 | ;; cell refers to. | ||
| 3454 | (dolist (ref (ses-formula-references (ses-cell-formula cell))) | 3374 | (dolist (ref (ses-formula-references (ses-cell-formula cell))) |
| 3455 | (let* ((x (ses-sym-rowcol ref)) | 3375 | (let* ((x (ses-sym-rowcol ref)) |
| 3456 | (xcell (ses-get-cell (car x) (cdr x)))) | 3376 | (xcell (ses-get-cell (car x) (cdr x)))) |
| 3457 | (ses-cell-references-aset xcell | 3377 | (setf (ses-cell-references xcell) |
| 3458 | (cons new-name (delq sym | 3378 | (cons new-name (delq sym |
| 3459 | (ses-cell-references xcell)))))) | 3379 | (ses-cell-references xcell)))))) |
| 3460 | (push new-name ses--renamed-cell-symb-list) | 3380 | (push new-name ses--renamed-cell-symb-list) |
| 3461 | (set new-name (symbol-value sym)) | 3381 | (set new-name (symbol-value sym)) |
| 3462 | (aset cell 0 new-name) | 3382 | (setf (ses-cell--symbol cell) new-name) |
| 3463 | (makunbound sym) | 3383 | (makunbound sym) |
| 3464 | (and curcell (setq ses--curcell new-name)) | 3384 | (and curcell (setq ses--curcell new-name)) |
| 3465 | (let* ((pos (point)) | 3385 | (let* ((pos (point)) |
| @@ -3477,8 +3397,9 @@ highlighted range in the spreadsheet." | |||
| 3477 | (force-mode-line-update))) | 3397 | (force-mode-line-update))) |
| 3478 | 3398 | ||
| 3479 | (defun ses-refresh-local-printer (name compiled-value) | 3399 | (defun ses-refresh-local-printer (name compiled-value) |
| 3480 | "Refresh printout of spreadsheet for all cells with printer | 3400 | "Refresh printout for all cells which use printer NAME. |
| 3481 | defined to local printer named NAME using the value COMPILED-VALUE for this printer" | 3401 | NAME should be the name of a locally defined printer. |
| 3402 | Uses the value COMPILED-VALUE for this printer." | ||
| 3482 | (message "Refreshing cells using printer %S" name) | 3403 | (message "Refreshing cells using printer %S" name) |
| 3483 | (let (new-print) | 3404 | (let (new-print) |
| 3484 | (dotimes (row ses--numrows) | 3405 | (dotimes (row ses--numrows) |
| @@ -3490,55 +3411,58 @@ highlighted range in the spreadsheet." | |||
| 3490 | (ses-begin-change)) | 3411 | (ses-begin-change)) |
| 3491 | (ses-print-cell row col))))))) | 3412 | (ses-print-cell row col))))))) |
| 3492 | 3413 | ||
| 3493 | (defun ses-define-local-printer (printer-name) | 3414 | (defun ses-define-local-printer (name) |
| 3494 | "Define a local printer with name PRINTER-NAME." | 3415 | "Define a local printer with name NAME." |
| 3495 | (interactive "*SEnter printer name: ") | 3416 | (interactive "*SEnter printer name: ") |
| 3496 | (let* ((cur-printer (gethash printer-name ses--local-printer-hashmap)) | 3417 | (let* ((cur-printer (gethash name ses--local-printer-hashmap)) |
| 3497 | (default (and (vectorp cur-printer) (ses-locprn-get-def cur-printer))) | 3418 | (default (and (vectorp cur-printer) (ses--locprn-def cur-printer))) |
| 3498 | printer-def-text | ||
| 3499 | create-printer | 3419 | create-printer |
| 3500 | (new-printer (ses-read-printer (format "Enter definition of printer %S: " printer-name) default))) | 3420 | (new-def |
| 3421 | (ses-read-printer (format "Enter definition of printer %S: " name) | ||
| 3422 | default))) | ||
| 3501 | (cond | 3423 | (cond |
| 3502 | ;; cancelled operation => do nothing | 3424 | ;; cancelled operation => do nothing |
| 3503 | ((eq new-printer t)) | 3425 | ((eq new-def t)) |
| 3504 | ;; no change => do nothing | 3426 | ;; no change => do nothing |
| 3505 | ((and (vectorp cur-printer) (equal new-printer default))) | 3427 | ((and (vectorp cur-printer) (equal new-def default))) |
| 3506 | ;; re-defined printer | 3428 | ;; re-defined printer |
| 3507 | ((vectorp cur-printer) | 3429 | ((vectorp cur-printer) |
| 3508 | (setq create-printer 0) | 3430 | (setq create-printer 0) |
| 3509 | (ses-locprn-def-aset cur-printer new-printer) | 3431 | (setf (ses--locprn-def cur-printer) new-def) |
| 3510 | (ses-refresh-local-printer | 3432 | (ses-refresh-local-printer |
| 3511 | printer-name | 3433 | name |
| 3512 | (ses-locprn-compiled-aset cur-printer (ses-local-printer-compile new-printer)))) | 3434 | (setf (ses--locprn-compiled cur-printer) |
| 3435 | (ses-local-printer-compile new-def)))) | ||
| 3513 | ;; new definition | 3436 | ;; new definition |
| 3514 | (t | 3437 | (t |
| 3515 | (setq create-printer 1) | 3438 | (setq create-printer 1) |
| 3516 | (puthash printer-name | 3439 | (puthash name |
| 3517 | (setq cur-printer | 3440 | (setq cur-printer |
| 3518 | (ses-make-local-printer-info new-printer)) | 3441 | (ses-make-local-printer-info new-def)) |
| 3519 | ses--local-printer-hashmap))) | 3442 | ses--local-printer-hashmap))) |
| 3520 | (when create-printer | 3443 | (when create-printer |
| 3521 | (setq printer-def-text | 3444 | (let ((printer-def-text |
| 3522 | (concat | 3445 | (concat |
| 3523 | "(ses-local-printer " | 3446 | "(ses-local-printer " |
| 3524 | (symbol-name printer-name) | 3447 | (symbol-name name) |
| 3525 | " " | 3448 | " " |
| 3526 | (prin1-to-string (ses-locprn-get-def cur-printer)) | 3449 | (prin1-to-string (ses--locprn-def cur-printer)) |
| 3527 | ")")) | 3450 | ")"))) |
| 3528 | (save-excursion | 3451 | (save-excursion |
| 3529 | (ses-goto-data ses--numrows | 3452 | (ses-goto-data ses--numrows |
| 3530 | (ses-locprn-get-number cur-printer)) | 3453 | (ses--locprn-number cur-printer)) |
| 3531 | (let ((inhibit-read-only t)) | 3454 | (let ((inhibit-read-only t)) |
| 3532 | ;; Special undo since it's outside the narrowed buffer. | 3455 | ;; Special undo since it's outside the narrowed buffer. |
| 3533 | (let (buffer-undo-list) | 3456 | (let (buffer-undo-list) |
| 3534 | (if (= create-printer 0) | 3457 | (if (= create-printer 0) |
| 3535 | (delete-region (point) (line-end-position)) | 3458 | (delete-region (point) (line-end-position)) |
| 3536 | (insert ?\n) | 3459 | (insert ?\n) |
| 3537 | (backward-char)) | 3460 | (backward-char)) |
| 3538 | (insert printer-def-text) | 3461 | (insert printer-def-text) |
| 3539 | (when (= create-printer 1) | 3462 | (when (= create-printer 1) |
| 3540 | (ses-file-format-extend-paramter-list 3) | 3463 | (ses-file-format-extend-paramter-list 3) |
| 3541 | (ses-set-parameter 'ses--numlocprn (+ ses--numlocprn create-printer))) ))))) ) | 3464 | (ses-set-parameter 'ses--numlocprn |
| 3465 | (+ ses--numlocprn create-printer)))))))))) | ||
| 3542 | 3466 | ||
| 3543 | 3467 | ||
| 3544 | ;;---------------------------------------------------------------------------- | 3468 | ;;---------------------------------------------------------------------------- |