2010-04-10 Carsten Dominik <carsten.dominik@gmail.com>
[bpt/emacs.git] / lisp / org / org-src.el
CommitLineData
c8d0cf5c
CD
1;;; org-src.el --- Source code examples in Org
2;;
114f9c96 3;; Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010
c8d0cf5c
CD
4;; Free Software Foundation, Inc.
5;;
6;; Author: Carsten Dominik <carsten at orgmode dot org>
7;; Bastien Guerry <bzg AT altern DOT org>
8bfe682a 8;; Dan Davison <davison at stats dot ox dot ac dot uk>
c8d0cf5c
CD
9;; Keywords: outlines, hypermedia, calendar, wp
10;; Homepage: http://orgmode.org
ed21c5c8 11;; Version: 6.35i
c8d0cf5c
CD
12;;
13;; This file is part of GNU Emacs.
14;;
15;; GNU Emacs is free software: you can redistribute it and/or modify
16;; it under the terms of the GNU General Public License as published by
17;; the Free Software Foundation, either version 3 of the License, or
18;; (at your option) any later version.
19
20;; GNU Emacs is distributed in the hope that it will be useful,
21;; but WITHOUT ANY WARRANTY; without even the implied warranty of
22;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23;; GNU General Public License for more details.
24
25;; You should have received a copy of the GNU General Public License
26;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
28;;
29;;; Commentary:
30
31;; This file contains the code dealing with source code examples in Org-mode.
32
33;;; Code:
34
35(require 'org-macs)
36(require 'org-compat)
8bfe682a
CD
37(eval-when-compile
38 (require 'cl))
c8d0cf5c
CD
39
40(declare-function org-do-remove-indentation "org" (&optional n))
ed21c5c8 41(declare-function org-at-table.el-p "org" ())
c8d0cf5c 42(declare-function org-get-indentation "org" (&optional line))
8bfe682a 43(declare-function org-switch-to-buffer-other-window "org" (&rest args))
c8d0cf5c
CD
44
45(defcustom org-edit-src-region-extra nil
46 "Additional regexps to identify regions for editing with `org-edit-src-code'.
47For examples see the function `org-edit-src-find-region-and-lang'.
48The regular expression identifying the begin marker should end with a newline,
49and the regexp marking the end line should start with a newline, to make sure
50there are kept outside the narrowed region."
51 :group 'org-edit-structure
52 :type '(repeat
53 (list
54 (regexp :tag "begin regexp")
55 (regexp :tag "end regexp")
56 (choice :tag "language"
57 (string :tag "specify")
58 (integer :tag "from match group")
59 (const :tag "from `lang' element")
60 (const :tag "from `style' element")))))
61
62(defcustom org-coderef-label-format "(ref:%s)"
63 "The default coderef format.
64This format string will be used to search for coderef labels in literal
65examples (EXAMPLE and SRC blocks). The format can be overwritten in
66an individual literal example with the -f option, like
67
68#+BEGIN_SRC pascal +n -r -l \"((%s))\"
69...
70#+END_SRC
71
72If you want to use this for HTML export, make sure that the format does
73not introduce special font-locking, and avoid the HTML special
74characters `<', `>', and `&'. The reason for this restriction is that
75the labels are searched for only after htmlize has done its job."
76 :group 'org-edit-structure ; FIXME this is not in the right group
77 :type 'string)
78
79(defcustom org-edit-fixed-width-region-mode 'artist-mode
80 "The mode that should be used to edit fixed-width regions.
81These are the regions where each line starts with a colon."
82 :group 'org-edit-structure
83 :type '(choice
84 (const artist-mode)
85 (const picture-mode)
86 (const fundamental-mode)
87 (function :tag "Other (specify)")))
88
8bfe682a
CD
89(defcustom org-src-preserve-indentation nil
90 "If non-nil, leading whitespace characters in source code
91blocks are preserved on export, and when switching between the
92org buffer and the language mode edit buffer. If this variable
93is nil then, after editing with \\[org-edit-src-code], the
94minimum (across-lines) number of leading whitespace characters
95are removed from all lines, and the code block is uniformly
96indented according to the value of `org-edit-src-content-indentation'."
97 :group 'org-edit-structure
98 :type 'boolean)
99
c8d0cf5c 100(defcustom org-edit-src-content-indentation 2
8bfe682a 101 "Indentation for the content of a source code block.
c8d0cf5c
CD
102This should be the number of spaces added to the indentation of the #+begin
103line in order to compute the indentation of the block content after
8bfe682a
CD
104editing it with \\[org-edit-src-code]. Has no effect if
105`org-src-preserve-indentation' is non-nil."
c8d0cf5c
CD
106 :group 'org-edit-structure
107 :type 'integer)
108
109(defcustom org-edit-src-persistent-message t
110 "Non-nil means show persistent exit help message while editing src examples.
111The message is shown in the header-line, which will be created in the
112first line of the window showing the editing buffer.
113When nil, the message will only be shown intermittently in the echo area."
114 :group 'org-edit-structure
115 :type 'boolean)
116
8bfe682a
CD
117(defcustom org-src-window-setup 'reorganize-frame
118 "How the source code edit buffer should be displayed.
119Possible values for this option are:
120
121current-window Show edit buffer in the current window, keeping all other
122 windows.
123other-window Use `switch-to-buffer-other-window' to display edit buffer.
124reorganize-frame Show only two windows on the current frame, the current
125 window and the edit buffer. When exiting the edit buffer,
126 return to one window.
127other-frame Use `switch-to-buffer-other-frame' to display edit buffer.
128 Also, when exiting the edit buffer, kill that frame."
129 :group 'org-edit-structure
130 :type '(choice
131 (const current-window)
132 (const other-frame)
133 (const other-window)
134 (const reorganize-frame)))
135
c8d0cf5c
CD
136(defvar org-src-mode-hook nil
137 "Hook run after Org switched a source code snippet to its Emacs mode.
138This hook will run
139
140- when editing a source code snippet with \"C-c '\".
141- When formatting a source code snippet for export with htmlize.
142
143You may want to use this hook for example to turn off `outline-minor-mode'
144or similar things which you want to have when editing a source code file,
145but which mess up the display of a snippet in Org exported files.")
146
54a0dee5 147(defcustom org-src-lang-modes
8d642074 148 '(("ocaml" . tuareg) ("elisp" . emacs-lisp) ("ditaa" . artist)
8bfe682a 149 ("asymptote" . asy) ("dot" . fundamental))
54a0dee5
CD
150 "Alist mapping languages to their major mode.
151The key is the language name, the value is the string that should
152be inserted as the name of the major mode. For many languages this is
153simple, but for language where this is not the case, this variable
154provides a way to simplify things on the user side.
155For example, there is no ocaml-mode in Emacs, but the mode to use is
156`tuareg-mode'."
157 :group 'org-edit-structure
158 :type '(repeat
159 (cons
160 (string "Language name")
161 (symbol "Major mode"))))
162
c8d0cf5c
CD
163;;; Editing source examples
164
165(defvar org-src-mode-map (make-sparse-keymap))
166(define-key org-src-mode-map "\C-c'" 'org-edit-src-exit)
c8d0cf5c
CD
167(defvar org-edit-src-force-single-line nil)
168(defvar org-edit-src-from-org-mode nil)
169(defvar org-edit-src-picture nil)
170(defvar org-edit-src-beg-marker nil)
171(defvar org-edit-src-end-marker nil)
172(defvar org-edit-src-overlay nil)
8bfe682a
CD
173(defvar org-edit-src-block-indentation nil)
174(defvar org-edit-src-saved-temp-window-config nil)
175
176(defvar org-src-ask-before-returning-to-edit-buffer t
177 "If nil, when org-edit-src code is used on a block that already
178 has an active edit buffer, it will switch to that edit buffer
179 immediately; otherwise it will ask whether you want to return
180 to the existing edit buffer.")
c8d0cf5c
CD
181
182(define-minor-mode org-src-mode
183 "Minor mode for language major mode buffers generated by org.
184This minor mode is turned on in two situations:
185- when editing a source code snippet with \"C-c '\".
186- When formatting a source code snippet for export with htmlize.
187There is a mode hook, and keybindings for `org-edit-src-exit' and
188`org-edit-src-save'")
189
8bfe682a 190(defun org-edit-src-code (&optional context)
c8d0cf5c
CD
191 "Edit the source code example at point.
192The example is copied to a separate buffer, and that buffer is switched
193to the correct language mode. When done, exit with \\[org-edit-src-exit].
194This will remove the original code in the Org buffer, and replace it with
ed21c5c8 195the edited version. Optional argument CONTEXT is used by
8bfe682a 196\\[org-edit-src-save] when calling this function."
c8d0cf5c 197 (interactive)
8bfe682a
CD
198 (unless (eq context 'save)
199 (setq org-edit-src-saved-temp-window-config (current-window-configuration)))
c8d0cf5c 200 (let ((line (org-current-line))
8bfe682a 201 (col (current-column))
c8d0cf5c
CD
202 (case-fold-search t)
203 (msg (substitute-command-keys
204 "Edit, then exit with C-c ' (C-c and single quote)"))
205 (info (org-edit-src-find-region-and-lang))
206 (org-mode-p (eq major-mode 'org-mode))
207 (beg (make-marker))
208 (end (make-marker))
8bfe682a
CD
209 (preserve-indentation org-src-preserve-indentation)
210 block-nindent total-nindent ovl lang lang-f single lfmt code begline buffer)
c8d0cf5c
CD
211 (if (not info)
212 nil
213 (setq beg (move-marker beg (nth 0 info))
214 end (move-marker end (nth 1 info))
215 code (buffer-substring-no-properties beg end)
54a0dee5
CD
216 lang (or (cdr (assoc (nth 2 info) org-src-lang-modes))
217 (nth 2 info))
218 lang (if (symbolp lang) (symbol-name lang) lang)
c8d0cf5c
CD
219 single (nth 3 info)
220 lfmt (nth 4 info)
8bfe682a 221 block-nindent (nth 5 info)
c8d0cf5c
CD
222 lang-f (intern (concat lang "-mode"))
223 begline (save-excursion (goto-char beg) (org-current-line)))
ed21c5c8
CD
224 (if (equal lang-f 'table.el-mode)
225 (setq lang-f (lambda ()
226 (text-mode)
227 (if (org-bound-and-true-p flyspell-mode)
228 (flyspell-mode -1))
229 (table-recognize)
230 (org-set-local 'org-edit-src-content-indentation 0))))
c8d0cf5c
CD
231 (unless (functionp lang-f)
232 (error "No such language mode: %s" lang-f))
54a0dee5 233 (org-goto-line line)
c8d0cf5c 234 (if (and (setq buffer (org-edit-src-find-buffer beg end))
8bfe682a
CD
235 (if org-src-ask-before-returning-to-edit-buffer
236 (y-or-n-p "Return to existing edit buffer? [n] will revert changes: ") t))
237 (org-src-switch-to-buffer buffer 'return)
c8d0cf5c
CD
238 (when buffer
239 (with-current-buffer buffer
240 (if (boundp 'org-edit-src-overlay)
241 (org-delete-overlay org-edit-src-overlay)))
242 (kill-buffer buffer))
54a0dee5 243 (setq buffer (generate-new-buffer
8d642074 244 (org-src-construct-edit-buffer-name (buffer-name) lang)))
c8d0cf5c 245 (setq ovl (org-make-overlay beg end))
c8d0cf5c
CD
246 (org-overlay-put ovl 'edit-buffer buffer)
247 (org-overlay-put ovl 'help-echo "Click with mouse-1 to switch to buffer editing this segment")
248 (org-overlay-put ovl 'face 'secondary-selection)
249 (org-overlay-put ovl
250 'keymap
251 (let ((map (make-sparse-keymap)))
252 (define-key map [mouse-1] 'org-edit-src-continue)
253 map))
254 (org-overlay-put ovl :read-only "Leave me alone")
8bfe682a
CD
255 (org-src-switch-to-buffer buffer 'edit)
256 (if (eq single 'macro-definition)
257 (setq code (replace-regexp-in-string "\\\\n" "\n" code t t)))
c8d0cf5c
CD
258 (insert code)
259 (remove-text-properties (point-min) (point-max)
260 '(display nil invisible nil intangible nil))
8bfe682a
CD
261 (unless preserve-indentation
262 (setq total-nindent (or (org-do-remove-indentation) 0)))
c8d0cf5c 263 (let ((org-inhibit-startup t))
54a0dee5 264 (funcall lang-f))
c8d0cf5c
CD
265 (set (make-local-variable 'org-edit-src-force-single-line) single)
266 (set (make-local-variable 'org-edit-src-from-org-mode) org-mode-p)
8bfe682a 267 (set (make-local-variable 'org-src-preserve-indentation) preserve-indentation)
c8d0cf5c
CD
268 (when lfmt
269 (set (make-local-variable 'org-coderef-label-format) lfmt))
270 (when org-mode-p
271 (goto-char (point-min))
272 (while (re-search-forward "^," nil t)
8bfe682a 273 (if (eq (org-current-line) line) (setq total-nindent (1+ total-nindent)))
c8d0cf5c 274 (replace-match "")))
54a0dee5 275 (org-goto-line (1+ (- line begline)))
8bfe682a
CD
276 (org-move-to-column
277 (if preserve-indentation col (max 0 (- col total-nindent))))
c8d0cf5c
CD
278 (org-set-local 'org-edit-src-beg-marker beg)
279 (org-set-local 'org-edit-src-end-marker end)
280 (org-set-local 'org-edit-src-overlay ovl)
8bfe682a 281 (org-set-local 'org-edit-src-block-indentation block-nindent)
54a0dee5
CD
282 (org-src-mode)
283 (set-buffer-modified-p nil)
c8d0cf5c
CD
284 (and org-edit-src-persistent-message
285 (org-set-local 'header-line-format msg)))
286 (message "%s" msg)
287 t)))
288
289(defun org-edit-src-continue (e)
290 (interactive "e")
291 (mouse-set-point e)
292 (let ((buf (get-char-property (point) 'edit-buffer)))
8bfe682a 293 (if buf (org-src-switch-to-buffer buf 'continue)
c8d0cf5c
CD
294 (error "Something is wrong here"))))
295
8bfe682a
CD
296(defun org-src-switch-to-buffer (buffer context)
297 (case org-src-window-setup
298 ('current-window
299 (switch-to-buffer buffer))
300 ('other-window
301 (switch-to-buffer-other-window buffer))
302 ('other-frame
303 (case context
304 ('exit
305 (let ((frame (selected-frame)))
306 (switch-to-buffer-other-frame buffer)
307 (delete-frame frame)))
308 ('save
309 (kill-buffer (current-buffer))
310 (switch-to-buffer buffer))
311 (t
312 (switch-to-buffer-other-frame buffer))))
313 ('reorganize-frame
314 (if (eq context 'edit) (delete-other-windows))
315 (org-switch-to-buffer-other-window buffer)
316 (if (eq context 'exit) (delete-other-windows)))
317 (t
318 (message "Invalid value %s for org-src-window-setup"
319 (symbol-name org-src-window-setup))
320 (switch-to-buffer buffer))))
321
8d642074
CD
322(defun org-src-construct-edit-buffer-name (org-buffer-name lang)
323 "Construct the buffer name for a source editing buffer"
324 (concat "*Org Src " org-buffer-name "[ " lang " ]*"))
325
c8d0cf5c
CD
326(defun org-edit-src-find-buffer (beg end)
327 "Find a source editing buffer that is already editing the region BEG to END."
328 (catch 'exit
329 (mapc
330 (lambda (b)
331 (with-current-buffer b
8d642074 332 (if (and (string-match "\\`*Org Src " (buffer-name))
c8d0cf5c
CD
333 (local-variable-p 'org-edit-src-beg-marker (current-buffer))
334 (local-variable-p 'org-edit-src-end-marker (current-buffer))
335 (equal beg org-edit-src-beg-marker)
336 (equal end org-edit-src-end-marker))
337 (throw 'exit (current-buffer)))))
338 (buffer-list))
339 nil))
340
341(defun org-edit-fixed-width-region ()
342 "Edit the fixed-width ascii drawing at point.
343This must be a region where each line starts with a colon followed by
344a space character.
345An new buffer is created and the fixed-width region is copied into it,
346and the buffer is switched into `artist-mode' for editing. When done,
347exit with \\[org-edit-src-exit]. The edited text will then replace
348the fragment in the Org-mode buffer."
349 (interactive)
350 (let ((line (org-current-line))
8bfe682a 351 (col (current-column))
c8d0cf5c
CD
352 (case-fold-search t)
353 (msg (substitute-command-keys
354 "Edit, then exit with C-c ' (C-c and single quote)"))
355 (org-mode-p (eq major-mode 'org-mode))
356 (beg (make-marker))
357 (end (make-marker))
8bfe682a
CD
358 (preserve-indentation org-src-preserve-indentation)
359 block-nindent ovl beg1 end1 code begline buffer)
c8d0cf5c
CD
360 (beginning-of-line 1)
361 (if (looking-at "[ \t]*[^:\n \t]")
362 nil
363 (if (looking-at "[ \t]*\\(\n\\|\\'\\)")
364 (setq beg1 (point) end1 beg1)
365 (save-excursion
366 (if (re-search-backward "^[ \t]*[^: \t]" nil 'move)
367 (setq beg1 (point-at-bol 2))
368 (setq beg1 (point))))
369 (save-excursion
370 (if (re-search-forward "^[ \t]*[^: \t]" nil 'move)
371 (setq end1 (1- (match-beginning 0)))
372 (setq end1 (point))))
54a0dee5 373 (org-goto-line line))
c8d0cf5c
CD
374 (setq beg (move-marker beg beg1)
375 end (move-marker end end1)
376 code (buffer-substring-no-properties beg end)
377 begline (save-excursion (goto-char beg) (org-current-line)))
378 (if (and (setq buffer (org-edit-src-find-buffer beg end))
379 (y-or-n-p "Return to existing edit buffer? [n] will revert changes: "))
380 (switch-to-buffer buffer)
381 (when buffer
382 (with-current-buffer buffer
383 (if (boundp 'org-edit-src-overlay)
384 (org-delete-overlay org-edit-src-overlay)))
385 (kill-buffer buffer))
8d642074
CD
386 (setq buffer (generate-new-buffer
387 (org-src-construct-edit-buffer-name
388 (buffer-name) "Fixed Width")))
c8d0cf5c
CD
389 (setq ovl (org-make-overlay beg end))
390 (org-overlay-put ovl 'face 'secondary-selection)
391 (org-overlay-put ovl 'edit-buffer buffer)
392 (org-overlay-put ovl 'help-echo "Click with mouse-1 to switch to buffer editing this segment")
393 (org-overlay-put ovl 'face 'secondary-selection)
394 (org-overlay-put ovl
395 'keymap
396 (let ((map (make-sparse-keymap)))
397 (define-key map [mouse-1] 'org-edit-src-continue)
398 map))
399 (org-overlay-put ovl :read-only "Leave me alone")
400 (switch-to-buffer buffer)
401 (insert code)
402 (remove-text-properties (point-min) (point-max)
403 '(display nil invisible nil intangible nil))
8bfe682a 404 (setq block-nindent (or (org-do-remove-indentation) 0))
c8d0cf5c
CD
405 (cond
406 ((eq org-edit-fixed-width-region-mode 'artist-mode)
407 (fundamental-mode)
408 (artist-mode 1))
409 (t (funcall org-edit-fixed-width-region-mode)))
410 (set (make-local-variable 'org-edit-src-force-single-line) nil)
411 (set (make-local-variable 'org-edit-src-from-org-mode) org-mode-p)
412 (set (make-local-variable 'org-edit-src-picture) t)
413 (goto-char (point-min))
414 (while (re-search-forward "^[ \t]*: ?" nil t)
415 (replace-match ""))
54a0dee5 416 (org-goto-line (1+ (- line begline)))
8bfe682a 417 (org-move-to-column (max 0 (- col block-nindent 2)))
c8d0cf5c
CD
418 (org-set-local 'org-edit-src-beg-marker beg)
419 (org-set-local 'org-edit-src-end-marker end)
420 (org-set-local 'org-edit-src-overlay ovl)
8bfe682a
CD
421 (org-set-local 'org-edit-src-block-indentation block-nindent)
422 (org-set-local 'org-edit-src-content-indentation 0)
423 (org-set-local 'org-src-preserve-indentation nil)
54a0dee5
CD
424 (org-src-mode)
425 (set-buffer-modified-p nil)
c8d0cf5c
CD
426 (and org-edit-src-persistent-message
427 (org-set-local 'header-line-format msg)))
428 (message "%s" msg)
429 t)))
430
431(defun org-edit-src-find-region-and-lang ()
432 "Find the region and language for a local edit.
433Return a list with beginning and end of the region, a string representing
8bfe682a 434the language, a switch telling if the content should be in a single line."
c8d0cf5c
CD
435 (let ((re-list
436 (append
437 org-edit-src-region-extra
438 '(
439 ("<src\\>[^<]*>[ \t]*\n?" "\n?[ \t]*</src>" lang)
440 ("<literal\\>[^<]*>[ \t]*\n?" "\n?[ \t]*</literal>" style)
441 ("<example>[ \t]*\n?" "\n?[ \t]*</example>" "fundamental")
442 ("<lisp>[ \t]*\n?" "\n?[ \t]*</lisp>" "emacs-lisp")
443 ("<perl>[ \t]*\n?" "\n?[ \t]*</perl>" "perl")
444 ("<python>[ \t]*\n?" "\n?[ \t]*</python>" "python")
445 ("<ruby>[ \t]*\n?" "\n?[ \t]*</ruby>" "ruby")
446 ("^[ \t]*#\\+begin_src\\( \\([^ \t\n]+\\)\\)?.*\n" "\n[ \t]*#\\+end_src" 2)
447 ("^[ \t]*#\\+begin_example.*\n" "\n[ \t]*#\\+end_example" "fundamental")
448 ("^[ \t]*#\\+html:" "\n" "html" single-line)
449 ("^[ \t]*#\\+begin_html.*\n" "\n[ \t]*#\\+end_html" "html")
450 ("^[ \t]*#\\+latex:" "\n" "latex" single-line)
451 ("^[ \t]*#\\+begin_latex.*\n" "\n[ \t]*#\\+end_latex" "latex")
452 ("^[ \t]*#\\+ascii:" "\n" "fundamental" single-line)
453 ("^[ \t]*#\\+begin_ascii.*\n" "\n[ \t]*#\\+end_ascii" "fundamental")
454 ("^[ \t]*#\\+docbook:" "\n" "xml" single-line)
8bfe682a
CD
455 ("^[ \t]*#\\+macro:[ \t]+\\S-+\\( \\|$\\)"
456 "\n" "fundamental" macro-definition)
c8d0cf5c
CD
457 ("^[ \t]*#\\+begin_docbook.*\n" "\n[ \t]*#\\+end_docbook" "xml")
458 )))
459 (pos (point))
460 re1 re2 single beg end lang lfmt match-re1 ind entry)
461 (catch 'exit
ed21c5c8
CD
462 (when (org-at-table.el-p)
463 (re-search-backward "^[\t]*[^ \t|\\+]" nil t)
464 (setq beg (1+ (point-at-eol)))
465 (goto-char beg)
466 (or (re-search-forward "^[\t]*[^ \t|\\+]" nil t)
467 (progn (goto-char (point-max)) (newline)))
468 (setq end (point-at-bol))
469 (setq ind (org-edit-src-get-indentation beg))
470 (throw 'exit (list beg end 'table.el nil nil ind)))
c8d0cf5c
CD
471 (while (setq entry (pop re-list))
472 (setq re1 (car entry) re2 (nth 1 entry) lang (nth 2 entry)
473 single (nth 3 entry))
474 (save-excursion
475 (if (or (looking-at re1)
476 (re-search-backward re1 nil t))
477 (progn
478 (setq match-re1 (match-string 0))
479 (setq beg (match-end 0)
480 lang (org-edit-src-get-lang lang)
481 lfmt (org-edit-src-get-label-format match-re1)
482 ind (org-edit-src-get-indentation (match-beginning 0)))
483 (if (and (re-search-forward re2 nil t)
484 (>= (match-end 0) pos))
485 (throw 'exit (list beg (match-beginning 0)
486 lang single lfmt ind))))
487 (if (or (looking-at re2)
488 (re-search-forward re2 nil t))
489 (progn
490 (setq end (match-beginning 0))
491 (if (and (re-search-backward re1 nil t)
492 (<= (match-beginning 0) pos))
493 (progn
494 (setq lfmt (org-edit-src-get-label-format
495 (match-string 0))
496 ind (org-edit-src-get-indentation
497 (match-beginning 0)))
498 (throw 'exit
499 (list (match-end 0) end
500 (org-edit-src-get-lang lang)
501 single lfmt ind))))))))))))
502
503(defun org-edit-src-get-lang (lang)
504 "Extract the src language."
505 (let ((m (match-string 0)))
506 (cond
507 ((stringp lang) lang)
508 ((integerp lang) (match-string lang))
509 ((and (eq lang 'lang)
510 (string-match "\\<lang=\"\\([^ \t\n\"]+\\)\"" m))
511 (match-string 1 m))
512 ((and (eq lang 'style)
513 (string-match "\\<style=\"\\([^ \t\n\"]+\\)\"" m))
514 (match-string 1 m))
515 (t "fundamental"))))
516
517(defun org-edit-src-get-label-format (s)
518 "Extract the label format."
519 (save-match-data
520 (if (string-match "-l[ \t]+\\\\?\"\\([^\t\r\n\"]+\\)\\\\?\"" s)
521 (match-string 1 s))))
522
523(defun org-edit-src-get-indentation (pos)
8bfe682a 524 "Count leading whitespace characters on line"
c8d0cf5c
CD
525 (save-match-data
526 (goto-char pos)
527 (org-get-indentation)))
528
8bfe682a 529(defun org-edit-src-exit (&optional context)
c8d0cf5c
CD
530 "Exit special edit and protect problematic lines."
531 (interactive)
54a0dee5
CD
532 (unless org-edit-src-from-org-mode
533 (error "This is not a sub-editing buffer, something is wrong..."))
ed21c5c8 534 (widen)
8bfe682a
CD
535 (let* ((beg org-edit-src-beg-marker)
536 (end org-edit-src-end-marker)
537 (ovl org-edit-src-overlay)
538 (buffer (current-buffer))
539 (single (org-bound-and-true-p org-edit-src-force-single-line))
540 (macro (eq single 'macro-definition))
541 (total-nindent (+ (or org-edit-src-block-indentation 0)
542 org-edit-src-content-indentation))
543 (preserve-indentation org-src-preserve-indentation)
544 (delta 0) code line col indent)
ed21c5c8 545 (unless preserve-indentation (untabify (point-min) (point-max)))
c8d0cf5c
CD
546 (save-excursion
547 (goto-char (point-min))
548 (if (looking-at "[ \t\n]*\n") (replace-match ""))
8bfe682a
CD
549 (unless macro
550 (if (re-search-forward "\n[ \t\n]*\\'" nil t) (replace-match ""))))
c8d0cf5c
CD
551 (setq line (if (org-bound-and-true-p org-edit-src-force-single-line)
552 1
8bfe682a
CD
553 (org-current-line))
554 col (current-column))
555 (when single
556 (goto-char (point-min))
557 (if (re-search-forward "\\s-+\\'" nil t) (replace-match ""))
c8d0cf5c 558 (goto-char (point-min))
8bfe682a
CD
559 (let ((cnt 0))
560 (while (re-search-forward "\n" nil t)
561 (setq cnt (1+ cnt))
562 (replace-match (if macro "\\n" " ") t t))
563 (when (and macro (> cnt 0))
564 (goto-char (point-max)) (insert "\\n")))
c8d0cf5c 565 (goto-char (point-min))
8bfe682a 566 (if (looking-at "\\s-*") (replace-match " ")))
c8d0cf5c
CD
567 (when (org-bound-and-true-p org-edit-src-from-org-mode)
568 (goto-char (point-min))
569 (while (re-search-forward
570 (if (org-mode-p) "^\\(.\\)" "^\\([*]\\|[ \t]*#\\+\\)") nil t)
8bfe682a 571 (if (eq (org-current-line) line) (setq delta (1+ delta)))
c8d0cf5c
CD
572 (replace-match ",\\1")))
573 (when (org-bound-and-true-p org-edit-src-picture)
8bfe682a 574 (setq preserve-indentation nil)
c8d0cf5c
CD
575 (untabify (point-min) (point-max))
576 (goto-char (point-min))
577 (while (re-search-forward "^" nil t)
578 (replace-match ": ")))
8bfe682a
CD
579 (unless (or single preserve-indentation (= total-nindent 0))
580 (setq indent (make-string total-nindent ?\ ))
c8d0cf5c
CD
581 (goto-char (point-min))
582 (while (re-search-forward "^" nil t)
8bfe682a
CD
583 (replace-match indent)))
584 (if (org-bound-and-true-p org-edit-src-picture)
585 (setq total-nindent (+ total-nindent 2)))
c8d0cf5c 586 (setq code (buffer-string))
54a0dee5 587 (set-buffer-modified-p nil)
8bfe682a 588 (org-src-switch-to-buffer (marker-buffer beg) (or context 'exit))
c8d0cf5c
CD
589 (kill-buffer buffer)
590 (goto-char beg)
c8d0cf5c
CD
591 (delete-region beg end)
592 (insert code)
593 (goto-char beg)
8bfe682a 594 (if single (just-one-space))
ed21c5c8
CD
595 (if (memq t (mapcar (lambda (overlay)
596 (eq (org-overlay-get overlay 'invisible)
597 'org-hide-block))
598 (org-overlays-at (point))))
599 ;; Block is hidden; put point at start of block
600 (beginning-of-line 0)
601 ;; Block is visible, put point where it was in the code buffer
602 (org-goto-line (1- (+ (org-current-line) line)))
603 (org-move-to-column (if preserve-indentation col (+ col total-nindent delta))))
c8d0cf5c 604 (move-marker beg nil)
8bfe682a
CD
605 (move-marker end nil))
606 (unless (eq context 'save)
607 (when org-edit-src-saved-temp-window-config
608 (set-window-configuration org-edit-src-saved-temp-window-config)
609 (setq org-edit-src-saved-temp-window-config nil))))
c8d0cf5c
CD
610
611(defun org-edit-src-save ()
612 "Save parent buffer with current state source-code buffer."
613 (interactive)
8bfe682a
CD
614 (let ((p (point)) (m (mark)) msg)
615 (save-window-excursion
616 (org-edit-src-exit 'save)
8d642074
CD
617 (save-buffer)
618 (setq msg (current-message))
8bfe682a
CD
619 (if (eq org-src-window-setup 'other-frame)
620 (let ((org-src-window-setup 'current-window))
621 (org-edit-src-code 'save))
622 (org-edit-src-code 'save)))
623 (push-mark m 'nomessage)
624 (goto-char (min p (point-max)))
625 (message (or msg ""))))
c8d0cf5c 626
54a0dee5
CD
627(defun org-src-mode-configure-edit-buffer ()
628 (when org-edit-src-from-org-mode
629 (setq buffer-offer-save t)
630 (setq buffer-file-name
631 (concat (buffer-file-name (marker-buffer org-edit-src-beg-marker))
632 "[" (buffer-name) "]"))
633 (set (if (featurep 'xemacs) 'write-contents-hooks 'write-contents-functions)
634 '(org-edit-src-save))
635 (org-add-hook 'kill-buffer-hook
636 '(lambda () (org-delete-overlay org-edit-src-overlay)) nil 'local)))
637
638(org-add-hook 'org-src-mode-hook 'org-src-mode-configure-edit-buffer)
639
c8d0cf5c
CD
640(provide 'org-src)
641
642;; arch-tag: 6a1fc84f-dec7-47be-a416-64be56bea5d8
c8d0cf5c 643;;; org-src.el ends here