Avoid the use of ((lambda ...) ...) in lexical-binding code.
[bpt/emacs.git] / lisp / org / org-src.el
CommitLineData
c8d0cf5c
CD
1;;; org-src.el --- Source code examples in Org
2;;
b73f1974 3;; Copyright (C) 2004-2012 Free Software Foundation, Inc.
c8d0cf5c
CD
4;;
5;; Author: Carsten Dominik <carsten at orgmode dot org>
e66ba1df 6;; Bastien Guerry <bzg AT gnu DOT org>
8bfe682a 7;; Dan Davison <davison at stats dot ox dot ac dot uk>
c8d0cf5c
CD
8;; Keywords: outlines, hypermedia, calendar, wp
9;; Homepage: http://orgmode.org
c8d0cf5c
CD
10;;
11;; This file is part of GNU Emacs.
12;;
13;; GNU Emacs is free software: you can redistribute it and/or modify
14;; it under the terms of the GNU General Public License as published by
15;; the Free Software Foundation, either version 3 of the License, or
16;; (at your option) any later version.
17
18;; GNU Emacs is distributed in the hope that it will be useful,
19;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21;; GNU General Public License for more details.
22
23;; You should have received a copy of the GNU General Public License
24;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
26;;
27;;; Commentary:
28
29;; This file contains the code dealing with source code examples in Org-mode.
30
31;;; Code:
32
33(require 'org-macs)
34(require 'org-compat)
afe98dfa
CD
35(require 'ob-keys)
36(require 'ob-comint)
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))
14e1337f 44(declare-function org-pop-to-buffer-same-window
e66ba1df 45 "org-compat" (&optional buffer-or-name norecord label))
153ae947
BG
46(declare-function org-strip-protective-commas "org" (beg end))
47(declare-function org-base-buffer "org" (buffer))
c8d0cf5c
CD
48
49(defcustom org-edit-src-region-extra nil
50 "Additional regexps to identify regions for editing with `org-edit-src-code'.
51For examples see the function `org-edit-src-find-region-and-lang'.
52The regular expression identifying the begin marker should end with a newline,
53and the regexp marking the end line should start with a newline, to make sure
54there are kept outside the narrowed region."
55 :group 'org-edit-structure
56 :type '(repeat
57 (list
58 (regexp :tag "begin regexp")
59 (regexp :tag "end regexp")
60 (choice :tag "language"
61 (string :tag "specify")
62 (integer :tag "from match group")
63 (const :tag "from `lang' element")
64 (const :tag "from `style' element")))))
65
66(defcustom org-coderef-label-format "(ref:%s)"
67 "The default coderef format.
68This format string will be used to search for coderef labels in literal
69examples (EXAMPLE and SRC blocks). The format can be overwritten in
86fbb8ca 70an individual literal example with the -l option, like
c8d0cf5c
CD
71
72#+BEGIN_SRC pascal +n -r -l \"((%s))\"
73...
74#+END_SRC
75
76If you want to use this for HTML export, make sure that the format does
77not introduce special font-locking, and avoid the HTML special
78characters `<', `>', and `&'. The reason for this restriction is that
79the labels are searched for only after htmlize has done its job."
80 :group 'org-edit-structure ; FIXME this is not in the right group
81 :type 'string)
82
83(defcustom org-edit-fixed-width-region-mode 'artist-mode
84 "The mode that should be used to edit fixed-width regions.
85These are the regions where each line starts with a colon."
86 :group 'org-edit-structure
87 :type '(choice
88 (const artist-mode)
89 (const picture-mode)
90 (const fundamental-mode)
91 (function :tag "Other (specify)")))
92
8bfe682a 93(defcustom org-src-preserve-indentation nil
86fbb8ca
CD
94 "If non-nil preserve leading whitespace characters on export.
95If non-nil leading whitespace characters in source code blocks
96are preserved on export, and when switching between the org
97buffer and the language mode edit buffer. If this variable is nil
98then, after editing with \\[org-edit-src-code], the
8bfe682a
CD
99minimum (across-lines) number of leading whitespace characters
100are removed from all lines, and the code block is uniformly
101indented according to the value of `org-edit-src-content-indentation'."
102 :group 'org-edit-structure
103 :type 'boolean)
104
c8d0cf5c 105(defcustom org-edit-src-content-indentation 2
8bfe682a 106 "Indentation for the content of a source code block.
c8d0cf5c
CD
107This should be the number of spaces added to the indentation of the #+begin
108line in order to compute the indentation of the block content after
86fbb8ca 109editing it with \\[org-edit-src-code]. Has no effect if
8bfe682a 110`org-src-preserve-indentation' is non-nil."
c8d0cf5c
CD
111 :group 'org-edit-structure
112 :type 'integer)
113
afe98dfa
CD
114(defvar org-src-strip-leading-and-trailing-blank-lines nil
115 "If non-nil, blank lines are removed when exiting the code edit
116buffer.")
117
c8d0cf5c
CD
118(defcustom org-edit-src-persistent-message t
119 "Non-nil means show persistent exit help message while editing src examples.
120The message is shown in the header-line, which will be created in the
3ab2c837 121first line of the window showing the editing buffer."
c8d0cf5c
CD
122 :group 'org-edit-structure
123 :type 'boolean)
124
8bfe682a
CD
125(defcustom org-src-window-setup 'reorganize-frame
126 "How the source code edit buffer should be displayed.
127Possible values for this option are:
128
129current-window Show edit buffer in the current window, keeping all other
130 windows.
131other-window Use `switch-to-buffer-other-window' to display edit buffer.
132reorganize-frame Show only two windows on the current frame, the current
133 window and the edit buffer. When exiting the edit buffer,
134 return to one window.
135other-frame Use `switch-to-buffer-other-frame' to display edit buffer.
136 Also, when exiting the edit buffer, kill that frame."
137 :group 'org-edit-structure
138 :type '(choice
139 (const current-window)
140 (const other-frame)
141 (const other-window)
142 (const reorganize-frame)))
143
c8d0cf5c
CD
144(defvar org-src-mode-hook nil
145 "Hook run after Org switched a source code snippet to its Emacs mode.
146This hook will run
147
148- when editing a source code snippet with \"C-c '\".
149- When formatting a source code snippet for export with htmlize.
150
151You may want to use this hook for example to turn off `outline-minor-mode'
152or similar things which you want to have when editing a source code file,
153but which mess up the display of a snippet in Org exported files.")
154
54a0dee5 155(defcustom org-src-lang-modes
8d642074 156 '(("ocaml" . tuareg) ("elisp" . emacs-lisp) ("ditaa" . artist)
afe98dfa 157 ("asymptote" . asy) ("dot" . fundamental) ("sqlite" . sql)
153ae947
BG
158 ("calc" . fundamental) ("C" . c) ("cpp" . c++)
159 ("screen" . shell-script))
54a0dee5
CD
160 "Alist mapping languages to their major mode.
161The key is the language name, the value is the string that should
162be inserted as the name of the major mode. For many languages this is
163simple, but for language where this is not the case, this variable
164provides a way to simplify things on the user side.
165For example, there is no ocaml-mode in Emacs, but the mode to use is
166`tuareg-mode'."
167 :group 'org-edit-structure
168 :type '(repeat
169 (cons
170 (string "Language name")
171 (symbol "Major mode"))))
172
c8d0cf5c
CD
173;;; Editing source examples
174
3ab2c837
BG
175(defvar org-src-mode-map (make-sparse-keymap))
176(define-key org-src-mode-map "\C-c'" 'org-edit-src-exit)
afe98dfa 177
c8d0cf5c
CD
178(defvar org-edit-src-force-single-line nil)
179(defvar org-edit-src-from-org-mode nil)
86fbb8ca 180(defvar org-edit-src-allow-write-back-p t)
c8d0cf5c
CD
181(defvar org-edit-src-picture nil)
182(defvar org-edit-src-beg-marker nil)
183(defvar org-edit-src-end-marker nil)
184(defvar org-edit-src-overlay nil)
8bfe682a
CD
185(defvar org-edit-src-block-indentation nil)
186(defvar org-edit-src-saved-temp-window-config nil)
187
188(defvar org-src-ask-before-returning-to-edit-buffer t
189 "If nil, when org-edit-src code is used on a block that already
190 has an active edit buffer, it will switch to that edit buffer
191 immediately; otherwise it will ask whether you want to return
192 to the existing edit buffer.")
c8d0cf5c 193
afe98dfa
CD
194(defvar org-src-babel-info nil)
195
c8d0cf5c
CD
196(define-minor-mode org-src-mode
197 "Minor mode for language major mode buffers generated by org.
198This minor mode is turned on in two situations:
199- when editing a source code snippet with \"C-c '\".
200- When formatting a source code snippet for export with htmlize.
201There is a mode hook, and keybindings for `org-edit-src-exit' and
202`org-edit-src-save'")
203
3ab2c837 204(defun org-edit-src-code (&optional context code edit-buffer-name)
c8d0cf5c 205 "Edit the source code example at point.
afe98dfa
CD
206The example is copied to a separate buffer, and that buffer is
207switched to the correct language mode. When done, exit with
208\\[org-edit-src-exit]. This will remove the original code in the
209Org buffer, and replace it with the edited version. Optional
210argument CONTEXT is used by \\[org-edit-src-save] when calling
211this function. See \\[org-src-window-setup] to configure the
212display of windows containing the Org buffer and the code
213buffer."
c8d0cf5c 214 (interactive)
8bfe682a
CD
215 (unless (eq context 'save)
216 (setq org-edit-src-saved-temp-window-config (current-window-configuration)))
153ae947
BG
217 (let* ((mark (and (org-region-active-p) (mark)))
218 (case-fold-search t)
219 (info (org-edit-src-find-region-and-lang))
220 (full-info (org-babel-get-src-block-info 'light))
221 (org-mode-p (derived-mode-p 'org-mode)) ;; derived-mode-p is reflexive
222 (beg (make-marker))
223 (end (make-marker))
224 (allow-write-back-p (null code))
225 block-nindent total-nindent ovl lang lang-f single lfmt buffer msg
226 begline markline markcol line col transmitted-variables)
c8d0cf5c
CD
227 (if (not info)
228 nil
229 (setq beg (move-marker beg (nth 0 info))
230 end (move-marker end (nth 1 info))
86fbb8ca
CD
231 msg (if allow-write-back-p
232 (substitute-command-keys
233 "Edit, then exit with C-c ' (C-c and single quote)")
234 "Exit with C-c ' (C-c and single quote)")
235 code (or code (buffer-substring-no-properties beg end))
54a0dee5
CD
236 lang (or (cdr (assoc (nth 2 info) org-src-lang-modes))
237 (nth 2 info))
238 lang (if (symbolp lang) (symbol-name lang) lang)
c8d0cf5c 239 single (nth 3 info)
8bfe682a 240 block-nindent (nth 5 info)
c8d0cf5c 241 lang-f (intern (concat lang "-mode"))
3ab2c837
BG
242 begline (save-excursion (goto-char beg) (org-current-line))
243 transmitted-variables
244 `((org-edit-src-content-indentation
245 ,org-edit-src-content-indentation)
246 (org-edit-src-force-single-line ,single)
247 (org-edit-src-from-org-mode ,org-mode-p)
248 (org-edit-src-allow-write-back-p ,allow-write-back-p)
249 (org-src-preserve-indentation ,org-src-preserve-indentation)
250 (org-src-babel-info ,(org-babel-get-src-block-info 'light))
251 (org-coderef-label-format
252 ,(or (nth 4 info) org-coderef-label-format))
253 (org-edit-src-beg-marker ,beg)
254 (org-edit-src-end-marker ,end)
255 (org-edit-src-block-indentation ,block-nindent)))
acedf35c
CD
256 (if (and mark (>= mark beg) (<= mark (1+ end)))
257 (save-excursion (goto-char (min mark end))
afe98dfa
CD
258 (setq markline (org-current-line)
259 markcol (current-column))))
ed21c5c8
CD
260 (if (equal lang-f 'table.el-mode)
261 (setq lang-f (lambda ()
262 (text-mode)
263 (if (org-bound-and-true-p flyspell-mode)
264 (flyspell-mode -1))
265 (table-recognize)
266 (org-set-local 'org-edit-src-content-indentation 0))))
c8d0cf5c
CD
267 (unless (functionp lang-f)
268 (error "No such language mode: %s" lang-f))
afe98dfa
CD
269 (save-excursion
270 (if (> (point) end) (goto-char end))
271 (setq line (org-current-line)
272 col (current-column)))
c8d0cf5c 273 (if (and (setq buffer (org-edit-src-find-buffer beg end))
8bfe682a
CD
274 (if org-src-ask-before-returning-to-edit-buffer
275 (y-or-n-p "Return to existing edit buffer? [n] will revert changes: ") t))
276 (org-src-switch-to-buffer buffer 'return)
c8d0cf5c
CD
277 (when buffer
278 (with-current-buffer buffer
279 (if (boundp 'org-edit-src-overlay)
86fbb8ca 280 (delete-overlay org-edit-src-overlay)))
c8d0cf5c 281 (kill-buffer buffer))
54a0dee5 282 (setq buffer (generate-new-buffer
86fbb8ca
CD
283 (or edit-buffer-name
284 (org-src-construct-edit-buffer-name (buffer-name) lang))))
285 (setq ovl (make-overlay beg end))
286 (overlay-put ovl 'edit-buffer buffer)
287 (overlay-put ovl 'help-echo "Click with mouse-1 to switch to buffer editing this segment")
288 (overlay-put ovl 'face 'secondary-selection)
289 (overlay-put ovl
290 'keymap
291 (let ((map (make-sparse-keymap)))
292 (define-key map [mouse-1] 'org-edit-src-continue)
293 map))
294 (overlay-put ovl :read-only "Leave me alone")
3ab2c837
BG
295 (setq transmitted-variables
296 (append transmitted-variables `((org-edit-src-overlay ,ovl))))
8bfe682a
CD
297 (org-src-switch-to-buffer buffer 'edit)
298 (if (eq single 'macro-definition)
299 (setq code (replace-regexp-in-string "\\\\n" "\n" code t t)))
c8d0cf5c
CD
300 (insert code)
301 (remove-text-properties (point-min) (point-max)
302 '(display nil invisible nil intangible nil))
3ab2c837 303 (unless (cadr (assq 'org-src-preserve-indentation transmitted-variables))
8bfe682a 304 (setq total-nindent (or (org-do-remove-indentation) 0)))
c8d0cf5c 305 (let ((org-inhibit-startup t))
afe98dfa
CD
306 (condition-case e
307 (funcall lang-f)
308 (error
309 (error "Language mode `%s' fails with: %S" lang-f (nth 1 e)))))
3ab2c837
BG
310 (dolist (pair transmitted-variables)
311 (org-set-local (car pair) (cadr pair)))
153ae947
BG
312 (if (eq major-mode 'org-mode)
313 (progn
314 (goto-char (point-min))
315 (while (re-search-forward "^," nil t)
316 (if (eq (org-current-line) line) (setq total-nindent (1+ total-nindent)))
317 (replace-match "")))
318 (org-strip-protective-commas (point-min) (point-max)))
afe98dfa
CD
319 (when markline
320 (org-goto-line (1+ (- markline begline)))
321 (org-move-to-column
3ab2c837
BG
322 (if org-src-preserve-indentation markcol
323 (max 0 (- markcol total-nindent))))
afe98dfa
CD
324 (push-mark (point) 'no-message t)
325 (setq deactivate-mark nil))
54a0dee5 326 (org-goto-line (1+ (- line begline)))
8bfe682a 327 (org-move-to-column
3ab2c837 328 (if org-src-preserve-indentation col (max 0 (- col total-nindent))))
54a0dee5
CD
329 (org-src-mode)
330 (set-buffer-modified-p nil)
c8d0cf5c 331 (and org-edit-src-persistent-message
3ab2c837
BG
332 (org-set-local 'header-line-format msg))
333 (let ((edit-prep-func (intern (concat "org-babel-edit-prep:" lang))))
334 (when (fboundp edit-prep-func)
335 (funcall edit-prep-func full-info))))
c8d0cf5c
CD
336 t)))
337
338(defun org-edit-src-continue (e)
339 (interactive "e")
340 (mouse-set-point e)
341 (let ((buf (get-char-property (point) 'edit-buffer)))
8bfe682a 342 (if buf (org-src-switch-to-buffer buf 'continue)
c8d0cf5c
CD
343 (error "Something is wrong here"))))
344
8bfe682a
CD
345(defun org-src-switch-to-buffer (buffer context)
346 (case org-src-window-setup
3ab2c837 347 ('current-window
e66ba1df 348 (org-pop-to-buffer-same-window buffer))
3ab2c837 349 ('other-window
8bfe682a 350 (switch-to-buffer-other-window buffer))
3ab2c837 351 ('other-frame
8bfe682a 352 (case context
3ab2c837 353 ('exit
8bfe682a
CD
354 (let ((frame (selected-frame)))
355 (switch-to-buffer-other-frame buffer)
356 (delete-frame frame)))
3ab2c837 357 ('save
8bfe682a 358 (kill-buffer (current-buffer))
e66ba1df 359 (org-pop-to-buffer-same-window buffer))
8bfe682a
CD
360 (t
361 (switch-to-buffer-other-frame buffer))))
3ab2c837 362 ('reorganize-frame
8bfe682a
CD
363 (if (eq context 'edit) (delete-other-windows))
364 (org-switch-to-buffer-other-window buffer)
365 (if (eq context 'exit) (delete-other-windows)))
3ab2c837 366 ('switch-invisibly
afe98dfa 367 (set-buffer buffer))
8bfe682a
CD
368 (t
369 (message "Invalid value %s for org-src-window-setup"
370 (symbol-name org-src-window-setup))
e66ba1df 371 (org-pop-to-buffer-same-window buffer))))
8bfe682a 372
8d642074 373(defun org-src-construct-edit-buffer-name (org-buffer-name lang)
86fbb8ca 374 "Construct the buffer name for a source editing buffer."
8d642074
CD
375 (concat "*Org Src " org-buffer-name "[ " lang " ]*"))
376
153ae947
BG
377(defun org-src-edit-buffer-p (&optional buffer)
378 "Test whether BUFFER (or the current buffer if BUFFER is nil)
379is a source block editing buffer."
380 (let ((buffer (org-base-buffer (or buffer (current-buffer)))))
381 (and (buffer-name buffer)
382 (string-match "\\`*Org Src " (buffer-name buffer))
383 (local-variable-p 'org-edit-src-beg-marker buffer)
384 (local-variable-p 'org-edit-src-end-marker buffer))))
385
c8d0cf5c
CD
386(defun org-edit-src-find-buffer (beg end)
387 "Find a source editing buffer that is already editing the region BEG to END."
388 (catch 'exit
389 (mapc
390 (lambda (b)
391 (with-current-buffer b
8d642074 392 (if (and (string-match "\\`*Org Src " (buffer-name))
c8d0cf5c
CD
393 (local-variable-p 'org-edit-src-beg-marker (current-buffer))
394 (local-variable-p 'org-edit-src-end-marker (current-buffer))
395 (equal beg org-edit-src-beg-marker)
396 (equal end org-edit-src-end-marker))
397 (throw 'exit (current-buffer)))))
398 (buffer-list))
399 nil))
400
401(defun org-edit-fixed-width-region ()
402 "Edit the fixed-width ascii drawing at point.
403This must be a region where each line starts with a colon followed by
404a space character.
405An new buffer is created and the fixed-width region is copied into it,
406and the buffer is switched into `artist-mode' for editing. When done,
407exit with \\[org-edit-src-exit]. The edited text will then replace
408the fragment in the Org-mode buffer."
409 (interactive)
410 (let ((line (org-current-line))
8bfe682a 411 (col (current-column))
c8d0cf5c
CD
412 (case-fold-search t)
413 (msg (substitute-command-keys
414 "Edit, then exit with C-c ' (C-c and single quote)"))
e66ba1df 415 (org-mode-p (eq major-mode 'org-mode))
c8d0cf5c
CD
416 (beg (make-marker))
417 (end (make-marker))
8bfe682a
CD
418 (preserve-indentation org-src-preserve-indentation)
419 block-nindent ovl beg1 end1 code begline buffer)
c8d0cf5c
CD
420 (beginning-of-line 1)
421 (if (looking-at "[ \t]*[^:\n \t]")
422 nil
423 (if (looking-at "[ \t]*\\(\n\\|\\'\\)")
424 (setq beg1 (point) end1 beg1)
425 (save-excursion
426 (if (re-search-backward "^[ \t]*[^: \t]" nil 'move)
427 (setq beg1 (point-at-bol 2))
428 (setq beg1 (point))))
429 (save-excursion
430 (if (re-search-forward "^[ \t]*[^: \t]" nil 'move)
431 (setq end1 (1- (match-beginning 0)))
432 (setq end1 (point))))
54a0dee5 433 (org-goto-line line))
c8d0cf5c
CD
434 (setq beg (move-marker beg beg1)
435 end (move-marker end end1)
436 code (buffer-substring-no-properties beg end)
437 begline (save-excursion (goto-char beg) (org-current-line)))
438 (if (and (setq buffer (org-edit-src-find-buffer beg end))
439 (y-or-n-p "Return to existing edit buffer? [n] will revert changes: "))
e66ba1df 440 (org-pop-to-buffer-same-window buffer)
c8d0cf5c
CD
441 (when buffer
442 (with-current-buffer buffer
443 (if (boundp 'org-edit-src-overlay)
86fbb8ca 444 (delete-overlay org-edit-src-overlay)))
c8d0cf5c 445 (kill-buffer buffer))
8d642074
CD
446 (setq buffer (generate-new-buffer
447 (org-src-construct-edit-buffer-name
448 (buffer-name) "Fixed Width")))
86fbb8ca
CD
449 (setq ovl (make-overlay beg end))
450 (overlay-put ovl 'face 'secondary-selection)
451 (overlay-put ovl 'edit-buffer buffer)
452 (overlay-put ovl 'help-echo "Click with mouse-1 to switch to buffer editing this segment")
453 (overlay-put ovl 'face 'secondary-selection)
454 (overlay-put ovl
c8d0cf5c
CD
455 'keymap
456 (let ((map (make-sparse-keymap)))
457 (define-key map [mouse-1] 'org-edit-src-continue)
458 map))
86fbb8ca 459 (overlay-put ovl :read-only "Leave me alone")
e66ba1df 460 (org-pop-to-buffer-same-window buffer)
c8d0cf5c
CD
461 (insert code)
462 (remove-text-properties (point-min) (point-max)
463 '(display nil invisible nil intangible nil))
8bfe682a 464 (setq block-nindent (or (org-do-remove-indentation) 0))
c8d0cf5c
CD
465 (cond
466 ((eq org-edit-fixed-width-region-mode 'artist-mode)
467 (fundamental-mode)
468 (artist-mode 1))
86fbb8ca 469 (t (funcall org-edit-fixed-width-region-mode)))
c8d0cf5c
CD
470 (set (make-local-variable 'org-edit-src-force-single-line) nil)
471 (set (make-local-variable 'org-edit-src-from-org-mode) org-mode-p)
472 (set (make-local-variable 'org-edit-src-picture) t)
473 (goto-char (point-min))
474 (while (re-search-forward "^[ \t]*: ?" nil t)
475 (replace-match ""))
54a0dee5 476 (org-goto-line (1+ (- line begline)))
8bfe682a 477 (org-move-to-column (max 0 (- col block-nindent 2)))
c8d0cf5c
CD
478 (org-set-local 'org-edit-src-beg-marker beg)
479 (org-set-local 'org-edit-src-end-marker end)
480 (org-set-local 'org-edit-src-overlay ovl)
8bfe682a
CD
481 (org-set-local 'org-edit-src-block-indentation block-nindent)
482 (org-set-local 'org-edit-src-content-indentation 0)
483 (org-set-local 'org-src-preserve-indentation nil)
54a0dee5
CD
484 (org-src-mode)
485 (set-buffer-modified-p nil)
c8d0cf5c
CD
486 (and org-edit-src-persistent-message
487 (org-set-local 'header-line-format msg)))
488 (message "%s" msg)
489 t)))
490
491(defun org-edit-src-find-region-and-lang ()
492 "Find the region and language for a local edit.
493Return a list with beginning and end of the region, a string representing
8bfe682a 494the language, a switch telling if the content should be in a single line."
c8d0cf5c
CD
495 (let ((re-list
496 (append
497 org-edit-src-region-extra
498 '(
499 ("<src\\>[^<]*>[ \t]*\n?" "\n?[ \t]*</src>" lang)
500 ("<literal\\>[^<]*>[ \t]*\n?" "\n?[ \t]*</literal>" style)
501 ("<example>[ \t]*\n?" "\n?[ \t]*</example>" "fundamental")
502 ("<lisp>[ \t]*\n?" "\n?[ \t]*</lisp>" "emacs-lisp")
503 ("<perl>[ \t]*\n?" "\n?[ \t]*</perl>" "perl")
504 ("<python>[ \t]*\n?" "\n?[ \t]*</python>" "python")
505 ("<ruby>[ \t]*\n?" "\n?[ \t]*</ruby>" "ruby")
506 ("^[ \t]*#\\+begin_src\\( \\([^ \t\n]+\\)\\)?.*\n" "\n[ \t]*#\\+end_src" 2)
507 ("^[ \t]*#\\+begin_example.*\n" "\n[ \t]*#\\+end_example" "fundamental")
508 ("^[ \t]*#\\+html:" "\n" "html" single-line)
509 ("^[ \t]*#\\+begin_html.*\n" "\n[ \t]*#\\+end_html" "html")
510 ("^[ \t]*#\\+latex:" "\n" "latex" single-line)
511 ("^[ \t]*#\\+begin_latex.*\n" "\n[ \t]*#\\+end_latex" "latex")
512 ("^[ \t]*#\\+ascii:" "\n" "fundamental" single-line)
513 ("^[ \t]*#\\+begin_ascii.*\n" "\n[ \t]*#\\+end_ascii" "fundamental")
514 ("^[ \t]*#\\+docbook:" "\n" "xml" single-line)
8bfe682a
CD
515 ("^[ \t]*#\\+macro:[ \t]+\\S-+\\( \\|$\\)"
516 "\n" "fundamental" macro-definition)
c8d0cf5c
CD
517 ("^[ \t]*#\\+begin_docbook.*\n" "\n[ \t]*#\\+end_docbook" "xml")
518 )))
519 (pos (point))
520 re1 re2 single beg end lang lfmt match-re1 ind entry)
521 (catch 'exit
522 (while (setq entry (pop re-list))
523 (setq re1 (car entry) re2 (nth 1 entry) lang (nth 2 entry)
524 single (nth 3 entry))
525 (save-excursion
526 (if (or (looking-at re1)
527 (re-search-backward re1 nil t))
528 (progn
529 (setq match-re1 (match-string 0))
530 (setq beg (match-end 0)
531 lang (org-edit-src-get-lang lang)
532 lfmt (org-edit-src-get-label-format match-re1)
533 ind (org-edit-src-get-indentation (match-beginning 0)))
534 (if (and (re-search-forward re2 nil t)
535 (>= (match-end 0) pos))
536 (throw 'exit (list beg (match-beginning 0)
537 lang single lfmt ind))))
538 (if (or (looking-at re2)
539 (re-search-forward re2 nil t))
540 (progn
541 (setq end (match-beginning 0))
542 (if (and (re-search-backward re1 nil t)
543 (<= (match-beginning 0) pos))
544 (progn
545 (setq lfmt (org-edit-src-get-label-format
546 (match-string 0))
547 ind (org-edit-src-get-indentation
548 (match-beginning 0)))
549 (throw 'exit
550 (list (match-end 0) end
551 (org-edit-src-get-lang lang)
86fbb8ca
CD
552 single lfmt ind)))))))))
553 (when (org-at-table.el-p)
554 (re-search-backward "^[\t]*[^ \t|\\+]" nil t)
555 (setq beg (1+ (point-at-eol)))
556 (goto-char beg)
557 (or (re-search-forward "^[\t]*[^ \t|\\+]" nil t)
558 (progn (goto-char (point-max)) (newline)))
559 (setq end (point-at-bol))
560 (setq ind (org-edit-src-get-indentation beg))
561 (throw 'exit (list beg end 'table.el nil nil ind))))))
c8d0cf5c
CD
562
563(defun org-edit-src-get-lang (lang)
564 "Extract the src language."
565 (let ((m (match-string 0)))
566 (cond
567 ((stringp lang) lang)
568 ((integerp lang) (match-string lang))
569 ((and (eq lang 'lang)
570 (string-match "\\<lang=\"\\([^ \t\n\"]+\\)\"" m))
571 (match-string 1 m))
572 ((and (eq lang 'style)
573 (string-match "\\<style=\"\\([^ \t\n\"]+\\)\"" m))
574 (match-string 1 m))
575 (t "fundamental"))))
576
577(defun org-edit-src-get-label-format (s)
578 "Extract the label format."
579 (save-match-data
580 (if (string-match "-l[ \t]+\\\\?\"\\([^\t\r\n\"]+\\)\\\\?\"" s)
581 (match-string 1 s))))
582
583(defun org-edit-src-get-indentation (pos)
86fbb8ca 584 "Count leading whitespace characters on line."
c8d0cf5c
CD
585 (save-match-data
586 (goto-char pos)
587 (org-get-indentation)))
588
8bfe682a 589(defun org-edit-src-exit (&optional context)
c8d0cf5c
CD
590 "Exit special edit and protect problematic lines."
591 (interactive)
86fbb8ca
CD
592 (unless (org-bound-and-true-p org-edit-src-from-org-mode)
593 (error "This is not a sub-editing buffer, something is wrong"))
ed21c5c8 594 (widen)
8bfe682a
CD
595 (let* ((beg org-edit-src-beg-marker)
596 (end org-edit-src-end-marker)
597 (ovl org-edit-src-overlay)
598 (buffer (current-buffer))
599 (single (org-bound-and-true-p org-edit-src-force-single-line))
600 (macro (eq single 'macro-definition))
601 (total-nindent (+ (or org-edit-src-block-indentation 0)
602 org-edit-src-content-indentation))
603 (preserve-indentation org-src-preserve-indentation)
86fbb8ca 604 (allow-write-back-p (org-bound-and-true-p org-edit-src-allow-write-back-p))
8bfe682a 605 (delta 0) code line col indent)
86fbb8ca
CD
606 (when allow-write-back-p
607 (unless preserve-indentation (untabify (point-min) (point-max)))
afe98dfa
CD
608 (if org-src-strip-leading-and-trailing-blank-lines
609 (save-excursion
610 (goto-char (point-min))
611 (if (looking-at "[ \t\n]*\n") (replace-match ""))
612 (unless macro
613 (if (re-search-forward "\n[ \t\n]*\\'" nil t) (replace-match ""))))))
c8d0cf5c
CD
614 (setq line (if (org-bound-and-true-p org-edit-src-force-single-line)
615 1
8bfe682a
CD
616 (org-current-line))
617 col (current-column))
86fbb8ca
CD
618 (when allow-write-back-p
619 (when single
620 (goto-char (point-min))
621 (if (re-search-forward "\\s-+\\'" nil t) (replace-match ""))
622 (goto-char (point-min))
623 (let ((cnt 0))
624 (while (re-search-forward "\n" nil t)
625 (setq cnt (1+ cnt))
626 (replace-match (if macro "\\n" " ") t t))
627 (when (and macro (> cnt 0))
628 (goto-char (point-max)) (insert "\\n")))
629 (goto-char (point-min))
630 (if (looking-at "\\s-*") (replace-match " ")))
631 (when (org-bound-and-true-p org-edit-src-from-org-mode)
632 (goto-char (point-min))
633 (while (re-search-forward
e66ba1df 634 (if (eq major-mode 'org-mode) "^\\(.\\)" "^\\([*]\\|[ \t]*#\\+\\)") nil t)
86fbb8ca
CD
635 (if (eq (org-current-line) line) (setq delta (1+ delta)))
636 (replace-match ",\\1")))
637 (when (org-bound-and-true-p org-edit-src-picture)
638 (setq preserve-indentation nil)
639 (untabify (point-min) (point-max))
640 (goto-char (point-min))
641 (while (re-search-forward "^" nil t)
642 (replace-match ": ")))
643 (unless (or single preserve-indentation (= total-nindent 0))
644 (setq indent (make-string total-nindent ?\ ))
645 (goto-char (point-min))
646 (while (re-search-forward "^" nil t)
647 (replace-match indent)))
648 (if (org-bound-and-true-p org-edit-src-picture)
649 (setq total-nindent (+ total-nindent 2)))
650 (setq code (buffer-string))
651 (set-buffer-modified-p nil))
8bfe682a 652 (org-src-switch-to-buffer (marker-buffer beg) (or context 'exit))
c8d0cf5c
CD
653 (kill-buffer buffer)
654 (goto-char beg)
86fbb8ca
CD
655 (when allow-write-back-p
656 (delete-region beg end)
657 (insert code)
658 (goto-char beg)
659 (if single (just-one-space)))
ed21c5c8 660 (if (memq t (mapcar (lambda (overlay)
86fbb8ca 661 (eq (overlay-get overlay 'invisible)
ed21c5c8 662 'org-hide-block))
86fbb8ca 663 (overlays-at (point))))
ed21c5c8
CD
664 ;; Block is hidden; put point at start of block
665 (beginning-of-line 0)
666 ;; Block is visible, put point where it was in the code buffer
667 (org-goto-line (1- (+ (org-current-line) line)))
668 (org-move-to-column (if preserve-indentation col (+ col total-nindent delta))))
c8d0cf5c 669 (move-marker beg nil)
8bfe682a
CD
670 (move-marker end nil))
671 (unless (eq context 'save)
672 (when org-edit-src-saved-temp-window-config
673 (set-window-configuration org-edit-src-saved-temp-window-config)
674 (setq org-edit-src-saved-temp-window-config nil))))
c8d0cf5c
CD
675
676(defun org-edit-src-save ()
677 "Save parent buffer with current state source-code buffer."
678 (interactive)
8bfe682a
CD
679 (let ((p (point)) (m (mark)) msg)
680 (save-window-excursion
681 (org-edit-src-exit 'save)
8d642074
CD
682 (save-buffer)
683 (setq msg (current-message))
8bfe682a
CD
684 (if (eq org-src-window-setup 'other-frame)
685 (let ((org-src-window-setup 'current-window))
686 (org-edit-src-code 'save))
687 (org-edit-src-code 'save)))
688 (push-mark m 'nomessage)
689 (goto-char (min p (point-max)))
690 (message (or msg ""))))
c8d0cf5c 691
54a0dee5 692(defun org-src-mode-configure-edit-buffer ()
86fbb8ca 693 (when (org-bound-and-true-p org-edit-src-from-org-mode)
54a0dee5 694 (org-add-hook 'kill-buffer-hook
3ab2c837 695 #'(lambda () (delete-overlay org-edit-src-overlay)) nil 'local)
86fbb8ca
CD
696 (if (org-bound-and-true-p org-edit-src-allow-write-back-p)
697 (progn
698 (setq buffer-offer-save t)
699 (setq buffer-file-name
700 (concat (buffer-file-name (marker-buffer org-edit-src-beg-marker))
701 "[" (buffer-name) "]"))
702 (if (featurep 'xemacs)
703 (progn
704 (make-variable-buffer-local 'write-contents-hooks) ; needed only for 21.4
705 (setq write-contents-hooks '(org-edit-src-save)))
706 (setq write-contents-functions '(org-edit-src-save))))
707 (setq buffer-read-only t))))
54a0dee5
CD
708
709(org-add-hook 'org-src-mode-hook 'org-src-mode-configure-edit-buffer)
710
afe98dfa
CD
711
712(defun org-src-associate-babel-session (info)
713 "Associate edit buffer with comint session."
714 (interactive)
715 (let ((session (cdr (assoc :session (nth 2 info)))))
716 (and session (not (string= session "none"))
717 (org-babel-comint-buffer-livep session)
718 ((lambda (f) (and (fboundp f) (funcall f session)))
719 (intern (format "org-babel-%s-associate-session" (nth 0 info)))))))
720
721(defun org-src-babel-configure-edit-buffer ()
722 (when org-src-babel-info
723 (org-src-associate-babel-session org-src-babel-info)))
724
725(org-add-hook 'org-src-mode-hook 'org-src-babel-configure-edit-buffer)
726(defmacro org-src-do-at-code-block (&rest body)
727 "Execute a command from an edit buffer in the Org-mode buffer."
728 `(let ((beg-marker org-edit-src-beg-marker))
729 (if beg-marker
730 (with-current-buffer (marker-buffer beg-marker)
731 (goto-char (marker-position beg-marker))
732 ,@body))))
e66ba1df 733(def-edebug-spec org-src-do-at-code-block (body))
afe98dfa
CD
734
735(defun org-src-do-key-sequence-at-code-block (&optional key)
736 "Execute key sequence at code block in the source Org buffer.
737The command bound to KEY in the Org-babel key map is executed
738remotely with point temporarily at the start of the code block in
739the Org buffer.
740
741This command is not bound to a key by default, to avoid conflicts
742with language major mode bindings. To bind it to C-c @ in all
743language major modes, you could use
744
745 (add-hook 'org-src-mode-hook
746 (lambda () (define-key org-src-mode-map \"\\C-c@\"
747 'org-src-do-key-sequence-at-code-block)))
748
749In that case, for example, C-c @ t issued in code edit buffers
750would tangle the current Org code block, C-c @ e would execute
751the block and C-c @ h would display the other available
752Org-babel commands."
753 (interactive "kOrg-babel key: ")
754 (if (equal key (kbd "C-g")) (keyboard-quit)
755 (org-edit-src-save)
756 (org-src-do-at-code-block
757 (call-interactively
758 (lookup-key org-babel-map key)))))
759
760(defcustom org-src-tab-acts-natively nil
761 "If non-nil, the effect of TAB in a code block is as if it were
762issued in the language major mode buffer."
763 :type 'boolean
372d7b21 764 :version "24.1"
afe98dfa
CD
765 :group 'org-babel)
766
767(defun org-src-native-tab-command-maybe ()
768 "Perform language-specific TAB action.
769Alter code block according to effect of TAB in the language major
770mode."
771 (and org-src-tab-acts-natively
772 (let ((org-src-strip-leading-and-trailing-blank-lines nil))
773 (org-babel-do-key-sequence-in-edit-buffer (kbd "TAB")))))
774
775(add-hook 'org-tab-first-hook 'org-src-native-tab-command-maybe)
776
777(defun org-src-font-lock-fontify-block (lang start end)
778 "Fontify code block.
779This function is called by emacs automatic fontification, as long
780as `org-src-fontify-natively' is non-nil. For manual
781fontification of code blocks see `org-src-fontify-block' and
782`org-src-fontify-buffer'"
3ab2c837
BG
783 (let ((lang-mode (org-src-get-lang-mode lang)))
784 (if (fboundp lang-mode)
785 (let ((string (buffer-substring-no-properties start end))
786 (modified (buffer-modified-p))
787 (org-buffer (current-buffer)) pos next)
788 (remove-text-properties start end '(face nil))
789 (with-current-buffer
790 (get-buffer-create
791 (concat " org-src-fontification:" (symbol-name lang-mode)))
792 (delete-region (point-min) (point-max))
793 (insert (concat string " ")) ;; so there's a final property change
794 (unless (eq major-mode lang-mode) (funcall lang-mode))
795 (font-lock-fontify-buffer)
796 (setq pos (point-min))
797 (while (setq next (next-single-property-change pos 'face))
798 (put-text-property
799 (+ start (1- pos)) (+ start next) 'face
800 (get-text-property pos 'face) org-buffer)
801 (setq pos next)))
802 (add-text-properties
803 start end
804 '(font-lock-fontified t fontified t font-lock-multiline t))
805 (set-buffer-modified-p modified)))))
afe98dfa
CD
806
807(defun org-src-fontify-block ()
808 "Fontify code block at point."
809 (interactive)
810 (save-excursion
811 (let ((org-src-fontify-natively t)
812 (info (org-edit-src-find-region-and-lang)))
813 (font-lock-fontify-region (nth 0 info) (nth 1 info)))))
814
815(defun org-src-fontify-buffer ()
816 "Fontify all code blocks in the current buffer"
817 (interactive)
818 (org-babel-map-src-blocks nil
819 (org-src-fontify-block)))
820
821(defun org-src-get-lang-mode (lang)
822 "Return major mode that should be used for LANG.
823LANG is a string, and the returned major mode is a symbol."
824 (intern
825 (concat
826 ((lambda (l) (if (symbolp l) (symbol-name l) l))
827 (or (cdr (assoc lang org-src-lang-modes)) lang)) "-mode")))
828
c8d0cf5c
CD
829(provide 'org-src)
830
c8d0cf5c 831;;; org-src.el ends here