소스 검색

org-src: Unify source editing tools

* lisp/org-src.el (org-src-strip-leading-and-trailing-blanklines,
  org-edit-src-force-single-line, org-edit-src-picture,
  org-edit-src-from-org-mode, org-edit-src-allow-write-back-p,
  org-edit-src-beg-marker, org-edit-src-end-marker,
  org-edit-src-overlay, org-edit-src-block-indentation,
  org-edit-src-saved-temp-window-config, org-edit-src-code-timer):
  Remove variables.
(org-src--allow-write-back-p, org-src--beg-marker,
org-src--block-indentation, org-src--code-timer, org-src--end-marker,
org-src--end-marker, org-src--from-org-mode, org-src--overlay,
org-src--saved-temp-window-config, org-src--type,
org-src--babel-info): New variables.

(org-src--construct-edit-buffer-name, org-src--edit-buffer,
org-src--source-buffer, org-src--get-lang-mode, org-src--coordinates,
org-src--goto-coordinates, org-src--element-contents-area,
org-src--make-source-overlay, org-src--on-element-p,
org-src--contents-for-write-back, org-src--edit-element,
org-edit-table.el, org-edit-export-block): New functions.
(org-edit-src-find-buffer, org-src-construct-edit-buffer-name,
org-src-tangle, org-src-in-org-buffer): Remove functions.

(org-edit-src-code, org-edit-fixed-width-region, org-edit-src-abort,
org-edit-src-save): Use new functions and variables.
(org-edit-src-exit): Use new functions and variables.  Change
signature.

* lisp/org.el (org-edit-special, org-indent-line, org-indent-region):
  Use new functions and variables.

* lisp/ob-core.el (org-babel-do-in-edit-buffer): Remove useless check.
(org-babel-expand-src-block): Apply signature change.

This patches resolves discrepancies between source editing tools and
globally simplifies process (auto-save feature, region
preservation...).  It introduces export block editing.  It also moves
internal variables and functions into an appropriate namespace and
delete some unused functions.
Nicolas Goaziou 10 년 전
부모
커밋
203bf5870f
3개의 변경된 파일545개의 추가작업 그리고 541개의 파일을 삭제
  1. 4 7
      lisp/ob-core.el
  2. 539 529
      lisp/org-src.el
  3. 2 5
      lisp/org.el

+ 4 - 7
lisp/ob-core.el

@@ -49,9 +49,8 @@
 (declare-function tramp-file-name-host "tramp" (vec))
 (declare-function with-parsed-tramp-file-name "tramp" (filename var &rest body))
 (declare-function org-icompleting-read "org" (&rest args))
-(declare-function org-edit-src-code "org-src"
-                  (&optional context code edit-buffer-name quietp))
-(declare-function org-edit-src-exit "org-src"  (&optional context))
+(declare-function org-edit-src-code "org-src" (&optional code edit-buffer-name))
+(declare-function org-edit-src-exit "org-src"  ())
 (declare-function org-open-at-point "org" (&optional in-emacs reference-buffer))
 (declare-function org-save-outline-visibility "org-macs" (use-markers &rest body))
 (declare-function org-outline-overlay-data "org" (&optional use-markers))
@@ -777,8 +776,7 @@ arguments and pop open the results in a preview buffer."
 			      (funcall assignments-cmd params))))))
     (if (org-called-interactively-p 'any)
 	(org-edit-src-code
-	 nil expanded
-	 (concat "*Org-Babel Preview " (buffer-name) "[ " lang " ]*"))
+	 expanded (concat "*Org-Babel Preview " (buffer-name) "[ " lang " ]*"))
       expanded)))
 
 (defun org-babel-edit-distance (s1 s2)
@@ -994,8 +992,7 @@ Return t if a code block was found at point, nil otherwise."
      (when (and (org-babel-where-is-src-block-head)
 		(org-edit-src-code))
        (unwind-protect (progn ,@body)
-	 (if (org-bound-and-true-p org-edit-src-from-org-mode)
-	     (org-edit-src-exit)))
+	 (org-edit-src-exit))
        t)))
 (def-edebug-spec org-babel-do-in-edit-buffer (body))
 

+ 539 - 529
lisp/org-src.el

@@ -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)
 

+ 2 - 5
lisp/org.el

@@ -22745,8 +22745,7 @@ Also align node properties according to `org-property-format'."
 		      (goto-char (org-element-property :end element))
 		      (skip-chars-backward " \r\t\n")
 		      (line-beginning-position))))
-	     (let ((org-src-strip-leading-and-trailing-blank-lines nil))
-	       (org-babel-do-key-sequence-in-edit-buffer (kbd "TAB"))))
+	     (org-babel-do-key-sequence-in-edit-buffer (kbd "TAB")))
 	    (t
 	     (let ((column (org--get-expected-indentation element nil)))
 	       ;; Preserve current column.
@@ -22854,9 +22853,7 @@ assumed to be significant there."
 		     ;; `org-src-tab-acts-natively' is non-nil.
 		     (when (and (< (point) end) org-src-tab-acts-natively)
 		       (ignore-errors
-			 (let (org-src-strip-leading-and-trailing-blank-lines
-			       ;; Region boundaries in edit buffer.
-			       (start (1+ (- (point) cbeg)))
+			 (let ((start (1+ (- (point) cbeg)))
 			       (end (- (min cend end) cbeg)))
 			   (org-babel-do-in-edit-buffer
 			    (indent-region start end))))))