]> code.delx.au - gnu-emacs/blobdiff - lisp/org/org-src.el
Update copyright year to 2015
[gnu-emacs] / lisp / org / org-src.el
index 501d30ab1d710b4855854a64a1fff9bd59e874f4..5c2ceaf341bcdffea297c50a73a498014a05df55 100644 (file)
@@ -1,9 +1,9 @@
 ;;; org-src.el --- Source code examples in Org
 ;;
-;; Copyright (C) 2004-2013 Free Software Foundation, Inc.
+;; Copyright (C) 2004-2015 Free Software Foundation, Inc.
 ;;
 ;; Author: Carsten Dominik <carsten at orgmode dot org>
-;;        Bastien Guerry <bzg AT gnu DOT org>
+;;        Bastien Guerry <bzg@gnu.org>
 ;;         Dan Davison <davison at stats dot ox dot ac dot uk>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: http://orgmode.org
@@ -64,6 +64,30 @@ there are kept outside the narrowed region."
                   (const :tag "from `lang' element")
                   (const :tag "from `style' element")))))
 
+(defcustom org-edit-src-turn-on-auto-save nil
+  "Non-nil means turn `auto-save-mode' on when editing a source block.
+This will save the content of the source code editing buffer into
+a newly created file, not the base buffer for this source block.
+
+If you want to regularly save the base buffer instead of the source
+code editing buffer, see `org-edit-src-auto-save-idle-delay' instead."
+  :group 'org-edit-structure
+  :version "24.4"
+  :package-version '(Org . "8.0")
+  :type 'boolean)
+
+(defcustom org-edit-src-auto-save-idle-delay 0
+  "Delay before saving a source code buffer back into its base buffer.
+When a positive integer N, save after N seconds of idle time.
+When 0 (the default), don't auto-save.
+
+If you want to save the source code buffer itself, don't use this.
+Check `org-edit-src-turn-on-auto-save' instead."
+  :group 'org-edit-structure
+  :version "24.4"
+  :package-version '(Org . "8.0")
+  :type 'integer)
+
 (defcustom org-coderef-label-format "(ref:%s)"
   "The default coderef format.
 This format string will be used to search for coderef labels in literal
@@ -155,7 +179,7 @@ but which mess up the display of a snippet in Org exported files.")
 (defcustom org-src-lang-modes
   '(("ocaml" . tuareg) ("elisp" . emacs-lisp) ("ditaa" . artist)
     ("asymptote" . asy) ("dot" . fundamental) ("sqlite" . sql)
-    ("calc" . fundamental) ("C" . c) ("cpp" . c++)
+    ("calc" . fundamental) ("C" . c) ("cpp" . c++) ("C++" . c++)
     ("screen" . shell-script))
   "Alist mapping languages to their major mode.
 The key is the language name, the value is the string that should
@@ -174,6 +198,7 @@ For example, there is no ocaml-mode in Emacs, but the mode to use is
 
 (defvar org-src-mode-map (make-sparse-keymap))
 (define-key org-src-mode-map "\C-c'" 'org-edit-src-exit)
+(define-key org-src-mode-map "\C-c\C-k" 'org-edit-src-abort)
 (define-key org-src-mode-map "\C-x\C-s" 'org-edit-src-save)
 
 (defvar org-edit-src-force-single-line nil)
@@ -186,11 +211,15 @@ For example, there is no ocaml-mode in Emacs, but the mode to use is
 (defvar org-edit-src-block-indentation nil)
 (defvar org-edit-src-saved-temp-window-config nil)
 
-(defvar org-src-ask-before-returning-to-edit-buffer t
+(defcustom org-src-ask-before-returning-to-edit-buffer t
   "If nil, when org-edit-src code is used on a block that already
 has an active edit buffer, it will switch to that edit buffer
 immediately; otherwise it will ask whether you want to return to
-the existing edit buffer.")
+the existing edit buffer."
+  :group 'org-edit-structure
+  :version "24.4"
+  :package-version '(Org . "8.0")
+  :type 'boolean)
 
 (defvar org-src-babel-info nil)
 
@@ -202,6 +231,7 @@ This minor mode is turned on in two situations:
 There is a mode hook, and keybindings for `org-edit-src-exit' and
 `org-edit-src-save'")
 
+(defvar org-edit-src-code-timer nil)
 (defun org-edit-src-code (&optional context code edit-buffer-name)
   "Edit the source CODE block at point.
 The code is copied to a separate buffer and the appropriate mode
@@ -241,8 +271,8 @@ the display of windows containing the Org buffer and the code buffer."
            end (move-marker end (nth 1 info))
            msg (if allow-write-back-p
                    (substitute-command-keys
-                    "Edit, then exit with C-c ' (C-c and single quote)")
-                 "Exit with C-c ' (C-c and single quote)")
+                    "Edit, then exit with C-c ' (C-c and single quote) -- C-c C-k to abort")
+                 "Exit with C-c ' (C-c and single quote) -- C-c C-k to abort")
            code (or code (buffer-substring-no-properties beg end))
            lang (or (cdr (assoc (nth 2 info) org-src-lang-modes))
                     (nth 2 info))
@@ -318,7 +348,7 @@ the display of windows containing the Org buffer and the code buffer."
          (condition-case e
              (funcall lang-f)
            (error
-            (error "Language mode `%s' fails with: %S" lang-f (nth 1 e)))))
+            (message "Language mode `%s' fails with: %S" lang-f (nth 1 e)))))
        (dolist (pair transmitted-variables)
          (org-set-local (car pair) (cadr pair)))
        ;; Remove protecting commas from visible part of buffer.
@@ -336,11 +366,30 @@ the display of windows containing the Org buffer and the code buffer."
        (org-src-mode)
        (set-buffer-modified-p nil)
        (setq buffer-file-name nil)
+       (when org-edit-src-turn-on-auto-save
+         (setq buffer-auto-save-file-name
+               (concat (make-temp-name "org-src-")
+                       (format-time-string "-%Y-%d-%m") ".txt")))
        (and org-edit-src-persistent-message
             (org-set-local 'header-line-format msg))
        (let ((edit-prep-func (intern (concat "org-babel-edit-prep:" lang))))
          (when (fboundp edit-prep-func)
-           (funcall edit-prep-func full-info))))
+           (funcall edit-prep-func full-info)))
+       (or org-edit-src-code-timer
+           (zerop org-edit-src-auto-save-idle-delay)
+           (setq org-edit-src-code-timer
+                 (run-with-idle-timer
+                  org-edit-src-auto-save-idle-delay t
+                  (lambda ()
+                    (cond
+                     ((org-string-match-p "\\`\\*Org Src" (buffer-name))
+                      (when (buffer-modified-p) (org-edit-src-save)))
+                     ((not (org-some (lambda (b)
+                                       (org-string-match-p "\\`\\*Org Src"
+                                                           (buffer-name b)))
+                                     (buffer-list)))
+                      (cancel-timer org-edit-src-code-timer)
+                      (setq org-edit-src-code-timer nil))))))))
       t)))
 
 (defun org-edit-src-continue (e)
@@ -420,7 +469,7 @@ the fragment in the Org-mode buffer."
        (col (current-column))
        (case-fold-search t)
        (msg (substitute-command-keys
-             "Edit, then exit with C-c ' (C-c and single quote)"))
+             "Edit, then exit with C-c ' (C-c and single quote) -- C-c C-k to abort"))
        (org-mode-p (derived-mode-p 'org-mode))
        (beg (make-marker))
        (end (make-marker))
@@ -520,22 +569,12 @@ the language, a switch telling if the content should be in a single line."
            ("^[ \t]*#\\+begin_latex.*\n" "\n[ \t]*#\\+end_latex" "latex")
            ("^[ \t]*#\\+ascii:" "\n" "fundamental" single-line)
            ("^[ \t]*#\\+begin_ascii.*\n" "\n[ \t]*#\\+end_ascii" "fundamental")
-           ("^[ \t]*#\\+docbook:" "\n" "xml" single-line)
            ("^[ \t]*#\\+macro:[ \t]+\\S-+\\( \\|$\\)"
             "\n" "fundamental" macro-definition)
-           ("^[ \t]*#\\+begin_docbook.*\n" "\n[ \t]*#\\+end_docbook" "xml")
            )))
        (pos (point))
        re1 re2 single beg end lang lfmt match-re1 ind entry)
     (catch 'exit
-      (when (org-at-table.el-p)
-       (re-search-backward "^[\t]*[^ \t|\\+]" nil t)
-       (setq beg (1+ (point-at-eol)))
-       (goto-char beg)
-       (or (re-search-forward "^[\t]*[^ \t|\\+]" nil t)
-           (progn (goto-char (point-max)) (newline)))
-       (setq end (1- (point-at-bol)))
-       (throw 'exit (list beg end 'table.el nil nil 0)))
       (while (setq entry (pop re-list))
        (setq re1 (car entry) re2 (nth 1 entry) lang (nth 2 entry)
              single (nth 3 entry))
@@ -566,7 +605,15 @@ the language, a switch telling if the content should be in a single line."
                        (throw 'exit
                               (list (match-end 0) end
                                     (org-edit-src-get-lang lang)
-                                    single lfmt ind))))))))))))
+                                    single lfmt ind)))))))))
+      (when (org-at-table.el-p)
+       (re-search-backward "^[\t]*[^ \t|\\+]" nil t)
+       (setq beg (1+ (point-at-eol)))
+       (goto-char beg)
+       (or (re-search-forward "^[\t]*[^ \t|\\+]" nil t)
+           (progn (goto-char (point-max)) (newline)))
+       (setq end (1- (point-at-bol)))
+       (throw 'exit (list beg end 'table.el nil nil 0))))))
 
 (defun org-edit-src-get-lang (lang)
   "Extract the src language."
@@ -688,8 +735,8 @@ with \",*\", \",#+\", \",,*\" and \",,#+\"."
       (unless (or single preserve-indentation (= total-nindent 0))
        (setq indent (make-string total-nindent ?\ ))
        (goto-char (point-min))
-       (while (re-search-forward "^" nil t)
-         (replace-match indent)))
+       (while (re-search-forward "\\(^\\).+" nil t)
+         (replace-match indent nil nil nil 1)))
       (if (org-bound-and-true-p org-edit-src-picture)
          (setq total-nindent (+ total-nindent 2)))
       (setq code (buffer-string))
