merge trunk
[bpt/emacs.git] / lisp / calc / calc-embed.el
index c6e0e33..954e5d0 100644 (file)
@@ -1,26 +1,24 @@
 ;;; calc-embed.el --- embed Calc in a buffer
 
-;; Copyright (C) 1990, 1991, 1992, 1993, 2001, 2005 Free Software Foundation, Inc.
+;; Copyright (C) 1990-1993, 2001-2012 Free Software Foundation, Inc.
 
 ;; Author: David Gillespie <daveg@synaptics.com>
-;; Maintainer: Jay Belanger <belanger@truman.edu>
+;; Maintainer: Jay Belanger <jay.p.belanger@gmail.com>
 
 ;; This file is part of GNU Emacs.
 
+;; 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 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.  No author or distributor
-;; accepts responsibility to anyone for the consequences of using it
-;; or for whether it serves any particular purpose or works at all,
-;; unless he says so in writing.  Refer to the GNU Emacs General Public
-;; License for full details.
-
-;; Everyone is granted permission to copy, modify and redistribute
-;; GNU Emacs, but only under the conditions described in the
-;; GNU Emacs General Public License.   A copy of this license is
-;; supposed to have been given to you along with GNU Emacs so you
-;; can know your rights and responsibilities.  It should be in a
-;; file named COPYING.  Among other things, the copyright notice
-;; and this notice must be preserved on all copies.
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
 (require 'calc-ext)
 (require 'calc-macs)
 
+;; Declare functions which are defined elsewhere.
+(declare-function thing-at-point-looking-at "thingatpt" (regexp))
+
+
 (defun calc-show-plain (n)
   (interactive "P")
   (calc-wrapper
 (defvar calc-embedded-announce-formula)
 (defvar calc-embedded-open-formula)
 (defvar calc-embedded-close-formula)
-(defvar calc-embedded-open-word)
-(defvar calc-embedded-close-word)
 (defvar calc-embedded-open-plain)
 (defvar calc-embedded-close-plain)
 (defvar calc-embedded-open-new-formula)
 (defvar calc-embedded-close-new-formula)
 (defvar calc-embedded-open-mode)
 (defvar calc-embedded-close-mode)
+(defvar calc-embedded-word-regexp)
 
-(defconst calc-embedded-mode-vars '(("precision" . calc-internal-prec)
+(defconst calc-embedded-mode-vars '(("twos-complement" . calc-twos-complement-mode)
+                                    ("precision" . calc-internal-prec)
                                    ("word-size" . calc-word-size)
                                    ("angles" . calc-angle-mode)
                                    ("symbolic" . calc-symbolic-mode)
 ))
 
 
-;;; Format of calc-embedded-info vector:
-;;;    0   Editing buffer.
-;;;    1   Calculator buffer.
-;;;    2   Top of current formula (marker).
-;;;    3   Bottom of current formula (marker).
-;;;    4   Top of current formula's delimiters (marker).
-;;;    5   Bottom of current formula's delimiters (marker).
-;;;    6   String representation of current formula.
-;;;    7   Non-nil if formula is embedded within a single line.
-;;;    8   Internal representation of current formula.
-;;;    9   Variable assigned by this formula, or nil.
-;;;   10   List of variables upon which this formula depends.
-;;;   11   Evaluated value of the formula, or nil.
-;;;   12   Mode settings for current formula.
-;;;   13   Local mode settings for current formula.
-;;;   14   Permanent mode settings for current formula.
-;;;   15   Global mode settings for editing buffer.
-
-
-;;; calc-embedded-active is an a-list keyed on buffers; each cdr is a
-;;; sorted list of calc-embedded-infos in that buffer.  We do this
-;;; rather than using buffer-local variables because the latter are
-;;; thrown away when a buffer changes major modes.
+;; Format of calc-embedded-info vector:
+;;    0   Editing buffer.
+;;    1   Calculator buffer.
+;;    2   Top of current formula (marker).
+;;    3   Bottom of current formula (marker).
+;;    4   Top of current formula's delimiters (marker).
+;;    5   Bottom of current formula's delimiters (marker).
+;;    6   String representation of current formula.
+;;    7   Non-nil if formula is embedded within a single line.
+;;    8   Internal representation of current formula.
+;;    9   Variable assigned by this formula, or nil.
+;;   10   List of variables upon which this formula depends.
+;;   11   Evaluated value of the formula, or nil.
+;;   12   Mode settings for current formula.
+;;   13   Local mode settings for current formula.
+;;   14   Permanent mode settings for current formula.
+;;   15   Global mode settings for editing buffer.
+
+
+;; calc-embedded-active is an a-list keyed on buffers; each cdr is a
+;; sorted list of calc-embedded-infos in that buffer.  We do this
+;; rather than using buffer-local variables because the latter are
+;; thrown away when a buffer changes major modes.
 
 (defvar calc-embedded-original-modes nil
   "The mode settings for Calc buffer when put in embedded mode.")
 
 (defun calc-embedded-save-original-modes ()
-  "Save the current Calc modes when entereding embedded mode."
+  "Save the current Calc modes when entering embedded mode."
   (let ((calcbuf (save-excursion
                    (calc-create-buffer)
                    (current-buffer)))
               (let ((var (cdr (car v))))
                 (unless (memq var '(the-language the-display-just))
                   (setq modes
-                        (cons (cons var (symbol-value var)) 
+                        (cons (cons var (symbol-value var))
                               modes))))
               (setq v (cdr v))))
           (setq calc-embedded-original-modes (cons lang modes)))
         (message "Current modes will be preserved when leaving embedded mode."))
     (message "Not in embedded mode.")))
 
-(defun calc-embedded-restore-original-modes ()
+(defun calc-embedded-restore-original-modes (calcbuf)
   "Restore the original Calc modes when leaving embedded mode."
-  (let ((calcbuf (get-buffer "*Calculator*"))
-        (changed nil)
+  (let ((changed nil)
         (lang (car calc-embedded-original-modes))
         (modes (cdr calc-embedded-original-modes)))
     (if (and calcbuf calc-embedded-original-modes)
             (calc-set-mode-line))))
     (setq calc-embedded-original-modes nil)))
 
-;; The variables calc-embed-outer-top, calc-embed-outer-bot, 
+;; The variables calc-embed-outer-top, calc-embed-outer-bot,
 ;; calc-embed-top and calc-embed-bot are
 ;; local to calc-do-embedded, calc-embedded-mark-formula,
 ;; calc-embedded-duplicate, calc-embedded-new-formula and
 
 ;; The variable calc-embed-arg is local to calc-do-embedded,
 ;; calc-embedded-update-formula, calc-embedded-edit and
-;; calc-do-embedded-activate, but is used by 
+;; calc-do-embedded-activate, but is used by
 ;; calc-embedded-make-info, which is called by the above
 ;; functions.
 (defvar calc-embed-arg)
 
 (defvar calc-embedded-quiet nil)
+
+(defvar calc-embedded-firsttime)
+(defvar calc-embedded-firsttime-buf)
+(defvar calc-embedded-firsttime-formula)
+
+;; The following is to take care of any minor modes which override
+;; a Calc command.
+(defvar calc-override-minor-modes-map
+  (make-sparse-keymap)
+  "A list of keybindings that might be overwritten by minor modes.")
+
+;; Add any keys that might be overwritten here.
+(define-key calc-override-minor-modes-map "`" 'calc-edit)
+
+(defvar calc-override-minor-modes
+  (cons t calc-override-minor-modes-map))
+
 (defun calc-do-embedded (calc-embed-arg end obeg oend)
   (if calc-embedded-info
 
 
            ((eq (current-buffer) (aref calc-embedded-info 0))
             (let* ((info calc-embedded-info)
-                   (mode calc-embedded-modes))
-              (save-excursion
-                (set-buffer (aref info 1))
+                   (mode calc-embedded-modes)
+                    (calcbuf (aref calc-embedded-info 1)))
+              (with-current-buffer (aref info 1)
                 (if (and (> (calc-stack-size) 0)
                          (equal (calc-top 1 'full) (aref info 8)))
                     (let ((calc-no-refresh-evaltos t))
                     truncate-lines (nth 2 mode)
                     buffer-read-only nil)
               (use-local-map (nth 1 mode))
+               (setq minor-mode-overriding-map-alist
+                     (remq calc-override-minor-modes minor-mode-overriding-map-alist))
               (set-buffer-modified-p (buffer-modified-p))
-               (calc-embedded-restore-original-modes)
+               (calc-embedded-restore-original-modes calcbuf)
               (or calc-embedded-quiet
-                  (message "Back to %s mode" mode-name))))
+                  (message "Back to %s mode" (format-mode-line mode-name)))))
 
            (t
             (if (buffer-name (aref calc-embedded-info 0))
-                (save-excursion
-                  (set-buffer (aref calc-embedded-info 0))
+                (with-current-buffer (aref calc-embedded-info 0)
                   (or (y-or-n-p (format "Cancel Calc Embedded mode in buffer %s? "
                                         (buffer-name)))
                       (keyboard-quit))
     (let ((modes (list mode-line-buffer-identification
                       (current-local-map)
                       truncate-lines))
+          (calc-embedded-firsttime (not calc-embedded-active))
+          (calc-embedded-firsttime-buf nil)
+          (calc-embedded-firsttime-formula nil)
          calc-embed-top calc-embed-bot calc-embed-outer-top calc-embed-outer-bot
          info chg ident)
       (barf-if-buffer-read-only)
       (calc-embedded-save-original-modes)
       (or calc-embedded-globals
          (calc-find-globals))
-      (setq info 
+      (setq info
             (calc-embedded-make-info (point) nil t calc-embed-arg end obeg oend))
       (if (eq (car-safe (aref info 8)) 'error)
          (progn
            buffer-read-only t)
       (set-buffer-modified-p (buffer-modified-p))
       (use-local-map calc-mode-map)
+      (setq minor-mode-overriding-map-alist
+            (cons calc-override-minor-modes
+                  minor-mode-overriding-map-alist))
       (setq calc-no-refresh-evaltos nil)
       (and chg calc-any-evaltos (calc-wrapper (calc-refresh-evaltos)))
       (let (str)
         (unless (equal str mode-line-buffer-identification)
           (setq mode-line-buffer-identification str)
           (set-buffer-modified-p (buffer-modified-p))))
+      (if calc-embedded-firsttime
+          (run-hooks 'calc-embedded-mode-hook))
+      (if calc-embedded-firsttime-buf
+          (run-hooks 'calc-embedded-new-buffer-hook))
+      (if calc-embedded-firsttime-formula
+          (run-hooks 'calc-embedded-new-formula-hook))
       (or (eq calc-embedded-quiet t)
          (message "Embedded Calc mode enabled; %s to return to normal"
                   (if calc-embedded-quiet
-                      "Type `M-# x'"
+                      "Type `C-x * x'"
                     "Give this command again")))))
   (scroll-down 0))    ; fix a bug which occurs when truncate-lines is changed.
 
        (start (point))
        pos)
     (switch-to-buffer calc-original-buffer)
-    (let ((val (save-excursion
-                (set-buffer (aref info 1))
+    (let ((val (with-current-buffer (aref info 1)
                 (let ((calc-language nil)
-                      (math-expr-opers math-standard-opers))
+                      (math-expr-opers (math-standard-ops)))
                   (math-read-expr str)))))
       (if (eq (car-safe val) 'error)
          (progn
       (aset info 8 val)
       (calc-embedded-update info 14 t t))))
 
+;;;###autoload
 (defun calc-do-embedded-activate (calc-embed-arg cbuf)
   (calc-plain-buffer-only)
   (if calc-embed-arg
@@ -533,7 +564,7 @@ The command \\[yank] can retrieve it from there."
     (goto-char calc-embed-outer-bot)
     (insert "\n")
     (setq new-top (point))
-    (insert-buffer-substring (current-buffer) 
+    (insert-buffer-substring (current-buffer)
                              calc-embed-outer-top calc-embed-outer-bot)
     (goto-char (+ new-top (- calc-embed-top calc-embed-outer-top)))
     (let ((calc-embedded-quiet (if already t 'x)))
@@ -628,7 +659,7 @@ The command \\[yank] can retrieve it from there."
            (equal (symbol-value (car (car v))) value))
          (progn
            (setq changed t)
-           (if temp (setq calc-embed-prev-modes 
+           (if temp (setq calc-embed-prev-modes
                            (cons (cons (car (car v))
                                        (symbol-value (car (car v))))
                                  calc-embed-prev-modes)))
@@ -778,28 +809,64 @@ The command \\[yank] can retrieve it from there."
     (list modes emodes pmodes)))
 
 ;; The variable calc-embed-vars-used is local to calc-embedded-make-info,
-;; calc-embedded-evaluate-expr and calc-embedded-update, but is 
+;; calc-embedded-evaluate-expr and calc-embedded-update, but is
 ;; used by calc-embedded-find-vars, which is called by the above functions.
 (defvar calc-embed-vars-used)
 
 (defun calc-embedded-make-info (point cbuf fresh &optional
-                                     calc-embed-top calc-embed-bot 
+                                     calc-embed-top calc-embed-bot
                                       calc-embed-outer-top calc-embed-outer-bot)
   (let* ((bufentry (assq (current-buffer) calc-embedded-active))
         (found bufentry)
-        (force (and fresh calc-embed-top))
+        (force (and fresh calc-embed-top (null (equal calc-embed-top '(t)))))
         (fixed calc-embed-top)
         (new-info nil)
         info str)
     (or found
-       (setq found (list (current-buffer))
-             calc-embedded-active (cons found calc-embedded-active)))
+        (and
+         (setq found (list (current-buffer))
+               calc-embedded-active (cons found calc-embedded-active)
+               calc-embedded-firsttime-buf t)
+         (let ((newann (assoc major-mode calc-embedded-announce-formula-alist))
+               (newform (assoc major-mode calc-embedded-open-close-formula-alist))
+               (newword (assoc major-mode calc-embedded-word-regexp-alist))
+               (newplain (assoc major-mode calc-embedded-open-close-plain-alist))
+               (newnewform
+                (assoc major-mode calc-embedded-open-close-new-formula-alist))
+               (newmode (assoc major-mode calc-embedded-open-close-mode-alist)))
+           (when newann
+             (make-local-variable 'calc-embedded-announce-formula)
+             (setq calc-embedded-announce-formula (cdr newann)))
+           (when newform
+             (make-local-variable 'calc-embedded-open-formula)
+             (make-local-variable 'calc-embedded-close-formula)
+             (setq calc-embedded-open-formula (nth 0 (cdr newform)))
+             (setq calc-embedded-close-formula (nth 1 (cdr newform))))
+           (when newword
+             (make-local-variable 'calc-embedded-word-regexp)
+             (setq calc-embedded-word-regexp (nth 1 newword)))
+           (when newplain
+             (make-local-variable 'calc-embedded-open-plain)
+             (make-local-variable 'calc-embedded-close-plain)
+             (setq calc-embedded-open-plain (nth 0 (cdr newplain)))
+             (setq calc-embedded-close-plain (nth 1 (cdr newplain))))
+           (when newnewform
+             (make-local-variable 'calc-embedded-open-new-formula)
+             (make-local-variable 'calc-embedded-close-new-formula)
+             (setq calc-embedded-open-new-formula (nth 0 (cdr newnewform)))
+             (setq calc-embedded-close-new-formula (nth 1 (cdr newnewform))))
+           (when newmode
+             (make-local-variable 'calc-embedded-open-mode)
+             (make-local-variable 'calc-embedded-close-mode)
+             (setq calc-embedded-open-mode (nth 0 (cdr newmode)))
+             (setq calc-embedded-close-mode (nth 1 (cdr newmode)))))))
     (while (and (cdr found)
                (> point (aref (car (cdr found)) 3)))
       (setq found (cdr found)))
     (if (and (cdr found)
             (>= point (aref (nth 1 found) 2)))
-       (setq info (nth 1 found))
+        (setq info (nth 1 found))
+      (setq calc-embedded-firsttime-formula t)
       (setq info (make-vector 16 nil)
            new-info t
            fresh t)
@@ -807,9 +874,9 @@ The command \\[yank] can retrieve it from there."
       (aset info 1 (or cbuf (save-excursion
                              (calc-create-buffer)
                              (current-buffer)))))
-    (if (and 
+    (if (and
          (or (integerp calc-embed-top) (equal calc-embed-top '(4)))
-         (not calc-embed-bot))  
+         (not calc-embed-bot))
                                         ; started with a user-supplied argument
        (progn
           (if (equal calc-embed-top '(4))
@@ -833,9 +900,18 @@ The command \\[yank] can retrieve it from there."
          (setq calc-embed-top (aref info 2)
                fixed calc-embed-top)
        (if (consp calc-embed-top)
-           (let ((calc-embedded-open-formula calc-embedded-open-word)
-                 (calc-embedded-close-formula calc-embedded-close-word))
-             (calc-embedded-find-bounds 'plain))
+            (progn
+              (require 'thingatpt)
+              (if (thing-at-point-looking-at calc-embedded-word-regexp)
+                  (progn
+                    (setq calc-embed-top (copy-marker (match-beginning 0)))
+                    (setq calc-embed-bot (copy-marker (match-end 0)))
+                    (setq calc-embed-outer-top calc-embed-top)
+                    (setq calc-embed-outer-bot calc-embed-bot))
+                (setq calc-embed-top (point-marker))
+                (setq calc-embed-bot (point-marker))
+                (setq calc-embed-outer-top calc-embed-top)
+                (setq calc-embed-outer-bot calc-embed-bot)))
          (or calc-embed-top
              (calc-embedded-find-bounds 'plain)))
        (aset info 2 (copy-marker (min calc-embed-top calc-embed-bot)))
@@ -867,8 +943,7 @@ The command \\[yank] can retrieve it from there."
                 (pref-len (length open-plain))
                 (calc-embed-vars-used nil)
                 suff-pos val temp)
-           (save-excursion
-             (set-buffer (aref info 1))
+           (with-current-buffer (aref info 1)
              (calc-embedded-set-modes (aref info 15)
                                       (aref info 12) (aref info 14))
              (if (and (> (length str) pref-len)
@@ -879,7 +954,9 @@ The command \\[yank] can retrieve it from there."
                             (substring str pref-len suff-pos)))
                (if (string-match "[^ \t\n]" str)
                    (setq pref-len 0
-                         val (math-read-big-expr str))
+                         val (condition-case nil
+                                  (math-read-big-expr str)
+                                (error (math-read-expr str))))
                  (setq val nil))))
            (if (eq (car-safe val) 'error)
                (setq val (list 'error
@@ -1080,7 +1157,7 @@ The command \\[yank] can retrieve it from there."
               (if need-display
                   (calc-embedded-set-justify (cdr (car calc-embed-prev-modes)))))
              (t
-              (set (car (car calc-embed-prev-modes)) 
+              (set (car (car calc-embed-prev-modes))
                     (cdr (car calc-embed-prev-modes)))))
        (setq calc-embed-prev-modes (cdr calc-embed-prev-modes))))))
 
@@ -1123,8 +1200,7 @@ The command \\[yank] can retrieve it from there."
 (defun calc-embedded-finish-command ()
   (let ((buf (current-buffer))
        horiz vert)
-    (save-excursion
-      (set-buffer (aref calc-embedded-info 1))
+    (with-current-buffer (aref calc-embedded-info 1)
       (if (> (calc-stack-size) 0)
          (let ((pt (point))
                (col (current-column))
@@ -1152,8 +1228,7 @@ The command \\[yank] can retrieve it from there."
 
 (defun calc-embedded-stack-change ()
   (or calc-executing-macro
-      (save-excursion
-       (set-buffer (aref calc-embedded-info 1))
+      (with-current-buffer (aref calc-embedded-info 1)
        (let* ((info calc-embedded-info)
               (extra-line (if (eq calc-language 'big) 1 0))
               (the-point (point))
@@ -1302,5 +1377,8 @@ The command \\[yank] can retrieve it from there."
 
 (provide 'calc-embed)
 
-;;; arch-tag: 1b8f311e-fba1-40d3-b8c3-1d6f68fd26fc
+;; Local variables:
+;; generated-autoload-file: "calc-loaddefs.el"
+;; End:
+
 ;;; calc-embed.el ends here