Commit | Line | Data |
---|---|---|
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'. | |
47 | For examples see the function `org-edit-src-find-region-and-lang'. | |
48 | The regular expression identifying the begin marker should end with a newline, | |
49 | and the regexp marking the end line should start with a newline, to make sure | |
50 | there 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. | |
64 | This format string will be used to search for coderef labels in literal | |
65 | examples (EXAMPLE and SRC blocks). The format can be overwritten in | |
66 | an individual literal example with the -f option, like | |
67 | ||
68 | #+BEGIN_SRC pascal +n -r -l \"((%s))\" | |
69 | ... | |
70 | #+END_SRC | |
71 | ||
72 | If you want to use this for HTML export, make sure that the format does | |
73 | not introduce special font-locking, and avoid the HTML special | |
74 | characters `<', `>', and `&'. The reason for this restriction is that | |
75 | the 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. | |
81 | These 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 | |
91 | blocks are preserved on export, and when switching between the | |
92 | org buffer and the language mode edit buffer. If this variable | |
93 | is nil then, after editing with \\[org-edit-src-code], the | |
94 | minimum (across-lines) number of leading whitespace characters | |
95 | are removed from all lines, and the code block is uniformly | |
96 | indented 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 |
102 | This should be the number of spaces added to the indentation of the #+begin |
103 | line in order to compute the indentation of the block content after | |
8bfe682a CD |
104 | editing 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. | |
111 | The message is shown in the header-line, which will be created in the | |
112 | first line of the window showing the editing buffer. | |
113 | When 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. | |
119 | Possible values for this option are: | |
120 | ||
121 | current-window Show edit buffer in the current window, keeping all other | |
122 | windows. | |
123 | other-window Use `switch-to-buffer-other-window' to display edit buffer. | |
124 | reorganize-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. | |
127 | other-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. | |
138 | This 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 | ||
143 | You may want to use this hook for example to turn off `outline-minor-mode' | |
144 | or similar things which you want to have when editing a source code file, | |
145 | but 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. |
151 | The key is the language name, the value is the string that should | |
152 | be inserted as the name of the major mode. For many languages this is | |
153 | simple, but for language where this is not the case, this variable | |
154 | provides a way to simplify things on the user side. | |
155 | For 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. | |
184 | This 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. | |
187 | There 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. |
192 | The example is copied to a separate buffer, and that buffer is switched | |
193 | to the correct language mode. When done, exit with \\[org-edit-src-exit]. | |
194 | This will remove the original code in the Org buffer, and replace it with | |
ed21c5c8 | 195 | the 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. | |
343 | This must be a region where each line starts with a colon followed by | |
344 | a space character. | |
345 | An new buffer is created and the fixed-width region is copied into it, | |
346 | and the buffer is switched into `artist-mode' for editing. When done, | |
347 | exit with \\[org-edit-src-exit]. The edited text will then replace | |
348 | the 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. | |
433 | Return a list with beginning and end of the region, a string representing | |
8bfe682a | 434 | the 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 |