frameset.el (frameset--jump-to-register): Check that buffer is live (bug#16749).
[bpt/emacs.git] / lisp / progmodes / sql.el
index 940afc3..eb8e076 100644 (file)
@@ -1,10 +1,10 @@
 ;;; sql.el --- specialized comint.el for SQL interpreters  -*- lexical-binding: t -*-
 
-;; Copyright (C) 1998-2013 Free Software Foundation, Inc.
+;; Copyright (C) 1998-2014 Free Software Foundation, Inc.
 
 ;; Author: Alex Schroeder <alex@gnu.org>
 ;; Maintainer: Michael Mauger <michael@mauger.com>
-;; Version: 3.2
+;; Version: 3.3
 ;; Keywords: comm languages processes
 ;; URL: http://savannah.gnu.org/projects/emacs/
 
   (require 'regexp-opt))
 (require 'custom)
 (require 'thingatpt)
+(require 'view)
 
 (defvar font-lock-keyword-face)
 (defvar font-lock-set-defaults)
   :group 'languages
   :group 'processes)
 
-;; These four variables will be used as defaults, if set.
+;; These five variables will be used as defaults, if set.
 
 (defcustom sql-user ""
   "Default username."
@@ -437,7 +438,7 @@ file.  Since that is a plaintext file, this could be dangerous."
      :completion-object sql-oracle-completion-object
      :prompt-regexp "^SQL> "
      :prompt-length 5
-     :prompt-cont-regexp "^\\s-*[[:digit:]]+  "
+     :prompt-cont-regexp "^\\(?:[ ][ ][1-9]\\|[ ][1-9][0-9]\\|[1-9][0-9]\\{2\\}\\)[ ]\\{2\\}"
      :statement sql-oracle-statement-starters
      :syntax-alist ((?$ . "_") (?# . "_"))
      :terminator ("\\(^/\\|;\\)$" . "/")
@@ -2438,7 +2439,7 @@ configuration."
       (user-error "Product `%s' is already defined" product)
 
     ;; Add product to the alist
-    (add-to-list 'sql-product-alist `((,product :name ,display . ,plist)))
+    (add-to-list 'sql-product-alist `(,product :name ,display . ,plist))
     ;; Add a menu item to the SQL->Product menu
     (easy-menu-add-item sql-mode-menu '("Product")
                        ;; Each product is represented by a radio
@@ -2825,14 +2826,14 @@ each line with INDENT."
                      "]\n"))))
     doc))
 
-;;;###autoload
-(eval
- ;; FIXME: This dynamic-docstring-function trick doesn't work for byte-compiled
- ;; functions, because of the lazy-loading of docstrings, which strips away
- ;; text properties.
- '(defun sql-help ()
-  #("Show short help for the SQL modes.
+(defun sql-help ()
+  "Show short help for the SQL modes."
+  (interactive)
+  (describe-function 'sql-help))
+(put 'sql-help 'function-documentation '(sql--make-help-docstring))
 
+(defvar sql--help-docstring
+  "Show short help for the SQL modes.
 Use an entry function to open an interactive SQL buffer.  This buffer is
 usually named `*SQL*'.  The name of the major mode is SQLi.
 
@@ -2861,24 +2862,20 @@ anything.  The name of the major mode is SQL.
 
 In this SQL buffer (SQL mode), you can send the region or the entire
 buffer to the interactive SQL buffer (SQLi mode).  The results are
-appended to the SQLi buffer without disturbing your SQL buffer."
-    0 1 (dynamic-docstring-function sql--make-help-docstring))
-  (interactive)
-  (describe-function 'sql-help)))
-
-(defun sql--make-help-docstring (doc _fun)
-  "Insert references to loaded products into the help buffer string."
-
-  ;; Insert FREE software list
-  (when (string-match "^\\(\\s-*\\)[\\\\][\\\\]FREE\\s-*\n" doc 0)
-    (setq doc (replace-match (sql-help-list-products (match-string 1 doc) t)
-                             t t doc 0)))
-
-  ;; Insert non-FREE software list
-  (when (string-match "^\\(\\s-*\\)[\\\\][\\\\]NONFREE\\s-*\n" doc 0)
-    (setq doc (replace-match (sql-help-list-products (match-string 1 doc) nil)
-                             t t doc 0)))
-  doc)
+appended to the SQLi buffer without disturbing your SQL buffer.")
+
+(defun sql--make-help-docstring ()
+  "Return a docstring for `sql-help' listing loaded SQL products."
+  (let ((doc sql--help-docstring))
+    ;; Insert FREE software list
+    (when (string-match "^\\(\\s-*\\)[\\\\][\\\\]FREE\\s-*$" doc 0)
+      (setq doc (replace-match (sql-help-list-products (match-string 1 doc) t)
+                              t t doc 0)))
+    ;; Insert non-FREE software list
+    (when (string-match "^\\(\\s-*\\)[\\\\][\\\\]NONFREE\\s-*$" doc 0)
+      (setq doc (replace-match (sql-help-list-products (match-string 1 doc) nil)
+                              t t doc 0)))
+    doc))
 
 (defun sql-default-value (var)
   "Fetch the value of a variable.
@@ -3276,6 +3273,17 @@ Allows the suppression of continuation prompts.")
 
 (defvar sql-preoutput-hold nil)
 
+(defun sql-starts-with-prompt-re ()
+  "Anchor the prompt expression at the beginning of the output line.
+Remove the start of line regexp."
+  (replace-regexp-in-string "\\^" "\\\\`" comint-prompt-regexp))
+
+(defun sql-ends-with-prompt-re ()
+  "Anchor the prompt expression at the end of the output line.
+Remove the start of line regexp from the prompt expression since
+it may not follow newline characters in the output line."
+  (concat (replace-regexp-in-string "\\^" "" sql-prompt-regexp) "\\'"))
+
 (defun sql-interactive-remove-continuation-prompt (oline)
   "Strip out continuation prompts out of the OLINE.
 
@@ -3293,38 +3301,52 @@ to the next chunk to properly match the broken-up prompt.
 If the filter gets confused, it should reset and stop filtering
 to avoid deleting non-prompt output."
 
-  (let (did-filter)
-    (setq oline (concat (or sql-preoutput-hold "") oline)
-          sql-preoutput-hold nil)
-
-    (if (and comint-prompt-regexp
-             (integerp sql-output-newline-count)
-             (>= sql-output-newline-count 1))
-        (progn
-          (while (and (not (string= oline ""))
-                      (> sql-output-newline-count 0)
-                      (string-match comint-prompt-regexp oline)
-                      (= (match-beginning 0) 0))
+  (when comint-prompt-regexp
+    (save-match-data
+      (let (prompt-found last-nl)
 
-            (setq oline (replace-match "" nil nil oline)
-                  sql-output-newline-count (1- sql-output-newline-count)
-                  did-filter t))
+        ;; Add this text to what's left from the last pass
+        (setq oline (concat sql-preoutput-hold oline)
+              sql-preoutput-hold "")
 
+        ;; If we are looking for multiple prompts
+        (when (and (integerp sql-output-newline-count)
+                   (>= sql-output-newline-count 1))
+          ;; Loop thru each starting prompt and remove it
+          (let ((start-re (sql-starts-with-prompt-re)))
+            (while (and (not (string= oline ""))
+                      (> sql-output-newline-count 0)
+                      (string-match start-re oline))
+              (setq oline (replace-match "" nil nil oline)
+                    sql-output-newline-count (1- sql-output-newline-count)
+                    prompt-found t)))
+          
+          ;; If we've found all the expected prompts, stop looking
           (if (= sql-output-newline-count 0)
               (setq sql-output-newline-count nil
                     oline (concat "\n" oline))
 
+            ;; Still more possible prompts, leave them for the next pass
             (setq sql-preoutput-hold oline
-                  oline ""))
-
-          (unless did-filter
-            (setq oline (or sql-preoutput-hold "")
-                  sql-preoutput-hold nil
-                  sql-output-newline-count nil)))
-
-      (setq sql-output-newline-count nil))
-
-    oline))
+                  oline "")))
+
+        ;; If no prompts were found, stop looking
+        (unless prompt-found
+          (setq sql-output-newline-count nil
+                oline (concat oline sql-preoutput-hold)
+                sql-preoutput-hold ""))
+
+        ;; Break up output by physical lines if we haven't hit the final prompt
+        (unless (and (not (string= oline ""))
+                     (string-match (sql-ends-with-prompt-re) oline)
+                     (>= (match-end 0) (length oline)))
+          (setq last-nl 0)
+          (while (string-match "\n" oline last-nl)
+            (setq last-nl (match-end 0)))
+          (setq sql-preoutput-hold (concat (substring oline last-nl)
+                                           sql-preoutput-hold)
+                oline (substring oline 0 last-nl))))))
+   oline)
 
 ;;; Sending the region to the SQLi buffer.
 
@@ -3462,7 +3484,8 @@ list of SQLi command strings."
                                                          :prompt-regexp))
           (start nil))
       (with-current-buffer buf
-        (setq view-read-only nil)
+        (setq-local view-no-disable-on-exit t)
+        (read-only-mode -1)
         (unless save-prior
           (erase-buffer))
         (goto-char (point-max))
@@ -3571,8 +3594,8 @@ buffer is popped into a view window."
                        (get-lru-window))))
       (with-current-buffer outbuf
         (set-buffer-modified-p nil)
-        (setq view-read-only t))
-      (view-buffer-other-window outbuf)
+        (read-only-mode +1))
+      (pop-to-buffer outbuf)
       (when one-win
         (shrink-window-if-larger-than-buffer)))))
 
@@ -3747,7 +3770,9 @@ must tell Emacs.  Here's how to do that in your init file:
   (setq-local abbrev-all-caps 1)
   ;; Contains the name of database objects
   (set (make-local-variable 'sql-contains-names) t)
+  ;; Set syntax and font-face highlighting
   ;; Catch changes to sql-product and highlight accordingly
+  (sql-set-product (or sql-product 'ansi)) ; Fixes bug#13591
   (add-hook 'hack-local-variables-hook 'sql-highlight-product t t))
 
 \f