;;; ses.el -- Simple Emacs Spreadsheet -*- coding: utf-8 -*-
-;; Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+;; Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+;; Free Software Foundation, Inc.
;; Author: Jonathan Yavner <jyavner@member.fsf.org>
;; Maintainer: Jonathan Yavner <jyavner@member.fsf.org>
;; This file is part of GNU Emacs.
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
"\"" ses-read-cell
"'" ses-read-symbol
"=" ses-edit-cell
+ "c" ses-recalculate-cell
"j" ses-jump
"p" ses-read-cell-printer
+ "t" ses-truncate-cell
"w" ses-set-column-width
"x" ses-export-keymap
"\M-p" ses-read-column-printer))
(make-local-variable x)
(set x nil)))
+;;;This variable is documented as being permitted in file-locals:
+(put 'ses--symbolic-formulas 'safe-local-variable 'consp)
+
(defconst ses-paramlines-plist
'(ses--col-widths -5 ses--col-printers -4 ses--default-printer -3
ses--header-row -2 ses--file-format 1 ses--numrows 2
(list (symbol-name (cadr formula))))))
(defun ses-column-letter (col)
- "Converts a column number to A..Z or AA..ZZ"
- (if (< col 26)
- (char-to-string (+ ?A col))
- (string (+ ?@ (/ col 26)) (+ ?A (% col 26)))))
+ "Return the alphabetic name of column number COL.
+0-25 become A-Z; 26-701 become AA-ZZ, and so on."
+ (let ((units (char-to-string (+ ?A (% col 26)))))
+ (if (< col 26)
+ units
+ (concat (ses-column-letter (1- (/ col 26))) units))))
(defun ses-create-cell-symbol (row col)
"Produce a symbol that names the cell (ROW,COL). (0,0) => 'A1."
(let ((oldval (ses-cell-value cell))
(formula (ses-cell-formula cell))
newval)
- (if (eq (car-safe formula) 'ses-safe-formula)
- (ses-set-cell row col 'formula (ses-safe-formula (cadr formula))))
+ (when (eq (car-safe formula) 'ses-safe-formula)
+ (setq formula (ses-safe-formula (cadr formula)))
+ (ses-set-cell row col 'formula formula))
(condition-case sig
(setq newval (eval formula))
(error
;;ses-goto-print is called during a recursive ses-print-cell).
(defun ses-goto-print (row col)
"Move point to print area for cell (ROW,COL)."
- (let ((inhibit-point-motion-hooks t))
+ (let ((inhibit-point-motion-hooks t)
+ (n 0))
(goto-char (point-min))
(forward-line row)
+ ;; calculate column position
(dotimes (c col)
- (forward-char (1+ (ses-col-width c))))))
+ (setq n (+ n (ses-col-width c) 1)))
+ ;; move to the position
+ (and (> n (move-to-column n))
+ (eolp)
+ ;; move point to the bol of next line (for TAB at the last cell)
+ (forward-char))))
(defun ses-set-curcell ()
"Sets `ses--curcell' to the current cell symbol, or a cons (BEG,END) for a
;;Range
(let ((bcell (get-text-property (region-beginning) 'intangible))
(ecell (get-text-property (1- (region-end)) 'intangible)))
+ (when (= (region-end) ses--data-marker)
+ ;;Correct for overflow
+ (setq ecell (get-text-property (- (region-end) 2) 'intangible)))
(setq ses--curcell (if (and bcell ecell)
(cons bcell ecell)
nil))))
(setq sig ses-call-printer-return))))
;;Adjust print width to match column width
(let ((width (ses-col-width col))
- (len (length text)))
+ (len (string-width text)))
(cond
((< len width)
;;Fill field to length with spaces
(setq sig `(error "Too wide" ,text))
(cond
((stringp value)
- (setq text (substring text 0 maxwidth)))
+ (setq text (truncate-string-to-width text maxwidth 0 ?\s)))
((and (numberp value)
(string-match "\\.[0-9]+" text)
(>= 0 (setq width
;;Install the printed result. This is not interruptible.
(let ((inhibit-read-only t)
(inhibit-quit t))
- (delete-char (1+ (length text)))
+ (let ((inhibit-point-motion-hooks t))
+ (delete-region (point) (progn
+ (move-to-column (+ (current-column)
+ (string-width text)))
+ (1+ (point)))))
;;We use concat instead of inserting separate strings in order to
;;reduce the number of cells in the undo list.
(setq x (concat text (if (< maxcol ses--numcols) " " "\n")))
(defun ses-call-printer (printer &optional value)
"Invokes PRINTER (a string or parenthesized string or function-symbol or
-lambda of one argument) on VALUE. Result is the the printed cell as a
-string. The variable `ses-call-printer-return' is set to t if the printer
-used parenthesis to request left-justification, or the error-signal if the
+lambda of one argument) on VALUE. Result is the printed cell as a string.
+The variable `ses-call-printer-return' is set to t if the printer used
+parenthesis to request left-justification, or the error-signal if the
printer signaled one (and \"%s\" is used as the default printer), else nil."
(setq ses-call-printer-return nil)
(unless value
(interactive)
(let ((end (point-min))
(inhibit-read-only t)
+ (inhibit-point-motion-hooks t)
(was-modified (buffer-modified-p))
pos sym)
(ses-goto-data 0 0) ;;Include marker between print-area and data-area
(eq (ses-cell-value row (1+ col)) '*skip*))
(setq end (+ end (ses-col-width col) 1)
col (1+ col)))
- (setq end (+ end (ses-col-width col) 1))
+ (setq end (save-excursion
+ (goto-char pos)
+ (move-to-column (+ (current-column) (- end pos)
+ (ses-col-width col)))
+ (if (eolp)
+ (+ end (ses-col-width col) 1)
+ (forward-char)
+ (point))))
(put-text-property pos end 'intangible sym)))
;;Adding these properties did not actually alter the text
(unless was-modified
(overlay-put ses--curcell-overlay 'face 'underline))
(defun ses-cleanup ()
- "Cleanup when changing a buffer from SES mode to something else. Delete
-overlay, remove special text properties."
+ "Cleanup when changing a buffer from SES mode to something else.
+Delete overlays, remove special text properties."
(widen)
(let ((inhibit-read-only t)
+ ;; When reverting, hide the buffer name, otherwise Emacs will ask
+ ;; the user "the file is modified, do you really want to make
+ ;; modifications to this buffer", where the "modifications" refer to
+ ;; the irrelevant set-text-properties below.
+ (buffer-file-name nil)
(was-modified (buffer-modified-p)))
;;Delete read-only, keymap, and intangible properties
(set-text-properties (point-min) (point-max) nil)
;;Delete overlay
(mapc 'delete-overlay (overlays-in (point-min) (point-max)))
(unless was-modified
- (set-buffer-modified-p nil))))
+ (restore-buffer-modified-p nil))))
;;;###autoload
(defun ses-mode ()
;;SES deliberately puts lots of trailing whitespace in its buffer
show-trailing-whitespace nil
;;Cell ranges do not work reasonably without this
- transient-mark-mode t)
+ transient-mark-mode t
+ ;;not to use tab characters for safe
+ ;;(tabs may do bad for column calculation)
+ indent-tabs-mode nil)
(1value (add-hook 'change-major-mode-hook 'ses-cleanup nil t))
(1value (add-hook 'before-revert-hook 'ses-cleanup nil t))
(setq ses--curcell nil
(defun ses-copy-region (beg end)
"Treat the region as rectangular. Convert the intangible attributes to
SES attributes recording the contents of the cell as of the time of copying."
+ (when (= end ses--data-marker)
+ ;;Avoid overflow situation
+ (setq end (1- ses--data-marker)))
(let* ((inhibit-point-motion-hooks t)
(x (mapconcat 'ses-copy-region-helper
(extract-rectangle beg (1- end)) "\n")))
;;----------------------------------------------------------------------------
;;These functions use the variables 'row' and 'col' that are
-;;dynamically bound by ses-print-cell. We define these varables at
+;;dynamically bound by ses-print-cell. We define these variables at
;;compile-time to make the compiler happy.
(eval-when-compile
(dolist (x '(row col))
(setq value (ses-call-printer printer value))
(dotimes (x span)
(setq width (+ width 1 (ses-col-width (+ col span (- x))))))
- (setq width (- width (length value)))
+ ;; set column width
+ (setq width (- width (string-width value)))
(if (<= width 0)
value ;Too large for field, anyway
(setq half (make-string (/ width 2) fill))
(dolist (x (cons 'ses-unsafe ses-standard-printer-functions))
(put x 'side-effect-free t))
+(defun ses-unload-function ()
+ "Unload the Simple Emacs Spreadsheet."
+ (dolist (fun '(copy-region-as-kill yank))
+ (ad-remove-advice fun 'around (intern (concat "ses-" (symbol-name fun))))
+ (ad-update fun))
+ (save-current-buffer
+ (dolist (buf (buffer-list))
+ (set-buffer buf)
+ (when (eq major-mode 'ses-mode)
+ (funcall (or (default-value 'major-mode) 'fundamental-mode)))))
+ ;; continue standard unloading
+ nil)
+
(provide 'ses)
;; arch-tag: 88c1ccf0-4293-4824-8c5d-0757b52217f3