-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathob-core.el
3723 lines (3441 loc) · 145 KB
/
ob-core.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;;; ob-core.el --- Working with Code Blocks -*- lexical-binding: t; -*-
;; Copyright (C) 2009-2025 Free Software Foundation, Inc.
;; Authors: Eric Schulte
;; Dan Davison
;; Keywords: literate programming, reproducible research
;; URL: https://orgmode.org
;; This file is part of GNU Emacs.
;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;;; Code:
(require 'org-macs)
(org-assert-version)
(require 'cl-lib)
(require 'ob-eval)
(require 'org-macs)
(require 'org-fold)
(require 'org-compat)
(require 'org-cycle)
(defconst org-babel-exeext
(if (memq system-type '(windows-nt cygwin))
".exe"
nil))
(defvar org-babel-library-of-babel)
(defvar org-edit-src-content-indentation)
(defvar org-link-file-path-type)
(defvar org-src-lang-modes)
(defvar org-babel-tangle-uncomment-comments)
(declare-function org-attach-dir "org-attach" (&optional create-if-not-exists-p no-fs-check))
(declare-function org-at-item-p "org-list" ())
(declare-function org-at-table-p "org" (&optional table-type))
(declare-function org-babel-lob-execute-maybe "ob-lob" ())
(declare-function org-babel-ref-goto-headline-id "ob-ref" (id))
(declare-function org-babel-ref-headline-body "ob-ref" ())
(declare-function org-babel-ref-parse "ob-ref" (assignment))
(declare-function org-babel-ref-resolve "ob-ref" (ref))
(declare-function org-babel-ref-split-args "ob-ref" (arg-string))
(declare-function org-babel-tangle-comment-links "ob-tangle" (&optional info))
(declare-function org-current-level "org" ())
(declare-function org-cycle "org-cycle" (&optional arg))
(declare-function org-edit-src-code "org-src" (&optional code edit-buffer-name))
(declare-function org-edit-src-exit "org-src" ())
(declare-function org-src-preserve-indentation-p "org-src" (node))
(declare-function org-element-at-point "org-element" (&optional pom cached-only))
(declare-function org-element-at-point-no-context "org-element" (&optional pom))
(declare-function org-element-context "org-element" (&optional element))
(declare-function org-element-normalize-string "org-element" (s))
(declare-function org-element-property "org-element-ast" (property node))
(declare-function org-element-begin "org-element" (node))
(declare-function org-element-end "org-element" (node))
(declare-function org-element-post-affiliated "org-element" (node))
(declare-function org-element-contents-begin "org-element" (node))
(declare-function org-element-contents-end "org-element" (node))
(declare-function org-element-parent "org-element-ast" (node))
(declare-function org-element-type "org-element-ast" (node &optional anonymous))
(declare-function org-element-type-p "org-element-ast" (node &optional types))
(declare-function org-element-interpret-data "org-element" (data))
(declare-function org-entry-get "org" (pom property &optional inherit literal-nil))
(declare-function org-escape-code-in-region "org-src" (beg end))
(declare-function org-forward-heading-same-level "org" (arg &optional invisible-ok))
(declare-function org-in-commented-heading-p "org" (&optional no-inheritance))
(declare-function org-indent-block "org" ())
(declare-function org-indent-line "org" ())
(declare-function org-list-get-list-end "org-list" (item struct prevs))
(declare-function org-list-prevs-alist "org-list" (struct))
(declare-function org-list-struct "org-list" ())
(declare-function org-list-to-generic "org-list" (LIST PARAMS))
(declare-function org-list-to-lisp "org-list" (&optional delete))
(declare-function org-list-to-org "org-list" (list &optional params))
(declare-function org-macro-escape-arguments "org-macro" (&rest args))
(declare-function org-mark-ring-push "org" (&optional pos buffer))
(declare-function org-narrow-to-subtree "org" (&optional element))
(declare-function org-next-block "org" (arg &optional backward block-regexp))
(declare-function org-open-at-point "org" (&optional in-emacs reference-buffer))
(declare-function org-previous-block "org" (arg &optional block-regexp))
(declare-function org-fold-show-context "org-fold" (&optional key))
(declare-function org-src-coderef-format "org-src" (&optional element))
(declare-function org-src-coderef-regexp "org-src" (fmt &optional label))
(declare-function org-src-get-lang-mode "org-src" (lang))
(declare-function org-table-align "org-table" ())
(declare-function org-table-convert-region "org-table" (beg0 end0 &optional separator))
(declare-function org-table-end "org-table" (&optional table-type))
(declare-function org-table-import "org-table" (file arg))
(declare-function org-table-to-lisp "org-table" (&optional txt))
(declare-function org-unescape-code-in-string "org-src" (s))
(declare-function orgtbl-to-generic "org-table" (table params))
(declare-function orgtbl-to-orgtbl "org-table" (table params))
(declare-function tramp-compat-make-temp-file "tramp-compat" (filename &optional dir-flag))
(defgroup org-babel nil
"Code block evaluation and management in `org-mode' documents."
:tag "Babel"
:group 'org)
(defcustom org-confirm-babel-evaluate t
"Confirm before evaluation.
\\<org-mode-map>\
Require confirmation before interactively evaluating code
blocks in Org buffers. The default value of this variable is t,
meaning confirmation is required for any code block evaluation.
This variable can be set to nil to inhibit any future
confirmation requests. This variable can also be set to a
function which takes two arguments the language of the code block
and the body of the code block. Such a function should then
return a non-nil value if the user should be prompted for
execution or nil if no prompt is required.
Warning: Disabling confirmation may result in accidental
evaluation of potentially harmful code. It may be advisable
remove code block execution from `\\[org-ctrl-c-ctrl-c]' \
as further protection
against accidental code block evaluation. The
`org-babel-no-eval-on-ctrl-c-ctrl-c' variable can be used to
remove code block execution from the `\\[org-ctrl-c-ctrl-c]' keybinding."
:group 'org-babel
:version "24.1"
:type '(choice boolean function))
;; don't allow this variable to be changed through file settings
(put 'org-confirm-babel-evaluate 'safe-local-variable (lambda (x) (eq x t)))
(defcustom org-babel-no-eval-on-ctrl-c-ctrl-c nil
"\\<org-mode-map>\
Remove code block evaluation from the `\\[org-ctrl-c-ctrl-c]' key binding."
:group 'org-babel
:version "24.1"
:type 'boolean)
(defcustom org-babel-results-keyword "RESULTS"
"Keyword used to name results generated by code blocks.
It should be \"RESULTS\". However any capitalization may be
used."
:group 'org-babel
:version "24.4"
:package-version '(Org . "8.0")
:type 'string
:safe (lambda (v)
(and (stringp v)
(org-string-equal-ignore-case "RESULTS" v))))
(defcustom org-babel-noweb-wrap-start "<<"
"String used to begin a noweb reference in a code block.
See also `org-babel-noweb-wrap-end'."
:group 'org-babel
:type 'string)
(defcustom org-babel-noweb-wrap-end ">>"
"String used to end a noweb reference in a code block.
See also `org-babel-noweb-wrap-start'."
:group 'org-babel
:type 'string)
(defcustom org-babel-inline-result-wrap "=%s="
"Format string used to wrap inline results.
This string must include a \"%s\" which will be replaced by the results."
:group 'org-babel
:type 'string)
(put 'org-babel-inline-result-wrap
'safe-local-variable
(lambda (value)
(and (stringp value)
(string-match-p "%s" value))))
(defcustom org-babel-hash-show-time nil
"Non-nil means show the time the code block was evaluated in the result hash."
:group 'org-babel
:type 'boolean
:package-version '(Org . "9.0")
:safe #'booleanp)
(defcustom org-babel-uppercase-example-markers nil
"When non-nil, begin/end example markers will be inserted in upper case."
:group 'org-babel
:type 'boolean
:version "26.1"
:package-version '(Org . "9.1")
:safe #'booleanp)
(defun org-babel-noweb-wrap (&optional regexp)
"Return regexp matching a Noweb reference.
Match any reference, or only those matching REGEXP, if non-nil.
When matching, reference is stored in match group 1."
(concat (regexp-quote org-babel-noweb-wrap-start)
(or regexp "\\([^ \t\n]\\(?:.*?[^ \t\n]\\)?\\)")
(regexp-quote org-babel-noweb-wrap-end)))
(defvar org-babel-src-name-regexp
"^[ \t]*#\\+name:[ \t]*"
"Regular expression used to match a source name line.")
(defvar org-babel-multi-line-header-regexp
"^[ \t]*#\\+headers?:[ \t]*\\([^\n]*\\)$"
"Regular expression used to match multi-line header arguments.")
(defvar org-babel-src-block-regexp
(concat
;; (1) indentation (2) lang
"^\\([ \t]*\\)#\\+begin_src\\(?:[ \t]+\\([^ \f\t\n\r\v]*\\)\\)?[ \t]*"
;; (3) switches
"\\([^\":\n]*\"[^\"\n*]*\"[^\":\n]*\\|[^\":\n]*\\)"
;; (4) header arguments
"\\([^\n]*\\)\n"
;; (5) body
"\\(\\(?:.\\|\n\\)*?\n\\)??[ \t]*#\\+end_src")
"Regexp used to identify code blocks.")
(defun org-babel--get-vars (params)
"Return the babel variable assignments in PARAMS.
PARAMS is a quasi-alist of header args, which may contain
multiple entries for the key `:var'. This function returns a
list of the cdr of all the `:var' entries."
(mapcar #'cdr
(cl-remove-if-not (lambda (x) (eq (car x) :var)) params)))
(defvar org-babel-exp-reference-buffer nil
"Buffer containing original contents of the exported buffer.
This is used by Babel to resolve references in source blocks.
Its value is dynamically bound during export.")
(defun org-babel-check-confirm-evaluate (info)
"Check whether INFO allows code block evaluation.
Returns nil if evaluation is disallowed, t if it is
unconditionally allowed, and the symbol `query' if the user
should be asked whether to allow evaluation."
(let* ((headers (nth 2 info))
(eval (or (cdr (assq :eval headers))
(when (assq :noeval headers) "no")))
(eval-no (member eval '("no" "never")))
(export org-babel-exp-reference-buffer)
(eval-no-export (and export (member eval '("no-export" "never-export"))))
(noeval (or eval-no eval-no-export))
(query (or (equal eval "query")
(and export (equal eval "query-export"))
(if (functionp org-confirm-babel-evaluate)
(funcall org-confirm-babel-evaluate
;; Language, code block body.
(nth 0 info)
(org-babel--expand-body info))
org-confirm-babel-evaluate))))
(cond
(noeval nil)
(query 'query)
(t t))))
(defun org-babel-check-evaluate (info)
"Check if code block INFO should be evaluated.
Do not query the user, but do display an informative message if
evaluation is blocked. Returns non-nil if evaluation is not blocked."
(let ((confirmed (org-babel-check-confirm-evaluate info)))
(unless confirmed
(message "Evaluation of this %s code block%sis disabled."
(nth 0 info)
(let ((name (nth 4 info)))
(if name (format " (%s) " name) " "))))
confirmed))
;; Dynamically scoped for asynchronous export.
(defvar org-babel-confirm-evaluate-answer-no)
(defun org-babel-confirm-evaluate (info)
"Confirm evaluation of the code block INFO.
This query can also be suppressed by setting the value of
`org-confirm-babel-evaluate' to nil, in which case all future
interactive code block evaluations will proceed without any
confirmation from the user.
Note disabling confirmation may result in accidental evaluation
of potentially harmful code.
The variable `org-babel-confirm-evaluate-answer-no' is used by
the async export process, which requires a non-interactive
environment, to override this check."
(let* ((evalp (org-babel-check-confirm-evaluate info))
(lang (nth 0 info))
(name (nth 4 info))
(name-string (if name (format " (%s) " name) " ")))
(pcase evalp
(`nil nil)
(`t t)
(`query (or
(and (not (bound-and-true-p
org-babel-confirm-evaluate-answer-no))
(yes-or-no-p
(format "Evaluate this %s code block%son your system? "
lang name-string)))
(progn
(message "Evaluation of this %s code block%sis aborted."
lang name-string)
nil)))
(x (error "Unexpected value `%s' from `org-babel-check-confirm-evaluate'" x)))))
;;;###autoload
(defun org-babel-execute-safely-maybe ()
"Maybe `org-babel-execute-maybe'.
This function does nothing unless `org-babel-no-eval-on-ctrl-c-ctrl-c'
is non-nil."
(unless org-babel-no-eval-on-ctrl-c-ctrl-c
(org-babel-execute-maybe)))
;;;###autoload
(defun org-babel-execute-maybe ()
"Execute src block or babel call at point."
(interactive)
(or (org-babel-execute-src-block-maybe)
(org-babel-lob-execute-maybe)))
(defmacro org-babel-when-in-src-block (&rest body)
"Execute BODY if point is in a source block and return t.
Otherwise do nothing and return nil."
`(if (org-element-type-p (org-element-context) '(inline-src-block src-block))
(progn
,@body
t)
nil))
(defun org-babel-execute-src-block-maybe ()
"Conditionally execute a source block.
Detect if this is context for a Babel src-block and if so
then run `org-babel-execute-src-block'."
(interactive)
(org-babel-when-in-src-block
(org-babel-eval-wipe-error-buffer)
(org-babel-execute-src-block current-prefix-arg)))
;;;###autoload
(defun org-babel-view-src-block-info ()
"Display information on the current source block.
This includes header arguments, language and name, and is largely
a window into the `org-babel-get-src-block-info' function."
(interactive)
(let ((info (org-babel-get-src-block-info 'no-eval))
(full (lambda (it) (> (length it) 0)))
(printf (lambda (fmt &rest args) (princ (apply #'format fmt args)))))
(when info
(let* ((name (nth 4 info))
(language (nth 0 info))
(switches (nth 3 info))
(header-args (nth 2 info))
(property-header-args
(org-entry-get (point) "header-args" t))
(property-header-args-language
(org-entry-get (point) (concat "header-args:" language) t)))
(with-help-window (help-buffer)
(when name (funcall printf "Name: %s\n" name))
(when language (funcall printf "Language: %s\n" language))
;; Show header arguments that have been set through
;; properties (i.e. in property drawers or through
;; #+PROPERTY)
(funcall printf "Properties:\n")
(funcall printf "\t:header-args \t%s\n" property-header-args)
(funcall printf "\t:header-args:%s \t%s\n" language property-header-args-language)
;; Show switches
(when (funcall full switches) (funcall printf "Switches: %s\n" switches))
;; Show default header arguments and header arguments that
;; have been explicitly set in the current code block.
(funcall printf "Header Arguments:\n")
(dolist (pair (sort header-args
(lambda (a b) (string< (symbol-name (car a))
(symbol-name (car b))))))
(when (funcall full (format "%s" (cdr pair)))
(funcall printf "\t%S%s\t%s\n"
(car pair)
(if (> (length (format "%S" (car pair))) 7) "" "\t")
(cdr pair)))))))))
;;;###autoload
(defun org-babel-expand-src-block-maybe ()
"Conditionally expand a source block.
Detect if this is context for an org-babel src-block and if so
then run `org-babel-expand-src-block'."
(interactive)
(org-babel-when-in-src-block
(org-babel-expand-src-block current-prefix-arg)))
;;;###autoload
(defun org-babel-load-in-session-maybe ()
"Conditionally load a source block in a session.
Detect if this is context for an org-babel src-block and if so
then run `org-babel-load-in-session'."
(interactive)
(org-babel-when-in-src-block
(org-babel-load-in-session current-prefix-arg)))
(add-hook 'org-metaup-hook 'org-babel-load-in-session-maybe)
;;;###autoload
(defun org-babel-pop-to-session-maybe ()
"Conditionally pop to a session.
Detect if this is context for an org-babel src-block and if so
then run `org-babel-switch-to-session'."
(interactive)
(org-babel-when-in-src-block
(org-babel-switch-to-session current-prefix-arg)))
(add-hook 'org-metadown-hook 'org-babel-pop-to-session-maybe)
(defconst org-babel-common-header-args-w-values
'((cache . ((no yes)))
(cmdline . :any)
(colnames . ((nil no yes)))
(comments . ((no link yes org both noweb)))
(dir . :any)
(eval . ((yes no no-export strip-export never-export eval never
query)))
(exports . ((code results both none)))
(epilogue . :any)
(file . :any)
(file-desc . :any)
(file-ext . :any)
(file-mode . ((#o755 #o555 #o444 :any)))
(hlines . ((no yes)))
(mkdirp . ((yes no)))
(no-expand)
(noeval)
(noweb . ((yes no tangle strip-tangle no-export strip-export)))
(noweb-ref . :any)
(noweb-sep . :any)
(noweb-prefix . ((no yes)))
(output-dir . :any)
(padline . ((yes no)))
(post . :any)
(prologue . :any)
(results . ((file list vector table scalar verbatim)
(raw html latex org code pp drawer link graphics)
(replace silent none discard append prepend)
(output value)))
(rownames . ((no yes)))
(sep . :any)
(session . :any)
(shebang . :any)
(tangle . ((tangle yes no :any)))
(tangle-mode . ((#o755 #o555 #o444 :any)))
(var . :any)
(wrap . :any))
"Alist defining common header args and their allowed values.
Keys of the alist are header arg symbols.
Values of the alist are either a symbol `:any' or a list of allowed
values as symbols:
(header-name . :any)
(header-name . ((value1 value2 value3 ...))
(header-name . ((value1 value2 value3 ... :any))
When Org considers header-arg property inheritance, the innermost
value from the list is considered.
Symbol `:any' in the value list implies that any value is allowed.
Yet the explicitly listed values from the list will be offered as
completion candidates.
FIXME: This is currently just supported for `results' and `exports'.
Values in the alist can also be a list of lists. The inner lists
define exclusive groups of values that can be set at the same time for
a given header argument.
(results . ((file list ...)
(raw html ...))
The above example allows multi-component header arguments like
#+begin_src bash :results file raw
<:results will combine the two values \"file raw\".>
#+begin_src bash :results file list
<:results will only use the last value \"list\".>
#+property: header-args :results file html
...
#+begin_src bash :results list
<:results will inherit with partial override \"list html\".>
See info node `(org)Results of evaluation' for more details.")
(defconst org-babel-header-arg-names
(mapcar #'car org-babel-common-header-args-w-values)
"Common header arguments used by org-babel.
Note that individual languages may define their own language
specific header arguments as well.")
(defconst org-babel-safe-header-args
'(:cache :colnames :comments :exports :epilogue :hlines :noeval
:noweb :noweb-ref :noweb-sep :noweb-prefix :padline
:prologue :rownames :sep :session :tangle :wrap
(:eval . ("never" "query"))
(:results . (lambda (str) (not (string-match "file" str)))))
"A list of safe header arguments for babel source blocks.
The list can have entries of the following forms:
- :ARG -> :ARG is always a safe header arg
- (:ARG . (VAL1 VAL2 ...)) -> :ARG is safe as a header arg if it is
`equal' to one of the VALs.
- (:ARG . FN) -> :ARG is safe as a header arg if the function FN
returns non-nil. FN is passed one
argument, the value of the header arg
(as a string).")
(defmacro org-babel-header-args-safe-fn (safe-list)
"Return a function that determines whether a list of header args are safe.
Intended usage is:
\(put \\='org-babel-default-header-args \\='safe-local-variable
(org-babel-header-args-safe-p org-babel-safe-header-args)
This allows org-babel languages to extend the list of safe values for
their `org-babel-default-header-args:foo' variable.
For the format of SAFE-LIST, see `org-babel-safe-header-args'."
`(lambda (value)
(and (listp value)
(cl-every
(lambda (pair)
(and (consp pair)
(org-babel-one-header-arg-safe-p pair ,safe-list)))
value))))
(defvar org-babel-default-header-args
'((:session . "none") (:results . "replace") (:exports . "code")
(:cache . "no") (:noweb . "no") (:hlines . "no") (:tangle . "no"))
"Default arguments to use when evaluating a source block.
This is a list in which each element is an alist. Each key
corresponds to a header argument, and each value to that header's
value. The value can either be a string or a closure that
evaluates to a string.
A closure is evaluated when the source block is being
evaluated (e.g. during execution or export), with point at the
source block. It is not possible to use an arbitrary function
symbol (e.g. `some-func'), since org uses lexical binding. To
achieve the same functionality, call the function within a
closure (e.g. (lambda () (some-func))).
To understand how closures can be used as default header
arguments, imagine you'd like to set the file name output of a
latex source block to a sha1 of its contents. We could achieve
this with:
(defun org-src-sha ()
(let ((elem (org-element-at-point)))
(concat (sha1 (org-element-property :value elem)) \".svg\")))
(setq org-babel-default-header-args:latex
`((:results . \"file link replace\")
(:file . (lambda () (org-src-sha)))))
Because the closure is evaluated with point at the source block,
the call to `org-element-at-point' above will always retrieve
information about the current source block.
Some header arguments can be provided multiple times for a source
block. An example of such a header argument is :var. This
functionality is also supported for default header arguments by
providing the header argument multiple times in the alist. For
example:
((:var . \"foo=\\\"bar\\\"\")
(:var . \"bar=\\\"foo\\\"\"))")
(put 'org-babel-default-header-args 'safe-local-variable
(org-babel-header-args-safe-fn org-babel-safe-header-args))
(defvar org-babel-default-inline-header-args
'((:session . "none") (:results . "replace")
(:exports . "results") (:hlines . "yes"))
"Default arguments to use when evaluating an inline source block.")
(put 'org-babel-default-inline-header-args 'safe-local-variable
(org-babel-header-args-safe-fn org-babel-safe-header-args))
(defconst org-babel-name-regexp
(format "^[ \t]*#\\+%s:[ \t]*"
;; FIXME: TBLNAME is for backward compatibility.
(regexp-opt '("NAME" "TBLNAME")))
"Regexp matching a NAME keyword.")
(defconst org-babel-result-regexp
(rx (seq bol
(zero-or-more (any "\t "))
"#+results"
(opt "["
;; Time stamp part.
(opt "("
(= 4 digit) (= 2 "-" (= 2 digit))
" "
(= 2 digit) (= 2 ":" (= 2 digit))
") ")
;; SHA1 hash.
(group (one-or-more hex-digit))
"]")
":"
(zero-or-more (any "\t "))))
"Regular expression used to match result lines.
If the results are associated with a hash key then the hash will
be saved in match group 1.")
(defconst org-babel-result-w-name-regexp
(concat org-babel-result-regexp "\\(?9:[^ \t\n\r\v\f]+\\)")
"Regexp matching a RESULTS keyword with a name.
Name is saved in match group 9.")
(defvar org-babel-min-lines-for-block-output 10
"The minimum number of lines for block output.
If number of lines of output is equal to or exceeds this
value, the output is placed in a #+begin_example...#+end_example
block. Otherwise the output is marked as literal by inserting
colons at the starts of the lines. This variable only takes
effect if the :results output option is in effect.")
(defvar org-babel-noweb-error-all-langs nil
"Raise errors when noweb references don't resolve.
Also see `org-babel-noweb-error-langs' to control noweb errors on
a language by language bases.")
(defvar org-babel-noweb-error-langs nil
"Languages for which Babel will raise literate programming errors.
List of languages for which errors should be raised when the
source code block satisfying a noweb reference in this language
can not be resolved. Also see `org-babel-noweb-error-all-langs'
to raise errors for all languages.")
(defvar org-babel-hash-show 4
"Number of initial characters to show of a hidden results hash.")
(defvar org-babel-after-execute-hook nil
"Hook for functions to be called after `org-babel-execute-src-block'.")
(defun org-babel-named-src-block-regexp-for-name (&optional name)
"Generate a regexp used to match a source block named NAME.
If NAME is nil, match any name. Matched name is then put in
match group 9. Other match groups are defined in
`org-babel-src-block-regexp'."
(concat org-babel-src-name-regexp
(concat (if name (regexp-quote name) "\\(?9:.*?\\)") "[ \t]*" )
"\\(?:\n[ \t]*#\\+\\S-+:.*\\)*?"
"\n"
(substring org-babel-src-block-regexp 1)))
(defun org-babel-named-data-regexp-for-name (name)
"Generate a regexp used to match data named NAME."
(concat org-babel-name-regexp (regexp-quote name) "[ \t]*$"))
(defun org-babel--normalize-body (datum)
"Normalize body for element or object DATUM.
DATUM is a source block element or an inline source block object.
Remove final newline character and spurious indentation."
(let* ((value (org-element-property :value datum))
(body (if (string-suffix-p "\n" value)
(substring value 0 -1)
value)))
(cond ((org-element-type-p datum 'inline-src-block)
;; Newline characters and indentation in an inline
;; src-block are not meaningful, since they could come from
;; some paragraph filling. Treat them as a white space.
(replace-regexp-in-string "\n[ \t]*" " " body))
((org-src-preserve-indentation-p datum) body)
(t (org-remove-indentation body)))))
;;; functions
(defvar org-babel-current-src-block-location nil
"Marker pointing to the source block currently being executed.
This may also point to a call line or an inline code block. If
multiple blocks are being executed (e.g., in chained execution
through use of the :var header argument) this marker points to
the outer-most code block.")
(defun org-babel-eval-headers (headers)
"Compute header list set with HEADERS.
Evaluate all header arguments set to functions prior to returning
the list of header arguments."
(let ((lst nil))
(dolist (elem headers)
(if (and (cdr elem) (functionp (cdr elem)))
(push `(,(car elem) . ,(funcall (cdr elem))) lst)
(push elem lst)))
(reverse lst)))
(defun org-babel-get-src-block-info (&optional no-eval datum)
"Extract information from a source block or inline source block.
When optional argument NO-EVAL is non-nil, Babel does not resolve
remote variable references; a process which could likely result
in the execution of other code blocks, and do not evaluate Lisp
values in parameters.
By default, consider the block at point. However, when optional
argument DATUM is provided, extract information from that parsed
object instead.
Return nil if point is not on a source block (blank lines after a
source block are considered a part of that source block).
Otherwise, return a list with the following pattern:
(language body arguments switches name start coderef)"
(let* ((datum (or datum (org-element-context)))
(type (org-element-type datum))
(inline (eq type 'inline-src-block)))
(when (memq type '(inline-src-block src-block))
(let* ((lang (org-element-property :language datum))
(lang-headers (intern
(concat "org-babel-default-header-args:" lang)))
(name (org-element-property :name datum))
(info
(list
lang
(org-babel--normalize-body datum)
(apply #'org-babel-merge-params
;; Use `copy-tree' to avoid creating shared structure
;; with the `org-babel-default-header-args-*' variables:
;; modifications by `org-babel-generate-file-param'
;; below would modify the shared structure, thereby
;; modifying the variables.
(copy-tree
(if inline org-babel-default-inline-header-args
org-babel-default-header-args)
t)
(and (boundp lang-headers)
(copy-tree (eval lang-headers t) t))
(append
;; If DATUM is provided, make sure we get node
;; properties applicable to its location within
;; the document.
(org-with-point-at (org-element-begin datum)
(org-babel-params-from-properties lang no-eval))
(mapcar (lambda (h)
(org-babel-parse-header-arguments h no-eval))
(cons (org-element-property :parameters datum)
(org-element-property :header datum)))))
(or (org-element-property :switches datum) "")
name
(org-element-property (if inline :begin :post-affiliated)
datum)
(and (not inline) (org-src-coderef-format datum)))))
(unless no-eval
(setf (nth 2 info) (org-babel-process-params (nth 2 info))))
(setf (nth 2 info) (org-babel-generate-file-param name (nth 2 info)))
info))))
(defun org-babel--expand-body (info)
"Expand noweb references in src block and remove any coderefs.
The src block is defined by its INFO, as returned by
`org-babel-get-src-block-info'."
(let ((coderef (nth 6 info))
(expand
(if (org-babel-noweb-p (nth 2 info) :eval)
(org-babel-expand-noweb-references info)
(nth 1 info))))
(if (not coderef) expand
(replace-regexp-in-string
(org-src-coderef-regexp coderef) "" expand nil nil 1))))
(defun org-babel--file-desc (params result)
"Retrieve description for file link result of evaluation.
PARAMS is header argument values. RESULT is the file link as returned
by the code block.
When `:file-desc' header argument is provided use its value or
duplicate RESULT in the description.
When `:file-desc' is missing, return nil."
(pcase (assq :file-desc params)
(`nil nil)
(`(:file-desc) result)
(`(:file-desc . ,(and (pred stringp) val)) val)))
(defvar *this*)
;; Dynamically bound in `org-babel-execute-src-block'
;; and `org-babel-read'
(defun org-babel-session-buffer (&optional info)
"Return buffer name for session associated with current code block.
Return nil when no such live buffer with process exists.
When INFO is non-nil, it should be a list returned by
`org-babel-get-src-block-info'.
This function uses org-babel-session-buffer:<lang> function to
retrieve backend-specific session buffer name."
(declare-function org-babel-comint-buffer-livep "ob-comint" (buffer))
(when-let* ((info (or info (org-babel-get-src-block-info 'no-eval)))
(lang (nth 0 info))
(session (cdr (assq :session (nth 2 info))))
(cmd (intern (concat "org-babel-session-buffer:" lang)))
(buffer-name
(if (fboundp cmd)
(funcall cmd session info)
;; Use session name as buffer name by default.
session)))
(require 'ob-comint)
(when (org-babel-comint-buffer-livep buffer-name)
buffer-name)))
;;;###autoload
(defun org-babel-execute-src-block (&optional arg info params executor-type)
"Execute the current source code block and return the result.
Insert the results of execution into the buffer. Source code
execution and the collection and formatting of results can be
controlled through a variety of header arguments.
With prefix argument ARG, force re-execution even if an existing
result cached in the buffer would otherwise have been returned.
Optionally supply a value for INFO in the form returned by
`org-babel-get-src-block-info'.
Optionally supply a value for PARAMS which will be merged with
the header arguments specified at the front of the source code
block.
EXECUTOR-TYPE is the type of the org element responsible for the
execution of the source block. If not provided then informed
guess will be made."
(interactive)
(let* ((org-babel-current-src-block-location
(or org-babel-current-src-block-location
(nth 5 info)
(org-babel-where-is-src-block-head)))
(info (if info (copy-tree info) (org-babel-get-src-block-info)))
(executor-type
(or executor-type
;; If `executor-type' is unset, then we will make an
;; informed guess.
(pcase (and
;; When executing virtual src block, no location
;; is known.
org-babel-current-src-block-location
(char-after org-babel-current-src-block-location))
(?s 'inline-src-block)
(?c 'inline-babel-call)
(?# (pcase (char-after (+ 2 org-babel-current-src-block-location))
(?b 'src-block)
(?c 'call-block)
(_ 'unknown)))
(_ 'unknown)))))
;; Merge PARAMS with INFO before considering source block
;; evaluation since both could disagree.
(cl-callf org-babel-merge-params (nth 2 info) params)
(when (org-babel-check-evaluate info)
(cl-callf org-babel-process-params (nth 2 info))
(let* ((params (nth 2 info))
(cache (let ((c (cdr (assq :cache params))))
(and (not arg) c (string= "yes" c))))
(new-hash (and cache (org-babel-sha1-hash info :eval)))
(old-hash (and cache (org-babel-current-result-hash)))
(current-cache (and new-hash (equal new-hash old-hash))))
(cond
(current-cache
(save-excursion ;Return cached result.
(goto-char (org-babel-where-is-src-block-result nil info))
(forward-line)
(skip-chars-forward " \t")
(let ((result (org-babel-read-result)))
(unless noninteractive
(message (format "Cached: %s"
(replace-regexp-in-string "%" "%%" (format "%S" result)))))
result)))
((org-babel-confirm-evaluate info)
(let* ((lang (nth 0 info))
(result-params (cdr (assq :result-params params)))
(body (org-babel--expand-body info))
(dir (cdr (assq :dir params)))
(mkdirp (cdr (assq :mkdirp params)))
(default-directory
(cond
((not dir) default-directory)
((when-let* ((session (org-babel-session-buffer info)))
(buffer-local-value 'default-directory (get-buffer session))))
((member mkdirp '("no" "nil" nil))
(file-name-as-directory (expand-file-name dir)))
(t
(let ((d (file-name-as-directory (expand-file-name dir))))
(make-directory d 'parents)
d))))
(cmd (intern (concat "org-babel-execute:" lang)))
result exec-start-time)
(unless (fboundp cmd)
(error "No org-babel-execute function for %s!" lang))
(unless noninteractive
(message "Executing %s %s %s..."
(capitalize lang)
(pcase executor-type
('src-block "code block")
('inline-src-block "inline code block")
('babel-call "call")
('inline-babel-call "inline call")
(e (symbol-name e)))
(let ((name (nth 4 info)))
(if name
(format "(%s)" name)
(format "at position %S" (nth 5 info))))))
(setq exec-start-time (current-time)
result
(let ((r
;; Code block may move point in the buffer.
;; Make sure that the point remains on the
;; code block.
(save-excursion (funcall cmd body params))))
(if (and (eq (cdr (assq :result-type params)) 'value)
(or (member "vector" result-params)
(member "table" result-params))
(not (listp r)))
(list (list r))
r)))
(let ((file (and (member "file" result-params)
(cdr (assq :file params)))))
;; If non-empty result and :file then write to :file.
(when file
;; If `:results' are special types like `link' or
;; `graphics', don't write result to `:file'. Only
;; insert a link to `:file'.
(when (and result
(not (or (member "link" result-params)
(member "graphics" result-params))))
(with-temp-file file
(insert (org-babel-format-result
result
(cdr (assq :sep params)))))
;; Set file permissions if header argument
;; `:file-mode' is provided.
(when (assq :file-mode params)
(set-file-modes file (cdr (assq :file-mode params)))))
(setq result file))
;; Possibly perform post process provided its
;; appropriate. Dynamically bind "*this*" to the
;; actual results of the block.
(let ((post (cdr (assq :post params))))
(when post
(let ((*this* (if (not file) result
(org-babel-result-to-file
file
(org-babel--file-desc params result)
'attachment))))
(setq result (org-babel-ref-resolve post))
(when file
(setq result-params (remove "file" result-params))))))
(unless (member "none" result-params)
(org-babel-insert-result
result result-params info
;; append/prepend cannot handle hash as we accumulate
;; multiple outputs together.
(when (member "replace" result-params) new-hash)
lang
(time-subtract (current-time) exec-start-time))))
(run-hooks 'org-babel-after-execute-hook)
result)))))))
(defun org-babel-expand-body:generic (body params &optional var-lines)
"Expand BODY with PARAMS.
Expand a block of code with org-babel according to its header
arguments. This generic implementation of body expansion is
called for languages which have not defined their own specific
org-babel-expand-body:lang function.
VAR-LINES is a list of lines that define variable environment. These
lines will be added after `:prologue' parameter and before BODY."
(let ((pro (cdr (assq :prologue params)))
(epi (cdr (assq :epilogue params))))
(mapconcat #'identity
(append (when pro (list pro))
var-lines
(list body)
(when epi (list epi)))
"\n")))
;;;###autoload
(defun org-babel-expand-src-block (&optional _arg info params)
"Expand the current source code block or block specified by INFO.
INFO is the output of `org-babel-get-src-block-info'.
PARAMS defines inherited header arguments.
Expand according to the source code block's header
arguments and pop open the results in a preview buffer."
(interactive)
(let* ((info (or info (org-babel-get-src-block-info)))
(lang (nth 0 info))
(params (setf (nth 2 info)