@@ -699,12 +746,17 @@ with \",*\", \",#+\", \",,*\" and \",,#+\"."
       (set-buffer-modified-p nil))
     (org-src-switch-to-buffer (marker-buffer beg) (or context 'exit))
     (if (eq context 'save) (save-buffer)
+      (with-current-buffer buffer
+       (set-buffer-modified-p nil))
       (kill-buffer buffer))
     (goto-char beg)
     (when allow-write-back-p
+      (undo-boundary)
       (delete-region beg (max beg end))
       (unless (string-match "\\`[ \t]*\\'" code)
        (insert code))
+      ;; Make sure the overlay stays in place
+      (when (eq context 'save) (move-overlay ovl beg (point)))
       (goto-char beg)
       (if single (just-one-space)))
     (if (memq t (mapcar (lambda (overlay)
@@ -714,8 +766,9 @@ with \",*\", \",#+\", \",,*\" and \",,#+\"."
        ;; Block is hidden; put point at start of block
        (beginning-of-line 0)
       ;; Block is visible, put point where it was in the code buffer
-      (org-goto-line (1- (+ (org-current-line) line)))
-      (org-move-to-column (if preserve-indentation col (+ col total-nindent delta))))
+      (when allow-write-back-p
+       (org-goto-line (1- (+ (org-current-line) line)))
+       (org-move-to-column (if preserve-indentation col (+ col total-nindent delta)))))
     (unless (eq context 'save)
       (move-marker beg nil)
       (move-marker end nil)))
@@ -724,6 +777,12 @@ with \",*\", \",#+\", \",,*\" and \",,#+\"."
       (set-window-configuration org-edit-src-saved-temp-window-config)
       (setq org-edit-src-saved-temp-window-config nil))))
 
+(defun org-edit-src-abort ()
+  "Abort editing of the src code and return to the Org buffer."
+  (interactive)
+  (let (org-edit-src-allow-write-back-p)
+    (org-edit-src-exit 'exit)))
+
 (defmacro org-src-in-org-buffer (&rest body)
   `(let ((p (point)) (m (mark)) (ul buffer-undo-list) msg)
      (save-window-excursion
@@ -743,9 +802,11 @@ with \",*\", \",#+\", \",,*\" and \",,#+\"."
 (defun org-edit-src-save ()
   "Save parent buffer with current state source-code buffer."
   (interactive)
-  (org-src-in-org-buffer (save-buffer)))
+  (if (string-match "Fixed Width" (buffer-name))
+      (user-error "Use C-c ' to save and exit, C-c C-k to abort editing")
+    (org-src-in-org-buffer (save-buffer))))
 
-(declare-function org-babel-tangle "ob-tangle" (&optional only-this-block target-file lang))
+(declare-function org-babel-tangle "ob-tangle" (&optional arg target-file lang))
 
 (defun org-src-tangle (arg)
   "Tangle the parent buffer."
@@ -778,8 +839,9 @@ with \",*\", \",#+\", \",,*\" and \",,#+\"."
   (let ((session (cdr (assoc :session (nth 2 info)))))
     (and session (not (string= session "none"))
         (org-babel-comint-buffer-livep session)
-        ((lambda (f) (and (fboundp f) (funcall f session)))
-         (intern (format "org-babel-%s-associate-session" (nth 0 info)))))))
+        (let ((f (intern (format "org-babel-%s-associate-session"
+                                  (nth 0 info)))))
+           (and (fboundp f) (funcall f session))))))
 
 (defun org-src-babel-configure-edit-buffer ()
   (when org-src-babel-info
@@ -829,9 +891,9 @@ issued in the language major mode buffer."
 
 (defun org-src-native-tab-command-maybe ()
   "Perform language-specific TAB action.
-Alter code block according to effect of TAB in the language major
-mode."
+Alter code block according to what TAB does in the language major mode."
   (and org-src-tab-acts-natively
+       (org-in-src-block-p)
        (not (equal this-command 'org-shifttab))
        (let ((org-src-strip-leading-and-trailing-blank-lines nil))
         (org-babel-do-key-sequence-in-edit-buffer (kbd "TAB")))))
@@ -856,7 +918,7 @@ fontification of code blocks see `org-src-fontify-block' and
            (delete-region (point-min) (point-max))
            (insert string " ") ;; so there's a final property change
            (unless (eq major-mode lang-mode) (funcall lang-mode))
-           (font-lock-fontify-buffer)
+            (org-font-lock-ensure)
            (setq pos (point-min))
            (while (setq next (next-single-property-change pos 'face))
              (put-text-property
@@ -887,8 +949,9 @@ fontification of code blocks see `org-src-fontify-block' and
 LANG is a string, and the returned major mode is a symbol."
   (intern
    (concat
-    ((lambda (l) (if (symbolp l) (symbol-name l) l))
-     (or (cdr (assoc lang org-src-lang-modes)) lang)) "-mode")))
+    (let ((l (or (cdr (assoc lang org-src-lang-modes)) lang)))
+      (if (symbolp l) (symbol-name l) l))
+    "-mode")))
 
 (provide 'org-src)