|
@@ -38,16 +38,12 @@
|
|
|
(require 'cl))
|
|
|
|
|
|
(declare-function org-do-remove-indentation "org" (&optional n))
|
|
|
-(declare-function org-at-table.el-p "org" ())
|
|
|
-(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-pop-to-buffer-same-window
|
|
|
"org-compat" (&optional buffer-or-name norecord label))
|
|
|
(declare-function org-base-buffer "org" (buffer))
|
|
|
|
|
|
-(declare-function org-babel-tangle "ob-tangle" (&optional arg target-file lang))
|
|
|
-
|
|
|
(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
|
|
@@ -121,9 +117,6 @@ editing it with \\[org-edit-src-code]. Has no effect if
|
|
|
:group 'org-edit-structure
|
|
|
:type 'integer)
|
|
|
|
|
|
-(defvar org-src-strip-leading-and-trailing-blank-lines nil
|
|
|
- "If non-nil, blank lines are removed when exiting the code edit buffer.")
|
|
|
-
|
|
|
(defcustom org-edit-src-persistent-message t
|
|
|
"Non-nil means show persistent exit help message while editing src examples.
|
|
|
The message is shown in the header-line, which will be created in the
|
|
@@ -186,357 +179,295 @@ issued in the language major mode buffer."
|
|
|
:version "24.1"
|
|
|
:group 'org-babel)
|
|
|
|
|
|
-;;; Editing source examples
|
|
|
-
|
|
|
-(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)
|
|
|
-(defvar org-edit-src-from-org-mode nil)
|
|
|
-(defvar org-edit-src-allow-write-back-p t)
|
|
|
-(defvar org-edit-src-picture nil)
|
|
|
-(defvar org-edit-src-beg-marker nil)
|
|
|
-(defvar org-edit-src-end-marker nil)
|
|
|
-(defvar org-edit-src-overlay nil)
|
|
|
-(defvar org-edit-src-block-indentation nil)
|
|
|
-(defvar org-edit-src-saved-temp-window-config nil)
|
|
|
+
|
|
|
+;;; Internal functions and variables
|
|
|
|
|
|
-(defvar org-src-babel-info nil)
|
|
|
+(defvar org-src--allow-write-back-p t)
|
|
|
+(defvar org-src--beg-marker nil)
|
|
|
+(defvar org-src--block-indentation nil)
|
|
|
+(defvar org-src--code-timer nil)
|
|
|
+(defvar org-src--end-marker nil)
|
|
|
+(defvar org-src--from-org-mode nil)
|
|
|
+(defvar org-src--overlay nil)
|
|
|
+(defvar org-src--saved-temp-window-config nil)
|
|
|
+(defvar org-src--type nil)
|
|
|
+(defvar org-src--babel-info nil)
|
|
|
|
|
|
-(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."
|
|
|
- :group 'org-edit-structure
|
|
|
- :version "24.4"
|
|
|
- :package-version '(Org . "8.0")
|
|
|
- :type 'boolean)
|
|
|
+(defun org-src--construct-edit-buffer-name (org-buffer-name lang)
|
|
|
+ "Construct the buffer name for a source editing buffer."
|
|
|
+ (concat "*Org Src " org-buffer-name "[ " lang " ]*"))
|
|
|
|
|
|
-(define-minor-mode org-src-mode
|
|
|
- "Minor mode for language major mode buffers generated by org.
|
|
|
-This minor mode is turned on in two situations:
|
|
|
-- when editing a source code snippet with \"C-c '\".
|
|
|
-- When formatting a source code snippet for export with htmlize.
|
|
|
-There is a mode hook, and keybindings for `org-edit-src-exit' and
|
|
|
-`org-edit-src-save'")
|
|
|
+(defun org-src--edit-buffer (beg end)
|
|
|
+ "Return buffer editing area between BEG and END.
|
|
|
+Return nil if there is no such buffer."
|
|
|
+ (catch 'exit
|
|
|
+ (dolist (b (buffer-list))
|
|
|
+ (with-current-buffer b
|
|
|
+ (and (org-src-edit-buffer-p)
|
|
|
+ (eq beg org-src--beg-marker)
|
|
|
+ (eq end org-src--end-marker)
|
|
|
+ (throw 'exit b))))))
|
|
|
+
|
|
|
+(defun org-src--source-buffer ()
|
|
|
+ "Return source buffer edited by current buffer."
|
|
|
+ (unless (org-src-edit-buffer-p) (error "Not in a source buffer"))
|
|
|
+ (or (marker-buffer org-src--beg-marker)
|
|
|
+ (error "No source buffer available for current editing session")))
|
|
|
+
|
|
|
+(defun org-src--get-lang-mode (lang)
|
|
|
+ "Return major mode that should be used for LANG.
|
|
|
+LANG is a string, and the returned major mode is a symbol."
|
|
|
+ (intern
|
|
|
+ (concat
|
|
|
+ (let ((l (or (cdr (assoc lang org-src-lang-modes)) lang)))
|
|
|
+ (if (symbolp l) (symbol-name l) l))
|
|
|
+ "-mode")))
|
|
|
|
|
|
-(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
|
|
|
-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)
|
|
|
- (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) -- 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))
|
|
|
- lang (if (symbolp lang) (symbol-name lang) lang)
|
|
|
- single (nth 3 info)
|
|
|
- block-nindent (nth 5 info)
|
|
|
- lang-f (intern (concat lang "-mode"))
|
|
|
- begline (save-excursion (goto-char beg) (org-current-line))
|
|
|
- transmitted-variables
|
|
|
- `((org-edit-src-content-indentation
|
|
|
- ,org-edit-src-content-indentation)
|
|
|
- (org-edit-src-force-single-line ,single)
|
|
|
- (org-edit-src-from-org-mode ,org-mode-p)
|
|
|
- (org-edit-src-allow-write-back-p ,allow-write-back-p)
|
|
|
- (org-src-preserve-indentation ,org-src-preserve-indentation)
|
|
|
- (org-src-babel-info ,(org-babel-get-src-block-info 'light))
|
|
|
- (org-coderef-label-format
|
|
|
- ,(or (nth 4 info) org-coderef-label-format))
|
|
|
- (org-edit-src-beg-marker ,beg)
|
|
|
- (org-edit-src-end-marker ,end)
|
|
|
- (org-edit-src-block-indentation ,block-nindent)))
|
|
|
- (if (and mark (>= mark beg) (<= mark (1+ end)))
|
|
|
- (save-excursion (goto-char (min mark end))
|
|
|
- (setq markline (org-current-line)
|
|
|
- markcol (current-column))))
|
|
|
- (if (equal lang-f 'table.el-mode)
|
|
|
- (setq lang-f (lambda ()
|
|
|
- (text-mode)
|
|
|
- (if (org-bound-and-true-p flyspell-mode)
|
|
|
- (flyspell-mode -1))
|
|
|
- (table-recognize)
|
|
|
- (org-set-local 'org-edit-src-content-indentation 0))))
|
|
|
- (unless (functionp lang-f)
|
|
|
- (error "No such language mode: %s" lang-f))
|
|
|
- (save-excursion
|
|
|
- (if (> (point) end) (goto-char end))
|
|
|
- (setq line (org-current-line)
|
|
|
- col (current-column)))
|
|
|
- (if (and (setq buffer (org-edit-src-find-buffer beg end))
|
|
|
- (or (eq context 'save)
|
|
|
- (if org-src-ask-before-returning-to-edit-buffer
|
|
|
- (y-or-n-p "Return to existing edit buffer ([n] will revert changes)? ") t)))
|
|
|
- (org-src-switch-to-buffer buffer 'return)
|
|
|
- (when buffer
|
|
|
- (with-current-buffer buffer
|
|
|
- (if (boundp 'org-edit-src-overlay)
|
|
|
- (delete-overlay org-edit-src-overlay)))
|
|
|
- (kill-buffer buffer))
|
|
|
- (setq buffer (generate-new-buffer
|
|
|
- (or edit-buffer-name
|
|
|
- (org-src-construct-edit-buffer-name (buffer-name) lang))))
|
|
|
- (setq ovl (make-overlay beg end))
|
|
|
- (overlay-put ovl 'edit-buffer buffer)
|
|
|
- (overlay-put ovl 'help-echo "Click with mouse-1 to switch to buffer editing this segment")
|
|
|
- (overlay-put ovl 'face 'secondary-selection)
|
|
|
- (overlay-put ovl
|
|
|
- 'keymap
|
|
|
- (let ((map (make-sparse-keymap)))
|
|
|
- (define-key map [mouse-1] 'org-edit-src-continue)
|
|
|
- map))
|
|
|
- (overlay-put ovl :read-only "Leave me alone")
|
|
|
- (setq transmitted-variables
|
|
|
- (append transmitted-variables `((org-edit-src-overlay ,ovl))))
|
|
|
+(defun org-src--coordinates (pos beg end)
|
|
|
+ "Return coordinates of POS relatively to BEG and END.
|
|
|
+POS, BEG and END are buffer positions. Return value is either
|
|
|
+a cons cell (LINE . COLUMN) or symbol `end'. See also
|
|
|
+`org-src--goto-coordinates'."
|
|
|
+ (if (>= pos end) 'end
|
|
|
+ (org-with-wide-buffer
|
|
|
+ (goto-char (max beg pos))
|
|
|
+ (cons (count-lines beg (line-beginning-position))
|
|
|
+ ;; Column is relative to the end of line to avoid problems of
|
|
|
+ ;; comma escaping or colons appended in front of the line.
|
|
|
+ (- (current-column)
|
|
|
+ (progn (end-of-line) (current-column)))))))
|
|
|
+
|
|
|
+(defun org-src--goto-coordinates (coord beg end)
|
|
|
+ "Move to coordinates COORD relatively to BEG and END.
|
|
|
+COORD are coordinates, as returned by `org-src--coordinates',
|
|
|
+which see. BEG and END are buffer positions."
|
|
|
+ (goto-char
|
|
|
+ (if (eq coord 'end) (max (1- end) beg)
|
|
|
+ ;; If BEG happens to be located outside of the narrowed part of
|
|
|
+ ;; the buffer, widen it first.
|
|
|
+ (org-with-wide-buffer
|
|
|
+ (goto-char beg)
|
|
|
+ (forward-line (car coord))
|
|
|
+ (end-of-line)
|
|
|
+ (org-move-to-column (max (+ (current-column) (cdr coord)) 0))
|
|
|
+ (point)))))
|
|
|
+
|
|
|
+(defun org-src--element-contents-area (element)
|
|
|
+ "Return contents boundaries of ELEMENT.
|
|
|
+Return value is a pair (BEG . END) where BEG and END are buffer
|
|
|
+positions."
|
|
|
+ (let ((blockp (memq (org-element-type element)
|
|
|
+ '(example-block export-block src-block))))
|
|
|
+ (cons (org-with-wide-buffer
|
|
|
+ (goto-char (org-element-property :post-affiliated element))
|
|
|
+ (if blockp (line-beginning-position 2) (point)))
|
|
|
+ (org-with-wide-buffer
|
|
|
+ (goto-char (org-element-property :end element))
|
|
|
+ (skip-chars-backward " \r\t\n")
|
|
|
+ (line-beginning-position (if blockp 1 2))))))
|
|
|
+
|
|
|
+(defun org-src--make-source-overlay (beg end edit-buffer)
|
|
|
+ "Create overlay between BEG and END positions and return it.
|
|
|
+EDIT-BUFFER is the buffer currently editing area between BEG and
|
|
|
+END."
|
|
|
+ (let ((overlay (make-overlay beg end)))
|
|
|
+ (overlay-put overlay 'face 'secondary-selection)
|
|
|
+ (overlay-put overlay 'edit-buffer edit-buffer)
|
|
|
+ (overlay-put overlay 'help-echo
|
|
|
+ "Click with mouse-1 to switch to buffer editing this segment")
|
|
|
+ (overlay-put overlay 'face 'secondary-selection)
|
|
|
+ (overlay-put overlay 'keymap
|
|
|
+ (let ((map (make-sparse-keymap)))
|
|
|
+ (define-key map [mouse-1] 'org-edit-src-continue)
|
|
|
+ map))
|
|
|
+ (overlay-put overlay :read-only "Leave me alone")
|
|
|
+ overlay))
|
|
|
+
|
|
|
+(defun org-src--on-element-p (element)
|
|
|
+ "Non-nil when point is on ELEMENT."
|
|
|
+ (and (>= (point) (org-element-property :begin element))
|
|
|
+ (<= (point)
|
|
|
+ (org-with-wide-buffer
|
|
|
+ (goto-char (org-element-property :end element))
|
|
|
+ (skip-chars-backward " \r\t\n")
|
|
|
+ (line-end-position)))))
|
|
|
+
|
|
|
+(defun org-src--contents-for-write-back ()
|
|
|
+ "Return buffer contents in a format appropriate for write back.
|
|
|
+Assume point is in the corresponding edit buffer."
|
|
|
+ (let ((indentation (+ (or org-src--block-indentation 0)
|
|
|
+ (if (memq org-src--type '(example-block src-block))
|
|
|
+ org-edit-src-content-indentation
|
|
|
+ 0)))
|
|
|
+ (preserve-indentation org-src-preserve-indentation)
|
|
|
+ (contents (org-with-wide-buffer (buffer-string)))
|
|
|
+ (fixed-width-p (eq org-src--type 'fixed-width)))
|
|
|
+ (with-temp-buffer
|
|
|
+ (insert contents)
|
|
|
+ (goto-char (point-min))
|
|
|
+ (if fixed-width-p
|
|
|
+ (progn
|
|
|
+ (untabify (point-min) (point-max))
|
|
|
+ (let ((prefix (concat (and (not preserve-indentation)
|
|
|
+ (make-string indentation ?\s))
|
|
|
+ ": ")))
|
|
|
+ (while (not (eobp)) (insert prefix) (forward-line))))
|
|
|
+ (unless preserve-indentation (untabify (point-min) (point-max)))
|
|
|
+ (org-escape-code-in-region (point-min) (point-max))
|
|
|
+ (unless (or preserve-indentation (zerop indentation))
|
|
|
+ (let ((ind (make-string indentation ?\s)))
|
|
|
+ (while (not (eobp))
|
|
|
+ (when (org-looking-at-p "[ \t]*\\S-") (insert ind))
|
|
|
+ (forward-line)))))
|
|
|
+ (buffer-string))))
|
|
|
+
|
|
|
+(defun org-src--edit-element (element name &optional major write-back contents)
|
|
|
+ "Edit ELEMENT contents in a dedicated buffer.
|
|
|
+
|
|
|
+MAJOR is the major mode used in the edit buffer. A nil value is
|
|
|
+equivalent to `fundamental-mode'. When WRITE-BACK is non-nil,
|
|
|
+assume contents will replace original region. When CONTENTS is
|
|
|
+non-nil, display them in the edit buffer. Otherwise, assume they
|
|
|
+are located in property `:value'.
|
|
|
+
|
|
|
+Leave point in edit buffer."
|
|
|
+ (setq org-src--saved-temp-window-config (current-window-configuration))
|
|
|
+ (let* ((area (org-src--element-contents-area element))
|
|
|
+ (beg (copy-marker (car area)))
|
|
|
+ (end (copy-marker (cdr area) t))
|
|
|
+ (old-edit-buffer (org-src--edit-buffer beg end)))
|
|
|
+ (if (and old-edit-buffer
|
|
|
+ (or (not org-src-ask-before-returning-to-edit-buffer)
|
|
|
+ (y-or-n-p "Return to existing edit buffer ([n] will revert changes)? ")))
|
|
|
+ ;; Move to existing buffer.
|
|
|
+ (org-src-switch-to-buffer old-edit-buffer 'return)
|
|
|
+ ;; Discard old edit buffer.
|
|
|
+ (when old-edit-buffer
|
|
|
+ (with-current-buffer old-edit-buffer
|
|
|
+ (when (boundp 'org-src--overlay)
|
|
|
+ (delete-overlay org-src--overlay)))
|
|
|
+ (kill-buffer old-edit-buffer))
|
|
|
+ (let* ((org-mode-p (derived-mode-p 'org-mode))
|
|
|
+ (type (org-element-type element))
|
|
|
+ (ind (org-with-wide-buffer
|
|
|
+ (goto-char (org-element-property :begin element))
|
|
|
+ (org-get-indentation)))
|
|
|
+ (preserve-ind
|
|
|
+ (and (memq type '(example-block src-block))
|
|
|
+ (or (org-element-property :preserve-indent element)
|
|
|
+ org-src-preserve-indentation)))
|
|
|
+ ;; Store relative positions of mark (if any) and point
|
|
|
+ ;; within the edited area.
|
|
|
+ (point-coordinates (org-src--coordinates (point) beg end))
|
|
|
+ (mark-coordinates (and (org-region-active-p)
|
|
|
+ (let ((m (mark)))
|
|
|
+ (and (>= m beg) (>= end m)
|
|
|
+ (org-src--coordinates m beg end)))))
|
|
|
+ ;; Generate a new edit buffer.
|
|
|
+ (buffer (generate-new-buffer name))
|
|
|
+ ;; Add an overlay on top of source.
|
|
|
+ (overlay (org-src--make-source-overlay beg end buffer)))
|
|
|
+ ;; Switch to edit buffer.
|
|
|
(org-src-switch-to-buffer buffer 'edit)
|
|
|
- (if (eq single 'macro-definition)
|
|
|
- (setq code (replace-regexp-in-string "\\\\n" "\n" code t t)))
|
|
|
- (insert code)
|
|
|
+ ;; Insert contents.
|
|
|
+ (insert (or contents (org-element-property :value element)))
|
|
|
(remove-text-properties (point-min) (point-max)
|
|
|
'(display nil invisible nil intangible nil))
|
|
|
- (unless (cadr (assq 'org-src-preserve-indentation transmitted-variables))
|
|
|
- (setq total-nindent (or (org-do-remove-indentation) 0)))
|
|
|
- (let ((org-inhibit-startup t))
|
|
|
- (condition-case e
|
|
|
- (funcall lang-f)
|
|
|
- (error
|
|
|
- (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.
|
|
|
- (org-unescape-code-in-region (point-min) (point-max))
|
|
|
- (when markline
|
|
|
- (org-goto-line (1+ (- markline begline)))
|
|
|
- (org-move-to-column
|
|
|
- (if org-src-preserve-indentation markcol
|
|
|
- (max 0 (- markcol total-nindent))))
|
|
|
- (push-mark (point) 'no-message t)
|
|
|
- (setq deactivate-mark nil))
|
|
|
- (org-goto-line (1+ (- line begline)))
|
|
|
- (org-move-to-column
|
|
|
- (if org-src-preserve-indentation col (max 0 (- col total-nindent))))
|
|
|
- (org-src-mode)
|
|
|
+ (unless preserve-ind (org-do-remove-indentation))
|
|
|
(set-buffer-modified-p nil)
|
|
|
(setq buffer-file-name nil)
|
|
|
+ ;; Start major mode.
|
|
|
+ (if (not major) (fundamental-mode)
|
|
|
+ (let ((org-inhibit-startup t))
|
|
|
+ (condition-case e (funcall major)
|
|
|
+ (error (message "Language mode `%s' fails with: %S"
|
|
|
+ major (nth 1 e))))))
|
|
|
+ ;; Transmit buffer-local variables for exit function. It must
|
|
|
+ ;; be done after initializing major mode, as this operation
|
|
|
+ ;; may reset them otherwise.
|
|
|
+ (org-set-local 'org-src--from-org-mode org-mode-p)
|
|
|
+ (org-set-local 'org-src--beg-marker beg)
|
|
|
+ (org-set-local 'org-src--end-marker end)
|
|
|
+ (org-set-local 'org-src--type type)
|
|
|
+ (org-set-local 'org-src--block-indentation ind)
|
|
|
+ (org-set-local 'org-src-preserve-indentation preserve-ind)
|
|
|
+ (org-set-local 'org-src--overlay overlay)
|
|
|
+ (org-set-local 'org-src--allow-write-back-p write-back)
|
|
|
+ ;; Start minor mode.
|
|
|
+ (org-src-mode)
|
|
|
+ (when org-edit-src-persistent-message
|
|
|
+ (org-set-local
|
|
|
+ 'header-line-format
|
|
|
+ (substitute-command-keys
|
|
|
+ (if write-back
|
|
|
+ "Edit, then exit with \\[org-edit-src-exit] or abort with \
|
|
|
+\\[org-edit-src-abort]"
|
|
|
+ "Exit with \\[org-edit-src-exit] or abort with \
|
|
|
+\\[org-edit-src-abort]"))))
|
|
|
+ ;; Possibly start `auto-save-mode'.
|
|
|
(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)))
|
|
|
- (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)
|
|
|
- "Continue editing source blocks." ;; Fixme: be more accurate
|
|
|
- (interactive "e")
|
|
|
- (mouse-set-point e)
|
|
|
- (let ((buf (get-char-property (point) 'edit-buffer)))
|
|
|
- (if buf (org-src-switch-to-buffer buf 'continue)
|
|
|
- (error "Something is wrong here"))))
|
|
|
-
|
|
|
-(defun org-src-switch-to-buffer (buffer context)
|
|
|
- (case org-src-window-setup
|
|
|
- ('current-window
|
|
|
- (org-pop-to-buffer-same-window buffer))
|
|
|
- ('other-window
|
|
|
- (switch-to-buffer-other-window buffer))
|
|
|
- ('other-frame
|
|
|
- (case context
|
|
|
- ('exit
|
|
|
- (let ((frame (selected-frame)))
|
|
|
- (switch-to-buffer-other-frame buffer)
|
|
|
- (delete-frame frame)))
|
|
|
- ('save
|
|
|
- (kill-buffer (current-buffer))
|
|
|
- (org-pop-to-buffer-same-window buffer))
|
|
|
- (t
|
|
|
- (switch-to-buffer-other-frame buffer))))
|
|
|
- ('reorganize-frame
|
|
|
- (if (eq context 'edit) (delete-other-windows))
|
|
|
- (org-switch-to-buffer-other-window buffer)
|
|
|
- (if (eq context 'exit) (delete-other-windows)))
|
|
|
- ('switch-invisibly
|
|
|
- (set-buffer buffer))
|
|
|
- (t
|
|
|
- (message "Invalid value %s for org-src-window-setup"
|
|
|
- (symbol-name org-src-window-setup))
|
|
|
- (org-pop-to-buffer-same-window buffer))))
|
|
|
-
|
|
|
-(defun org-src-construct-edit-buffer-name (org-buffer-name lang)
|
|
|
- "Construct the buffer name for a source editing buffer."
|
|
|
- (concat "*Org Src " org-buffer-name "[ " lang " ]*"))
|
|
|
-
|
|
|
-(defun org-src-edit-buffer-p (&optional buffer)
|
|
|
- "Test whether BUFFER (or the current buffer if BUFFER is nil)
|
|
|
-is a source block editing buffer."
|
|
|
- (let ((buffer (org-base-buffer (or buffer (current-buffer)))))
|
|
|
- (and (buffer-name buffer)
|
|
|
- (string-match "\\`*Org Src " (buffer-name buffer))
|
|
|
- (local-variable-p 'org-edit-src-beg-marker buffer)
|
|
|
- (local-variable-p 'org-edit-src-end-marker buffer))))
|
|
|
-
|
|
|
-(defun org-edit-src-find-buffer (beg end)
|
|
|
- "Find a source editing buffer that is already editing the region BEG to END."
|
|
|
- (catch 'exit
|
|
|
- (mapc
|
|
|
- (lambda (b)
|
|
|
- (with-current-buffer b
|
|
|
- (if (and (string-match "\\`*Org Src " (buffer-name))
|
|
|
- (local-variable-p 'org-edit-src-beg-marker (current-buffer))
|
|
|
- (local-variable-p 'org-edit-src-end-marker (current-buffer))
|
|
|
- (equal beg org-edit-src-beg-marker)
|
|
|
- (equal end org-edit-src-end-marker))
|
|
|
- (throw 'exit (current-buffer)))))
|
|
|
- (buffer-list))
|
|
|
- nil))
|
|
|
+ (format-time-string "-%Y-%d-%m")
|
|
|
+ ".txt")))
|
|
|
+ ;; Move mark and point in edit buffer to the corresponding
|
|
|
+ ;; location.
|
|
|
+ (when mark-coordinates
|
|
|
+ (org-src--goto-coordinates mark-coordinates (point-min) (point-max))
|
|
|
+ (push-mark (point) 'no-message t)
|
|
|
+ (setq deactivate-mark nil))
|
|
|
+ (org-src--goto-coordinates point-coordinates (point-min) (point-max)))
|
|
|
+ ;; Install idle auto save feature, if necessary.
|
|
|
+ (or org-src--code-timer
|
|
|
+ (zerop org-edit-src-auto-save-idle-delay)
|
|
|
+ (setq org-src--code-timer
|
|
|
+ (run-with-idle-timer
|
|
|
+ org-edit-src-auto-save-idle-delay t
|
|
|
+ (lambda ()
|
|
|
+ (cond
|
|
|
+ ((org-src-edit-buffer-p)
|
|
|
+ (when (buffer-modified-p) (org-edit-src-save)))
|
|
|
+ ((not (org-some (lambda (b) (org-src-edit-buffer-p b))
|
|
|
+ (buffer-list)))
|
|
|
+ (cancel-timer org-src--code-timer)
|
|
|
+ (setq org-src--code-timer nil))))))))))
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+;;; Fontification of source blocks
|
|
|
|
|
|
-(defun org-edit-fixed-width-region ()
|
|
|
- "Edit the fixed-width ascii drawing at point.
|
|
|
-This must be a region where each line starts with a colon followed by
|
|
|
-a space character.
|
|
|
-An new buffer is created and the fixed-width region is copied into it,
|
|
|
-and the buffer is switched into `artist-mode' for editing. When done,
|
|
|
-exit with \\[org-edit-src-exit]. The edited text will then replace
|
|
|
-the fragment in the Org-mode buffer."
|
|
|
- (interactive)
|
|
|
- (let ((line (org-current-line))
|
|
|
- (col (current-column))
|
|
|
- (case-fold-search t)
|
|
|
- (msg (substitute-command-keys
|
|
|
- "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))
|
|
|
- (preserve-indentation org-src-preserve-indentation)
|
|
|
- block-nindent ovl beg1 end1 code begline buffer)
|
|
|
- (beginning-of-line 1)
|
|
|
- (if (looking-at "[ \t]*[^:\n \t]")
|
|
|
- nil
|
|
|
- (if (looking-at "[ \t]*\\(\n\\|\\'\\)")
|
|
|
- (setq beg1 (point) end1 beg1)
|
|
|
- (save-excursion
|
|
|
- (if (re-search-backward "^[ \t]*[^: \t]" nil 'move)
|
|
|
- (setq beg1 (point-at-bol 2))
|
|
|
- (setq beg1 (point))))
|
|
|
- (save-excursion
|
|
|
- (if (re-search-forward "^[ \t]*[^: \t]" nil 'move)
|
|
|
- (setq end1 (1- (match-beginning 0)))
|
|
|
- (setq end1 (point))))
|
|
|
- (org-goto-line line))
|
|
|
- (setq beg (move-marker beg beg1)
|
|
|
- end (move-marker end end1)
|
|
|
- code (buffer-substring-no-properties beg end)
|
|
|
- begline (save-excursion (goto-char beg) (org-current-line)))
|
|
|
- (if (and (setq buffer (org-edit-src-find-buffer beg end))
|
|
|
- (y-or-n-p "Return to existing edit buffer ([n] will revert changes)? "))
|
|
|
- (org-pop-to-buffer-same-window buffer)
|
|
|
- (when buffer
|
|
|
- (with-current-buffer buffer
|
|
|
- (if (boundp 'org-edit-src-overlay)
|
|
|
- (delete-overlay org-edit-src-overlay)))
|
|
|
- (kill-buffer buffer))
|
|
|
- (setq buffer (generate-new-buffer
|
|
|
- (org-src-construct-edit-buffer-name
|
|
|
- (buffer-name) "Fixed Width")))
|
|
|
- (setq ovl (make-overlay beg end))
|
|
|
- (overlay-put ovl 'face 'secondary-selection)
|
|
|
- (overlay-put ovl 'edit-buffer buffer)
|
|
|
- (overlay-put ovl 'help-echo "Click with mouse-1 to switch to buffer editing this segment")
|
|
|
- (overlay-put ovl 'face 'secondary-selection)
|
|
|
- (overlay-put ovl
|
|
|
- 'keymap
|
|
|
- (let ((map (make-sparse-keymap)))
|
|
|
- (define-key map [mouse-1] 'org-edit-src-continue)
|
|
|
- map))
|
|
|
- (overlay-put ovl :read-only "Leave me alone")
|
|
|
- (org-pop-to-buffer-same-window buffer)
|
|
|
- (insert code)
|
|
|
- (remove-text-properties (point-min) (point-max)
|
|
|
- '(display nil invisible nil intangible nil))
|
|
|
- (setq block-nindent (or (org-do-remove-indentation) 0))
|
|
|
- (cond
|
|
|
- ((eq org-edit-fixed-width-region-mode 'artist-mode)
|
|
|
- (fundamental-mode)
|
|
|
- (artist-mode 1))
|
|
|
- (t (funcall org-edit-fixed-width-region-mode)))
|
|
|
- (set (make-local-variable 'org-edit-src-force-single-line) nil)
|
|
|
- (set (make-local-variable 'org-edit-src-from-org-mode) org-mode-p)
|
|
|
- (set (make-local-variable 'org-edit-src-picture) t)
|
|
|
- (goto-char (point-min))
|
|
|
- (while (re-search-forward "^[ \t]*: ?" nil t)
|
|
|
- (replace-match ""))
|
|
|
- (org-goto-line (1+ (- line begline)))
|
|
|
- (org-move-to-column (max 0 (- col block-nindent 2)))
|
|
|
- (org-set-local 'org-edit-src-beg-marker beg)
|
|
|
- (org-set-local 'org-edit-src-end-marker end)
|
|
|
- (org-set-local 'org-edit-src-overlay ovl)
|
|
|
- (org-set-local 'org-edit-src-block-indentation block-nindent)
|
|
|
- (org-set-local 'org-edit-src-content-indentation 0)
|
|
|
- (org-set-local 'org-src-preserve-indentation nil)
|
|
|
- (org-src-mode)
|
|
|
- (set-buffer-modified-p nil)
|
|
|
- (and org-edit-src-persistent-message
|
|
|
- (org-set-local 'header-line-format msg)))
|
|
|
- (message "%s" msg)
|
|
|
- t)))
|
|
|
+(defun org-src-font-lock-fontify-block (lang start end)
|
|
|
+ "Fontify code block.
|
|
|
+This function is called by emacs automatic fontification, as long
|
|
|
+as `org-src-fontify-natively' is non-nil."
|
|
|
+ (let ((lang-mode (org-src--get-lang-mode lang)))
|
|
|
+ (when (fboundp lang-mode)
|
|
|
+ (let ((string (buffer-substring-no-properties start end))
|
|
|
+ (modified (buffer-modified-p))
|
|
|
+ (org-buffer (current-buffer)) pos next)
|
|
|
+ (remove-text-properties start end '(face nil))
|
|
|
+ (with-current-buffer
|
|
|
+ (get-buffer-create
|
|
|
+ (concat " org-src-fontification:" (symbol-name lang-mode)))
|
|
|
+ (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)
|
|
|
+ (setq pos (point-min))
|
|
|
+ (while (setq next (next-single-property-change pos 'face))
|
|
|
+ (put-text-property
|
|
|
+ (+ start (1- pos)) (1- (+ start next)) 'face
|
|
|
+ (get-text-property pos 'face) org-buffer)
|
|
|
+ (setq pos next)))
|
|
|
+ (add-text-properties
|
|
|
+ start end
|
|
|
+ '(font-lock-fontified t fontified t font-lock-multiline t))
|
|
|
+ (set-buffer-modified-p modified)))))
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+;;; Escape contents
|
|
|
|
|
|
(defun org-escape-code-in-region (beg end)
|
|
|
"Escape lines between BEG and END.
|
|
@@ -571,152 +502,42 @@ 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."
|
|
|
- (interactive)
|
|
|
- (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* ((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))
|
|
|
- (buffer (current-buffer))
|
|
|
- (single (org-bound-and-true-p org-edit-src-force-single-line))
|
|
|
- (macro (eq single 'macro-definition))
|
|
|
- (total-nindent (+ (or org-edit-src-block-indentation 0)
|
|
|
- org-edit-src-content-indentation))
|
|
|
- (preserve-indentation org-src-preserve-indentation)
|
|
|
- (allow-write-back-p (org-bound-and-true-p org-edit-src-allow-write-back-p))
|
|
|
- (delta 0) code line col indent)
|
|
|
- (when allow-write-back-p
|
|
|
- (unless preserve-indentation (untabify (point-min) (point-max)))
|
|
|
- (if org-src-strip-leading-and-trailing-blank-lines
|
|
|
- (save-excursion
|
|
|
- (goto-char (point-min))
|
|
|
- (if (looking-at "[ \t\n]*\n") (replace-match ""))
|
|
|
- (unless macro
|
|
|
- (if (re-search-forward "\n[ \t\n]*\\'" nil t) (replace-match ""))))))
|
|
|
- (setq line (if (org-bound-and-true-p org-edit-src-force-single-line)
|
|
|
- 1
|
|
|
- (org-current-line))
|
|
|
- col (current-column))
|
|
|
- (when allow-write-back-p
|
|
|
- (when single
|
|
|
- (goto-char (point-min))
|
|
|
- (if (re-search-forward "\\s-+\\'" nil t) (replace-match ""))
|
|
|
- (goto-char (point-min))
|
|
|
- (let ((cnt 0))
|
|
|
- (while (re-search-forward "\n" nil t)
|
|
|
- (setq cnt (1+ cnt))
|
|
|
- (replace-match (if macro "\\n" " ") t t))
|
|
|
- (when (and macro (> cnt 0))
|
|
|
- (goto-char (point-max)) (insert "\\n")))
|
|
|
- (goto-char (point-min))
|
|
|
- (if (looking-at "\\s-*") (replace-match " ")))
|
|
|
- (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))
|
|
|
- (goto-char (point-min))
|
|
|
- (while (re-search-forward "^" nil t)
|
|
|
- (replace-match ": ")))
|
|
|
- (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 nil nil nil 1)))
|
|
|
- (if (org-bound-and-true-p org-edit-src-picture)
|
|
|
- (setq total-nindent (+ total-nindent 2)))
|
|
|
- (setq code (buffer-string))
|
|
|
- (when (eq context 'save)
|
|
|
- (erase-buffer)
|
|
|
- (insert bufstr))
|
|
|
- (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)
|
|
|
- (eq (overlay-get overlay 'invisible)
|
|
|
- 'org-hide-block))
|
|
|
- (overlays-at (point))))
|
|
|
- ;; 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
|
|
|
- (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)))
|
|
|
- (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
|
|
|
- (org-edit-src-exit 'save)
|
|
|
- ,@body
|
|
|
- (setq msg (current-message))
|
|
|
- (if (eq org-src-window-setup 'other-frame)
|
|
|
- (let ((org-src-window-setup 'current-window))
|
|
|
- (org-edit-src-code 'save))
|
|
|
- (org-edit-src-code 'save)))
|
|
|
- (setq buffer-undo-list ul)
|
|
|
- (push-mark m 'nomessage)
|
|
|
- (goto-char (min p (point-max)))
|
|
|
- (message (or msg ""))))
|
|
|
-(def-edebug-spec org-src-in-org-buffer (body))
|
|
|
+
|
|
|
+;;; Org src minor mode
|
|
|
|
|
|
-(defun org-edit-src-save ()
|
|
|
- "Save parent buffer with current state source-code buffer."
|
|
|
- (interactive)
|
|
|
- (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))))
|
|
|
+(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)
|
|
|
|
|
|
-(defun org-src-tangle (arg)
|
|
|
- "Tangle the parent buffer."
|
|
|
- (interactive)
|
|
|
- (org-src-in-org-buffer (org-babel-tangle arg)))
|
|
|
+(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."
|
|
|
+ :group 'org-edit-structure
|
|
|
+ :version "24.4"
|
|
|
+ :package-version '(Org . "8.0")
|
|
|
+ :type 'boolean)
|
|
|
+
|
|
|
+(define-minor-mode org-src-mode
|
|
|
+ "Minor mode for language major mode buffers generated by org.
|
|
|
+This minor mode is turned on in two situations:
|
|
|
+- when editing a source code snippet with \"C-c '\".
|
|
|
+- When formatting a source code snippet for export with htmlize.
|
|
|
+There is a mode hook, and keybindings for `org-edit-src-exit' and
|
|
|
+`org-edit-src-save'")
|
|
|
|
|
|
(defun org-src-mode-configure-edit-buffer ()
|
|
|
- (when (org-bound-and-true-p org-edit-src-from-org-mode)
|
|
|
+ (when (org-bound-and-true-p org-src--from-org-mode)
|
|
|
(org-add-hook 'kill-buffer-hook
|
|
|
- #'(lambda () (delete-overlay org-edit-src-overlay)) nil 'local)
|
|
|
- (if (org-bound-and-true-p org-edit-src-allow-write-back-p)
|
|
|
+ (lambda () (delete-overlay org-src--overlay)) nil 'local)
|
|
|
+ (if (org-bound-and-true-p org-src--allow-write-back-p)
|
|
|
(progn
|
|
|
(setq buffer-offer-save t)
|
|
|
(setq buffer-file-name
|
|
|
- (concat (buffer-file-name (marker-buffer org-edit-src-beg-marker))
|
|
|
+ (concat (buffer-file-name (marker-buffer org-src--beg-marker))
|
|
|
"[" (buffer-name) "]"))
|
|
|
(if (featurep 'xemacs)
|
|
|
(progn
|
|
@@ -725,8 +546,11 @@ with \",*\", \",#+\", \",,*\" and \",,#+\"."
|
|
|
(setq write-contents-functions '(org-edit-src-save))))
|
|
|
(setq buffer-read-only t))))
|
|
|
|
|
|
-(org-add-hook 'org-src-mode-hook 'org-src-mode-configure-edit-buffer)
|
|
|
+(org-add-hook 'org-src-mode-hook #'org-src-mode-configure-edit-buffer)
|
|
|
+
|
|
|
|
|
|
+
|
|
|
+;;; Babel related functions
|
|
|
|
|
|
(defun org-src-associate-babel-session (info)
|
|
|
"Associate edit buffer with comint session."
|
|
@@ -739,17 +563,18 @@ with \",*\", \",#+\", \",,*\" and \",,#+\"."
|
|
|
(and (fboundp f) (funcall f session))))))
|
|
|
|
|
|
(defun org-src-babel-configure-edit-buffer ()
|
|
|
- (when org-src-babel-info
|
|
|
- (org-src-associate-babel-session org-src-babel-info)))
|
|
|
+ (when org-src--babel-info
|
|
|
+ (org-src-associate-babel-session org-src--babel-info)))
|
|
|
+
|
|
|
+(org-add-hook 'org-src-mode-hook #'org-src-babel-configure-edit-buffer)
|
|
|
|
|
|
-(org-add-hook 'org-src-mode-hook 'org-src-babel-configure-edit-buffer)
|
|
|
(defmacro org-src-do-at-code-block (&rest body)
|
|
|
- "Execute a command from an edit buffer in the Org-mode buffer."
|
|
|
- `(let ((beg-marker org-edit-src-beg-marker))
|
|
|
- (if beg-marker
|
|
|
- (with-current-buffer (marker-buffer beg-marker)
|
|
|
- (goto-char (marker-position beg-marker))
|
|
|
- ,@body))))
|
|
|
+ "Execute a command from an edit buffer in the Org mode buffer."
|
|
|
+ `(let ((beg-marker org-src--beg-marker))
|
|
|
+ (when beg-marker
|
|
|
+ (with-current-buffer (marker-buffer beg-marker)
|
|
|
+ (goto-char beg-marker)
|
|
|
+ ,@body))))
|
|
|
(def-edebug-spec org-src-do-at-code-block (body))
|
|
|
|
|
|
(defun org-src-do-key-sequence-at-code-block (&optional key)
|
|
@@ -774,45 +599,230 @@ Org-babel commands."
|
|
|
(if (equal key (kbd "C-g")) (keyboard-quit)
|
|
|
(org-edit-src-save)
|
|
|
(org-src-do-at-code-block
|
|
|
- (call-interactively
|
|
|
- (lookup-key org-babel-map key)))))
|
|
|
+ (call-interactively (lookup-key org-babel-map key)))))
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+;;; Public functions
|
|
|
+
|
|
|
+(defun org-src-edit-buffer-p (&optional buffer)
|
|
|
+ "Non-nil when current buffer is a source editing buffer.
|
|
|
+If BUFFER is non-nil, test it instead."
|
|
|
+ (let ((buffer (org-base-buffer (or buffer (current-buffer)))))
|
|
|
+ (and (buffer-live-p buffer)
|
|
|
+ (local-variable-p 'org-src--beg-marker buffer)
|
|
|
+ (local-variable-p 'org-src--end-marker buffer))))
|
|
|
+
|
|
|
+(defun org-src-switch-to-buffer (buffer context)
|
|
|
+ (case org-src-window-setup
|
|
|
+ (current-window (org-pop-to-buffer-same-window buffer))
|
|
|
+ (other-window
|
|
|
+ (switch-to-buffer-other-window buffer))
|
|
|
+ (other-frame
|
|
|
+ (case context
|
|
|
+ (exit
|
|
|
+ (let ((frame (selected-frame)))
|
|
|
+ (switch-to-buffer-other-frame buffer)
|
|
|
+ (delete-frame frame)))
|
|
|
+ (save
|
|
|
+ (kill-buffer (current-buffer))
|
|
|
+ (org-pop-to-buffer-same-window buffer))
|
|
|
+ (t (switch-to-buffer-other-frame buffer))))
|
|
|
+ (reorganize-frame
|
|
|
+ (when (eq context 'edit) (delete-other-windows))
|
|
|
+ (org-switch-to-buffer-other-window buffer)
|
|
|
+ (when (eq context 'exit) (delete-other-windows)))
|
|
|
+ (switch-invisibly (set-buffer buffer))
|
|
|
+ (t
|
|
|
+ (message "Invalid value %s for `org-src-window-setup'"
|
|
|
+ org-src-window-setup)
|
|
|
+ (org-pop-to-buffer-same-window buffer))))
|
|
|
+
|
|
|
+(defun org-edit-table.el ()
|
|
|
+ "Edit \"table.el\" table at point.
|
|
|
+
|
|
|
+A new buffer is created and the table is copied into it. Then
|
|
|
+the table is recognized with `table-recognize'. When done
|
|
|
+editing, exit with \\[org-edit-src-exit]. The edited text will
|
|
|
+then replace the area in the Org mode buffer.
|
|
|
+
|
|
|
+Throw an error when not at such a table."
|
|
|
+ (interactive)
|
|
|
+ (let ((element (org-element-at-point)))
|
|
|
+ (unless (and (eq (org-element-type element) 'table)
|
|
|
+ (eq (org-element-property :type element) 'table.el)
|
|
|
+ (org-src--on-element-p element))
|
|
|
+ (user-error "Not in a table.el table"))
|
|
|
+ (org-src--edit-element
|
|
|
+ element
|
|
|
+ (org-src--construct-edit-buffer-name (buffer-name) "Table")
|
|
|
+ #'text-mode t)
|
|
|
+ (when (org-bound-and-true-p flyspell-mode) (flyspell-mode -1))
|
|
|
+ (table-recognize)
|
|
|
+ t))
|
|
|
+
|
|
|
+(defun org-edit-export-block ()
|
|
|
+ "Edit export block at point.
|
|
|
+
|
|
|
+A new buffer is created and the block is copied into it, and the
|
|
|
+buffer is switched into an appropriate major mode. See also
|
|
|
+`org-src-lang-modes'. When done, exit with
|
|
|
+\\[org-edit-src-exit]. The edited text will then replace the
|
|
|
+area in the Org mode buffer.
|
|
|
+
|
|
|
+Throw an error when not at an export block."
|
|
|
+ (interactive)
|
|
|
+ (let ((element (org-element-at-point)))
|
|
|
+ (unless (and (eq (org-element-type element) 'export-block)
|
|
|
+ (org-src--on-element-p element))
|
|
|
+ (user-error "Not in an export block"))
|
|
|
+ (let* ((type (downcase (org-element-property :type element)))
|
|
|
+ (mode (org-src--get-lang-mode type)))
|
|
|
+ (unless (functionp mode) (error "No such language mode: %s" mode))
|
|
|
+ (org-src--edit-element
|
|
|
+ element (org-src--construct-edit-buffer-name (buffer-name) type) mode t))
|
|
|
+ t))
|
|
|
+
|
|
|
+(defun org-edit-src-code (&optional code edit-buffer-name)
|
|
|
+ "Edit the source or example 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. See `org-src-window-setup' to configure
|
|
|
+the display of windows containing the Org buffer and the code
|
|
|
+buffer.
|
|
|
+
|
|
|
+When optional argument CODE is a string, edit it in a dedicated
|
|
|
+buffer instead.
|
|
|
+
|
|
|
+When optional argument EDIT-BUFFER-NAME is non-nil, use it as the
|
|
|
+name of the sub-editing buffer."
|
|
|
+ (interactive)
|
|
|
+ (let* ((element (org-element-at-point))
|
|
|
+ (type (org-element-type element)))
|
|
|
+ (unless (and (memq type '(example-block src-block))
|
|
|
+ (org-src--on-element-p element))
|
|
|
+ (user-error "Not in a source or example block"))
|
|
|
+ (let* ((lang
|
|
|
+ (if (eq type 'src-block) (org-element-property :language element)
|
|
|
+ "example"))
|
|
|
+ (lang-f (and (eq type 'src-block) (org-src--get-lang-mode lang)))
|
|
|
+ (babel-info (and (eq type 'src-block)
|
|
|
+ (org-babel-get-src-block-info 'light))))
|
|
|
+ (when (and (eq type 'src-block) (not (functionp lang-f)))
|
|
|
+ (error "No such language mode: %s" lang-f))
|
|
|
+ (org-src--edit-element
|
|
|
+ element
|
|
|
+ (or edit-buffer-name
|
|
|
+ (org-src--construct-edit-buffer-name (buffer-name) lang))
|
|
|
+ lang-f (null code) (and code (org-unescape-code-in-string code)))
|
|
|
+ ;; Finalize buffer.
|
|
|
+ (org-set-local 'org-coderef-label-format
|
|
|
+ (or (org-element-property :label-fmt element)
|
|
|
+ org-coderef-label-format))
|
|
|
+ (when (eq type 'src-block)
|
|
|
+ (org-set-local 'org-src--babel-info babel-info)
|
|
|
+ (let ((edit-prep-func (intern (concat "org-babel-edit-prep:" lang))))
|
|
|
+ (when (fboundp edit-prep-func)
|
|
|
+ (funcall edit-prep-func babel-info))))
|
|
|
+ t)))
|
|
|
+
|
|
|
+(defun org-edit-fixed-width-region ()
|
|
|
+ "Edit the fixed-width ASCII drawing at point.
|
|
|
+
|
|
|
+This must be a region where each line starts with a colon
|
|
|
+followed by a space or a newline character.
|
|
|
+
|
|
|
+A new buffer is created and the fixed-width region is copied into
|
|
|
+it, and the buffer is switched into the major mode defined in
|
|
|
+`org-edit-fixed-width-region-mode', which see. When done, exit
|
|
|
+with \\[org-edit-src-exit]. The edited text will then replace
|
|
|
+the area in the Org mode buffer."
|
|
|
+ (interactive)
|
|
|
+ (let ((element (org-element-at-point)))
|
|
|
+ (unless (and (eq (org-element-type element) 'fixed-width)
|
|
|
+ (org-src--on-element-p element))
|
|
|
+ (user-error "Not in a fixed-width area"))
|
|
|
+ (org-src--edit-element
|
|
|
+ element
|
|
|
+ (org-src--construct-edit-buffer-name (buffer-name) "Fixed Width")
|
|
|
+ org-edit-fixed-width-region-mode
|
|
|
+ t)
|
|
|
+ ;; Return success.
|
|
|
+ t))
|
|
|
+
|
|
|
+(defun org-edit-src-abort ()
|
|
|
+ "Abort editing of the src code and return to the Org buffer."
|
|
|
+ (interactive)
|
|
|
+ (let (org-src--allow-write-back-p) (org-edit-src-exit)))
|
|
|
+
|
|
|
+(defun org-edit-src-continue (e)
|
|
|
+ "Unconditionally return to buffer editing area under point.
|
|
|
+Throw an error if there is no such buffer."
|
|
|
+ (interactive "e")
|
|
|
+ (mouse-set-point e)
|
|
|
+ (let ((buf (get-char-property (point) 'edit-buffer)))
|
|
|
+ (if buf (org-src-switch-to-buffer buf 'continue)
|
|
|
+ (user-error "No sub-editing buffer for area at point"))))
|
|
|
+
|
|
|
+(defun org-edit-src-save ()
|
|
|
+ "Save parent buffer with current state source-code buffer."
|
|
|
+ (interactive)
|
|
|
+ (unless (org-src-edit-buffer-p) (user-error "Not in a sub-editing buffer"))
|
|
|
+ (set-buffer-modified-p nil)
|
|
|
+ (let ((edited-code (org-src--contents-for-write-back))
|
|
|
+ (beg org-src--beg-marker)
|
|
|
+ (end org-src--end-marker)
|
|
|
+ (overlay org-src--overlay))
|
|
|
+ (with-current-buffer (org-src--source-buffer)
|
|
|
+ (undo-boundary)
|
|
|
+ (delete-region beg end)
|
|
|
+ (when (org-string-nw-p edited-code) (insert edited-code))
|
|
|
+ (unless (bolp) (insert "\n"))
|
|
|
+ (move-overlay overlay beg (point))
|
|
|
+ (save-buffer))))
|
|
|
+
|
|
|
+(defun org-edit-src-exit ()
|
|
|
+ "Kill current sub-editing buffer and return to source buffer."
|
|
|
+ (interactive)
|
|
|
+ (unless (org-src-edit-buffer-p) (error "Not in a sub-editing buffer"))
|
|
|
+ (let* ((allow-write-back-p org-src--allow-write-back-p)
|
|
|
+ (beg org-src--beg-marker)
|
|
|
+ (end org-src--end-marker)
|
|
|
+ (coordinates (org-src--coordinates (point) 1 (point-max)))
|
|
|
+ (code (and allow-write-back-p (org-src--contents-for-write-back))))
|
|
|
+ (set-buffer-modified-p nil)
|
|
|
+ ;; Switch to source buffer. Kill sub-editing buffer.
|
|
|
+ (let ((edit-buffer (current-buffer)))
|
|
|
+ (org-src-switch-to-buffer (marker-buffer beg) 'exit)
|
|
|
+ (kill-buffer edit-buffer))
|
|
|
+ ;; Insert modified code. Ensure it ends with a newline character.
|
|
|
+ (when (and allow-write-back-p
|
|
|
+ (not (equal (buffer-substring-no-properties beg end) code)))
|
|
|
+ (undo-boundary)
|
|
|
+ (goto-char beg)
|
|
|
+ (delete-region beg end)
|
|
|
+ (when (org-string-nw-p code)
|
|
|
+ (insert code)
|
|
|
+ (unless (bolp) (insert "\n"))))
|
|
|
+ ;; If we are to return to source buffer, put point at an
|
|
|
+ ;; appropriate location. In particular, if block is hidden, move
|
|
|
+ ;; to the beginning of the block opening line.
|
|
|
+ (goto-char beg)
|
|
|
+ (cond
|
|
|
+ ;; Block is hidden; move at start of block.
|
|
|
+ ((org-some (lambda (o) (eq (overlay-get o 'invisible) 'org-hide-block))
|
|
|
+ (overlays-at (point)))
|
|
|
+ (beginning-of-line 0))
|
|
|
+ (allow-write-back-p (org-src--goto-coordinates coordinates beg end)))
|
|
|
+ ;; Clean up left-over markers and restore window configuration.
|
|
|
+ (set-marker beg nil)
|
|
|
+ (set-marker end nil)
|
|
|
+ (when org-src--saved-temp-window-config
|
|
|
+ (set-window-configuration org-src--saved-temp-window-config)
|
|
|
+ (setq org-src--saved-temp-window-config nil))))
|
|
|
|
|
|
-(defun org-src-font-lock-fontify-block (lang start end)
|
|
|
- "Fontify code block.
|
|
|
-This function is called by emacs automatic fontification, as long
|
|
|
-as `org-src-fontify-natively' is non-nil."
|
|
|
- (let ((lang-mode (org-src-get-lang-mode lang)))
|
|
|
- (if (fboundp lang-mode)
|
|
|
- (let ((string (buffer-substring-no-properties start end))
|
|
|
- (modified (buffer-modified-p))
|
|
|
- (org-buffer (current-buffer)) pos next)
|
|
|
- (remove-text-properties start end '(face nil))
|
|
|
- (with-current-buffer
|
|
|
- (get-buffer-create
|
|
|
- (concat " org-src-fontification:" (symbol-name lang-mode)))
|
|
|
- (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)
|
|
|
- (setq pos (point-min))
|
|
|
- (while (setq next (next-single-property-change pos 'face))
|
|
|
- (put-text-property
|
|
|
- (+ start (1- pos)) (1- (+ start next)) 'face
|
|
|
- (get-text-property pos 'face) org-buffer)
|
|
|
- (setq pos next)))
|
|
|
- (add-text-properties
|
|
|
- start end
|
|
|
- '(font-lock-fontified t fontified t font-lock-multiline t))
|
|
|
- (set-buffer-modified-p modified)))))
|
|
|
-
|
|
|
-(defun org-src-get-lang-mode (lang)
|
|
|
- "Return major mode that should be used for LANG.
|
|
|
-LANG is a string, and the returned major mode is a symbol."
|
|
|
- (intern
|
|
|
- (concat
|
|
|
- (let ((l (or (cdr (assoc lang org-src-lang-modes)) lang)))
|
|
|
- (if (symbolp l) (symbol-name l) l))
|
|
|
- "-mode")))
|
|
|
|
|
|
(provide 'org-src)
|
|
|
|