diff options
Diffstat (limited to 'lisp/org-src.el')
-rw-r--r-- | lisp/org-src.el | 255 |
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"))))) |