summaryrefslogtreecommitdiff
path: root/lisp/org-src.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/org-src.el')
-rw-r--r--lisp/org-src.el255
1 files changed, 174 insertions, 81 deletions
diff --git a/lisp/org-src.el b/lisp/org-src.el
index 9d6bc1a..81b8e40 100644
--- a/lisp/org-src.el
+++ b/lisp/org-src.el
@@ -1,6 +1,6 @@
;;; org-src.el --- Source code examples in Org
;;
-;; Copyright (C) 2004-2012 Free Software Foundation, Inc.
+;; Copyright (C) 2004-2013 Free Software Foundation, Inc.
;;
;; Author: Carsten Dominik <carsten at orgmode dot org>
;; Bastien Guerry <bzg AT gnu DOT org>
@@ -39,12 +39,12 @@
(declare-function org-do-remove-indentation "org" (&optional n))
(declare-function org-at-table.el-p "org" ())
+(declare-function org-in-src-block-p "org" (&optional inside))
+(declare-function org-in-block-p "org" (names))
(declare-function org-get-indentation "org" (&optional line))
(declare-function org-switch-to-buffer-other-window "org" (&rest args))
-(declare-function org-strip-protective-commas "org" (beg end))
(declare-function org-pop-to-buffer-same-window
"org-compat" (&optional buffer-or-name norecord label))
-(declare-function org-strip-protective-commas "org" (beg end))
(declare-function org-base-buffer "org" (buffer))
(defcustom org-edit-src-region-extra nil
@@ -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 regularily 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
@@ -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,40 +231,51 @@ 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 example at point.
-The example is copied to a separate buffer, and that buffer is
-switched to the correct language mode. When done, exit with
-\\[org-edit-src-exit]. This will remove the original code in the
-Org buffer, and replace it with the edited version. An optional
-argument CONTEXT is used by \\[org-edit-src-save] when calling
-this function. See `org-src-window-setup' to configure the
-display of windows containing the Org buffer and the code
-buffer."
+ "Edit the source CODE block at point.
+The code is copied to a separate buffer and the appropriate mode
+is turned on. When done, exit with \\[org-edit-src-exit]. This will
+remove the original code in the Org buffer, and replace it with the
+edited version. An optional argument CONTEXT is used by \\[org-edit-src-save]
+when calling this function. See `org-src-window-setup' to configure
+the display of windows containing the Org buffer and the code buffer."
(interactive)
- (unless (eq context 'save)
- (setq org-edit-src-saved-temp-window-config (current-window-configuration)))
- (let* ((mark (and (org-region-active-p) (mark)))
- (case-fold-search t)
- (info (org-edit-src-find-region-and-lang))
- (full-info (org-babel-get-src-block-info 'light))
- (org-mode-p (derived-mode-p 'org-mode)) ;; derived-mode-p is reflexive
- (beg (make-marker))
- (end (make-marker))
- (allow-write-back-p (null code))
- block-nindent total-nindent ovl lang lang-f single lfmt buffer msg
- begline markline markcol line col transmitted-variables)
- (if (not info)
- nil
+ (if (not (or (org-in-block-p '("src" "example" "latex" "html"))
+ (org-at-table.el-p)))
+ (user-error "Not in a source code or example block")
+ (unless (eq context 'save)
+ (setq org-edit-src-saved-temp-window-config (current-window-configuration)))
+ (let* ((mark (and (org-region-active-p) (mark)))
+ (case-fold-search t)
+ (info
+ ;; If the src region consists in no lines, we insert a blank
+ ;; line.
+ (let* ((temp (org-edit-src-find-region-and-lang))
+ (beg (nth 0 temp))
+ (end (nth 1 temp)))
+ (if (>= end beg) temp
+ (goto-char beg)
+ (insert "\n")
+ (org-edit-src-find-region-and-lang))))
+ (full-info (org-babel-get-src-block-info 'light))
+ (org-mode-p (derived-mode-p 'org-mode)) ;; derived-mode-p is reflexive
+ (beg (make-marker))
+ ;; Move marker with inserted text for case when src block is
+ ;; just one empty line, i.e. beg == end.
+ (end (copy-marker (make-marker) t))
+ (allow-write-back-p (null code))
+ block-nindent total-nindent ovl lang lang-f single lfmt buffer msg
+ begline markline markcol line col transmitted-variables)
(setq beg (move-marker beg (nth 0 info))
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))
+ (nth 2 info))
lang (if (symbolp lang) (symbol-name lang) lang)
single (nth 3 info)
block-nindent (nth 5 info)
@@ -311,13 +351,8 @@ buffer."
(error "Language mode `%s' fails with: %S" lang-f (nth 1 e)))))
(dolist (pair transmitted-variables)
(org-set-local (car pair) (cadr pair)))
- (if (derived-mode-p 'org-mode)
- (progn
- (goto-char (point-min))
- (while (re-search-forward "^," nil t)
- (if (eq (org-current-line) line) (setq total-nindent (1+ total-nindent)))
- (replace-match "")))
- (org-strip-protective-commas (point-min) (point-max)))
+ ;; Remove protecting commas from visible part of buffer.
+ (org-unescape-code-in-region (point-min) (point-max))
(when markline
(org-goto-line (1+ (- markline begline)))
(org-move-to-column
@@ -331,12 +366,33 @@ 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))))
- t)))
+ (funcall edit-prep-func full-info)))
+ (or org-edit-src-code-timer
+ (setq org-edit-src-code-timer
+ (unless (zerop org-edit-src-auto-save-idle-delay)
+ (run-with-idle-timer
+ org-edit-src-auto-save-idle-delay t
+ (lambda ()
+ (cond
+ ((and (string-match "\*Org Src" (buffer-name))
+ (buffer-modified-p))
+ (org-edit-src-save))
+ ((not
+ (delq nil (mapcar
+ (lambda (b)
+ (string-match "\*Org Src" (buffer-name b)))
+ (buffer-list))))
+ (cancel-timer org-edit-src-code-timer)
+ (setq org-edit-src-code-timer)))))))))
+ t)))
(defun org-edit-src-continue (e)
"Continue editing source blocks." ;; Fixme: be more accurate
@@ -415,7 +471,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))
@@ -515,14 +571,20 @@ 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))
@@ -553,16 +615,7 @@ 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)))))))))
- (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 (point-at-bol))
- (setq ind (org-edit-src-get-indentation beg))
- (throw 'exit (list beg end 'table.el nil nil ind))))))
+ single lfmt ind))))))))))))
(defun org-edit-src-get-lang (lang)
"Extract the src language."
@@ -590,20 +643,38 @@ the language, a switch telling if the content should be in a single line."
(goto-char pos)
(org-get-indentation)))
-(defun org-add-protective-commas (beg end &optional line)
- "Add protective commas in region.
-Return the delta in size of the region."
+(defun org-escape-code-in-region (beg end)
+ "Escape lines between BEG and END.
+Escaping happens when a line starts with \"*\", \"#+\", \",*\" or
+\",#+\" by appending a comma to it."
(interactive "r")
- (let ((org-re "^\\(.\\)")
- (other-re "^\\([*]\\|[ \t]*#\\+\\)")
- (delta 0))
- (save-excursion
- (goto-char beg)
- (while (re-search-forward (if (derived-mode-p 'org-mode) org-re other-re)
- end t)
- (if (and line (eq (org-current-line) line)) (setq delta (1+ delta)))
- (replace-match ",\\1")))
- delta))
+ (save-excursion
+ (goto-char beg)
+ (while (re-search-forward "^[ \t]*,?\\(\\*\\|#\\+\\)" end t)
+ (replace-match ",\\1" nil nil nil 1))))
+
+(defun org-escape-code-in-string (s)
+ "Escape lines in string S.
+Escaping happens when a line starts with \"*\", \"#+\", \",*\" or
+\",#+\" by appending a comma to it."
+ (replace-regexp-in-string "^[ \t]*,?\\(\\*\\|#\\+\\)" ",\\1" s nil nil 1))
+
+(defun org-unescape-code-in-region (beg end)
+ "Un-escape lines between BEG and END.
+Un-escaping happens by removing the first comma on lines starting
+with \",*\", \",#+\", \",,*\" and \",,#+\"."
+ (interactive "r")
+ (save-excursion
+ (goto-char beg)
+ (while (re-search-forward "^[ \t]*,?\\(,\\)\\(?:\\*\\|#\\+\\)" end t)
+ (replace-match "" nil nil nil 1))))
+
+(defun org-unescape-code-in-string (s)
+ "Un-escape lines in string S.
+Un-escaping happens by removing the first comma on lines starting
+with \",*\", \",#+\", \",,*\" and \",,#+\"."
+ (replace-regexp-in-string
+ "^[ \t]*,?\\(,\\)\\(?:\\*\\|#\\+\\)" "" s nil nil 1))
(defun org-edit-src-exit (&optional context)
"Exit special edit and protect problematic lines."
@@ -611,7 +682,8 @@ Return the delta in size of the region."
(unless (org-bound-and-true-p org-edit-src-from-org-mode)
(error "This is not a sub-editing buffer, something is wrong"))
(widen)
- (let* ((beg org-edit-src-beg-marker)
+ (let* ((fixed-width-p (string-match "Fixed Width" (buffer-name)))
+ (beg org-edit-src-beg-marker)
(end org-edit-src-end-marker)
(ovl org-edit-src-overlay)
(bufstr (buffer-string))
@@ -648,9 +720,14 @@ Return the delta in size of the region."
(goto-char (point-max)) (insert "\\n")))
(goto-char (point-min))
(if (looking-at "\\s-*") (replace-match " ")))
- (when (org-bound-and-true-p org-edit-src-from-org-mode)
- (setq delta (+ delta (org-add-protective-commas
- (point-min) (point-max) line))))
+ (when (and (org-bound-and-true-p org-edit-src-from-org-mode)
+ (not fixed-width-p))
+ (org-escape-code-in-region (point-min) (point-max))
+ (setq delta (+ delta
+ (save-excursion
+ (org-goto-line line)
+ (if (looking-at "[ \t]*\\(,,\\)?\\(\\*\\|#+\\)") 1
+ 0)))))
(when (org-bound-and-true-p org-edit-src-picture)
(setq preserve-indentation nil)
(untabify (point-min) (point-max))
@@ -671,14 +748,17 @@ Return the delta in size of the region."
(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
- (delete-region beg (1- end))
- (insert code)
- (delete-char 1)
- (goto-char beg)
- (if single (just-one-space)))
+ (let ((buffer-undo-list t))
+ (delete-region beg (max beg end))
+ (unless (string-match "\\`[ \t]*\\'" code)
+ (insert code))
+ (goto-char beg)
+ (if single (just-one-space))))
(if (memq t (mapcar (lambda (overlay)
(eq (overlay-get overlay 'invisible)
'org-hide-block))
@@ -686,16 +766,26 @@ Return the delta in size of the region."
;; 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)))
+ (when org-edit-src-code-timer
+ (cancel-timer org-edit-src-code-timer)
+ (setq org-edit-src-code-timer nil))
(unless (eq context 'save)
(when org-edit-src-saved-temp-window-config
(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
@@ -715,9 +805,11 @@ Return the delta in size of the region."
(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."
@@ -801,9 +893,10 @@ 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")))))