Update to Org 9.7.3
This commit is contained in:
parent
e1cc2d1f61
commit
5a125fb5a9
123 changed files with 21824 additions and 12969 deletions
2410
doc/misc/org.org
2410
doc/misc/org.org
File diff suppressed because it is too large
Load diff
1697
etc/ORG-NEWS
1697
etc/ORG-NEWS
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
% Reference Card for Org Mode
|
||||
\def\orgversionnumber{9.6.15}
|
||||
\def\versionyear{2023} % latest update
|
||||
\def\orgversionnumber{9.7.3}
|
||||
\def\versionyear{2024} % latest update
|
||||
\input emacsver.tex
|
||||
|
||||
%**start of header
|
||||
|
@ -11,10 +11,14 @@
|
|||
% Specify how many you want here.
|
||||
\columnsperpage=3
|
||||
|
||||
% Set letterpaper to 0 for A4 paper, 1 for letter (US) paper. Useful
|
||||
% only when columnsperpage is 2 or 3.
|
||||
\letterpaper=1
|
||||
|
||||
% PDF output layout. 0 for A4, 1 for letter (US), a `l' is added for
|
||||
% a landscape layout.
|
||||
\input pdflayout.sty
|
||||
\pdflayout=(0l)
|
||||
\pdflayout=(1l)
|
||||
|
||||
% Nothing else needs to be changed below this line.
|
||||
% Copyright (C) 1987, 1993, 1996--1997, 2001--2024 Free Software
|
||||
|
@ -113,17 +117,14 @@
|
|||
\footline{\hss\folio}
|
||||
\def\makefootline{\baselineskip10pt\hsize6.5in\line{\the\footline}}
|
||||
\else %2 or 3 columns uses prereduced size
|
||||
\hsize 3.2in
|
||||
\if 1\the\letterpaper
|
||||
\hsize 3.2in
|
||||
\vsize 7.95in
|
||||
\hoffset -.75in
|
||||
\voffset -.745in
|
||||
\else
|
||||
\hsize 3.2in
|
||||
\vsize 7.65in
|
||||
\hoffset -.25in
|
||||
\voffset -.745in
|
||||
\fi
|
||||
\hoffset -.75in
|
||||
\voffset -.745in
|
||||
\font\titlefont=cmbx10 \scaledmag2
|
||||
\font\headingfont=cmbx10 \scaledmag1
|
||||
\font\smallfont=cmr6
|
||||
|
@ -280,7 +281,7 @@
|
|||
%**end of header
|
||||
|
||||
|
||||
\title{Org-Mode Reference Card (1/2)}
|
||||
\title{Org-Mode Reference Card}
|
||||
|
||||
\centerline{(for version \orgversionnumber)}
|
||||
|
||||
|
@ -482,7 +483,7 @@ \section{Completion and Template Insertion}
|
|||
|
||||
|
||||
\newcolumn
|
||||
\title{Org-Mode Reference Card (2/2)}
|
||||
\title{Org-Mode Reference Card}
|
||||
|
||||
\centerline{(for version \orgversionnumber)}
|
||||
|
||||
|
|
|
@ -93,44 +93,45 @@ parameter may be used, like rdmd --chatty"
|
|||
is currently being evaluated.")
|
||||
|
||||
(defun org-babel-execute:cpp (body params)
|
||||
"Execute BODY according to PARAMS.
|
||||
"Execute BODY according to its header arguments PARAMS.
|
||||
This function calls `org-babel-execute:C++'."
|
||||
(org-babel-execute:C++ body params))
|
||||
|
||||
(defun org-babel-expand-body:cpp (body params)
|
||||
"Expand a block of C++ code with org-babel according to its header arguments."
|
||||
"Expand C++ BODY with org-babel according to its header arguments PARAMS."
|
||||
(org-babel-expand-body:C++ body params))
|
||||
|
||||
(defun org-babel-execute:C++ (body params)
|
||||
"Execute a block of C++ code with org-babel.
|
||||
"Execute C++ BODY with org-babel according to its header arguments PARAMS.
|
||||
This function is called by `org-babel-execute-src-block'."
|
||||
(let ((org-babel-c-variant 'cpp)) (org-babel-C-execute body params)))
|
||||
|
||||
(defun org-babel-expand-body:C++ (body params)
|
||||
"Expand a block of C++ code with org-babel according to its header arguments."
|
||||
"Expand C++ BODY with org-babel according to its header arguments PARAMS."
|
||||
(let ((org-babel-c-variant 'cpp)) (org-babel-C-expand-C++ body params)))
|
||||
|
||||
(defun org-babel-execute:D (body params)
|
||||
"Execute a block of D code with org-babel.
|
||||
"Execute D BODY with org-babel according to its header arguments PARAMS.
|
||||
This function is called by `org-babel-execute-src-block'."
|
||||
(let ((org-babel-c-variant 'd)) (org-babel-C-execute body params)))
|
||||
|
||||
(defun org-babel-expand-body:D (body params)
|
||||
"Expand a block of D code with org-babel according to its header arguments."
|
||||
"Expand D BODY with org-babel according to its header arguments PARAMS."
|
||||
(let ((org-babel-c-variant 'd)) (org-babel-C-expand-D body params)))
|
||||
|
||||
(defun org-babel-execute:C (body params)
|
||||
"Execute a block of C code with org-babel.
|
||||
"Execute a C BODY according to its header arguments PARAMS.
|
||||
This function is called by `org-babel-execute-src-block'."
|
||||
(let ((org-babel-c-variant 'c)) (org-babel-C-execute body params)))
|
||||
|
||||
(defun org-babel-expand-body:C (body params)
|
||||
"Expand a block of C code with org-babel according to its header arguments."
|
||||
"Expand C BODY according to its header arguments PARAMS."
|
||||
(let ((org-babel-c-variant 'c)) (org-babel-C-expand-C body params)))
|
||||
|
||||
(defun org-babel-C-execute (body params)
|
||||
"This function should only be called by `org-babel-execute:C'
|
||||
or `org-babel-execute:C++' or `org-babel-execute:D'."
|
||||
"Execute C/C++/D BODY according to its header arguments PARAMS.
|
||||
This function should only be called by `org-babel-execute:C' or
|
||||
`org-babel-execute:C++' or `org-babel-execute:D'."
|
||||
(let* ((tmp-src-file (org-babel-temp-file
|
||||
"C-src-"
|
||||
(pcase org-babel-c-variant
|
||||
|
@ -196,11 +197,11 @@ or `org-babel-execute:C++' or `org-babel-execute:D'."
|
|||
)))
|
||||
|
||||
(defun org-babel-C-expand-C++ (body params)
|
||||
"Expand a block of C/C++ code with org-babel according to its header arguments."
|
||||
"Expand C/C++ BODY with according to its header arguments PARAMS."
|
||||
(org-babel-C-expand-C body params))
|
||||
|
||||
(defun org-babel-C-expand-C (body params)
|
||||
"Expand a block of C/C++ code with org-babel according to its header arguments."
|
||||
"Expand C/C++ BODY according to its header arguments PARAMS."
|
||||
(let ((vars (org-babel--get-vars params))
|
||||
(colnames (cdr (assq :colname-names params)))
|
||||
(main-p (not (string= (cdr (assq :main params)) "no")))
|
||||
|
@ -212,7 +213,9 @@ or `org-babel-execute:C++' or `org-babel-execute:D'."
|
|||
nil))
|
||||
(namespaces (org-babel-read
|
||||
(cdr (assq :namespaces params))
|
||||
nil)))
|
||||
nil))
|
||||
(prologue (cdr (assq :prologue params)))
|
||||
(epilogue (cdr (assq :epilogue params))))
|
||||
(when (stringp includes)
|
||||
(setq includes (split-string includes)))
|
||||
(when (stringp namespaces)
|
||||
|
@ -226,6 +229,11 @@ or `org-babel-execute:C++' or `org-babel-execute:D'."
|
|||
(nconc result (list (concat y " " x)))
|
||||
(setq y nil)))
|
||||
(setq defines (cdr result))))
|
||||
(setq body
|
||||
(concat
|
||||
(and prologue (concat prologue "\n"))
|
||||
body
|
||||
(and epilogue (concat "\n" epilogue "\n"))))
|
||||
(mapconcat 'identity
|
||||
(list
|
||||
;; includes
|
||||
|
@ -269,7 +277,7 @@ or `org-babel-execute:C++' or `org-babel-execute:D'."
|
|||
body) "\n") "\n")))
|
||||
|
||||
(defun org-babel-C-expand-D (body params)
|
||||
"Expand a block of D code with org-babel according to its header arguments."
|
||||
"Expand D BODY according to its header arguments PARAMS."
|
||||
(let ((vars (org-babel--get-vars params))
|
||||
(colnames (cdr (assq :colname-names params)))
|
||||
(main-p (not (string= (cdr (assq :main params)) "no")))
|
||||
|
@ -313,13 +321,15 @@ or `org-babel-execute:C++' or `org-babel-execute:D'."
|
|||
(format "int main() {\n%s\nreturn 0;\n}\n" body)))
|
||||
|
||||
(defun org-babel-prep-session:C (_session _params)
|
||||
"This function does nothing as C is a compiled language with no
|
||||
support for sessions."
|
||||
"Throw and error that sessions are not supported.
|
||||
This function does nothing as C is a compiled language with no support
|
||||
for sessions."
|
||||
(error "C is a compiled language -- no support for sessions"))
|
||||
|
||||
(defun org-babel-load-session:C (_session _body _params)
|
||||
"This function does nothing as C is a compiled language with no
|
||||
support for sessions."
|
||||
"Throw and error that sessions are not supported.
|
||||
This function does nothing as C is a compiled language with no support
|
||||
for sessions."
|
||||
(error "C is a compiled language -- no support for sessions"))
|
||||
|
||||
;; helper functions
|
||||
|
@ -379,10 +389,11 @@ FORMAT can be either a format string or a function which is called with VAL."
|
|||
type))))
|
||||
|
||||
(defun org-babel-C-val-to-base-type (val)
|
||||
"Determine the base type of VAL which may be
|
||||
`integerp' if all base values are integers
|
||||
`floatp' if all base values are either floating points or integers
|
||||
`stringp' otherwise."
|
||||
"Determine the base type of VAL.
|
||||
The type is:
|
||||
- `integerp' if all base values are integers;
|
||||
- `floatp' if all base values are either floating points or integers;
|
||||
- `stringp' otherwise."
|
||||
(cond
|
||||
((integerp val) 'integerp)
|
||||
((floatp val) 'floatp)
|
||||
|
@ -401,7 +412,7 @@ FORMAT can be either a format string or a function which is called with VAL."
|
|||
(t 'stringp)))
|
||||
|
||||
(defun org-babel-C-var-to-C (pair)
|
||||
"Convert an elisp val into a string of C code specifying a var of the same value."
|
||||
"Convert PAIR of (var . val) C variable assignment."
|
||||
;; TODO list support
|
||||
(let ((var (car pair))
|
||||
(val (cdr pair)))
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
(colormodel . :any)
|
||||
(useDingbats . :any)
|
||||
(horizontal . :any)
|
||||
(async . ((yes no)))
|
||||
(results . ((file list vector table scalar verbatim)
|
||||
(raw html latex org code pp drawer)
|
||||
(replace silent none append prepend)
|
||||
|
@ -91,15 +92,6 @@ this variable.")
|
|||
:version "24.1"
|
||||
:type 'string)
|
||||
|
||||
(defvar ess-current-process-name) ; dynamically scoped
|
||||
(defvar ess-local-process-name) ; dynamically scoped
|
||||
(defun org-babel-edit-prep:R (info)
|
||||
(let ((session (cdr (assq :session (nth 2 info)))))
|
||||
(when (and session
|
||||
(string-prefix-p "*" session)
|
||||
(string-suffix-p "*" session))
|
||||
(org-babel-R-initiate-session session nil))))
|
||||
|
||||
;; The usage of utils::read.table() ensures that the command
|
||||
;; read.table() can be found even in circumstances when the utils
|
||||
;; package is not in the search path from R.
|
||||
|
@ -156,7 +148,7 @@ This function is used when the table does not contain a header.")
|
|||
"\n"))
|
||||
|
||||
(defun org-babel-execute:R (body params)
|
||||
"Execute a block of R code.
|
||||
"Execute a block of R code BODY according to PARAMS.
|
||||
This function is called by `org-babel-execute-src-block'."
|
||||
(save-excursion
|
||||
(let* ((result-params (cdr (assq :result-params params)))
|
||||
|
@ -215,7 +207,8 @@ This function is called by `org-babel-execute-src-block'."
|
|||
;; helper functions
|
||||
|
||||
(defun org-babel-variable-assignments:R (params)
|
||||
"Return list of R statements assigning the block's variables."
|
||||
"Return list of R statements assigning the block's variables.
|
||||
Retrieve variables from PARAMS."
|
||||
(let ((vars (org-babel--get-vars params)))
|
||||
(mapcar
|
||||
(lambda (pair)
|
||||
|
@ -261,42 +254,44 @@ This function is called by `org-babel-execute-src-block'."
|
|||
(t (format "%s <- %S" name (prin1-to-string value))))))
|
||||
|
||||
|
||||
(defvar ess-current-process-name) ; dynamically scoped
|
||||
(defvar ess-local-process-name) ; dynamically scoped
|
||||
(defvar ess-ask-for-ess-directory) ; dynamically scoped
|
||||
(defvar ess-gen-proc-buffer-name-function) ; defined in ess-inf.el
|
||||
(defun org-babel-R-initiate-session (session params)
|
||||
"If there is not a current R process then create one."
|
||||
"Create or return the current R SESSION buffer.
|
||||
Use PARAMS to set default directory when creating a new session."
|
||||
(unless (string= session "none")
|
||||
(let ((session (or session "*R*"))
|
||||
(ess-ask-for-ess-directory
|
||||
(and (boundp 'ess-ask-for-ess-directory)
|
||||
ess-ask-for-ess-directory
|
||||
(not (cdr (assq :dir params))))))
|
||||
(let* ((session (or session "*R*"))
|
||||
(ess-ask-for-ess-directory
|
||||
(and (boundp 'ess-ask-for-ess-directory)
|
||||
ess-ask-for-ess-directory
|
||||
(not (cdr (assq :dir params)))))
|
||||
;; Make ESS name the process buffer as SESSION.
|
||||
(ess-gen-proc-buffer-name-function
|
||||
(lambda (_) session)))
|
||||
(if (org-babel-comint-buffer-livep session)
|
||||
session
|
||||
(save-window-excursion
|
||||
(when (get-buffer session)
|
||||
;; Session buffer exists, but with dead process
|
||||
(set-buffer session))
|
||||
(require 'ess-r-mode)
|
||||
(org-require-package 'ess-r-mode "ESS")
|
||||
(set-buffer (run-ess-r))
|
||||
(let ((R-proc (get-process (or ess-local-process-name
|
||||
ess-current-process-name))))
|
||||
(while (process-get R-proc 'callbacks)
|
||||
(ess-wait-for-process R-proc)))
|
||||
(rename-buffer
|
||||
(if (bufferp session)
|
||||
(buffer-name session)
|
||||
(if (stringp session)
|
||||
session
|
||||
(buffer-name))))
|
||||
(current-buffer))))))
|
||||
|
||||
(defun org-babel-R-associate-session (session)
|
||||
"Associate R code buffer with an R session.
|
||||
Make SESSION be the inferior ESS process associated with the
|
||||
current code buffer."
|
||||
(setq ess-local-process-name
|
||||
(process-name (get-buffer-process session)))
|
||||
(ess-make-buffer-current))
|
||||
(when-let ((process (get-buffer-process session)))
|
||||
(setq ess-local-process-name (process-name process))
|
||||
(ess-make-buffer-current))
|
||||
(setq-local ess-gen-proc-buffer-name-function (lambda (_) session)))
|
||||
|
||||
(defvar org-babel-R-graphics-devices
|
||||
'((:bmp "bmp" "filename")
|
||||
|
@ -520,7 +515,7 @@ by `org-babel-comint-async-filter'."
|
|||
(ess-eval-buffer nil)))
|
||||
tmp-file))
|
||||
(output
|
||||
(let ((uuid (md5 (number-to-string (random 100000000))))
|
||||
(let ((uuid (org-id-uuid))
|
||||
(ess-local-process-name
|
||||
(process-name (get-buffer-process session)))
|
||||
(ess-eval-visibly-p nil))
|
||||
|
|
|
@ -48,12 +48,18 @@
|
|||
(defvar org-babel-awk-command "awk"
|
||||
"Name of the awk executable command.")
|
||||
|
||||
(defun org-babel-expand-body:awk (body _params)
|
||||
(defun org-babel-expand-body:awk (body params)
|
||||
"Expand BODY according to PARAMS, return the expanded body."
|
||||
body)
|
||||
(let ((prologue (cdr (assq :prologue params)))
|
||||
(epilogue (cdr (assq :epilogue params))))
|
||||
(concat
|
||||
(and prologue (concat prologue "\n"))
|
||||
body
|
||||
(and epilogue (concat "\n" epilogue "\n")))))
|
||||
|
||||
(defun org-babel-execute:awk (body params)
|
||||
"Execute a block of Awk code with org-babel.
|
||||
"Execute a block of Awk code BODY with org-babel.
|
||||
PARAMS is a plist of src block parameters .
|
||||
This function is called by `org-babel-execute-src-block'."
|
||||
(message "Executing Awk source code block")
|
||||
(let* ((result-params (cdr (assq :result-params params)))
|
||||
|
@ -100,7 +106,9 @@ This function is called by `org-babel-execute-src-block'."
|
|||
(cdr (assq :rowname-names params)) (cdr (assq :rownames params))))))
|
||||
|
||||
(defun org-babel-awk-var-to-awk (var &optional sep)
|
||||
"Return a printed value of VAR suitable for parsing with awk."
|
||||
"Return a printed value of VAR suitable for parsing with awk.
|
||||
SEP, when non-nil is a separator used when converting list values to awk
|
||||
table."
|
||||
(let ((echo-var (lambda (v) (if (stringp v) v (format "%S" v)))))
|
||||
(cond
|
||||
((and (listp var) (listp (car var)))
|
||||
|
|
|
@ -44,13 +44,19 @@
|
|||
(defvar org-babel-default-header-args:calc nil
|
||||
"Default arguments for evaluating a calc source block.")
|
||||
|
||||
(defun org-babel-expand-body:calc (body _params)
|
||||
"Expand BODY according to PARAMS, return the expanded body." body)
|
||||
(defun org-babel-expand-body:calc (body params)
|
||||
"Expand BODY according to PARAMS, return the expanded body."
|
||||
(let ((prologue (cdr (assq :prologue params)))
|
||||
(epilogue (cdr (assq :epilogue params))))
|
||||
(concat
|
||||
(and prologue (concat prologue "\n"))
|
||||
body
|
||||
(and epilogue (concat "\n" epilogue "\n")))))
|
||||
|
||||
(defvar org--var-syms) ; Dynamically scoped from org-babel-execute:calc
|
||||
|
||||
(defun org-babel-execute:calc (body params)
|
||||
"Execute a block of calc code with Babel."
|
||||
"Execute BODY of calc code with Babel using PARAMS."
|
||||
(unless (get-buffer "*Calculator*")
|
||||
(save-window-excursion (calc) (calc-quit)))
|
||||
(let* ((vars (org-babel--get-vars params))
|
||||
|
@ -58,7 +64,23 @@
|
|||
(var-names (mapcar #'symbol-name org--var-syms)))
|
||||
(mapc
|
||||
(lambda (pair)
|
||||
(calc-push-list (list (cdr pair)))
|
||||
(let ((val (cdr pair)))
|
||||
(calc-push-list
|
||||
(list
|
||||
(cond
|
||||
;; For a vector, Calc follows the format (vec 1 2 3 ...) so
|
||||
;; a matrix becomes (vec (vec 1 2 3) (vec 4 5 6) ...). See
|
||||
;; the comments in "Arithmetic routines." section of
|
||||
;; calc.el.
|
||||
((listp val)
|
||||
(cons 'vec
|
||||
(if (null (cdr val))
|
||||
(car val)
|
||||
(mapcar (lambda (x) (if (listp x) (cons 'vec x) x))
|
||||
val))))
|
||||
((numberp val)
|
||||
(math-read-number (number-to-string val)))
|
||||
(t val)))))
|
||||
(calc-store-into (car pair)))
|
||||
vars)
|
||||
(mapc
|
||||
|
@ -99,6 +121,8 @@
|
|||
(calc-pop 1)))))
|
||||
|
||||
(defun org-babel-calc-maybe-resolve-var (el)
|
||||
"Resolve user variables in EL.
|
||||
EL is taken from the output of `math-read-exprs'."
|
||||
(if (consp el)
|
||||
(if (and (eq 'var (car el)) (member (cadr el) org--var-syms))
|
||||
(progn
|
||||
|
|
|
@ -25,20 +25,21 @@
|
|||
|
||||
;;; Commentary:
|
||||
|
||||
;; Support for evaluating Clojure code
|
||||
;; Support for evaluating Clojure / ClojureScript code.
|
||||
|
||||
;; Requirements:
|
||||
|
||||
;; - Clojure (at least 1.2.0)
|
||||
;; - clojure-mode
|
||||
;; - inf-clojure, Cider, SLIME, babashka or nbb
|
||||
;; - babashka, nbb, Clojure CLI tools, Cider, inf-clojure or SLIME
|
||||
|
||||
;; For clojure-mode, see https://github.com/clojure-emacs/clojure-mode
|
||||
;; For inf-clojure, see https://github.com/clojure-emacs/inf-clojure
|
||||
;; For Cider, see https://github.com/clojure-emacs/cider
|
||||
;; For SLIME, see https://slime.common-lisp.dev
|
||||
;; For babashka, see https://github.com/babashka/babashka
|
||||
;; For nbb, see https://github.com/babashka/nbb
|
||||
;; For Clojure CLI tools, see https://clojure.org/guides/deps_and_cli
|
||||
;; For Cider, see https://github.com/clojure-emacs/cider
|
||||
;; For inf-clojure, see https://github.com/clojure-emacs/inf-clojure
|
||||
;; For SLIME, see https://slime.common-lisp.dev
|
||||
|
||||
;; For SLIME, the best way to install its components is by following
|
||||
;; the directions as set out by Phil Hagelberg (Technomancy) on the
|
||||
|
@ -78,20 +79,33 @@
|
|||
|
||||
(defcustom org-babel-clojure-backend (cond
|
||||
((executable-find "bb") 'babashka)
|
||||
((executable-find "nbb") 'nbb)
|
||||
((executable-find "clojure") 'clojure-cli)
|
||||
((featurep 'cider) 'cider)
|
||||
((featurep 'inf-clojure) 'inf-clojure)
|
||||
((featurep 'slime) 'slime)
|
||||
(t nil))
|
||||
"Backend used to evaluate Clojure code blocks."
|
||||
:group 'org-babel
|
||||
:package-version '(Org . "9.6")
|
||||
:package-version '(Org . "9.7")
|
||||
:type '(choice
|
||||
(const :tag "inf-clojure" inf-clojure)
|
||||
(const :tag "cider" cider)
|
||||
(const :tag "slime" slime)
|
||||
(const :tag "babashka" babashka)
|
||||
(const :tag "clojure-cli" clojure-cli)
|
||||
(const :tag "cider" cider)
|
||||
(const :tag "inf-clojure" inf-clojure)
|
||||
(const :tag "slime" slime)
|
||||
(const :tag "Not configured yet" nil)))
|
||||
|
||||
(defcustom org-babel-clojurescript-backend
|
||||
(cond
|
||||
((or (executable-find "nbb") (executable-find "npx")) 'nbb)
|
||||
((featurep 'cider) 'cider)
|
||||
(t nil))
|
||||
"Backend used to evaluate ClojureScript code blocks."
|
||||
:group 'org-babel
|
||||
:package-version '(Org . "9.7")
|
||||
:type '(choice
|
||||
(const :tag "nbb" nbb)
|
||||
(const :tag "cider" cider)
|
||||
(const :tag "Not configured yet" nil)))
|
||||
|
||||
(defcustom org-babel-clojure-default-ns "user"
|
||||
|
@ -100,19 +114,29 @@
|
|||
:group 'org-babel)
|
||||
|
||||
(defcustom ob-clojure-babashka-command (executable-find "bb")
|
||||
"Path to the babashka executable."
|
||||
"Babashka command used by the Clojure `babashka' backend."
|
||||
:type '(choice file (const nil))
|
||||
:group 'org-babel
|
||||
:package-version '(Org . "9.6"))
|
||||
|
||||
(defcustom ob-clojure-nbb-command (executable-find "nbb")
|
||||
"Path to the nbb executable."
|
||||
:type '(choice file (const nil))
|
||||
(defcustom ob-clojure-nbb-command (or (executable-find "nbb")
|
||||
(when-let (npx (executable-find "npx"))
|
||||
(concat npx " nbb")))
|
||||
"Nbb command used by the ClojureScript `nbb' backend."
|
||||
:type '(choice string (const nil))
|
||||
:group 'org-babel
|
||||
:package-version '(Org . "9.6"))
|
||||
:package-version '(Org . "9.7"))
|
||||
|
||||
(defun org-babel-expand-body:clojure (body params)
|
||||
"Expand BODY according to PARAMS, return the expanded body."
|
||||
(defcustom ob-clojure-cli-command (when-let (cmd (executable-find "clojure"))
|
||||
(concat cmd " -M"))
|
||||
"Clojure CLI command used by the Clojure `clojure-cli' backend."
|
||||
:type 'string
|
||||
:group 'org-babel
|
||||
:package-version '(Org . "9.7"))
|
||||
|
||||
(defun org-babel-expand-body:clojure (body params &optional cljs-p)
|
||||
"Expand BODY according to PARAMS, return the expanded body.
|
||||
When CLJS-P is non-nil, expand in a cljs context instead of clj."
|
||||
(let* ((vars (org-babel--get-vars params))
|
||||
(backend-override (cdr (assq :backend params)))
|
||||
(org-babel-clojure-backend
|
||||
|
@ -146,10 +170,26 @@ or set the `:backend' header argument"))))
|
|||
vars
|
||||
"\n ")
|
||||
body))))))
|
||||
(if (or (member "code" result-params)
|
||||
(member "pp" result-params))
|
||||
(format "(clojure.pprint/pprint (do %s))" body)
|
||||
body)))
|
||||
;; If the result param is set to "output" we don't have to do
|
||||
;; anything special and just let the backend handle everything
|
||||
(if (member "output" result-params)
|
||||
body
|
||||
|
||||
;; If the result is not "output" (i.e. it's "value"), disable
|
||||
;; stdout output and print the last returned value. Use pprint
|
||||
;; instead of prn when results param is "pp" or "code".
|
||||
(concat
|
||||
(if (or (member "code" result-params)
|
||||
(member "pp" result-params))
|
||||
(concat (if cljs-p
|
||||
"(require '[cljs.pprint :refer [pprint]])"
|
||||
"(require '[clojure.pprint :refer [pprint]])")
|
||||
" (pprint ")
|
||||
"(prn ")
|
||||
(if cljs-p
|
||||
"(binding [cljs.core/*print-fn* (constantly nil)]"
|
||||
"(binding [*out* (java.io.StringWriter.)]")
|
||||
body "))"))))
|
||||
|
||||
(defvar ob-clojure-inf-clojure-filter-out)
|
||||
(defvar ob-clojure-inf-clojure-tmp-output)
|
||||
|
@ -186,8 +226,7 @@ or set the `:backend' header argument"))))
|
|||
(defvar inf-clojure-comint-prompt-regexp)
|
||||
(defun ob-clojure-eval-with-inf-clojure (expanded params)
|
||||
"Evaluate EXPANDED code block with PARAMS using inf-clojure."
|
||||
(condition-case nil (require 'inf-clojure)
|
||||
(user-error "inf-clojure not available"))
|
||||
(org-require-package 'inf-clojure)
|
||||
;; Maybe initiate the inf-clojure session
|
||||
(unless (and inf-clojure-buffer
|
||||
(buffer-live-p (get-buffer inf-clojure-buffer)))
|
||||
|
@ -198,7 +237,9 @@ or set the `:backend' header argument"))))
|
|||
"clojure" (format "clojure -A%s" alias)
|
||||
cmd0)
|
||||
cmd0)))
|
||||
(setq comint-prompt-regexp inf-clojure-comint-prompt-regexp)
|
||||
(setq
|
||||
org-babel-comint-prompt-regexp-old comint-prompt-regexp
|
||||
comint-prompt-regexp inf-clojure-comint-prompt-regexp)
|
||||
(funcall-interactively #'inf-clojure cmd)
|
||||
(goto-char (point-max))))
|
||||
(sit-for 1))
|
||||
|
@ -226,38 +267,24 @@ or set the `:backend' header argument"))))
|
|||
s))
|
||||
(reverse ob-clojure-inf-clojure-tmp-output)))))
|
||||
|
||||
(defun ob-clojure-eval-with-cider (expanded params)
|
||||
"Evaluate EXPANDED code block with PARAMS using cider."
|
||||
(condition-case nil (require 'cider)
|
||||
(user-error "cider not available"))
|
||||
(let ((connection (cider-current-connection (cdr (assq :target params))))
|
||||
(result-params (cdr (assq :result-params params)))
|
||||
result0)
|
||||
(defun ob-clojure-eval-with-cider (expanded _params &optional cljs-p)
|
||||
"Evaluate EXPANDED code block using cider.
|
||||
When CLJS-P is non-nil, use a cljs connection instead of clj.
|
||||
The PARAMS from Babel are not used in this function."
|
||||
(org-require-package 'cider "Cider")
|
||||
(let ((connection (cider-current-connection (if cljs-p "cljs" "clj"))))
|
||||
(unless connection (sesman-start-session 'CIDER))
|
||||
(if (not connection)
|
||||
;; Display in the result instead of using `user-error'
|
||||
(setq result0 "Please reevaluate when nREPL is connected")
|
||||
(ob-clojure-with-temp-expanded expanded params
|
||||
(let ((response (nrepl-sync-request:eval exp connection)))
|
||||
(push (or (nrepl-dict-get response "root-ex")
|
||||
(nrepl-dict-get response "ex")
|
||||
(nrepl-dict-get
|
||||
response (if (or (member "output" result-params)
|
||||
(member "pp" result-params))
|
||||
"out"
|
||||
"value")))
|
||||
result0)))
|
||||
(ob-clojure-string-or-list
|
||||
;; Filter out s-expressions that return nil (string "nil"
|
||||
;; from nrepl eval) or comment forms (actual nil from nrepl)
|
||||
(reverse (delete "" (mapcar (lambda (r)
|
||||
(replace-regexp-in-string "nil" "" (or r "")))
|
||||
result0)))))))
|
||||
"Please reevaluate when nREPL is connected"
|
||||
(let ((response (nrepl-sync-request:eval expanded connection)))
|
||||
(or (nrepl-dict-get response "root-ex")
|
||||
(nrepl-dict-get response "ex")
|
||||
(nrepl-dict-get response "out"))))))
|
||||
|
||||
(defun ob-clojure-eval-with-slime (expanded params)
|
||||
"Evaluate EXPANDED code block with PARAMS using slime."
|
||||
(condition-case nil (require 'slime)
|
||||
(user-error "slime not available"))
|
||||
(org-require-package 'slime "SLIME")
|
||||
(with-temp-buffer
|
||||
(insert expanded)
|
||||
(slime-eval
|
||||
|
@ -265,39 +292,54 @@ or set the `:backend' header argument"))))
|
|||
,(buffer-substring-no-properties (point-min) (point-max)))
|
||||
(cdr (assq :package params)))))
|
||||
|
||||
(defun ob-clojure-eval-with-babashka (bb expanded)
|
||||
"Evaluate EXPANDED code block using BB (babashka or nbb)."
|
||||
(let ((script-file (org-babel-temp-file "clojure-bb-script-" ".clj")))
|
||||
(defun ob-clojure-eval-with-cmd (cmd expanded)
|
||||
"Evaluate EXPANDED code block using CMD (babashka, clojure or nbb)."
|
||||
(let ((script-file (org-babel-temp-file "clojure-cmd-script-" ".clj")))
|
||||
(with-temp-file script-file
|
||||
(insert expanded))
|
||||
(org-babel-eval
|
||||
(format "%s %s" bb (org-babel-process-file-name script-file))
|
||||
(format "%s %s" cmd (org-babel-process-file-name script-file))
|
||||
"")))
|
||||
|
||||
(defun org-babel-execute:clojure (body params)
|
||||
"Execute the BODY block of Clojure code with PARAMS using Babel."
|
||||
(defun org-babel-execute:clojure (body params &optional cljs-p)
|
||||
"Execute the BODY block of Clojure code with PARAMS using Babel.
|
||||
When CLJS-P is non-nil, execute with a ClojureScript backend
|
||||
instead of Clojure."
|
||||
(let* ((backend-override (cdr (assq :backend params)))
|
||||
(org-babel-clojure-backend
|
||||
(cond
|
||||
(backend-override (intern backend-override))
|
||||
(org-babel-clojure-backend org-babel-clojure-backend)
|
||||
(t (user-error "You need to customize `org-babel-clojure-backend'
|
||||
or set the `:backend' header argument")))))
|
||||
(let* ((expanded (org-babel-expand-body:clojure body params))
|
||||
(org-babel-clojure-backend (if cljs-p
|
||||
org-babel-clojurescript-backend
|
||||
org-babel-clojure-backend))
|
||||
(t (user-error "You need to customize `%S'
|
||||
or set the `:backend' header argument"
|
||||
(if cljs-p
|
||||
org-babel-clojurescript-backend
|
||||
org-babel-clojure-backend)))))
|
||||
;; We allow a Clojure source block to be evaluated with the
|
||||
;; nbb backend and therefore have to expand the body with
|
||||
;; ClojureScript syntax when we either evaluate a
|
||||
;; ClojureScript source block or use the nbb backend.
|
||||
(cljs-p (or cljs-p (eq org-babel-clojure-backend 'nbb))))
|
||||
(let* ((expanded (org-babel-expand-body:clojure body params cljs-p))
|
||||
(result-params (cdr (assq :result-params params)))
|
||||
result)
|
||||
(setq result
|
||||
(cond
|
||||
((eq org-babel-clojure-backend 'inf-clojure)
|
||||
(ob-clojure-eval-with-inf-clojure expanded params))
|
||||
((eq org-babel-clojure-backend 'clojure-cli)
|
||||
(ob-clojure-eval-with-cmd ob-clojure-cli-command expanded))
|
||||
((eq org-babel-clojure-backend 'babashka)
|
||||
(ob-clojure-eval-with-babashka ob-clojure-babashka-command expanded))
|
||||
(ob-clojure-eval-with-cmd ob-clojure-babashka-command expanded))
|
||||
((eq org-babel-clojure-backend 'nbb)
|
||||
(ob-clojure-eval-with-babashka ob-clojure-nbb-command expanded))
|
||||
(ob-clojure-eval-with-cmd ob-clojure-nbb-command expanded))
|
||||
((eq org-babel-clojure-backend 'cider)
|
||||
(ob-clojure-eval-with-cider expanded params))
|
||||
(ob-clojure-eval-with-cider expanded params cljs-p))
|
||||
((eq org-babel-clojure-backend 'slime)
|
||||
(ob-clojure-eval-with-slime expanded params))))
|
||||
(ob-clojure-eval-with-slime expanded params))
|
||||
(t (user-error "Invalid backend"))))
|
||||
(org-babel-result-cond result-params
|
||||
result
|
||||
(condition-case nil (org-babel-script-escape result)
|
||||
|
@ -305,7 +347,7 @@ or set the `:backend' header argument")))))
|
|||
|
||||
(defun org-babel-execute:clojurescript (body params)
|
||||
"Evaluate BODY with PARAMS as ClojureScript code."
|
||||
(org-babel-execute:clojure body (cons '(:target . "cljs") params)))
|
||||
(org-babel-execute:clojure body params t))
|
||||
|
||||
(provide 'ob-clojure)
|
||||
|
||||
|
|
|
@ -58,6 +58,48 @@ executed inside the protection of `save-excursion' and
|
|||
(let ((comint-input-filter (lambda (_input) nil)))
|
||||
,@body))))))
|
||||
|
||||
(defvar-local org-babel-comint-prompt-regexp-old nil
|
||||
"Fallback regexp used to detect prompt.")
|
||||
|
||||
(defcustom org-babel-comint-fallback-regexp-threshold 5.0
|
||||
"Waiting time until trying to use fallback regexp to detect prompt.
|
||||
This is useful when prompt unexpectedly changes."
|
||||
:type 'float
|
||||
:group 'org-babel
|
||||
:package-version '(Org . "9.7"))
|
||||
|
||||
(defun org-babel-comint--set-fallback-prompt ()
|
||||
"Swap `comint-prompt-regexp' and `org-babel-comint-prompt-regexp-old'."
|
||||
(when org-babel-comint-prompt-regexp-old
|
||||
(let ((tmp comint-prompt-regexp))
|
||||
(setq comint-prompt-regexp org-babel-comint-prompt-regexp-old
|
||||
org-babel-comint-prompt-regexp-old tmp))))
|
||||
|
||||
(defun org-babel-comint--prompt-filter (string &optional prompt-regexp)
|
||||
"Remove PROMPT-REGEXP from STRING.
|
||||
|
||||
PROMPT-REGEXP defaults to `comint-prompt-regexp'."
|
||||
(let* ((prompt-regexp (or prompt-regexp comint-prompt-regexp))
|
||||
;; We need newline in case if we do progressive replacement
|
||||
;; of agglomerated comint prompts with `comint-prompt-regexp'
|
||||
;; containing ^.
|
||||
(separator "org-babel-comint--prompt-filter-separator\n"))
|
||||
(while (string-match-p prompt-regexp string)
|
||||
(setq string
|
||||
(replace-regexp-in-string
|
||||
(format "\\(?:%s\\)?\\(?:%s\\)[ \t]*" separator prompt-regexp)
|
||||
separator string)))
|
||||
(delete "" (split-string string separator))))
|
||||
|
||||
(defun org-babel-comint--echo-filter (string &optional echo)
|
||||
"Remove ECHO from STRING."
|
||||
(and echo string
|
||||
(string-match
|
||||
(replace-regexp-in-string "\n" "[\r\n]+" (regexp-quote echo))
|
||||
string)
|
||||
(setq string (substring string (match-end 0))))
|
||||
string)
|
||||
|
||||
(defmacro org-babel-comint-with-output (meta &rest body)
|
||||
"Evaluate BODY in BUFFER and return process output.
|
||||
Will wait until EOE-INDICATOR appears in the output, then return
|
||||
|
@ -74,9 +116,7 @@ or user `keyboard-quit' during execution of body."
|
|||
(let ((buffer (nth 0 meta))
|
||||
(eoe-indicator (nth 1 meta))
|
||||
(remove-echo (nth 2 meta))
|
||||
(full-body (nth 3 meta))
|
||||
(org-babel-comint-prompt-separator
|
||||
"org-babel-comint-prompt-separator"))
|
||||
(full-body (nth 3 meta)))
|
||||
`(org-babel-comint-in-buffer ,buffer
|
||||
(let* ((string-buffer "")
|
||||
(comint-output-filter-functions
|
||||
|
@ -93,43 +133,39 @@ or user `keyboard-quit' during execution of body."
|
|||
;; pass FULL-BODY to process
|
||||
,@body
|
||||
;; wait for end-of-evaluation indicator
|
||||
(while (progn
|
||||
(goto-char comint-last-input-end)
|
||||
(not (save-excursion
|
||||
(and (re-search-forward
|
||||
(regexp-quote ,eoe-indicator) nil t)
|
||||
(re-search-forward
|
||||
comint-prompt-regexp nil t)))))
|
||||
(accept-process-output (get-buffer-process (current-buffer))))
|
||||
(let ((start-time (current-time)))
|
||||
(while (progn
|
||||
(goto-char comint-last-input-end)
|
||||
(not (save-excursion
|
||||
(and (re-search-forward
|
||||
(regexp-quote ,eoe-indicator) nil t)
|
||||
(re-search-forward
|
||||
comint-prompt-regexp nil t)))))
|
||||
(accept-process-output
|
||||
(get-buffer-process (current-buffer))
|
||||
org-babel-comint-fallback-regexp-threshold)
|
||||
(when (and org-babel-comint-prompt-regexp-old
|
||||
(> (float-time (time-since start-time))
|
||||
org-babel-comint-fallback-regexp-threshold)
|
||||
(progn
|
||||
(goto-char comint-last-input-end)
|
||||
(save-excursion
|
||||
(and
|
||||
(re-search-forward
|
||||
(regexp-quote ,eoe-indicator) nil t)
|
||||
(re-search-forward
|
||||
org-babel-comint-prompt-regexp-old nil t)))))
|
||||
(org-babel-comint--set-fallback-prompt))))
|
||||
;; replace cut dangling text
|
||||
(goto-char (process-mark (get-buffer-process (current-buffer))))
|
||||
(insert dangling-text)
|
||||
|
||||
;; remove echo'd FULL-BODY from input
|
||||
(and ,remove-echo ,full-body
|
||||
(setq string-buffer (org-babel-comint--echo-filter string-buffer ,full-body)))
|
||||
|
||||
;; Filter out prompts.
|
||||
(setq string-buffer
|
||||
(replace-regexp-in-string
|
||||
;; Sometimes, we get multiple agglomerated
|
||||
;; prompts together in a single output:
|
||||
;; "prompt prompt prompt output"
|
||||
;; Remove them progressively, so that
|
||||
;; possible "^" in the prompt regexp gets to
|
||||
;; work as we remove the heading prompt
|
||||
;; instance.
|
||||
(if (string-prefix-p "^" comint-prompt-regexp)
|
||||
(format "^\\(%s\\)+" (substring comint-prompt-regexp 1))
|
||||
comint-prompt-regexp)
|
||||
,org-babel-comint-prompt-separator
|
||||
string-buffer))
|
||||
;; remove echo'd FULL-BODY from input
|
||||
(when (and ,remove-echo ,full-body
|
||||
(string-match
|
||||
(replace-regexp-in-string
|
||||
"\n" "[\r\n]+" (regexp-quote (or ,full-body "")))
|
||||
string-buffer))
|
||||
(setq string-buffer (substring string-buffer (match-end 0))))
|
||||
(delete "" (split-string
|
||||
string-buffer
|
||||
,org-babel-comint-prompt-separator))))))
|
||||
(org-babel-comint--prompt-filter string-buffer)))))
|
||||
|
||||
(defun org-babel-comint-input-command (buffer cmd)
|
||||
"Pass CMD to BUFFER.
|
||||
|
@ -145,11 +181,23 @@ The input will not be echoed."
|
|||
Note: this is only safe when waiting for the result of a single
|
||||
statement (not large blocks of code)."
|
||||
(org-babel-comint-in-buffer buffer
|
||||
(while (progn
|
||||
(goto-char comint-last-input-end)
|
||||
(not (and (re-search-forward comint-prompt-regexp nil t)
|
||||
(goto-char (match-beginning 0)))))
|
||||
(accept-process-output (get-buffer-process buffer)))))
|
||||
(let ((start-time (current-time)))
|
||||
(while (progn
|
||||
(goto-char comint-last-input-end)
|
||||
(not (and (re-search-forward comint-prompt-regexp nil t)
|
||||
(goto-char (match-beginning 0)))))
|
||||
(accept-process-output
|
||||
(get-buffer-process buffer)
|
||||
org-babel-comint-fallback-regexp-threshold)
|
||||
(when (and org-babel-comint-prompt-regexp-old
|
||||
(> (float-time (time-since start-time))
|
||||
org-babel-comint-fallback-regexp-threshold)
|
||||
(progn
|
||||
(goto-char comint-last-input-end)
|
||||
(save-excursion
|
||||
(re-search-forward
|
||||
org-babel-comint-prompt-regexp-old nil t))))
|
||||
(org-babel-comint--set-fallback-prompt))))))
|
||||
|
||||
(defun org-babel-comint-eval-invisibly-and-wait-for-file
|
||||
(buffer file string &optional period)
|
||||
|
@ -192,8 +240,8 @@ comint process. It should return a string that will be passed
|
|||
to `org-babel-insert-result'.")
|
||||
|
||||
(defvar-local org-babel-comint-async-dangling nil
|
||||
"Dangling piece of the last process output, in case
|
||||
`org-babel-comint-async-indicator' is spread across multiple
|
||||
"Dangling piece of the last process output, as a string.
|
||||
Used when `org-babel-comint-async-indicator' is spread across multiple
|
||||
comint outputs due to buffering.")
|
||||
|
||||
(defun org-babel-comint-use-async (params)
|
||||
|
@ -221,6 +269,8 @@ STRING contains the output originally inserted into the comint buffer."
|
|||
(file-callback org-babel-comint-async-file-callback)
|
||||
(combined-string (concat org-babel-comint-async-dangling string))
|
||||
(new-dangling combined-string)
|
||||
;; Assumes comint filter called with session buffer current
|
||||
(session-dir default-directory)
|
||||
;; list of UUID's matched by `org-babel-comint-async-indicator'
|
||||
uuid-list)
|
||||
(with-temp-buffer
|
||||
|
@ -245,7 +295,8 @@ STRING contains the output originally inserted into the comint buffer."
|
|||
(let* ((info (org-babel-get-src-block-info))
|
||||
(params (nth 2 info))
|
||||
(result-params
|
||||
(cdr (assq :result-params params))))
|
||||
(cdr (assq :result-params params)))
|
||||
(default-directory session-dir))
|
||||
(org-babel-insert-result
|
||||
(funcall file-callback
|
||||
(nth
|
||||
|
@ -268,16 +319,17 @@ STRING contains the output originally inserted into the comint buffer."
|
|||
(res-str-raw
|
||||
(buffer-substring
|
||||
;; move point to beginning of indicator
|
||||
(- (match-beginning 0) 1)
|
||||
(match-beginning 0)
|
||||
;; find the matching start indicator
|
||||
(cl-loop
|
||||
do (re-search-backward indicator)
|
||||
until (and (equal (match-string 1) "start")
|
||||
(equal (match-string 2) uuid))
|
||||
finally return (+ 1 (match-end 0)))))
|
||||
;; Apply callback to clean up the result
|
||||
(res-str (funcall org-babel-comint-async-chunk-callback
|
||||
res-str-raw)))
|
||||
;; Remove prompt
|
||||
(res-promptless (org-trim (string-join (mapcar #'org-trim (org-babel-comint--prompt-filter res-str-raw)) "\n") "\n"))
|
||||
;; Apply user callback
|
||||
(res-str (funcall org-babel-comint-async-chunk-callback res-promptless)))
|
||||
;; Search for uuid in associated org-buffers to insert results
|
||||
(cl-loop for buf in org-buffers
|
||||
until (with-current-buffer buf
|
||||
|
@ -288,7 +340,8 @@ STRING contains the output originally inserted into the comint buffer."
|
|||
(let* ((info (org-babel-get-src-block-info))
|
||||
(params (nth 2 info))
|
||||
(result-params
|
||||
(cdr (assq :result-params params))))
|
||||
(cdr (assq :result-params params)))
|
||||
(default-directory session-dir))
|
||||
(org-babel-insert-result
|
||||
res-str result-params info))
|
||||
t))))
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -36,7 +36,7 @@
|
|||
(defvar org-babel-default-header-args:css '())
|
||||
|
||||
(defun org-babel-execute:css (body _params)
|
||||
"Execute a block of CSS code.
|
||||
"Execute BODY of CSS code.
|
||||
This function is called by `org-babel-execute-src-block'."
|
||||
body)
|
||||
|
||||
|
|
|
@ -83,11 +83,11 @@ Do not leave leading or trailing spaces in this string."
|
|||
:type 'string)
|
||||
|
||||
(defun org-babel-execute:ditaa (body params)
|
||||
"Execute a block of Ditaa code with org-babel.
|
||||
"Execute BODY of Ditaa code with org-babel according to PARAMS.
|
||||
This function is called by `org-babel-execute-src-block'."
|
||||
(let* ((out-file (or (cdr (assq :file params))
|
||||
(error
|
||||
"ditaa code block requires :file header argument")))
|
||||
"Ditaa code block requires :file header argument")))
|
||||
(cmdline (cdr (assq :cmdline params)))
|
||||
(java (cdr (assq :java params)))
|
||||
(in-file (org-babel-temp-file "ditaa-"))
|
||||
|
|
|
@ -51,7 +51,9 @@
|
|||
|
||||
(defun org-babel-expand-body:dot (body params)
|
||||
"Expand BODY according to PARAMS, return the expanded body."
|
||||
(let ((vars (org-babel--get-vars params)))
|
||||
(let ((vars (org-babel--get-vars params))
|
||||
(prologue (cdr (assq :prologue params)))
|
||||
(epilogue (cdr (assq :epilogue params))))
|
||||
(mapc
|
||||
(lambda (pair)
|
||||
(let ((name (symbol-name (car pair)))
|
||||
|
@ -64,10 +66,13 @@
|
|||
t
|
||||
t))))
|
||||
vars)
|
||||
body))
|
||||
(concat
|
||||
(and prologue (concat prologue "\n"))
|
||||
body
|
||||
(and epilogue (concat "\n" epilogue "\n")))))
|
||||
|
||||
(defun org-babel-execute:dot (body params)
|
||||
"Execute a block of Dot code with org-babel.
|
||||
"Execute Dot BODY with org-babel according to PARAMS.
|
||||
This function is called by `org-babel-execute-src-block'."
|
||||
(let* ((out-file (cdr (or (assq :file params)
|
||||
(error "You need to specify a :file parameter"))))
|
||||
|
|
|
@ -53,18 +53,23 @@ by `org-edit-src-code'.")
|
|||
"Expand BODY according to PARAMS, return the expanded body."
|
||||
(let ((vars (org-babel--get-vars params))
|
||||
(print-level nil)
|
||||
(print-length nil))
|
||||
(print-length nil)
|
||||
(prologue (cdr (assq :prologue params)))
|
||||
(epilogue (cdr (assq :epilogue params))))
|
||||
(if (null vars) (concat body "\n")
|
||||
(format "(let (%s)\n%s\n)"
|
||||
(format "(let (%s)\n%s%s%s\n)"
|
||||
(mapconcat
|
||||
(lambda (var)
|
||||
(format "%S" `(,(car var) ',(cdr var))))
|
||||
vars "\n ")
|
||||
body))))
|
||||
(if prologue (concat prologue "\n ") "")
|
||||
body
|
||||
(if epilogue (concat "\n " epilogue "\n") "")))))
|
||||
|
||||
(defun org-babel-execute:emacs-lisp (body params)
|
||||
"Execute a block of emacs-lisp code with Babel."
|
||||
"Execute emacs-lisp code BODY according to PARAMS."
|
||||
(let* ((lexical (cdr (assq :lexical params)))
|
||||
(session (cdr (assq :session params)))
|
||||
(result-params (cdr (assq :result-params params)))
|
||||
(body (format (if (member "output" result-params)
|
||||
"(with-output-to-string %s\n)"
|
||||
|
@ -75,6 +80,8 @@ by `org-edit-src-code'.")
|
|||
(concat "(pp " body ")")
|
||||
body))
|
||||
(org-babel-emacs-lisp-lexical lexical))))
|
||||
(when (and session (not (equal session "none")))
|
||||
(error "ob-emacs-lisp backend does not support sessions"))
|
||||
(org-babel-result-cond result-params
|
||||
(let ((print-level nil)
|
||||
(print-length nil))
|
||||
|
@ -100,12 +107,17 @@ and the LEXICAL argument to `eval'."
|
|||
(defun org-babel-edit-prep:emacs-lisp (info)
|
||||
"Set `lexical-binding' in Org edit buffer.
|
||||
Set `lexical-binding' in Org edit buffer according to the
|
||||
corresponding :lexical source block argument."
|
||||
corresponding :lexical source block argument provide in the INFO
|
||||
channel, as returned by `org-babel-get-src-block-info'."
|
||||
(setq lexical-binding
|
||||
(org-babel-emacs-lisp-lexical
|
||||
(org-babel-read
|
||||
(cdr (assq :lexical (nth 2 info)))))))
|
||||
|
||||
(defun org-babel-prep-session:emacs-lisp (_session _params)
|
||||
"Return an error because we do not support sessions."
|
||||
(error "ob-emacs-lisp backend does not support sessions"))
|
||||
|
||||
(org-babel-make-language-alias "elisp" "emacs-lisp")
|
||||
|
||||
(provide 'ob-emacs-lisp)
|
||||
|
|
|
@ -95,10 +95,11 @@ The PARAMS argument is passed to
|
|||
session))
|
||||
|
||||
(defun org-babel-variable-assignments:eshell (params)
|
||||
"Convert ob-eshell :var specified variables into Eshell variables assignments."
|
||||
"Convert ob-eshell variables from PARAMS into Eshell variables assignments."
|
||||
(mapcar
|
||||
(lambda (pair)
|
||||
(format "(setq %s %S)" (car pair) (cdr pair)))
|
||||
;; Use `ignore' to suppress value in the command output.
|
||||
(format "(ignore (setq %s %S))" (car pair) (cdr pair)))
|
||||
(org-babel--get-vars params)))
|
||||
|
||||
(defun org-babel-load-session:eshell (session body params)
|
||||
|
|
|
@ -37,16 +37,21 @@
|
|||
(declare-function org-babel-temp-file "ob-core" (prefix &optional suffix))
|
||||
|
||||
(defun org-babel-eval-error-notify (exit-code stderr)
|
||||
"Open a buffer to display STDERR and a message with the value of EXIT-CODE."
|
||||
"Open a buffer to display STDERR and a message with the value of EXIT-CODE.
|
||||
If EXIT-CODE is nil, display the message without a code."
|
||||
(let ((buf (get-buffer-create org-babel-error-buffer-name)))
|
||||
(with-current-buffer buf
|
||||
(goto-char (point-max))
|
||||
(save-excursion
|
||||
(unless (bolp) (insert "\n"))
|
||||
(insert stderr)
|
||||
(insert (format "[ Babel evaluation exited with code %S ]" exit-code))))
|
||||
(if exit-code
|
||||
(insert (format "[ Babel evaluation exited with code %S ]" exit-code))
|
||||
(insert "[ Babel evaluation exited abnormally ]"))))
|
||||
(display-buffer buf))
|
||||
(message "Babel evaluation exited with code %S" exit-code))
|
||||
(if exit-code
|
||||
(message "Babel evaluation exited with code %S" exit-code)
|
||||
(message "Babel evaluation exited abnormally")))
|
||||
|
||||
(defun org-babel-eval (command query)
|
||||
"Run COMMAND on QUERY.
|
||||
|
@ -59,6 +64,7 @@ Writes QUERY into a temp-buffer that is processed with
|
|||
(let ((error-buffer (get-buffer-create " *Org-Babel Error*")) exit-code)
|
||||
(with-current-buffer error-buffer (erase-buffer))
|
||||
(with-temp-buffer
|
||||
;; Ensure trailing newline. It is required for cmdproxy.exe.
|
||||
(insert query "\n")
|
||||
(setq exit-code
|
||||
(org-babel--shell-command-on-region
|
||||
|
@ -100,11 +106,6 @@ returned."
|
|||
(error-file (if error-buffer (org-babel-temp-file "ob-error-") nil))
|
||||
(shell-file-name (org-babel--get-shell-file-name))
|
||||
exit-status)
|
||||
;; There is an error in `process-file' when `error-file' exists.
|
||||
;; This is fixed in Emacs trunk as of 2012-12-21; let's use this
|
||||
;; workaround for now.
|
||||
(unless (file-remote-p default-directory)
|
||||
(delete-file error-file))
|
||||
;; we always call this with 'replace, remove conditional
|
||||
;; Replace specified region with output from command.
|
||||
(org-babel--write-temp-buffer-input-file input-file)
|
||||
|
|
|
@ -32,8 +32,10 @@
|
|||
(declare-function org-babel-lob-get-info "ob-lob" (&optional datum no-eval))
|
||||
(declare-function org-element-at-point "org-element" (&optional pom cached-only))
|
||||
(declare-function org-element-context "org-element" (&optional element))
|
||||
(declare-function org-element-property "org-element" (property element))
|
||||
(declare-function org-element-type "org-element" (element))
|
||||
(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-type "org-element-ast" (node &optional anonymous))
|
||||
(declare-function org-escape-code-in-string "org-src" (s))
|
||||
(declare-function org-export-copy-buffer "ox"
|
||||
(&optional buffer drop-visibility
|
||||
|
@ -41,8 +43,7 @@
|
|||
drop-locals))
|
||||
(declare-function org-in-commented-heading-p "org" (&optional no-inheritance element))
|
||||
(declare-function org-in-archived-heading-p "org" (&optional no-inheritance element))
|
||||
|
||||
(defvar org-src-preserve-indentation)
|
||||
(declare-function org-src-preserve-indentation-p "org-src" (node))
|
||||
|
||||
(defcustom org-export-use-babel t
|
||||
"Switch controlling code evaluation and header processing during export.
|
||||
|
@ -140,217 +141,236 @@ this template."
|
|||
"Execute all Babel blocks in current buffer."
|
||||
(interactive)
|
||||
(when org-export-use-babel
|
||||
(save-window-excursion
|
||||
(let ((case-fold-search t)
|
||||
(regexp "\\(call\\|src\\)_\\|^[ \t]*#\\+\\(BEGIN_SRC\\|CALL:\\)")
|
||||
;; Get a pristine copy of current buffer so Babel
|
||||
;; references are properly resolved and source block
|
||||
;; context is preserved.
|
||||
(org-babel-exp-reference-buffer (org-export-copy-buffer))
|
||||
element)
|
||||
(unwind-protect
|
||||
(save-excursion
|
||||
;; First attach to every source block their original
|
||||
;; position, so that they can be retrieved within
|
||||
;; `org-babel-exp-reference-buffer', even after heavy
|
||||
;; modifications on current buffer.
|
||||
;;
|
||||
;; False positives are harmless, so we don't check if
|
||||
;; we're really at some Babel object. Moreover,
|
||||
;; `line-end-position' ensures that we propertize
|
||||
;; a noticeable part of the object, without affecting
|
||||
;; multiple objects on the same line.
|
||||
(goto-char (point-min))
|
||||
(let ((case-fold-search t)
|
||||
(regexp "\\(call\\|src\\)_\\|^[ \t]*#\\+\\(BEGIN_SRC\\|CALL:\\)")
|
||||
;; Get a pristine copy of current buffer so Babel
|
||||
;; references are properly resolved and source block
|
||||
;; context is preserved.
|
||||
(org-babel-exp-reference-buffer (org-export-copy-buffer))
|
||||
element)
|
||||
(unwind-protect
|
||||
(save-excursion
|
||||
;; First attach to every source block their original
|
||||
;; position, so that they can be retrieved within
|
||||
;; `org-babel-exp-reference-buffer', even after heavy
|
||||
;; modifications on current buffer.
|
||||
;;
|
||||
;; False positives are harmless, so we don't check if
|
||||
;; we're really at some Babel object. Moreover,
|
||||
;; `line-end-position' ensures that we propertize
|
||||
;; a noticeable part of the object, without affecting
|
||||
;; multiple objects on the same line.
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward regexp nil t)
|
||||
(let ((s (match-beginning 0)))
|
||||
(put-text-property s (line-end-position) 'org-reference s)))
|
||||
;; Evaluate from top to bottom every Babel block
|
||||
;; encountered.
|
||||
(goto-char (point-min))
|
||||
;; We are about to do a large number of changes in
|
||||
;; buffer, but we do not care about folding in this
|
||||
;; buffer.
|
||||
(org-fold-core-ignore-modifications
|
||||
(while (re-search-forward regexp nil t)
|
||||
(let ((s (match-beginning 0)))
|
||||
(put-text-property s (line-end-position) 'org-reference s)))
|
||||
;; Evaluate from top to bottom every Babel block
|
||||
;; encountered.
|
||||
(goto-char (point-min))
|
||||
;; We are about to do a large number of changes in
|
||||
;; buffer, but we do not care about folding in this
|
||||
;; buffer.
|
||||
(org-fold-core-ignore-modifications
|
||||
(while (re-search-forward regexp nil t)
|
||||
(setq element (org-element-at-point))
|
||||
(unless (save-match-data
|
||||
(or (org-in-commented-heading-p nil element)
|
||||
(org-in-archived-heading-p nil element)))
|
||||
(let* ((object? (match-end 1))
|
||||
(element (save-match-data
|
||||
(if object?
|
||||
(org-element-context element)
|
||||
;; No deep inspection if we're
|
||||
;; just looking for an element.
|
||||
element)))
|
||||
(type
|
||||
(pcase (org-element-type element)
|
||||
;; Discard block elements if we're looking
|
||||
;; for inline objects. False results
|
||||
;; happen when, e.g., "call_" syntax is
|
||||
;; located within affiliated keywords:
|
||||
;;
|
||||
;; #+name: call_src
|
||||
;; #+begin_src ...
|
||||
((and (or `babel-call `src-block) (guard object?))
|
||||
nil)
|
||||
(type type)))
|
||||
(begin
|
||||
(copy-marker (org-element-property :begin element)))
|
||||
(end
|
||||
(copy-marker
|
||||
(save-excursion
|
||||
(goto-char (org-element-property :end element))
|
||||
(skip-chars-backward " \r\t\n")
|
||||
(point)))))
|
||||
(pcase type
|
||||
(`inline-src-block
|
||||
(let* ((info
|
||||
(org-babel-get-src-block-info nil element))
|
||||
(params (nth 2 info)))
|
||||
(setf (nth 1 info)
|
||||
(if (and (cdr (assq :noweb params))
|
||||
(string= "yes"
|
||||
(cdr (assq :noweb params))))
|
||||
(org-babel-expand-noweb-references
|
||||
info org-babel-exp-reference-buffer)
|
||||
(nth 1 info)))
|
||||
(goto-char begin)
|
||||
(let ((replacement
|
||||
(org-babel-exp-do-export info 'inline)))
|
||||
(if (equal replacement "")
|
||||
;; Replacement code is empty: remove
|
||||
;; inline source block, including extra
|
||||
;; white space that might have been
|
||||
;; created when inserting results.
|
||||
(delete-region begin
|
||||
(progn (goto-char end)
|
||||
(skip-chars-forward " \t")
|
||||
(point)))
|
||||
;; Otherwise: remove inline source block
|
||||
;; but preserve following white spaces.
|
||||
;; Then insert value.
|
||||
(unless (string= replacement
|
||||
(buffer-substring begin end))
|
||||
(delete-region begin end)
|
||||
(insert replacement))))))
|
||||
((or `babel-call `inline-babel-call)
|
||||
(org-babel-exp-do-export
|
||||
(or (org-babel-lob-get-info element)
|
||||
(user-error "Unknown Babel reference: %s"
|
||||
(org-element-property :call element)))
|
||||
'lob)
|
||||
(let ((rep
|
||||
(org-fill-template
|
||||
org-babel-exp-call-line-template
|
||||
`(("line" .
|
||||
,(org-element-property :value element))))))
|
||||
;; If replacement is empty, completely remove
|
||||
;; the object/element, including any extra
|
||||
;; white space that might have been created
|
||||
;; when including results.
|
||||
(if (equal rep "")
|
||||
(delete-region
|
||||
begin
|
||||
(progn (goto-char end)
|
||||
(if (not (eq type 'babel-call))
|
||||
(progn (skip-chars-forward " \t")
|
||||
(point))
|
||||
(skip-chars-forward " \r\t\n")
|
||||
(line-beginning-position))))
|
||||
;; Otherwise, preserve trailing
|
||||
;; spaces/newlines and then, insert
|
||||
;; replacement string.
|
||||
(goto-char begin)
|
||||
(setq element (save-match-data (org-element-at-point)))
|
||||
(unless (save-match-data
|
||||
(or (org-in-commented-heading-p nil element)
|
||||
(org-in-archived-heading-p nil element)))
|
||||
(let* ((object? (match-end 1))
|
||||
(element (save-match-data
|
||||
(if object?
|
||||
(org-element-context element)
|
||||
;; No deep inspection if we're
|
||||
;; just looking for an element.
|
||||
element)))
|
||||
(type
|
||||
(pcase (org-element-type element)
|
||||
;; Discard block elements if we're looking
|
||||
;; for inline objects. False results
|
||||
;; happen when, e.g., "call_" syntax is
|
||||
;; located within affiliated keywords:
|
||||
;;
|
||||
;; #+name: call_src
|
||||
;; #+begin_src ...
|
||||
((and (or `babel-call `src-block) (guard object?))
|
||||
nil)
|
||||
(type type)))
|
||||
(begin
|
||||
(copy-marker (org-element-begin element)))
|
||||
(end
|
||||
(copy-marker
|
||||
(save-excursion
|
||||
(goto-char (org-element-end element))
|
||||
(skip-chars-backward " \r\t\n")
|
||||
(point)))))
|
||||
(pcase type
|
||||
(`inline-src-block
|
||||
(let* ((info
|
||||
(org-babel-get-src-block-info nil element))
|
||||
(params (nth 2 info)))
|
||||
(setf (nth 1 info)
|
||||
(if (and (cdr (assq :noweb params))
|
||||
(string= "yes"
|
||||
(cdr (assq :noweb params))))
|
||||
(org-babel-expand-noweb-references
|
||||
info org-babel-exp-reference-buffer)
|
||||
(nth 1 info)))
|
||||
(goto-char begin)
|
||||
(let ((replacement
|
||||
(org-babel-exp-do-export info 'inline)))
|
||||
(cond
|
||||
((equal replacement "")
|
||||
;; Replacement code is empty: remove
|
||||
;; inline source block, including extra
|
||||
;; white space that might have been
|
||||
;; created when inserting results.
|
||||
(delete-region begin
|
||||
(progn (goto-char end)
|
||||
(skip-chars-forward " \t")
|
||||
(point))))
|
||||
((not replacement)
|
||||
;; Replacement code cannot be determined.
|
||||
;; Leave the code block as is.
|
||||
(goto-char end))
|
||||
;; Otherwise: remove inline source block
|
||||
;; but preserve following white spaces.
|
||||
;; Then insert value.
|
||||
((not (string= replacement
|
||||
(buffer-substring begin end)))
|
||||
(delete-region begin end)
|
||||
(insert rep))))
|
||||
(`src-block
|
||||
(let ((match-start (copy-marker (match-beginning 0)))
|
||||
(ind (org-current-text-indentation)))
|
||||
;; Take care of matched block: compute
|
||||
;; replacement string. In particular, a nil
|
||||
;; REPLACEMENT means the block is left as-is
|
||||
;; while an empty string removes the block.
|
||||
(let ((replacement
|
||||
(progn (goto-char match-start)
|
||||
(org-babel-exp-src-block element))))
|
||||
(cond ((not replacement) (goto-char end))
|
||||
((equal replacement "")
|
||||
(goto-char end)
|
||||
(skip-chars-forward " \r\t\n")
|
||||
(beginning-of-line)
|
||||
(delete-region begin (point)))
|
||||
(t
|
||||
(if (or org-src-preserve-indentation
|
||||
(org-element-property
|
||||
:preserve-indent element))
|
||||
;; Indent only code block
|
||||
;; markers.
|
||||
(with-temp-buffer
|
||||
;; Do not use tabs for block
|
||||
;; indentation.
|
||||
(when (fboundp 'indent-tabs-mode)
|
||||
(indent-tabs-mode -1)
|
||||
;; FIXME: Emacs 26
|
||||
;; compatibility.
|
||||
(setq-local indent-tabs-mode nil))
|
||||
(insert replacement)
|
||||
(skip-chars-backward " \r\t\n")
|
||||
(indent-line-to ind)
|
||||
(goto-char 1)
|
||||
(indent-line-to ind)
|
||||
(setq replacement (buffer-string)))
|
||||
;; Indent everything.
|
||||
(with-temp-buffer
|
||||
;; Do not use tabs for block
|
||||
;; indentation.
|
||||
(when (fboundp 'indent-tabs-mode)
|
||||
(indent-tabs-mode -1)
|
||||
;; FIXME: Emacs 26
|
||||
;; compatibility.
|
||||
(setq-local indent-tabs-mode nil))
|
||||
(insert replacement)
|
||||
(indent-rigidly
|
||||
1 (point) ind)
|
||||
(setq replacement (buffer-string))))
|
||||
(goto-char match-start)
|
||||
(let ((rend (save-excursion
|
||||
(goto-char end)
|
||||
(line-end-position))))
|
||||
(if (string-equal replacement
|
||||
(buffer-substring match-start rend))
|
||||
(goto-char rend)
|
||||
(delete-region match-start
|
||||
(save-excursion
|
||||
(goto-char end)
|
||||
(line-end-position)))
|
||||
(insert replacement))))))
|
||||
(set-marker match-start nil))))
|
||||
(set-marker begin nil)
|
||||
(set-marker end nil))))))
|
||||
(kill-buffer org-babel-exp-reference-buffer)
|
||||
(remove-text-properties (point-min) (point-max)
|
||||
'(org-reference nil)))))))
|
||||
(insert replacement))
|
||||
;; Replacement is the same as the source
|
||||
;; block. Continue onwards.
|
||||
(t (goto-char end))))))
|
||||
((or `babel-call `inline-babel-call)
|
||||
(org-babel-exp-do-export
|
||||
(or (org-babel-lob-get-info element)
|
||||
(user-error "Unknown Babel reference: %s"
|
||||
(org-element-property :call element)))
|
||||
'lob)
|
||||
(let ((rep
|
||||
(org-fill-template
|
||||
org-babel-exp-call-line-template
|
||||
`(("line" .
|
||||
,(org-element-property :value element))))))
|
||||
;; If replacement is empty, completely remove
|
||||
;; the object/element, including any extra
|
||||
;; white space that might have been created
|
||||
;; when including results.
|
||||
(cond
|
||||
((equal rep "")
|
||||
(delete-region
|
||||
begin
|
||||
(progn (goto-char end)
|
||||
(if (not (eq type 'babel-call))
|
||||
(progn (skip-chars-forward " \t")
|
||||
(point))
|
||||
(skip-chars-forward " \r\t\n")
|
||||
(line-beginning-position)))))
|
||||
((not rep)
|
||||
;; Replacement code cannot be determined.
|
||||
;; Leave the code block as is.
|
||||
(goto-char end))
|
||||
(t
|
||||
;; Otherwise, preserve trailing
|
||||
;; spaces/newlines and then, insert
|
||||
;; replacement string.
|
||||
(goto-char begin)
|
||||
(delete-region begin end)
|
||||
(insert rep)))))
|
||||
(`src-block
|
||||
(let ((match-start (copy-marker (match-beginning 0)))
|
||||
(ind (org-current-text-indentation)))
|
||||
;; Take care of matched block: compute
|
||||
;; replacement string. In particular, a nil
|
||||
;; REPLACEMENT means the block is left as-is
|
||||
;; while an empty string removes the block.
|
||||
(let ((replacement
|
||||
(progn (goto-char match-start)
|
||||
(org-babel-exp-src-block element))))
|
||||
(cond ((not replacement) (goto-char end))
|
||||
((equal replacement "")
|
||||
(goto-char end)
|
||||
(skip-chars-forward " \r\t\n")
|
||||
(forward-line 0)
|
||||
(delete-region begin (point)))
|
||||
(t
|
||||
(if (org-src-preserve-indentation-p element)
|
||||
;; Indent only code block
|
||||
;; markers.
|
||||
(with-temp-buffer
|
||||
;; Do not use tabs for block
|
||||
;; indentation.
|
||||
(when (fboundp 'indent-tabs-mode)
|
||||
(indent-tabs-mode -1)
|
||||
;; FIXME: Emacs 26
|
||||
;; compatibility.
|
||||
(setq-local indent-tabs-mode nil))
|
||||
(insert replacement)
|
||||
(skip-chars-backward " \r\t\n")
|
||||
(indent-line-to ind)
|
||||
(goto-char 1)
|
||||
(indent-line-to ind)
|
||||
(setq replacement (buffer-string)))
|
||||
;; Indent everything.
|
||||
(with-temp-buffer
|
||||
;; Do not use tabs for block
|
||||
;; indentation.
|
||||
(when (fboundp 'indent-tabs-mode)
|
||||
(indent-tabs-mode -1)
|
||||
;; FIXME: Emacs 26
|
||||
;; compatibility.
|
||||
(setq-local indent-tabs-mode nil))
|
||||
(insert replacement)
|
||||
(indent-rigidly
|
||||
1 (point) ind)
|
||||
(setq replacement (buffer-string))))
|
||||
(goto-char match-start)
|
||||
(let ((rend (save-excursion
|
||||
(goto-char end)
|
||||
(line-end-position))))
|
||||
(if (string-equal replacement
|
||||
(buffer-substring match-start rend))
|
||||
(goto-char rend)
|
||||
(delete-region match-start
|
||||
(save-excursion
|
||||
(goto-char end)
|
||||
(line-end-position)))
|
||||
(insert replacement))))))
|
||||
(set-marker match-start nil))))
|
||||
(set-marker begin nil)
|
||||
(set-marker end nil))))))
|
||||
(kill-buffer org-babel-exp-reference-buffer)
|
||||
(remove-text-properties (point-min) (point-max)
|
||||
'(org-reference nil))))))
|
||||
|
||||
(defun org-babel-exp-do-export (info type &optional hash)
|
||||
"Return a string with the exported content of a code block.
|
||||
"Return a string with the exported content of a code block defined by INFO.
|
||||
TYPE is the code block type: `block', `inline', or `lob'. HASH is the
|
||||
result hash.
|
||||
|
||||
Return nil when exported content cannot be determined.
|
||||
|
||||
The function respects the value of the :exports header argument."
|
||||
(let ((silently (lambda () (let ((session (cdr (assq :session (nth 2 info)))))
|
||||
(unless (equal "none" session)
|
||||
(org-babel-exp-results info type 'silent)))))
|
||||
(unless (equal "none" session)
|
||||
(org-babel-exp-results info type 'silent)))))
|
||||
(clean (lambda () (if (eq type 'inline)
|
||||
(org-babel-remove-inline-result)
|
||||
(org-babel-remove-result info)))))
|
||||
(org-babel-remove-inline-result)
|
||||
(org-babel-remove-result info)))))
|
||||
(pcase (or (cdr (assq :exports (nth 2 info))) "code")
|
||||
("none" (funcall silently) (funcall clean) "")
|
||||
("code" (funcall silently) (funcall clean) (org-babel-exp-code info type))
|
||||
("results" (org-babel-exp-results info type nil hash) "")
|
||||
("both"
|
||||
(org-babel-exp-results info type nil hash)
|
||||
(org-babel-exp-code info type)))))
|
||||
(org-babel-exp-code info type))
|
||||
(unknown-value
|
||||
(warn "Unknown value of src block parameter :exports %S" unknown-value)
|
||||
nil))))
|
||||
|
||||
(defcustom org-babel-exp-code-template
|
||||
"#+begin_src %lang%switches%flags\n%body\n#+end_src"
|
||||
"#+begin_src %lang%switches%header-args\n%body\n#+end_src"
|
||||
"Template used to export the body of code blocks.
|
||||
This template may be customized to include additional information
|
||||
such as the code block name, or the values of particular header
|
||||
|
@ -361,17 +381,17 @@ and the following %keys may be used.
|
|||
name ------ the name of the code block
|
||||
body ------ the body of the code block
|
||||
switches -- the switches associated to the code block
|
||||
flags ----- the flags passed to the code block
|
||||
header-args the header arguments of the code block
|
||||
|
||||
In addition to the keys mentioned above, every header argument
|
||||
defined for the code block may be used as a key and will be
|
||||
replaced with its value."
|
||||
:group 'org-babel
|
||||
:type 'string
|
||||
:package-version '(Org . "9.6"))
|
||||
:package-version '(Org . "9.7"))
|
||||
|
||||
(defcustom org-babel-exp-inline-code-template
|
||||
"src_%lang[%switches%flags]{%body}"
|
||||
"src_%lang[%switches%header-args]{%body}"
|
||||
"Template used to export the body of inline code blocks.
|
||||
This template may be customized to include additional information
|
||||
such as the code block name, or the values of particular header
|
||||
|
@ -382,18 +402,17 @@ and the following %keys may be used.
|
|||
name ------ the name of the code block
|
||||
body ------ the body of the code block
|
||||
switches -- the switches associated to the code block
|
||||
flags ----- the flags passed to the code block
|
||||
header-args the header arguments of the code block
|
||||
|
||||
In addition to the keys mentioned above, every header argument
|
||||
defined for the code block may be used as a key and will be
|
||||
replaced with its value."
|
||||
:group 'org-babel
|
||||
:type 'string
|
||||
:version "26.1"
|
||||
:package-version '(Org . "8.3"))
|
||||
:package-version '(Org . "9.7"))
|
||||
|
||||
(defun org-babel-exp-code (info type)
|
||||
"Return the original code block formatted for export."
|
||||
"Return the original code block of TYPE defined by INFO, formatted for export."
|
||||
(setf (nth 1 info)
|
||||
(if (string= "strip-export" (cdr (assq :noweb (nth 2 info))))
|
||||
(replace-regexp-in-string
|
||||
|
@ -415,6 +434,11 @@ replaced with its value."
|
|||
(and (org-string-nw-p f) (concat " " f))))
|
||||
("flags" . ,(let ((f (assq :flags (nth 2 info))))
|
||||
(and f (concat " " (cdr f)))))
|
||||
("header-args"
|
||||
.
|
||||
,(org-babel-exp--at-source
|
||||
(when-let ((params (org-element-property :parameters (org-element-context))))
|
||||
(concat " " params))))
|
||||
,@(mapcar (lambda (pair)
|
||||
(cons (substring (symbol-name (car pair)) 1)
|
||||
(format "%S" (cdr pair))))
|
||||
|
@ -423,6 +447,9 @@ replaced with its value."
|
|||
|
||||
(defun org-babel-exp-results (info type &optional silent hash)
|
||||
"Evaluate and return the results of the current code block for export.
|
||||
INFO is as returned by `org-babel-get-src-block-info'. TYPE is the
|
||||
code block type. HASH is the result hash.
|
||||
|
||||
Results are prepared in a manner suitable for export by Org mode.
|
||||
This function is called by `org-babel-exp-do-export'. The code
|
||||
block will be evaluated. Optional argument SILENT can be used to
|
||||
|
@ -436,7 +463,8 @@ inhibit insertion of results into the buffer."
|
|||
(info (copy-sequence info))
|
||||
(org-babel-current-src-block-location (point-marker)))
|
||||
;; Skip code blocks which we can't evaluate.
|
||||
(when (fboundp (intern (concat "org-babel-execute:" lang)))
|
||||
(if (not (fboundp (intern (concat "org-babel-execute:" lang))))
|
||||
(warn "org-export: No org-babel-execute function for %s. Not updating exported results." lang)
|
||||
(org-babel-eval-wipe-error-buffer)
|
||||
(setf (nth 1 info) body)
|
||||
(setf (nth 2 info)
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
"Default header arguments for forth code blocks.")
|
||||
|
||||
(defun org-babel-execute:forth (body params)
|
||||
"Execute a block of Forth code with org-babel.
|
||||
"Execute Forth BODY according to PARAMS.
|
||||
This function is called by `org-babel-execute-src-block'."
|
||||
(if (string= "none" (cdr (assq :session params)))
|
||||
(error "Non-session evaluation not supported for Forth code blocks")
|
||||
|
@ -55,7 +55,8 @@ This function is called by `org-babel-execute-src-block'."
|
|||
(car (last all-results))))))
|
||||
|
||||
(defun org-babel-forth-session-execute (body params)
|
||||
(require 'forth-mode)
|
||||
"Execute Forth BODY in session defined via PARAMS."
|
||||
(org-require-package 'forth-mode)
|
||||
(let ((proc (forth-proc))
|
||||
(rx " \\(\n:\\|compiled\n\\|ok\n\\)")
|
||||
(result-start))
|
||||
|
|
|
@ -51,7 +51,8 @@
|
|||
:type 'string)
|
||||
|
||||
(defun org-babel-execute:fortran (body params)
|
||||
"This function should only be called by `org-babel-execute:fortran'."
|
||||
"Execute Fortran BODY according to PARAMS.
|
||||
This function is called by `org-babel-execute-src-block'."
|
||||
(let* ((tmp-src-file (org-babel-temp-file "fortran-src-" ".F90"))
|
||||
(tmp-bin-file (org-babel-temp-file "fortran-bin-" org-babel-exeext))
|
||||
(cmdline (cdr (assq :cmdline params)))
|
||||
|
@ -82,9 +83,10 @@
|
|||
(cdr (assq :rowname-names params)) (cdr (assq :rownames params)))))))
|
||||
|
||||
(defun org-babel-expand-body:fortran (body params)
|
||||
"Expand a block of fortran or fortran code with org-babel according to
|
||||
its header arguments."
|
||||
"Expand a fortran BODY according to its header arguments defined in PARAMS."
|
||||
(let ((vars (org-babel--get-vars params))
|
||||
(prologue (cdr (assq :prologue params)))
|
||||
(epilogue (cdr (assq :epilogue params)))
|
||||
(main-p (not (string= (cdr (assq :main params)) "no")))
|
||||
(includes (or (cdr (assq :includes params))
|
||||
(org-babel-read (org-entry-get nil "includes" t))))
|
||||
|
@ -107,12 +109,20 @@ its header arguments."
|
|||
(concat
|
||||
;; variables
|
||||
(mapconcat 'org-babel-fortran-var-to-fortran vars "\n")
|
||||
body)
|
||||
(and prologue (concat prologue "\n"))
|
||||
body
|
||||
(and prologue (concat prologue "\n")))
|
||||
params)
|
||||
body) "\n") "\n")))
|
||||
(concat
|
||||
(and prologue (concat prologue "\n"))
|
||||
body
|
||||
(and epilogue (concat "\n" epilogue "\n"))))
|
||||
"\n")
|
||||
"\n")))
|
||||
|
||||
(defun org-babel-fortran-ensure-main-wrap (body params)
|
||||
"Wrap body in a \"program ... end program\" block if none exists."
|
||||
"Wrap BODY in a \"program ... end program\" block if none exists.
|
||||
Variable assignments are derived from PARAMS."
|
||||
(if (string-match "^[ \t]*program\\>" (capitalize body))
|
||||
(let ((vars (org-babel--get-vars params)))
|
||||
(when vars (error "Cannot use :vars if `program' statement is present"))
|
||||
|
@ -120,20 +130,22 @@ its header arguments."
|
|||
(format "program main\n%s\nend program main\n" body)))
|
||||
|
||||
(defun org-babel-prep-session:fortran (_session _params)
|
||||
"This function does nothing as fortran is a compiled language with no
|
||||
"Do nothing.
|
||||
This function does nothing as fortran is a compiled language with no
|
||||
support for sessions."
|
||||
(error "Fortran is a compiled languages -- no support for sessions"))
|
||||
|
||||
(defun org-babel-load-session:fortran (_session _body _params)
|
||||
"This function does nothing as fortran is a compiled language with no
|
||||
"Do nothing.
|
||||
This function does nothing as fortran is a compiled language with no
|
||||
support for sessions."
|
||||
(error "Fortran is a compiled languages -- no support for sessions"))
|
||||
|
||||
;; helper functions
|
||||
|
||||
(defun org-babel-fortran-var-to-fortran (pair)
|
||||
"Convert an elisp val into a string of fortran code specifying a var
|
||||
of the same value."
|
||||
"Convert PAIR of (VAR . VAL) into a string of fortran code.
|
||||
The fortran code will assign VAL to VAR variable."
|
||||
;; TODO list support
|
||||
(let ((var (car pair))
|
||||
(val (cdr pair)))
|
||||
|
@ -164,7 +176,7 @@ of the same value."
|
|||
(error "The type of parameter %s is not supported by ob-fortran" var)))))
|
||||
|
||||
(defun org-babel-fortran-transform-list (val)
|
||||
"Return a fortran representation of enclose syntactic lists."
|
||||
"Return a fortran representation of enclose syntactic list VAL."
|
||||
(if (listp val)
|
||||
(concat "(/" (mapconcat #'org-babel-fortran-transform-list val ", ") "/)")
|
||||
(format "%S" val)))
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
;; Copyright (C) 2009-2024 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric Schulte
|
||||
;; Maintainer: Ihor Radchenko <yantar92@gmail.com>
|
||||
;; Maintainer: Ihor Radchenko <yantar92 at posteo dot net>
|
||||
;; Keywords: literate programming, reproducible research
|
||||
;; URL: https://orgmode.org
|
||||
|
||||
|
@ -45,6 +45,7 @@
|
|||
|
||||
(require 'ob)
|
||||
(require 'org-macs)
|
||||
(require 'ox-ascii)
|
||||
|
||||
(declare-function org-time-string-to-time "org" (s))
|
||||
(declare-function orgtbl-to-generic "org-table" (table params))
|
||||
|
@ -186,7 +187,7 @@ code."
|
|||
;; value of the variable
|
||||
(mapc (lambda (pair)
|
||||
(setq body (replace-regexp-in-string
|
||||
(format "\\$%s" (car pair)) (cdr pair) body)))
|
||||
(format "\\$%s" (car pair)) (cdr pair) body t t)))
|
||||
vars)
|
||||
(when prologue (funcall add-to-body prologue))
|
||||
(when epilogue (setq body (concat body "\n" epilogue)))
|
||||
|
@ -196,9 +197,9 @@ code."
|
|||
body))
|
||||
|
||||
(defun org-babel-execute:gnuplot (body params)
|
||||
"Execute a block of Gnuplot code.
|
||||
"Execute Gnuplot BODY according to PARAMS.
|
||||
This function is called by `org-babel-execute-src-block'."
|
||||
(require 'gnuplot)
|
||||
(org-require-package 'gnuplot)
|
||||
(let ((session (cdr (assq :session params)))
|
||||
(result-type (cdr (assq :results params)))
|
||||
(body (org-babel-expand-body:gnuplot body params))
|
||||
|
@ -251,7 +252,8 @@ This function is called by `org-babel-execute-src-block'."
|
|||
buffer)))
|
||||
|
||||
(defun org-babel-variable-assignments:gnuplot (params)
|
||||
"Return list of gnuplot statements assigning the block's variables."
|
||||
"Return list of gnuplot statements assigning the block's variables.
|
||||
PARAMS is src block parameters alist defining variable assignments."
|
||||
(mapcar
|
||||
(lambda (pair) (format "%s = \"%s\"" (car pair) (cdr pair)))
|
||||
(org-babel-gnuplot-process-vars params)))
|
||||
|
@ -262,7 +264,7 @@ This function is called by `org-babel-execute-src-block'."
|
|||
If there is not a current inferior-process-buffer in SESSION
|
||||
then create one. Return the initialized session. The current
|
||||
`gnuplot-mode' doesn't provide support for multiple sessions."
|
||||
(require 'gnuplot)
|
||||
(org-require-package 'gnuplot)
|
||||
(unless (string= session "none")
|
||||
(save-window-excursion
|
||||
(gnuplot-send-string-to-gnuplot "" "line")
|
||||
|
@ -295,14 +297,29 @@ Pass PARAMS through to `orgtbl-to-generic' when exporting TABLE."
|
|||
(require 'ox-org)
|
||||
(with-temp-file data-file
|
||||
(insert (let ((org-babel-gnuplot-timestamp-fmt
|
||||
(or (plist-get params :timefmt) "%Y-%m-%d-%H:%M:%S")))
|
||||
(or (plist-get params :timefmt) "%Y-%m-%d-%H:%M:%S"))
|
||||
;; Create custom limited backend that will disable
|
||||
;; advanced ASCII export features that may alter the
|
||||
;; original data.
|
||||
(ob-gnuplot-data
|
||||
(org-export-create-backend
|
||||
:parent 'ascii
|
||||
:transcoders
|
||||
`(;; Do not try to resolve links. Export them verbatim.
|
||||
(link . (lambda (link _ _) (org-element-interpret-data link)))
|
||||
;; Drop emphasis markers from verbatim and code.
|
||||
;; This way, data can use verbatim when escaping
|
||||
;; is necessary and yet be readable by Gnuplot,
|
||||
;; which is not aware about Org's markup.
|
||||
(verbatim . (lambda (verbatim _ _) (org-element-property :value verbatim)))
|
||||
(code . (lambda (code _ _) (org-element-property :value code)))))))
|
||||
(orgtbl-to-generic
|
||||
table
|
||||
(org-combine-plists
|
||||
'( :sep "\t" :fmt org-babel-gnuplot-quote-tsv-field
|
||||
`( :sep "\t" :fmt org-babel-gnuplot-quote-tsv-field
|
||||
;; Two setting below are needed to make :fmt work.
|
||||
:raw t
|
||||
:backend ascii)
|
||||
:backend ,ob-gnuplot-data)
|
||||
params)))))
|
||||
data-file)
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ parameters may be used, like groovy -v"
|
|||
:type 'string)
|
||||
|
||||
(defun org-babel-execute:groovy (body params)
|
||||
"Execute a block of Groovy code with org-babel.
|
||||
"Execute Groovy BODY according to PARAMS.
|
||||
This function is called by `org-babel-execute-src-block'."
|
||||
(message "Executing Groovy source code block")
|
||||
(let* ((processed-params (org-babel-process-params params))
|
||||
|
@ -81,6 +81,7 @@ println(new Runner().run())
|
|||
(defun org-babel-groovy-evaluate
|
||||
(session body &optional result-type result-params)
|
||||
"Evaluate BODY in external Groovy process.
|
||||
SESSION must be nil as sessions are not yet supported.
|
||||
If RESULT-TYPE equals `output' then return standard output as a string.
|
||||
If RESULT-TYPE equals `value' then return the value of the last statement
|
||||
in BODY as elisp."
|
||||
|
@ -107,9 +108,8 @@ in BODY as elisp."
|
|||
(error "Sessions are not (yet) supported for Groovy"))
|
||||
|
||||
(defun org-babel-groovy-initiate-session (&optional _session)
|
||||
"If there is not a current inferior-process-buffer in SESSION
|
||||
then create. Return the initialized session. Sessions are not
|
||||
supported in Groovy."
|
||||
"Do nothing.
|
||||
Sessions are not supported in Groovy."
|
||||
nil)
|
||||
|
||||
(provide 'ob-groovy)
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
|
||||
(defvar org-babel-haskell-lhs2tex-command "lhs2tex")
|
||||
|
||||
(defvar org-babel-haskell-eoe "\"org-babel-haskell-eoe\"")
|
||||
(defvar org-babel-haskell-eoe "org-babel-haskell-eoe")
|
||||
|
||||
(defvar haskell-prompt-regexp)
|
||||
|
||||
|
@ -77,8 +77,35 @@ a parameter, such as \"ghc -v\"."
|
|||
(defconst org-babel-header-args:haskell '((compile . :any))
|
||||
"Haskell-specific header arguments.")
|
||||
|
||||
|
||||
(defun org-babel-haskell-with-session--worker (params todo)
|
||||
"See `org-babel-haskell-with-session'."
|
||||
(let* ((sn (cdr (assq :session params)))
|
||||
(session (org-babel-haskell-initiate-session sn params))
|
||||
(one-shot (equal sn "none")))
|
||||
(unwind-protect
|
||||
(funcall todo session)
|
||||
(when (and one-shot (buffer-live-p session))
|
||||
;; As we don't control how the session temporary buffer is
|
||||
;; created, we need to explicitly work around the hooks and
|
||||
;; query functions.
|
||||
(with-current-buffer session
|
||||
(let ((kill-buffer-query-functions nil)
|
||||
(kill-buffer-hook nil))
|
||||
(kill-buffer session)))))))
|
||||
|
||||
(defmacro org-babel-haskell-with-session (session-symbol params &rest body)
|
||||
"Get the session identified by PARAMS and run BODY with it.
|
||||
|
||||
Get or create a session, as needed to match PARAMS. Assign the session to
|
||||
SESSION-SYMBOL. Execute BODY. Destroy the session if needed.
|
||||
Return the value of the last form of BODY."
|
||||
(declare (indent 2) (debug (symbolp form body)))
|
||||
`(org-babel-haskell-with-session--worker ,params (lambda (,session-symbol) ,@body)))
|
||||
|
||||
(defun org-babel-haskell-execute (body params)
|
||||
"This function should only be called by `org-babel-execute:haskell'."
|
||||
"Execute Haskell BODY according to PARAMS.
|
||||
This function should only be called by `org-babel-execute:haskell'."
|
||||
(let* ((tmp-src-file (org-babel-temp-file "Haskell-src-" ".hs"))
|
||||
(tmp-bin-file
|
||||
(org-babel-process-file-name
|
||||
|
@ -122,39 +149,63 @@ a parameter, such as \"ghc -v\"."
|
|||
(cdr (assq :rowname-names params)) (cdr (assq :rownames params))))))))
|
||||
|
||||
(defun org-babel-interpret-haskell (body params)
|
||||
(require 'inf-haskell)
|
||||
(org-require-package 'inf-haskell "haskell-mode")
|
||||
(add-hook 'inferior-haskell-hook
|
||||
(lambda ()
|
||||
(setq-local comint-prompt-regexp
|
||||
(concat haskell-prompt-regexp "\\|^λ?> "))))
|
||||
(let* ((session (cdr (assq :session params)))
|
||||
(result-type (cdr (assq :result-type params)))
|
||||
(full-body (org-babel-expand-body:generic
|
||||
body params
|
||||
(org-babel-variable-assignments:haskell params)))
|
||||
(session (org-babel-haskell-initiate-session session params))
|
||||
(comint-preoutput-filter-functions
|
||||
(cons 'ansi-color-filter-apply comint-preoutput-filter-functions))
|
||||
(raw (org-babel-comint-with-output
|
||||
(session org-babel-haskell-eoe nil full-body)
|
||||
(insert (org-trim full-body))
|
||||
(comint-send-input nil t)
|
||||
(insert org-babel-haskell-eoe)
|
||||
(comint-send-input nil t)))
|
||||
(results (mapcar #'org-strip-quotes
|
||||
(cdr (member org-babel-haskell-eoe
|
||||
(reverse (mapcar #'org-trim raw)))))))
|
||||
(org-babel-reassemble-table
|
||||
(let ((result
|
||||
(pcase result-type
|
||||
(`output (mapconcat #'identity (reverse results) "\n"))
|
||||
(`value (car results)))))
|
||||
(org-babel-result-cond (cdr (assq :result-params params))
|
||||
result (when result (org-babel-script-escape result))))
|
||||
(org-babel-pick-name (cdr (assq :colname-names params))
|
||||
(cdr (assq :colname-names params)))
|
||||
(org-babel-pick-name (cdr (assq :rowname-names params))
|
||||
(cdr (assq :rowname-names params))))))
|
||||
(setq-local
|
||||
org-babel-comint-prompt-regexp-old comint-prompt-regexp
|
||||
comint-prompt-regexp
|
||||
(concat haskell-prompt-regexp "\\|^λ?> "))))
|
||||
(org-babel-haskell-with-session session params
|
||||
(cl-labels
|
||||
((send-txt-to-ghci (txt)
|
||||
(insert txt) (comint-send-input nil t))
|
||||
(send-eoe ()
|
||||
(send-txt-to-ghci (concat "putStrLn \"" org-babel-haskell-eoe "\"\n")))
|
||||
(comint-with-output (todo)
|
||||
(let ((comint-preoutput-filter-functions
|
||||
(cons 'ansi-color-filter-apply
|
||||
comint-preoutput-filter-functions)))
|
||||
(org-babel-comint-with-output
|
||||
(session org-babel-haskell-eoe nil nil)
|
||||
(funcall todo)))))
|
||||
(let* ((result-type (cdr (assq :result-type params)))
|
||||
(full-body (org-babel-expand-body:generic
|
||||
body params
|
||||
(org-babel-variable-assignments:haskell params)))
|
||||
(raw (pcase result-type
|
||||
(`output
|
||||
(comint-with-output
|
||||
(lambda () (send-txt-to-ghci (org-trim full-body)) (send-eoe))))
|
||||
(`value
|
||||
;; We first compute the value and store it,
|
||||
;; ignoring any output.
|
||||
(comint-with-output
|
||||
(lambda ()
|
||||
(send-txt-to-ghci "__LAST_VALUE_IMPROBABLE_NAME__=()::()\n")
|
||||
(send-txt-to-ghci (org-trim full-body))
|
||||
(send-txt-to-ghci "__LAST_VALUE_IMPROBABLE_NAME__=it\n")
|
||||
(send-eoe)))
|
||||
;; We now display and capture the value.
|
||||
(comint-with-output
|
||||
(lambda()
|
||||
(send-txt-to-ghci "__LAST_VALUE_IMPROBABLE_NAME__\n")
|
||||
(send-eoe))))))
|
||||
(results (mapcar #'org-strip-quotes
|
||||
(cdr (member org-babel-haskell-eoe
|
||||
(reverse (mapcar #'org-trim raw)))))))
|
||||
(org-babel-reassemble-table
|
||||
(let ((result
|
||||
(pcase result-type
|
||||
(`output (mapconcat #'identity (reverse results) "\n"))
|
||||
(`value (car results)))))
|
||||
(org-babel-result-cond (cdr (assq :result-params params))
|
||||
result (when result (org-babel-script-escape result))))
|
||||
(org-babel-pick-name (cdr (assq :colname-names params))
|
||||
(cdr (assq :colname-names params)))
|
||||
(org-babel-pick-name (cdr (assq :rowname-names params))
|
||||
(cdr (assq :rowname-names params))))))))
|
||||
|
||||
|
||||
(defun org-babel-execute:haskell (body params)
|
||||
"Execute a block of Haskell code."
|
||||
|
@ -163,13 +214,65 @@ a parameter, such as \"ghc -v\"."
|
|||
(org-babel-interpret-haskell body params)
|
||||
(org-babel-haskell-execute body params))))
|
||||
|
||||
(defun org-babel-haskell-initiate-session (&optional _session _params)
|
||||
|
||||
|
||||
|
||||
;; Variable defined in inf-haskell (haskell-mode package).
|
||||
(defvar inferior-haskell-buffer)
|
||||
(defvar inferior-haskell-root-dir)
|
||||
|
||||
(defun org-babel-haskell-initiate-session (&optional session-name _params)
|
||||
"Initiate a haskell session.
|
||||
If there is not a current inferior-process-buffer in SESSION
|
||||
then create one. Return the initialized session."
|
||||
(require 'inf-haskell)
|
||||
(or (get-buffer "*haskell*")
|
||||
(save-window-excursion (run-haskell) (sleep-for 0.25) (current-buffer))))
|
||||
Return the initialized session, i.e. the buffer for this session.
|
||||
When SESSION-NAME is nil, use a global session named
|
||||
\"*ob-haskell*\". When SESSION-NAME is the string \"none\", use
|
||||
a temporary buffer. Else, (re)use the session named
|
||||
SESSION-NAME. The buffer name is the session name. See also
|
||||
`org-babel-haskell-with-session'."
|
||||
(org-require-package 'inf-haskell "haskell-mode")
|
||||
(cond
|
||||
((equal "none" session-name)
|
||||
;; Temporary buffer name.
|
||||
(setq session-name (generate-new-buffer-name " *ob-haskell-tmp*")))
|
||||
((eq nil session-name)
|
||||
;; The global default session. As haskell-mode is using the buffer
|
||||
;; named "*haskell*", we stay away from it.
|
||||
(setq session-name "*ob-haskell*"))
|
||||
((not (stringp session-name))
|
||||
(error "session-name must be a string")))
|
||||
(let ((session (get-buffer session-name)))
|
||||
;; NOTE: By construction, as SESSION-NAME is a string, session is
|
||||
;; either nil or a live buffer.
|
||||
(save-window-excursion
|
||||
(or (org-babel-comint-buffer-livep session)
|
||||
(let ((inferior-haskell-buffer session))
|
||||
;; As inferior-haskell expects the buffer to be named
|
||||
;; "*haskell*", we temporarily rename it while executing
|
||||
;; `run-haskell' (unless the user explicitly requested to
|
||||
;; use the name "*haskell*").
|
||||
(when (not (equal "*haskell*" session-name))
|
||||
(when (bufferp session)
|
||||
(when (bufferp "*haskell*")
|
||||
(user-error "Conflicting buffer '*haskell*', rename it or kill it"))
|
||||
(with-current-buffer session (rename-buffer "*haskell*"))))
|
||||
(unwind-protect
|
||||
(let ((inferior-haskell-root-dir default-directory))
|
||||
(run-haskell)
|
||||
(sleep-for 0.25)
|
||||
(setq session inferior-haskell-buffer))
|
||||
(when (and (not (equal "*haskell*" session-name))
|
||||
(bufferp session))
|
||||
(with-current-buffer session (rename-buffer session-name))))
|
||||
;; Disable secondary prompt: If we do not do this,
|
||||
;; org-comint may treat secondary prompts as a part of
|
||||
;; output.
|
||||
(org-babel-comint-input-command
|
||||
session
|
||||
":set prompt-cont \"\"")
|
||||
session)
|
||||
))
|
||||
session))
|
||||
|
||||
|
||||
(defun org-babel-load-session:haskell (session body params)
|
||||
"Load BODY into SESSION."
|
||||
|
@ -226,7 +329,7 @@ constructs (header arguments, no-web syntax etc...) are ignored."
|
|||
(let* ((contents (buffer-string))
|
||||
(haskell-regexp
|
||||
(concat "^\\([ \t]*\\)#\\+begin_src[ \t]haskell*\\(.*\\)[\r\n]"
|
||||
"\\([^\000]*?\\)[\r\n][ \t]*#\\+end_src.*"))
|
||||
"\\(\\(?:.\\|\n\\)*?\\)[\r\n][ \t]*#\\+end_src.*"))
|
||||
(base-name (file-name-sans-extension (buffer-file-name)))
|
||||
(tmp-file (org-babel-temp-file "haskell-"))
|
||||
(tmp-org-file (concat tmp-file ".org"))
|
||||
|
@ -255,26 +358,27 @@ constructs (header arguments, no-web syntax etc...) are ignored."
|
|||
t t)
|
||||
(indent-code-rigidly (match-beginning 0) (match-end 0) indentation)))
|
||||
(save-excursion
|
||||
;; export to latex w/org and save as .lhs
|
||||
(require 'ox-latex)
|
||||
(find-file tmp-org-file)
|
||||
;; Ensure we do not clutter kill ring with incomplete results.
|
||||
(let (org-export-copy-to-kill-ring)
|
||||
(org-export-to-file 'latex tmp-tex-file))
|
||||
(kill-buffer nil)
|
||||
(delete-file tmp-org-file)
|
||||
(find-file tmp-tex-file)
|
||||
(goto-char (point-min)) (forward-line 2)
|
||||
(insert "%include polycode.fmt\n")
|
||||
;; ensure all \begin/end{code} statements start at the first column
|
||||
(while (re-search-forward "^[ \t]+\\\\begin{code}[^\000]+\\\\end{code}" nil t)
|
||||
(replace-match (save-match-data (org-remove-indentation (match-string 0)))
|
||||
t t))
|
||||
(setq contents (buffer-string))
|
||||
(save-buffer) (kill-buffer nil))
|
||||
(delete-file tmp-tex-file)
|
||||
;; save org exported latex to a .lhs file
|
||||
(with-temp-file lhs-file (insert contents))
|
||||
(unwind-protect
|
||||
(with-temp-buffer
|
||||
;; Export to latex w/org and save as .lhs
|
||||
(require 'ox-latex)
|
||||
(insert-file-contents tmp-org-file)
|
||||
;; Ensure we do not clutter kill ring with incomplete results.
|
||||
(let (org-export-copy-to-kill-ring)
|
||||
(org-export-to-file 'latex tmp-tex-file)))
|
||||
(delete-file tmp-org-file))
|
||||
(unwind-protect
|
||||
(with-temp-buffer
|
||||
(insert-file-contents tmp-tex-file)
|
||||
(goto-char (point-min)) (forward-line 2)
|
||||
(insert "%include polycode.fmt\n")
|
||||
;; ensure all \begin/end{code} statements start at the first column
|
||||
(while (re-search-forward "^[ \t]+\\\\begin{code}\\(?:.\\|\n\\)+\\\\end{code}" nil t)
|
||||
(replace-match (save-match-data (org-remove-indentation (match-string 0)))
|
||||
t t))
|
||||
;; save org exported latex to a .lhs file
|
||||
(write-region nil nil lhs-file))
|
||||
(delete-file tmp-tex-file)))
|
||||
(if (not arg)
|
||||
(find-file lhs-file)
|
||||
;; process .lhs file with lhs2tex
|
||||
|
|
|
@ -341,9 +341,13 @@ is simplest to expand the code block from the inside out."
|
|||
(imports-val (assq :imports params))
|
||||
(imports (if imports-val
|
||||
(split-string (org-babel-read (cdr imports-val) nil) " ")
|
||||
nil)))
|
||||
nil))
|
||||
(prologue (cdr (assq :prologue params)))
|
||||
(epilogue (cdr (assq :epilogue params))))
|
||||
(with-temp-buffer
|
||||
(when prologue (insert prologue "\n"))
|
||||
(insert body)
|
||||
(when epilogue (insert "\n" epilogue))
|
||||
|
||||
;; wrap main. If there are methods defined, but no main method
|
||||
;; and no class, wrap everything in a generic main method.
|
||||
|
|
|
@ -76,7 +76,7 @@
|
|||
"Javascript code to print value of body.")
|
||||
|
||||
(defun org-babel-execute:js (body params)
|
||||
"Execute a block of Javascript code with org-babel.
|
||||
"Execute Javascript BODY according to PARAMS.
|
||||
This function is called by `org-babel-execute-src-block'."
|
||||
(let* ((org-babel-js-cmd (or (cdr (assq :cmd params)) org-babel-js-cmd))
|
||||
(session (cdr (assq :session params)))
|
||||
|
@ -99,7 +99,7 @@ This function is called by `org-babel-execute-src-block'."
|
|||
;; Indium Node REPL. Separate case because Indium
|
||||
;; REPL is not inherited from Comint mode.
|
||||
((string= session "*JS REPL*")
|
||||
(require 'indium-repl)
|
||||
(org-require-package 'indium-repl "indium")
|
||||
(unless (get-buffer session)
|
||||
(indium-run-node org-babel-js-cmd))
|
||||
(indium-eval full-body))
|
||||
|
@ -158,7 +158,8 @@ specifying a variable of the same value."
|
|||
session))
|
||||
|
||||
(defun org-babel-variable-assignments:js (params)
|
||||
"Return list of Javascript statements assigning the block's variables."
|
||||
"Return list of Javascript statements assigning the block's variables.
|
||||
The variables are defined in PARAMS."
|
||||
(mapcar
|
||||
(lambda (pair) (format "var %s=%s;"
|
||||
(car pair) (org-babel-js-var-to-js (cdr pair))))
|
||||
|
@ -171,7 +172,7 @@ Return the initialized session."
|
|||
((string= session "none")
|
||||
(warn "Session evaluation of ob-js is not supported"))
|
||||
((string= "*skewer-repl*" session)
|
||||
(require 'skewer-repl)
|
||||
(org-require-package 'skewer-repl "skewer-mode")
|
||||
(let ((session-buffer (get-buffer "*skewer-repl*")))
|
||||
(if (and session-buffer
|
||||
(org-babel-comint-buffer-livep (get-buffer session-buffer))
|
||||
|
@ -183,7 +184,7 @@ Return the initialized session."
|
|||
(skewer-repl)
|
||||
session-buffer)))
|
||||
((string= "*Javascript REPL*" session)
|
||||
(require 'js-comint)
|
||||
(org-require-package 'js-comint)
|
||||
(let ((session-buffer "*Javascript REPL*"))
|
||||
(if (and (org-babel-comint-buffer-livep (get-buffer session-buffer))
|
||||
(comint-check-proc session-buffer))
|
||||
|
@ -192,7 +193,9 @@ Return the initialized session."
|
|||
(sit-for .5)
|
||||
session-buffer)))
|
||||
((string= "mozrepl" org-babel-js-cmd)
|
||||
(require 'moz)
|
||||
;; FIXME: According to https://github.com/bard/mozrepl, this REPL
|
||||
;; is outdated and does not work for Firefox >54.
|
||||
(org-require-package 'moz "mozrepl")
|
||||
(let ((session-buffer (save-window-excursion
|
||||
(run-mozilla nil)
|
||||
(rename-buffer session)
|
||||
|
|
|
@ -70,12 +70,15 @@
|
|||
(defvar ess-local-process-name) ; dynamically scoped
|
||||
(defvar ess-eval-visibly-p) ; dynamically scoped
|
||||
(defvar ess-local-customize-alist); dynamically scoped
|
||||
(defun org-babel-edit-prep:julia (info)
|
||||
(let ((session (cdr (assq :session (nth 2 info)))))
|
||||
(when (and session
|
||||
(string-prefix-p "*" session)
|
||||
(string-suffix-p "*" session))
|
||||
(org-babel-julia-initiate-session session nil))))
|
||||
(defvar ess-gen-proc-buffer-name-function) ; defined in ess-inf.el
|
||||
(defun org-babel-julia-associate-session (session)
|
||||
"Associate R code buffer with an R session.
|
||||
Make SESSION be the inferior ESS process associated with the
|
||||
current code buffer."
|
||||
(when-let ((process (get-buffer-process session)))
|
||||
(setq ess-local-process-name (process-name process))
|
||||
(ess-make-buffer-current))
|
||||
(setq-local ess-gen-proc-buffer-name-function (lambda (_) session)))
|
||||
|
||||
(defun org-babel-expand-body:julia (body params &optional _graphics-file)
|
||||
"Expand BODY according to PARAMS, return the expanded body."
|
||||
|
@ -181,10 +184,13 @@ end"
|
|||
(defun org-babel-julia-initiate-session (session params)
|
||||
"If there is not a current julia process then create one."
|
||||
(unless (string= session "none")
|
||||
(let ((session (or session "*Julia*"))
|
||||
(ess-ask-for-ess-directory
|
||||
(and (bound-and-true-p ess-ask-for-ess-directory)
|
||||
(not (cdr (assq :dir params))))))
|
||||
(let* ((session (or session "*Julia*"))
|
||||
(ess-ask-for-ess-directory
|
||||
(and (bound-and-true-p ess-ask-for-ess-directory)
|
||||
(not (cdr (assq :dir params)))))
|
||||
;; Make ESS name the process buffer as SESSION.
|
||||
(ess-gen-proc-buffer-name-function
|
||||
(lambda (_) session)))
|
||||
(if (org-babel-comint-buffer-livep session)
|
||||
session
|
||||
;; FIXME: Depending on `display-buffer-alist', (julia) may end up
|
||||
|
@ -196,13 +202,8 @@ end"
|
|||
(when (get-buffer session)
|
||||
;; Session buffer exists, but with dead process
|
||||
(set-buffer session))
|
||||
(require 'ess) (set-buffer (julia))
|
||||
(rename-buffer
|
||||
(if (bufferp session)
|
||||
(buffer-name session)
|
||||
(if (stringp session)
|
||||
session
|
||||
(buffer-name))))
|
||||
(org-require-package 'ess "ESS")
|
||||
(set-buffer (julia))
|
||||
(current-buffer))))))
|
||||
|
||||
(defun org-babel-julia-graphical-output-file (params)
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
(defvar org-format-latex-options) ; From org.el
|
||||
(defvar org-latex-default-packages-alist) ; From org.el
|
||||
(defvar org-latex-packages-alist) ; From org.el
|
||||
(defvar org-preview-latex-process-alist) ; From org.el
|
||||
|
||||
(defvar org-babel-default-header-args:latex
|
||||
'((:results . "latex") (:exports . "results"))
|
||||
|
@ -128,6 +129,18 @@ exporting the literal LaTeX source."
|
|||
:group 'org-babel
|
||||
:type '(repeat (string)))
|
||||
|
||||
(defcustom org-babel-latex-process-alist
|
||||
`(,(cons 'png (alist-get 'dvipng org-preview-latex-process-alist)))
|
||||
"Definitions of external processes for LaTeX result generation.
|
||||
See `org-preview-latex-process-alist' for more details.
|
||||
|
||||
The following process symbols are recognized:
|
||||
- `png' :: Process used to produce .png output."
|
||||
:group 'org-babel
|
||||
:package-version '(Org . "9.7")
|
||||
:type '(alist :tag "LaTeX to image backends"
|
||||
:value-type (plist)))
|
||||
|
||||
(defun org-babel-expand-body:latex (body params)
|
||||
"Expand BODY according to PARAMS, return the expanded body."
|
||||
(mapc (lambda (pair) ;; replace variables
|
||||
|
@ -136,12 +149,18 @@ exporting the literal LaTeX source."
|
|||
(regexp-quote (format "%S" (car pair)))
|
||||
(if (stringp (cdr pair))
|
||||
(cdr pair) (format "%S" (cdr pair)))
|
||||
body)))
|
||||
body t t)))
|
||||
(org-babel--get-vars params))
|
||||
(org-trim body))
|
||||
(let ((prologue (cdr (assq :prologue params)))
|
||||
(epilogue (cdr (assq :epilogue params))))
|
||||
(org-trim
|
||||
(concat
|
||||
(and prologue (concat prologue "\n"))
|
||||
body
|
||||
(and epilogue (concat "\n" epilogue "\n"))))))
|
||||
|
||||
(defun org-babel-execute:latex (body params)
|
||||
"Execute a block of LaTeX code with Babel.
|
||||
"Execute LaTeX BODY according to PARAMS.
|
||||
This function is called by `org-babel-execute-src-block'."
|
||||
(setq body (org-babel-expand-body:latex body params))
|
||||
(if (cdr (assq :file params))
|
||||
|
@ -163,9 +182,10 @@ This function is called by `org-babel-execute-src-block'."
|
|||
((and (string-suffix-p ".png" out-file) (not imagemagick))
|
||||
(let ((org-format-latex-header
|
||||
(concat org-format-latex-header "\n"
|
||||
(mapconcat #'identity headers "\n"))))
|
||||
(mapconcat #'identity headers "\n")))
|
||||
(org-preview-latex-process-alist org-babel-latex-process-alist))
|
||||
(org-create-formula-image
|
||||
body out-file org-format-latex-options in-buffer)))
|
||||
body out-file org-format-latex-options in-buffer 'png)))
|
||||
((string= "svg" extension)
|
||||
(with-temp-file tex-file
|
||||
(insert (concat (funcall org-babel-latex-preamble params)
|
||||
|
@ -273,7 +293,9 @@ This function is called by `org-babel-execute-src-block'."
|
|||
body))
|
||||
|
||||
(defun org-babel-latex-convert-pdf (pdffile out-file im-in-options im-out-options)
|
||||
"Generate a file from a pdf file using imagemagick."
|
||||
"Generate OUT-FILE from PDFFILE using imagemagick.
|
||||
IM-IN-OPTIONS are command line options for input file, as a string;
|
||||
and IM-OUT-OPTIONS are the output file options."
|
||||
(let ((cmd (concat "convert " im-in-options " " pdffile " "
|
||||
im-out-options " " out-file)))
|
||||
(message "Converting pdffile file %s..." cmd)
|
||||
|
|
|
@ -40,10 +40,8 @@
|
|||
|
||||
(declare-function org-fold-show-all "org-fold" (&optional types))
|
||||
|
||||
;; FIXME: Doesn't this rather belong in lilypond-mode.el?
|
||||
(defalias 'lilypond-mode 'LilyPond-mode)
|
||||
|
||||
(add-to-list 'org-babel-tangle-lang-exts '("LilyPond" . "ly"))
|
||||
(add-to-list 'org-src-lang-modes '("lilypond" . "LilyPond"))
|
||||
|
||||
(defvar org-babel-default-header-args:lilypond '()
|
||||
"Default header arguments for lilypond code blocks.
|
||||
|
@ -60,23 +58,13 @@ and stored in `org-babel-default-header-args:lilypond'
|
|||
See `org-babel-lilypond-set-header-args'.")
|
||||
|
||||
(defvar org-babel-lilypond-compile-post-tangle t
|
||||
"Following the org-babel-tangle (C-c C-v t) command,
|
||||
org-babel-lilypond-compile-post-tangle determines whether ob-lilypond should
|
||||
automatically attempt to compile the resultant tangled file.
|
||||
If the value is nil, no automated compilation takes place.
|
||||
Default value is t.")
|
||||
"When non-nil, compile tangled file after `org-babel-tangle'.")
|
||||
|
||||
(defvar org-babel-lilypond-display-pdf-post-tangle t
|
||||
"Following a successful LilyPond compilation
|
||||
org-babel-lilypond-display-pdf-post-tangle determines whether to automate the
|
||||
drawing / redrawing of the resultant pdf. If the value is nil,
|
||||
the pdf is not automatically redrawn. Default value is t.")
|
||||
"When non-nil, display pdf after successful LilyPond compilation.")
|
||||
|
||||
(defvar org-babel-lilypond-play-midi-post-tangle t
|
||||
"Following a successful LilyPond compilation
|
||||
org-babel-lilypond-play-midi-post-tangle determines whether to automate the
|
||||
playing of the resultant midi file. If the value is nil,
|
||||
the midi file is not automatically played. Default value is t")
|
||||
"When non-nil, play midi file after successful LilyPond compilation.")
|
||||
|
||||
(defvar org-babel-lilypond-ly-command ""
|
||||
"Command to execute lilypond on your system.
|
||||
|
@ -143,7 +131,9 @@ blocks.")
|
|||
|
||||
(defun org-babel-expand-body:lilypond (body params)
|
||||
"Expand BODY according to PARAMS, return the expanded body."
|
||||
(let ((vars (org-babel--get-vars params)))
|
||||
(let ((vars (org-babel--get-vars params))
|
||||
(prologue (cdr (assq :prologue params)))
|
||||
(epilogue (cdr (assq :epilogue params))))
|
||||
(mapc
|
||||
(lambda (pair)
|
||||
(let ((name (symbol-name (car pair)))
|
||||
|
@ -152,54 +142,75 @@ blocks.")
|
|||
(replace-regexp-in-string
|
||||
(concat "$" (regexp-quote name))
|
||||
(if (stringp value) value (format "%S" value))
|
||||
body))))
|
||||
body t t))))
|
||||
vars)
|
||||
body))
|
||||
(concat
|
||||
(and prologue (concat prologue "\n"))
|
||||
body
|
||||
(and epilogue (concat "\n" epilogue "\n")))))
|
||||
|
||||
(defun org-babel-execute:lilypond (body params)
|
||||
"This function is called by `org-babel-execute-src-block'.
|
||||
Depending on whether we are in arrange mode either:
|
||||
1. Attempt to execute lilypond block according to header settings
|
||||
(This is the default basic mode)
|
||||
2. Tangle all lilypond blocks and process the result (arrange mode)"
|
||||
"Execute LilyPond src block according to arrange mode.
|
||||
See `org-babel-execute-src-block' for BODY and PARAMS.
|
||||
When in arrange mode, tangle all blocks and process the result.
|
||||
Otherwise, execute block according to header settings."
|
||||
(org-babel-lilypond-set-header-args org-babel-lilypond-arrange-mode)
|
||||
(if org-babel-lilypond-arrange-mode
|
||||
(org-babel-lilypond-tangle)
|
||||
(org-babel-lilypond-process-basic body params)))
|
||||
|
||||
(defun org-babel-lilypond-tangle ()
|
||||
"ob-lilypond specific tangle, attempts to invoke
|
||||
=ly-execute-tangled-ly= if tangle is successful. Also passes
|
||||
specific arguments to =org-babel-tangle=."
|
||||
"Tangle lilypond blocks, then `org-babel-liypond-execute-tangled-ly'."
|
||||
(interactive)
|
||||
(if (org-babel-tangle nil "yes" "lilypond")
|
||||
(org-babel-lilypond-execute-tangled-ly) nil))
|
||||
|
||||
;; https://lilypond.org/doc/v2.24/Documentation/usage/other-programs
|
||||
(defvar org-babel-lilypond-paper-settings
|
||||
"#(if (ly:get-option 'use-paper-size-for-page)
|
||||
(begin (ly:set-option 'use-paper-size-for-page #f)
|
||||
(ly:set-option 'tall-page-formats '%s)))
|
||||
\\paper {
|
||||
indent=0\\mm
|
||||
tagline=\"\"
|
||||
oddFooterMarkup=##f
|
||||
oddHeaderMarkup=##f
|
||||
bookTitleMarkup=##f
|
||||
scoreTitleMarkup=##f
|
||||
}\n"
|
||||
"The paper settings required to generate music fragments.
|
||||
They are needed for mixing music and text in basic-mode.")
|
||||
|
||||
(defun org-babel-lilypond-process-basic (body params)
|
||||
"Execute a lilypond block in basic mode."
|
||||
"Execute a lilypond block in basic mode.
|
||||
See `org-babel-execute-src-block' for BODY and PARAMS."
|
||||
(let* ((out-file (cdr (assq :file params)))
|
||||
(file-type (file-name-extension out-file))
|
||||
(cmdline (or (cdr (assq :cmdline params))
|
||||
""))
|
||||
(in-file (org-babel-temp-file "lilypond-")))
|
||||
|
||||
(with-temp-file in-file
|
||||
(insert (org-babel-expand-body:generic body params)))
|
||||
(insert
|
||||
(format org-babel-lilypond-paper-settings file-type)
|
||||
(org-babel-expand-body:generic body params)))
|
||||
(org-babel-eval
|
||||
(concat
|
||||
org-babel-lilypond-ly-command
|
||||
" -dbackend=eps "
|
||||
"-dno-gs-load-fonts "
|
||||
"-dinclude-eps-fonts "
|
||||
(or (cdr (assoc (file-name-extension out-file)
|
||||
'(("pdf" . "--pdf ")
|
||||
("ps" . "--ps ")
|
||||
("png" . "--png "))))
|
||||
(or (assoc-default file-type
|
||||
'(("pdf" . "--pdf ")
|
||||
("eps" . "--eps ")))
|
||||
"--png ")
|
||||
"--output="
|
||||
(file-name-sans-extension out-file)
|
||||
" "
|
||||
cmdline
|
||||
in-file) "")) nil)
|
||||
in-file)
|
||||
""))
|
||||
nil)
|
||||
|
||||
(defun org-babel-prep-session:lilypond (_session _params)
|
||||
"Return an error because LilyPond exporter does not support sessions."
|
||||
|
@ -219,7 +230,7 @@ If error in compilation, attempt to mark the error in lilypond org file."
|
|||
(delete-file org-babel-lilypond-temp-file))
|
||||
(rename-file org-babel-lilypond-tangled-file
|
||||
org-babel-lilypond-temp-file))
|
||||
(org-switch-to-buffer-other-window "*lilypond*")
|
||||
(switch-to-buffer-other-window "*lilypond*")
|
||||
(erase-buffer)
|
||||
(org-babel-lilypond-compile-lilyfile org-babel-lilypond-temp-file)
|
||||
(goto-char (point-min))
|
||||
|
@ -229,27 +240,20 @@ If error in compilation, attempt to mark the error in lilypond org file."
|
|||
(org-babel-lilypond-attempt-to-open-pdf org-babel-lilypond-temp-file)
|
||||
(org-babel-lilypond-attempt-to-play-midi org-babel-lilypond-temp-file)))))
|
||||
|
||||
(defun org-babel-lilypond-compile-lilyfile (file-name &optional test)
|
||||
"Compile lilypond file and check for compile errors.
|
||||
FILE-NAME is full path to lilypond (.ly) file."
|
||||
(message "Compiling LilyPond...")
|
||||
(let ((arg-1 org-babel-lilypond-ly-command) ;program
|
||||
;; (arg-2 nil) ;infile
|
||||
(arg-3 "*lilypond*") ;buffer
|
||||
(arg-4 t) ;display
|
||||
(arg-5 (if org-babel-lilypond-gen-png "--png" "")) ;&rest...
|
||||
(arg-6 (if org-babel-lilypond-gen-html "--html" ""))
|
||||
(arg-7 (if org-babel-lilypond-gen-pdf "--pdf" ""))
|
||||
(arg-8 (if org-babel-lilypond-use-eps "-dbackend=eps" ""))
|
||||
(arg-9 (if org-babel-lilypond-gen-svg "-dbackend=svg" ""))
|
||||
(arg-10 (concat "--output=" (file-name-sans-extension file-name)))
|
||||
(arg-11 file-name))
|
||||
(if test
|
||||
`(,arg-1 ,nil ,arg-3 ,arg-4 ,arg-5 ,arg-6 ;; arg-2
|
||||
,arg-7 ,arg-8 ,arg-9 ,arg-10 ,arg-11)
|
||||
(call-process
|
||||
arg-1 nil arg-3 arg-4 arg-5 arg-6 ;; arg-2
|
||||
arg-7 arg-8 arg-9 arg-10 arg-11))))
|
||||
;;Ignoring second arg for pre Org 9.7 compatibility
|
||||
(defun org-babel-lilypond-compile-lilyfile (filename &optional _)
|
||||
"Compile Lilypond FILENAME and check for compile errors."
|
||||
(message "Compiling %s..." filename)
|
||||
(let ((args (delq nil (list
|
||||
(and org-babel-lilypond-gen-png "--png")
|
||||
(and org-babel-lilypond-gen-html "--html")
|
||||
(and org-babel-lilypond-gen-pdf "--pdf")
|
||||
(and org-babel-lilypond-use-eps "-dbackend=eps")
|
||||
(and org-babel-lilypond-gen-svg "-dbackend=svg")
|
||||
(concat "--output=" (file-name-sans-extension filename))
|
||||
filename))))
|
||||
(apply #'call-process org-babel-lilypond-ly-command nil
|
||||
"*lilypond*" 'display args)))
|
||||
|
||||
(defun org-babel-lilypond-check-for-compile-error (file-name &optional test)
|
||||
"Check for compile error.
|
||||
|
@ -276,7 +280,7 @@ FILE-NAME is full path to lilypond file."
|
|||
"Mark the erroneous lines in the lilypond org buffer.
|
||||
FILE-NAME is full path to lilypond file.
|
||||
LINE is the erroneous line."
|
||||
(org-switch-to-buffer-other-window
|
||||
(switch-to-buffer-other-window
|
||||
(concat (file-name-nondirectory
|
||||
(org-babel-lilypond-switch-extension file-name ".org"))))
|
||||
(let ((temp (point)))
|
||||
|
@ -290,7 +294,7 @@ LINE is the erroneous line."
|
|||
(goto-char temp))))
|
||||
|
||||
(defun org-babel-lilypond-parse-line-num (&optional buffer)
|
||||
"Extract error line number."
|
||||
"Extract error line number in BUFFER or `current-buffer'."
|
||||
(when buffer (set-buffer buffer))
|
||||
(let ((start
|
||||
(and (search-backward ":" nil t)
|
||||
|
@ -423,8 +427,7 @@ These depend upon whether we are in Arrange mode i.e. MODE is t."
|
|||
ob-lilypond-header-args)))
|
||||
|
||||
(defun org-babel-lilypond-set-header-args (mode)
|
||||
"Set org-babel-default-header-args:lilypond
|
||||
dependent on ORG-BABEL-LILYPOND-ARRANGE-MODE."
|
||||
"Set lilypond babel header according to MODE."
|
||||
(setq org-babel-default-header-args:lilypond
|
||||
(org-babel-lilypond-get-header-args mode)))
|
||||
|
||||
|
|
|
@ -74,13 +74,19 @@ current directory string."
|
|||
(let* ((vars (org-babel--get-vars params))
|
||||
(result-params (cdr (assq :result-params params)))
|
||||
(print-level nil) (print-length nil)
|
||||
(prologue (cdr (assq :prologue params)))
|
||||
(epilogue (cdr (assq :epilogue params)))
|
||||
(body (if (null vars) (org-trim body)
|
||||
(concat "(let ("
|
||||
(mapconcat
|
||||
(lambda (var)
|
||||
(format "(%S (quote %S))" (car var) (cdr var)))
|
||||
vars "\n ")
|
||||
")\n" body ")"))))
|
||||
")\n"
|
||||
(and prologue (concat prologue "\n"))
|
||||
body
|
||||
(and epilogue (concat "\n" epilogue "\n"))
|
||||
")"))))
|
||||
(if (or (member "code" result-params)
|
||||
(member "pp" result-params))
|
||||
(format "(pprint %s)" body)
|
||||
|
@ -90,37 +96,41 @@ current directory string."
|
|||
"Execute a block of Common Lisp code with Babel.
|
||||
BODY is the contents of the block, as a string. PARAMS is
|
||||
a property list containing the parameters of the block."
|
||||
(require (pcase org-babel-lisp-eval-fn
|
||||
(`slime-eval 'slime)
|
||||
(`sly-eval 'sly)))
|
||||
(org-babel-reassemble-table
|
||||
(let ((result
|
||||
(funcall (if (member "output" (cdr (assq :result-params params)))
|
||||
#'car #'cadr)
|
||||
(with-temp-buffer
|
||||
(insert (org-babel-expand-body:lisp body params))
|
||||
(funcall org-babel-lisp-eval-fn
|
||||
`(swank:eval-and-grab-output
|
||||
,(let ((dir (if (assq :dir params)
|
||||
(cdr (assq :dir params))
|
||||
default-directory)))
|
||||
(format
|
||||
(if dir (format org-babel-lisp-dir-fmt dir)
|
||||
"(progn %s\n)")
|
||||
(buffer-substring-no-properties
|
||||
(point-min) (point-max)))))
|
||||
(cdr (assq :package params)))))))
|
||||
(org-babel-result-cond (cdr (assq :result-params params))
|
||||
(org-strip-quotes result)
|
||||
(condition-case nil
|
||||
(read (org-babel-lisp-vector-to-list result))
|
||||
(error result))))
|
||||
(org-babel-pick-name (cdr (assq :colname-names params))
|
||||
(cdr (assq :colnames params)))
|
||||
(org-babel-pick-name (cdr (assq :rowname-names params))
|
||||
(cdr (assq :rownames params)))))
|
||||
(let (eval-and-grab-output)
|
||||
(pcase org-babel-lisp-eval-fn
|
||||
(`slime-eval (org-require-package 'slime "SLIME")
|
||||
(setq eval-and-grab-output 'swank:eval-and-grab-output))
|
||||
(`sly-eval (org-require-package 'sly "SLY")
|
||||
(setq eval-and-grab-output 'slynk:eval-and-grab-output)))
|
||||
(org-babel-reassemble-table
|
||||
(let ((result
|
||||
(funcall (if (member "output" (cdr (assq :result-params params)))
|
||||
#'car #'cadr)
|
||||
(with-temp-buffer
|
||||
(insert (org-babel-expand-body:lisp body params))
|
||||
(funcall org-babel-lisp-eval-fn
|
||||
`(,eval-and-grab-output
|
||||
,(let ((dir (if (assq :dir params)
|
||||
(cdr (assq :dir params))
|
||||
default-directory)))
|
||||
(format
|
||||
(if dir (format org-babel-lisp-dir-fmt dir)
|
||||
"(progn %s\n)")
|
||||
(buffer-substring-no-properties
|
||||
(point-min) (point-max)))))
|
||||
(cdr (assq :package params)))))))
|
||||
(org-babel-result-cond (cdr (assq :result-params params))
|
||||
(org-strip-quotes result)
|
||||
(condition-case nil
|
||||
(read (org-babel-lisp-vector-to-list result))
|
||||
(error result))))
|
||||
(org-babel-pick-name (cdr (assq :colname-names params))
|
||||
(cdr (assq :colnames params)))
|
||||
(org-babel-pick-name (cdr (assq :rowname-names params))
|
||||
(cdr (assq :rownames params))))))
|
||||
|
||||
(defun org-babel-lisp-vector-to-list (results)
|
||||
"Convert #(...) values in RESULTS string into a (...) list."
|
||||
;; TODO: better would be to replace #(...) with [...]
|
||||
(replace-regexp-in-string "#(" "(" results))
|
||||
|
||||
|
|
|
@ -34,8 +34,8 @@
|
|||
(declare-function org-babel-ref-split-args "ob-ref" (arg-string))
|
||||
(declare-function org-element-at-point "org-element" (&optional pom cached-only))
|
||||
(declare-function org-element-context "org-element" (&optional element))
|
||||
(declare-function org-element-property "org-element" (property element))
|
||||
(declare-function org-element-type "org-element" (element))
|
||||
(declare-function org-element-property "org-element-ast" (property node))
|
||||
(declare-function org-element-type "org-element-ast" (node &optional anonymous))
|
||||
|
||||
(defvar org-babel-library-of-babel nil
|
||||
"Library of source-code blocks.
|
||||
|
|
|
@ -81,8 +81,14 @@ This will typically be `lua-mode'."
|
|||
:package-version '(Org . "8.3")
|
||||
:type 'symbol)
|
||||
|
||||
(defcustom org-babel-lua-multiple-values-separator ", "
|
||||
"Separate multiple values with this string."
|
||||
:group 'org-babel
|
||||
:package-version '(Org . "9.7")
|
||||
:type 'string)
|
||||
|
||||
(defun org-babel-execute:lua (body params)
|
||||
"Execute a block of Lua code with Babel.
|
||||
"Execute Lua BODY according to PARAMS.
|
||||
This function is called by `org-babel-execute-src-block'."
|
||||
(let* ((session (org-babel-lua-initiate-session
|
||||
(cdr (assq :session params))))
|
||||
|
@ -129,7 +135,8 @@ VARS contains resolved variable references."
|
|||
;; helper functions
|
||||
|
||||
(defun org-babel-variable-assignments:lua (params)
|
||||
"Return a list of Lua statements assigning the block's variables."
|
||||
"Return a list of Lua statements assigning the block's variables.
|
||||
The variable definitions are defining in PARAMS."
|
||||
(mapcar
|
||||
(lambda (pair)
|
||||
(format "%s=%s"
|
||||
|
@ -176,13 +183,20 @@ Emacs-lisp table, otherwise return the results as a string."
|
|||
(cdr (assoc session org-babel-lua-buffers)))
|
||||
|
||||
(defun org-babel-lua-with-earmuffs (session)
|
||||
"Return buffer name for SESSION, as *SESSION*."
|
||||
(let ((name (if (stringp session) session (format "%s" session))))
|
||||
(if (and (string= "*" (substring name 0 1))
|
||||
(string= "*" (substring name (- (length name) 1))))
|
||||
name
|
||||
(format "*%s*" name))))
|
||||
|
||||
(defun org-babel-session-buffer:lua (session &optional _)
|
||||
"Return session buffer name for SESSION."
|
||||
(or (org-babel-lua-session-buffer session)
|
||||
(org-babel-lua-with-earmuffs session)))
|
||||
|
||||
(defun org-babel-lua-without-earmuffs (session)
|
||||
"Remove stars around *SESSION*, leaving SESSION."
|
||||
(let ((name (if (stringp session) session (format "%s" session))))
|
||||
(if (and (string= "*" (substring name 0 1))
|
||||
(string= "*" (substring name (- (length name) 1))))
|
||||
|
@ -243,45 +257,55 @@ function main()
|
|||
%s
|
||||
end
|
||||
|
||||
fd=io.open(\"%s\", \"w\")
|
||||
fd:write( main() )
|
||||
fd:close()")
|
||||
(defvar org-babel-lua-pp-wrapper-method
|
||||
"
|
||||
-- table to string
|
||||
function t2s(t, indent)
|
||||
function dump(it, indent)
|
||||
if indent == nil then
|
||||
indent = \"\"
|
||||
indent = ''
|
||||
end
|
||||
if type(t) == \"table\" then
|
||||
ts = \"\"
|
||||
for k,v in pairs(t) do
|
||||
if type(v) == \"table\" then
|
||||
ts = ts .. indent .. t2s(k,indent .. \" \") .. \" = \\n\" ..
|
||||
t2s(v, indent .. \" \")
|
||||
else
|
||||
ts = ts .. indent .. t2s(k,indent .. \" \") .. \" = \" ..
|
||||
t2s(v, indent .. \" \") .. \"\\n\"
|
||||
if type(it) == 'table' and %s then
|
||||
local count = 0
|
||||
for _ in pairs(it) do
|
||||
count = count + 1
|
||||
end
|
||||
local result = ''
|
||||
if #indent ~= 0 then
|
||||
result = result .. '\\n'
|
||||
end
|
||||
for key, value in pairs(it) do
|
||||
result = result
|
||||
.. indent
|
||||
.. dump(key)
|
||||
.. ' = '
|
||||
.. dump(value, indent .. ' ')
|
||||
count = count - 1
|
||||
if count ~= 0 then
|
||||
result = result .. '\\n'
|
||||
end
|
||||
end
|
||||
return ts
|
||||
return result
|
||||
else
|
||||
return tostring(t)
|
||||
return tostring(it)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function main()
|
||||
%s
|
||||
function combine(...)
|
||||
local result = {}
|
||||
for index = 1, select('#', ...) do
|
||||
result[index] = dump(select(index, ...))
|
||||
end
|
||||
return table.concat(result, '%s')
|
||||
end
|
||||
|
||||
fd=io.open(\"%s\", \"w\")
|
||||
fd:write(t2s(main()))
|
||||
fd:close()")
|
||||
output = io.open('%s', 'w')
|
||||
output:write(combine(main()))
|
||||
output:close()")
|
||||
|
||||
(defun org-babel-lua-evaluate
|
||||
(session body &optional result-type result-params preamble)
|
||||
"Evaluate BODY as Lua code."
|
||||
"Evaluate BODY in SESSION as Lua code.
|
||||
RESULT-TYPE and RESULT-PARAMS are passed to
|
||||
`org-babel-lua-evaluate-session' or
|
||||
`org-babel-lua-evaluate-external-process'.
|
||||
PREAMBLE is passed to `org-babel-lua-evaluate-external-process'."
|
||||
(if session
|
||||
(org-babel-lua-evaluate-session
|
||||
session body result-type result-params)
|
||||
|
@ -290,10 +314,12 @@ fd:close()")
|
|||
|
||||
(defun org-babel-lua-evaluate-external-process
|
||||
(body &optional result-type result-params preamble)
|
||||
"Evaluate BODY in external lua process.
|
||||
"Evaluate BODY in external Lua process.
|
||||
If RESULT-TYPE equals `output' then return standard output as a
|
||||
string. If RESULT-TYPE equals `value' then return the value of the
|
||||
last statement in BODY, as elisp."
|
||||
last statement in BODY, as elisp.
|
||||
RESULT-PARAMS list all the :result header arg parameters.
|
||||
PREAMBLE string is appended to BODY."
|
||||
(let ((raw
|
||||
(pcase result-type
|
||||
(`output (org-babel-eval org-babel-lua-command
|
||||
|
@ -305,15 +331,17 @@ last statement in BODY, as elisp."
|
|||
(concat
|
||||
preamble (and preamble "\n")
|
||||
(format
|
||||
(if (member "pp" result-params)
|
||||
org-babel-lua-pp-wrapper-method
|
||||
org-babel-lua-wrapper-method)
|
||||
org-babel-lua-wrapper-method
|
||||
(mapconcat
|
||||
(lambda (line) (format "\t%s" line))
|
||||
(split-string
|
||||
(org-remove-indentation
|
||||
(org-trim body))
|
||||
"[\r\n]") "\n")
|
||||
"[\r\n]")
|
||||
"\n")
|
||||
(if (member "pp" result-params)
|
||||
"true" "false")
|
||||
org-babel-lua-multiple-values-separator
|
||||
(org-babel-process-file-name tmp-file 'noquote))))
|
||||
(org-babel-eval-read-file tmp-file))))))
|
||||
(org-babel-result-cond result-params
|
||||
|
@ -399,7 +427,7 @@ fd:close()"
|
|||
(org-babel-lua-table-or-string results)))))
|
||||
|
||||
(defun org-babel-lua-read-string (string)
|
||||
"Strip single quotes from around Lua string."
|
||||
"Strip single quotes from around Lua STRING."
|
||||
(org-unbracket-string "'" "'" string))
|
||||
|
||||
(provide 'ob-lua)
|
||||
|
|
|
@ -36,7 +36,8 @@
|
|||
(defvar org-babel-default-header-args:makefile '())
|
||||
|
||||
(defun org-babel-execute:makefile (body _params)
|
||||
"Execute a block of makefile code.
|
||||
"Execute makefile BODY.
|
||||
Second function argument is ignored.
|
||||
This function is called by `org-babel-execute-src-block'."
|
||||
body)
|
||||
|
||||
|
|
|
@ -37,6 +37,11 @@
|
|||
|
||||
(require 'ob)
|
||||
|
||||
(defconst org-babel-header-args:maxima
|
||||
'((batch . ((batchload batch load)))
|
||||
(graphics-pkg . ((plot draw))))
|
||||
"Maxima-specific header arguments.")
|
||||
|
||||
(defvar org-babel-tangle-lang-exts)
|
||||
(add-to-list 'org-babel-tangle-lang-exts '("maxima" . "max"))
|
||||
|
||||
|
@ -48,43 +53,102 @@
|
|||
:group 'org-babel
|
||||
:type 'string)
|
||||
|
||||
(defvar org-babel-maxima--command-arguments-default
|
||||
"--very-quiet"
|
||||
"Command-line arguments sent to Maxima by default.
|
||||
If the `:batch' header argument is set to `batchload' or unset,
|
||||
then the `:cmdline' header argument is appended to this default;
|
||||
otherwise, if the `:cmdline' argument is set, it over-rides this
|
||||
default. See `org-babel-maxima-command' and
|
||||
`org-babel-execute:maxima'.")
|
||||
|
||||
(defvar org-babel-maxima--graphic-package-options
|
||||
'((plot . "(set_plot_option ('[gnuplot_term, %s]), set_plot_option ('[gnuplot_out_file, %S]))$")
|
||||
(draw . "(load(draw), set_draw_defaults(terminal='%s,file_name=%S))$"))
|
||||
"An alist of graphics packages and Maxima code.
|
||||
Each element is a cons (PACKAGE-NAME . FORMAT-STRING).
|
||||
FORMAT-STRING contains Maxima code to configure the graphics
|
||||
package; it must contain `%s' to set the terminal and `%S' to set
|
||||
the filename, in that order. The default graphics package is
|
||||
`plot'; `draw' is also supported. See
|
||||
`org-babel-maxima-expand'.")
|
||||
|
||||
(defvar org-babel-maxima--default-epilogue
|
||||
'((graphical-output . "gnuplot_close ()$")
|
||||
(non-graphical-output . ""))
|
||||
"The final Maxima code executed in a source block.
|
||||
An alist with the epilogue for graphical and non-graphical
|
||||
output. See `org-babel-maxima-expand'.")
|
||||
|
||||
(defun org-babel-maxima-expand (body params)
|
||||
"Expand a block of Maxima code according to its header arguments."
|
||||
(let ((vars (org-babel--get-vars params))
|
||||
(epilogue (cdr (assq :epilogue params)))
|
||||
(prologue (cdr (assq :prologue params))))
|
||||
"Expand Maxima BODY according to its header arguments from PARAMS."
|
||||
(let* ((vars (org-babel--get-vars params))
|
||||
(graphic-file (ignore-errors (org-babel-graphical-output-file params)))
|
||||
(epilogue (cdr (assq :epilogue params)))
|
||||
(prologue (cdr (assq :prologue params))))
|
||||
(mapconcat 'identity
|
||||
(list
|
||||
;; Any code from the specified prologue at the start.
|
||||
prologue
|
||||
;; graphic output
|
||||
(let ((graphic-file (ignore-errors (org-babel-graphical-output-file params))))
|
||||
(if graphic-file
|
||||
(format
|
||||
"set_plot_option ([gnuplot_term, png]); set_plot_option ([gnuplot_out_file, %S]);"
|
||||
graphic-file)
|
||||
""))
|
||||
;; variables
|
||||
(mapconcat 'org-babel-maxima-var-to-maxima vars "\n")
|
||||
;; body
|
||||
body
|
||||
;; Any code from the specified epilogue at the end.
|
||||
epilogue
|
||||
"gnuplot_close ()$")
|
||||
(delq nil
|
||||
(list
|
||||
;; Any code from the specified prologue at the start.
|
||||
prologue
|
||||
;; graphic output
|
||||
(if graphic-file
|
||||
(let* ((graphics-pkg (intern (or (cdr (assq :graphics-pkg params)) "plot")))
|
||||
(graphic-format-string (cdr (assq graphics-pkg org-babel-maxima--graphic-package-options)))
|
||||
(graphic-terminal (file-name-extension graphic-file))
|
||||
(graphic-file (if (eq graphics-pkg 'plot) graphic-file (file-name-sans-extension graphic-file))))
|
||||
(format graphic-format-string graphic-terminal graphic-file)))
|
||||
;; variables
|
||||
(mapconcat 'org-babel-maxima-var-to-maxima vars "\n")
|
||||
;; body
|
||||
body
|
||||
;; Any code from the specified epilogue at the end.
|
||||
epilogue
|
||||
(if graphic-file
|
||||
(cdr (assq :graphical-output org-babel-maxima--default-epilogue))
|
||||
(cdr (assq :non-graphical-output org-babel-maxima--default-epilogue)))))
|
||||
"\n")))
|
||||
|
||||
(defvar org-babel-maxima--output-filter-regexps
|
||||
'("batch" ;; remove the `batch' or `batchload' line
|
||||
"^rat: replaced .*$" ;; remove notices from `rat'
|
||||
"^;;; Loading #P" ;; remove notices from the lisp implementation
|
||||
"^read and interpret" ;; remove notice from `batch'
|
||||
"^(%\\([i]-?[0-9]+\\))[ ]$" ;; remove empty input lines from `batch'-ing
|
||||
)
|
||||
"Regexps to remove extraneous lines from Maxima's output.
|
||||
See `org-babel-maxima--output-filter'.")
|
||||
|
||||
(defun org-babel-maxima--output-filter (line)
|
||||
"Filter empty or undesired lines from Maxima output.
|
||||
Return nil if LINE is zero-length or it matches a regexp in
|
||||
`org-babel-maxima--output-filter'; otherwise, return LINE."
|
||||
(unless (or (= 0 (length line))
|
||||
(cl-some #'(lambda(r) (string-match r line))
|
||||
org-babel-maxima--output-filter-regexps))
|
||||
line))
|
||||
|
||||
(defun org-babel-execute:maxima (body params)
|
||||
"Execute a block of Maxima entries with org-babel.
|
||||
"Execute Maxima BODY according to PARAMS.
|
||||
This function is called by `org-babel-execute-src-block'."
|
||||
(message "Executing Maxima source code block")
|
||||
(let ((result-params (split-string (or (cdr (assq :results params)) "")))
|
||||
(result
|
||||
(let* ((cmdline (or (cdr (assq :cmdline params)) ""))
|
||||
(batch/load (or (cdr (assq :batch params)) "batchload"))
|
||||
(cmdline (if (or (equal cmdline "") (equal batch/load "batchload"))
|
||||
;; legacy behaviour:
|
||||
;; ensure that --very-quiet is on command-line by default
|
||||
(concat cmdline " " org-babel-maxima--command-arguments-default)
|
||||
;; if using an alternate loader, :cmdline overwrites default
|
||||
cmdline))
|
||||
(in-file (org-babel-temp-file "maxima-" ".max"))
|
||||
(cmd (format "%s --very-quiet -r %s %s"
|
||||
(cmd (format "%s -r %s %s"
|
||||
org-babel-maxima-command
|
||||
(shell-quote-argument
|
||||
(format "batchload(%S)$" in-file))
|
||||
;; bind linenum to 0 so the first line
|
||||
;; of in-file has line number 1
|
||||
(format "(linenum:0, %s(%S))$" batch/load in-file))
|
||||
cmdline)))
|
||||
(with-temp-file in-file (insert (org-babel-maxima-expand body params)))
|
||||
(message cmd)
|
||||
|
@ -93,12 +157,7 @@ This function is called by `org-babel-execute-src-block'."
|
|||
(mapconcat
|
||||
#'identity
|
||||
(delq nil
|
||||
(mapcar (lambda (line)
|
||||
(unless (or (string-match "batch" line)
|
||||
(string-match "^rat: replaced .*$" line)
|
||||
(string-match "^;;; Loading #P" line)
|
||||
(= 0 (length line)))
|
||||
line))
|
||||
(mapcar #'org-babel-maxima--output-filter
|
||||
(split-string raw "[\r\n]"))) "\n")))))
|
||||
(if (ignore-errors (org-babel-graphical-output-file params))
|
||||
nil
|
||||
|
@ -110,11 +169,11 @@ This function is called by `org-babel-execute-src-block'."
|
|||
|
||||
|
||||
(defun org-babel-prep-session:maxima (_session _params)
|
||||
"Throw an error. Maxima does not support sessions."
|
||||
(error "Maxima does not support sessions"))
|
||||
|
||||
(defun org-babel-maxima-var-to-maxima (pair)
|
||||
"Convert an elisp val into a string of maxima code specifying a var
|
||||
of the same value."
|
||||
"Convert an elisp variable-value PAIR to maxima code."
|
||||
(let ((var (car pair))
|
||||
(val (cdr pair)))
|
||||
(when (symbolp val)
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
:type 'string)
|
||||
|
||||
(defun org-babel-execute:ocaml (body params)
|
||||
"Execute a block of Ocaml code with Babel."
|
||||
"Execute Ocaml BODY according to PARAMS."
|
||||
(let* ((full-body (org-babel-expand-body:generic
|
||||
body params
|
||||
(org-babel-variable-assignments:ocaml params)))
|
||||
|
@ -109,7 +109,7 @@
|
|||
(defvar tuareg-interactive-buffer-name)
|
||||
(defun org-babel-prep-session:ocaml (session _params)
|
||||
"Prepare SESSION according to the header arguments in PARAMS."
|
||||
(require 'tuareg)
|
||||
(org-require-package 'tuareg)
|
||||
(let ((tuareg-interactive-buffer-name (if (and (not (string= session "none"))
|
||||
(not (string= session "default"))
|
||||
(stringp session))
|
||||
|
@ -121,7 +121,8 @@
|
|||
(get-buffer tuareg-interactive-buffer-name)))
|
||||
|
||||
(defun org-babel-variable-assignments:ocaml (params)
|
||||
"Return list of ocaml statements assigning the block's variables."
|
||||
"Return list of ocaml statements assigning the block's variables.
|
||||
The variables are defined in PARAMS."
|
||||
(mapcar
|
||||
(lambda (pair) (format "let %s = %s;;" (car pair)
|
||||
(org-babel-ocaml-elisp-to-ocaml (cdr pair))))
|
||||
|
|
|
@ -70,11 +70,12 @@ end")
|
|||
(defvar org-babel-octave-eoe-output "ans = org_babel_eoe")
|
||||
|
||||
(defun org-babel-execute:matlab (body params)
|
||||
"Execute a block of matlab code with Babel."
|
||||
"Execute Matlab BODY according to PARAMS."
|
||||
(org-babel-execute:octave body params 'matlab))
|
||||
|
||||
(defun org-babel-execute:octave (body params &optional matlabp)
|
||||
"Execute a block of octave code with Babel."
|
||||
"Execute Octave or Matlab BODY according to PARAMS.
|
||||
When MATLABP is non-nil, execute Matlab. Otherwise, execute Octave."
|
||||
(let* ((session
|
||||
(funcall (intern (format "org-babel-%s-initiate-session"
|
||||
(if matlabp "matlab" "octave")))
|
||||
|
@ -109,7 +110,8 @@ end")
|
|||
(org-babel-prep-session:octave session params 'matlab))
|
||||
|
||||
(defun org-babel-variable-assignments:octave (params)
|
||||
"Return list of octave statements assigning the block's variables."
|
||||
"Return list of octave statements assigning the block's variables.
|
||||
The variables are taken from PARAMS."
|
||||
(mapcar
|
||||
(lambda (pair)
|
||||
(format "%s=%s;"
|
||||
|
@ -120,21 +122,22 @@ end")
|
|||
(defalias 'org-babel-variable-assignments:matlab
|
||||
'org-babel-variable-assignments:octave)
|
||||
|
||||
(defun org-babel-octave-var-to-octave (var)
|
||||
"Convert an emacs-lisp value into an octave variable.
|
||||
(defun org-babel-octave-var-to-octave (value)
|
||||
"Convert an emacs-lisp VALUE into an octave variable.
|
||||
Converts an emacs-lisp variable into a string of octave code
|
||||
specifying a variable of the same value."
|
||||
(if (listp var)
|
||||
(concat "[" (mapconcat #'org-babel-octave-var-to-octave var
|
||||
(if (listp (car var)) "; " ",")) "]")
|
||||
(if (listp value)
|
||||
(concat "[" (mapconcat #'org-babel-octave-var-to-octave value
|
||||
(if (listp (car value)) "; " ",")) "]")
|
||||
(cond
|
||||
((stringp var)
|
||||
(format "'%s'" var))
|
||||
((stringp value)
|
||||
(format "'%s'" value))
|
||||
(t
|
||||
(format "%s" var)))))
|
||||
(format "%s" value)))))
|
||||
|
||||
(defun org-babel-prep-session:octave (session params &optional matlabp)
|
||||
"Prepare SESSION according to the header arguments specified in PARAMS."
|
||||
"Prepare SESSION according to the header arguments specified in PARAMS.
|
||||
The session will be an Octave session, unless MATLABP is non-nil."
|
||||
(let* ((session (org-babel-octave-initiate-session session params matlabp))
|
||||
(var-lines (org-babel-variable-assignments:octave params)))
|
||||
(org-babel-comint-in-buffer session
|
||||
|
@ -147,15 +150,18 @@ specifying a variable of the same value."
|
|||
(defun org-babel-matlab-initiate-session (&optional session params)
|
||||
"Create a matlab inferior process buffer.
|
||||
If there is not a current inferior-process-buffer in SESSION then
|
||||
create. Return the initialized session."
|
||||
create. Return the initialized session. PARAMS are src block parameters."
|
||||
(org-babel-octave-initiate-session session params 'matlab))
|
||||
|
||||
(defun org-babel-octave-initiate-session (&optional session _params matlabp)
|
||||
"Create an octave inferior process buffer.
|
||||
If there is not a current inferior-process-buffer in SESSION then
|
||||
create. Return the initialized session."
|
||||
(if matlabp (require 'matlab) (or (require 'octave-inf nil 'noerror)
|
||||
(require 'octave)))
|
||||
create. Return the initialized session. The session will be an
|
||||
Octave session, unless MATLABP is non-nil."
|
||||
(if matlabp
|
||||
(org-require-package 'matlab "matlab-mode")
|
||||
(or (require 'octave-inf nil 'noerror)
|
||||
(require 'octave)))
|
||||
(unless (string= session "none")
|
||||
(let ((session (or session
|
||||
(if matlabp "*Inferior Matlab*" "*Inferior Octave*"))))
|
||||
|
@ -178,7 +184,8 @@ value of the last statement in BODY, as elisp."
|
|||
(org-babel-octave-evaluate-external-process body result-type matlabp)))
|
||||
|
||||
(defun org-babel-octave-evaluate-external-process (body result-type matlabp)
|
||||
"Evaluate BODY in an external octave process."
|
||||
"Evaluate BODY in an external Octave or Matalab process.
|
||||
Process the result as RESULT-TYPE. Use Octave, unless MATLABP is non-nil."
|
||||
(let ((cmd (if matlabp
|
||||
org-babel-matlab-shell-command
|
||||
org-babel-octave-shell-command)))
|
||||
|
|
|
@ -45,15 +45,25 @@
|
|||
"Default header inserted during export of org blocks.")
|
||||
|
||||
(defun org-babel-expand-body:org (body params)
|
||||
"Expand Org BODY according to PARAMS.
|
||||
$VAR instances are replaced by VAR values defined in PARAMS."
|
||||
(dolist (var (org-babel--get-vars params))
|
||||
(setq body (replace-regexp-in-string
|
||||
(regexp-quote (format "$%s" (car var)))
|
||||
(format "%s" (cdr var))
|
||||
body nil 'literal)))
|
||||
body)
|
||||
body 'fixedcase 'literal)))
|
||||
|
||||
(let ((prologue (cdr (assq :prologue params)))
|
||||
(epilogue (cdr (assq :epilogue params))))
|
||||
(concat
|
||||
(and prologue (concat prologue "\n"))
|
||||
body
|
||||
(and epilogue (concat "\n" epilogue "\n")))))
|
||||
|
||||
(defun org-babel-execute:org (body params)
|
||||
"Execute a block of Org code with.
|
||||
"Execute a Org BODY according to PARAMS.
|
||||
The BODY is returned expanded as is or exported, if PARAMS define
|
||||
latex/html/ascii result type.
|
||||
This function is called by `org-babel-execute-src-block'."
|
||||
(let ((result-params (split-string (or (cdr (assq :results params)) "")))
|
||||
(body (org-babel-expand-body:org
|
||||
|
|
|
@ -143,6 +143,7 @@ This function is called by `org-babel-execute-src-block'."
|
|||
("eps" '("-teps"))
|
||||
("pdf" '("-tpdf"))
|
||||
("tex" '("-tlatex"))
|
||||
("tikz" '("-tlatex:nopreamble"))
|
||||
("vdx" '("-tvdx"))
|
||||
("xmi" '("-txmi"))
|
||||
("scxml" '("-tscxml"))
|
||||
|
|
|
@ -78,7 +78,7 @@
|
|||
(defun org-babel-processing-view-sketch ()
|
||||
"Show the sketch of the Processing block under point in an external viewer."
|
||||
(interactive)
|
||||
(require 'processing-mode)
|
||||
(org-require-package 'processing-mode)
|
||||
(let ((info (org-babel-get-src-block-info)))
|
||||
(if (string= (nth 0 info) "processing")
|
||||
(let* ((body (nth 1 info))
|
||||
|
@ -118,7 +118,7 @@
|
|||
(message "Not inside a Processing source block."))))
|
||||
|
||||
(defun org-babel-execute:processing (body params)
|
||||
"Execute a block of Processing code.
|
||||
"Execute Processing code BODY according to PARAMS.
|
||||
This function is called by `org-babel-execute-src-block'."
|
||||
(let ((sketch-code
|
||||
(org-babel-expand-body:generic
|
||||
|
@ -144,7 +144,8 @@ Processing does not support sessions."
|
|||
(error "Processing does not support sessions"))
|
||||
|
||||
(defun org-babel-variable-assignments:processing (params)
|
||||
"Return list of processing statements assigning the block's variables."
|
||||
"Return list of processing statements assigning the block's variables.
|
||||
The variable assignments are defined in PARAMS."
|
||||
(mapcar #'org-babel-processing-var-to-processing
|
||||
(org-babel--get-vars params)))
|
||||
|
||||
|
|
|
@ -36,53 +36,70 @@
|
|||
(require 'org-macs)
|
||||
(require 'python)
|
||||
|
||||
(declare-function py-shell "ext:python-mode" (&rest args))
|
||||
(declare-function py-choose-shell "ext:python-mode" (&optional shell))
|
||||
(declare-function py-shell-send-string "ext:python-mode" (strg &optional process))
|
||||
|
||||
(defvar org-babel-tangle-lang-exts)
|
||||
(add-to-list 'org-babel-tangle-lang-exts '("python" . "py"))
|
||||
|
||||
(defvar org-babel-default-header-args:python '())
|
||||
|
||||
(defcustom org-babel-python-command "python"
|
||||
"Name of the command for executing Python code."
|
||||
:version "24.4"
|
||||
:package-version '(Org . "8.0")
|
||||
(defconst org-babel-header-args:python
|
||||
'((return . :any)
|
||||
(python . :any)
|
||||
(async . ((yes no))))
|
||||
"Python-specific header arguments.")
|
||||
|
||||
(defcustom org-babel-python-command 'auto
|
||||
"Command (including arguments) for interactive and non-interactive Python code.
|
||||
When not `auto', it overrides `org-babel-python-command-session'
|
||||
and `org-babel-python-command-nonsession'."
|
||||
:package-version '(Org . "9.7")
|
||||
:group 'org-babel
|
||||
:type '(choice string (const auto)))
|
||||
|
||||
(defcustom org-babel-python-command-session 'auto
|
||||
"Command (including arguments) for starting interactive Python sessions.
|
||||
If `auto' (the default), uses the values from
|
||||
`python-shell-interpreter' and `python-shell-interpreter-args'.
|
||||
If `org-babel-python-command' is set, then it overrides this
|
||||
option."
|
||||
:package-version '(Org . "9.7")
|
||||
:group 'org-babel
|
||||
:type '(choice string (const auto)))
|
||||
|
||||
(defcustom org-babel-python-command-nonsession "python"
|
||||
"Command (including arguments) for executing non-interactive Python code.
|
||||
If `org-babel-python-command' is set, then it overrides this option."
|
||||
:package-version '(Org . "9.7")
|
||||
:group 'org-babel
|
||||
:type 'string)
|
||||
|
||||
(defcustom org-babel-python-mode
|
||||
(if (featurep 'python-mode) 'python-mode 'python)
|
||||
"Preferred python mode for use in running python interactively.
|
||||
This will typically be either `python' or `python-mode'."
|
||||
:group 'org-babel
|
||||
:version "24.4"
|
||||
:package-version '(Org . "8.0")
|
||||
:type 'symbol)
|
||||
|
||||
(defcustom org-babel-python-hline-to "None"
|
||||
"Replace hlines in incoming tables with this when translating to python."
|
||||
:group 'org-babel
|
||||
:version "24.4"
|
||||
:package-version '(Org . "8.0")
|
||||
:type 'string)
|
||||
|
||||
(defcustom org-babel-python-None-to 'hline
|
||||
"Replace `None' in python tables with this before returning."
|
||||
:group 'org-babel
|
||||
:version "24.4"
|
||||
:package-version '(Org . "8.0")
|
||||
:type 'symbol)
|
||||
|
||||
(defun org-babel-python-associate-session (session)
|
||||
"Associate Python code buffer with an Python session.
|
||||
Make SESSION without earmuffs be the Python buffer name."
|
||||
(setq-local python-shell-buffer-name
|
||||
(org-babel-python-without-earmuffs session)))
|
||||
|
||||
(defun org-babel-execute:python (body params)
|
||||
"Execute a block of Python code with Babel.
|
||||
"Execute Python BODY according to PARAMS.
|
||||
This function is called by `org-babel-execute-src-block'."
|
||||
(let* ((org-babel-python-command
|
||||
(or (cdr (assq :python params))
|
||||
org-babel-python-command))
|
||||
(session (org-babel-python-initiate-session
|
||||
(cdr (assq :session params))))
|
||||
(graphics-file (and (member "graphics" (assq :result-params params))
|
||||
(org-babel-graphical-output-file params)))
|
||||
(result-params (cdr (assq :result-params params)))
|
||||
(result-type (cdr (assq :result-type params)))
|
||||
(return-val (when (eq result-type 'value)
|
||||
|
@ -98,7 +115,7 @@ This function is called by `org-babel-execute-src-block'."
|
|||
(format (if session "\n%s" "\nreturn %s") return-val))))
|
||||
(result (org-babel-python-evaluate
|
||||
session full-body result-type
|
||||
result-params preamble async)))
|
||||
result-params preamble async graphics-file)))
|
||||
(org-babel-reassemble-table
|
||||
result
|
||||
(org-babel-pick-name (cdr (assq :colname-names params))
|
||||
|
@ -130,8 +147,63 @@ VARS contains resolved variable references."
|
|||
|
||||
;; helper functions
|
||||
|
||||
(defconst org-babel-python--output-graphics-wrapper "\
|
||||
import matplotlib.pyplot
|
||||
matplotlib.pyplot.gcf().clear()
|
||||
%s
|
||||
matplotlib.pyplot.savefig('%s')"
|
||||
"Format string for saving Python graphical output.
|
||||
Has two %s escapes, for the Python code to be evaluated, and the
|
||||
file to save the graphics to.")
|
||||
|
||||
(defconst org-babel-python--def-format-value "\
|
||||
def __org_babel_python_format_value(result, result_file, result_params):
|
||||
with open(result_file, 'w') as f:
|
||||
if 'graphics' in result_params:
|
||||
result.savefig(result_file)
|
||||
elif 'pp' in result_params:
|
||||
import pprint
|
||||
f.write(pprint.pformat(result))
|
||||
elif 'list' in result_params and isinstance(result, dict):
|
||||
f.write(str(['{} :: {}'.format(k, v) for k, v in result.items()]))
|
||||
else:
|
||||
if not set(result_params).intersection(\
|
||||
['scalar', 'verbatim', 'raw']):
|
||||
def dict2table(res):
|
||||
if isinstance(res, dict):
|
||||
return [(k, dict2table(v)) for k, v in res.items()]
|
||||
elif isinstance(res, list) or isinstance(res, tuple):
|
||||
return [dict2table(x) for x in res]
|
||||
else:
|
||||
return res
|
||||
if 'table' in result_params:
|
||||
result = dict2table(result)
|
||||
try:
|
||||
import pandas
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
if isinstance(result, pandas.DataFrame) and 'table' in result_params:
|
||||
result = [[result.index.name or ''] + list(result.columns)] + \
|
||||
[None] + [[i] + list(row) for i, row in result.iterrows()]
|
||||
elif isinstance(result, pandas.Series) and 'table' in result_params:
|
||||
result = list(result.items())
|
||||
try:
|
||||
import numpy
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
if isinstance(result, numpy.ndarray):
|
||||
if 'table' in result_params:
|
||||
result = result.tolist()
|
||||
else:
|
||||
result = repr(result)
|
||||
f.write(str(result))"
|
||||
"Python function to format value result and save it to file.")
|
||||
|
||||
(defun org-babel-variable-assignments:python (params)
|
||||
"Return a list of Python statements assigning the block's variables."
|
||||
"Return a list of Python statements assigning the block's variables.
|
||||
The assignments are defined in PARAMS."
|
||||
(mapcar
|
||||
(lambda (pair)
|
||||
(format "%s=%s"
|
||||
|
@ -153,9 +225,13 @@ specifying a variable of the same value."
|
|||
|
||||
(defun org-babel-python-table-or-string (results)
|
||||
"Convert RESULTS into an appropriate elisp value.
|
||||
If the results look like a list or tuple, then convert them into an
|
||||
Emacs-lisp table, otherwise return the results as a string."
|
||||
(let ((res (org-babel-script-escape results)))
|
||||
If the results look like a list or tuple (but not a dict), then
|
||||
convert them into an Emacs-lisp table. Otherwise return the
|
||||
results as a string."
|
||||
(let ((res (if (and (> (length results) 0)
|
||||
(string-equal "{" (substring results 0 1)))
|
||||
results ;don't covert dicts to elisp
|
||||
(org-babel-script-escape results))))
|
||||
(if (listp res)
|
||||
(mapcar (lambda (el) (if (eq el 'None)
|
||||
org-babel-python-None-to el))
|
||||
|
@ -169,6 +245,7 @@ Emacs-lisp table, otherwise return the results as a string."
|
|||
(cdr (assoc session org-babel-python-buffers)))
|
||||
|
||||
(defun org-babel-python-with-earmuffs (session)
|
||||
"Return SESSION name as string, ensuring *...* around."
|
||||
(let ((name (if (stringp session) session (format "%s" session))))
|
||||
(if (and (string= "*" (substring name 0 1))
|
||||
(string= "*" (substring name (- (length name) 1))))
|
||||
|
@ -176,74 +253,113 @@ Emacs-lisp table, otherwise return the results as a string."
|
|||
(format "*%s*" name))))
|
||||
|
||||
(defun org-babel-python-without-earmuffs (session)
|
||||
"Return SESSION name as string, without *...* around."
|
||||
(let ((name (if (stringp session) session (format "%s" session))))
|
||||
(if (and (string= "*" (substring name 0 1))
|
||||
(string= "*" (substring name (- (length name) 1))))
|
||||
(substring name 1 (- (length name) 1))
|
||||
name)))
|
||||
|
||||
(defvar py-which-bufname)
|
||||
(defvar python-shell-buffer-name)
|
||||
(defun org-babel-session-buffer:python (session &optional _)
|
||||
"Return session buffer name for SESSION."
|
||||
(or (org-babel-python-session-buffer session)
|
||||
(org-babel-python-with-earmuffs session)))
|
||||
|
||||
(defun org-babel-python--python-util-comint-end-of-output-p ()
|
||||
"Return non-nil if the last prompt matches input prompt.
|
||||
Backport of `python-util-comint-end-of-output-p' to emacs28. To
|
||||
be removed after minimum supported version reaches emacs29."
|
||||
(when-let ((prompt (python-util-comint-last-prompt)))
|
||||
(python-shell-comint-end-of-output-p
|
||||
(buffer-substring-no-properties
|
||||
(car prompt) (cdr prompt)))))
|
||||
|
||||
(defun org-babel-python--command (is-session)
|
||||
"Helper function to return the Python command.
|
||||
This checks `org-babel-python-command', and then
|
||||
`org-babel-python-command-session' (if IS-SESSION) or
|
||||
`org-babel-python-command-nonsession' (if not IS-SESSION). If
|
||||
IS-SESSION, this might return `nil', which means to use
|
||||
`python-shell-calculate-command'."
|
||||
(or (unless (eq org-babel-python-command 'auto)
|
||||
org-babel-python-command)
|
||||
(if is-session
|
||||
(unless (eq org-babel-python-command-session 'auto)
|
||||
org-babel-python-command-session)
|
||||
org-babel-python-command-nonsession)))
|
||||
|
||||
(defvar-local org-babel-python--initialized nil
|
||||
"Flag used to mark that python session has been initialized.")
|
||||
(defun org-babel-python--setup-session ()
|
||||
"Babel Python session setup code, to be run once per session.
|
||||
Function should be run from within the Python session buffer.
|
||||
This is often run as a part of `python-shell-first-prompt-hook',
|
||||
unless the Python session was created outside Org."
|
||||
(python-shell-send-string-no-output org-babel-python--def-format-value)
|
||||
(setq-local org-babel-python--initialized t))
|
||||
(defun org-babel-python-initiate-session-by-key (&optional session)
|
||||
"Initiate a python session.
|
||||
If there is not a current inferior-process-buffer in SESSION
|
||||
then create. Return the initialized session."
|
||||
If there is not a current inferior-process-buffer matching
|
||||
SESSION then create it. If inferior process already
|
||||
exists (e.g. if it was manually started with `run-python'), make
|
||||
sure it's configured to work with ob-python. If session has
|
||||
already been configured as such, do nothing. Return the
|
||||
initialized session."
|
||||
(save-window-excursion
|
||||
(let* ((session (if session (intern session) :default))
|
||||
(py-buffer (org-babel-python-session-buffer session))
|
||||
(cmd (if (member system-type '(cygwin windows-nt ms-dos))
|
||||
(concat org-babel-python-command " -i")
|
||||
org-babel-python-command)))
|
||||
(cond
|
||||
((eq 'python org-babel-python-mode) ; python.el
|
||||
(unless py-buffer
|
||||
(setq py-buffer (org-babel-python-with-earmuffs session)))
|
||||
(let ((python-shell-buffer-name
|
||||
(org-babel-python-without-earmuffs py-buffer)))
|
||||
(run-python cmd)
|
||||
(with-current-buffer py-buffer
|
||||
(add-hook
|
||||
'python-shell-first-prompt-hook
|
||||
(lambda ()
|
||||
(setq-local org-babel-python--initialized t)
|
||||
(message "I am running!!!"))
|
||||
nil 'local))))
|
||||
((and (eq 'python-mode org-babel-python-mode)
|
||||
(fboundp 'py-shell)) ; python-mode.el
|
||||
(require 'python-mode)
|
||||
;; Make sure that py-which-bufname is initialized, as otherwise
|
||||
;; it will be overwritten the first time a Python buffer is
|
||||
;; created.
|
||||
(py-choose-shell)
|
||||
;; `py-shell' creates a buffer whose name is the value of
|
||||
;; `py-which-bufname' with '*'s at the beginning and end
|
||||
(let* ((bufname (if (and py-buffer (buffer-live-p py-buffer))
|
||||
(replace-regexp-in-string ;; zap surrounding *
|
||||
"^\\*\\([^*]+\\)\\*$" "\\1" py-buffer)
|
||||
(concat "Python-" (symbol-name session))))
|
||||
(py-which-bufname bufname))
|
||||
(setq py-buffer (org-babel-python-with-earmuffs bufname))
|
||||
(py-shell nil nil t org-babel-python-command py-buffer nil nil t nil)))
|
||||
(t
|
||||
(error "No function available for running an inferior Python")))
|
||||
;; Wait until Python initializes.
|
||||
(if (eq 'python org-babel-python-mode) ; python.el
|
||||
;; This is more reliable compared to
|
||||
;; `org-babel-comint-wait-for-output' as python may emit
|
||||
;; multiple prompts during initialization.
|
||||
(with-current-buffer py-buffer
|
||||
(while (not org-babel-python--initialized)
|
||||
(sleep-for 0.01)))
|
||||
(org-babel-comint-wait-for-output py-buffer))
|
||||
(py-buffer (org-babel-session-buffer:python session))
|
||||
(python-shell-buffer-name
|
||||
(org-babel-python-without-earmuffs py-buffer))
|
||||
(existing-session-p (comint-check-proc py-buffer))
|
||||
(cmd (org-babel-python--command t)))
|
||||
(if cmd
|
||||
(let* ((cmd-split (split-string-and-unquote cmd))
|
||||
(python-shell-interpreter (car cmd-split))
|
||||
(python-shell-interpreter-args
|
||||
(combine-and-quote-strings
|
||||
(append (cdr cmd-split)
|
||||
(when (member system-type
|
||||
'(cygwin windows-nt ms-dos))
|
||||
(list "-i"))))))
|
||||
(run-python))
|
||||
(run-python))
|
||||
(with-current-buffer py-buffer
|
||||
(if existing-session-p
|
||||
;; Session was created outside Org. Assume first prompt
|
||||
;; already happened; run session setup code directly
|
||||
(unless org-babel-python--initialized
|
||||
;; Ensure first prompt. Based on python-tests.el
|
||||
;; (`python-tests-shell-wait-for-prompt')
|
||||
(while (not (org-babel-python--python-util-comint-end-of-output-p))
|
||||
(sit-for 0.1))
|
||||
(org-babel-python--setup-session))
|
||||
;; Adding to `python-shell-first-prompt-hook' immediately
|
||||
;; after `run-python' should be safe from race conditions,
|
||||
;; because subprocess output only arrives when Emacs is
|
||||
;; waiting (see elisp manual, "Output from Processes")
|
||||
(add-hook
|
||||
'python-shell-first-prompt-hook
|
||||
#'org-babel-python--setup-session
|
||||
nil 'local)))
|
||||
;; Wait until Python initializes
|
||||
;; This is more reliable compared to
|
||||
;; `org-babel-comint-wait-for-output' as python may emit
|
||||
;; multiple prompts during initialization.
|
||||
(with-current-buffer py-buffer
|
||||
(while (not org-babel-python--initialized)
|
||||
(sleep-for 0.010)))
|
||||
(setq org-babel-python-buffers
|
||||
(cons (cons session py-buffer)
|
||||
(assq-delete-all session org-babel-python-buffers)))
|
||||
session)))
|
||||
|
||||
(defun org-babel-python-initiate-session (&optional session _params)
|
||||
"Create a session named SESSION according to PARAMS."
|
||||
"Initiate Python session named SESSION according to PARAMS.
|
||||
If there is not a current inferior-process-buffer matching
|
||||
SESSION then create it. If inferior process already
|
||||
exists (e.g. if it was manually started with `run-python'), make
|
||||
sure it's configured to work with ob-python. If session has
|
||||
already been configured as such, do nothing."
|
||||
(unless (string= session "none")
|
||||
(org-babel-python-session-buffer
|
||||
(org-babel-python-initiate-session-by-key session))))
|
||||
|
@ -251,31 +367,10 @@ then create. Return the initialized session."
|
|||
(defvar org-babel-python-eoe-indicator "org_babel_python_eoe"
|
||||
"A string to indicate that evaluation has completed.")
|
||||
|
||||
(defconst org-babel-python-wrapper-method
|
||||
"
|
||||
def main():
|
||||
%s
|
||||
|
||||
open('%s', 'w').write( str(main()) )")
|
||||
(defconst org-babel-python-pp-wrapper-method
|
||||
"
|
||||
import pprint
|
||||
def main():
|
||||
%s
|
||||
|
||||
open('%s', 'w').write( pprint.pformat(main()) )")
|
||||
|
||||
(defconst org-babel-python--exec-tmpfile "\
|
||||
with open('%s') as __org_babel_python_tmpfile:
|
||||
exec(compile(__org_babel_python_tmpfile.read(), __org_babel_python_tmpfile.name, 'exec'))"
|
||||
"Template for Python session command with output results.
|
||||
|
||||
Has a single %s escape, the tempfile containing the source code
|
||||
to evaluate.")
|
||||
|
||||
(defun org-babel-python-format-session-value
|
||||
(src-file result-file result-params)
|
||||
"Return Python code to evaluate SRC-FILE and write result to RESULT-FILE."
|
||||
"Return Python code to evaluate SRC-FILE and write result to RESULT-FILE.
|
||||
RESULT-PARAMS defines the result type."
|
||||
(format "\
|
||||
import ast
|
||||
with open('%s') as __org_babel_python_tmpfile:
|
||||
|
@ -286,30 +381,25 @@ if isinstance(__org_babel_python_final, ast.Expr):
|
|||
exec(compile(__org_babel_python_ast, '<string>', 'exec'))
|
||||
__org_babel_python_final = eval(compile(ast.Expression(
|
||||
__org_babel_python_final.value), '<string>', 'eval'))
|
||||
with open('%s', 'w') as __org_babel_python_tmpfile:
|
||||
if %s:
|
||||
import pprint
|
||||
__org_babel_python_tmpfile.write(pprint.pformat(__org_babel_python_final))
|
||||
else:
|
||||
__org_babel_python_tmpfile.write(str(__org_babel_python_final))
|
||||
else:
|
||||
exec(compile(__org_babel_python_ast, '<string>', 'exec'))
|
||||
__org_babel_python_final = None"
|
||||
__org_babel_python_final = None
|
||||
__org_babel_python_format_value(__org_babel_python_final, '%s', %s)"
|
||||
(org-babel-process-file-name src-file 'noquote)
|
||||
(org-babel-process-file-name result-file 'noquote)
|
||||
(if (member "pp" result-params) "True" "False")))
|
||||
(org-babel-python-var-to-python result-params)))
|
||||
|
||||
(defun org-babel-python-evaluate
|
||||
(session body &optional result-type result-params preamble async)
|
||||
(session body &optional result-type result-params preamble async graphics-file)
|
||||
"Evaluate BODY as Python code."
|
||||
(if session
|
||||
(if async
|
||||
(org-babel-python-async-evaluate-session
|
||||
session body result-type result-params)
|
||||
session body result-type result-params graphics-file)
|
||||
(org-babel-python-evaluate-session
|
||||
session body result-type result-params))
|
||||
session body result-type result-params graphics-file))
|
||||
(org-babel-python-evaluate-external-process
|
||||
body result-type result-params preamble)))
|
||||
body result-type result-params preamble graphics-file)))
|
||||
|
||||
(defun org-babel-python--shift-right (body &optional count)
|
||||
(with-temp-buffer
|
||||
|
@ -325,33 +415,40 @@ else:
|
|||
(buffer-string)))
|
||||
|
||||
(defun org-babel-python-evaluate-external-process
|
||||
(body &optional result-type result-params preamble)
|
||||
(body &optional result-type result-params preamble graphics-file)
|
||||
"Evaluate BODY in external python process.
|
||||
If RESULT-TYPE equals `output' then return standard output as a
|
||||
string. If RESULT-TYPE equals `value' then return the value of the
|
||||
last statement in BODY, as elisp."
|
||||
string. If RESULT-TYPE equals `value' then return the value of
|
||||
the last statement in BODY, as elisp. If GRAPHICS-FILE is
|
||||
non-nil, then save graphical results to that file instead."
|
||||
(let ((raw
|
||||
(pcase result-type
|
||||
(`output (org-babel-eval org-babel-python-command
|
||||
(`output (org-babel-eval (org-babel-python--command nil)
|
||||
(concat preamble (and preamble "\n")
|
||||
body)))
|
||||
(`value (let ((tmp-file (org-babel-temp-file "python-")))
|
||||
(org-babel-eval
|
||||
org-babel-python-command
|
||||
(if graphics-file
|
||||
(format org-babel-python--output-graphics-wrapper
|
||||
body graphics-file)
|
||||
body))))
|
||||
(`value (let ((results-file (or graphics-file
|
||||
(org-babel-temp-file "python-"))))
|
||||
(org-babel-eval (org-babel-python--command nil)
|
||||
(concat
|
||||
preamble (and preamble "\n")
|
||||
(format
|
||||
(if (member "pp" result-params)
|
||||
org-babel-python-pp-wrapper-method
|
||||
org-babel-python-wrapper-method)
|
||||
(org-babel-python--shift-right body)
|
||||
(org-babel-process-file-name tmp-file 'noquote))))
|
||||
(org-babel-eval-read-file tmp-file))))))
|
||||
(concat org-babel-python--def-format-value "
|
||||
def main():
|
||||
%s
|
||||
|
||||
__org_babel_python_format_value(main(), '%s', %s)")
|
||||
(org-babel-python--shift-right body)
|
||||
(org-babel-process-file-name results-file 'noquote)
|
||||
(org-babel-python-var-to-python result-params))))
|
||||
(org-babel-eval-read-file results-file))))))
|
||||
(org-babel-result-cond result-params
|
||||
raw
|
||||
(org-babel-python-table-or-string (org-trim raw)))))
|
||||
(org-babel-python-table-or-string raw))))
|
||||
|
||||
(defun org-babel-python--send-string (session body)
|
||||
(defun org-babel-python-send-string (session body)
|
||||
"Pass BODY to the Python process in SESSION.
|
||||
Return output."
|
||||
(with-current-buffer session
|
||||
|
@ -369,48 +466,54 @@ finally:
|
|||
print('%s')"
|
||||
(org-babel-python--shift-right body 4)
|
||||
org-babel-python-eoe-indicator)))
|
||||
(if (not (eq 'python-mode org-babel-python-mode))
|
||||
(let ((python-shell-buffer-name
|
||||
(org-babel-python-without-earmuffs session)))
|
||||
(python-shell-send-string body))
|
||||
(require 'python-mode)
|
||||
(py-shell-send-string body (get-buffer-process session)))
|
||||
(let ((python-shell-buffer-name
|
||||
(org-babel-python-without-earmuffs session)))
|
||||
(python-shell-send-string body))
|
||||
;; same as `python-shell-comint-end-of-output-p' in emacs-25.1+
|
||||
(while (not (string-match
|
||||
org-babel-python-eoe-indicator
|
||||
string-buffer))
|
||||
(while (not (and (python-shell-comint-end-of-output-p string-buffer)
|
||||
(string-match
|
||||
org-babel-python-eoe-indicator
|
||||
string-buffer)))
|
||||
(accept-process-output (get-buffer-process (current-buffer))))
|
||||
(org-babel-chomp (substring string-buffer 0 (match-beginning 0))))))
|
||||
|
||||
(defun org-babel-python-evaluate-session
|
||||
(session body &optional result-type result-params)
|
||||
(session body &optional result-type result-params graphics-file)
|
||||
"Pass BODY to the Python process in SESSION.
|
||||
If RESULT-TYPE equals `output' then return standard output as a
|
||||
string. If RESULT-TYPE equals `value' then return the value of the
|
||||
last statement in BODY, as elisp."
|
||||
string. If RESULT-TYPE equals `value' then return the value of
|
||||
the last statement in BODY, as elisp. If GRAPHICS-FILE is
|
||||
non-nil, then save graphical results to that file instead."
|
||||
(let* ((tmp-src-file (org-babel-temp-file "python-"))
|
||||
(results
|
||||
(progn
|
||||
(with-temp-file tmp-src-file (insert body))
|
||||
(with-temp-file tmp-src-file
|
||||
(insert (if (and graphics-file (eq result-type 'output))
|
||||
(format org-babel-python--output-graphics-wrapper
|
||||
body graphics-file)
|
||||
body)))
|
||||
(pcase result-type
|
||||
(`output
|
||||
(let ((body (format org-babel-python--exec-tmpfile
|
||||
(let ((body (format "\
|
||||
with open('%s') as f:
|
||||
exec(compile(f.read(), f.name, 'exec'))"
|
||||
(org-babel-process-file-name
|
||||
tmp-src-file 'noquote))))
|
||||
(org-babel-python--send-string session body)))
|
||||
(org-babel-python-send-string session body)))
|
||||
(`value
|
||||
(let* ((tmp-results-file (org-babel-temp-file "python-"))
|
||||
(let* ((results-file (or graphics-file
|
||||
(org-babel-temp-file "python-")))
|
||||
(body (org-babel-python-format-session-value
|
||||
tmp-src-file tmp-results-file result-params)))
|
||||
(org-babel-python--send-string session body)
|
||||
(sleep-for 0.01)
|
||||
(org-babel-eval-read-file tmp-results-file)))))))
|
||||
tmp-src-file results-file result-params)))
|
||||
(org-babel-python-send-string session body)
|
||||
(sleep-for 0.010)
|
||||
(org-babel-eval-read-file results-file)))))))
|
||||
(org-babel-result-cond result-params
|
||||
results
|
||||
(org-babel-python-table-or-string results))))
|
||||
|
||||
(defun org-babel-python-read-string (string)
|
||||
"Strip \\='s from around Python string."
|
||||
"Strip \\='s from around Python STRING."
|
||||
(if (and (string-prefix-p "'" string)
|
||||
(string-suffix-p "'" string))
|
||||
(substring string 1 -1)
|
||||
|
@ -428,7 +531,7 @@ last statement in BODY, as elisp."
|
|||
(org-babel-python-table-or-string results))))
|
||||
|
||||
(defun org-babel-python-async-evaluate-session
|
||||
(session body &optional result-type result-params)
|
||||
(session body &optional result-type result-params graphics-file)
|
||||
"Asynchronously evaluate BODY in SESSION.
|
||||
Returns a placeholder string for insertion, to later be replaced
|
||||
by `org-babel-comint-async-filter'."
|
||||
|
@ -436,28 +539,37 @@ by `org-babel-comint-async-filter'."
|
|||
session (current-buffer)
|
||||
"ob_comint_async_python_\\(.+\\)_\\(.+\\)"
|
||||
'org-babel-chomp 'org-babel-python-async-value-callback)
|
||||
(let ((python-shell-buffer-name (org-babel-python-without-earmuffs session)))
|
||||
(pcase result-type
|
||||
(`output
|
||||
(let ((uuid (md5 (number-to-string (random 100000000)))))
|
||||
(with-temp-buffer
|
||||
(insert (format org-babel-python-async-indicator "start" uuid))
|
||||
(insert "\n")
|
||||
(insert body)
|
||||
(insert "\n")
|
||||
(insert (format org-babel-python-async-indicator "end" uuid))
|
||||
(python-shell-send-buffer))
|
||||
uuid))
|
||||
(`value
|
||||
(let ((tmp-results-file (org-babel-temp-file "python-"))
|
||||
(tmp-src-file (org-babel-temp-file "python-")))
|
||||
(with-temp-file tmp-src-file (insert body))
|
||||
(with-temp-buffer
|
||||
(insert (org-babel-python-format-session-value tmp-src-file tmp-results-file result-params))
|
||||
(insert "\n")
|
||||
(insert (format org-babel-python-async-indicator "file" tmp-results-file))
|
||||
(python-shell-send-buffer))
|
||||
tmp-results-file)))))
|
||||
(pcase result-type
|
||||
(`output
|
||||
(let ((uuid (org-id-uuid)))
|
||||
(with-temp-buffer
|
||||
(insert (format org-babel-python-async-indicator "start" uuid))
|
||||
(insert "\n")
|
||||
(insert (if graphics-file
|
||||
(format org-babel-python--output-graphics-wrapper
|
||||
body graphics-file)
|
||||
body))
|
||||
(insert "\n")
|
||||
(insert (format org-babel-python-async-indicator "end" uuid))
|
||||
(let ((python-shell-buffer-name
|
||||
(org-babel-python-without-earmuffs session)))
|
||||
(python-shell-send-buffer)))
|
||||
uuid))
|
||||
(`value
|
||||
(let ((results-file (or graphics-file
|
||||
(org-babel-temp-file "python-")))
|
||||
(tmp-src-file (org-babel-temp-file "python-")))
|
||||
(with-temp-file tmp-src-file (insert body))
|
||||
(with-temp-buffer
|
||||
(insert (org-babel-python-format-session-value
|
||||
tmp-src-file results-file result-params))
|
||||
(insert "\n")
|
||||
(unless graphics-file
|
||||
(insert (format org-babel-python-async-indicator "file" results-file)))
|
||||
(let ((python-shell-buffer-name
|
||||
(org-babel-python-without-earmuffs session)))
|
||||
(python-shell-send-buffer)))
|
||||
results-file))))
|
||||
|
||||
(provide 'ob-python)
|
||||
|
||||
|
|
|
@ -59,8 +59,9 @@
|
|||
|
||||
(declare-function org-babel-lob-get-info "ob-lob" (&optional datum no-eval))
|
||||
(declare-function org-element-at-point "org-element" (&optional pom cached-only))
|
||||
(declare-function org-element-property "org-element" (property element))
|
||||
(declare-function org-element-type "org-element" (element))
|
||||
(declare-function org-element-property "org-element-ast" (property node))
|
||||
(declare-function org-element-post-affiliated "org-element" (node))
|
||||
(declare-function org-element-type "org-element-ast" (node &optional anonymous))
|
||||
(declare-function org-end-of-meta-data "org" (&optional full))
|
||||
(declare-function org-find-property "org" (property &optional value))
|
||||
(declare-function org-id-find-id-file "org-id" (id))
|
||||
|
@ -155,8 +156,9 @@ Emacs Lisp representation of the value of the variable."
|
|||
(when (string-match "^\\(.+\\):\\(.+\\)$" ref)
|
||||
(setq split-file (match-string 1 ref))
|
||||
(setq split-ref (match-string 2 ref))
|
||||
(find-file split-file)
|
||||
(setq ref split-ref))
|
||||
(when (file-exists-p split-file)
|
||||
(find-file split-file)
|
||||
(setq ref split-ref)))
|
||||
(org-with-wide-buffer
|
||||
(goto-char (point-min))
|
||||
(let* ((params (append args '((:results . "none"))))
|
||||
|
@ -171,7 +173,7 @@ Emacs Lisp representation of the value of the variable."
|
|||
(let ((e (org-element-at-point)))
|
||||
(when (equal (org-element-property :name e) ref)
|
||||
(goto-char
|
||||
(org-element-property :post-affiliated e))
|
||||
(org-element-post-affiliated e))
|
||||
(pcase (org-element-type e)
|
||||
(`babel-call
|
||||
(throw :found
|
||||
|
|
|
@ -73,7 +73,7 @@ It's possible to override it by using a header argument `:ruby'")
|
|||
:type 'symbol)
|
||||
|
||||
(defun org-babel-execute:ruby (body params)
|
||||
"Execute a block of Ruby code with Babel.
|
||||
"Execute Ruby BODY according to PARAMS.
|
||||
This function is called by `org-babel-execute-src-block'."
|
||||
(let* ((session (org-babel-ruby-initiate-session
|
||||
(cdr (assq :session params)) params))
|
||||
|
@ -86,7 +86,7 @@ This function is called by `org-babel-execute-src-block'."
|
|||
body params (org-babel-variable-assignments:ruby params)))
|
||||
(result (if (member "xmp" result-params)
|
||||
(with-temp-buffer
|
||||
(require 'rcodetools)
|
||||
(org-require-package 'rcodetools "rcodetools (gem package)")
|
||||
(insert full-body)
|
||||
(xmp (cdr (assq :xmp-option params)))
|
||||
(buffer-string))
|
||||
|
@ -127,7 +127,8 @@ This function is called by `org-babel-execute-src-block'."
|
|||
;; helper functions
|
||||
|
||||
(defun org-babel-variable-assignments:ruby (params)
|
||||
"Return list of ruby statements assigning the block's variables."
|
||||
"Return list of ruby statements assigning the block's variables.
|
||||
The assignments are defined in PARAMS."
|
||||
(mapcar
|
||||
(lambda (pair)
|
||||
(format "%s=%s"
|
||||
|
@ -140,7 +141,7 @@ This function is called by `org-babel-execute-src-block'."
|
|||
Convert an elisp value into a string of ruby source code
|
||||
specifying a variable of the same value."
|
||||
(if (listp var)
|
||||
(concat "[" (mapconcat #'org-babel-ruby-var-to-ruby var ", ") "]")
|
||||
(concat "[" (mapconcat #'org-babel-ruby-var-to-ruby var ", \n") "]")
|
||||
(if (eq var 'hline)
|
||||
org-babel-ruby-hline-to
|
||||
(format "%S" var))))
|
||||
|
@ -152,20 +153,28 @@ Emacs-lisp table, otherwise return the results as a string."
|
|||
(let ((res (org-babel-script-escape results)))
|
||||
(if (listp res)
|
||||
(mapcar (lambda (el) (if (not el)
|
||||
org-babel-ruby-nil-to el))
|
||||
org-babel-ruby-nil-to el))
|
||||
res)
|
||||
res)))
|
||||
|
||||
(defvar org-babel-ruby-prompt "_org_babel_ruby_prompt "
|
||||
"String used for unique prompt.")
|
||||
|
||||
(defvar org-babel-ruby-define-prompt
|
||||
(format "IRB.conf[:PROMPT][:CUSTOM] = { :PROMPT_I => \"%s\" }" org-babel-ruby-prompt))
|
||||
|
||||
(defun org-babel-ruby-initiate-session (&optional session params)
|
||||
"Initiate a ruby session.
|
||||
If there is not a current inferior-process-buffer in SESSION
|
||||
then create one. Return the initialized session."
|
||||
then create one. Return the initialized session.
|
||||
Session settings (`:ruby' header arg value) are taken from PARAMS."
|
||||
(unless (string= session "none")
|
||||
(require 'inf-ruby)
|
||||
(org-require-package 'inf-ruby)
|
||||
(let* ((command (cdr (or (assq :ruby params)
|
||||
(assoc inf-ruby-default-implementation
|
||||
inf-ruby-implementations))))
|
||||
(buffer (get-buffer (format "*%s*" session)))
|
||||
(new-session? (not buffer))
|
||||
(session-buffer (or buffer (save-window-excursion
|
||||
(run-ruby-or-pop-to-buffer
|
||||
(if (functionp command)
|
||||
|
@ -176,16 +185,32 @@ then create one. Return the initialized session."
|
|||
(inf-ruby-buffer)))
|
||||
(current-buffer)))))
|
||||
(if (org-babel-comint-buffer-livep session-buffer)
|
||||
(progn (sit-for .25) session-buffer)
|
||||
(progn
|
||||
(sit-for .25)
|
||||
;; Setup machine-readable prompt: no echo, prompts matching
|
||||
;; uniquely by regexp.
|
||||
(when new-session?
|
||||
(with-current-buffer session-buffer
|
||||
(setq-local
|
||||
org-babel-comint-prompt-regexp-old comint-prompt-regexp
|
||||
comint-prompt-regexp (concat "^" org-babel-ruby-prompt))
|
||||
(insert org-babel-ruby-define-prompt ";")
|
||||
(insert "_org_prompt_mode=conf.prompt_mode;conf.prompt_mode=:CUSTOM;")
|
||||
(insert "conf.echo=false\n")
|
||||
(comint-send-input nil t)))
|
||||
session-buffer)
|
||||
(sit-for .5)
|
||||
(org-babel-ruby-initiate-session session)))))
|
||||
|
||||
(defvar org-babel-ruby-eoe-indicator ":org_babel_ruby_eoe"
|
||||
"String to indicate that evaluation has completed.")
|
||||
|
||||
(defvar org-babel-ruby-f-write
|
||||
"File.open('%s','w'){|f| f.write((_.class == String) ? _ : _.inspect)}")
|
||||
|
||||
(defvar org-babel-ruby-pp-f-write
|
||||
"File.open('%s','w'){|f| $stdout = f; pp(results); $stdout = orig_out}")
|
||||
|
||||
(defvar org-babel-ruby-wrapper-method
|
||||
"
|
||||
def main()
|
||||
|
@ -194,6 +219,7 @@ end
|
|||
results = main()
|
||||
File.open('%s', 'w'){ |f| f.write((results.class == String) ? results : results.inspect) }
|
||||
")
|
||||
|
||||
(defvar org-babel-ruby-pp-wrapper-method
|
||||
"
|
||||
require 'pp'
|
||||
|
@ -237,7 +263,6 @@ return the value of the last statement in BODY, as elisp."
|
|||
(org-babel-comint-with-output
|
||||
(buffer org-babel-ruby-eoe-indicator t eoe-string)
|
||||
(insert eoe-string) (comint-send-input nil t))
|
||||
;; Now we can start the evaluation.
|
||||
(mapconcat
|
||||
#'identity
|
||||
(butlast
|
||||
|
@ -246,14 +271,9 @@ return the value of the last statement in BODY, as elisp."
|
|||
#'org-trim
|
||||
(org-babel-comint-with-output
|
||||
(buffer org-babel-ruby-eoe-indicator t body)
|
||||
(mapc
|
||||
(lambda (line)
|
||||
(insert (org-babel-chomp line)) (comint-send-input nil t))
|
||||
(list "conf.echo=false;_org_prompt_mode=conf.prompt_mode;conf.prompt_mode=:NULL"
|
||||
body
|
||||
"conf.prompt_mode=_org_prompt_mode;conf.echo=true"
|
||||
eoe-string)))
|
||||
"\n") "[\r\n]") 4) "\n")))
|
||||
(insert (org-babel-chomp body) "\n" eoe-string)
|
||||
(comint-send-input nil t))
|
||||
"\n") "[\r\n]")) "\n")))
|
||||
(`value
|
||||
(let* ((tmp-file (org-babel-temp-file "ruby-"))
|
||||
(ppp (or (member "code" result-params)
|
||||
|
@ -273,7 +293,7 @@ return the value of the last statement in BODY, as elisp."
|
|||
"results=_" "require 'pp'" "orig_out = $stdout"
|
||||
(format org-babel-ruby-pp-f-write
|
||||
(org-babel-process-file-name tmp-file 'noquote))))
|
||||
(list org-babel-ruby-eoe-indicator)))
|
||||
(list (format "puts \"%s\"" org-babel-ruby-eoe-indicator))))
|
||||
(comint-send-input nil t))
|
||||
(org-babel-eval-read-file tmp-file))))))
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
(defvar geiser-debug-jump-to-debug-p) ; Defined in geiser-debug.el
|
||||
(defvar geiser-repl-use-other-window) ; Defined in geiser-repl.el
|
||||
(defvar geiser-repl-window-allow-split) ; Defined in geiser-repl.el
|
||||
|
||||
(declare-function geiser-connect "ext:geiser-repl" (impl &optional host port))
|
||||
(declare-function run-geiser "ext:geiser-repl" (impl))
|
||||
(declare-function geiser "ext:geiser-repl" (impl))
|
||||
(declare-function geiser-mode "ext:geiser-mode" ())
|
||||
|
@ -65,6 +65,9 @@
|
|||
(declare-function geiser-repl-exit "ext:geiser-repl" (&optional arg))
|
||||
(declare-function geiser-eval--retort-output "ext:geiser-eval" (ret))
|
||||
(declare-function geiser-eval--retort-result-str "ext:geiser-eval" (ret prefix))
|
||||
(declare-function geiser-eval--retort-error "ext:geiser-eval" (ret))
|
||||
(declare-function geiser-eval--retort-error-msg "ext:geiser-eval" (err))
|
||||
(declare-function geiser-eval--error-msg "ext:geiser-eval" (err))
|
||||
|
||||
(defcustom org-babel-scheme-null-to 'hline
|
||||
"Replace `null' and empty lists in scheme tables with this before returning."
|
||||
|
@ -75,6 +78,17 @@
|
|||
|
||||
(defvar org-babel-default-header-args:scheme '()
|
||||
"Default header arguments for scheme code blocks.")
|
||||
(defconst org-babel-header-args:scheme '((host . :any)
|
||||
(port . :any))
|
||||
"Header arguments supported in Scheme.")
|
||||
|
||||
(defun org-babel-scheme-expand-header-arg-vars (vars)
|
||||
"Expand :var header arguments given as VARS."
|
||||
(mapconcat
|
||||
(lambda (var)
|
||||
(format "(define %S %S)" (car var) (cdr var)))
|
||||
vars
|
||||
"\n"))
|
||||
|
||||
(defun org-babel-expand-body:scheme (body params)
|
||||
"Expand BODY according to PARAMS, return the expanded body."
|
||||
|
@ -83,13 +97,7 @@
|
|||
(postpends (cdr (assq :epilogue params))))
|
||||
(concat (and prepends (concat prepends "\n"))
|
||||
(if (null vars) body
|
||||
(format "(let (%s)\n%s\n)"
|
||||
(mapconcat
|
||||
(lambda (var)
|
||||
(format "%S" (print `(,(car var) ',(cdr var)))))
|
||||
vars
|
||||
"\n ")
|
||||
body))
|
||||
(concat (org-babel-scheme-expand-header-arg-vars vars) "\n" body))
|
||||
(and postpends (concat "\n" postpends)))))
|
||||
|
||||
|
||||
|
@ -116,13 +124,17 @@
|
|||
(with-current-buffer (set-buffer buffer)
|
||||
geiser-impl--implementation))
|
||||
|
||||
(defun org-babel-scheme-get-repl (impl name)
|
||||
"Switch to a scheme REPL, creating it if it doesn't exist."
|
||||
(defun org-babel-scheme-get-repl (impl name &optional host port)
|
||||
"Switch to a Scheme REPL, creating it if it doesn't exist.
|
||||
|
||||
If the variables HOST and PORT are set, connect to the running Scheme REPL."
|
||||
(let ((buffer (org-babel-scheme-get-session-buffer name)))
|
||||
(or buffer
|
||||
(progn
|
||||
(if (fboundp 'geiser)
|
||||
(geiser impl)
|
||||
(if (and host port)
|
||||
(geiser-connect impl host port)
|
||||
(geiser impl))
|
||||
;; Obsolete since Geiser 0.26.
|
||||
(run-geiser impl))
|
||||
(when name
|
||||
|
@ -159,7 +171,7 @@ org-babel-scheme-execute-with-geiser will use a temporary session."
|
|||
,@body
|
||||
(current-message))))
|
||||
|
||||
(defun org-babel-scheme-execute-with-geiser (code output impl repl)
|
||||
(defun org-babel-scheme-execute-with-geiser (code output impl repl &optional host port)
|
||||
"Execute code in specified REPL.
|
||||
If the REPL doesn't exist, create it using the given scheme
|
||||
implementation.
|
||||
|
@ -170,45 +182,58 @@ is true; otherwise returns the last value."
|
|||
(with-temp-buffer
|
||||
(insert (format ";; -*- geiser-scheme-implementation: %s -*-" impl))
|
||||
(newline)
|
||||
(insert code)
|
||||
(geiser-mode)
|
||||
(let ((geiser-repl-window-allow-split nil)
|
||||
(geiser-repl-use-other-window nil))
|
||||
(let ((repl-buffer (save-current-buffer
|
||||
(org-babel-scheme-get-repl impl repl))))
|
||||
(when (not (eq impl (org-babel-scheme-get-buffer-impl
|
||||
(let ((beg (point)))
|
||||
(insert code)
|
||||
(geiser-mode)
|
||||
(let ((geiser-repl-window-allow-split nil)
|
||||
(geiser-repl-use-other-window nil))
|
||||
(let ((repl-buffer (save-current-buffer
|
||||
(org-babel-scheme-get-repl impl repl host port))))
|
||||
(when (not (eq impl (org-babel-scheme-get-buffer-impl
|
||||
(current-buffer))))
|
||||
(message "Implementation mismatch: %s (%s) %s (%s)" impl (symbolp impl)
|
||||
(org-babel-scheme-get-buffer-impl (current-buffer))
|
||||
(symbolp (org-babel-scheme-get-buffer-impl
|
||||
(current-buffer)))))
|
||||
(setq geiser-repl--repl repl-buffer)
|
||||
(setq geiser-impl--implementation nil)
|
||||
(let ((geiser-debug-jump-to-debug-p nil)
|
||||
(geiser-debug-show-debug-p nil))
|
||||
;; `geiser-eval-region/wait' was introduced to await the
|
||||
;; result of async evaluation in geiser version 0.22.
|
||||
(let ((ret (funcall (if (fboundp 'geiser-eval-region/wait)
|
||||
#'geiser-eval-region/wait
|
||||
#'geiser-eval-region)
|
||||
(point-min)
|
||||
(point-max))))
|
||||
(setq result (if output
|
||||
(or (geiser-eval--retort-output ret)
|
||||
"Geiser Interpreter produced no output")
|
||||
(geiser-eval--retort-result-str ret "")))))
|
||||
(when (not repl)
|
||||
(save-current-buffer (set-buffer repl-buffer)
|
||||
(geiser-repl-exit))
|
||||
(set-process-query-on-exit-flag (get-buffer-process repl-buffer) nil)
|
||||
(kill-buffer repl-buffer)))))
|
||||
(message "Implementation mismatch: %s (%s) %s (%s)" impl (symbolp impl)
|
||||
(org-babel-scheme-get-buffer-impl (current-buffer))
|
||||
(symbolp (org-babel-scheme-get-buffer-impl
|
||||
(current-buffer)))))
|
||||
(setq geiser-repl--repl repl-buffer)
|
||||
(setq geiser-impl--implementation nil)
|
||||
(let ((geiser-debug-jump-to-debug-p nil)
|
||||
(geiser-debug-show-debug-p nil))
|
||||
;; `geiser-eval-region/wait' was introduced to await the
|
||||
;; result of async evaluation in geiser version 0.22.
|
||||
(let ((ret (funcall (if (fboundp 'geiser-eval-region/wait)
|
||||
#'geiser-eval-region/wait
|
||||
#'geiser-eval-region)
|
||||
;; Do not include top comment into evaluation.
|
||||
;; Apparently, mit-scheme has
|
||||
;; problems with the top comment we add:
|
||||
;; "Unexpected read restart on: #[textual-i/o-port 27 for console]"
|
||||
beg
|
||||
(point-max))))
|
||||
(let ((err (geiser-eval--retort-error ret)))
|
||||
(setq result (cond
|
||||
(output
|
||||
(or (geiser-eval--retort-output ret)
|
||||
"Geiser Interpreter produced no output"))
|
||||
(err nil)
|
||||
(t (geiser-eval--retort-result-str ret ""))))
|
||||
(when (not repl)
|
||||
(save-current-buffer (set-buffer repl-buffer)
|
||||
(geiser-repl-exit))
|
||||
(set-process-query-on-exit-flag (get-buffer-process repl-buffer) nil)
|
||||
(kill-buffer repl-buffer))
|
||||
(when err
|
||||
(let ((msg (geiser-eval--error-msg err)))
|
||||
(org-babel-eval-error-notify
|
||||
nil
|
||||
(concat (if (listp msg) (car msg) msg) "\n")))))))))))
|
||||
result))
|
||||
|
||||
(defun org-babel-scheme--table-or-string (results)
|
||||
"Convert RESULTS into an appropriate elisp value.
|
||||
If the results look like a list or tuple, then convert them into an
|
||||
Emacs-lisp table, otherwise return the results as a string."
|
||||
(let ((res (org-babel-script-escape results)))
|
||||
(let ((res (and results (org-babel-script-escape results))))
|
||||
(cond ((listp res)
|
||||
(mapcar (lambda (el)
|
||||
(if (or (null el) (eq el 'null))
|
||||
|
@ -231,6 +256,8 @@ This function is called by `org-babel-execute-src-block'."
|
|||
geiser-scheme-implementation
|
||||
geiser-default-implementation
|
||||
(car geiser-active-implementations)))
|
||||
(host (cdr (assq :host params)))
|
||||
(port (cdr (assq :port params)))
|
||||
(session (org-babel-scheme-make-session-name
|
||||
source-buffer-name (cdr (assq :session params)) impl))
|
||||
(full-body (org-babel-expand-body:scheme body params))
|
||||
|
@ -240,7 +267,9 @@ This function is called by `org-babel-execute-src-block'."
|
|||
full-body ; code
|
||||
(string= result-type "output") ; output?
|
||||
impl ; implementation
|
||||
(and (not (string= session "none")) session)))) ; session
|
||||
(and (not (string= session "none")) session) ; session
|
||||
host ; REPL host
|
||||
port))) ; REPL port
|
||||
(let ((table
|
||||
(org-babel-reassemble-table
|
||||
result
|
||||
|
|
|
@ -50,8 +50,8 @@ In case you want to use a different screen than one selected by your $PATH")
|
|||
"Default arguments to use when running screen source blocks.")
|
||||
|
||||
(defun org-babel-execute:screen (body params)
|
||||
"Send a block of code via screen to a terminal using Babel.
|
||||
\"default\" session is used when none is specified."
|
||||
"Send BODY via screen to a terminal using Babel, according to PARAMS.
|
||||
\"default\" session is used when none is specified in the PARAMS."
|
||||
(message "Sending source code block to interactive terminal session...")
|
||||
(save-window-excursion
|
||||
(let* ((session (cdr (assq :session params)))
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
;; Copyright (C) 2009-2024 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric Schulte
|
||||
;; Maintainer: Matthew Trzcinski <matt@excalamus.com>
|
||||
;; Keywords: literate programming, reproducible research
|
||||
;; URL: https://orgmode.org
|
||||
|
||||
|
@ -44,6 +45,11 @@
|
|||
(declare-function orgtbl-to-generic "org-table" (table params))
|
||||
|
||||
(defvar org-babel-default-header-args:shell '())
|
||||
|
||||
(defconst org-babel-header-args:shell
|
||||
'((async . ((yes no))))
|
||||
"Shell-specific header arguments.")
|
||||
|
||||
(defvar org-babel-shell-names)
|
||||
|
||||
(defconst org-babel-shell-set-prompt-commands
|
||||
|
@ -51,8 +57,6 @@
|
|||
("fish" . "function fish_prompt\n\techo \"%s\"\nend")
|
||||
;; prompt2 is like PS2 in POSIX shells.
|
||||
("csh" . "set prompt=\"%s\"\nset prompt2=\"\"")
|
||||
;; PowerShell, similar to fish, does not have PS2 equivalent.
|
||||
("posh" . "function prompt { \"%s\" }")
|
||||
;; PROMPT_COMMAND can override PS1 settings. Disable it.
|
||||
;; Disable PS2 to avoid garbage in multi-line inputs.
|
||||
(t . "PROMPT_COMMAND=;PS1=\"%s\";PS2="))
|
||||
|
@ -66,28 +70,32 @@ that will be called with a single additional argument: prompt string.
|
|||
The fallback association template is defined in (t . \"template\")
|
||||
alist element.")
|
||||
|
||||
(defvar org-babel-prompt-command)
|
||||
|
||||
(defun org-babel-shell-initialize ()
|
||||
"Define execution functions associated to shell names.
|
||||
This function has to be called whenever `org-babel-shell-names'
|
||||
is modified outside the Customize interface."
|
||||
(interactive)
|
||||
(dolist (name org-babel-shell-names)
|
||||
(eval `(defun ,(intern (concat "org-babel-execute:" name))
|
||||
(body params)
|
||||
,(format "Execute a block of %s commands with Babel." name)
|
||||
(let ((shell-file-name ,name)
|
||||
(org-babel-prompt-command
|
||||
(or (cdr (assoc ,name org-babel-shell-set-prompt-commands))
|
||||
(alist-get t org-babel-shell-set-prompt-commands))))
|
||||
(org-babel-execute:shell body params))))
|
||||
(eval `(defalias ',(intern (concat "org-babel-variable-assignments:" name))
|
||||
'org-babel-variable-assignments:shell
|
||||
,(format "Return list of %s statements assigning to the block's \
|
||||
(let ((fname (intern (concat "org-babel-execute:" name))))
|
||||
(defalias fname
|
||||
(lambda (body params)
|
||||
(:documentation
|
||||
(format "Execute a block of %s commands with Babel." name))
|
||||
(let ((explicit-shell-file-name name)
|
||||
(shell-file-name name))
|
||||
(org-babel-execute:shell body params))))
|
||||
(put fname 'definition-name 'org-babel-shell-initialize))
|
||||
(defalias (intern (concat "org-babel-variable-assignments:" name))
|
||||
#'org-babel-variable-assignments:shell
|
||||
(format "Return list of %s statements assigning to the block's \
|
||||
variables."
|
||||
name)))
|
||||
(eval `(defvar ,(intern (concat "org-babel-default-header-args:" name)) '()))))
|
||||
name))
|
||||
(funcall (if (fboundp 'defvar-1) #'defvar-1 #'set) ;Emacs-29
|
||||
(intern (concat "org-babel-default-header-args:" name))
|
||||
nil)
|
||||
(funcall (if (fboundp 'defvar-1) #'defvar-1 #'set) ;Emacs-29
|
||||
(intern (concat "org-babel-header-args:" name))
|
||||
nil)))
|
||||
|
||||
(defcustom org-babel-shell-names
|
||||
'("sh" "bash" "zsh" "fish" "csh" "ash" "dash" "ksh" "mksh" "posh")
|
||||
|
@ -114,7 +122,7 @@ a shell execution being its exit code."
|
|||
:package-version '(Org . "9.4"))
|
||||
|
||||
(defun org-babel-execute:shell (body params)
|
||||
"Execute a block of Shell commands with Babel.
|
||||
"Execute Shell BODY according to PARAMS.
|
||||
This function is called by `org-babel-execute-src-block'."
|
||||
(let* ((session (org-babel-sh-initiate-session
|
||||
(cdr (assq :session params))))
|
||||
|
@ -261,22 +269,38 @@ var of the same value."
|
|||
(org-babel-comint-wait-for-output (current-buffer))
|
||||
(org-babel-comint-input-command
|
||||
(current-buffer)
|
||||
(format org-babel-prompt-command org-babel-sh-prompt))
|
||||
(setq-local comint-prompt-regexp
|
||||
(concat "^" (regexp-quote org-babel-sh-prompt)
|
||||
" *"))
|
||||
(format
|
||||
(or (cdr (assoc (file-name-nondirectory shell-file-name)
|
||||
org-babel-shell-set-prompt-commands))
|
||||
(alist-get t org-babel-shell-set-prompt-commands))
|
||||
org-babel-sh-prompt))
|
||||
(setq-local
|
||||
org-babel-comint-prompt-regexp-old comint-prompt-regexp
|
||||
comint-prompt-regexp
|
||||
(concat "^" (regexp-quote org-babel-sh-prompt)
|
||||
" *"))
|
||||
;; Needed for Emacs 23 since the marker is initially
|
||||
;; undefined and the filter functions try to use it without
|
||||
;; checking.
|
||||
(set-marker comint-last-output-start (point))
|
||||
(get-buffer (current-buffer)))))))
|
||||
|
||||
(defconst ob-shell-async-indicator "echo 'ob_comint_async_shell_%s_%s'"
|
||||
"Session output delimiter template.
|
||||
See `org-babel-comint-async-indicator'.")
|
||||
|
||||
(defun ob-shell-async-chunk-callback (string)
|
||||
"Filter applied to results before insertion.
|
||||
See `org-babel-comint-async-chunk-callback'."
|
||||
(replace-regexp-in-string comint-prompt-regexp "" string))
|
||||
|
||||
(defun org-babel-sh-evaluate (session body &optional params stdin cmdline)
|
||||
"Pass BODY to the Shell process in BUFFER.
|
||||
If RESULT-TYPE equals `output' then return a list of the outputs
|
||||
of the statements in BODY, if RESULT-TYPE equals `value' then
|
||||
return the value of the last statement in BODY."
|
||||
(let* ((shebang (cdr (assq :shebang params)))
|
||||
(async (org-babel-comint-use-async params))
|
||||
(results-params (cdr (assq :result-params params)))
|
||||
(value-is-exit-status
|
||||
(or (and
|
||||
|
@ -308,19 +332,37 @@ return the value of the last statement in BODY."
|
|||
(concat (file-local-name script-file) " " cmdline)))))
|
||||
(buffer-string))))
|
||||
(session ; session evaluation
|
||||
(mapconcat
|
||||
#'org-babel-sh-strip-weird-long-prompt
|
||||
(mapcar
|
||||
#'org-trim
|
||||
(butlast ; Remove eoe indicator
|
||||
(org-babel-comint-with-output
|
||||
(session org-babel-sh-eoe-output t body)
|
||||
(insert (org-trim body) "\n"
|
||||
org-babel-sh-eoe-indicator)
|
||||
(comint-send-input nil t))
|
||||
;; Remove `org-babel-sh-eoe-indicator' output line.
|
||||
1))
|
||||
"\n"))
|
||||
(if async
|
||||
(progn
|
||||
(let ((uuid (org-id-uuid)))
|
||||
(org-babel-comint-async-register
|
||||
session
|
||||
(current-buffer)
|
||||
"ob_comint_async_shell_\\(.+\\)_\\(.+\\)"
|
||||
'ob-shell-async-chunk-callback
|
||||
nil)
|
||||
(org-babel-comint-async-delete-dangling-and-eval
|
||||
session
|
||||
(insert (format ob-shell-async-indicator "start" uuid))
|
||||
(comint-send-input nil t)
|
||||
(insert (org-trim body))
|
||||
(comint-send-input nil t)
|
||||
(insert (format ob-shell-async-indicator "end" uuid))
|
||||
(comint-send-input nil t))
|
||||
uuid))
|
||||
(mapconcat
|
||||
#'org-babel-sh-strip-weird-long-prompt
|
||||
(mapcar
|
||||
#'org-trim
|
||||
(butlast ; Remove eoe indicator
|
||||
(org-babel-comint-with-output
|
||||
(session org-babel-sh-eoe-output t body)
|
||||
(insert (org-trim body) "\n"
|
||||
org-babel-sh-eoe-indicator)
|
||||
(comint-send-input nil t))
|
||||
;; Remove `org-babel-sh-eoe-indicator' output line.
|
||||
1))
|
||||
"\n")))
|
||||
;; External shell script, with or without a predefined
|
||||
;; shebang.
|
||||
((org-string-nw-p shebang)
|
||||
|
@ -331,7 +373,13 @@ return the value of the last statement in BODY."
|
|||
(when padline (insert "\n"))
|
||||
(insert body))
|
||||
(set-file-modes script-file #o755)
|
||||
(org-babel-eval script-file "")))
|
||||
(if (file-remote-p script-file)
|
||||
;; Run remote script using its local path as COMMAND.
|
||||
;; The remote execution is ensured by setting
|
||||
;; correct `default-directory'.
|
||||
(let ((default-directory (file-name-directory script-file)))
|
||||
(org-babel-eval (file-local-name script-file) ""))
|
||||
(org-babel-eval script-file ""))))
|
||||
(t (org-babel-eval shell-file-name (org-trim body))))))
|
||||
(when (and results value-is-exit-status)
|
||||
(setq results (car (reverse (split-string results "\n" t)))))
|
||||
|
|
|
@ -113,9 +113,7 @@
|
|||
Set `sql-product' in Org edit buffer according to the
|
||||
corresponding :engine source block header argument."
|
||||
(let ((product (cdr (assq :engine (nth 2 info)))))
|
||||
(condition-case nil
|
||||
(sql-set-product product)
|
||||
(user-error "Cannot set `sql-product' in Org Src edit buffer"))))
|
||||
(sql-set-product product)))
|
||||
|
||||
(defun org-babel-sql-dbstring-mysql (host port user password database)
|
||||
"Make MySQL cmd line args for database connection. Pass nil to omit that arg."
|
||||
|
@ -409,11 +407,11 @@ argument mechanism."
|
|||
val (if sqlite
|
||||
nil
|
||||
'(:fmt (lambda (el) (if (stringp el)
|
||||
el
|
||||
(format "%S" el))))))))
|
||||
el
|
||||
(format "%S" el))))))))
|
||||
data-file)
|
||||
(if (stringp val) val (format "%S" val))))
|
||||
body)))
|
||||
body t t)))
|
||||
vars)
|
||||
body)
|
||||
|
||||
|
|
|
@ -57,13 +57,20 @@
|
|||
|
||||
(defun org-babel-expand-body:sqlite (body params)
|
||||
"Expand BODY according to the values of PARAMS."
|
||||
(org-babel-sql-expand-vars
|
||||
body (org-babel--get-vars params) t))
|
||||
(let ((prologue (cdr (assq :prologue params)))
|
||||
(epilogue (cdr (assq :epilogue params))))
|
||||
(mapconcat 'identity
|
||||
(list
|
||||
prologue
|
||||
(org-babel-sql-expand-vars
|
||||
body (org-babel--get-vars params) t)
|
||||
epilogue)
|
||||
"\n")))
|
||||
|
||||
(defvar org-babel-sqlite3-command "sqlite3")
|
||||
|
||||
(defun org-babel-execute:sqlite (body params)
|
||||
"Execute a block of Sqlite code with Babel.
|
||||
"Execute Sqlite BODY according to PARAMS.
|
||||
This function is called by `org-babel-execute-src-block'."
|
||||
(let ((result-params (split-string (or (cdr (assq :results params)) "")))
|
||||
(db (cdr (assq :db params)))
|
||||
|
@ -74,7 +81,6 @@ This function is called by `org-babel-execute-src-block'."
|
|||
(lambda (arg) (car (assq arg params)))
|
||||
(list :header :echo :bail :column
|
||||
:csv :html :line :list)))))
|
||||
(unless db (error "ob-sqlite: can't evaluate without a database"))
|
||||
(with-temp-buffer
|
||||
(insert
|
||||
(org-babel-eval
|
||||
|
@ -97,7 +103,7 @@ This function is called by `org-babel-execute-src-block'."
|
|||
(member :html others) separator)
|
||||
""
|
||||
"-csv"))
|
||||
(cons "db " db)))
|
||||
(cons "db" (or db ""))))
|
||||
;; body of the code block
|
||||
(org-babel-expand-body:sqlite body params)))
|
||||
(org-babel-result-cond result-params
|
||||
|
@ -122,7 +128,8 @@ This function is called by `org-babel-execute-src-block'."
|
|||
(org-babel-sql-expand-vars body vars t))
|
||||
|
||||
(defun org-babel-sqlite-table-or-scalar (result)
|
||||
"If RESULT looks like a trivial table, then unwrap it."
|
||||
"Cleanup cells in the RESULT table.
|
||||
If RESULT is a trivial 1x1 table, then unwrap it."
|
||||
(if (and (equal 1 (length result))
|
||||
(equal 1 (length (car result))))
|
||||
(org-babel-read (caar result) t)
|
||||
|
@ -133,7 +140,7 @@ This function is called by `org-babel-execute-src-block'."
|
|||
result)))
|
||||
|
||||
(defun org-babel-sqlite-offset-colnames (table headers-p)
|
||||
"If HEADERS-P is non-nil then offset the first row as column names."
|
||||
"If HEADERS-P is non-nil then offset the first row as column names in TABLE."
|
||||
(if headers-p
|
||||
(cons (car table) (cons 'hline (cdr table)))
|
||||
table))
|
||||
|
|
|
@ -87,18 +87,20 @@ is the equivalent of the following source code block:
|
|||
results
|
||||
#+end_src
|
||||
|
||||
NOTE: The quotation marks around the function name,
|
||||
`source-block', are optional.
|
||||
The quotation marks around the function name, `source-block', are
|
||||
optional.
|
||||
|
||||
NOTE: By default, string variable names are interpreted as
|
||||
references to source-code blocks, to force interpretation of a
|
||||
cell's value as a string, prefix the identifier a \"$\" (e.g.,
|
||||
\"$$2\" instead of \"$2\" or \"$@2$2\" instead of \"@2$2\").
|
||||
By default, string variable names are interpreted as references to
|
||||
source-code blocks, to force interpretation of a cell's value as a
|
||||
string, prefix the identifier a \"$\" (e.g., \"$$2\" instead of \"$2\"
|
||||
or \"$@2$2\" instead of \"@2$2\"). \"$\" will also force interpreting
|
||||
string value literally: $\"value\" will refer to a string, not a
|
||||
source block name.
|
||||
|
||||
NOTE: It is also possible to pass header arguments to the code
|
||||
block. In this case a table cell should hold the string value of
|
||||
the header argument which can then be passed before all variables
|
||||
as shown in the example below.
|
||||
It is also possible to pass header arguments to the code block. In
|
||||
this case a table cell should hold the string value of the header
|
||||
argument which can then be passed before all variables as shown in the
|
||||
example below.
|
||||
|
||||
| 1 | 2 | :file nothing.png | nothing.png |
|
||||
#+TBLFM: @1$4=\\='(org-sbe test-sbe $3 (x $1) (y $2))"
|
||||
|
@ -117,7 +119,7 @@ as shown in the example below.
|
|||
(prog1 nil (setq quote t))
|
||||
(prog1
|
||||
(cond
|
||||
(quote (format "\"%s\"" el))
|
||||
(quote (format "%S" el))
|
||||
((stringp el) (org-no-properties el))
|
||||
(t el))
|
||||
(setq quote nil))))
|
||||
|
|
|
@ -40,11 +40,11 @@
|
|||
(declare-function org-babel-update-block-body "ob-core" (new-body))
|
||||
(declare-function org-back-to-heading "org" (&optional invisible-ok))
|
||||
(declare-function org-before-first-heading-p "org" ())
|
||||
(declare-function org-element--cache-active-p "org-element" ())
|
||||
(declare-function org-element-lineage "org-element" (datum &optional types with-self))
|
||||
(declare-function org-element-property "org-element" (property element))
|
||||
(declare-function org-element-lineage "org-element-ast" (datum &optional types with-self))
|
||||
(declare-function org-element-property "org-element-ast" (property node))
|
||||
(declare-function org-element-begin "org-element" (node))
|
||||
(declare-function org-element-at-point "org-element" (&optional pom cached-only))
|
||||
(declare-function org-element-type "org-element" (element))
|
||||
(declare-function org-element-type-p "org-element-ast" (node types))
|
||||
(declare-function org-heading-components "org" ())
|
||||
(declare-function org-in-commented-heading-p "org" (&optional no-inheritance))
|
||||
(declare-function org-in-archived-heading-p "org" (&optional no-inheritance))
|
||||
|
@ -166,6 +166,23 @@ read-write permissions for the user, read-only for everyone else."
|
|||
:package-version '(Org . "9.6")
|
||||
:type 'integer)
|
||||
|
||||
(defcustom org-babel-tangle-remove-file-before-write 'auto
|
||||
"How to overwrite the existing tangle target.
|
||||
When set to nil, `org-babel-tangle' will replace contents of an existing
|
||||
tangle target (and fail when tangle target is read-only).
|
||||
When set to t, the tangle target (including read-only) will be deleted
|
||||
first and a new file, possibly with different ownership and
|
||||
permissions, will be created.
|
||||
When set to symbol `auto', overwrite read-only tangle targets and
|
||||
replace contents otherwise."
|
||||
:group 'org-babel-tangle
|
||||
:package-version '(Org . "9.7")
|
||||
:type '(choice
|
||||
(const :tag "Replace contents, but keep the same file" nil)
|
||||
(const :tag "Re-create file" t)
|
||||
(const :tag "Re-create when read-only" auto))
|
||||
:safe t)
|
||||
|
||||
(defun org-babel-find-file-noselect-refresh (file)
|
||||
"Find file ensuring that the latest changes on disk are
|
||||
represented in the file."
|
||||
|
@ -205,21 +222,20 @@ source code blocks by languages matching a regular expression.
|
|||
|
||||
Return list of the tangled file names."
|
||||
(interactive "fFile to tangle: \nP")
|
||||
(let* ((visited (find-buffer-visiting file))
|
||||
(buffer (or visited (find-file-noselect file))))
|
||||
(prog1
|
||||
(with-current-buffer buffer
|
||||
(org-with-wide-buffer
|
||||
(mapcar #'expand-file-name
|
||||
(org-babel-tangle nil target-file lang-re))))
|
||||
(unless visited (kill-buffer buffer)))))
|
||||
(org-with-file-buffer file
|
||||
(org-with-wide-buffer
|
||||
(mapcar #'expand-file-name
|
||||
(org-babel-tangle nil target-file lang-re)))))
|
||||
|
||||
(defun org-babel-tangle-publish (_ filename pub-dir)
|
||||
"Tangle FILENAME and place the results in PUB-DIR."
|
||||
(unless (file-exists-p pub-dir)
|
||||
(make-directory pub-dir t))
|
||||
(setq pub-dir (file-name-as-directory pub-dir))
|
||||
(mapc (lambda (el) (copy-file el pub-dir t)) (org-babel-tangle-file filename)))
|
||||
;; Rename files to avoid copying to same file when publishing to ./
|
||||
;; `copy-file' would throw an error when copying file to self.
|
||||
(mapc (lambda (el) (rename-file el pub-dir t))
|
||||
(org-babel-tangle-file filename)))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-babel-tangle (&optional arg target-file lang-re)
|
||||
|
@ -253,7 +269,8 @@ matching a regular expression."
|
|||
(when (equal arg '(16))
|
||||
(or (cdr (assq :tangle (nth 2 (org-babel-get-src-block-info 'no-eval))))
|
||||
(user-error "Point is not in a source code block"))))
|
||||
path-collector)
|
||||
path-collector
|
||||
(source-file buffer-file-name))
|
||||
(mapc ;; map over file-names
|
||||
(lambda (by-fn)
|
||||
(let ((file-name (car by-fn)))
|
||||
|
@ -310,10 +327,28 @@ matching a regular expression."
|
|||
(compare-buffer-substrings
|
||||
nil nil nil
|
||||
tangle-buf nil nil)))))))
|
||||
;; erase previous file
|
||||
(when (file-exists-p file-name)
|
||||
(when (equal (if (file-name-absolute-p file-name)
|
||||
file-name
|
||||
(expand-file-name file-name))
|
||||
(if (file-name-absolute-p source-file)
|
||||
source-file
|
||||
(expand-file-name source-file)))
|
||||
(error "Not allowed to tangle into the same file as self"))
|
||||
;; We do not erase, but overwrite previous file
|
||||
;; to preserve any existing symlinks.
|
||||
;; This behavior is modified using
|
||||
;; `org-babel-tangle-remove-file-before-write' to
|
||||
;; tangle to read-only files.
|
||||
(when (and
|
||||
(file-exists-p file-name)
|
||||
(pcase org-babel-tangle-remove-file-before-write
|
||||
(`auto (not (file-writable-p file-name)))
|
||||
(`t t)
|
||||
(`nil nil)
|
||||
(_ (error "Invalid value of `org-babel-tangle-remove-file-before-write': %S"
|
||||
org-babel-tangle-remove-file-before-write))))
|
||||
(delete-file file-name))
|
||||
(write-region nil nil file-name)
|
||||
(write-region nil nil file-name)
|
||||
(mapc (lambda (mode) (set-file-modes file-name mode)) modes))
|
||||
(push file-name path-collector))))))
|
||||
(if (equal arg '(4))
|
||||
|
@ -378,7 +413,7 @@ references."
|
|||
(goto-char (point-min))
|
||||
(while (or (re-search-forward "\\[\\[file:.*\\]\\[.*\\]\\]" nil t)
|
||||
(re-search-forward (org-babel-noweb-wrap) nil t))
|
||||
(delete-region (save-excursion (beginning-of-line 1) (point))
|
||||
(delete-region (save-excursion (forward-line) (point))
|
||||
(save-excursion (end-of-line 1) (forward-char 1) (point)))))
|
||||
|
||||
(defun org-babel-spec-to-string (spec)
|
||||
|
@ -427,17 +462,19 @@ that the appropriate major-mode is set. SPEC has the form:
|
|||
org-babel-tangle-comment-format-end link-data)))))
|
||||
|
||||
(defun org-babel-effective-tangled-filename (buffer-fn src-lang src-tfile)
|
||||
"Return effective tangled filename of a source-code block.
|
||||
BUFFER-FN is the name of the buffer, SRC-LANG the language of the
|
||||
block and SRC-TFILE is the value of the :tangle header argument,
|
||||
as computed by `org-babel-tangle-single-block'."
|
||||
(let ((base-name (cond
|
||||
((string= "yes" src-tfile)
|
||||
;; Use the buffer name
|
||||
(file-name-sans-extension buffer-fn))
|
||||
((string= "no" src-tfile) nil)
|
||||
((> (length src-tfile) 0) src-tfile)))
|
||||
(ext (or (cdr (assoc src-lang org-babel-tangle-lang-exts)) src-lang)))
|
||||
"Return effective tangled absolute filename of a source-code block.
|
||||
BUFFER-FN is the absolute file name of the buffer, SRC-LANG the
|
||||
language of the block and SRC-TFILE is the value of the :tangle
|
||||
header argument, as computed by `org-babel-tangle-single-block'."
|
||||
(let* ((fnd (file-name-directory buffer-fn))
|
||||
(base-name (cond
|
||||
((string= "yes" src-tfile)
|
||||
;; Use the buffer name
|
||||
(file-name-sans-extension buffer-fn))
|
||||
((string= "no" src-tfile) nil)
|
||||
((> (length src-tfile) 0)
|
||||
(expand-file-name src-tfile fnd))))
|
||||
(ext (or (cdr (assoc src-lang org-babel-tangle-lang-exts)) src-lang)))
|
||||
(when base-name
|
||||
;; decide if we want to add ext to base-name
|
||||
(if (and ext (string= "yes" src-tfile))
|
||||
|
@ -454,13 +491,16 @@ source code blocks by languages matching a regular expression.
|
|||
|
||||
Optional argument TANGLE-FILE can be used to limit the collected
|
||||
code blocks by target file."
|
||||
(let ((counter 0) last-heading-pos blocks)
|
||||
(let ((counter 0)
|
||||
(buffer-fn (buffer-file-name (buffer-base-buffer)))
|
||||
last-heading-pos blocks)
|
||||
(org-babel-map-src-blocks (buffer-file-name)
|
||||
(let ((current-heading-pos
|
||||
(if (org-element--cache-active-p)
|
||||
(or (org-element-property :begin (org-element-lineage (org-element-at-point) '(headline) t)) 1)
|
||||
(org-with-wide-buffer
|
||||
(org-with-limited-levels (outline-previous-heading))))))
|
||||
(or (org-element-begin
|
||||
(org-element-lineage
|
||||
(org-element-at-point)
|
||||
'headline t))
|
||||
1)))
|
||||
(if (eq last-heading-pos current-heading-pos) (cl-incf counter)
|
||||
(setq counter 1)
|
||||
(setq last-heading-pos current-heading-pos)))
|
||||
|
@ -470,6 +510,7 @@ code blocks by target file."
|
|||
(src-lang (nth 0 info))
|
||||
(src-tfile (cdr (assq :tangle (nth 2 info)))))
|
||||
(unless (or (string= src-tfile "no")
|
||||
(not src-lang) ;; src block without lang
|
||||
(and tangle-file (not (equal tangle-file src-tfile)))
|
||||
(and lang-re (not (string-match-p lang-re src-lang))))
|
||||
;; Add the spec for this block to blocks under its tangled
|
||||
|
@ -477,7 +518,7 @@ code blocks by target file."
|
|||
(let* ((block (org-babel-tangle-single-block counter))
|
||||
(src-tfile (cdr (assq :tangle (nth 4 block))))
|
||||
(file-name (org-babel-effective-tangled-filename
|
||||
(nth 1 block) src-lang src-tfile))
|
||||
buffer-fn src-lang src-tfile))
|
||||
(by-fn (assoc file-name blocks)))
|
||||
(if by-fn (setcdr by-fn (cons (cons src-lang block) (cdr by-fn)))
|
||||
(push (cons file-name (list (cons src-lang block))) blocks)))))))
|
||||
|
@ -491,12 +532,7 @@ code blocks by target file."
|
|||
The PARAMS are the 3rd element of the info for the same src block."
|
||||
(unless (string= "no" (cdr (assq :comments params)))
|
||||
(save-match-data
|
||||
(let* (;; The created link is transient. Using ID is not necessary,
|
||||
;; but could have side-effects if used. An ID property may
|
||||
;; be added to existing entries thus creating unexpected file
|
||||
;; modifications.
|
||||
(org-id-link-to-org-use-id nil)
|
||||
(l (org-no-properties
|
||||
(let* ((l (org-no-properties
|
||||
(cl-letf (((symbol-function 'org-store-link-functions)
|
||||
(lambda () nil)))
|
||||
(org-store-link nil))))
|
||||
|
@ -589,13 +625,12 @@ non-nil, return the full association list to be used by
|
|||
link
|
||||
source-name
|
||||
params
|
||||
(if org-src-preserve-indentation
|
||||
(org-trim body t)
|
||||
(if (org-src-preserve-indentation-p) (org-trim body t)
|
||||
(org-trim (org-remove-indentation body)))
|
||||
comment)))
|
||||
(if only-this-block
|
||||
(let* ((file-name (org-babel-effective-tangled-filename
|
||||
(nth 1 result) src-lang src-tfile)))
|
||||
file src-lang src-tfile)))
|
||||
(list (cons file-name (list (cons src-lang result)))))
|
||||
result)))
|
||||
|
||||
|
@ -616,9 +651,12 @@ by `org-babel-get-src-block-info'."
|
|||
|
||||
;; de-tangling functions
|
||||
(defun org-babel-detangle (&optional source-code-file)
|
||||
"Propagate changes in source file back original to Org file.
|
||||
"Propagate changes from current source buffer back to the original Org file.
|
||||
This requires that code blocks were tangled with link comments
|
||||
which enable the original code blocks to be found."
|
||||
which enable the original code blocks to be found.
|
||||
|
||||
Optional argument SOURCE-CODE-FILE is the file path to be used instead
|
||||
of the current buffer."
|
||||
(interactive)
|
||||
(save-excursion
|
||||
(when source-code-file (find-file source-code-file))
|
||||
|
@ -673,8 +711,7 @@ which enable the original code blocks to be found."
|
|||
(org-back-to-heading t))
|
||||
;; Do not skip the first block if it begins at point min.
|
||||
(cond ((or (org-at-heading-p)
|
||||
(not (eq (org-element-type (org-element-at-point))
|
||||
'src-block)))
|
||||
(not (org-element-type-p (org-element-at-point) 'src-block)))
|
||||
(org-babel-next-src-block n))
|
||||
((= n 1))
|
||||
(t (org-babel-next-src-block (1- n)))))
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
;;; oc-basic.el --- basic back-end for citations -*- lexical-binding: t; -*-
|
||||
;;; oc-basic.el --- basic backend for citations -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2021-2024 Free Software Foundation, Inc.
|
||||
|
||||
|
@ -78,9 +78,19 @@
|
|||
(declare-function org-open-at-point "org" (&optional arg))
|
||||
(declare-function org-open-file "org" (path &optional in-emacs line search))
|
||||
|
||||
(declare-function org-element-create "org-element-ast" (type &optional props &rest children))
|
||||
(declare-function org-element-set "org-element-ast" (old new &optional keep-props))
|
||||
|
||||
(declare-function org-element-interpret-data "org-element" (data))
|
||||
(declare-function org-element-property "org-element" (property element))
|
||||
(declare-function org-element-type "org-element" (element))
|
||||
(declare-function org-element-parse-secondary-string "org-element" (string restriction &optional parent))
|
||||
(declare-function org-element-map "org-element"
|
||||
( data types fun
|
||||
&optional
|
||||
info first-match no-recursion
|
||||
with-affiliated no-undefer))
|
||||
(declare-function org-element-property "org-element-ast" (property node))
|
||||
(declare-function org-element-type-p "org-element-ast" (node types))
|
||||
(declare-function org-element-contents "org-element-ast" (node))
|
||||
|
||||
(declare-function org-export-data "org-export" (data info))
|
||||
(declare-function org-export-derived-backend-p "org-export" (backend &rest backends))
|
||||
|
@ -272,6 +282,9 @@ Optional argument INFO is the export state, as a property list."
|
|||
(plist-get info :cite-basic/bibliography)
|
||||
(let ((results nil))
|
||||
(dolist (file (org-cite-list-bibliography-files))
|
||||
;; Follow symlinks, to look into modification time of the
|
||||
;; actual file, not its symlink.
|
||||
(setq file (file-truename file))
|
||||
(when (file-readable-p file)
|
||||
(with-temp-buffer
|
||||
(when (or (org-file-has-changed-p file)
|
||||
|
@ -330,9 +343,11 @@ FIELD is a symbol. ENTRY-OR-KEY is either an association list, as returned by
|
|||
|
||||
Optional argument INFO is the export state, as a property list.
|
||||
|
||||
Return value may be nil or a string. If current export back-end is derived
|
||||
from `latex', return a raw string instead, unless optional argument RAW is
|
||||
non-nil."
|
||||
Return value may be nil or a string. If current export backend is derived
|
||||
from `latex', return a raw string object instead, unless optional
|
||||
argument RAW is non-nil.
|
||||
|
||||
Throw an error if the field value is non-string and non-nil."
|
||||
(let ((value
|
||||
(cdr
|
||||
(assq field
|
||||
|
@ -343,6 +358,8 @@ non-nil."
|
|||
entry-or-key)
|
||||
(_
|
||||
(error "Wrong value for ENTRY-OR-KEY: %S" entry-or-key)))))))
|
||||
(when (and value (not (stringp value)))
|
||||
(error "Non-string bibliography field value: %S" value))
|
||||
(if (and value
|
||||
(not raw)
|
||||
(org-export-derived-backend-p (plist-get info :back-end) 'latex))
|
||||
|
@ -351,17 +368,27 @@ non-nil."
|
|||
|
||||
(defun org-cite-basic--shorten-names (names)
|
||||
"Return a list of family names from a list of full NAMES.
|
||||
NAMES can be a string or raw string object.
|
||||
|
||||
To better accomomodate corporate names, this will only shorten
|
||||
personal names of the form \"family, given\"."
|
||||
(when (stringp names)
|
||||
(mapconcat
|
||||
(lambda (name)
|
||||
(if (eq 1 (length name))
|
||||
(cdr (split-string name))
|
||||
(car (split-string name ", "))))
|
||||
(split-string names " and ")
|
||||
", ")))
|
||||
(let (names-string raw-p)
|
||||
(cond
|
||||
((stringp names) (setq names-string names))
|
||||
((org-element-type-p names 'raw)
|
||||
(setq names-string (mapconcat #'identity (org-element-contents names) "")
|
||||
raw-p t)))
|
||||
(when names-string
|
||||
(setq names-string
|
||||
(mapconcat
|
||||
(lambda (name)
|
||||
(if (eq 1 (length name))
|
||||
(cdr (split-string name))
|
||||
(car (split-string name ", "))))
|
||||
(split-string names-string " and ")
|
||||
", "))
|
||||
(if raw-p (org-export-raw-string names-string)
|
||||
names-string))))
|
||||
|
||||
(defun org-cite-basic--number-to-suffix (n)
|
||||
"Compute suffix associated to number N.
|
||||
|
@ -417,7 +444,7 @@ necessary, unless optional argument NO-SUFFIX is non-nil."
|
|||
(year
|
||||
(or (org-cite-basic--get-field 'year entry-or-key info 'raw)
|
||||
(let ((date
|
||||
(org-cite-basic--get-field 'date entry-or-key info t)))
|
||||
(org-cite-basic--get-field 'date entry-or-key info 'raw)))
|
||||
(and (stringp date)
|
||||
(string-match (rx string-start
|
||||
(group (= 4 digit))
|
||||
|
@ -445,6 +472,38 @@ necessary, unless optional argument NO-SUFFIX is non-nil."
|
|||
new))))
|
||||
(if no-suffix year (concat year suffix)))))))
|
||||
|
||||
(defun org-cite-basic--print-bibtex-string (element &optional info)
|
||||
"Print Bibtex formatted string ELEMENT, according to Bibtex syntax.
|
||||
Remove all the {...} that are not a part of LaTeX macros and parse the
|
||||
LaTeX fragments. Do nothing when current backend is derived from
|
||||
LaTeX, according to INFO.
|
||||
|
||||
Return updated ELEMENT."
|
||||
(if (org-export-derived-backend-p (plist-get info :back-end) 'latex)
|
||||
;; Derived from LaTeX, no need to use manual ad-hoc LaTeX
|
||||
;; parser.
|
||||
element
|
||||
;; Convert ELEMENT to anonymous when ELEMENT is string.
|
||||
;; Otherwise, we cannot modify ELEMENT by side effect.
|
||||
(when (org-element-type-p element 'plain-text)
|
||||
(setq element (org-element-create 'anonymous nil element)))
|
||||
;; Approximately parse LaTeX fragments, assuming Org mode syntax
|
||||
;; (it is close to original LaTeX, and we do not want to
|
||||
;; re-implement complete LaTeX parser here))
|
||||
(org-element-map element t
|
||||
(lambda (str)
|
||||
(when (stringp str)
|
||||
(org-element-set
|
||||
str
|
||||
(org-element-parse-secondary-string
|
||||
str '(latex-fragment entity))))))
|
||||
;; Strip the remaining { and }.
|
||||
(org-element-map element t
|
||||
(lambda (str)
|
||||
(when (stringp str)
|
||||
(org-element-set str (replace-regexp-in-string "[{}]" "" str)))))
|
||||
element))
|
||||
|
||||
(defun org-cite-basic--print-entry (entry style &optional info)
|
||||
"Format ENTRY according to STYLE string.
|
||||
ENTRY is an alist, as returned by `org-cite-basic--get-entry'.
|
||||
|
@ -456,27 +515,29 @@ Optional argument INFO is the export state, as a property list."
|
|||
(org-cite-basic--get-field 'journal entry info)
|
||||
(org-cite-basic--get-field 'institution entry info)
|
||||
(org-cite-basic--get-field 'school entry info))))
|
||||
(pcase style
|
||||
("plain"
|
||||
(let ((year (org-cite-basic--get-year entry info 'no-suffix)))
|
||||
(org-cite-concat
|
||||
(org-cite-basic--shorten-names author) ". "
|
||||
title (and from (list ", " from)) ", " year ".")))
|
||||
("numeric"
|
||||
(let ((n (org-cite-basic--key-number (cdr (assq 'id entry)) info))
|
||||
(year (org-cite-basic--get-year entry info 'no-suffix)))
|
||||
(org-cite-concat
|
||||
(format "[%d] " n) author ", "
|
||||
(org-cite-emphasize 'italic title)
|
||||
(and from (list ", " from)) ", "
|
||||
year ".")))
|
||||
;; Default to author-year. Use year disambiguation there.
|
||||
(_
|
||||
(let ((year (org-cite-basic--get-year entry info)))
|
||||
(org-cite-concat
|
||||
author " (" year "). "
|
||||
(org-cite-emphasize 'italic title)
|
||||
(and from (list ", " from)) "."))))))
|
||||
(org-cite-basic--print-bibtex-string
|
||||
(pcase style
|
||||
("plain"
|
||||
(let ((year (org-cite-basic--get-year entry info 'no-suffix)))
|
||||
(org-cite-concat
|
||||
(org-cite-basic--shorten-names author) ". "
|
||||
title (and from (list ", " from)) ", " year ".")))
|
||||
("numeric"
|
||||
(let ((n (org-cite-basic--key-number (cdr (assq 'id entry)) info))
|
||||
(year (org-cite-basic--get-year entry info 'no-suffix)))
|
||||
(org-cite-concat
|
||||
(format "[%d] " n) author ", "
|
||||
(org-cite-emphasize 'italic title)
|
||||
(and from (list ", " from)) ", "
|
||||
year ".")))
|
||||
;; Default to author-year. Use year disambiguation there.
|
||||
(_
|
||||
(let ((year (org-cite-basic--get-year entry info)))
|
||||
(org-cite-concat
|
||||
author " (" year "). "
|
||||
(org-cite-emphasize 'italic title)
|
||||
(and from (list ", " from)) "."))))
|
||||
info)))
|
||||
|
||||
|
||||
;;; "Activate" capability
|
||||
|
@ -580,8 +641,8 @@ INFO is the export state, as a property list."
|
|||
(suffix (org-element-property :suffix ref)))
|
||||
(funcall format-ref
|
||||
prefix
|
||||
(org-cite-basic--get-author k info)
|
||||
(org-cite-basic--get-year k info)
|
||||
(or (org-cite-basic--get-author k info) "??")
|
||||
(or (org-cite-basic--get-year k info) "????")
|
||||
suffix)))
|
||||
(org-cite-get-references citation)
|
||||
org-cite-basic-author-year-separator)
|
||||
|
@ -619,7 +680,7 @@ INFO is the export state as a property list."
|
|||
INFO is the export state, as a property list."
|
||||
(and field
|
||||
(lambda (a b)
|
||||
(string-collate-lessp
|
||||
(org-string<
|
||||
(org-cite-basic--get-field field a info 'raw)
|
||||
(org-cite-basic--get-field field b info 'raw)
|
||||
nil t))))
|
||||
|
@ -649,20 +710,30 @@ export communication channel, as a property list."
|
|||
;; "author" style.
|
||||
(`(,(or "author" "a") . ,variant)
|
||||
(let ((caps (member variant '("caps" "c"))))
|
||||
(org-export-data
|
||||
(mapconcat
|
||||
(lambda (key)
|
||||
(let ((author (org-cite-basic--get-author key info)))
|
||||
(if caps (capitalize author) author)))
|
||||
(org-cite-get-references citation t)
|
||||
org-cite-basic-author-year-separator)
|
||||
(org-cite-basic--format-author-year
|
||||
citation
|
||||
(lambda (p c s) (org-cite-concat p c s))
|
||||
(lambda (prefix author _ suffix)
|
||||
(org-cite-concat
|
||||
prefix
|
||||
(if caps (org-cite-capitalize author) author)
|
||||
suffix))
|
||||
info)))
|
||||
;; "noauthor" style.
|
||||
(`(,(or "noauthor" "na") . ,variant)
|
||||
(format (if (funcall has-variant-p variant 'bare) "%s" "(%s)")
|
||||
(mapconcat (lambda (key) (org-cite-basic--get-year key info))
|
||||
(org-cite-get-references citation t)
|
||||
org-cite-basic-author-year-separator)))
|
||||
(let ((bare? (funcall has-variant-p variant 'bare)))
|
||||
(org-cite-basic--format-author-year
|
||||
citation
|
||||
(lambda (prefix contents suffix)
|
||||
(org-cite-concat
|
||||
(unless bare? "(")
|
||||
prefix
|
||||
contents
|
||||
suffix
|
||||
(unless bare? ")")))
|
||||
(lambda (prefix _ year suffix)
|
||||
(org-cite-concat prefix year suffix))
|
||||
info)))
|
||||
;; "nocite" style.
|
||||
(`(,(or "nocite" "n") . ,_) nil)
|
||||
;; "text" and "note" styles.
|
||||
|
@ -678,10 +749,11 @@ export communication channel, as a property list."
|
|||
(lambda (p c s) (org-cite-concat p c s))
|
||||
(lambda (p a y s)
|
||||
(org-cite-concat p
|
||||
(if caps (capitalize a) a)
|
||||
(if caps (org-cite-capitalize a) a)
|
||||
(if bare " " " (")
|
||||
y s
|
||||
(and (not bare) ")")))
|
||||
y
|
||||
(and (not bare) ")")
|
||||
s))
|
||||
info)))
|
||||
;; "numeric" style.
|
||||
;;
|
||||
|
@ -702,7 +774,7 @@ export communication channel, as a property list."
|
|||
(lambda (p c s)
|
||||
(org-cite-concat (and (not bare) "(") p c s (and (not bare) ")")))
|
||||
(lambda (p a y s)
|
||||
(org-cite-concat p (if caps (capitalize a) a) ", " y s))
|
||||
(org-cite-concat p (if caps (org-cite-capitalize a) a) ", " y s))
|
||||
info)))
|
||||
;; This should not happen.
|
||||
(_ (error "Invalid style: %S" style)))))
|
||||
|
@ -710,7 +782,7 @@ export communication channel, as a property list."
|
|||
(defun org-cite-basic-export-bibliography (keys _files style _props backend info)
|
||||
"Generate bibliography.
|
||||
KEYS is the list of cited keys, as strings. STYLE is the expected bibliography
|
||||
style, as a string. BACKEND is the export back-end, as a symbol. INFO is the
|
||||
style, as a string. BACKEND is the export backend, as a symbol. INFO is the
|
||||
export state, as a property list."
|
||||
(mapconcat
|
||||
(lambda (entry)
|
||||
|
@ -734,7 +806,7 @@ When DATUM is a citation reference, open bibliography entry referencing
|
|||
the citation key. Otherwise, select which key to follow among all keys
|
||||
present in the citation."
|
||||
(let* ((key
|
||||
(if (eq 'citation-reference (org-element-type datum))
|
||||
(if (org-element-type-p datum 'citation-reference)
|
||||
(org-element-property :key datum)
|
||||
(pcase (org-cite-get-references datum t)
|
||||
(`(,key) key)
|
||||
|
@ -806,7 +878,7 @@ Return nil if there are no bibliography files or no entries."
|
|||
(let ((date (org-cite-basic--get-year entry nil 'no-suffix)))
|
||||
(format "%4s" (or date "")))
|
||||
org-cite-basic-column-separator
|
||||
(org-cite-basic--get-field 'title entry nil t))))
|
||||
(org-cite-basic--get-field 'title entry nil 'raw))))
|
||||
(puthash completion key org-cite-basic--completion-cache)))
|
||||
(unless (map-empty-p org-cite-basic--completion-cache) ;no key
|
||||
(puthash entries t org-cite-basic--completion-cache)
|
||||
|
|
|
@ -70,7 +70,8 @@
|
|||
(require 'org-macs)
|
||||
(require 'oc)
|
||||
|
||||
(declare-function org-element-property "org-element" (property element))
|
||||
(declare-function org-element-property "org-element-ast" (property node))
|
||||
(declare-function org-element-parent "org-element-ast" (node))
|
||||
(declare-function org-export-data "org-export" (data info))
|
||||
|
||||
|
||||
|
@ -189,20 +190,23 @@ INITIAL is an initial style of comma-separated options, as a string or nil.
|
|||
STYLE is the style definition as a string or nil.
|
||||
|
||||
Return a string."
|
||||
(let ((options-no-style
|
||||
(and initial
|
||||
(let ((re (rx string-start (or "bibstyle" "citestyle" "style"))))
|
||||
(seq-filter
|
||||
(lambda (option) (not (string-match re option)))
|
||||
(split-string (org-unbracket-string "[" "]" initial)
|
||||
"," t " \t")))))
|
||||
(style-options
|
||||
(cond
|
||||
((null style) nil)
|
||||
((not (string-match "/" style)) (list (concat "style=" style)))
|
||||
(t
|
||||
(list (concat "bibstyle=" (substring style nil (match-beginning 0)))
|
||||
(concat "citestyle=" (substring style (match-end 0))))))))
|
||||
(let* ((options-no-style
|
||||
(and initial
|
||||
(let ((re (rx string-start (or "bibstyle" "citestyle" "style"))))
|
||||
(seq-filter
|
||||
(lambda (option) (not (string-match re option)))
|
||||
(split-string (org-unbracket-string "[" "]" initial)
|
||||
"," t " \t")))))
|
||||
;; Check whether the string is in key=val,...
|
||||
(biblatex-options-p (and (stringp style) (string-match-p "\\`[^,=]+=[^,]+\\(,[^=]+=[^,]+\\)\\'" style)))
|
||||
(style-options
|
||||
(cond
|
||||
((null style) nil)
|
||||
;; Assume it is a valid options string for biblatex if it is in key=val,... format
|
||||
((not (string-match "/" style)) (list (if biblatex-options-p style (concat "style=" style))))
|
||||
(t
|
||||
(list (concat "bibstyle=" (substring style nil (match-beginning 0)))
|
||||
(concat "citestyle=" (substring style (match-end 0))))))))
|
||||
(if (or options-no-style style-options)
|
||||
(format "[%s]"
|
||||
(mapconcat #'identity
|
||||
|
@ -231,7 +235,7 @@ When NO-OPT argument is non-nil, only provide mandatory arguments."
|
|||
(let* ((origin (pcase references
|
||||
(`(,reference) reference)
|
||||
(`(,reference . ,_)
|
||||
(org-element-property :parent reference))))
|
||||
(org-element-parent reference))))
|
||||
(suffix (org-element-property :suffix origin))
|
||||
(prefix (org-element-property :prefix origin)))
|
||||
(concat (and prefix
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
|
||||
(require 'oc)
|
||||
|
||||
(declare-function org-element-property "org-element" (property element))
|
||||
(declare-function org-element-property "org-element-ast" (property node))
|
||||
|
||||
(declare-function org-export-data "org-export" (data info))
|
||||
|
||||
|
|
|
@ -134,11 +134,12 @@
|
|||
(declare-function citeproc-render-bib "ext:citeproc")
|
||||
(declare-function citeproc-hash-itemgetter-from-any "ext:citeproc")
|
||||
(declare-function citeproc-add-subbib-filters "ext:citeproc")
|
||||
(declare-function citeproc-style-cite-superscript-p "ext:citeproc")
|
||||
|
||||
(declare-function org-element-interpret-data "org-element" (data))
|
||||
(declare-function org-element-map "org-element" (data types fun &optional info first-match no-recursion with-affiliated))
|
||||
(declare-function org-element-property "org-element" (property element))
|
||||
(declare-function org-element-put-property "org-element" (element property value))
|
||||
(declare-function org-element-property "org-element-ast" (property node))
|
||||
(declare-function org-element-put-property "org-element-ast" (node property value))
|
||||
|
||||
(declare-function org-export-data "org-export" (data info))
|
||||
(declare-function org-export-derived-backend-p "org-export" (backend &rest backends))
|
||||
|
@ -184,8 +185,8 @@ looks for style files in this directory, too."
|
|||
:safe #'booleanp)
|
||||
|
||||
(defcustom org-cite-csl-no-citelinks-backends '(ascii)
|
||||
"List of export back-ends for which cite linking is disabled.
|
||||
Cite linking for export back-ends derived from any of the back-ends listed here,
|
||||
"List of export backends for which cite linking is disabled.
|
||||
Cite linking for export backends derived from any of the backends listed here,
|
||||
is also disabled."
|
||||
:group 'org-cite
|
||||
:package-version '(Org . "9.5")
|
||||
|
@ -214,6 +215,112 @@ Used only when `second-field-align' is activated by the used CSL style."
|
|||
:type 'string
|
||||
:safe #'stringp)
|
||||
|
||||
(defcustom org-cite-csl-latex-label-separator "0.6em"
|
||||
"Distance between citation label and bibliography item for LaTeX output.
|
||||
The value is a string representing the distance in valid LaTeX units.
|
||||
Used only when `second-field-align' is activated by the used CSL
|
||||
style.
|
||||
|
||||
The indentation length in these cases is computed as the sum of
|
||||
`org-cite-csl-latex-label-separator' and the maximal label width, for
|
||||
example,
|
||||
|
||||
indentation length
|
||||
<------------------------->
|
||||
max. label width separator
|
||||
<---------------><-------->
|
||||
[Doe22] John Doe. A title...
|
||||
[DoeSmithJones19] John Doe, Jane Smith and...
|
||||
[SmithDoe02] Jane Smith and John Doe...
|
||||
|
||||
The maximal label width, in turn, is calculated as the product of
|
||||
`org-cite-csl-latex-label-width-per-char' and the maximal label
|
||||
length measured in characters."
|
||||
:group 'org-cite
|
||||
:package-version '(Org . "9.7")
|
||||
:type 'string
|
||||
:safe #'stringp)
|
||||
|
||||
(defcustom org-cite-csl-latex-label-width-per-char "0.45em"
|
||||
"Character width in LaTeX units for calculating entry label widths.
|
||||
Used only when `second-field-align' is activated by the used CSL
|
||||
style.
|
||||
|
||||
See the documentation of `org-cite-csl-latex-label-separator' for
|
||||
details."
|
||||
:group 'org-cite
|
||||
:package-version '(Org . "9.7")
|
||||
:type 'string
|
||||
:safe #'stringp)
|
||||
|
||||
;; The following was inspired by and in many details follows how
|
||||
;; Pandoc's (<https://github.com/jgm/pandoc>) default LaTeX template
|
||||
;; handles CSL output. Many thanks to the author, John MacFarlane!
|
||||
(defcustom org-cite-csl-latex-preamble
|
||||
"\\usepackage{calc}
|
||||
\\newlength{\\cslhangindent}
|
||||
\\setlength{\\cslhangindent}{[CSL-HANGINDENT]}
|
||||
\\newlength{\\csllabelsep}
|
||||
\\setlength{\\csllabelsep}{[CSL-LABELSEP]}
|
||||
\\newlength{\\csllabelwidth}
|
||||
\\setlength{\\csllabelwidth}{[CSL-LABELWIDTH-PER-CHAR] * [CSL-MAXLABEL-CHARS]}
|
||||
\\newenvironment{cslbibliography}[2] % 1st arg. is hanging-indent, 2nd entry spacing.
|
||||
{% By default, paragraphs are not indented.
|
||||
\\setlength{\\parindent}{0pt}
|
||||
% Hanging indent is turned on when first argument is 1.
|
||||
\\ifodd #1
|
||||
\\let\\oldpar\\par
|
||||
\\def\\par{\\hangindent=\\cslhangindent\\oldpar}
|
||||
\\fi
|
||||
% Set entry spacing based on the second argument.
|
||||
\\setlength{\\parskip}{\\parskip + #2\\baselineskip}
|
||||
}%
|
||||
{}
|
||||
\\newcommand{\\cslblock}[1]{#1\\hfill\\break}
|
||||
\\newcommand{\\cslleftmargin}[1]{\\parbox[t]{\\csllabelsep + \\csllabelwidth}{#1}}
|
||||
\\newcommand{\\cslrightinline}[1]
|
||||
{\\parbox[t]{\\linewidth - \\csllabelsep - \\csllabelwidth}{#1}\\break}
|
||||
\\newcommand{\\cslindent}[1]{\\hspace{\\cslhangindent}#1}
|
||||
\\newcommand{\\cslbibitem}[2]
|
||||
{\\leavevmode\\vadjust pre{\\hypertarget{citeproc_bib_item_#1}{}}#2}
|
||||
\\makeatletter
|
||||
\\newcommand{\\cslcitation}[2]
|
||||
{\\protect\\hyper@linkstart{cite}{citeproc_bib_item_#1}#2\\hyper@linkend}
|
||||
\\makeatother"
|
||||
"LaTeX preamble content inserted by the `csl' citation processor.
|
||||
|
||||
This preamble can be anything as long as it provides definitions
|
||||
for the environment and commands that Citeproc's `org-latex'
|
||||
formatter uses for formatting citations and bibliographies. In
|
||||
particular, it has to define
|
||||
- the commands \\cslblock{<text>}, \\cslleftmargin{<text>},
|
||||
\\cslrightinline{<text>} and \\cslindent{<text>} for formatting
|
||||
text that have, respectively, the CSL display attributes
|
||||
`block', `left-margin', `right-inline' and `indent';
|
||||
- the commands \\cslcitation{<item_no>}{<item_text>} and
|
||||
\\cslbibitem{<item_no>}{<item_text>}, which are used to
|
||||
format individual citations and bibliography items, including
|
||||
hyperlinking citations to the corresponding bibliography entry
|
||||
using their numerical id, which is passed as the first,
|
||||
<item_no> argument;
|
||||
- and the environment \\cslbibliography{<hanging-indent>}{<entry-spacing>},
|
||||
in which bibliographies are wrapped; the value of the
|
||||
<hanging-indent> argument is 1 if hanging indent should be
|
||||
applied and 0 if not, while the <entry-spacing> argument is an
|
||||
integer specifying the number of extra line-heights
|
||||
required between bibliography entries in addition to normal
|
||||
line spacing.
|
||||
|
||||
When present, the placeholders [CSL-HANGINDENT], [CSL-LABELSEP],
|
||||
[CSL-LABELWIDTH-PER-CHAR] and [CSL-MAXLABEL-CHARS] are replaced,
|
||||
respectively, by the contents of the customizable variables
|
||||
`org-cite-csl-latex-hanging-indent', `org-cite-csl-latex-label-separator',
|
||||
`org-cite-csl-latex-label-width-per-char', and the maximal label length
|
||||
in the bibliography measured in characters."
|
||||
:group 'org-cite
|
||||
:type 'string
|
||||
:package-version '(Org . "9.7"))
|
||||
|
||||
|
||||
;;; Internal variables
|
||||
(defconst org-cite-csl--etc-dir
|
||||
|
@ -277,13 +384,17 @@ If nil then the Chicago author-date style is used as a fallback.")
|
|||
("paragraph" . "paragraph")
|
||||
("para." . "paragraph")
|
||||
("paras." . "paragraph")
|
||||
("\\P" . "paragraph")
|
||||
("¶" . "paragraph")
|
||||
("\\P\\P" . "paragraph")
|
||||
("¶¶" . "paragraph")
|
||||
("part" . "part")
|
||||
("pt." . "part")
|
||||
("pts." . "part")
|
||||
("§" . "section")
|
||||
("\\S" . "section")
|
||||
("§§" . "section")
|
||||
("\\S\\S" . "section")
|
||||
("section" . "section")
|
||||
("sec." . "section")
|
||||
("secs." . "section")
|
||||
|
@ -312,10 +423,6 @@ Label is in match group 1.")
|
|||
|
||||
|
||||
;;; Internal functions
|
||||
(defun org-cite-csl--barf-without-citeproc ()
|
||||
"Raise an error if Citeproc library is not loaded."
|
||||
(unless (featurep 'citeproc)
|
||||
(error "Citeproc library is not loaded")))
|
||||
|
||||
(defun org-cite-csl--note-style-p (info)
|
||||
"Non-nil when bibliography style implies wrapping citations in footnotes.
|
||||
|
@ -324,6 +431,13 @@ INFO is the export state, as a property list."
|
|||
(citeproc-proc-style
|
||||
(org-cite-csl--processor info))))
|
||||
|
||||
(defun org-cite-csl--style-cite-superscript-p (info)
|
||||
"Non-nil when bibliography style produces citations in superscript.
|
||||
INFO is the export state, as a property list."
|
||||
(citeproc-style-cite-superscript-p
|
||||
(citeproc-proc-style
|
||||
(org-cite-csl--processor info))))
|
||||
|
||||
(defun org-cite-csl--nocite-p (citation info)
|
||||
"Non-nil when CITATION object's style is nocite.
|
||||
INFO is the export state, as a property list."
|
||||
|
@ -332,8 +446,8 @@ INFO is the export state, as a property list."
|
|||
|
||||
(defun org-cite-csl--create-structure-params (citation info)
|
||||
"Return citeproc structure creation params for CITATION object.
|
||||
STYLE is the citation style, as a string or nil. INFO is the export state, as
|
||||
a property list."
|
||||
STYLE is the citation style, as a string or nil. INFO is the export
|
||||
state, as a property list."
|
||||
(let ((style (org-cite-citation-style citation info)))
|
||||
(pcase style
|
||||
;; "author" style.
|
||||
|
@ -393,7 +507,8 @@ a property list."
|
|||
(_ (error "Invalid style: %S" style)))))
|
||||
|
||||
(defun org-cite-csl--no-citelinks-p (info)
|
||||
"Non-nil when export BACKEND should not create cite-reference links."
|
||||
"Non-nil when export backend should not create cite-reference links.
|
||||
INFO is the info channel plist."
|
||||
(or (not org-cite-csl-link-cites)
|
||||
(and org-cite-csl-no-citelinks-backends
|
||||
(apply #'org-export-derived-backend-p
|
||||
|
@ -413,7 +528,7 @@ corresponding to one of the output formats supported by Citeproc: `html',
|
|||
(let ((backend (plist-get info :back-end)))
|
||||
(cond
|
||||
((org-export-derived-backend-p backend 'html) 'html)
|
||||
((org-export-derived-backend-p backend 'latex) 'latex)
|
||||
((org-export-derived-backend-p backend 'latex) 'org-latex)
|
||||
(t 'org))))
|
||||
|
||||
(defun org-cite-csl--style-file (info)
|
||||
|
@ -569,6 +684,9 @@ INFO is the export state, as a property list."
|
|||
(when (and (not footnote) (org-cite-csl--note-style-p info))
|
||||
(org-cite-adjust-note citation info)
|
||||
(setq footnote (org-cite-wrap-citation citation info)))
|
||||
;; Remove white space before CITATION when it is in superscript.
|
||||
(when (org-cite-csl--style-cite-superscript-p info)
|
||||
(org-cite--set-previous-post-blank citation 0 info))
|
||||
;; Return structure.
|
||||
(apply #'citeproc-citation-create
|
||||
`(:note-index
|
||||
|
@ -670,12 +788,27 @@ value is the bibliography as rendered by Citeproc."
|
|||
(plist-put info :cite-citeproc-rendered-bibliographies result)
|
||||
result)))))
|
||||
|
||||
(defun org-cite-csl--generate-latex-preamble (info)
|
||||
"Generate the CSL-related part of the LaTeX preamble.
|
||||
INFO is the export state, as a property list."
|
||||
(let* ((parameters (cadr (org-cite-csl--rendered-bibliographies info)))
|
||||
(max-offset (cdr (assq 'max-offset parameters)))
|
||||
(result org-cite-csl-latex-preamble))
|
||||
(map-do (lambda (placeholder replacement)
|
||||
(when (string-match placeholder result)
|
||||
(setq result (replace-match replacement t t result))))
|
||||
`("\\[CSL-HANGINDENT\\]" ,org-cite-csl-latex-hanging-indent
|
||||
"\\[CSL-LABELSEP\\]" ,org-cite-csl-latex-label-separator
|
||||
"\\[CSL-LABELWIDTH-PER-CHAR\\]" ,org-cite-csl-latex-label-width-per-char
|
||||
"\\[CSL-MAXLABEL-CHARS\\]" ,(number-to-string max-offset)))
|
||||
result))
|
||||
|
||||
|
||||
;;; Export capability
|
||||
(defun org-cite-csl-render-citation (citation _style _backend info)
|
||||
"Export CITATION object.
|
||||
INFO is the export state, as a property list."
|
||||
(org-cite-csl--barf-without-citeproc)
|
||||
(org-require-package 'citeproc)
|
||||
(let ((output (cdr (assq citation (org-cite-csl--rendered-citations info)))))
|
||||
(if (not (eq 'org (org-cite-csl--output-format info)))
|
||||
output
|
||||
|
@ -686,10 +819,10 @@ INFO is the export state, as a property list."
|
|||
(defun org-cite-csl-render-bibliography (_keys _files _style props _backend info)
|
||||
"Export bibliography.
|
||||
INFO is the export state, as a property list."
|
||||
(org-cite-csl--barf-without-citeproc)
|
||||
(org-require-package 'citeproc)
|
||||
(pcase-let* ((format (org-cite-csl--output-format info))
|
||||
(`(,outputs ,parameters) (org-cite-csl--rendered-bibliographies info))
|
||||
(output (cdr (assoc props outputs))))
|
||||
(`(,outputs ,parameters) (org-cite-csl--rendered-bibliographies info))
|
||||
(output (cdr (assoc props outputs))))
|
||||
(pcase format
|
||||
('html
|
||||
(concat
|
||||
|
@ -714,12 +847,7 @@ INFO is the export state, as a property list."
|
|||
org-cite-csl-html-hanging-indent
|
||||
org-cite-csl-html-hanging-indent))
|
||||
output))
|
||||
('latex
|
||||
(if (cdr (assq 'hanging-indent parameters))
|
||||
(format "\\begin{hangparas}{%s}{1}\n%s\n\\end{hangparas}"
|
||||
org-cite-csl-latex-hanging-indent
|
||||
output)
|
||||
output))
|
||||
('org-latex output)
|
||||
(_
|
||||
;; Parse Org output to re-export it during the regular export
|
||||
;; process.
|
||||
|
@ -729,19 +857,15 @@ INFO is the export state, as a property list."
|
|||
"Add \"hanging\" package if missing from LaTeX output.
|
||||
OUTPUT is the export document, as a string. INFO is the export state, as a
|
||||
property list."
|
||||
(org-cite-csl--barf-without-citeproc)
|
||||
(if (not (eq 'latex (org-cite-csl--output-format info)))
|
||||
(org-require-package 'citeproc)
|
||||
(if (not (eq 'org-latex (org-cite-csl--output-format info)))
|
||||
output
|
||||
(with-temp-buffer
|
||||
(save-excursion (insert output))
|
||||
(when (search-forward "\\begin{document}" nil t)
|
||||
(goto-char (match-beginning 0))
|
||||
;; Ensure that \citeprocitem is defined for citeproc-el.
|
||||
(insert "\\makeatletter\n\\newcommand{\\citeprocitem}[2]{\\hyper@linkstart{cite}{citeproc_bib_item_#1}#2\\hyper@linkend}\n\\makeatother\n\n")
|
||||
;; Ensure there is a \usepackage{hanging} somewhere or add one.
|
||||
(let ((re (rx "\\usepackage" (opt "[" (*? nonl) "]") "{hanging}")))
|
||||
(unless (re-search-backward re nil t)
|
||||
(insert "\\usepackage[notquote]{hanging}\n"))))
|
||||
(goto-char (match-beginning 0))
|
||||
;; Insert the CSL-specific parts of the LaTeX preamble.
|
||||
(insert (org-cite-csl--generate-latex-preamble info)))
|
||||
(buffer-string))))
|
||||
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
|
||||
(require 'oc)
|
||||
|
||||
(declare-function org-element-property "org-element" (property element))
|
||||
(declare-function org-element-property "org-element-ast" (property node))
|
||||
|
||||
(declare-function org-export-data "org-export" (data info))
|
||||
|
||||
|
@ -77,6 +77,15 @@ If \"natbib\" package is already required in the document, e.g., through
|
|||
(const :tag "redefine \\thebibliography to issue \\section* instead of \\chapter*" sectionbib)
|
||||
(const :tag "keep all the authors' names in a citation on one line" nonamebreak)))
|
||||
|
||||
(defcustom org-cite-natbib-bibliography-style 'unsrtnat
|
||||
"Default bibliography style."
|
||||
:group 'org-cite
|
||||
:package-version '(Org . "9.7")
|
||||
:type
|
||||
'(choice
|
||||
(const unsrtnat)
|
||||
(symbol :tag "Other")))
|
||||
|
||||
|
||||
;;; Internal functions
|
||||
(defun org-cite-natbib--style-to-command (style)
|
||||
|
@ -143,11 +152,13 @@ CITATION is the citation object. INFO is the export state, as a property list."
|
|||
"Print references from bibliography FILES.
|
||||
FILES is a list of absolute file names. STYLE is the bibliography style, as
|
||||
a string or nil."
|
||||
(concat (and style (format "\\bibliographystyle{%s}\n" style))
|
||||
(format "\\bibliography{%s}"
|
||||
(mapconcat #'file-name-sans-extension
|
||||
files
|
||||
","))))
|
||||
(concat
|
||||
(format "\\bibliographystyle{%s}\n"
|
||||
(or style org-cite-natbib-bibliography-style))
|
||||
(format "\\bibliography{%s}"
|
||||
(mapconcat #'file-name-sans-extension
|
||||
files
|
||||
","))))
|
||||
|
||||
(defun org-cite-natbib-export-citation (citation style _ info)
|
||||
"Export CITATION object.
|
||||
|
|
222
lisp/org/oc.el
222
lisp/org/oc.el
|
@ -46,8 +46,8 @@
|
|||
;; The "export" capability is slightly more involved as one need to
|
||||
;; select the processor providing it, but may also provide a default
|
||||
;; style for citations and bibliography. Also, the choice of an
|
||||
;; export processor may depend of the current export back-end. The
|
||||
;; association between export back-ends and triplets of parameters can
|
||||
;; export processor may depend of the current export backend. The
|
||||
;; association between export backends and triplets of parameters can
|
||||
;; be set in `org-cite-export-processors' variable, or in a document,
|
||||
;; through the "cite_export" keyword.
|
||||
|
||||
|
@ -71,25 +71,33 @@
|
|||
(declare-function org-at-heading-p "org" (&optional _))
|
||||
(declare-function org-collect-keywords "org" (keywords &optional unique directory))
|
||||
|
||||
(declare-function org-element-adopt-elements "org-element" (parent &rest children))
|
||||
(declare-function org-element-adopt "org-element-ast" (parent &rest children))
|
||||
(declare-function org-element-citation-parser "org-element" ())
|
||||
(declare-function org-element-citation-reference-parser "org-element" ())
|
||||
(declare-function org-element-class "org-element" (datum &optional parent))
|
||||
(declare-function org-element-contents "org-element" (element))
|
||||
(declare-function org-element-create "org-element" (type &optional props &rest children))
|
||||
(declare-function org-element-extract-element "org-element" (element))
|
||||
(declare-function org-element-insert-before "org-element" (element location))
|
||||
(declare-function org-element-lineage "org-element" (datum &optional types with-self))
|
||||
(declare-function org-element-contents "org-element-ast" (node))
|
||||
(declare-function org-element-create "org-element-ast" (type &optional props &rest children))
|
||||
(declare-function org-element-extract "org-element-ast" (node))
|
||||
(declare-function org-element-insert-before "org-element-ast" (node location))
|
||||
(declare-function org-element-lineage "org-element-ast" (datum &optional types with-self))
|
||||
(declare-function org-element-map "org-element" (data types fun &optional info first-match no-recursion with-affiliated))
|
||||
(declare-function org-element-normalize-string "org-element" (s))
|
||||
(declare-function org-element-parse-buffer "org-element" (&optional granularity visible-only))
|
||||
(declare-function org-element-parse-buffer "org-element" (&optional granularity visible-only keep-deferred))
|
||||
(declare-function org-element-parse-secondary-string "org-element" (string restriction &optional parent))
|
||||
(declare-function org-element-context "org-element" (&optional element))
|
||||
(declare-function org-element-property "org-element" (property element))
|
||||
(declare-function org-element-put-property "org-element" (element property value))
|
||||
(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-post-blank "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-put-property "org-element-ast" (node property value))
|
||||
(declare-function org-element-restriction "org-element" (element))
|
||||
(declare-function org-element-set-element "org-element" (old new))
|
||||
(declare-function org-element-type "org-element" (element))
|
||||
(declare-function org-element-set "org-element-ast" (old new))
|
||||
(declare-function org-element-type "org-element-ast" (node &optional anonymous))
|
||||
(declare-function org-element-type-p "org-element-ast" (node types))
|
||||
|
||||
(declare-function org-export-derived-backend-p "org-export" (backend &rest backends))
|
||||
(declare-function org-export-get-next-element "org-export" (blob info &optional n))
|
||||
|
@ -143,12 +151,12 @@ File names must be absolute."
|
|||
|
||||
When nil, citations and bibliography are not exported.
|
||||
|
||||
When non-nil, the value is an association list between export back-ends and
|
||||
When non-nil, the value is an association list between export backends and
|
||||
citation export processors:
|
||||
|
||||
(BACK-END . PROCESSOR)
|
||||
(BACKEND . PROCESSOR)
|
||||
|
||||
where BACK-END is the name of an export back-end or t, and PROCESSOR is a
|
||||
where BACKEND is the name of an export backend or t, and PROCESSOR is a
|
||||
triplet following the pattern
|
||||
|
||||
(NAME BIBLIOGRAPHY-STYLE CITATION-STYLE)
|
||||
|
@ -160,7 +168,7 @@ exporting a citation), as a string or nil. Both BIBLIOGRAPHY-STYLE and
|
|||
CITATION-STYLE are optional. NAME is mandatory.
|
||||
|
||||
The export process selects the citation processor associated to the current
|
||||
export back-end, or the most specific back-end the current one is derived from,
|
||||
export backend, or the most specific backend the current one is derived from,
|
||||
or, if all are inadequate, to the processor associated to t. For example, with
|
||||
the following value
|
||||
|
||||
|
@ -168,9 +176,9 @@ the following value
|
|||
(latex biblatex)
|
||||
(t csl))
|
||||
|
||||
exporting with `beamer' or any back-end derived from it will use `natbib',
|
||||
whereas exporting with `latex' or any back-end derived from it but different
|
||||
from `beamer' will use `biblatex' processor. Any other back-end, such as
|
||||
exporting with `beamer' or any backend derived from it will use `natbib',
|
||||
whereas exporting with `latex' or any backend derived from it but different
|
||||
from `beamer' will use `biblatex' processor. Any other backend, such as
|
||||
`html', will use `csl' processor.
|
||||
|
||||
CITATION-STYLE is overridden by adding a style to any citation object. A nil
|
||||
|
@ -187,7 +195,7 @@ or
|
|||
#+CITE_EXPORT: basic
|
||||
|
||||
In that case, `basic' processor is used on every export, independently on the
|
||||
back-end."
|
||||
backend."
|
||||
:group 'org-cite
|
||||
:package-version '(Org . "9.5")
|
||||
:type '(choice (const :tag "No export" nil)
|
||||
|
@ -345,7 +353,7 @@ optional keys can be set:
|
|||
arguments: the list of citation keys used in the document, as
|
||||
strings, a list of bibliography files, the style, as a string
|
||||
or nil, the local properties, as a property list, the export
|
||||
back-end, as a symbol, and the communication channel, as a
|
||||
backend, as a symbol, and the communication channel, as a
|
||||
property list.
|
||||
|
||||
It is called at each \"print_bibliography\" keyword in the
|
||||
|
@ -358,7 +366,7 @@ optional keys can be set:
|
|||
|
||||
Function rendering citations. It is called with four
|
||||
arguments: a citation object, the style, as a pair, the
|
||||
export back-end, as a symbol, and the communication channel,
|
||||
export backend, as a symbol, and the communication channel,
|
||||
as a property list.
|
||||
|
||||
It is called on each citation object in the parse tree. It
|
||||
|
@ -373,7 +381,7 @@ optional keys can be set:
|
|||
six arguments: the output, as a string, a list of citation
|
||||
keys used in the document, a list of bibliography files, the
|
||||
expected bibliography style, as a string or nil, the export
|
||||
back-end, as a symbol, and the communication channel, as a
|
||||
backend, as a symbol, and the communication channel, as a
|
||||
property list.
|
||||
|
||||
It must return a string, which will become the final output
|
||||
|
@ -468,11 +476,11 @@ PROCESSOR is the name of a cite processor, as a symbol. CAPABILITY is
|
|||
"Set `:post-blank' property from element or object before DATUM to BLANKS.
|
||||
DATUM is an element or object. BLANKS is an integer. DATUM is modified
|
||||
by side-effect."
|
||||
(if (not (eq 'plain-text (org-element-type datum)))
|
||||
(if (not (org-element-type-p datum 'plain-text))
|
||||
(org-element-put-property datum :post-blank blanks)
|
||||
;; Remove any blank from string before DATUM so it is exported
|
||||
;; with exactly BLANKS white spaces.
|
||||
(org-element-set-element
|
||||
(org-element-set
|
||||
datum
|
||||
(replace-regexp-in-string
|
||||
"[ \t\n]*\\'" (make-string blanks ?\s) datum))))
|
||||
|
@ -492,11 +500,11 @@ S is split at beginning of match group N upon matching REGEXP against it.
|
|||
This function assumes S precedes CITATION."
|
||||
;; When extracting the citation, remove white spaces before it, but
|
||||
;; preserve those after it.
|
||||
(let ((post-blank (org-element-property :post-blank citation)))
|
||||
(let ((post-blank (org-element-post-blank citation)))
|
||||
(when (and post-blank (> post-blank 0))
|
||||
(org-element-insert-before (make-string post-blank ?\s) citation)))
|
||||
(org-element-insert-before
|
||||
(org-element-put-property (org-element-extract-element citation)
|
||||
(org-element-put-property (org-element-extract citation)
|
||||
:post-blank 0)
|
||||
s)
|
||||
(string-match regexp s)
|
||||
|
@ -510,21 +518,21 @@ This function assumes S precedes CITATION."
|
|||
(substring s split))))
|
||||
(when (org-string-nw-p first-part)
|
||||
(org-element-insert-before first-part citation))
|
||||
(org-element-set-element s last-part)))
|
||||
(org-element-set s last-part)))
|
||||
|
||||
(defun org-cite--move-punct-before (punct citation s info)
|
||||
"Move punctuation PUNCT before CITATION object.
|
||||
String S contains PUNCT. INFO is the export state, as a property list.
|
||||
The function assumes S follows CITATION. Parse tree is modified by side-effect."
|
||||
(if (equal s punct)
|
||||
(org-element-extract-element s) ;it would be empty anyway
|
||||
(org-element-set-element s (substring s (length punct))))
|
||||
(org-element-extract s) ;it would be empty anyway
|
||||
(org-element-set s (substring s (length punct))))
|
||||
;; Remove blanks before citation.
|
||||
(org-cite--set-previous-post-blank citation 0 info)
|
||||
(org-element-insert-before
|
||||
;; Blanks between citation and punct are now before punct and
|
||||
;; citation.
|
||||
(concat (make-string (or (org-element-property :post-blank citation) 0) ?\s)
|
||||
(concat (make-string (or (org-element-post-blank citation) 0) ?\s)
|
||||
punct)
|
||||
citation))
|
||||
|
||||
|
@ -602,7 +610,18 @@ to (adaptive outside after)."
|
|||
(append (mapcar (lambda (value)
|
||||
(pcase value
|
||||
(`(,f . ,d)
|
||||
(expand-file-name (org-strip-quotes f) d))))
|
||||
(setq f (org-strip-quotes f))
|
||||
(if (or (file-name-absolute-p f)
|
||||
(file-remote-p f)
|
||||
(equal d default-directory))
|
||||
;; Keep absolute paths, remote paths, and
|
||||
;; local relative paths.
|
||||
f
|
||||
;; Adjust relative bibliography path for
|
||||
;; #+SETUP files located in other directory.
|
||||
;; Also, see `org-export--update-included-link'.
|
||||
(file-relative-name
|
||||
(expand-file-name f d) default-directory)))))
|
||||
(pcase (org-collect-keywords
|
||||
'("BIBLIOGRAPHY") nil '("BIBLIOGRAPHY"))
|
||||
(`(("BIBLIOGRAPHY" . ,pairs)) pairs)))
|
||||
|
@ -619,12 +638,12 @@ or from the current buffer."
|
|||
(let ((contents (org-element-contents citation)))
|
||||
(cond
|
||||
((null contents)
|
||||
(org-with-point-at (org-element-property :contents-begin citation)
|
||||
(narrow-to-region (point) (org-element-property :contents-end citation))
|
||||
(org-with-point-at (org-element-contents-begin citation)
|
||||
(narrow-to-region (point) (org-element-contents-end citation))
|
||||
(let ((references nil))
|
||||
(while (not (eobp))
|
||||
(let ((reference (org-element-citation-reference-parser)))
|
||||
(goto-char (org-element-property :end reference))
|
||||
(goto-char (org-element-end reference))
|
||||
(push (if keys-only
|
||||
(org-element-property :key reference)
|
||||
reference)
|
||||
|
@ -636,8 +655,8 @@ or from the current buffer."
|
|||
(defun org-cite-boundaries (citation)
|
||||
"Return the beginning and end strict position of CITATION.
|
||||
Returns a (BEG . END) pair."
|
||||
(let ((beg (org-element-property :begin citation))
|
||||
(end (org-with-point-at (org-element-property :end citation)
|
||||
(let ((beg (org-element-begin citation))
|
||||
(end (org-with-point-at (org-element-end citation)
|
||||
(skip-chars-backward " \t")
|
||||
(point))))
|
||||
(cons beg end)))
|
||||
|
@ -646,15 +665,15 @@ Returns a (BEG . END) pair."
|
|||
"Return citation REFERENCE's key boundaries as buffer positions.
|
||||
The function returns a pair (START . END) where START and END denote positions
|
||||
in the current buffer. Positions include leading \"@\" character."
|
||||
(org-with-point-at (org-element-property :begin reference)
|
||||
(let ((end (org-element-property :end reference)))
|
||||
(org-with-point-at (org-element-begin reference)
|
||||
(let ((end (org-element-end reference)))
|
||||
(re-search-forward org-element-citation-key-re end t)
|
||||
(cons (match-beginning 0) (match-end 0)))))
|
||||
|
||||
(defun org-cite-main-affixes (citation)
|
||||
"Return main affixes for CITATION object.
|
||||
|
||||
Some export back-ends only support a single pair of affixes per
|
||||
Some export backends only support a single pair of affixes per
|
||||
citation, even if it contains multiple keys. This function
|
||||
decides what affixes are the most appropriate.
|
||||
|
||||
|
@ -730,7 +749,7 @@ When removing the last reference, also remove the whole citation."
|
|||
(org-with-point-at begin
|
||||
(skip-chars-backward " \t")
|
||||
(point)))
|
||||
(pos-after-blank (org-element-property :end datum))
|
||||
(pos-after-blank (org-element-end datum))
|
||||
(first-on-line?
|
||||
(= pos-before-blank (line-beginning-position)))
|
||||
(last-on-line?
|
||||
|
@ -753,22 +772,22 @@ When removing the last reference, also remove the whole citation."
|
|||
(when (= pos-after-blank end)
|
||||
(org-with-point-at pos-before-blank (insert " ")))))))
|
||||
('citation-reference
|
||||
(let* ((citation (org-element-property :parent datum))
|
||||
(let* ((citation (org-element-parent datum))
|
||||
(references (org-cite-get-references citation))
|
||||
(begin (org-element-property :begin datum))
|
||||
(end (org-element-property :end datum)))
|
||||
(begin (org-element-begin datum))
|
||||
(end (org-element-end datum)))
|
||||
(cond
|
||||
;; Single reference.
|
||||
((= 1 (length references))
|
||||
(org-cite-delete-citation citation))
|
||||
;; First reference, no prefix.
|
||||
((and (= begin (org-element-property :contents-begin citation))
|
||||
((and (= begin (org-element-contents-begin citation))
|
||||
(not (org-element-property :prefix citation)))
|
||||
(org-with-point-at (org-element-property :begin datum)
|
||||
(org-with-point-at (org-element-begin datum)
|
||||
(skip-chars-backward " \t")
|
||||
(delete-region (point) end)))
|
||||
;; Last reference, no suffix.
|
||||
((and (= end (org-element-property :contents-end citation))
|
||||
((and (= end (org-element-contents-end citation))
|
||||
(not (org-element-property :suffix citation)))
|
||||
(delete-region (1- begin) (1- (cdr (org-cite-boundaries citation)))))
|
||||
;; Somewhere in-between.
|
||||
|
@ -838,6 +857,11 @@ tokens. Spurious spaces are ignored."
|
|||
s))
|
||||
(nreverse result))))
|
||||
|
||||
(defun org-cite-processor (info)
|
||||
"Return expected citation/bibliography processor.
|
||||
INFO is a plist used as a communication channel."
|
||||
(car (plist-get info :cite-export)))
|
||||
|
||||
(defun org-cite-bibliography-style (info)
|
||||
"Return expected bibliography style.
|
||||
INFO is a plist used as a communication channel."
|
||||
|
@ -937,11 +961,12 @@ the sole contents of the footnote, e.g., after calling `org-cite-wrap-citation'.
|
|||
|
||||
When non-nil, the return value if the footnote container."
|
||||
(let ((footnote
|
||||
(org-element-lineage citation
|
||||
'(footnote-definition footnote-reference))))
|
||||
(org-element-lineage
|
||||
citation
|
||||
'(footnote-definition footnote-reference))))
|
||||
(and footnote
|
||||
(or (not strict)
|
||||
(equal (org-element-contents (org-element-property :parent citation))
|
||||
(equal (org-element-contents (org-element-parent citation))
|
||||
(list citation)))
|
||||
;; Return value.
|
||||
footnote)))
|
||||
|
@ -959,15 +984,15 @@ Return newly created footnote object."
|
|||
(list 'footnote-reference
|
||||
(list :label nil
|
||||
:type 'inline
|
||||
:contents-begin (org-element-property :begin citation)
|
||||
:contents-end (org-element-property :end citation)
|
||||
:post-blank (org-element-property :post-blank citation)))))
|
||||
:contents-begin (org-element-begin citation)
|
||||
:contents-end (org-element-end citation)
|
||||
:post-blank (org-element-post-blank citation)))))
|
||||
;; Remove any white space before citation.
|
||||
(org-cite--set-previous-post-blank citation 0 info)
|
||||
;; Footnote swallows citation.
|
||||
(org-element-insert-before footnote citation)
|
||||
(org-element-adopt-elements footnote
|
||||
(org-element-extract-element citation))))
|
||||
(org-element-adopt footnote
|
||||
(org-element-extract citation))))
|
||||
|
||||
(defun org-cite-adjust-note (citation info &optional rule punct)
|
||||
"Adjust note number location for CITATION object, and punctuation around it.
|
||||
|
@ -1046,8 +1071,8 @@ the same object, call `org-cite-adjust-note' first."
|
|||
;; as an argument is not available.
|
||||
(rx-to-string `(seq string-start ,final-punct) t)
|
||||
"" next)))
|
||||
(org-element-set-element previous new-prev)
|
||||
(org-element-set-element next new-next)
|
||||
(org-element-set previous new-prev)
|
||||
(org-element-set next new-next)
|
||||
(setq previous new-prev)
|
||||
(setq next new-next)
|
||||
(setq punct final-punct)
|
||||
|
@ -1066,15 +1091,15 @@ the same object, call `org-cite-adjust-note' first."
|
|||
(replace-regexp-in-string
|
||||
previous-punct-re "" previous nil nil 1))
|
||||
(new-next (if (stringp next) (concat punct next) punct)))
|
||||
(org-element-set-element previous new-prev)
|
||||
(org-element-set previous new-prev)
|
||||
(cond
|
||||
((stringp next)
|
||||
(org-element-set-element next new-next))
|
||||
(org-element-set next new-next))
|
||||
(next
|
||||
(org-element-insert-before new-next next))
|
||||
(t
|
||||
(org-element-adopt-elements
|
||||
(org-element-property :parent citation)
|
||||
(org-element-adopt
|
||||
(org-element-parent citation)
|
||||
new-next)))
|
||||
(setq previous new-prev)
|
||||
(setq next new-next)
|
||||
|
@ -1141,7 +1166,7 @@ raises an error if S contains a headline."
|
|||
(insert s)
|
||||
(pcase (org-element-contents (org-element-parse-buffer))
|
||||
('nil nil)
|
||||
(`(,(and section (guard (eq 'section (org-element-type section)))))
|
||||
(`(,(and section (guard (org-element-type-p section 'section))))
|
||||
(org-element-contents section))
|
||||
(_
|
||||
(error "Headlines cannot replace a keyword")))))
|
||||
|
@ -1201,14 +1226,23 @@ and must return either a string, an object, or a secondary string."
|
|||
(org-cite-concat result separator (funcall function datum))))
|
||||
result)))
|
||||
|
||||
(defun org-cite-capitalize (str)
|
||||
"Capitalize string of raw string object STR."
|
||||
(cond
|
||||
((stringp str) (capitalize str))
|
||||
((org-element-type-p str 'raw)
|
||||
(org-export-raw-string
|
||||
(capitalize (mapconcat #'identity (org-element-contents str) ""))))
|
||||
(t (error "%S must be either a string or raw string object" str))))
|
||||
|
||||
|
||||
;;; Internal interface with fontification (activate capability)
|
||||
(defun org-cite-fontify-default (cite)
|
||||
"Fontify CITE with `org-cite' and `org-cite-key' faces.
|
||||
CITE is a citation object. The function applies `org-cite' face
|
||||
on the whole citation, and `org-cite-key' face on each key."
|
||||
(let ((beg (org-element-property :begin cite))
|
||||
(end (org-with-point-at (org-element-property :end cite)
|
||||
(let ((beg (org-element-begin cite))
|
||||
(end (org-with-point-at (org-element-end cite)
|
||||
(skip-chars-backward " \t")
|
||||
(point))))
|
||||
(add-text-properties beg end '(font-lock-multiline t))
|
||||
|
@ -1237,7 +1271,7 @@ from the processor set in `org-cite-activate-processor'."
|
|||
(save-match-data (funcall activate cite))
|
||||
;; Move after cite object and make sure to return
|
||||
;; a non-nil value.
|
||||
(goto-char (org-element-property :end cite)))))))
|
||||
(goto-char (org-element-end cite)))))))
|
||||
|
||||
|
||||
;;; Internal interface with Org Export library (export capability)
|
||||
|
@ -1274,12 +1308,12 @@ side-effect."
|
|||
;; Value is an alist. It must come from
|
||||
;; `org-cite-export-processors' variable. Find the most
|
||||
;; appropriate processor according to current export
|
||||
;; back-end.
|
||||
;; backend.
|
||||
((and (pred consp) alist)
|
||||
(let* ((backend (plist-get info :back-end))
|
||||
(candidates
|
||||
;; Limit candidates to processors associated to
|
||||
;; back-ends derived from or equal to the current
|
||||
;; backends derived from or equal to the current
|
||||
;; one.
|
||||
(sort (seq-filter
|
||||
(pcase-lambda (`(,key . ,_))
|
||||
|
@ -1331,7 +1365,7 @@ selected citation processor."
|
|||
|
||||
(defun org-cite-export-bibliography (keyword _ info)
|
||||
"Return bibliography associated to \"print_bibliography\" KEYWORD.
|
||||
BACKEND is the export back-end, as a symbol. INFO is a plist
|
||||
BACKEND is the export backend, as a symbol. INFO is a plist
|
||||
used as a communication channel."
|
||||
(pcase (plist-get info :cite-export)
|
||||
('nil nil)
|
||||
|
@ -1355,7 +1389,7 @@ INFO is the communication channel, as a plist. Parse tree is modified
|
|||
by side-effect."
|
||||
(dolist (cite (org-cite-list-citations info))
|
||||
(let ((replacement (org-cite-export-citation cite nil info))
|
||||
(blanks (or (org-element-property :post-blank cite) 0)))
|
||||
(blanks (or (org-element-post-blank cite) 0)))
|
||||
(if (null replacement)
|
||||
;; Before removing the citation, transfer its `:post-blank'
|
||||
;; property to the object before, if any.
|
||||
|
@ -1389,7 +1423,7 @@ by side-effect."
|
|||
(_
|
||||
(error "Invalid return value from citation export processor: %S"
|
||||
replacement))))
|
||||
(org-element-extract-element cite))))
|
||||
(org-element-extract cite))))
|
||||
|
||||
(defun org-cite-process-bibliography (info)
|
||||
"Replace all \"print_bibliography\" keywords in the parse tree.
|
||||
|
@ -1400,18 +1434,18 @@ by side effect."
|
|||
(lambda (keyword)
|
||||
(when (equal "PRINT_BIBLIOGRAPHY" (org-element-property :key keyword))
|
||||
(let ((replacement (org-cite-export-bibliography keyword nil info))
|
||||
(blanks (or (org-element-property :post-blank keyword) 0)))
|
||||
(blanks (or (org-element-post-blank keyword) 0)))
|
||||
(pcase replacement
|
||||
;; Before removing the citation, transfer its
|
||||
;; `:post-blank' property to the element before, if any.
|
||||
('nil
|
||||
(org-cite--set-previous-post-blank keyword blanks info)
|
||||
(org-element-extract-element keyword))
|
||||
(org-element-extract keyword))
|
||||
;; Handle `:post-blank' before replacing keyword with string.
|
||||
((pred stringp)
|
||||
(let ((output (concat (org-element-normalize-string replacement)
|
||||
(make-string blanks ?\n))))
|
||||
(org-element-set-element keyword (org-export-raw-string output))))
|
||||
(org-element-set keyword (org-export-raw-string output))))
|
||||
;; List of elements: splice contents before keyword and
|
||||
;; remove the latter. Transfer `:post-blank' to last
|
||||
;; element.
|
||||
|
@ -1421,11 +1455,11 @@ by side effect."
|
|||
(setq last datum)
|
||||
(org-element-insert-before datum keyword))
|
||||
(org-cite--set-post-blank last blanks)
|
||||
(org-element-extract-element keyword)))
|
||||
(org-element-extract keyword)))
|
||||
;; Single element: replace the keyword.
|
||||
(`(,(pred symbolp) . ,_)
|
||||
(org-cite--set-post-blank replacement blanks)
|
||||
(org-element-set-element keyword replacement))
|
||||
(org-element-set keyword replacement))
|
||||
(_
|
||||
(error "Invalid return value from citation export processor: %S"
|
||||
replacement))))))
|
||||
|
@ -1481,7 +1515,7 @@ CONTEXT is the element or object at point, as returned by `org-element-context'.
|
|||
;;
|
||||
;; XXX: Inserting citation in a secondary value is not allowed
|
||||
;; yet. Is it useful?
|
||||
((let ((post (org-element-property :post-affiliated context)))
|
||||
((let ((post (org-element-post-affiliated context)))
|
||||
(and post (< (point) post)))
|
||||
(let ((case-fold-search t))
|
||||
(looking-back
|
||||
|
@ -1497,14 +1531,14 @@ CONTEXT is the element or object at point, as returned by `org-element-context'.
|
|||
((memq type '(nil paragraph)))
|
||||
;; So are contents of verse blocks.
|
||||
((eq type 'verse-block)
|
||||
(and (>= (point) (org-element-property :contents-begin context))
|
||||
(< (point) (org-element-property :contents-end context))))
|
||||
(and (>= (point) (org-element-contents-begin context))
|
||||
(< (point) (org-element-contents-end context))))
|
||||
;; In an headline or inlinetask, point must be either on the
|
||||
;; heading itself or on the blank lines below.
|
||||
((memq type '(headline inlinetask))
|
||||
(or (not (org-at-heading-p))
|
||||
(and (save-excursion
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(and (let ((case-fold-search t))
|
||||
(not (looking-at-p "\\*+ END[ \t]*$")))
|
||||
(let ((case-fold-search nil))
|
||||
|
@ -1523,43 +1557,43 @@ CONTEXT is the element or object at point, as returned by `org-element-context'.
|
|||
;; White spaces after an object or blank lines after an element
|
||||
;; are OK.
|
||||
((>= (point)
|
||||
(save-excursion (goto-char (org-element-property :end context))
|
||||
(skip-chars-backward " \r\t\n")
|
||||
(if (eq (org-element-class context) 'object) (point)
|
||||
(line-beginning-position 2)))))
|
||||
(save-excursion (goto-char (org-element-end context))
|
||||
(skip-chars-backward " \r\t\n")
|
||||
(if (eq (org-element-class context) 'object) (point)
|
||||
(line-beginning-position 2)))))
|
||||
;; At the beginning of a footnote definition, right after the
|
||||
;; label, is OK.
|
||||
((eq type 'footnote-definition) (looking-at (rx space)))
|
||||
;; At the start of a list item is fine, as long as the bullet is
|
||||
;; unaffected.
|
||||
((eq type 'item)
|
||||
(> (point) (+ (org-element-property :begin context)
|
||||
(> (point) (+ (org-element-begin context)
|
||||
(org-current-text-indentation)
|
||||
(if (org-element-property :checkbox context)
|
||||
5 1))))
|
||||
;; Other elements are invalid.
|
||||
((eq (org-element-class context) 'element) nil)
|
||||
;; Just before object is fine.
|
||||
((= (point) (org-element-property :begin context)))
|
||||
((= (point) (org-element-begin context)))
|
||||
;; Within recursive object too, but not in a link.
|
||||
((eq type 'link) nil)
|
||||
((eq type 'table-cell)
|
||||
;; :contents-begin is not reliable on empty cells, so special
|
||||
;; case it.
|
||||
(<= (save-excursion (skip-chars-backward " \t") (point))
|
||||
(org-element-property :contents-end context)))
|
||||
((let ((cbeg (org-element-property :contents-begin context))
|
||||
(cend (org-element-property :contents-end context)))
|
||||
(org-element-contents-end context)))
|
||||
((let ((cbeg (org-element-contents-begin context))
|
||||
(cend (org-element-contents-end context)))
|
||||
(and cbeg (>= (point) cbeg) (<= (point) cend)))))))
|
||||
|
||||
(defun org-cite--insert-string-before (string reference)
|
||||
"Insert STRING before citation REFERENCE object."
|
||||
(org-with-point-at (org-element-property :begin reference)
|
||||
(org-with-point-at (org-element-begin reference)
|
||||
(insert string ";")))
|
||||
|
||||
(defun org-cite--insert-string-after (string reference)
|
||||
"Insert STRING after citation REFERENCE object."
|
||||
(org-with-point-at (org-element-property :end reference)
|
||||
(org-with-point-at (org-element-end reference)
|
||||
;; Make sure to move forward when we're inserting at point, so the
|
||||
;; insertion can happen multiple times.
|
||||
(if (char-equal ?\; (char-before))
|
||||
|
@ -1630,7 +1664,7 @@ More specifically,
|
|||
;; action depends on the point.
|
||||
(if arg
|
||||
(org-cite-delete-citation context)
|
||||
(let* ((begin (org-element-property :begin context))
|
||||
(let* ((begin (org-element-begin context))
|
||||
(style-end (1- (org-with-point-at begin (search-forward ":")))))
|
||||
(if (>= style-end (point))
|
||||
;; On style part, edit the style.
|
||||
|
@ -1644,7 +1678,7 @@ More specifically,
|
|||
;; point.
|
||||
(let* ((references (org-cite-get-references context))
|
||||
(key (concat "@" (funcall select-key nil))))
|
||||
(if (< (point) (org-element-property :contents-begin context))
|
||||
(if (< (point) (org-element-contents-begin context))
|
||||
(org-cite--insert-string-before key (car references))
|
||||
(org-cite--insert-string-after key (org-last references))))))))
|
||||
;; On a citation reference. If ARG is not nil, remove the
|
||||
|
@ -1699,7 +1733,7 @@ ARG is the prefix argument received when calling interactively the function."
|
|||
(let ((context (org-element-context))
|
||||
(insert (org-cite-processor-insert (org-cite-get-processor name))))
|
||||
(cond
|
||||
((memq (org-element-type context) '(citation citation-reference))
|
||||
((org-element-type-p context '(citation citation-reference))
|
||||
(funcall insert context arg))
|
||||
((org-cite--allowed-p context)
|
||||
(funcall insert nil arg))
|
||||
|
|
|
@ -226,7 +226,7 @@ date year)."
|
|||
|
||||
;;; Implementation
|
||||
|
||||
(defun org-bbdb-store-link ()
|
||||
(defun org-bbdb-store-link (&optional _interactive?)
|
||||
"Store a link to a BBDB database entry."
|
||||
(when (eq major-mode 'bbdb-mode)
|
||||
;; This is BBDB, we make this link!
|
||||
|
@ -255,7 +255,7 @@ italicized, in all other cases it is left unchanged."
|
|||
|
||||
(defun org-bbdb-open (name _)
|
||||
"Follow a BBDB link to NAME."
|
||||
(require 'bbdb-com)
|
||||
(org-require-package 'bbdb-com "bbdb")
|
||||
(let ((inhibit-redisplay (not debug-on-error)))
|
||||
(if (fboundp 'bbdb-name)
|
||||
(org-bbdb-open-old name)
|
||||
|
@ -369,7 +369,7 @@ This is used by Org to re-create the anniversary hash table."
|
|||
"Extract anniversaries from BBDB for display in the agenda.
|
||||
When called programmatically, this function expects the `date'
|
||||
variable to be globally bound."
|
||||
(require 'bbdb)
|
||||
(org-require-package 'bbdb)
|
||||
(require 'diary-lib)
|
||||
(unless (hash-table-p org-bbdb-anniv-hash)
|
||||
(setq org-bbdb-anniv-hash
|
||||
|
@ -500,7 +500,7 @@ must be positive"))
|
|||
|
||||
(defun org-bbdb-complete-link ()
|
||||
"Read a bbdb link with name completion."
|
||||
(require 'bbdb-com)
|
||||
(org-require-package 'bbdb-com "bbdb")
|
||||
(let ((rec (bbdb-completing-read-record "Name: ")))
|
||||
(concat "bbdb:"
|
||||
(bbdb-record-name (if (listp rec)
|
||||
|
@ -509,7 +509,7 @@ must be positive"))
|
|||
|
||||
(defun org-bbdb-anniv-export-ical ()
|
||||
"Extract anniversaries from BBDB and convert them to icalendar format."
|
||||
(require 'bbdb)
|
||||
(org-require-package 'bbdb)
|
||||
(require 'diary-lib)
|
||||
(unless (hash-table-p org-bbdb-anniv-hash)
|
||||
(setq org-bbdb-anniv-hash
|
||||
|
|
|
@ -266,7 +266,7 @@ a missing title field."
|
|||
:type 'boolean)
|
||||
|
||||
(defcustom org-bibtex-headline-format-function
|
||||
(lambda (entry) (cdr (assq :title entry)))
|
||||
#'org-bibtex-headline-format-default
|
||||
"Function returning the headline text for `org-bibtex-write'.
|
||||
It should take a single argument, the bibtex entry (an alist as
|
||||
returned by `org-bibtex-read'). The default value simply returns
|
||||
|
@ -507,7 +507,7 @@ ARG, when non-nil, is a universal prefix argument. See
|
|||
`org-open-file' for details."
|
||||
(org-link-open-as-file path arg))
|
||||
|
||||
(defun org-bibtex-store-link ()
|
||||
(defun org-bibtex-store-link (&optional _interactive?)
|
||||
"Store a link to a BibTeX entry."
|
||||
(when (eq major-mode 'bibtex-mode)
|
||||
(let* ((search (org-create-file-search-in-bibtex))
|
||||
|
@ -636,22 +636,27 @@ With prefix argument OPTIONAL also prompt for optional fields."
|
|||
With prefix argument OPTIONAL also prompt for optional fields."
|
||||
(interactive) (org-map-entries (lambda () (org-bibtex-check optional))))
|
||||
|
||||
(defun org-bibtex-create (&optional arg nonew)
|
||||
(defun org-bibtex-headline-format-default (entry)
|
||||
"Return headline text according to ENTRY title."
|
||||
(cdr (assq :title entry)))
|
||||
|
||||
(defun org-bibtex-create (&optional arg update-heading)
|
||||
"Create a new entry at the given level.
|
||||
With a prefix arg, query for optional fields as well.
|
||||
If nonew is t, add data to the headline of the entry at point."
|
||||
With a prefix ARG, query for optional fields as well.
|
||||
If UPDATE-HEADING is non-nil, add data to the headline of the entry at
|
||||
point."
|
||||
(interactive "P")
|
||||
(let* ((type (completing-read
|
||||
"Type: " (mapcar (lambda (type)
|
||||
(substring (symbol-name (car type)) 1))
|
||||
org-bibtex-types)
|
||||
nil nil (when nonew
|
||||
(org-bibtex-get org-bibtex-type-property-name))))
|
||||
nil nil (when update-heading
|
||||
(org-bibtex-get org-bibtex-type-property-name))))
|
||||
(type (if (keywordp type) type (intern (concat ":" type))))
|
||||
(org-bibtex-treat-headline-as-title (if nonew nil t)))
|
||||
(org-bibtex-treat-headline-as-title (if update-heading nil t)))
|
||||
(unless (assoc type org-bibtex-types)
|
||||
(error "Type:%s is not known" type))
|
||||
(if nonew
|
||||
(if update-heading
|
||||
(org-back-to-heading)
|
||||
(org-insert-heading)
|
||||
(let ((title (org-bibtex-ask :title)))
|
||||
|
@ -718,29 +723,32 @@ Return the number of saved entries."
|
|||
(interactive "fFile: ")
|
||||
(org-bibtex-read-buffer (find-file-noselect file 'nowarn 'rawfile)))
|
||||
|
||||
(defun org-bibtex-write (&optional noindent)
|
||||
(defun org-bibtex-write (&optional noindent update-heading)
|
||||
"Insert a heading built from the first element of `org-bibtex-entries'.
|
||||
When optional argument NOINDENT is non-nil, do not indent the properties
|
||||
drawer."
|
||||
drawer. If UPDATE-HEADING is non-nil, add data to the headline of the
|
||||
entry at point."
|
||||
(interactive)
|
||||
(unless org-bibtex-entries
|
||||
(error "No entries in `org-bibtex-entries'"))
|
||||
(let* ((entry (pop org-bibtex-entries))
|
||||
(org-special-properties nil) ; avoids errors with `org-entry-put'
|
||||
(val (lambda (field) (cdr (assoc field entry))))
|
||||
(togtag (lambda (tag) (org-toggle-tag tag 'on))))
|
||||
(org-insert-heading)
|
||||
(insert (funcall org-bibtex-headline-format-function entry))
|
||||
(insert "\n:PROPERTIES:\n")
|
||||
(org-bibtex-put "TITLE" (funcall val :title) 'insert)
|
||||
(togtag (lambda (tag) (org-toggle-tag tag 'on)))
|
||||
(insert-raw (not update-heading)))
|
||||
(unless update-heading
|
||||
(org-insert-heading)
|
||||
(insert (funcall org-bibtex-headline-format-function entry))
|
||||
(insert "\n:PROPERTIES:\n"))
|
||||
(org-bibtex-put "TITLE" (funcall val :title) insert-raw)
|
||||
(org-bibtex-put org-bibtex-type-property-name
|
||||
(downcase (funcall val :type))
|
||||
'insert)
|
||||
insert-raw)
|
||||
(dolist (pair entry)
|
||||
(pcase (car pair)
|
||||
(:title nil)
|
||||
(:type nil)
|
||||
(:key (org-bibtex-put org-bibtex-key-property (cdr pair) 'insert))
|
||||
(:key (org-bibtex-put org-bibtex-key-property (cdr pair) insert-raw))
|
||||
(:keywords (if org-bibtex-tags-are-keywords
|
||||
(dolist (kw (split-string (cdr pair) ", *"))
|
||||
(funcall
|
||||
|
@ -748,25 +756,28 @@ drawer."
|
|||
(replace-regexp-in-string
|
||||
"[^[:alnum:]_@#%]" ""
|
||||
(replace-regexp-in-string "[ \t]+" "_" kw))))
|
||||
(org-bibtex-put (car pair) (cdr pair) 'insert)))
|
||||
(_ (org-bibtex-put (car pair) (cdr pair) 'insert))))
|
||||
(insert ":END:\n")
|
||||
(org-bibtex-put (car pair) (cdr pair) insert-raw)))
|
||||
(_ (org-bibtex-put (car pair) (cdr pair) insert-raw))))
|
||||
(unless update-heading
|
||||
(insert ":END:\n"))
|
||||
(mapc togtag org-bibtex-tags)
|
||||
(unless noindent
|
||||
(org-indent-region
|
||||
(save-excursion (org-back-to-heading t) (point))
|
||||
(point)))))
|
||||
|
||||
(defun org-bibtex-yank ()
|
||||
"If kill ring holds a bibtex entry yank it as an Org headline."
|
||||
(interactive)
|
||||
(defun org-bibtex-yank (&optional update-heading)
|
||||
"If kill ring holds a bibtex entry yank it as an Org headline.
|
||||
When called with non-nil prefix argument UPDATE-HEADING, add data to the
|
||||
headline of the entry at point."
|
||||
(interactive "P")
|
||||
(let (entry)
|
||||
(with-temp-buffer
|
||||
(yank 1)
|
||||
(bibtex-mode)
|
||||
(setf entry (org-bibtex-read)))
|
||||
(if entry
|
||||
(org-bibtex-write)
|
||||
(org-bibtex-write nil update-heading)
|
||||
(error "Yanked text does not appear to contain a BibTeX entry"))))
|
||||
|
||||
(defun org-bibtex-import-from-file (file)
|
||||
|
|
|
@ -57,20 +57,21 @@
|
|||
:export #'org-docview-export
|
||||
:store #'org-docview-store-link)
|
||||
|
||||
(defun org-docview-export (link description format)
|
||||
"Export a docview link from Org files."
|
||||
(defun org-docview-export (link description backend _info)
|
||||
"Export a docview LINK with DESCRIPTION for BACKEND."
|
||||
(let ((path (if (string-match "\\(.+\\)::.+" link) (match-string 1 link)
|
||||
link))
|
||||
(desc (or description link)))
|
||||
(when (stringp path)
|
||||
(setq path (expand-file-name path))
|
||||
(cond
|
||||
((eq format 'html) (format "<a href=\"%s\">%s</a>" path desc))
|
||||
((eq format 'latex) (format "\\href{%s}{%s}" path desc))
|
||||
((eq format 'ascii) (format "%s (%s)" desc path))
|
||||
((eq backend 'html) (format "<a href=\"%s\">%s</a>" path desc))
|
||||
((eq backend 'latex) (format "\\href{%s}{%s}" path desc))
|
||||
((eq backend 'ascii) (format "[%s] (<%s>)" desc path))
|
||||
(t path)))))
|
||||
|
||||
(defun org-docview-open (link _)
|
||||
"Open docview: LINK."
|
||||
(string-match "\\(.*?\\)\\(?:::\\([0-9]+\\)\\)?$" link)
|
||||
(let ((path (match-string 1 link))
|
||||
(page (and (match-beginning 2)
|
||||
|
@ -82,7 +83,7 @@
|
|||
(error "No such file: %s" path))
|
||||
(when page (doc-view-goto-page page))))
|
||||
|
||||
(defun org-docview-store-link ()
|
||||
(defun org-docview-store-link (&optional _interactive?)
|
||||
"Store a link to a docview buffer."
|
||||
(when (eq major-mode 'doc-view-mode)
|
||||
;; This buffer is in doc-view-mode
|
||||
|
|
|
@ -40,7 +40,8 @@
|
|||
|
||||
(defun org-link-doi-open (path arg)
|
||||
"Open a \"doi\" type link.
|
||||
PATH is a the path to search for, as a string."
|
||||
PATH is a the path to search for, as a string.
|
||||
ARG is passed to `browse-url'."
|
||||
(browse-url (url-encode-url (concat org-link-doi-server-url path)) arg))
|
||||
|
||||
(defun org-link-doi-export (path desc backend info)
|
||||
|
|
|
@ -37,8 +37,8 @@
|
|||
:store #'org-eshell-store-link)
|
||||
|
||||
(defun org-eshell-open (link _)
|
||||
"Switch to an eshell buffer and execute a command line.
|
||||
The link can be just a command line (executed in the default
|
||||
"Switch to an eshell buffer and execute a command line for LINK.
|
||||
The LINK can be just a command line (executed in the default
|
||||
eshell buffer) or a command line prefixed by a buffer name
|
||||
followed by a colon."
|
||||
(let* ((buffer-and-command
|
||||
|
@ -60,9 +60,10 @@ followed by a colon."
|
|||
(insert command)
|
||||
(eshell-send-input)))
|
||||
|
||||
(defun org-eshell-store-link ()
|
||||
"Store a link that, when opened, switches back to the current eshell buffer
|
||||
and the current working directory."
|
||||
(defun org-eshell-store-link (&optional _interactive?)
|
||||
"Store eshell link.
|
||||
When opened, the link switches back to the current eshell buffer and
|
||||
the current working directory."
|
||||
(when (eq major-mode 'eshell-mode)
|
||||
(let* ((command (concat "cd " (eshell/pwd)))
|
||||
(link (concat (buffer-name) ":" command)))
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
"Open URL with Eww in the current buffer."
|
||||
(eww url))
|
||||
|
||||
(defun org-eww-store-link ()
|
||||
(defun org-eww-store-link (&optional _interactive?)
|
||||
"Store a link to the url of an EWW buffer."
|
||||
(when (eq major-mode 'eww-mode)
|
||||
(org-link-store-props
|
||||
|
@ -162,6 +162,7 @@ keep the structure of the Org file."
|
|||
;; Additional keys for eww-mode
|
||||
|
||||
(defun org-eww-extend-eww-keymap ()
|
||||
"Add ol-eww bindings to `eww-mode-map'."
|
||||
(define-key eww-mode-map "\C-c\C-x\M-w" 'org-eww-copy-for-org-mode)
|
||||
(define-key eww-mode-map "\C-c\C-x\C-w" 'org-eww-copy-for-org-mode))
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@ If `org-store-link' was called with a prefix arg the meaning of
|
|||
(url-encode-url message-id))
|
||||
(concat "gnus:" group "#" message-id)))
|
||||
|
||||
(defun org-gnus-store-link ()
|
||||
(defun org-gnus-store-link (&optional _interactive?)
|
||||
"Store a link to a Gnus folder or message."
|
||||
(pcase major-mode
|
||||
(`gnus-group-mode
|
||||
|
@ -137,27 +137,23 @@ If `org-store-link' was called with a prefix arg the meaning of
|
|||
(let* ((group
|
||||
(pcase (gnus-find-method-for-group gnus-newsgroup-name)
|
||||
(`(nnvirtual . ,_)
|
||||
(save-excursion
|
||||
(car (nnvirtual-map-article (gnus-summary-article-number)))))
|
||||
(with-current-buffer gnus-summary-buffer
|
||||
(save-excursion
|
||||
(car (nnvirtual-map-article (gnus-summary-article-number))))))
|
||||
(`(,(or `nnselect `nnir) . ,_) ; nnir is for Emacs < 28.
|
||||
(save-excursion
|
||||
(cond
|
||||
((fboundp 'nnselect-article-group)
|
||||
(nnselect-article-group (gnus-summary-article-number)))
|
||||
((fboundp 'nnir-article-group)
|
||||
(nnir-article-group (gnus-summary-article-number)))
|
||||
(t
|
||||
(error "No article-group variant bound")))))
|
||||
(with-current-buffer gnus-summary-buffer
|
||||
(save-excursion
|
||||
(cond
|
||||
((fboundp 'nnselect-article-group)
|
||||
(nnselect-article-group (gnus-summary-article-number)))
|
||||
((fboundp 'nnir-article-group)
|
||||
(nnir-article-group (gnus-summary-article-number)))
|
||||
(t
|
||||
(error "No article-group variant bound"))))))
|
||||
(_ gnus-newsgroup-name)))
|
||||
(header (if (eq major-mode 'gnus-article-mode)
|
||||
;; When in an article, first move to summary
|
||||
;; buffer, with point on the summary of the
|
||||
;; current article before extracting headers.
|
||||
(save-window-excursion
|
||||
(save-excursion
|
||||
(gnus-article-show-summary)
|
||||
(gnus-summary-article-header)))
|
||||
(gnus-summary-article-header)))
|
||||
(header (with-current-buffer gnus-summary-buffer
|
||||
(save-excursion
|
||||
(gnus-summary-article-header))))
|
||||
(from (mail-header-from header))
|
||||
(message-id (org-unbracket-string "<" ">" (mail-header-id header)))
|
||||
(date (org-trim (mail-header-date header)))
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
:insert-description #'org-info-description-as-command)
|
||||
|
||||
;; Implementation
|
||||
(defun org-info-store-link ()
|
||||
(defun org-info-store-link (&optional _interactive?)
|
||||
"Store a link to an Info file and node."
|
||||
(when (eq major-mode 'Info-mode)
|
||||
(let ((link (concat "info:"
|
||||
|
@ -139,13 +139,17 @@ If LINK is not an info link then DESC is returned."
|
|||
"List of Emacs documents available.
|
||||
Taken from <https://www.gnu.org/software/emacs/manual/html_mono/.>")
|
||||
|
||||
(defconst org-info-other-documents
|
||||
(defcustom org-info-other-documents
|
||||
'(("dir" . "https://www.gnu.org/manual/manual.html") ; index
|
||||
("libc" . "https://www.gnu.org/software/libc/manual/html_mono/libc.html")
|
||||
("make" . "https://www.gnu.org/software/make/manual/make.html"))
|
||||
"Alist of documents generated from Texinfo source.
|
||||
When converting info links to HTML, links to any one of these manuals are
|
||||
converted to use these URL.")
|
||||
converted to use these URL."
|
||||
:group 'org-link
|
||||
:type '(alist :key-type string :value-type string)
|
||||
:package-version '(Org . "9.7")
|
||||
:safe t)
|
||||
|
||||
(defun org-info-map-html-url (filename)
|
||||
"Return URL or HTML file associated to Info FILENAME.
|
||||
|
@ -153,11 +157,11 @@ If FILENAME refers to an official GNU document, return a URL pointing to
|
|||
the official page for that document, e.g., use \"gnu.org\" for all Emacs
|
||||
related documents. Otherwise, append \".html\" extension to FILENAME.
|
||||
See `org-info-emacs-documents' and `org-info-other-documents' for details."
|
||||
(cond ((member filename org-info-emacs-documents)
|
||||
(format "https://www.gnu.org/software/emacs/manual/html_mono/%s.html"
|
||||
filename))
|
||||
((cdr (assoc filename org-info-other-documents)))
|
||||
(t (concat filename ".html"))))
|
||||
(cond ((cdr (assoc filename org-info-other-documents)))
|
||||
((member filename org-info-emacs-documents)
|
||||
(format "https://www.gnu.org/software/emacs/manual/html_mono/%s.html"
|
||||
filename))
|
||||
(t (concat filename ".html"))))
|
||||
|
||||
(defun org-info--expand-node-name (node)
|
||||
"Expand Info NODE to HTML cross reference."
|
||||
|
|
|
@ -103,7 +103,7 @@ attributes that are found."
|
|||
parts))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-irc-store-link ()
|
||||
(defun org-irc-store-link (&optional _interactive?)
|
||||
"Dispatch to the appropriate function to store a link to an IRC session."
|
||||
(cond
|
||||
((eq major-mode 'erc-mode)
|
||||
|
|
|
@ -24,12 +24,17 @@
|
|||
;;
|
||||
;;; Commentary:
|
||||
|
||||
;; This file implements links to man pages from within Org mode.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'org-macs)
|
||||
(org-assert-version)
|
||||
|
||||
(require 'ol)
|
||||
|
||||
(org-link-set-parameters "man"
|
||||
:complete #'org-man-complete
|
||||
:follow #'org-man-open
|
||||
:export #'org-man-export
|
||||
:store #'org-man-store-link)
|
||||
|
@ -37,15 +42,29 @@
|
|||
(defcustom org-man-command 'man
|
||||
"The Emacs command to be used to display a man page."
|
||||
:group 'org-link
|
||||
:type '(choice (const man) (const woman)))
|
||||
:type '(choice (const man) (const :tag "WoMan (obsolete)" woman)))
|
||||
|
||||
(declare-function Man-translate-references "man" (ref))
|
||||
(defun org-man-open (path _)
|
||||
"Visit the manpage on PATH.
|
||||
PATH should be a topic that can be thrown at the man command.
|
||||
If PATH contains extra ::STRING which will use `occur' to search
|
||||
matched strings in man buffer."
|
||||
(require 'man) ; For `Man-translate-references'
|
||||
(string-match "\\(.*?\\)\\(?:::\\(.*\\)\\)?$" path)
|
||||
(let* ((command (match-string 1 path))
|
||||
;; FIXME: Remove after we drop Emacs 29 support.
|
||||
;; Working around security bug #66390.
|
||||
(command (if (not (equal (Man-translate-references ";id") ";id"))
|
||||
;; We are on Emacs that escapes man command args
|
||||
;; (see Emacs commit 820f0793f0b).
|
||||
command
|
||||
;; Older Emacs without the fix - escape the
|
||||
;; arguments ourselves.
|
||||
(mapconcat 'identity
|
||||
(mapcar #'shell-quote-argument
|
||||
(split-string command "\\s-+"))
|
||||
" ")))
|
||||
(search (match-string 2 path))
|
||||
(buffer (funcall org-man-command command)))
|
||||
(when search
|
||||
|
@ -63,7 +82,7 @@ matched strings in man buffer."
|
|||
(set-window-point window point)
|
||||
(set-window-start window point)))))))
|
||||
|
||||
(defun org-man-store-link ()
|
||||
(defun org-man-store-link (&optional _interactive?)
|
||||
"Store a link to a README file."
|
||||
(when (memq major-mode '(Man-mode woman-mode))
|
||||
;; This is a man page, we do make this link
|
||||
|
@ -82,18 +101,31 @@ matched strings in man buffer."
|
|||
(match-string 1 (buffer-name))
|
||||
(error "Cannot create link to this man page")))
|
||||
|
||||
(defun org-man-export (link description format)
|
||||
"Export a man page link from Org files."
|
||||
(defun org-man-export (link description backend)
|
||||
"Export a man page LINK with DESCRIPTION.
|
||||
BACKEND is the current export backend."
|
||||
(let ((path (format "http://man.he.net/?topic=%s§ion=all" link))
|
||||
(desc (or description link)))
|
||||
(cond
|
||||
((eq format 'html) (format "<a target=\"_blank\" href=\"%s\">%s</a>" path desc))
|
||||
((eq format 'latex) (format "\\href{%s}{%s}" path desc))
|
||||
((eq format 'texinfo) (format "@uref{%s,%s}" path desc))
|
||||
((eq format 'ascii) (format "%s (%s)" desc path))
|
||||
((eq format 'md) (format "[%s](%s)" desc path))
|
||||
((eq backend 'html) (format "<a target=\"_blank\" href=\"%s\">%s</a>" path desc))
|
||||
((eq backend 'latex) (format "\\href{%s}{%s}" path desc))
|
||||
((eq backend 'texinfo) (format "@uref{%s,%s}" path desc))
|
||||
((eq backend 'ascii) (format "[%s] (<%s>)" desc path))
|
||||
((eq backend 'md) (format "[%s](%s)" desc path))
|
||||
(t path))))
|
||||
|
||||
(defvar Man-completion-cache) ; Defined in `man'.
|
||||
(defun org-man-complete (&optional _arg)
|
||||
"Complete man pages for `org-insert-link'."
|
||||
(require 'man)
|
||||
(concat
|
||||
"man:"
|
||||
(let ((completion-ignore-case t) ; See `man' comments.
|
||||
(Man-completion-cache)) ; See `man' implementation.
|
||||
(completing-read
|
||||
"Manual entry: "
|
||||
'Man-completion-table))))
|
||||
|
||||
(provide 'ol-man)
|
||||
|
||||
;;; ol-man.el ends here
|
||||
|
|
|
@ -80,7 +80,7 @@ supported by MH-E."
|
|||
(org-link-set-parameters "mhe" :follow #'org-mhe-open :store #'org-mhe-store-link)
|
||||
|
||||
;; Implementation
|
||||
(defun org-mhe-store-link ()
|
||||
(defun org-mhe-store-link (&optional _interactive?)
|
||||
"Store a link to an MH-E folder or message."
|
||||
(when (or (eq major-mode 'mh-folder-mode)
|
||||
(eq major-mode 'mh-show-mode))
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
:store #'org-rmail-store-link)
|
||||
|
||||
;; Implementation
|
||||
(defun org-rmail-store-link ()
|
||||
(defun org-rmail-store-link (&optional _interactive?)
|
||||
"Store a link to an Rmail folder or message."
|
||||
(when (or (eq major-mode 'rmail-mode)
|
||||
(eq major-mode 'rmail-summary-mode))
|
||||
|
|
663
lisp/org/ol.el
663
lisp/org/ol.el
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -34,9 +34,9 @@
|
|||
(require 'org)
|
||||
(require 'cl-lib)
|
||||
|
||||
(declare-function org-element-type "org-element" (element))
|
||||
(declare-function org-datetree-find-date-create "org-datetree" (date &optional keep-restriction))
|
||||
(declare-function org-inlinetask-remove-END-maybe "org-inlinetask" ())
|
||||
(declare-function org-timestamp-to-now "org" (timestamp-string &optional seconds))
|
||||
|
||||
;; From org-element.el
|
||||
(defvar org-element--cache-avoid-synchronous-headline-re-parsing)
|
||||
|
@ -154,10 +154,10 @@ archive location, but not yet deleted from the original file.")
|
|||
|
||||
;;;###autoload
|
||||
(defun org-add-archive-files (files)
|
||||
"Splice the archive files into the list of files.
|
||||
"Splice the archive FILES into the list of files.
|
||||
This implies visiting all these files and finding out what the
|
||||
archive file is."
|
||||
(org-uniquify
|
||||
(seq-uniq
|
||||
(apply
|
||||
'append
|
||||
(mapcar
|
||||
|
@ -166,7 +166,9 @@ archive file is."
|
|||
nil
|
||||
(with-current-buffer (org-get-agenda-file-buffer f)
|
||||
(cons f (org-all-archive-files)))))
|
||||
files))))
|
||||
files))
|
||||
#'file-equal-p
|
||||
))
|
||||
|
||||
(defun org-all-archive-files ()
|
||||
"List of all archive files used in the current buffer."
|
||||
|
@ -252,8 +254,7 @@ direct children of this heading."
|
|||
(newfile-p (and (org-string-nw-p afile)
|
||||
(not (file-exists-p afile))))
|
||||
(buffer (cond ((not (org-string-nw-p afile)) this-buffer)
|
||||
((find-buffer-visiting afile))
|
||||
((find-file-noselect afile))
|
||||
((find-file-noselect afile 'nowarn))
|
||||
(t (error "Cannot access file \"%s\"" afile))))
|
||||
(org-odd-levels-only
|
||||
(if (local-variable-p 'org-odd-levels-only (current-buffer))
|
||||
|
@ -477,9 +478,9 @@ Archiving time is retained in the ARCHIVE_TIME node property."
|
|||
(goto-char e)
|
||||
(or (bolp) (newline))
|
||||
(insert leader org-archive-sibling-heading "\n")
|
||||
(beginning-of-line 0)
|
||||
(forward-line -1)
|
||||
(org-toggle-tag org-archive-tag 'on))
|
||||
(beginning-of-line 1)
|
||||
(forward-line 0)
|
||||
(if org-archive-reversed-order
|
||||
(outline-next-heading)
|
||||
(org-end-of-subtree t t))
|
||||
|
@ -524,12 +525,12 @@ When TAG is non-nil, don't move trees, but mark them with the ARCHIVE tag."
|
|||
(let (ts)
|
||||
(and (re-search-forward org-ts-regexp end t)
|
||||
(setq ts (match-string 0))
|
||||
(< (org-time-stamp-to-now ts) 0)
|
||||
(< (org-timestamp-to-now ts) 0)
|
||||
(if (not (looking-at
|
||||
(concat "--\\(" org-ts-regexp "\\)")))
|
||||
(concat "--\\(" org-ts-regexp "\\)")))
|
||||
(concat "old timestamp " ts)
|
||||
(setq ts (concat "old timestamp " ts (match-string 0)))
|
||||
(and (< (org-time-stamp-to-now (match-string 1)) 0)
|
||||
(and (< (org-timestamp-to-now (match-string 1)) 0)
|
||||
ts)))))
|
||||
tag))
|
||||
|
||||
|
@ -590,8 +591,9 @@ don't move trees, but mark them with the ARCHIVE tag."
|
|||
;;;###autoload
|
||||
(defun org-toggle-archive-tag (&optional find-done)
|
||||
"Toggle the archive tag for the current headline.
|
||||
With prefix ARG, check all children of current headline and offer tagging
|
||||
the children that do not contain any open TODO items."
|
||||
With prefix argument FIND-DONE, check all children of current headline
|
||||
and offer tagging the children that do not contain any open TODO
|
||||
items."
|
||||
(interactive "P")
|
||||
(if (and (org-region-active-p) org-loop-over-headlines-in-active-region)
|
||||
(let ((cl (if (eq org-loop-over-headlines-in-active-region 'start-level)
|
||||
|
@ -608,7 +610,7 @@ the children that do not contain any open TODO items."
|
|||
(org-back-to-heading t)
|
||||
(setq set (org-toggle-tag org-archive-tag))
|
||||
(when set (org-fold-subtree t)))
|
||||
(and set (beginning-of-line 1))
|
||||
(and set (forward-line 0))
|
||||
(message "Subtree %s" (if set "archived" "unarchived"))))))
|
||||
|
||||
(defun org-archive-set-tag ()
|
||||
|
|
|
@ -44,8 +44,12 @@
|
|||
|
||||
(declare-function dired-dwim-target-directory "dired-aux")
|
||||
(declare-function dired-get-marked-files "dired" (&optional localp arg filter distinguish-one-marked error))
|
||||
(declare-function org-element-property "org-element" (property element))
|
||||
(declare-function org-element-type "org-element" (element))
|
||||
(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-contents-begin "org-element" (node))
|
||||
(declare-function org-element-contents-end "org-element" (node))
|
||||
(declare-function org-element-type-p "org-element-ast" (node types))
|
||||
(declare-function org-inlinetask-goto-beginning "org-inlinetask" ())
|
||||
(declare-function org-inlinetask-in-task-p "org-inlinetask" ())
|
||||
|
||||
|
@ -138,13 +142,13 @@ Selective means to respect the inheritance setting in
|
|||
(const :tag "Inherit parent node attachments" t)
|
||||
(const :tag "Respect org-use-property-inheritance" selective)))
|
||||
|
||||
(defcustom org-attach-store-link-p nil
|
||||
(defcustom org-attach-store-link-p 'attached
|
||||
"Non-nil means store a link to a file when attaching it.
|
||||
When t, store the link to original file location.
|
||||
When `file', store link to the attached file location.
|
||||
When `attached', store attach: link to the attached file."
|
||||
:group 'org-attach
|
||||
:version "24.1"
|
||||
:package-version '(Org . "9.7")
|
||||
:type '(choice
|
||||
(const :tag "Don't store link" nil)
|
||||
(const :tag "Link to origin location" t)
|
||||
|
@ -297,67 +301,71 @@ ask the user instead, else remove without asking."
|
|||
"The dispatcher for attachment commands.
|
||||
Shows a list of commands and prompts for another key to execute a command."
|
||||
(interactive)
|
||||
(let ((dir (org-attach-dir nil 'no-fs-check))
|
||||
c marker)
|
||||
(let (c marker)
|
||||
(when (eq major-mode 'org-agenda-mode)
|
||||
(setq marker (or (get-text-property (point) 'org-hd-marker)
|
||||
(get-text-property (point) 'org-marker)))
|
||||
(unless marker
|
||||
(error "No item in current line")))
|
||||
(org-with-point-at marker
|
||||
(if (and (featurep 'org-inlinetask)
|
||||
(not (org-inlinetask-in-task-p)))
|
||||
(org-with-limited-levels
|
||||
(org-back-to-heading-or-point-min t))
|
||||
(let ((dir (org-attach-dir nil 'no-fs-check)))
|
||||
(if (and (featurep 'org-inlinetask)
|
||||
(org-inlinetask-in-task-p))
|
||||
(org-inlinetask-goto-beginning)
|
||||
(org-back-to-heading-or-point-min t)))
|
||||
(save-excursion
|
||||
(save-window-excursion
|
||||
(unless org-attach-expert
|
||||
(org-switch-to-buffer-other-window "*Org Attach*")
|
||||
(erase-buffer)
|
||||
(setq cursor-type nil
|
||||
header-line-format "Use C-v, M-v, C-n or C-p to navigate.")
|
||||
(insert
|
||||
(concat "Attachment folder:\n"
|
||||
(or dir
|
||||
"Can't find an existing attachment-folder")
|
||||
(unless (and dir (file-directory-p dir))
|
||||
"\n(Not yet created)")
|
||||
"\n\n"
|
||||
(format "Select an Attachment Command:\n\n%s"
|
||||
(mapconcat
|
||||
(lambda (entry)
|
||||
(pcase entry
|
||||
(`((,key . ,_) ,_ ,docstring)
|
||||
(format "%c %s"
|
||||
key
|
||||
(replace-regexp-in-string "\n\\([\t ]*\\)"
|
||||
" "
|
||||
docstring
|
||||
nil nil 1)))
|
||||
(_
|
||||
(user-error
|
||||
"Invalid `org-attach-commands' item: %S"
|
||||
entry))))
|
||||
org-attach-commands
|
||||
"\n")))))
|
||||
(org-fit-window-to-buffer (get-buffer-window "*Org Attach*"))
|
||||
(let ((msg (format "Select command: [%s]"
|
||||
(concat (mapcar #'caar org-attach-commands)))))
|
||||
(message msg)
|
||||
(while (and (setq c (read-char-exclusive))
|
||||
(memq c '(?\C-n ?\C-p ?\C-v ?\M-v)))
|
||||
(org-scroll c t)))
|
||||
(and (get-buffer "*Org Attach*") (kill-buffer "*Org Attach*"))))
|
||||
(let ((command (cl-some (lambda (entry)
|
||||
(and (memq c (nth 0 entry)) (nth 1 entry)))
|
||||
org-attach-commands)))
|
||||
(if (commandp command)
|
||||
(command-execute command)
|
||||
(error "No such attachment command: %c" c))))))
|
||||
(not (org-inlinetask-in-task-p)))
|
||||
(org-with-limited-levels
|
||||
(org-back-to-heading-or-point-min t))
|
||||
(if (and (featurep 'org-inlinetask)
|
||||
(org-inlinetask-in-task-p))
|
||||
(org-inlinetask-goto-beginning)
|
||||
(org-back-to-heading-or-point-min t)))
|
||||
(save-excursion
|
||||
(save-window-excursion
|
||||
(unless org-attach-expert
|
||||
(switch-to-buffer-other-window "*Org Attach*")
|
||||
(erase-buffer)
|
||||
(setq cursor-type nil
|
||||
header-line-format "Use C-v, M-v, C-n or C-p to navigate.")
|
||||
(insert
|
||||
(concat "Attachment folder:\n"
|
||||
(or dir
|
||||
"Can't find an existing attachment-folder")
|
||||
(unless (and dir (file-directory-p dir))
|
||||
"\n(Not yet created)")
|
||||
"\n\n"
|
||||
(format "Select an Attachment Command:\n\n%s"
|
||||
(mapconcat
|
||||
(lambda (entry)
|
||||
(pcase entry
|
||||
(`((,key . ,_) ,_ ,docstring)
|
||||
(format "%c %s"
|
||||
key
|
||||
(replace-regexp-in-string "\n\\([\t ]*\\)"
|
||||
" "
|
||||
docstring
|
||||
nil nil 1)))
|
||||
(_
|
||||
(user-error
|
||||
"Invalid `org-attach-commands' item: %S"
|
||||
entry))))
|
||||
org-attach-commands
|
||||
"\n"))))
|
||||
(goto-char (point-min)))
|
||||
(org-fit-window-to-buffer (get-buffer-window "*Org Attach*"))
|
||||
(unwind-protect
|
||||
(let ((msg (format "Select command: [%s]"
|
||||
(concat (mapcar #'caar org-attach-commands)))))
|
||||
(message msg)
|
||||
(while (and (setq c (read-char-exclusive))
|
||||
(memq c '(?\C-n ?\C-p ?\C-v ?\M-v)))
|
||||
(org-scroll c t)))
|
||||
(when-let ((window (get-buffer-window "*Org Attach*" t)))
|
||||
(quit-window 'kill window))
|
||||
(and (get-buffer "*Org Attach*") (kill-buffer "*Org Attach*")))))
|
||||
(let ((command (cl-some (lambda (entry)
|
||||
(and (memq c (nth 0 entry)) (nth 1 entry)))
|
||||
org-attach-commands)))
|
||||
(if (commandp command)
|
||||
(command-execute command)
|
||||
(error "No such attachment command: %c" c)))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-attach-dir (&optional create-if-not-exists-p no-fs-check)
|
||||
|
@ -432,17 +440,26 @@ ignoring nils. If EXISTING is non-nil, then return the first path
|
|||
found in the filesystem. Otherwise return the first non-nil value."
|
||||
(let ((fun-list org-attach-id-to-path-function-list)
|
||||
(base-dir (expand-file-name org-attach-id-dir))
|
||||
(default-base-dir (expand-file-name "data/"))
|
||||
preferred first)
|
||||
(while (and fun-list
|
||||
(not preferred))
|
||||
(let* ((name (funcall (car fun-list) id))
|
||||
(candidate (and name (expand-file-name name base-dir))))
|
||||
(candidate (and name (expand-file-name name base-dir)))
|
||||
;; Try the default value `org-attach-id-dir' as a fallback.
|
||||
(candidate2 (and name (not (equal base-dir default-base-dir))
|
||||
(expand-file-name name default-base-dir))))
|
||||
(setq fun-list (cdr fun-list))
|
||||
(when candidate
|
||||
(if (or (not existing) (file-directory-p candidate))
|
||||
(setq preferred candidate)
|
||||
(unless first
|
||||
(setq first candidate))))))
|
||||
(setq first candidate)))
|
||||
(when (and existing
|
||||
candidate2
|
||||
(not (file-directory-p candidate))
|
||||
(file-directory-p candidate2))
|
||||
(setq preferred candidate2)))))
|
||||
(or preferred first)))
|
||||
|
||||
(defun org-attach-check-absolute-path (dir)
|
||||
|
@ -512,9 +529,13 @@ DIR-property exists (that is different from the unset one)."
|
|||
(defun org-attach-tag (&optional off)
|
||||
"Turn the autotag on or (if OFF is set) off."
|
||||
(when org-attach-auto-tag
|
||||
(save-excursion
|
||||
(org-back-to-heading t)
|
||||
(org-toggle-tag org-attach-auto-tag (if off 'off 'on)))))
|
||||
;; FIXME: There is currently no way to set #+FILETAGS
|
||||
;; programatically. Do nothing when before first heading
|
||||
;; (attaching to file) to avoid blocking error.
|
||||
(unless (org-before-first-heading-p)
|
||||
(save-excursion
|
||||
(org-back-to-heading t)
|
||||
(org-toggle-tag org-attach-auto-tag (if off 'off 'on))))))
|
||||
|
||||
(defun org-attach-untag ()
|
||||
"Turn the autotag off."
|
||||
|
@ -573,7 +594,7 @@ METHOD may be `cp', `mv', `ln', `lns' or `url' default taken from
|
|||
((eq method 'url)
|
||||
(if (org--should-fetch-remote-resource-p file)
|
||||
(url-copy-file file attach-file)
|
||||
(error "The remote resource %S is considered unsafe, and will not be downloaded."
|
||||
(error "The remote resource %S is considered unsafe, and will not be downloaded"
|
||||
file))))
|
||||
(run-hook-with-args 'org-attach-after-change-hook attach-dir)
|
||||
(org-attach-tag)
|
||||
|
@ -736,20 +757,20 @@ It is meant to be added to `org-export-before-parsing-hook'."
|
|||
(save-excursion
|
||||
(while (re-search-forward "attachment:" nil t)
|
||||
(let ((link (org-element-context)))
|
||||
(when (and (eq 'link (org-element-type link))
|
||||
(when (and (org-element-type-p link 'link)
|
||||
(string-equal "attachment"
|
||||
(org-element-property :type link)))
|
||||
(let* ((description (and (org-element-property :contents-begin link)
|
||||
(let* ((description (and (org-element-contents-begin link)
|
||||
(buffer-substring-no-properties
|
||||
(org-element-property :contents-begin link)
|
||||
(org-element-property :contents-end link))))
|
||||
(org-element-contents-begin link)
|
||||
(org-element-contents-end link))))
|
||||
(file (org-element-property :path link))
|
||||
(new-link (org-link-make-string
|
||||
(concat "file:" (org-attach-expand file))
|
||||
description)))
|
||||
(goto-char (org-element-property :end link))
|
||||
(goto-char (org-element-end link))
|
||||
(skip-chars-backward " \t")
|
||||
(delete-region (org-element-property :begin link) (point))
|
||||
(delete-region (org-element-begin link) (point))
|
||||
(insert new-link)))))))
|
||||
|
||||
(defun org-attach-follow (file arg)
|
||||
|
|
|
@ -58,11 +58,13 @@
|
|||
(declare-function org-at-table-p "org-table" (&optional table-type))
|
||||
(declare-function org-clock-update-mode-line "org-clock" (&optional refresh))
|
||||
(declare-function org-datetree-find-date-create "org-datetree" (date &optional keep-restriction))
|
||||
(declare-function org-datetree-find-month-create (d &optional keep-restriction))
|
||||
(declare-function org-datetree-find-month-create "org-datetree" (d &optional keep-restriction))
|
||||
(declare-function org-decrypt-entry "org-crypt" ())
|
||||
(declare-function org-element-at-point "org-element" (&optional pom cached-only))
|
||||
(declare-function org-element-lineage "org-element" (datum &optional types with-self))
|
||||
(declare-function org-element-property "org-element" (property element))
|
||||
(declare-function org-element-lineage "org-element-ast" (datum &optional types with-self))
|
||||
(declare-function org-element-property "org-element-ast" (property node))
|
||||
(declare-function org-element-contents-end "org-element" (node))
|
||||
(declare-function org-element-post-affiliated "org-element" (node))
|
||||
(declare-function org-encrypt-entry "org-crypt" ())
|
||||
(declare-function org-insert-link "ol" (&optional complete-file link-location default-description))
|
||||
(declare-function org-link-make-string "ol" (link &optional description))
|
||||
|
@ -220,6 +222,9 @@ target Specification of where the captured item should be placed.
|
|||
(clock)
|
||||
File to the entry that is currently being clocked
|
||||
|
||||
(here)
|
||||
The position of point
|
||||
|
||||
(function function-finding-location)
|
||||
Most general way: write your own function which both visits
|
||||
the file and moves point to the right location
|
||||
|
@ -366,6 +371,10 @@ be replaced with content and expanded:
|
|||
%^{prompt} Prompt the user for a string and replace this sequence with it.
|
||||
A default value and a completion table can be specified like this:
|
||||
%^{prompt|default|completion2|completion3|...}.
|
||||
%^{prompt}X where X is one of g, G, t, T, u, U, C, or L.
|
||||
Same as %^X (see above), but also supply custom
|
||||
prompt/completions. Default value and completions as in
|
||||
%^{prompt|default|...}X are allowed.
|
||||
%? After completing the template, position cursor here.
|
||||
%\\1 ... %\\N Insert the text entered at the nth %^{prompt}, where N
|
||||
is a number, starting from 1.
|
||||
|
@ -393,7 +402,7 @@ calendar | %:type %:date
|
|||
When you need to insert a literal percent sign in the template,
|
||||
you can escape ambiguous cases with a backward slash, e.g., \\%i."
|
||||
:group 'org-capture
|
||||
:package-version '(Org . "9.6")
|
||||
:package-version '(Org . "9.7")
|
||||
:set (lambda (s v) (set-default-toplevel-value s (org-capture-upgrade-templates v)))
|
||||
:type
|
||||
(let ((file-variants '(choice :tag "Filename "
|
||||
|
@ -496,12 +505,6 @@ The capture buffer is current and still narrowed."
|
|||
:version "24.1"
|
||||
:type 'hook)
|
||||
|
||||
(defcustom org-capture-bookmark t
|
||||
"When non-nil, add bookmark pointing at the last stored position when capturing."
|
||||
:group 'org-capture
|
||||
:version "24.3"
|
||||
:type 'boolean)
|
||||
|
||||
;;; The property list for keeping information about the capture process
|
||||
|
||||
(defvar org-capture-plist nil
|
||||
|
@ -579,7 +582,9 @@ this template to be accessible only from `message-mode' buffers,
|
|||
use this:
|
||||
|
||||
(setq org-capture-templates-contexts
|
||||
\\='((\"c\" ((in-mode . \"message-mode\")))))
|
||||
\\='((\"c\" ((in-mode . \"message-mode\")))
|
||||
(\"d\" (my-context-function
|
||||
(in-mode . \"org-mode\")))))
|
||||
|
||||
Here are the available contexts definitions:
|
||||
|
||||
|
@ -889,10 +894,16 @@ captured item after finalizing."
|
|||
(goto-char (+ size pos))
|
||||
(goto-char (if (< ipt pos) (+ size pos) pos))))))
|
||||
|
||||
;; Kill the target buffer if that is desired
|
||||
(when (and base-buffer new-buffer kill-buffer)
|
||||
(with-current-buffer base-buffer (save-buffer))
|
||||
(kill-buffer base-buffer))
|
||||
(if (and base-buffer org-note-abort new-buffer)
|
||||
;; Unconditionally kill the new buffer when capture is
|
||||
;; aborted.
|
||||
(with-current-buffer base-buffer
|
||||
(set-buffer-modified-p nil)
|
||||
(kill-buffer))
|
||||
;; Kill the target buffer if that is desired
|
||||
(when (and base-buffer new-buffer kill-buffer)
|
||||
(with-current-buffer base-buffer (save-buffer))
|
||||
(kill-buffer base-buffer)))
|
||||
|
||||
;; Restore the window configuration before capture
|
||||
(set-window-configuration return-wconf))
|
||||
|
@ -985,14 +996,15 @@ Store them in the capture property list."
|
|||
(let ((target-entry-p t))
|
||||
(save-excursion
|
||||
(pcase (or target (org-capture-get :target))
|
||||
(`here
|
||||
((or `here
|
||||
`(here))
|
||||
(org-capture-put :exact-position (point) :insert-here t))
|
||||
(`(file ,path)
|
||||
(set-buffer (org-capture-target-buffer path))
|
||||
(org-capture-put-target-region-and-position)
|
||||
(widen)
|
||||
(setq target-entry-p nil))
|
||||
(`(id ,id)
|
||||
(`(id ,(and id (or (pred stringp) (pred symbolp))))
|
||||
(pcase (org-id-find id)
|
||||
(`(,path . ,position)
|
||||
(set-buffer (org-capture-target-buffer path))
|
||||
|
@ -1000,7 +1012,7 @@ Store them in the capture property list."
|
|||
(org-capture-put-target-region-and-position)
|
||||
(goto-char position))
|
||||
(_ (error "Cannot find target ID \"%s\"" id))))
|
||||
(`(file+headline ,path ,headline)
|
||||
(`(file+headline ,path ,(and headline (pred stringp)))
|
||||
(set-buffer (org-capture-target-buffer path))
|
||||
;; Org expects the target file to be in Org mode, otherwise
|
||||
;; it throws an error. However, the default notes files
|
||||
|
@ -1017,12 +1029,12 @@ Store them in the capture property list."
|
|||
(if (re-search-forward (format org-complex-heading-regexp-format
|
||||
(regexp-quote headline))
|
||||
nil t)
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(goto-char (point-max))
|
||||
(unless (bolp) (insert "\n"))
|
||||
(insert "* " headline "\n")
|
||||
(beginning-of-line 0)))
|
||||
(`(file+olp ,path . ,outline-path)
|
||||
(forward-line -1)))
|
||||
(`(file+olp ,path . ,(and outline-path (guard outline-path)))
|
||||
(let ((m (org-find-olp (cons (org-capture-expand-file path)
|
||||
outline-path))))
|
||||
(set-buffer (marker-buffer m))
|
||||
|
@ -1030,7 +1042,7 @@ Store them in the capture property list."
|
|||
(widen)
|
||||
(goto-char m)
|
||||
(set-marker m nil)))
|
||||
(`(file+regexp ,path ,regexp)
|
||||
(`(file+regexp ,path ,(and regexp (pred stringp)))
|
||||
(set-buffer (org-capture-target-buffer path))
|
||||
(org-capture-put-target-region-and-position)
|
||||
(widen)
|
||||
|
@ -1098,7 +1110,7 @@ Store them in the capture property list."
|
|||
;; the following is the keep-restriction argument for
|
||||
;; org-datetree-find-date-create
|
||||
(when outline-path 'subtree-at-point))))
|
||||
(`(file+function ,path ,function)
|
||||
(`(file+function ,path ,(and function (pred functionp)))
|
||||
(set-buffer (org-capture-target-buffer path))
|
||||
(org-capture-put-target-region-and-position)
|
||||
(widen)
|
||||
|
@ -1106,7 +1118,7 @@ Store them in the capture property list."
|
|||
(org-capture-put :exact-position (point))
|
||||
(setq target-entry-p
|
||||
(and (derived-mode-p 'org-mode) (org-at-heading-p))))
|
||||
(`(function ,fun)
|
||||
(`(function ,(and fun (pred functionp)))
|
||||
(funcall fun)
|
||||
(org-capture-put :exact-position (point))
|
||||
(setq target-entry-p
|
||||
|
@ -1162,9 +1174,9 @@ When INHIBIT-WCONF-STORE is non-nil, don't store the window configuration, as it
|
|||
may have been stored before."
|
||||
(unless inhibit-wconf-store
|
||||
(org-capture-put :return-to-wconf (current-window-configuration)))
|
||||
(delete-other-windows)
|
||||
(org-switch-to-buffer-other-window
|
||||
(org-capture-get-indirect-buffer (org-capture-get :buffer) "CAPTURE"))
|
||||
(pop-to-buffer
|
||||
(org-capture-get-indirect-buffer (org-capture-get :buffer) "CAPTURE")
|
||||
'(org-display-buffer-split))
|
||||
(widen)
|
||||
(org-fold-show-all)
|
||||
(goto-char (org-capture-get :pos))
|
||||
|
@ -1262,7 +1274,7 @@ may have been stored before."
|
|||
(catch :found
|
||||
(while (re-search-forward item-regexp end t)
|
||||
(when (setq item (org-element-lineage
|
||||
(org-element-at-point) '(plain-list) t))
|
||||
(org-element-at-point) 'plain-list t))
|
||||
(goto-char (org-element-property (if prepend? :post-affiliated
|
||||
:contents-end)
|
||||
item))
|
||||
|
@ -1304,7 +1316,7 @@ may have been stored before."
|
|||
(point-marker))))
|
||||
(when item
|
||||
(let ((i (save-excursion
|
||||
(goto-char (org-element-property :post-affiliated item))
|
||||
(goto-char (org-element-post-affiliated item))
|
||||
(org-current-text-indentation))))
|
||||
(save-excursion
|
||||
(goto-char beg)
|
||||
|
@ -1367,13 +1379,13 @@ may have been stored before."
|
|||
;; Narrow to the table, possibly creating one if necessary.
|
||||
(catch :found
|
||||
(while (re-search-forward org-table-dataline-regexp end t)
|
||||
(pcase (org-element-lineage (org-element-at-point) '(table) t)
|
||||
(pcase (org-element-lineage (org-element-at-point) 'table t)
|
||||
(`nil nil)
|
||||
((pred (lambda (e) (eq 'table.el (org-element-property :type e))))
|
||||
nil)
|
||||
(table
|
||||
(goto-char (org-element-property :contents-end table))
|
||||
(narrow-to-region (org-element-property :post-affiliated table)
|
||||
(goto-char (org-element-contents-end table))
|
||||
(narrow-to-region (org-element-post-affiliated table)
|
||||
(point))
|
||||
(throw :found t))))
|
||||
;; No table found. Create it with an empty header.
|
||||
|
@ -1403,7 +1415,7 @@ may have been stored before."
|
|||
(goto-char (point-min))
|
||||
(cond
|
||||
((not (re-search-forward org-table-hline-regexp nil t)))
|
||||
((re-search-forward org-table-dataline-regexp nil t) (beginning-of-line))
|
||||
((re-search-forward org-table-dataline-regexp nil t) (forward-line 0))
|
||||
(t (goto-char (org-table-end)))))
|
||||
(t
|
||||
(goto-char (org-table-end))))
|
||||
|
@ -1492,10 +1504,15 @@ Of course, if exact position has been required, just put it there."
|
|||
(point))))))
|
||||
(with-current-buffer (buffer-base-buffer (current-buffer))
|
||||
(org-with-point-at pos
|
||||
(when org-capture-bookmark
|
||||
;; FIXME: `org-capture-bookmark' is obsolete. To be removed
|
||||
;; in future Org releases.
|
||||
(when (with-no-warnings org-capture-bookmark)
|
||||
(let ((bookmark (plist-get org-bookmark-names-plist :last-capture)))
|
||||
(when bookmark (with-demoted-errors "Bookmark set error: %S"
|
||||
(bookmark-set bookmark)))))
|
||||
(when bookmark
|
||||
(condition-case err
|
||||
(bookmark-set bookmark)
|
||||
(error
|
||||
(message "Bookmark set error: %S" err))))))
|
||||
(move-marker org-capture-last-stored-marker (point))))))
|
||||
|
||||
(defun org-capture-narrow (beg end)
|
||||
|
@ -1658,12 +1675,12 @@ Expansion occurs in a temporary Org mode buffer."
|
|||
(org-no-properties org-clock-heading)
|
||||
""))
|
||||
(v-K (if (marker-buffer org-clock-marker)
|
||||
(org-link-make-string
|
||||
(format "%s::*%s"
|
||||
(buffer-file-name (marker-buffer org-clock-marker))
|
||||
v-k)
|
||||
v-k)
|
||||
""))
|
||||
(let ((original-link-plist org-store-link-plist)
|
||||
(clocked-task-link (org-with-point-at org-clock-marker
|
||||
(org-store-link nil nil))))
|
||||
(setq org-store-link-plist original-link-plist)
|
||||
clocked-task-link)
|
||||
""))
|
||||
(v-f (or (org-capture-get :original-file-nondirectory) ""))
|
||||
(v-F (or (org-capture-get :original-file) ""))
|
||||
(org-capture--clipboards
|
||||
|
@ -1680,7 +1697,7 @@ Expansion occurs in a temporary Org mode buffer."
|
|||
(message "no template") (ding)
|
||||
(sit-for 1))
|
||||
(save-window-excursion
|
||||
(org-switch-to-buffer-other-window (get-buffer-create "*Capture*"))
|
||||
(switch-to-buffer-other-window (get-buffer-create "*Capture*"))
|
||||
(erase-buffer)
|
||||
(setq buffer-file-name nil)
|
||||
(setq mark-active nil)
|
||||
|
@ -1852,7 +1869,7 @@ Expansion occurs in a temporary Org mode buffer."
|
|||
(let* ((upcase? (equal (upcase key) key))
|
||||
(org-end-time-was-given nil)
|
||||
(time (org-read-date upcase? t nil prompt)))
|
||||
(org-insert-time-stamp
|
||||
(org-insert-timestamp
|
||||
time (or org-time-was-given upcase?)
|
||||
(member key '("u" "U"))
|
||||
nil nil (list org-end-time-was-given))))
|
||||
|
|
|
@ -36,9 +36,11 @@
|
|||
|
||||
(declare-function calendar-iso-to-absolute "cal-iso" (date))
|
||||
(declare-function notifications-notify "notifications" (&rest params))
|
||||
(declare-function org-element-property "org-element" (property element))
|
||||
(declare-function org-element-type "org-element" (element))
|
||||
(declare-function org-element--cache-active-p "org-element" ())
|
||||
(declare-function org-element-property "org-element-ast" (property node))
|
||||
(declare-function org-element-contents-end "org-element" (node))
|
||||
(declare-function org-element-end "org-element" (node))
|
||||
(declare-function org-element-type "org-element-ast" (node &optional anonymous))
|
||||
(declare-function org-element-type-p "org-element-ast" (node types))
|
||||
(defvar org-element-use-cache)
|
||||
(declare-function org-inlinetask-at-task-p "org-inlinetask" ())
|
||||
(declare-function org-inlinetask-goto-beginning "org-inlinetask" ())
|
||||
|
@ -51,6 +53,9 @@
|
|||
(declare-function org-dynamic-block-define "org" (type func))
|
||||
(declare-function w32-notification-notify "w32fns.c" (&rest params))
|
||||
(declare-function w32-notification-close "w32fns.c" (&rest params))
|
||||
(declare-function dbus-list-activatable-names "dbus" (&optional bus))
|
||||
(declare-function dbus-call-method "dbus" (bus service path interface method &rest args))
|
||||
(declare-function dbus-get-property "dbus" (bus service path interface property))
|
||||
(declare-function haiku-notifications-notify "haikuselect.c")
|
||||
(declare-function android-notifications-notify "androidselect.c")
|
||||
|
||||
|
@ -127,7 +132,7 @@ clocking out."
|
|||
"Rounding minutes when clocking in or out.
|
||||
The default value is 0 so that no rounding is done.
|
||||
When set to a non-integer value, use the car of
|
||||
`org-time-stamp-rounding-minutes', like for setting a time-stamp.
|
||||
`org-timestamp-rounding-minutes', like for setting a timestamp.
|
||||
|
||||
E.g. if `org-clock-rounding-minutes' is set to 5, time is 14:47
|
||||
and you clock in: then the clock starts at 14:45. If you clock
|
||||
|
@ -346,14 +351,16 @@ For more information, see `org-clocktable-write-default'."
|
|||
:version "24.1"
|
||||
:type 'function)
|
||||
|
||||
;; FIXME: translate es and nl last string "Clock summary at"
|
||||
(defcustom org-clock-clocktable-language-setup
|
||||
'(("en" "File" "L" "Timestamp" "Headline" "Time" "ALL" "Total time" "File time" "Clock summary at")
|
||||
("es" "Archivo" "N" "Fecha y hora" "Tarea" "Tiempo" "TODO" "Tiempo total" "Tiempo archivo" "Clock summary at")
|
||||
("fr" "Fichier" "N" "Horodatage" "En-tête" "Durée" "TOUT" "Durée totale" "Durée fichier" "Horodatage sommaire à")
|
||||
("nl" "Bestand" "N" "Tijdstip" "Hoofding" "Duur" "ALLES" "Totale duur" "Bestandstijd" "Clock summary at")
|
||||
("de" "Datei" "E" "Zeitstempel" "Kopfzeile" "Dauer" "GESAMT"
|
||||
"Gesamtdauer" "Dateizeit" "Erstellt am"))
|
||||
'(("en" "File" "L" "Timestamp" "Headline" "Time" "ALL" "Total time" "File time" "Clock summary at")
|
||||
("de" "Datei" "E" "Zeitstempel" "Kopfzeile" "Dauer" "GESAMT" "Gesamtdauer" "Dateizeit" "Erstellt am")
|
||||
("es" "Archivo" "N" "Fecha y hora" "Tarea" "Duración" "TODO" "Duración total" "Tiempo archivo" "Generado el")
|
||||
("fr" "Fichier" "N" "Horodatage" "En-tête" "Durée" "TOUT" "Durée totale" "Durée fichier" "Horodatage sommaire à")
|
||||
("nl" "Bestand" "N" "Tijdstip" "Rubriek" "Duur" "ALLES" "Totale duur" "Bestandstijd" "Klok overzicht op")
|
||||
("nn" "Fil" "N" "Tidspunkt" "Overskrift" "Tid" "ALLE" "Total tid" "Filtid" "Tidsoversyn")
|
||||
("pl" "Plik" "P" "Data i godzina" "Nagłówek" "Czas" "WSZYSTKO" "Czas całkowity" "Czas pliku" "Poddumowanie zegara na")
|
||||
("pt-BR" "Arquivo" "N" "Data e hora" "Título" "Hora" "TODOS" "Hora total" "Hora do arquivo" "Resumo das horas em")
|
||||
("sk" "Súbor" "L" "Časová značka" "Záhlavie" "Čas" "VŠETKO" "Celkový čas" "Čas súboru" "Časový súhrn pre"))
|
||||
"Terms used in clocktable, translated to different languages."
|
||||
:group 'org-clocktable
|
||||
:version "24.1"
|
||||
|
@ -413,8 +420,8 @@ play with them."
|
|||
:type 'string)
|
||||
|
||||
(defcustom org-clock-clocked-in-display 'mode-line
|
||||
"When clocked in for a task, Org can display the current
|
||||
task and accumulated time in the mode line and/or frame title.
|
||||
"Where to display clocked in task and accumulated time when clocked in.
|
||||
|
||||
Allowed values are:
|
||||
|
||||
both displays in both mode line and frame title
|
||||
|
@ -440,7 +447,9 @@ This uses the same format as `frame-title-format', which see."
|
|||
:group 'org-clock
|
||||
:type 'sexp)
|
||||
|
||||
(defcustom org-clock-x11idle-program-name "x11idle"
|
||||
(defcustom org-clock-x11idle-program-name
|
||||
(if (executable-find "xprintidle")
|
||||
"xprintidle" "x11idle")
|
||||
"Name of the program which prints X11 idle time in milliseconds.
|
||||
|
||||
you can do \"~$ sudo apt-get install xprintidle\" if you are using
|
||||
|
@ -449,8 +458,7 @@ a Debian-based distribution.
|
|||
Alternatively, can find x11idle.c in
|
||||
https://orgmode.org/worg/code/scripts/x11idle.c"
|
||||
:group 'org-clock
|
||||
:version "24.4"
|
||||
:package-version '(Org . "8.0")
|
||||
:package-version '(Org . "9.7")
|
||||
:type 'string)
|
||||
|
||||
(defcustom org-clock-goto-before-context 2
|
||||
|
@ -508,7 +516,11 @@ to add an effort property.")
|
|||
(defvar org-clock-in-hook nil
|
||||
"Hook run when starting the clock.")
|
||||
(defvar org-clock-out-hook nil
|
||||
"Hook run when stopping the current clock.")
|
||||
"Hook run when stopping the current clock.
|
||||
The point is at the current clock line when the hook is executed.
|
||||
|
||||
The hook functions can access `org-clock-out-removed-last-clock' to
|
||||
check whether the latest CLOCK line has been cleared.")
|
||||
|
||||
(defvar org-clock-cancel-hook nil
|
||||
"Hook run when canceling the current clock.")
|
||||
|
@ -562,6 +574,10 @@ of a different task.")
|
|||
Assume S in the English term to translate. Return S as-is if it
|
||||
cannot be translated."
|
||||
(or (nth (pcase s
|
||||
;; "L" stands for "Level"
|
||||
;; "ALL" stands for a line summarizing clock data across
|
||||
;; all the files, when the clocktable includes multiple
|
||||
;; files.
|
||||
("File" 1) ("L" 2) ("Timestamp" 3) ("Headline" 4) ("Time" 5)
|
||||
("ALL" 6) ("Total time" 7) ("File time" 8) ("Clock summary at" 9))
|
||||
(assoc-string language org-clock-clocktable-language-setup t))
|
||||
|
@ -576,6 +592,7 @@ cannot be translated."
|
|||
(org-no-properties (org-get-heading t t t t))))))
|
||||
|
||||
(defun org-clock-menu ()
|
||||
"Pop up org-clock menu."
|
||||
(interactive)
|
||||
(popup-menu
|
||||
'("Clock"
|
||||
|
@ -585,7 +602,12 @@ cannot be translated."
|
|||
["Switch task" (lambda () (interactive) (org-clock-in '(4))) :active t :keys "C-u C-c C-x C-i"])))
|
||||
|
||||
(defun org-clock-history-push (&optional pos buffer)
|
||||
"Push a marker to the clock history."
|
||||
"Push point marker to the clock history.
|
||||
When POS is provided, use it as marker point.
|
||||
When BUFFER and POS are provided, use marker at POS in base buffer of
|
||||
BUFFER."
|
||||
;; When buffer is provided, POS must be provided.
|
||||
(cl-assert (or (not buffer) pos))
|
||||
(setq org-clock-history-length (max 1 org-clock-history-length))
|
||||
(let ((m (move-marker (make-marker)
|
||||
(or pos (point)) (org-base-buffer
|
||||
|
@ -605,7 +627,10 @@ cannot be translated."
|
|||
(push m org-clock-history)))
|
||||
|
||||
(defun org-clock-save-markers-for-cut-and-paste (beg end)
|
||||
"Save relative positions of markers in region."
|
||||
"Save relative positions of markers in region BEG..END.
|
||||
Save `org-clock-marker', `org-clock-hd-marker',
|
||||
`org-clock-default-task', `org-clock-interrupted-task', and the
|
||||
markers in `org-clock-history'."
|
||||
(org-check-and-save-marker org-clock-marker beg end)
|
||||
(org-check-and-save-marker org-clock-hd-marker beg end)
|
||||
(org-check-and-save-marker org-clock-default-task beg end)
|
||||
|
@ -631,6 +656,7 @@ cannot be translated."
|
|||
|
||||
(defun org-clock-select-task (&optional prompt)
|
||||
"Select a task that was recently associated with clocking.
|
||||
PROMPT is the prompt text to be used, as a string.
|
||||
Return marker position of the selected task. Raise an error if
|
||||
there is no recent clock to choose from."
|
||||
(let (och chl sel-list rpl (i 0) s)
|
||||
|
@ -641,7 +667,7 @@ there is no recent clock to choose from."
|
|||
(if (zerop chl)
|
||||
(user-error "No recent clock")
|
||||
(save-window-excursion
|
||||
(org-switch-to-buffer-other-window
|
||||
(switch-to-buffer-other-window
|
||||
(get-buffer-create "*Clock Task Select*"))
|
||||
(erase-buffer)
|
||||
(when (marker-buffer org-clock-default-task)
|
||||
|
@ -671,8 +697,11 @@ there is no recent clock to choose from."
|
|||
;; `fit-window-to-buffer'
|
||||
(fit-window-to-buffer nil nil (if (< chl 10) chl (+ 5 chl)))
|
||||
(message (or prompt "Select task for clocking:"))
|
||||
(setq cursor-type nil rpl (read-char-exclusive))
|
||||
(kill-buffer)
|
||||
(unwind-protect (setq cursor-type nil rpl (read-char-exclusive))
|
||||
(when-let ((window (get-buffer-window "*Clock Task Select*" t)))
|
||||
(quit-window 'kill window))
|
||||
(when (get-buffer "*Clock Task Select*")
|
||||
(kill-buffer "*Clock Task Select*")))
|
||||
(cond
|
||||
((eq rpl ?q) nil)
|
||||
((eq rpl ?x) nil)
|
||||
|
@ -781,6 +810,7 @@ previous clocking intervals."
|
|||
60)))
|
||||
(+ currently-clocked-time (or org-clock-total-time 0))))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-clock-modify-effort-estimate (&optional value)
|
||||
"Add to or set the effort estimate of the item currently being clocked.
|
||||
VALUE can be a number of minutes, or a string with format hh:mm or mm.
|
||||
|
@ -911,7 +941,7 @@ If CLOCK-SOUND is non-nil, it overrides `org-clock-sound'."
|
|||
(if (executable-find "aplay")
|
||||
(start-process "org-clock-play-notification" nil
|
||||
"aplay" file)
|
||||
(condition-case nil
|
||||
(condition-case-unless-debug nil
|
||||
(play-sound-file file)
|
||||
(error (beep t) (beep t))))))))))
|
||||
|
||||
|
@ -928,9 +958,11 @@ If CLOCK-SOUND is non-nil, it overrides `org-clock-sound'."
|
|||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward org-clock-re nil t)
|
||||
(push (cons (copy-marker (match-end 1) t)
|
||||
(org-time-string-to-time (match-string 1)))
|
||||
clocks))))
|
||||
(when (save-match-data
|
||||
(org-element-type-p (org-element-at-point) 'clock))
|
||||
(push (cons (copy-marker (match-end 1) t)
|
||||
(org-time-string-to-time (match-string 1)))
|
||||
clocks)))))
|
||||
clocks))
|
||||
|
||||
(defsubst org-is-active-clock (clock)
|
||||
|
@ -944,7 +976,7 @@ If CLOCK-SOUND is non-nil, it overrides `org-clock-sound'."
|
|||
`(with-current-buffer (marker-buffer (car ,clock))
|
||||
(org-with-wide-buffer
|
||||
(goto-char (car ,clock))
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
,@forms)))
|
||||
|
||||
(defmacro org-with-clock (clock &rest forms)
|
||||
|
@ -1050,8 +1082,8 @@ CLOCK is a cons cell of the form (MARKER START-TIME)."
|
|||
(catch 'exit
|
||||
(while (re-search-backward drawer-re beg t)
|
||||
(let ((element (org-element-at-point)))
|
||||
(when (eq (org-element-type element) 'drawer)
|
||||
(when (> (org-element-property :end element) (car clock))
|
||||
(when (org-element-type-p element 'drawer)
|
||||
(when (> (org-element-end element) (car clock))
|
||||
(org-fold-hide-drawer-toggle 'off nil element))
|
||||
(throw 'exit nil)))))))))))
|
||||
|
||||
|
@ -1226,6 +1258,27 @@ If `only-dangling-p' is non-nil, only ask to resolve dangling
|
|||
"Return the current X11 idle time in seconds."
|
||||
(/ (string-to-number (shell-command-to-string org-clock-x11idle-program-name)) 1000))
|
||||
|
||||
(defvar org-logind-dbus-session-path
|
||||
(when (and (boundp 'dbus-runtime-version)
|
||||
(require 'dbus nil t)
|
||||
(member "org.freedesktop.login1" (dbus-list-activatable-names)))
|
||||
(ignore-errors
|
||||
(dbus-call-method
|
||||
:system "org.freedesktop.login1"
|
||||
"/org/freedesktop/login1"
|
||||
"org.freedesktop.login1.Manager"
|
||||
"GetSessionByPID" (emacs-pid))))
|
||||
"D-Bus session path for the elogind interface.")
|
||||
|
||||
(defun org-logind-user-idle-seconds ()
|
||||
"Return the number of idle seconds for the user according to logind."
|
||||
(- (float-time)
|
||||
(/ (dbus-get-property
|
||||
:system "org.freedesktop.login1"
|
||||
org-logind-dbus-session-path
|
||||
"org.freedesktop.login1.Session" "IdleSinceHint")
|
||||
1e6)))
|
||||
|
||||
(defun org-user-idle-seconds ()
|
||||
"Return the number of seconds the user has been idle for.
|
||||
This routine returns a floating point number."
|
||||
|
@ -1234,6 +1287,13 @@ This routine returns a floating point number."
|
|||
(org-mac-idle-seconds))
|
||||
((and (eq window-system 'x) org-x11idle-exists-p)
|
||||
(org-x11-idle-seconds))
|
||||
((and
|
||||
org-logind-dbus-session-path
|
||||
(dbus-get-property
|
||||
:system "org.freedesktop.login1"
|
||||
org-logind-dbus-session-path
|
||||
"org.freedesktop.login1.Session" "IdleHint"))
|
||||
(org-logind-user-idle-seconds))
|
||||
(t
|
||||
(org-emacs-idle-seconds))))
|
||||
|
||||
|
@ -1291,8 +1351,6 @@ time as the start time. See `org-clock-continuously' to make this
|
|||
the default behavior."
|
||||
(interactive "P")
|
||||
(setq org-clock-notification-was-shown nil)
|
||||
(unless org-element-use-cache
|
||||
(org-refresh-effort-properties))
|
||||
(catch 'abort
|
||||
(let ((interrupting (and (not org-clock-resolving-clocks-due-to-idleness)
|
||||
(org-clocking-p)))
|
||||
|
@ -1370,8 +1428,8 @@ the default behavior."
|
|||
(when newstate (org-todo newstate))))
|
||||
((and org-clock-in-switch-to-state
|
||||
(not (looking-at (concat org-outline-regexp "[ \t]*"
|
||||
org-clock-in-switch-to-state
|
||||
"\\>"))))
|
||||
org-clock-in-switch-to-state
|
||||
"\\(?:[ \t]\\|$\\)"))))
|
||||
(org-todo org-clock-in-switch-to-state)))
|
||||
(setq org-clock-heading (org-clock--mode-line-heading))
|
||||
(org-clock-find-position org-clock-in-resume)
|
||||
|
@ -1397,12 +1455,15 @@ the default behavior."
|
|||
(sit-for 2)
|
||||
(throw 'abort nil))
|
||||
(t
|
||||
;; Make sure that point moves after clock line upon
|
||||
;; inserting it. Then, users can continue typing even if
|
||||
;; point was right where the clock is inserted.
|
||||
(insert-before-markers-and-inherit "\n")
|
||||
(backward-char 1)
|
||||
(when (and (save-excursion
|
||||
(end-of-line 0)
|
||||
(org-in-item-p)))
|
||||
(beginning-of-line 1)
|
||||
(forward-line 0)
|
||||
(indent-line-to (max 0 (- (current-indentation) 2))))
|
||||
(insert-and-inherit org-clock-string " ")
|
||||
(setq org-clock-effort (org-entry-get (point) org-effort-property))
|
||||
|
@ -1422,8 +1483,8 @@ the default behavior."
|
|||
leftover)
|
||||
start-time
|
||||
(org-current-time org-clock-rounding-minutes t)))
|
||||
(setq ts (org-insert-time-stamp org-clock-start-time
|
||||
'with-hm 'inactive))
|
||||
(setq ts (org-insert-timestamp org-clock-start-time
|
||||
'with-hm 'inactive))
|
||||
(org-indent-line)))
|
||||
(move-marker org-clock-marker (point) (buffer-base-buffer))
|
||||
(move-marker org-clock-hd-marker
|
||||
|
@ -1459,6 +1520,33 @@ the default behavior."
|
|||
(message "Clock starts at %s - %s" ts org--msg-extra)
|
||||
(run-hooks 'org-clock-in-hook))))))
|
||||
|
||||
(defvar org-clock--auto-clockout-timer-obj nil
|
||||
"Timer object holding the existing clockout timer.")
|
||||
(defun org-clock--auto-clockout-maybe ()
|
||||
"Clock out the currently clocked in task when idle.
|
||||
See `org-clock-auto-clockout-timer' to set the idle time span.
|
||||
|
||||
This function is to be called by a timer."
|
||||
(when (and (numberp org-clock-auto-clockout-timer)
|
||||
org-clock-current-task)
|
||||
(let ((user-idle-seconds (org-user-idle-seconds)))
|
||||
(cond
|
||||
;; Already idle. Clock out.
|
||||
((>= user-idle-seconds org-clock-auto-clockout-timer)
|
||||
(setq org-clock--auto-clockout-timer-obj nil)
|
||||
(org-clock-out))
|
||||
;; Emacs is idle but system is not. Retry assuming that system will remain idle.
|
||||
((>= (org-emacs-idle-seconds) org-clock-auto-clockout-timer)
|
||||
(setq org-clock--auto-clockout-timer-obj
|
||||
(run-with-timer
|
||||
(- org-clock-auto-clockout-timer user-idle-seconds)
|
||||
nil #'org-clock--auto-clockout-maybe)))
|
||||
;; Emacs is not idle. Check again next time we are idle.
|
||||
(t
|
||||
(setq org-clock--auto-clockout-timer-obj
|
||||
(run-with-idle-timer
|
||||
org-clock-auto-clockout-timer nil #'org-clock--auto-clockout-maybe)))))))
|
||||
|
||||
(defun org-clock-auto-clockout ()
|
||||
"Clock out the currently clocked in task if Emacs is idle.
|
||||
See `org-clock-auto-clockout-timer' to set the idle time span.
|
||||
|
@ -1466,9 +1554,11 @@ See `org-clock-auto-clockout-timer' to set the idle time span.
|
|||
This is only effective when `org-clock-auto-clockout-insinuate'
|
||||
is present in the user configuration."
|
||||
(when (and (numberp org-clock-auto-clockout-timer)
|
||||
org-clock-current-task)
|
||||
(run-with-idle-timer
|
||||
org-clock-auto-clockout-timer nil #'org-clock-out)))
|
||||
org-clock-current-task
|
||||
(not (timerp org-clock--auto-clockout-timer-obj)))
|
||||
(setq org-clock--auto-clockout-timer-obj
|
||||
(run-with-idle-timer
|
||||
org-clock-auto-clockout-timer nil #'org-clock--auto-clockout-maybe))))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-clock-toggle-auto-clockout ()
|
||||
|
@ -1576,9 +1666,9 @@ line and position cursor in that line."
|
|||
" *\\sw+ +[012][0-9]:[0-5][0-9]\\)\\][ \t]*$")))
|
||||
(while (re-search-forward open-clock-re end t)
|
||||
(let ((element (org-element-at-point)))
|
||||
(when (and (eq (org-element-type element) 'clock)
|
||||
(when (and (org-element-type-p element 'clock)
|
||||
(eq (org-element-property :status element) 'running))
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(throw 'exit t))))))
|
||||
;; Look for an existing clock drawer.
|
||||
(when drawer
|
||||
|
@ -1586,8 +1676,8 @@ line and position cursor in that line."
|
|||
(let ((drawer-re (concat "^[ \t]*:" (regexp-quote drawer) ":[ \t]*$")))
|
||||
(while (re-search-forward drawer-re end t)
|
||||
(let ((element (org-element-at-point)))
|
||||
(when (eq (org-element-type element) 'drawer)
|
||||
(let ((cend (org-element-property :contents-end element)))
|
||||
(when (org-element-type-p element 'drawer)
|
||||
(let ((cend (org-element-contents-end element)))
|
||||
(if (and (not org-log-states-order-reversed) cend)
|
||||
(goto-char cend)
|
||||
(forward-line))
|
||||
|
@ -1600,7 +1690,7 @@ line and position cursor in that line."
|
|||
(save-excursion
|
||||
(while (re-search-forward clock-re end t)
|
||||
(let ((element (org-element-at-point)))
|
||||
(when (eq (org-element-type element) 'clock)
|
||||
(when (org-element-type-p element 'clock)
|
||||
(setq positions (cons (line-beginning-position) positions)
|
||||
count (1+ count))))))
|
||||
(cond
|
||||
|
@ -1608,19 +1698,18 @@ line and position cursor in that line."
|
|||
(org-fold-core-ignore-modifications
|
||||
;; Skip planning line and property drawer, if any.
|
||||
(org-end-of-meta-data)
|
||||
(unless (bolp) (insert-and-inherit "\n"))
|
||||
(unless (bolp) (insert-before-markers-and-inherit "\n"))
|
||||
;; Create a new drawer if necessary.
|
||||
(when (and org-clock-into-drawer
|
||||
(or (not (wholenump org-clock-into-drawer))
|
||||
(< org-clock-into-drawer 2)))
|
||||
(let ((beg (point)))
|
||||
(insert-and-inherit ":" drawer ":\n:END:\n")
|
||||
;; Make sure that point moves after drawer upon
|
||||
;; inserting it. Then, users can continue typing even
|
||||
;; if point was right where the clock is inserted.
|
||||
(insert-before-markers-and-inherit ":" drawer ":\n:END:\n")
|
||||
(org-indent-region beg (point))
|
||||
(if (eq org-fold-core-style 'text-properties)
|
||||
(org-fold-region
|
||||
(line-end-position -1) (1- (point)) t 'drawer)
|
||||
(org-fold-region
|
||||
(line-end-position -1) (1- (point)) t 'outline))
|
||||
(org-fold-region (line-end-position -1) (1- (point)) t 'drawer)
|
||||
(forward-line -1)))))
|
||||
;; When a clock drawer needs to be created because of the
|
||||
;; number of clock items or simply if it is missing, collect
|
||||
|
@ -1645,13 +1734,13 @@ line and position cursor in that line."
|
|||
"\n:END:\n")
|
||||
(let ((end (point-marker)))
|
||||
(goto-char beg)
|
||||
(save-excursion (insert-and-inherit ":" drawer ":\n"))
|
||||
(save-excursion (insert-before-markers-and-inherit ":" drawer ":\n"))
|
||||
(org-fold-region (line-end-position) (1- end) t 'outline)
|
||||
(org-indent-region (point) end)
|
||||
(forward-line)
|
||||
(unless org-log-states-order-reversed
|
||||
(goto-char end)
|
||||
(beginning-of-line -1))
|
||||
(forward-line -2))
|
||||
(set-marker end nil)))))
|
||||
(org-log-states-order-reversed (goto-char (car (last positions))))
|
||||
(t (goto-char (car positions))))))))
|
||||
|
@ -1664,6 +1753,11 @@ and current `frame-title-format' is equal to `org-clock-frame-title-format'."
|
|||
(equal frame-title-format org-clock-frame-title-format))
|
||||
(setq frame-title-format org-frame-title-format-backup)))
|
||||
|
||||
(defvar org-clock-out-removed-last-clock nil
|
||||
"When non-nil, the last `org-clock-out' removed the clock line.
|
||||
This can happen when `org-clock-out-remove-zero-time-clocks' is set to
|
||||
non-nil and the latest clock took 0 minutes.")
|
||||
|
||||
;;;###autoload
|
||||
(defun org-clock-out (&optional switch-to-state fail-quietly at-time)
|
||||
"Stop the currently running clock.
|
||||
|
@ -1694,7 +1788,7 @@ to, overriding the existing value of `org-clock-out-switch-to-state'."
|
|||
(save-restriction
|
||||
(widen)
|
||||
(goto-char org-clock-marker)
|
||||
(beginning-of-line 1)
|
||||
(forward-line 0)
|
||||
(if (and (looking-at (concat "[ \t]*" org-keyword-time-regexp))
|
||||
(equal (match-string 1) org-clock-string))
|
||||
(setq ts (match-string 2))
|
||||
|
@ -1703,7 +1797,7 @@ to, overriding the existing value of `org-clock-out-switch-to-state'."
|
|||
(delete-region (point) (line-end-position))
|
||||
(org-fold-core-ignore-modifications
|
||||
(insert-and-inherit "--")
|
||||
(setq te (org-insert-time-stamp (or at-time now) 'with-hm 'inactive))
|
||||
(setq te (org-insert-timestamp (or at-time now) 'with-hm 'inactive))
|
||||
(setq s (org-time-convert-to-integer
|
||||
(time-subtract
|
||||
(org-time-string-to-time te)
|
||||
|
@ -1742,10 +1836,10 @@ to, overriding the existing value of `org-clock-out-switch-to-state'."
|
|||
(when newstate (org-todo newstate))))
|
||||
((and org-clock-out-switch-to-state
|
||||
(not (looking-at
|
||||
(concat
|
||||
org-outline-regexp "[ \t]*"
|
||||
org-clock-out-switch-to-state
|
||||
"\\>"))))
|
||||
(concat
|
||||
org-outline-regexp "[ \t]*"
|
||||
org-clock-out-switch-to-state
|
||||
"\\(?:[ \t]\\|$\\)"))))
|
||||
(org-todo org-clock-out-switch-to-state))))))
|
||||
(force-mode-line-update)
|
||||
(message (if remove
|
||||
|
@ -1754,6 +1848,7 @@ to, overriding the existing value of `org-clock-out-switch-to-state'."
|
|||
te (org-duration-from-minutes (+ (* 60 h) m)))
|
||||
(unless (org-clocking-p)
|
||||
(setq org-clock-current-task nil))
|
||||
(setq org-clock-out-removed-last-clock remove)
|
||||
(run-hooks 'org-clock-out-hook)
|
||||
;; Add a note, but only if we didn't remove the clock line.
|
||||
(when (and org-log-note-clock-out (not remove))
|
||||
|
@ -1948,17 +2043,30 @@ PROPNAME lets you set a custom text property instead of :org-clock-minutes."
|
|||
(save-excursion
|
||||
(goto-char (point-max))
|
||||
(while (re-search-backward re nil t)
|
||||
(let ((element-type
|
||||
(org-element-type
|
||||
(save-match-data
|
||||
(org-element-at-point)))))
|
||||
(let* ((element (save-match-data (org-element-at-point)))
|
||||
(element-type (org-element-type element)))
|
||||
(cond
|
||||
((and (eq element-type 'clock) (match-end 2))
|
||||
;; Two time stamps.
|
||||
(let* ((ss (match-string 2))
|
||||
(se (match-string 3))
|
||||
(ts (org-time-string-to-seconds ss))
|
||||
(te (org-time-string-to-seconds se))
|
||||
(let* ((timestamp (org-element-property :value element))
|
||||
(ts (float-time
|
||||
(org-encode-time
|
||||
(list 0
|
||||
(org-element-property :minute-start timestamp)
|
||||
(org-element-property :hour-start timestamp)
|
||||
(org-element-property :day-start timestamp)
|
||||
(org-element-property :month-start timestamp)
|
||||
(org-element-property :year-start timestamp)
|
||||
nil -1 nil))))
|
||||
(te (float-time
|
||||
(org-encode-time
|
||||
(list 0
|
||||
(org-element-property :minute-end timestamp)
|
||||
(org-element-property :hour-end timestamp)
|
||||
(org-element-property :day-end timestamp)
|
||||
(org-element-property :month-end timestamp)
|
||||
(org-element-property :year-end timestamp)
|
||||
nil -1 nil))))
|
||||
(dt (- (if tend (min te tend) te)
|
||||
(if tstart (max ts tstart) ts))))
|
||||
(when (> dt 0) (cl-incf t1 (floor dt 60)))))
|
||||
|
@ -2358,7 +2466,7 @@ have priority."
|
|||
d (+ d shift)))
|
||||
((or `week `thisweek)
|
||||
(let* ((ws (or wstart 1))
|
||||
(diff (+ (* -7 shift) (if (= dow 0) (- 7 ws) (- dow ws)))))
|
||||
(diff (+ (* -7 shift) (mod (+ dow 7 (- ws)) 7))))
|
||||
(setq m 0 h org-extend-today-until d (- d diff) d1 (+ 7 d))))
|
||||
((or `month `thismonth)
|
||||
(setq h org-extend-today-until m 0 d (or mstart 1)
|
||||
|
@ -2509,7 +2617,7 @@ the currently selected interval size."
|
|||
(goto-char b)
|
||||
(insert ins)
|
||||
(delete-region (point) (+ (point) (- e b)))
|
||||
(beginning-of-line 1)
|
||||
(forward-line 0)
|
||||
(org-update-dblock)
|
||||
t)))))
|
||||
|
||||
|
@ -2811,13 +2919,13 @@ from the dynamic block definition."
|
|||
(if timestamp (concat ts "|") "") ;timestamp, maybe
|
||||
(if tags (concat (mapconcat #'identity tgs ", ") "|") "") ;tags, maybe
|
||||
(if properties ;properties columns, maybe
|
||||
(concat (mapconcat (lambda (p) (or (cdr (assoc p props)) ""))
|
||||
properties
|
||||
"|")
|
||||
"|")
|
||||
(concat (mapconcat (lambda (p) (or (cdr (assoc p props)) ""))
|
||||
properties
|
||||
"|")
|
||||
"|")
|
||||
"")
|
||||
(if indent ;indentation
|
||||
(org-clocktable-indent-string level)
|
||||
(org-clocktable-indent-string level)
|
||||
"")
|
||||
(format-field headline)
|
||||
;; Empty fields for higher levels.
|
||||
|
@ -2825,7 +2933,7 @@ from the dynamic block definition."
|
|||
(format-field (org-duration-from-minutes time))
|
||||
(make-string (max 0 (- time-columns level)) ?|)
|
||||
(if (eq formula '%)
|
||||
(format "%.1f |" (* 100 (/ time (float total-time))))
|
||||
(format "%.1f |" (* 100 (/ time (float total-time))))
|
||||
"")
|
||||
"\n")))))))
|
||||
(delete-char -1)
|
||||
|
@ -2836,7 +2944,7 @@ from the dynamic block definition."
|
|||
(when (and contents (string-match "^\\([ \t]*#\\+tblfm:.*\\)" contents))
|
||||
(setq recalc t)
|
||||
(insert "\n" (match-string 1 contents))
|
||||
(beginning-of-line 0))))
|
||||
(forward-line -1))))
|
||||
;; Insert specified formula line.
|
||||
((stringp formula)
|
||||
(insert "\n#+TBLFM: " formula)
|
||||
|
@ -3018,8 +3126,9 @@ PROPERTIES: The list properties specified in the `:properties' parameter
|
|||
(let* ((todo (org-get-todo-state))
|
||||
(tags-list (org-get-tags))
|
||||
(org-scanner-tags tags-list)
|
||||
(org-trust-scanner-tags t))
|
||||
(funcall matcher todo tags-list nil)))))
|
||||
(org-trust-scanner-tags t)
|
||||
(level (org-current-level)))
|
||||
(funcall matcher todo tags-list level)))))
|
||||
(goto-char (point-min))
|
||||
(setq st t)
|
||||
(while (or (and (bobp) (prog1 st (setq st nil))
|
||||
|
@ -3079,7 +3188,7 @@ Otherwise, return nil."
|
|||
(let ((origin (point))) ;; `save-excursion' may not work when deleting.
|
||||
(prog1
|
||||
(save-excursion
|
||||
(beginning-of-line 1)
|
||||
(forward-line 0)
|
||||
(skip-chars-forward " \t")
|
||||
(when (looking-at org-clock-string)
|
||||
(let ((re (concat "[ \t]*" org-clock-string
|
||||
|
|
|
@ -37,13 +37,13 @@
|
|||
(declare-function org-agenda-redo "org-agenda" (&optional all))
|
||||
(declare-function org-agenda-do-context-action "org-agenda" ())
|
||||
(declare-function org-clock-sum-today "org-clock" (&optional headline-filter))
|
||||
(declare-function org-element-extract-element "org-element" (element))
|
||||
(declare-function org-element-extract "org-element-ast" (node))
|
||||
(declare-function org-element-interpret-data "org-element" (data))
|
||||
(declare-function org-element-map "org-element" (data types fun &optional info first-match no-recursion with-affiliated))
|
||||
(declare-function org-element-parse-secondary-string "org-element" (string restriction &optional parent))
|
||||
(declare-function org-element-property "org-element" (property element))
|
||||
(declare-function org-element-property "org-element-ast" (property node))
|
||||
(declare-function org-element-restriction "org-element" (element))
|
||||
(declare-function org-element-type "org-element" (element))
|
||||
(declare-function org-element-type-p "org-element-ast" (node types))
|
||||
(declare-function org-dynamic-block-define "org" (type func))
|
||||
(declare-function org-link-display-format "ol" (s))
|
||||
(declare-function org-link-open-from-string "ol" (s &optional arg))
|
||||
|
@ -59,6 +59,19 @@
|
|||
|
||||
;;; Configuration
|
||||
|
||||
(defcustom org-columns-checkbox-allowed-values '("[ ]" "[X]")
|
||||
"Allowed values for columns with SUMMARY-TYPE that uses checkbox.
|
||||
The affected summary types are \"X%\", \"X/\", and \"X\" (see info
|
||||
node `(org)Column attributes')."
|
||||
:group 'org-properties
|
||||
:package-version '(Org . "9.6")
|
||||
:type '(repeat (choice
|
||||
(const :tag "Unchecked [ ]" "[ ]")
|
||||
(const :tag "Checked [X]" "[X]")
|
||||
(const :tag "No checkbox" "")
|
||||
(const :tag "Intermediate state [-]" "[-]")
|
||||
(string :tag "Arbitrary string"))))
|
||||
|
||||
(defcustom org-columns-modify-value-for-display-function nil
|
||||
"Function that modifies values for display in column view.
|
||||
For example, it can be used to cut out a certain part from a time stamp.
|
||||
|
@ -110,6 +123,12 @@ in `org-columns-summary-types-default', which see."
|
|||
(function :tag "Summarize")
|
||||
(function :tag "Collect")))))
|
||||
|
||||
(defcustom org-columns-dblock-formatter #'org-columns-dblock-write-default
|
||||
"Function to format data in column view dynamic blocks.
|
||||
For more information, see `org-columns-dblock-write-default'."
|
||||
:group 'org-properties
|
||||
:package-version '(Org . "9.7")
|
||||
:type 'function)
|
||||
|
||||
|
||||
;;; Column View
|
||||
|
@ -118,6 +137,9 @@ in `org-columns-summary-types-default', which see."
|
|||
"Holds the list of current column overlays.")
|
||||
(put 'org-columns-overlays 'permanent-local t)
|
||||
|
||||
(defvar-local org-columns-global nil
|
||||
"Local variable, holds non-nil when current columns are global.")
|
||||
|
||||
(defvar-local org-columns-current-fmt nil
|
||||
"Local variable, holds the currently active column format.")
|
||||
|
||||
|
@ -180,28 +202,10 @@ See `org-columns-summary-types' for details.")
|
|||
(org-defkey org-columns-map "\M-b" #'backward-char)
|
||||
(org-defkey org-columns-map "a" #'org-columns-edit-allowed)
|
||||
(org-defkey org-columns-map "s" #'org-columns-edit-attributes)
|
||||
(org-defkey org-columns-map "\M-f"
|
||||
(lambda () (interactive) (goto-char (1+ (point)))))
|
||||
(org-defkey org-columns-map [right]
|
||||
(lambda () (interactive) (goto-char (1+ (point)))))
|
||||
(org-defkey org-columns-map [down]
|
||||
(lambda () (interactive)
|
||||
(let ((col (current-column)))
|
||||
(beginning-of-line 2)
|
||||
(while (and (org-invisible-p2) (not (eobp)))
|
||||
(beginning-of-line 2))
|
||||
(move-to-column col)
|
||||
(if (derived-mode-p 'org-agenda-mode)
|
||||
(org-agenda-do-context-action)))))
|
||||
(org-defkey org-columns-map [up]
|
||||
(lambda () (interactive)
|
||||
(let ((col (current-column)))
|
||||
(beginning-of-line 0)
|
||||
(while (and (org-invisible-p2) (not (bobp)))
|
||||
(beginning-of-line 0))
|
||||
(move-to-column col)
|
||||
(if (eq major-mode 'org-agenda-mode)
|
||||
(org-agenda-do-context-action)))))
|
||||
(org-defkey org-columns-map "\M-f" #'forward-char)
|
||||
(org-defkey org-columns-map [right] #'forward-char)
|
||||
(org-defkey org-columns-map [up] #'org-columns-move-up)
|
||||
(org-defkey org-columns-map [down] #'org-columns-move-down)
|
||||
(org-defkey org-columns-map [(shift right)] #'org-columns-next-allowed-value)
|
||||
(org-defkey org-columns-map "n" #'org-columns-next-allowed-value)
|
||||
(org-defkey org-columns-map [(shift left)] #'org-columns-previous-allowed-value)
|
||||
|
@ -210,6 +214,8 @@ See `org-columns-summary-types' for details.")
|
|||
(org-defkey org-columns-map ">" #'org-columns-widen)
|
||||
(org-defkey org-columns-map [(meta right)] #'org-columns-move-right)
|
||||
(org-defkey org-columns-map [(meta left)] #'org-columns-move-left)
|
||||
(org-defkey org-columns-map [(meta down)] #'org-columns-move-row-down)
|
||||
(org-defkey org-columns-map [(meta up)] #'org-columns-move-row-up)
|
||||
(org-defkey org-columns-map [(shift meta right)] #'org-columns-new)
|
||||
(org-defkey org-columns-map [(shift meta left)] #'org-columns-delete)
|
||||
(dotimes (i 10)
|
||||
|
@ -231,6 +237,8 @@ See `org-columns-summary-types' for details.")
|
|||
"--"
|
||||
["Move column right" org-columns-move-right t]
|
||||
["Move column left" org-columns-move-left t]
|
||||
["Move row up" org-columns-move-row-up t]
|
||||
["Move row down" org-columns-move-row-down t]
|
||||
["Add column" org-columns-new t]
|
||||
["Delete column" org-columns-delete t]
|
||||
"--"
|
||||
|
@ -376,17 +384,19 @@ ORIGINAL is the real string, i.e., before it is modified by
|
|||
"Store the relative remapping of column header-line.
|
||||
This is needed to later remove this relative remapping.")
|
||||
|
||||
(defvar org-columns--read-only-string nil)
|
||||
(defun org-columns--display-here (columns &optional dateline)
|
||||
"Overlay the current line with column display.
|
||||
COLUMNS is an alist (SPEC VALUE DISPLAYED). Optional argument
|
||||
DATELINE is non-nil when the face used should be
|
||||
`org-agenda-column-dateline'."
|
||||
(when (and (ignore-errors (require 'face-remap))
|
||||
org-columns-header-line-remap)
|
||||
(when (and (not org-columns-header-line-remap)
|
||||
(or (fboundp 'face-remap-add-relative)
|
||||
(ignore-errors (require 'face-remap))))
|
||||
(setq org-columns-header-line-remap
|
||||
(face-remap-add-relative 'header-line '(:inherit default))))
|
||||
(save-excursion
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(let* ((level-face (and (looking-at "\\(\\**\\)\\(\\* \\)")
|
||||
(org-get-level-face 2)))
|
||||
(ref-face (or level-face
|
||||
|
@ -449,18 +459,36 @@ DATELINE is non-nil when the face used should be
|
|||
(line-end-position 0)
|
||||
(line-beginning-position 2)
|
||||
'read-only
|
||||
(substitute-command-keys
|
||||
"Type \\<org-columns-map>`\\[org-columns-edit-value]' \
|
||||
to edit property")))))))
|
||||
(or org-columns--read-only-string
|
||||
(setq org-columns--read-only-string
|
||||
(substitute-command-keys
|
||||
"Type \\<org-columns-map>`\\[org-columns-edit-value]' \
|
||||
to edit property")))))))))
|
||||
|
||||
(defun org-columns--truncate-below-width (string width)
|
||||
"Return a substring of STRING no wider than WIDTH.
|
||||
This substring must start at 0, and must be the longest possible
|
||||
substring whose `string-width' does not exceed WIDTH."
|
||||
(declare (side-effect-free t))
|
||||
(let ((end (min width (length string))) res)
|
||||
(while (and end (>= end 0))
|
||||
(let* ((curr (string-width (substring string 0 end)))
|
||||
(excess (- curr width)))
|
||||
(if (> excess 0)
|
||||
(cl-decf end (max 1 (/ excess 2)))
|
||||
(setq res (substring string 0 end) end nil))))
|
||||
res))
|
||||
|
||||
(defun org-columns-add-ellipses (string width)
|
||||
"Truncate STRING with WIDTH characters, with ellipses."
|
||||
(cond
|
||||
((<= (length string) width) string)
|
||||
((<= width (length org-columns-ellipses))
|
||||
(substring org-columns-ellipses 0 width))
|
||||
(t (concat (substring string 0 (- width (length org-columns-ellipses)))
|
||||
org-columns-ellipses))))
|
||||
((<= (string-width string) width) string)
|
||||
((<= width (string-width org-columns-ellipses))
|
||||
(org-columns--truncate-below-width org-columns-ellipses width))
|
||||
(t (concat
|
||||
(org-columns--truncate-below-width
|
||||
string (- width (string-width org-columns-ellipses)))
|
||||
org-columns-ellipses))))
|
||||
|
||||
(defvar org-columns-full-header-line-format nil
|
||||
"The full header line format, will be shifted by horizontal scrolling." )
|
||||
|
@ -728,7 +756,7 @@ an integer, select that value."
|
|||
(let ((all
|
||||
(or (org-property-get-allowed-values pom key)
|
||||
(pcase (nth column org-columns-current-fmt-compiled)
|
||||
(`(,_ ,_ ,_ ,(or "X" "X/" "X%") ,_) '("[ ]" "[X]")))
|
||||
(`(,_ ,_ ,_ ,(or "X" "X/" "X%") ,_) org-columns-checkbox-allowed-values))
|
||||
(org-colview-construct-allowed-dates value))))
|
||||
(if previous (reverse all) all))))
|
||||
(when (equal key "ITEM") (error "Cannot edit item headline from here"))
|
||||
|
@ -818,7 +846,7 @@ current specifications. This function also sets
|
|||
(let ((case-fold-search t))
|
||||
(while (re-search-forward "^[ \t]*#\\+COLUMNS: .+$" nil t)
|
||||
(let ((element (org-element-at-point)))
|
||||
(when (eq (org-element-type element) 'keyword)
|
||||
(when (org-element-type-p element 'keyword)
|
||||
(throw :found (org-element-property :value element)))))
|
||||
nil)))
|
||||
org-columns-default-format)))
|
||||
|
@ -851,6 +879,7 @@ turn on column view for the whole buffer unconditionally.
|
|||
When COLUMNS-FMT-STRING is non-nil, use it as the column format."
|
||||
(interactive "P")
|
||||
(org-columns-remove-overlays)
|
||||
(setq-local org-columns-global global)
|
||||
(save-excursion
|
||||
(when global (goto-char (point-min)))
|
||||
(if (markerp org-columns-begin-marker)
|
||||
|
@ -873,7 +902,7 @@ When COLUMNS-FMT-STRING is non-nil, use it as the column format."
|
|||
;; Collect contents of columns ahead of time so as to
|
||||
;; compute their maximum width.
|
||||
(org-scan-tags
|
||||
(lambda () (cons (point) (org-columns--collect-values))) t org--matcher-tags-todo-only)))
|
||||
(lambda () (cons (point-marker) (org-columns--collect-values))) t org--matcher-tags-todo-only)))
|
||||
(when cache
|
||||
(org-columns--set-widths cache)
|
||||
(org-columns--display-here-title)
|
||||
|
@ -971,6 +1000,30 @@ details."
|
|||
(interactive "p")
|
||||
(org-columns-widen (- arg)))
|
||||
|
||||
(defun org-columns-move-up ()
|
||||
"In column view, move cursor up one row.
|
||||
When in agenda column view, also call `org-agenda-do-context-action'."
|
||||
(interactive)
|
||||
(let ((col (current-column)))
|
||||
(forward-line -1)
|
||||
(while (and (org-invisible-p2) (not (bobp)))
|
||||
(forward-line -1))
|
||||
(move-to-column col)
|
||||
(if (eq major-mode 'org-agenda-mode)
|
||||
(org-agenda-do-context-action))))
|
||||
|
||||
(defun org-columns-move-down ()
|
||||
"In column view, move cursor down one row.
|
||||
When in agenda column view, also call `org-agenda-do-context-action'."
|
||||
(interactive)
|
||||
(let ((col (current-column)))
|
||||
(forward-line 1)
|
||||
(while (and (org-invisible-p2) (not (eobp)))
|
||||
(forward-line 1))
|
||||
(move-to-column col)
|
||||
(if (derived-mode-p 'org-agenda-mode)
|
||||
(org-agenda-do-context-action))))
|
||||
|
||||
(defun org-columns-move-right ()
|
||||
"Swap this column with the one to the right."
|
||||
(interactive)
|
||||
|
@ -1005,6 +1058,27 @@ details."
|
|||
(org-columns-move-right)
|
||||
(backward-char 1)))
|
||||
|
||||
(defun org-columns--move-row (&optional up)
|
||||
"Move the current table row down.
|
||||
With non-nil optional argument UP, move it up."
|
||||
(let ((inhibit-read-only t)
|
||||
(col (current-column)))
|
||||
(if up (org-move-subtree-up)
|
||||
(org-move-subtree-down))
|
||||
(let ((org-columns-inhibit-recalculation t))
|
||||
(org-columns-redo)
|
||||
(move-to-column col))))
|
||||
|
||||
(defun org-columns-move-row-down ()
|
||||
"Move the current table row down."
|
||||
(interactive)
|
||||
(org-columns--move-row))
|
||||
|
||||
(defun org-columns-move-row-up ()
|
||||
"Move the current table row up."
|
||||
(interactive)
|
||||
(org-columns--move-row 'up))
|
||||
|
||||
(defun org-columns-store-format ()
|
||||
"Store the text version of the current columns format.
|
||||
The format is stored either in the COLUMNS property of the node
|
||||
|
@ -1022,7 +1096,7 @@ the current buffer."
|
|||
(catch :found
|
||||
(while (re-search-forward "^[ \t]*#\\+COLUMNS:\\(.*\\)" nil t)
|
||||
(let ((element (save-match-data (org-element-at-point))))
|
||||
(when (and (eq (org-element-type element) 'keyword)
|
||||
(when (and (org-element-type-p element 'keyword)
|
||||
(equal (org-element-property :key element)
|
||||
"COLUMNS"))
|
||||
(replace-match (concat " " fmt) t t nil 1)
|
||||
|
@ -1072,7 +1146,7 @@ the current buffer."
|
|||
(if (derived-mode-p 'org-mode)
|
||||
;; Since we already know the columns format, provide it
|
||||
;; instead of computing again.
|
||||
(call-interactively #'org-columns org-columns-current-fmt)
|
||||
(funcall-interactively #'org-columns org-columns-global org-columns-current-fmt)
|
||||
(org-agenda-redo)
|
||||
(call-interactively #'org-agenda-columns)))
|
||||
(message "Recomputing columns...done")))
|
||||
|
@ -1132,7 +1206,7 @@ This function updates `org-columns-current-fmt-compiled'."
|
|||
|
||||
(defun org-columns--age-to-minutes (s)
|
||||
"Turn age string S into a number of minutes.
|
||||
An age is either computed from a given time-stamp, or indicated
|
||||
An age is either computed from a given timestamp, or indicated
|
||||
as a canonical duration, i.e., using units defined in
|
||||
`org-duration-canonical-units'."
|
||||
(cond
|
||||
|
@ -1161,8 +1235,8 @@ Return the result as a duration."
|
|||
SPEC is a column format specification. When optional argument
|
||||
UPDATE is non-nil, summarized values can replace existing ones in
|
||||
properties drawers."
|
||||
(let* ((lmax (if (bound-and-true-p org-inlinetask-min-level)
|
||||
org-inlinetask-min-level
|
||||
(let* ((lmax (if (bound-and-true-p org-inlinetask-max-level)
|
||||
org-inlinetask-max-level
|
||||
29)) ;Hard-code deepest level.
|
||||
(lvals (make-vector (1+ lmax) nil))
|
||||
(level 0)
|
||||
|
@ -1198,9 +1272,9 @@ properties drawers."
|
|||
;; property `org-summaries', in alist whose key is SPEC.
|
||||
(let* ((summary
|
||||
(and summarize
|
||||
(let ((values (append (and (/= last-level inminlevel)
|
||||
(aref lvals last-level))
|
||||
(aref lvals inminlevel))))
|
||||
(let ((values
|
||||
(cl-loop for l from (1+ level) to lmax
|
||||
append (aref lvals l))))
|
||||
(and values (funcall summarize values printf))))))
|
||||
;; Leaf values are not summaries: do not mark them.
|
||||
(when summary
|
||||
|
@ -1374,9 +1448,13 @@ that will be excluded from the resulting view. FORMAT is a
|
|||
format string for columns, or nil. When LOCAL is non-nil, only
|
||||
capture headings in current subtree.
|
||||
|
||||
This function returns a list containing the title row and all
|
||||
other rows. Each row is a list of fields, as strings, or
|
||||
`hline'."
|
||||
This function returns a list containing the title row and all other
|
||||
rows. Each row is either a list, or the symbol `hline'. The first list
|
||||
is the heading row as a list of strings with the column titles according
|
||||
to FORMAT. All subsequent lists each represent a body row as a list
|
||||
whose first element is an integer indicating the outline level of the
|
||||
entry, and whose remaining elements are strings with the contents for
|
||||
the columns according to FORMAT."
|
||||
(org-columns (not local) format)
|
||||
(goto-char org-columns-top-level-marker)
|
||||
(let ((columns (length org-columns-current-fmt-compiled))
|
||||
|
@ -1389,11 +1467,10 @@ other rows. Each row is a list of fields, as strings, or
|
|||
(dotimes (i columns)
|
||||
(let* ((col (+ (line-beginning-position) i))
|
||||
(p (get-char-property col 'org-columns-key)))
|
||||
(push (org-quote-vert
|
||||
(get-char-property col
|
||||
(if (string= p "ITEM")
|
||||
'org-columns-value
|
||||
'org-columns-value-modified)))
|
||||
(push (get-char-property col
|
||||
(if (string= p "ITEM")
|
||||
'org-columns-value
|
||||
'org-columns-value-modified))
|
||||
row)))
|
||||
(unless (or
|
||||
(and skip-empty
|
||||
|
@ -1424,8 +1501,10 @@ an inline src-block."
|
|||
(org-element-map data
|
||||
'(footnote-reference inline-babel-call inline-src-block target
|
||||
radio-target statistics-cookie)
|
||||
#'org-element-extract-element)
|
||||
(org-no-properties (org-element-interpret-data data))))
|
||||
#'org-element-extract)
|
||||
(org-quote-vert
|
||||
(org-no-properties
|
||||
(org-element-interpret-data data)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-dblock-write:columnview (params)
|
||||
|
@ -1477,7 +1556,17 @@ PARAMS is a property list of parameters:
|
|||
`:vlines'
|
||||
|
||||
When non-nil, make each column a column group to enforce
|
||||
vertical lines."
|
||||
vertical lines.
|
||||
|
||||
`:link'
|
||||
|
||||
Link the item headlines in the table to their origins.
|
||||
|
||||
`:formatter'
|
||||
|
||||
A function to format the data and insert it into the
|
||||
buffer. Overrides the default formatting function set in
|
||||
`org-columns-dblock-formatter'."
|
||||
(let ((table
|
||||
(let ((id (plist-get params :id))
|
||||
view-file view-pos)
|
||||
|
@ -1495,7 +1584,7 @@ PARAMS is a property list of parameters:
|
|||
(setq view-file filename)
|
||||
(setq view-pos position))
|
||||
(_ (user-error "Cannot find entry with :ID: %s" id)))
|
||||
(with-current-buffer (if view-file (get-file-buffer view-file)
|
||||
(with-current-buffer (if view-file (org-get-agenda-file-buffer view-file)
|
||||
(current-buffer))
|
||||
(org-with-wide-buffer
|
||||
(when view-pos (goto-char view-pos))
|
||||
|
@ -1504,7 +1593,21 @@ PARAMS is a property list of parameters:
|
|||
(plist-get params :skip-empty-rows)
|
||||
(plist-get params :exclude-tags)
|
||||
(plist-get params :format)
|
||||
view-pos))))))
|
||||
view-pos)))))
|
||||
(formatter (or (plist-get params :formatter)
|
||||
org-columns-dblock-formatter
|
||||
#'org-columns-dblock-write-default)))
|
||||
(funcall formatter (point) table params)))
|
||||
|
||||
(defun org-columns-dblock-write-default (ipos table params)
|
||||
"Write out a columnview table at position IPOS in the current buffer.
|
||||
TABLE is a table with data as produced by `org-columns--capture-view'.
|
||||
PARAMS is the parameter property list obtained from the dynamic block
|
||||
definition."
|
||||
(let ((link (plist-get params :link))
|
||||
(width-specs
|
||||
(mapcar (lambda (spec) (nth 2 spec))
|
||||
org-columns-current-fmt-compiled)))
|
||||
(when table
|
||||
;; Prune level information from the table. Also normalize
|
||||
;; headings: remove stars, add indentation entities, if
|
||||
|
@ -1528,7 +1631,14 @@ PARAMS is a property list of parameters:
|
|||
(and (numberp hlines) (<= level hlines))))
|
||||
(push 'hline new-table))
|
||||
(when item-index
|
||||
(let ((item (org-columns--clean-item (nth item-index (cdr row)))))
|
||||
(let* ((raw (nth item-index (cdr row)))
|
||||
(cleaned (org-columns--clean-item raw))
|
||||
(item (if (not link) cleaned
|
||||
(let ((search (org-link-heading-search-string raw)))
|
||||
(org-link-make-string
|
||||
(if (not (buffer-file-name)) search
|
||||
(format "file:%s::%s" (buffer-file-name) search))
|
||||
cleaned)))))
|
||||
(setf (nth item-index (cdr row))
|
||||
(if (and indent (> level 1))
|
||||
(concat "\\_" (make-string (* 2 (1- level)) ?\s) item)
|
||||
|
@ -1540,6 +1650,13 @@ PARAMS is a property list of parameters:
|
|||
(append (mapcar (lambda (x) (if (eq 'hline x) x (cons "" x)))
|
||||
table)
|
||||
(list (cons "/" (make-list size "<>")))))))
|
||||
(when (seq-find #'identity width-specs)
|
||||
;; There are width specifiers in column format. Pass them
|
||||
;; to the resulting table, adding alignment field as the first
|
||||
;; row.
|
||||
(push (mapcar (lambda (width) (when width (format "<%d>" width))) width-specs) table))
|
||||
;; now insert the table into the buffer
|
||||
(goto-char ipos)
|
||||
(let ((content-lines (org-split-string (plist-get params :content) "\n"))
|
||||
recalc)
|
||||
;; Insert affiliated keywords before the table.
|
||||
|
@ -1561,7 +1678,9 @@ PARAMS is a property list of parameters:
|
|||
(insert "\n" line)
|
||||
(unless recalc (setq recalc t))))))
|
||||
(when recalc (org-table-recalculate 'all t))
|
||||
(org-table-align)))))
|
||||
(org-table-align)
|
||||
(when (seq-find #'identity width-specs)
|
||||
(org-table-shrink))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-columns-insert-dblock ()
|
||||
|
|
|
@ -52,9 +52,15 @@
|
|||
(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-lineage "org-element" (blob &optional types with-self))
|
||||
(declare-function org-element-type "org-element" (element))
|
||||
(declare-function org-element-property "org-element" (property element))
|
||||
(declare-function org-element-lineage "org-element-ast" (blob &optional types with-self))
|
||||
(declare-function org-element-type "org-element-ast" (node &optional anonymous))
|
||||
(declare-function org-element-type-p "org-element-ast" (node types))
|
||||
(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-contents-begin "org-element" (node))
|
||||
(declare-function org-element-contents-end "org-element" (node))
|
||||
(declare-function org-element-post-affiliated "org-element" (node))
|
||||
(declare-function org-end-of-subtree "org" (&optional invisible-ok to-heading))
|
||||
(declare-function org-get-heading "org" (&optional no-tags no-todo no-priority no-comment))
|
||||
(declare-function org-get-tags "org" (&optional pos local))
|
||||
|
@ -71,6 +77,7 @@
|
|||
(declare-function outline-next-heading "outline" ())
|
||||
(declare-function speedbar-line-directory "speedbar" (&optional depth))
|
||||
(declare-function table--at-cell-p "table" (position &optional object at-column))
|
||||
(declare-function ob-clojure-eval-with-cmd "ob-clojure" (cmd expanded))
|
||||
(declare-function org-fold-folded-p "org-fold" (&optional pos spec-or-alias))
|
||||
(declare-function org-fold-hide-sublevels "org-fold" (levels))
|
||||
(declare-function org-fold-hide-subtree "org-fold" ())
|
||||
|
@ -96,6 +103,25 @@
|
|||
|
||||
;;; Emacs < 29 compatibility
|
||||
|
||||
(if (fboundp 'display-buffer-full-frame)
|
||||
(defalias 'org-display-buffer-full-frame #'display-buffer-full-frame)
|
||||
(defun org-display-buffer-full-frame (buffer alist)
|
||||
"Display BUFFER in the current frame, taking the entire frame.
|
||||
ALIST is an association list of action symbols and values. See
|
||||
Info node `(elisp) Buffer Display Action Alists' for details of
|
||||
such alists.
|
||||
|
||||
This is an action function for buffer display, see Info
|
||||
node `(elisp) Buffer Display Action Functions'. It should be
|
||||
called only by `display-buffer' or a function directly or
|
||||
indirectly called by the latter."
|
||||
(when-let ((window (or (display-buffer-reuse-window buffer alist)
|
||||
(display-buffer-same-window buffer alist)
|
||||
(display-buffer-pop-up-window buffer alist)
|
||||
(display-buffer-use-some-window buffer alist))))
|
||||
(delete-other-windows window)
|
||||
window)))
|
||||
|
||||
(defvar org-file-has-changed-p--hash-table (make-hash-table :test #'equal)
|
||||
"Internal variable used by `org-file-has-changed-p'.")
|
||||
|
||||
|
@ -130,9 +156,41 @@ Upper-case and lower-case letters are treated as equal.
|
|||
Unibyte strings are converted to multibyte for comparison."
|
||||
(eq t (compare-strings string1 0 nil string2 0 nil t))))
|
||||
|
||||
(defun org-buffer-text-pixel-width ()
|
||||
"Return pixel width of text in current buffer.
|
||||
This function uses `buffer-text-pixel-size', when available, and falls
|
||||
back to `window-text-pixel-size' otherwise."
|
||||
(if (fboundp 'buffer-text-pixel-size)
|
||||
(car (buffer-text-pixel-size nil nil t))
|
||||
(if (get-buffer-window (current-buffer))
|
||||
;; FIXME: 10000 because `most-positive-fixnum' ain't working
|
||||
;; (tests failing) and this call will be removed after we drop
|
||||
;; Emacs 28 support anyway.
|
||||
(car (window-text-pixel-size
|
||||
nil (point-min) (point-max) 10000))
|
||||
(let ((dedicatedp (window-dedicated-p))
|
||||
(oldbuffer (window-buffer)))
|
||||
(unwind-protect
|
||||
(progn
|
||||
;; Do not throw error in dedicated windows.
|
||||
(set-window-dedicated-p nil nil)
|
||||
(set-window-buffer nil (current-buffer))
|
||||
(car (window-text-pixel-size
|
||||
nil (point-min) (point-max) 10000)))
|
||||
(set-window-buffer nil oldbuffer)
|
||||
(set-window-dedicated-p nil dedicatedp))))))
|
||||
|
||||
|
||||
;;; Emacs < 28.1 compatibility
|
||||
|
||||
(if (= 2 (cdr (subr-arity (symbol-function 'get-buffer-create))))
|
||||
;; Emacs >27.
|
||||
(defalias 'org-get-buffer-create #'get-buffer-create)
|
||||
(defun org-get-buffer-create (buffer-or-name &optional _)
|
||||
"Call `get-buffer-create' with BUFFER-OR-NAME argument.
|
||||
Ignore optional argument."
|
||||
(get-buffer-create buffer-or-name)))
|
||||
|
||||
(if (fboundp 'file-name-concat)
|
||||
(defalias 'org-file-name-concat #'file-name-concat)
|
||||
(defun org-file-name-concat (directory &rest components)
|
||||
|
@ -204,6 +262,25 @@ removed."
|
|||
`(progn ,@body))
|
||||
(defalias 'org-combine-change-calls 'combine-change-calls))
|
||||
|
||||
;; `flatten-tree' was added in Emacs 27.1.
|
||||
(if (fboundp 'flatten-tree)
|
||||
(defalias 'org--flatten-tree #'flatten-tree)
|
||||
;; The implementation is taken from Emacs subr.el 8664ba18c7c5.
|
||||
(defun org--flatten-tree (tree)
|
||||
"Return a \"flattened\" copy of TREE.
|
||||
|
||||
A `flatten-tree' polyfill for compatibility with Emacs versions
|
||||
older than 27.1"
|
||||
(let (elems)
|
||||
(while (consp tree)
|
||||
(let ((elem (pop tree)))
|
||||
(while (consp elem)
|
||||
(push (cdr elem) tree)
|
||||
(setq elem (car elem)))
|
||||
(if elem (push elem elems))))
|
||||
(if tree (push tree elems))
|
||||
(nreverse elems))))
|
||||
|
||||
(if (version< emacs-version "27.1")
|
||||
(defsubst org-replace-buffer-contents (source &optional _max-secs _max-costs)
|
||||
(replace-buffer-contents source))
|
||||
|
@ -290,6 +367,24 @@ Execute BODY, and unwind connection-local variables."
|
|||
`(with-connection-local-profiles (connection-local-get-profiles nil)
|
||||
,@body)))
|
||||
|
||||
;; assoc-delete-all missing from 26.1
|
||||
(if (fboundp 'assoc-delete-all)
|
||||
(defalias 'org-assoc-delete-all 'assoc-delete-all)
|
||||
;; from compat/compat-27.el
|
||||
(defun org-assoc-delete-all (key alist &optional test)
|
||||
"Delete all matching key from alist, default test equal"
|
||||
(unless test (setq test #'equal))
|
||||
(while (and (consp (car alist))
|
||||
(funcall test (caar alist) key))
|
||||
(setq alist (cdr alist)))
|
||||
(let ((tail alist) tail-cdr)
|
||||
(while (setq tail-cdr (cdr tail))
|
||||
(if (and (consp (car tail-cdr))
|
||||
(funcall test (caar tail-cdr) key))
|
||||
(setcdr tail (cdr tail-cdr))
|
||||
(setq tail tail-cdr))))
|
||||
alist))
|
||||
|
||||
|
||||
;;; Emacs < 26.1 compatibility
|
||||
|
||||
|
@ -386,6 +481,10 @@ Counting starts at 1."
|
|||
(define-obsolete-function-alias 'org-string-match-p 'string-match-p "9.0")
|
||||
|
||||
;;;; Functions and variables from previous releases now obsolete.
|
||||
(define-obsolete-variable-alias 'org-export-ignored-local-variables
|
||||
'org-element-ignored-local-variables "Org 9.7")
|
||||
(define-obsolete-function-alias 'org-habit-get-priority
|
||||
'org-habit-get-urgency "Org 9.7")
|
||||
(define-obsolete-function-alias 'org-timestamp-format
|
||||
'org-format-timestamp "Org 9.6")
|
||||
(define-obsolete-variable-alias 'org-export-before-processing-hook
|
||||
|
@ -411,7 +510,7 @@ Counting starts at 1."
|
|||
'completing-read "9.0")
|
||||
(define-obsolete-function-alias 'org-iread-file-name 'read-file-name "9.0")
|
||||
(define-obsolete-function-alias 'org-days-to-time
|
||||
'org-time-stamp-to-now "8.2")
|
||||
'org-timestamp-to-now "8.2")
|
||||
(define-obsolete-variable-alias 'org-agenda-ignore-drawer-properties
|
||||
'org-agenda-ignore-properties "9.0")
|
||||
(define-obsolete-function-alias 'org-preview-latex-fragment
|
||||
|
@ -549,10 +648,51 @@ Counting starts at 1."
|
|||
(define-obsolete-function-alias 'org-file-url-p 'org-url-p "9.6")
|
||||
(define-obsolete-variable-alias 'org-plantuml-executable-args 'org-plantuml-args
|
||||
"Org 9.6")
|
||||
|
||||
(defvar org-cached-props nil)
|
||||
(defvar org-use-property-inheritance)
|
||||
(declare-function org-entry-get "org" (epom property &optional inherit literal-nil))
|
||||
(declare-function org-entry-properties "org" (&optional epom which))
|
||||
(defun org-cached-entry-get (pom property)
|
||||
(if (or (eq t org-use-property-inheritance)
|
||||
(and (stringp org-use-property-inheritance)
|
||||
(let ((case-fold-search t))
|
||||
(string-match-p org-use-property-inheritance property)))
|
||||
(and (listp org-use-property-inheritance)
|
||||
(member-ignore-case property org-use-property-inheritance)))
|
||||
;; Caching is not possible, check it directly.
|
||||
(org-entry-get pom property 'inherit)
|
||||
;; Get all properties, so we can do complicated checks easily.
|
||||
(cdr (assoc-string property
|
||||
(or org-cached-props
|
||||
(setq org-cached-props (org-entry-properties pom)))
|
||||
t))))
|
||||
|
||||
(make-obsolete 'org-cached-entry-get
|
||||
"Performs badly. Instead use `org-entry-get' with the argument INHERIT set to `selective'"
|
||||
"9.7")
|
||||
|
||||
(defconst org-latex-line-break-safe "\\\\[0pt]"
|
||||
"Linebreak protecting the following [...].
|
||||
|
||||
Without \"[0pt]\" it would be interpreted as an optional argument to
|
||||
the \\\\.
|
||||
|
||||
This constant, for example, makes the below code not err:
|
||||
|
||||
\\begin{tabular}{c|c}
|
||||
[t] & s\\\\[0pt]
|
||||
[I] & A\\\\[0pt]
|
||||
[m] & kg
|
||||
\\end{tabular}")
|
||||
(make-obsolete 'org-latex-line-break-safe
|
||||
"should not be used - it is not safe in all the scenarios."
|
||||
"9.7")
|
||||
|
||||
(defun org-in-fixed-width-region-p ()
|
||||
"Non-nil if point in a fixed-width region."
|
||||
(save-match-data
|
||||
(eq 'fixed-width (org-element-type (org-element-at-point)))))
|
||||
(org-element-type-p (org-element-at-point) 'fixed-width)))
|
||||
(make-obsolete 'org-in-fixed-width-region-p
|
||||
"use `org-element' library"
|
||||
"9.0")
|
||||
|
@ -570,6 +710,26 @@ Counting starts at 1."
|
|||
(make-obsolete 'org-let "to be removed" "9.6")
|
||||
(make-obsolete 'org-let2 "to be removed" "9.6")
|
||||
|
||||
(define-obsolete-function-alias 'org--math-always-on
|
||||
'org--math-p "9.7")
|
||||
|
||||
(defmacro org-no-popups (&rest body)
|
||||
"Suppress popup windows and evaluate BODY."
|
||||
`(let (pop-up-frames pop-up-windows)
|
||||
,@body))
|
||||
(make-obsolete 'org-no-popups "no longer used" "9.7")
|
||||
|
||||
(defun org-switch-to-buffer-other-window (&rest args)
|
||||
"Switch to buffer in a second window on the current frame.
|
||||
In particular, do not allow pop-up frames.
|
||||
Returns the newly created buffer."
|
||||
(let (pop-up-frames pop-up-windows)
|
||||
(apply #'switch-to-buffer-other-window args)))
|
||||
(make-obsolete 'org-switch-to-buffer-other-window "no longer used" "9.7")
|
||||
|
||||
(make-obsolete 'org-refresh-category-properties "no longer used" "9.7")
|
||||
(make-obsolete 'org-refresh-effort-properties "no longer used" "9.7")
|
||||
|
||||
(defun org-compatible-face (inherits specs)
|
||||
"Make a compatible face specification.
|
||||
If INHERITS is an existing face and if the Emacs version supports
|
||||
|
@ -616,7 +776,7 @@ See `org-link-parameters' for documentation on the other parameters."
|
|||
(defun org-table-recognize-table.el ()
|
||||
"If there is a table.el table nearby, recognize it and move into it."
|
||||
(when (org-at-table.el-p)
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(unless (or (looking-at org-table-dataline-regexp)
|
||||
(not (looking-at org-table1-hline-regexp)))
|
||||
(forward-line)
|
||||
|
@ -658,13 +818,23 @@ See `org-link-parameters' for documentation on the other parameters."
|
|||
(org-unbracket-string "<" ">" s))
|
||||
(make-obsolete 'org-remove-angle-brackets 'org-unbracket-string "9.0")
|
||||
|
||||
(defcustom org-capture-bookmark t
|
||||
"When non-nil, add bookmark pointing at the last stored position when capturing."
|
||||
:group 'org-capture
|
||||
:version "24.3"
|
||||
:type 'boolean)
|
||||
(make-obsolete-variable
|
||||
'org-capture-bookmark
|
||||
"use `org-bookmark-names-plist' instead."
|
||||
"9.7")
|
||||
|
||||
(defcustom org-publish-sitemap-file-entry-format "%t"
|
||||
"Format string for site-map file entry.
|
||||
You could use brackets to delimit on what part the link will be.
|
||||
|
||||
%t is the title.
|
||||
%a is the author.
|
||||
%d is the date formatted using `org-publish-sitemap-date-format'."
|
||||
%d is the date."
|
||||
:group 'org-export-publish
|
||||
:type 'string)
|
||||
(make-obsolete-variable
|
||||
|
@ -881,21 +1051,21 @@ When optional argument ELEMENT is a parsed drawer, as returned by
|
|||
When buffer positions BEG and END are provided, hide or show that
|
||||
region as a drawer without further ado."
|
||||
(declare (obsolete "use `org-hide-drawer-toggle' instead." "9.4"))
|
||||
(if (and beg end) (org-fold-region beg end flag (if (eq org-fold-core-style 'text-properties) 'drawer 'outline))
|
||||
(if (and beg end) (org-fold-region beg end flag 'drawer)
|
||||
(let ((drawer
|
||||
(or element
|
||||
(and (save-excursion
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(looking-at-p "^[ \t]*:\\(\\(?:\\w\\|[-_]\\)+\\):[ \t]*$"))
|
||||
(org-element-at-point)))))
|
||||
(when (memq (org-element-type drawer) '(drawer property-drawer))
|
||||
(let ((post (org-element-property :post-affiliated drawer)))
|
||||
(when (org-element-type-p drawer '(drawer property-drawer))
|
||||
(let ((post (org-element-post-affiliated drawer)))
|
||||
(org-fold-region
|
||||
(save-excursion (goto-char post) (line-end-position))
|
||||
(save-excursion (goto-char (org-element-property :end drawer))
|
||||
(save-excursion (goto-char (org-element-end drawer))
|
||||
(skip-chars-backward " \t\n")
|
||||
(line-end-position))
|
||||
flag (if (eq org-fold-core-style 'text-properties) 'drawer 'outline))
|
||||
flag 'drawer)
|
||||
;; When the drawer is hidden away, make sure point lies in
|
||||
;; a visible part of the buffer.
|
||||
(when (invisible-p (max (1- (point)) (point-min)))
|
||||
|
@ -919,7 +1089,7 @@ an error. Return a non-nil value when toggling is successful."
|
|||
(goto-char start)
|
||||
(while (and (< (point) end)
|
||||
(re-search-forward "^[ \t]*#\\+begin_?\
|
||||
\\([^ \n]+\\)\\(\\([^\n]+\\)\\)?\n\\([^\000]+?\\)#\\+end_?\\1[ \t]*$" end t))
|
||||
\\([^ \n]+\\)\\(\\([^\n]+\\)\\)?\n\\(\\(?:.\\|\n\\)+?\\)#\\+end_?\\1[ \t]*$" end t))
|
||||
(save-excursion
|
||||
(save-match-data
|
||||
(goto-char (match-beginning 0))
|
||||
|
@ -1116,6 +1286,26 @@ context. See the individual commands for more information."
|
|||
(make-obsolete-variable 'org-latex-polyglossia-language-alist
|
||||
"set `org-latex-language-alist' instead." "9.6")
|
||||
|
||||
(defconst org-babel-python-mode 'python
|
||||
"Python mode for use in running python interactively.")
|
||||
|
||||
(make-obsolete-variable
|
||||
'org-babel-python-mode
|
||||
"Only the built-in Python mode is supported in ob-python now."
|
||||
"9.7")
|
||||
|
||||
(define-obsolete-function-alias 'ob-clojure-eval-with-babashka
|
||||
#'ob-clojure-eval-with-cmd "9.7")
|
||||
|
||||
(define-obsolete-function-alias 'org-export-get-parent
|
||||
'org-element-parent "9.7")
|
||||
(define-obsolete-function-alias 'org-export-get-parent-element
|
||||
'org-element-parent-element "9.7")
|
||||
|
||||
(define-obsolete-function-alias 'org-print-speed-command
|
||||
'org--print-speed-command "9.7"
|
||||
"Internal function. Subject of unannounced changes.")
|
||||
|
||||
;;;; Obsolete link types
|
||||
|
||||
(eval-after-load 'ol
|
||||
|
@ -1366,7 +1556,7 @@ ELEMENT is the element at point."
|
|||
;; Only in inline footnotes, within the definition.
|
||||
(and (eq (org-element-property :type object) 'inline)
|
||||
(< (save-excursion
|
||||
(goto-char (org-element-property :begin object))
|
||||
(goto-char (org-element-begin object))
|
||||
(search-forward ":" nil t 2))
|
||||
(point))))
|
||||
(otherwise t))))
|
||||
|
@ -1375,7 +1565,7 @@ ELEMENT is the element at point."
|
|||
"Function used for `flyspell-generic-check-word-predicate'."
|
||||
(if (org-at-heading-p)
|
||||
;; At a headline or an inlinetask, check title only.
|
||||
(and (save-excursion (beginning-of-line)
|
||||
(and (save-excursion (forward-line 0)
|
||||
(and (let ((case-fold-search t))
|
||||
(not (looking-at-p "\\*+ END[ \t]*$")))
|
||||
(let ((case-fold-search nil))
|
||||
|
@ -1387,19 +1577,19 @@ ELEMENT is the element at point."
|
|||
;; Ignore checks in code, verbatim and others.
|
||||
(org--flyspell-object-check-p (org-element-at-point-no-context)))
|
||||
(let* ((element (org-element-at-point-no-context))
|
||||
(post-affiliated (org-element-property :post-affiliated element)))
|
||||
(post-affiliated (org-element-post-affiliated element)))
|
||||
(cond
|
||||
;; Ignore checks in all affiliated keywords but captions.
|
||||
((< (point) post-affiliated)
|
||||
(and (save-excursion
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(let ((case-fold-search t)) (looking-at "[ \t]*#\\+CAPTION:")))
|
||||
(> (point) (match-end 0))
|
||||
(org--flyspell-object-check-p element)))
|
||||
;; Ignore checks in LOGBOOK (or equivalent) drawer.
|
||||
((let ((log (org-log-into-drawer)))
|
||||
(and log
|
||||
(let ((drawer (org-element-lineage element '(drawer))))
|
||||
(let ((drawer (org-element-lineage element 'drawer)))
|
||||
(and drawer
|
||||
(org-string-equal-ignore-case
|
||||
log (org-element-property :drawer-name drawer))))))
|
||||
|
@ -1413,7 +1603,7 @@ ELEMENT is the element at point."
|
|||
(save-excursion
|
||||
(end-of-line)
|
||||
(skip-chars-forward " \r\t\n")
|
||||
(< (point) (org-element-property :end element)))))
|
||||
(< (point) (org-element-end element)))))
|
||||
;; Arbitrary list of keywords where checks are meaningful.
|
||||
;; Make sure point is on the value part of the element.
|
||||
(keyword
|
||||
|
@ -1425,8 +1615,8 @@ ELEMENT is the element at point."
|
|||
;; table rows (after affiliated keywords) but some objects
|
||||
;; must not be affected.
|
||||
((paragraph table-row verse-block)
|
||||
(let ((cbeg (org-element-property :contents-begin element))
|
||||
(cend (org-element-property :contents-end element)))
|
||||
(let ((cbeg (org-element-contents-begin element))
|
||||
(cend (org-element-contents-end element)))
|
||||
(and cbeg (>= (point) cbeg) (< (point) cend)
|
||||
(org--flyspell-object-check-p element))))))))))
|
||||
(put 'org-mode 'flyspell-mode-predicate 'org-mode-flyspell-verify)
|
||||
|
@ -1561,7 +1751,7 @@ key."
|
|||
"Run `org-back-to-heading' when in org-mode."
|
||||
(if (derived-mode-p 'org-mode)
|
||||
(progn
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(or (org-at-heading-p (not invisible-ok))
|
||||
(let (found)
|
||||
(save-excursion
|
||||
|
|
|
@ -71,16 +71,18 @@
|
|||
(defvar epg-context)
|
||||
|
||||
(declare-function org-back-over-empty-lines "org" ())
|
||||
(declare-function org-current-level "org" ())
|
||||
(declare-function org-back-to-heading "org" (&optional invisible-ok))
|
||||
(declare-function org-before-first-heading-p "org" ())
|
||||
(declare-function org-end-of-meta-data "org" (&optional full))
|
||||
(declare-function org-end-of-subtree "org" (&optional invisible-ok to-heading))
|
||||
(declare-function org-end-of-subtree "org" (&optional invisible-ok to-heading element))
|
||||
(declare-function org-entry-get "org" (pom property &optional inherit literal-nil))
|
||||
(declare-function org-fold-subtree "org-fold" (flag))
|
||||
(declare-function org-make-tags-matcher "org" (match))
|
||||
(declare-function org-make-tags-matcher "org" (match &optional only-local-tags))
|
||||
(declare-function org-previous-visible-heading "org" (arg))
|
||||
(declare-function org-scan-tags "org" (action matcher todo-only &optional start-level))
|
||||
(declare-function org-set-property "org" (property value))
|
||||
(declare-function org-cycle-set-startup-visibility "org-cycle" ())
|
||||
|
||||
(defgroup org-crypt nil
|
||||
"Org Crypt."
|
||||
|
@ -113,16 +115,16 @@ This setting can be overridden in the CRYPTKEY property."
|
|||
(defcustom org-crypt-disable-auto-save 'ask
|
||||
"What org-decrypt should do if `auto-save-mode' is enabled.
|
||||
|
||||
t : Disable auto-save-mode for the current buffer
|
||||
t : Disable `auto-save-mode' for the current buffer
|
||||
prior to decrypting an entry.
|
||||
|
||||
nil : Leave auto-save-mode enabled.
|
||||
nil : Leave `auto-save-mode' enabled.
|
||||
This may cause data to be written to disk unencrypted!
|
||||
|
||||
`ask' : Ask user whether or not to disable auto-save-mode
|
||||
`ask' : Ask user whether or not to disable `auto-save-mode'
|
||||
for the current buffer.
|
||||
|
||||
`encrypt': Leave auto-save-mode enabled for the current buffer,
|
||||
`encrypt': Leave `auto-save-mode' enabled for the current buffer,
|
||||
but automatically re-encrypt all decrypted entries
|
||||
*before* auto-saving.
|
||||
NOTE: This only works for entries which have a tag
|
||||
|
@ -165,7 +167,7 @@ and END are buffer positions delimiting the encrypted area."
|
|||
(cons start (line-beginning-position 2)))))))))
|
||||
|
||||
(defun org-crypt-check-auto-save ()
|
||||
"Check whether auto-save-mode is enabled for the current buffer.
|
||||
"Check whether `auto-save-mode' is enabled for the current buffer.
|
||||
|
||||
`auto-save-mode' may cause leakage when decrypting entries, so
|
||||
check whether it's enabled, and decide what to do about it.
|
||||
|
@ -177,7 +179,7 @@ See `org-crypt-disable-auto-save'."
|
|||
(eq org-crypt-disable-auto-save t)
|
||||
(and
|
||||
(eq org-crypt-disable-auto-save 'ask)
|
||||
(y-or-n-p "org-decrypt: auto-save-mode may cause leakage. Disable it for current buffer? ")))
|
||||
(y-or-n-p "`org-decrypt': auto-save-mode may cause leakage. Disable it for current buffer? ")))
|
||||
(message "org-decrypt: Disabling auto-save-mode for %s"
|
||||
(or (buffer-file-name) (current-buffer)))
|
||||
;; The argument to auto-save-mode has to be "-1", since
|
||||
|
@ -244,12 +246,13 @@ Assume `epg-context' is set."
|
|||
;; contents in the buffer.
|
||||
(error
|
||||
(insert contents)
|
||||
(error (error-message-string err)))))
|
||||
(error "%s" (error-message-string err)))))
|
||||
(when folded-heading
|
||||
(goto-char folded-heading)
|
||||
(org-fold-subtree t))
|
||||
nil)))))
|
||||
|
||||
(defvar org-outline-regexp-bol)
|
||||
;;;###autoload
|
||||
(defun org-decrypt-entry ()
|
||||
"Decrypt the content of the current headline."
|
||||
|
@ -265,23 +268,44 @@ Assume `epg-context' is set."
|
|||
(save-excursion
|
||||
(org-previous-visible-heading 1)
|
||||
(point))))
|
||||
(level (org-current-level))
|
||||
(encrypted-text (org-crypt--encrypted-text beg end))
|
||||
(decrypted-text
|
||||
(decode-coding-string
|
||||
(epg-decrypt-string epg-context encrypted-text)
|
||||
'utf-8)))
|
||||
'utf-8))
|
||||
origin-marker)
|
||||
;; Delete region starting just before point, because the
|
||||
;; outline property starts at the \n of the heading.
|
||||
(delete-region (1- (point)) end)
|
||||
;; Store a checksum of the decrypted and the encrypted text
|
||||
;; value. This allows reusing the same encrypted text if the
|
||||
;; text does not change, and therefore avoid a re-encryption
|
||||
;; process.
|
||||
(insert "\n"
|
||||
(propertize decrypted-text
|
||||
'org-crypt-checksum (sha1 decrypted-text)
|
||||
'org-crypt-key (org-crypt-key-for-heading)
|
||||
'org-crypt-text encrypted-text))
|
||||
(setq origin-marker (point-marker))
|
||||
(if (string-match (org-headline-re level) decrypted-text)
|
||||
;; If decrypted text contains other headings with levels
|
||||
;; below LEVEL, adjust the subtree.
|
||||
(let ((start 0) (min-level level))
|
||||
(while (string-match (org-headline-re level) decrypted-text start)
|
||||
(setq min-level (min min-level (1- (length (match-string 0 decrypted-text))))
|
||||
start (match-end 0)))
|
||||
(insert "\n"
|
||||
(replace-regexp-in-string
|
||||
org-outline-regexp-bol
|
||||
(concat (make-string (1+ (- level min-level)) ?*) "\\&")
|
||||
decrypted-text)))
|
||||
;; Store a checksum of the decrypted and the encrypted text
|
||||
;; value. This allows reusing the same encrypted text if the
|
||||
;; text does not change, and therefore avoid a re-encryption
|
||||
;; process.
|
||||
(insert "\n"
|
||||
(propertize decrypted-text
|
||||
'org-crypt-checksum (sha1 decrypted-text)
|
||||
'org-crypt-key (org-crypt-key-for-heading)
|
||||
'org-crypt-text encrypted-text)))
|
||||
;; Apply initial visibility.
|
||||
(save-restriction
|
||||
(narrow-to-region origin-marker (point))
|
||||
(set-marker origin-marker nil)
|
||||
(org-cycle-set-startup-visibility))
|
||||
;; ... but keep the previous folded state.
|
||||
(when folded-heading
|
||||
(goto-char folded-heading)
|
||||
(org-fold-subtree t))
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
;;
|
||||
;; Allows Org mode to make use of the Emacs `etags' system. Defines
|
||||
;; tag destinations in Org files as any text between <<double angled
|
||||
;; brackets>>. This allows the tags-generation program `exuberant
|
||||
;; brackets>>. This allows the tags-generation program `exuberant
|
||||
;; ctags' to parse these files and create tag tables that record where
|
||||
;; these destinations are found. Plain [[links]] in org mode files
|
||||
;; which do not have <<matching destinations>> within the same file
|
||||
|
@ -57,6 +57,12 @@
|
|||
;; (add-hook 'org-mode-hook
|
||||
;; (lambda ()
|
||||
;; (define-key org-mode-map "\C-co" 'org-ctags-find-tag-interactive)))
|
||||
;; (with-eval-after-load "org-ctags"
|
||||
;; (org-ctags-enable))
|
||||
;;
|
||||
;; To activate the library, you need to call `org-ctags-enable' explicitly.
|
||||
;; It used to be invoked during library loading, but it was against Emacs
|
||||
;; policy and caused inconvenience of Org users who do not use `org-ctags'.
|
||||
;;
|
||||
;; By default, with org-ctags loaded, org will first try and visit the tag
|
||||
;; with the same name as the link; then, if unsuccessful, ask the user if
|
||||
|
@ -66,7 +72,7 @@
|
|||
;; search the entire text of the current buffer for 'tag'.
|
||||
;;
|
||||
;; This behavior can be modified by changing the value of
|
||||
;; ORG-CTAGS-OPEN-LINK-FUNCTIONS. For example I have the following in my
|
||||
;; ORG-CTAGS-OPEN-LINK-FUNCTIONS. For example, I have the following in my
|
||||
;; .emacs, which describes the same behavior as the above paragraph with
|
||||
;; one difference:
|
||||
;;
|
||||
|
@ -149,20 +155,36 @@
|
|||
(defvar org-ctags-enabled-p t
|
||||
"Activate ctags support in org mode?")
|
||||
|
||||
(defvar org-ctags-tag-regexp "/<<([^>]+)>>/\\1/d,definition/"
|
||||
(defvar org-ctags-tag-regexp "/<<([^<>]+)>>/\\1/d,definition/"
|
||||
"Regexp expression used by ctags external program.
|
||||
The regexp matches tag destinations in Org files.
|
||||
Format is: /REGEXP/TAGNAME/FLAGS,TAGTYPE/
|
||||
See the ctags documentation for more information.")
|
||||
|
||||
(defcustom org-ctags-path-to-ctags
|
||||
(if (executable-find "ctags-exuberant")
|
||||
"ctags-exuberant"
|
||||
ctags-program-name)
|
||||
(cond ((executable-find "ctags-exuberant")
|
||||
"ctags-exuberant")
|
||||
((boundp 'ctags-program-name)
|
||||
ctags-program-name)
|
||||
(t "ctags")) ; Emacs < 30
|
||||
"Name of the ctags executable file."
|
||||
:version "24.1"
|
||||
:type 'file)
|
||||
|
||||
(defconst org-ctags--open-link-functions-list
|
||||
(list
|
||||
#'org-ctags-find-tag
|
||||
#'org-ctags-ask-rebuild-tags-file-then-find-tag
|
||||
#'org-ctags-rebuild-tags-file-then-find-tag
|
||||
#'org-ctags-ask-append-topic
|
||||
#'org-ctags-append-topic
|
||||
#'org-ctags-ask-visit-buffer-or-file
|
||||
#'org-ctags-visit-buffer-or-file
|
||||
#'org-ctags-fail-silently)
|
||||
"Options for `org-open-link-functions'.
|
||||
Ensure that the user option and `unload-feature'
|
||||
use the same set of functions.")
|
||||
|
||||
(defcustom org-ctags-open-link-functions
|
||||
'(org-ctags-find-tag
|
||||
org-ctags-ask-rebuild-tags-file-then-find-tag
|
||||
|
@ -170,14 +192,7 @@ See the ctags documentation for more information.")
|
|||
"List of functions to be prepended to ORG-OPEN-LINK-FUNCTIONS by ORG-CTAGS."
|
||||
:version "24.1"
|
||||
:type 'hook
|
||||
:options '(org-ctags-find-tag
|
||||
org-ctags-ask-rebuild-tags-file-then-find-tag
|
||||
org-ctags-rebuild-tags-file-then-find-tag
|
||||
org-ctags-ask-append-topic
|
||||
org-ctags-append-topic
|
||||
org-ctags-ask-visit-buffer-or-file
|
||||
org-ctags-visit-buffer-or-file
|
||||
org-ctags-fail-silently))
|
||||
:options org-ctags--open-link-functions-list)
|
||||
|
||||
|
||||
(defvar org-ctags-tag-list nil
|
||||
|
@ -193,21 +208,21 @@ The following patterns are replaced in the string:
|
|||
:type 'string)
|
||||
|
||||
|
||||
(add-hook 'org-mode-hook
|
||||
(lambda ()
|
||||
(when (and org-ctags-enabled-p
|
||||
(buffer-file-name))
|
||||
;; Make sure this file's directory is added to default
|
||||
;; directories in which to search for tags.
|
||||
(let ((tags-filename
|
||||
(expand-file-name
|
||||
(concat (file-name-directory (buffer-file-name))
|
||||
"/TAGS"))))
|
||||
(when (file-exists-p tags-filename)
|
||||
(visit-tags-table tags-filename))))))
|
||||
(defun org-ctags--visit-tags-table ()
|
||||
"Load tags for current file.
|
||||
A function for `org-mode-hook."
|
||||
(when (and org-ctags-enabled-p
|
||||
(buffer-file-name))
|
||||
;; Make sure this file's directory is added to default
|
||||
;; directories in which to search for tags.
|
||||
(let ((tags-filename
|
||||
(expand-file-name
|
||||
(concat (file-name-directory (buffer-file-name))
|
||||
"/TAGS"))))
|
||||
(when (file-exists-p tags-filename)
|
||||
(visit-tags-table tags-filename)))))
|
||||
|
||||
|
||||
(advice-add 'visit-tags-table :after #'org--ctags-load-tag-list)
|
||||
(defun org--ctags-load-tag-list (&rest _)
|
||||
(when (and org-ctags-enabled-p tags-file-name)
|
||||
(setq-local org-ctags-tag-list
|
||||
|
@ -215,12 +230,28 @@ The following patterns are replaced in the string:
|
|||
|
||||
|
||||
(defun org-ctags-enable ()
|
||||
(add-hook 'org-mode-hook #'org-ctags--visit-tags-table)
|
||||
(advice-add 'visit-tags-table :after #'org--ctags-load-tag-list)
|
||||
(advice-add 'xref-find-definitions :before
|
||||
#'org--ctags-set-org-mark-before-finding-tag)
|
||||
|
||||
(put 'org-mode 'find-tag-default-function 'org-ctags-find-tag-at-point)
|
||||
(setq org-ctags-enabled-p t)
|
||||
(dolist (fn org-ctags-open-link-functions)
|
||||
(add-hook 'org-open-link-functions fn t)))
|
||||
|
||||
|
||||
(defun org-ctags-unload-function ()
|
||||
"Disable `org-ctags' library.
|
||||
Called by `unload-feature'."
|
||||
(put 'org-mode 'find-tag-default-function nil)
|
||||
(advice-remove 'visit-tags-table #'org--ctags-load-tag-list)
|
||||
(advice-remove 'xref-find-definitions
|
||||
#'org--ctags-set-org-mark-before-finding-tag)
|
||||
(dolist (fn org-ctags--open-link-functions-list)
|
||||
(remove-hook 'org-open-link-functions fn nil)))
|
||||
|
||||
|
||||
;;; General utility functions. ===============================================
|
||||
;; These work outside org-ctags mode.
|
||||
|
||||
|
@ -296,8 +327,6 @@ The new topic will be titled NAME (or TITLE if supplied)."
|
|||
;;;; Misc interoperability with etags system =================================
|
||||
|
||||
|
||||
(advice-add 'xref-find-definitions :before
|
||||
#'org--ctags-set-org-mark-before-finding-tag)
|
||||
(defun org--ctags-set-org-mark-before-finding-tag (&rest _)
|
||||
"Before trying to find a tag, save our current position on org mark ring."
|
||||
(save-excursion
|
||||
|
@ -479,18 +508,21 @@ function may take several seconds to finish if the directory or
|
|||
its subdirectories contain large numbers of taggable files."
|
||||
(interactive)
|
||||
(cl-assert (buffer-file-name))
|
||||
(let ((dir-name (or directory-name
|
||||
(file-name-directory (buffer-file-name))))
|
||||
(let ((dir-name (shell-quote-argument
|
||||
(expand-file-name
|
||||
(if directory-name
|
||||
(file-name-as-directory directory-name)
|
||||
(file-name-directory (buffer-file-name))))))
|
||||
(exitcode nil))
|
||||
(save-excursion
|
||||
(setq exitcode
|
||||
(shell-command
|
||||
(format (concat "%s --langdef=orgmode --langmap=orgmode:.org "
|
||||
"--regex-orgmode=\"%s\" -f \"%s\" -e -R \"%s\"")
|
||||
"--regex-orgmode=%s -f %sTAGS -e -R %s*")
|
||||
org-ctags-path-to-ctags
|
||||
org-ctags-tag-regexp
|
||||
(expand-file-name (concat dir-name "/TAGS"))
|
||||
(expand-file-name (concat dir-name "/*")))))
|
||||
(shell-quote-argument org-ctags-tag-regexp)
|
||||
dir-name
|
||||
dir-name)))
|
||||
(cond
|
||||
((eql 0 exitcode)
|
||||
(setq-local org-ctags-tag-list
|
||||
|
@ -508,12 +540,11 @@ its subdirectories contain large numbers of taggable files."
|
|||
|
||||
(defun org-ctags-find-tag-interactive ()
|
||||
"Prompt for the name of a tag, with autocompletion, then visit the named tag.
|
||||
Uses `ido-mode' if available.
|
||||
If the user enters a string that does not match an existing tag, create
|
||||
a new topic."
|
||||
(interactive)
|
||||
(let* ((tag (ido-completing-read "Topic: " org-ctags-tag-list
|
||||
nil 'confirm nil 'org-ctags-find-tag-history)))
|
||||
(let* ((tag (completing-read "Topic: " org-ctags-tag-list
|
||||
nil 'confirm nil 'org-ctags-find-tag-history)))
|
||||
(when tag
|
||||
(cond
|
||||
((member tag org-ctags-tag-list)
|
||||
|
@ -526,8 +557,6 @@ a new topic."
|
|||
'org-open-link-functions tag))))))
|
||||
|
||||
|
||||
(org-ctags-enable)
|
||||
|
||||
(provide 'org-ctags)
|
||||
|
||||
;;; org-ctags.el ends here
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
;;
|
||||
;; Copyright (C) 2020-2024 Free Software Foundation, Inc.
|
||||
;;
|
||||
;; Maintainer: Ihor Radchenko <yantar92 at gmail dot com>
|
||||
;; Maintainer: Ihor Radchenko <yantar92 at posteo dot net>
|
||||
;; Keywords: folding, visibility cycling, invisible text
|
||||
;; URL: https://orgmode.org
|
||||
;;
|
||||
|
@ -35,9 +35,10 @@
|
|||
(require 'org-macs)
|
||||
(require 'org-fold)
|
||||
|
||||
(declare-function org-element-type "org-element" (element))
|
||||
(declare-function org-element-property "org-element" (property element))
|
||||
(declare-function org-element-lineage "org-element" (datum &optional types with-self))
|
||||
(declare-function org-element-type-p "org-element-ast" (node types))
|
||||
(declare-function org-element-property "org-element-ast" (property node))
|
||||
(declare-function org-element-post-affiliated "org-element" (node))
|
||||
(declare-function org-element-lineage "org-element-ast" (datum &optional types with-self))
|
||||
(declare-function org-element-at-point "org-element" (&optional pom cached-only))
|
||||
(declare-function org-display-inline-images "org" (&optional include-linked refresh beg end))
|
||||
(declare-function org-get-tags "org" (&optional pos local fontify))
|
||||
|
@ -115,6 +116,7 @@ than its value."
|
|||
(const :tag "No limit" nil)
|
||||
(integer :tag "Maximum level")))
|
||||
|
||||
(defvaralias 'org-hide-block-startup 'org-cycle-hide-block-startup)
|
||||
(defcustom org-cycle-hide-block-startup nil
|
||||
"Non-nil means entering Org mode will fold all blocks.
|
||||
This can also be set in on a per-file basis with
|
||||
|
@ -125,6 +127,7 @@ This can also be set in on a per-file basis with
|
|||
:group 'org-cycle
|
||||
:type 'boolean)
|
||||
|
||||
(defvaralias 'org-hide-drawer-startup 'org-cycle-hide-drawer-startup)
|
||||
(defcustom org-cycle-hide-drawer-startup t
|
||||
"Non-nil means entering Org mode will fold all drawers.
|
||||
This can also be set in on a per-file basis with
|
||||
|
@ -200,6 +203,7 @@ Special case: when 0, never leave empty lines in collapsed view."
|
|||
:type 'integer)
|
||||
(put 'org-cycle-separator-lines 'safe-local-variable 'integerp)
|
||||
|
||||
(defvaralias 'org-pre-cycle-hook 'org-cycle-pre-hook)
|
||||
(defcustom org-cycle-pre-hook nil
|
||||
"Hook that is run before visibility cycling is happening.
|
||||
The function(s) in this hook must accept a single argument which indicates
|
||||
|
@ -240,6 +244,7 @@ normal outline commands like `show-all', but not with the cycling commands."
|
|||
:package-version '(Org . "9.6")
|
||||
:type 'boolean)
|
||||
|
||||
(defvaralias 'org-tab-first-hook 'org-cycle-tab-first-hook)
|
||||
(defvar org-cycle-tab-first-hook nil
|
||||
"Hook for functions to attach themselves to TAB.
|
||||
See `org-ctrl-c-ctrl-c-hook' for more information.
|
||||
|
@ -335,6 +340,10 @@ same as `S-TAB') also when called without prefix argument."
|
|||
(and org-cycle-level-after-item/entry-creation
|
||||
(or (org-cycle-level)
|
||||
(org-cycle-item-indentation))))
|
||||
(when (and org-cycle-max-level
|
||||
(or (not (integerp org-cycle-max-level))
|
||||
(< org-cycle-max-level 1)))
|
||||
(user-error "`org-cycle-max-level' must be a positive integer"))
|
||||
(let* ((limit-level
|
||||
(or org-cycle-max-level
|
||||
(and (boundp 'org-inlinetask-min-level)
|
||||
|
@ -388,8 +397,8 @@ same as `S-TAB') also when called without prefix argument."
|
|||
((org-fold-hide-drawer-toggle nil t element))
|
||||
;; Table: enter it or move to the next field.
|
||||
((and (org-match-line "[ \t]*[|+]")
|
||||
(org-element-lineage element '(table) t))
|
||||
(if (and (eq 'table (org-element-type element))
|
||||
(org-element-lineage element 'table t))
|
||||
(if (and (org-element-type-p element 'table)
|
||||
(eq 'table.el (org-element-property :type element)))
|
||||
(message (substitute-command-keys "\\<org-mode-map>\
|
||||
Use `\\[org-edit-special]' to edit table.el tables"))
|
||||
|
@ -404,8 +413,8 @@ Use `\\[org-edit-special]' to edit table.el tables"))
|
|||
t)))
|
||||
(and item
|
||||
(= (line-beginning-position)
|
||||
(org-element-property :post-affiliated
|
||||
item)))))
|
||||
(org-element-post-affiliated
|
||||
item)))))
|
||||
(org-match-line org-outline-regexp))
|
||||
(or (bolp) (not (eq org-cycle-emulate-tab 'exc-hl-bol))))
|
||||
(org-cycle-internal-local))
|
||||
|
@ -421,7 +430,7 @@ Use `\\[org-edit-special]' to edit table.el tables"))
|
|||
(call-interactively (global-key-binding (kbd "TAB"))))
|
||||
((or (eq org-cycle-emulate-tab t)
|
||||
(and (memq org-cycle-emulate-tab '(white whitestart))
|
||||
(save-excursion (beginning-of-line 1) (looking-at "[ \t]*"))
|
||||
(save-excursion (forward-line 0) (looking-at "[ \t]*"))
|
||||
(or (and (eq org-cycle-emulate-tab 'white)
|
||||
(= (match-end 0) (line-end-position)))
|
||||
(and (eq org-cycle-emulate-tab 'whitestart)
|
||||
|
@ -480,7 +489,7 @@ Use `\\[org-edit-special]' to edit table.el tables"))
|
|||
(save-excursion
|
||||
(if (org-at-item-p)
|
||||
(progn
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(setq struct (org-list-struct))
|
||||
(setq eoh (line-end-position))
|
||||
(setq eos (org-list-get-item-end-before-blank (point) struct))
|
||||
|
@ -502,16 +511,16 @@ Use `\\[org-edit-special]' to edit table.el tables"))
|
|||
(save-excursion
|
||||
(org-list-search-forward (org-item-beginning-re) eos t))))))
|
||||
;; Determine end invisible part of buffer (EOL)
|
||||
(beginning-of-line 2)
|
||||
(forward-line 1)
|
||||
(if (eq org-fold-core-style 'text-properties)
|
||||
(while (and (not (eobp)) ;this is like `next-line'
|
||||
(org-fold-folded-p (1- (point))))
|
||||
(goto-char (org-fold-next-visibility-change nil nil t))
|
||||
(and (eolp) (beginning-of-line 2)))
|
||||
(and (eolp) (forward-line 1)))
|
||||
(while (and (not (eobp)) ;this is like `next-line'
|
||||
(get-char-property (1- (point)) 'invisible))
|
||||
(goto-char (next-single-char-property-change (point) 'invisible))
|
||||
(and (eolp) (beginning-of-line 2))))
|
||||
(and (eolp) (forward-line 1))))
|
||||
(setq eol (point)))
|
||||
;; Find out what to do next and set `this-command'
|
||||
(cond
|
||||
|
@ -545,7 +554,7 @@ Use `\\[org-edit-special]' to edit table.el tables"))
|
|||
(save-excursion
|
||||
(org-back-to-heading)
|
||||
(while (org-list-search-forward (org-item-beginning-re) eos t)
|
||||
(beginning-of-line 1)
|
||||
(forward-line 0)
|
||||
(let* ((struct (org-list-struct))
|
||||
(prevs (org-list-prevs-alist struct))
|
||||
(end (org-list-get-bottom-point struct)))
|
||||
|
@ -608,7 +617,9 @@ With a numeric prefix, show all headlines up to that level."
|
|||
(defun org-cycle-set-startup-visibility ()
|
||||
"Set the visibility required by startup options and properties."
|
||||
(cond
|
||||
((eq org-startup-folded t)
|
||||
;; `fold' is technically not allowed value, but it is often
|
||||
;; intuitively tried by users by analogy with #+STARTUP: fold.
|
||||
((memq org-startup-folded '(t fold overview))
|
||||
(org-cycle-overview))
|
||||
((eq org-startup-folded 'content)
|
||||
(org-cycle-content))
|
||||
|
@ -620,8 +631,10 @@ With a numeric prefix, show all headlines up to that level."
|
|||
(org-cycle-content 4))
|
||||
((eq org-startup-folded 'show5levels)
|
||||
(org-cycle-content 5))
|
||||
((or (eq org-startup-folded 'showeverything)
|
||||
(eq org-startup-folded nil))
|
||||
;; `nofold' and `showall' are technically not allowed values, but
|
||||
;; they are often intuitively tried by users by analogy with
|
||||
;; #+STARTUP: nofold or #STARUP: showall.
|
||||
((memq org-startup-folded '(showeverything nil nofold showall))
|
||||
(org-fold-show-all)))
|
||||
(unless (eq org-startup-folded 'showeverything)
|
||||
(when org-cycle-hide-block-startup (org-fold-hide-block-all))
|
||||
|
@ -634,20 +647,21 @@ With a numeric prefix, show all headlines up to that level."
|
|||
"Switch subtree visibility according to VISIBILITY property."
|
||||
(interactive)
|
||||
(let ((regexp (org-re-property "VISIBILITY")))
|
||||
(org-with-point-at 1
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward regexp nil t)
|
||||
(let ((state (match-string 3)))
|
||||
(let ((state (match-string 3)))
|
||||
(if (not (org-at-property-p)) (outline-next-heading)
|
||||
(save-excursion
|
||||
(org-back-to-heading t)
|
||||
(org-fold-subtree t)
|
||||
(pcase state
|
||||
("folded"
|
||||
("folded"
|
||||
(org-fold-subtree t))
|
||||
("children"
|
||||
("children"
|
||||
(org-fold-show-hidden-entry)
|
||||
(org-fold-show-children))
|
||||
("content"
|
||||
("content"
|
||||
;; Newline before heading will be outside the
|
||||
;; narrowing. Make sure that it is revealed.
|
||||
(org-fold-heading nil)
|
||||
|
@ -655,10 +669,9 @@ With a numeric prefix, show all headlines up to that level."
|
|||
(save-restriction
|
||||
(org-narrow-to-subtree)
|
||||
(org-cycle-content))))
|
||||
((or "all" "showall")
|
||||
((or "all" "showall")
|
||||
(org-fold-show-subtree))
|
||||
(_ nil)))
|
||||
(org-end-of-subtree)))))))
|
||||
(_ nil)))))))))
|
||||
|
||||
(defun org-cycle-overview ()
|
||||
"Switch to overview mode, showing only top-level headlines."
|
||||
|
@ -683,7 +696,7 @@ With a numeric prefix, show all headlines up to that level."
|
|||
|
||||
(defun org-cycle-content (&optional arg)
|
||||
"Show all headlines in the buffer, like a table of contents.
|
||||
With numerical argument N, show content up to level N."
|
||||
With numerical argument ARG, show content up to level ARG."
|
||||
(interactive "p")
|
||||
(org-fold-show-all '(headings))
|
||||
(save-excursion
|
||||
|
@ -705,7 +718,9 @@ With numerical argument N, show content up to level N."
|
|||
"Temporarily store scroll position to restore.")
|
||||
(defun org-cycle-optimize-window-after-visibility-change (state)
|
||||
"Adjust the window after a change in outline visibility.
|
||||
This function is the default value of the hook `org-cycle-hook'."
|
||||
This function is the default value of the hook `org-cycle-hook'.
|
||||
STATE is the current outline visibility state. It should be one of
|
||||
symbols `content', `all', `folded', `children', or `subtree'."
|
||||
(when (get-buffer-window (current-buffer))
|
||||
(let ((repeat (eq last-command this-command)))
|
||||
(unless repeat
|
||||
|
@ -791,7 +806,9 @@ STATE should be one of the symbols listed in the docstring of
|
|||
|
||||
(defun org-cycle-display-inline-images (state)
|
||||
"Auto display inline images under subtree when cycling.
|
||||
It works when `org-cycle-inline-images-display' is non-nil."
|
||||
It works when `org-cycle-inline-images-display' is non-nil.
|
||||
STATE is the current outline visibility state. It should be one of
|
||||
symbols `content', `all', `folded', `children', or `subtree'."
|
||||
(when org-cycle-inline-images-display
|
||||
(pcase state
|
||||
('children
|
||||
|
|
|
@ -99,16 +99,15 @@ If time-period is month, then group entries by month."
|
|||
(month (calendar-extract-month d))
|
||||
(day (calendar-extract-day d)))
|
||||
(org-datetree--find-create
|
||||
"^\\*+[ \t]+\\([12][0-9]\\{3\\}\\)\\(\\s-*?\
|
||||
\\([ \t]:[[:alnum:]:_@#%%]+:\\)?\\s-*$\\)"
|
||||
year)
|
||||
"\\([12][0-9]\\{3\\}\\)"
|
||||
year nil nil nil t)
|
||||
(org-datetree--find-create
|
||||
"^\\*+[ \t]+%d-\\([01][0-9]\\) \\w+$"
|
||||
year month)
|
||||
"%d-\\([01][0-9]\\) \\w+"
|
||||
year month nil nil t)
|
||||
(when (eq time-grouping 'day)
|
||||
(org-datetree--find-create
|
||||
"^\\*+[ \t]+%d-%02d-\\([0123][0-9]\\) \\w+$"
|
||||
year month day)))))
|
||||
"%d-%02d-\\([0123][0-9]\\) \\w+"
|
||||
year month day nil t)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-datetree-find-iso-week-create (d &optional keep-restriction)
|
||||
|
@ -147,33 +146,51 @@ will be built under the headline at point."
|
|||
(week (nth 0 iso-date)))
|
||||
;; ISO 8601 week format is %G-W%V(-%u)
|
||||
(org-datetree--find-create
|
||||
"^\\*+[ \t]+\\([12][0-9]\\{3\\}\\)\\(\\s-*?\
|
||||
\\([ \t]:[[:alnum:]:_@#%%]+:\\)?\\s-*$\\)"
|
||||
weekyear nil nil
|
||||
(format-time-string "%G" time))
|
||||
"\\([12][0-9]\\{3\\}\\)"
|
||||
weekyear nil nil (format-time-string "%G" time) t)
|
||||
(org-datetree--find-create
|
||||
"^\\*+[ \t]+%d-W\\([0-5][0-9]\\)$"
|
||||
weekyear week nil
|
||||
(format-time-string "%G-W%V" time))
|
||||
"%d-W\\([0-5][0-9]\\)"
|
||||
weekyear week nil (format-time-string "%G-W%V" time) t)
|
||||
;; For the actual day we use the regular date instead of ISO week.
|
||||
(org-datetree--find-create
|
||||
"^\\*+[ \t]+%d-%02d-\\([0123][0-9]\\) \\w+$"
|
||||
year month day))))
|
||||
"%d-%02d-\\([0123][0-9]\\) \\w+" year month day nil t))))
|
||||
|
||||
(defun org-datetree--find-create
|
||||
(regex-template year &optional month day insert)
|
||||
(regex-template year &optional month day insert match-title)
|
||||
"Find the datetree matched by REGEX-TEMPLATE for YEAR, MONTH, or DAY.
|
||||
REGEX-TEMPLATE is passed to `format' with YEAR, MONTH, and DAY as
|
||||
arguments. Match group 1 is compared against the specified date
|
||||
arguments.
|
||||
|
||||
If MATCH-TITLE is non-nil, REGEX-TEMPLATE is matched against
|
||||
heading title and the exact regexp matched against heading line is:
|
||||
|
||||
(format org-complex-heading-regexp-format
|
||||
(format regex-template year month day))
|
||||
|
||||
If MATCH-TITLE is nil, the regexp matched against heading line is
|
||||
REGEX-TEMPLATE:
|
||||
|
||||
(format regex-template year month day)
|
||||
|
||||
Match group 1 in REGEX-TEMPLATE is compared against the specified date
|
||||
component. If INSERT is non-nil and there is no match then it is
|
||||
inserted into the buffer."
|
||||
(when (or month day)
|
||||
(org-narrow-to-subtree))
|
||||
(let ((re (format regex-template year month day))
|
||||
;; ensure that the first match group in REGEX-TEMPLATE
|
||||
;; is the first inside `org-complex-heading-regexp-format'
|
||||
(when (and match-title
|
||||
(not (string-match-p "\\\\(\\?1:" regex-template))
|
||||
(string-match "\\\\(" regex-template))
|
||||
(setq regex-template (replace-match "\\(?1:" nil t regex-template)))
|
||||
(let ((re (if match-title
|
||||
(format org-complex-heading-regexp-format
|
||||
(format regex-template year month day))
|
||||
(format regex-template year month day)))
|
||||
match)
|
||||
(goto-char (point-min))
|
||||
(while (and (setq match (re-search-forward re nil t))
|
||||
(goto-char (match-beginning 1))
|
||||
(goto-char (match-beginning 1))
|
||||
(< (string-to-number (match-string 1)) (or day month year))))
|
||||
(cond
|
||||
((not match)
|
||||
|
@ -181,9 +198,9 @@ inserted into the buffer."
|
|||
(unless (bolp) (insert "\n"))
|
||||
(org-datetree-insert-line year month day insert))
|
||||
((= (string-to-number (match-string 1)) (or day month year))
|
||||
(beginning-of-line))
|
||||
(forward-line 0))
|
||||
(t
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(org-datetree-insert-line year month day insert)))))
|
||||
|
||||
(defun org-datetree-insert-line (year &optional month day text)
|
||||
|
@ -205,11 +222,11 @@ inserted into the buffer."
|
|||
(save-excursion
|
||||
(insert "\n")
|
||||
(org-indent-line)
|
||||
(org-insert-time-stamp
|
||||
(org-insert-timestamp
|
||||
(org-encode-time 0 0 0 day month year)
|
||||
nil
|
||||
(eq org-datetree-add-timestamp 'inactive))))
|
||||
(beginning-of-line))
|
||||
(forward-line 0))
|
||||
|
||||
(defun org-datetree-file-entry-under (txt d)
|
||||
"Insert a node TXT into the date tree under date D."
|
||||
|
|
|
@ -324,109 +324,110 @@ When optional argument CANONICAL is non-nil, ignore
|
|||
`org-duration-units' and use standard time units value.
|
||||
|
||||
Raise an error if expected format is unknown."
|
||||
(pcase (or fmt org-duration-format)
|
||||
(`h:mm
|
||||
(format "%d:%02d" (/ minutes 60) (mod minutes 60)))
|
||||
(`h:mm:ss
|
||||
(let* ((whole-minutes (floor minutes))
|
||||
(seconds (mod (* 60 minutes) 60)))
|
||||
(format "%s:%02d"
|
||||
(org-duration-from-minutes whole-minutes 'h:mm)
|
||||
seconds)))
|
||||
((pred atom) (error "Invalid duration format specification: %S" fmt))
|
||||
;; Mixed format. Call recursively the function on both parts.
|
||||
((and duration-format
|
||||
(let `(special . ,(and mode (or `h:mm:ss `h:mm)))
|
||||
(assq 'special duration-format)))
|
||||
(let* ((truncated-format
|
||||
;; Remove "special" mode from duration format in order to
|
||||
;; recurse properly. Also remove units smaller or equal
|
||||
;; to an hour since H:MM part takes care of it.
|
||||
(cl-remove-if-not
|
||||
(lambda (pair)
|
||||
(pcase pair
|
||||
(`(,(and unit (pred stringp)) . ,_)
|
||||
(> (org-duration--modifier unit canonical) 60))
|
||||
(_ nil)))
|
||||
duration-format))
|
||||
(min-modifier ;smallest modifier above hour
|
||||
(and truncated-format
|
||||
(apply #'min
|
||||
(mapcar (lambda (p)
|
||||
(org-duration--modifier (car p) canonical))
|
||||
truncated-format)))))
|
||||
(if (or (null min-modifier) (< minutes min-modifier))
|
||||
;; There is not unit above the hour or the smallest unit
|
||||
;; above the hour is too large for the number of minutes we
|
||||
;; need to represent. Use H:MM or H:MM:SS syntax.
|
||||
(org-duration-from-minutes minutes mode canonical)
|
||||
;; Represent minutes above hour using provided units and H:MM
|
||||
;; or H:MM:SS below.
|
||||
(let* ((units-part (* min-modifier (/ (floor minutes) min-modifier)))
|
||||
(minutes-part (- minutes units-part))
|
||||
(compact (memq 'compact duration-format)))
|
||||
(concat
|
||||
(org-duration-from-minutes units-part truncated-format canonical)
|
||||
(and (not compact) " ")
|
||||
(org-duration-from-minutes minutes-part mode))))))
|
||||
;; Units format.
|
||||
(duration-format
|
||||
(let* ((fractional
|
||||
(let ((digits (cdr (assq 'special duration-format))))
|
||||
(and digits
|
||||
(or (wholenump digits)
|
||||
(error "Unknown formatting directive: %S" digits))
|
||||
(format "%%.%df" digits))))
|
||||
(selected-units
|
||||
(sort (cl-remove-if
|
||||
;; Ignore special format cells and compact option.
|
||||
(lambda (pair)
|
||||
(pcase pair
|
||||
((or `compact `(special . ,_)) t)
|
||||
(_ nil)))
|
||||
duration-format)
|
||||
(lambda (a b)
|
||||
(> (org-duration--modifier (car a) canonical)
|
||||
(org-duration--modifier (car b) canonical)))))
|
||||
(separator (if (memq 'compact duration-format) "" " ")))
|
||||
(cond
|
||||
;; Fractional duration: use first unit that is either required
|
||||
;; or smaller than MINUTES.
|
||||
(fractional
|
||||
(let* ((unit (car
|
||||
(or (cl-find-if
|
||||
(lambda (pair)
|
||||
(pcase pair
|
||||
(`(,u . ,req?)
|
||||
(or req?
|
||||
(<= (org-duration--modifier u canonical)
|
||||
minutes)))))
|
||||
selected-units)
|
||||
;; Fall back to smallest unit.
|
||||
(org-last selected-units))))
|
||||
(modifier (org-duration--modifier unit canonical)))
|
||||
(concat (format fractional (/ (float minutes) modifier)) unit)))
|
||||
;; Otherwise build duration string according to available
|
||||
;; units.
|
||||
((org-string-nw-p
|
||||
(org-trim
|
||||
(mapconcat
|
||||
(lambda (units)
|
||||
(pcase-let* ((`(,unit . ,required?) units)
|
||||
(modifier (org-duration--modifier unit canonical)))
|
||||
(cond ((<= modifier minutes)
|
||||
(let ((value (floor minutes modifier)))
|
||||
(cl-decf minutes (* value modifier))
|
||||
(format "%s%d%s" separator value unit)))
|
||||
(required? (concat separator "0" unit))
|
||||
(t ""))))
|
||||
selected-units
|
||||
""))))
|
||||
;; No unit can properly represent MINUTES. Use the smallest
|
||||
;; one anyway.
|
||||
(t
|
||||
(pcase-let ((`((,unit . ,_)) (last selected-units)))
|
||||
(concat "0" unit))))))))
|
||||
(if (< minutes 0) (concat "-" (org-duration-from-minutes (abs minutes) fmt canonical))
|
||||
(pcase (or fmt org-duration-format)
|
||||
(`h:mm
|
||||
(format "%d:%02d" (/ minutes 60) (mod minutes 60)))
|
||||
(`h:mm:ss
|
||||
(let* ((whole-minutes (floor minutes))
|
||||
(seconds (mod (* 60 minutes) 60)))
|
||||
(format "%s:%02d"
|
||||
(org-duration-from-minutes whole-minutes 'h:mm)
|
||||
seconds)))
|
||||
((pred atom) (error "Invalid duration format specification: %S" fmt))
|
||||
;; Mixed format. Call recursively the function on both parts.
|
||||
((and duration-format
|
||||
(let `(special . ,(and mode (or `h:mm:ss `h:mm)))
|
||||
(assq 'special duration-format)))
|
||||
(let* ((truncated-format
|
||||
;; Remove "special" mode from duration format in order to
|
||||
;; recurse properly. Also remove units smaller or equal
|
||||
;; to an hour since H:MM part takes care of it.
|
||||
(cl-remove-if-not
|
||||
(lambda (pair)
|
||||
(pcase pair
|
||||
(`(,(and unit (pred stringp)) . ,_)
|
||||
(> (org-duration--modifier unit canonical) 60))
|
||||
(_ nil)))
|
||||
duration-format))
|
||||
(min-modifier ;smallest modifier above hour
|
||||
(and truncated-format
|
||||
(apply #'min
|
||||
(mapcar (lambda (p)
|
||||
(org-duration--modifier (car p) canonical))
|
||||
truncated-format)))))
|
||||
(if (or (null min-modifier) (< minutes min-modifier))
|
||||
;; There is not unit above the hour or the smallest unit
|
||||
;; above the hour is too large for the number of minutes we
|
||||
;; need to represent. Use H:MM or H:MM:SS syntax.
|
||||
(org-duration-from-minutes minutes mode canonical)
|
||||
;; Represent minutes above hour using provided units and H:MM
|
||||
;; or H:MM:SS below.
|
||||
(let* ((units-part (* min-modifier (/ (floor minutes) min-modifier)))
|
||||
(minutes-part (- minutes units-part))
|
||||
(compact (memq 'compact duration-format)))
|
||||
(concat
|
||||
(org-duration-from-minutes units-part truncated-format canonical)
|
||||
(and (not compact) " ")
|
||||
(org-duration-from-minutes minutes-part mode))))))
|
||||
;; Units format.
|
||||
(duration-format
|
||||
(let* ((fractional
|
||||
(let ((digits (cdr (assq 'special duration-format))))
|
||||
(and digits
|
||||
(or (wholenump digits)
|
||||
(error "Unknown formatting directive: %S" digits))
|
||||
(format "%%.%df" digits))))
|
||||
(selected-units
|
||||
(sort (cl-remove-if
|
||||
;; Ignore special format cells and compact option.
|
||||
(lambda (pair)
|
||||
(pcase pair
|
||||
((or `compact `(special . ,_)) t)
|
||||
(_ nil)))
|
||||
duration-format)
|
||||
(lambda (a b)
|
||||
(> (org-duration--modifier (car a) canonical)
|
||||
(org-duration--modifier (car b) canonical)))))
|
||||
(separator (if (memq 'compact duration-format) "" " ")))
|
||||
(cond
|
||||
;; Fractional duration: use first unit that is either required
|
||||
;; or smaller than MINUTES.
|
||||
(fractional
|
||||
(let* ((unit (car
|
||||
(or (cl-find-if
|
||||
(lambda (pair)
|
||||
(pcase pair
|
||||
(`(,u . ,req?)
|
||||
(or req?
|
||||
(<= (org-duration--modifier u canonical)
|
||||
minutes)))))
|
||||
selected-units)
|
||||
;; Fall back to smallest unit.
|
||||
(org-last selected-units))))
|
||||
(modifier (org-duration--modifier unit canonical)))
|
||||
(concat (format fractional (/ (float minutes) modifier)) unit)))
|
||||
;; Otherwise build duration string according to available
|
||||
;; units.
|
||||
((org-string-nw-p
|
||||
(org-trim
|
||||
(mapconcat
|
||||
(lambda (units)
|
||||
(pcase-let* ((`(,unit . ,required?) units)
|
||||
(modifier (org-duration--modifier unit canonical)))
|
||||
(cond ((<= modifier minutes)
|
||||
(let ((value (floor minutes modifier)))
|
||||
(cl-decf minutes (* value modifier))
|
||||
(format "%s%d%s" separator value unit)))
|
||||
(required? (concat separator "0" unit))
|
||||
(t ""))))
|
||||
selected-units
|
||||
""))))
|
||||
;; No unit can properly represent MINUTES. Use the smallest
|
||||
;; one anyway.
|
||||
(t
|
||||
(pcase-let ((`((,unit . ,_)) (last selected-units)))
|
||||
(concat "0" unit)))))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-duration-h:mm-only-p (times)
|
||||
|
|
1150
lisp/org/org-element-ast.el
Normal file
1150
lisp/org/org-element-ast.el
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -29,6 +29,7 @@
|
|||
|
||||
(require 'org-macs)
|
||||
(org-assert-version)
|
||||
(require 'seq) ; Emacs 27 does not preload seq.el; for `seq-every-p'.
|
||||
|
||||
(declare-function org-mode "org" ())
|
||||
(declare-function org-toggle-pretty-entities "org" ())
|
||||
|
@ -277,8 +278,10 @@ packages to be loaded, add these packages to `org-latex-packages-alist'."
|
|||
("vert" "\\vert{}" t "|" "|" "|" "|")
|
||||
("vbar" "|" nil "|" "|" "|" "|")
|
||||
("brvbar" "\\textbrokenbar{}" nil "¦" "|" "¦" "¦")
|
||||
("S" "\\S" nil "§" "paragraph" "§" "§")
|
||||
("sect" "\\S" nil "§" "paragraph" "§" "§")
|
||||
("S" "\\S" nil "§" "section" "§" "§")
|
||||
("sect" "\\S" nil "§" "section" "§" "§")
|
||||
("P" "\\P{}" nil "¶" "paragraph" "¶" "¶")
|
||||
("para" "\\P{}" nil "¶" "paragraph" "¶" "¶")
|
||||
("amp" "\\&" nil "&" "&" "&" "&")
|
||||
("lt" "\\textless{}" nil "<" "<" "<" "<")
|
||||
("gt" "\\textgreater{}" nil ">" ">" ">" ">")
|
||||
|
@ -494,7 +497,6 @@ packages to be loaded, add these packages to `org-latex-packages-alist'."
|
|||
("checkmark" "\\checkmark" t "✓" "[checkmark]" "[checkmark]" "✓")
|
||||
|
||||
"** Miscellaneous (seldom used)"
|
||||
("para" "\\P{}" nil "¶" "[pilcrow]" "¶" "¶")
|
||||
("ordf" "\\textordfeminine{}" nil "ª" "_a_" "ª" "ª")
|
||||
("ordm" "\\textordmasculine{}" nil "º" "_o_" "º" "º")
|
||||
("cedil" "\\c{}" nil "¸" "[cedilla]" "¸" "¸")
|
||||
|
|
|
@ -389,6 +389,10 @@ changes."
|
|||
"Face used for tables."
|
||||
:group 'org-faces)
|
||||
|
||||
(defface org-table-row '((t :inherit org-table))
|
||||
"Face used to fontify whole table rows (including newlines and indentation)."
|
||||
:group 'org-faces)
|
||||
|
||||
(defface org-table-header '((t :inherit org-table
|
||||
:background "LightGray"
|
||||
:foreground "Black"))
|
||||
|
@ -660,6 +664,10 @@ month and 365.24 days for a year)."
|
|||
"Face used for agenda entries that come from the Emacs diary."
|
||||
:group 'org-faces)
|
||||
|
||||
(defface org-agenda-calendar-daterange '((t :inherit default))
|
||||
"Face used to show entries with a date range in the agenda."
|
||||
:group 'org-faces)
|
||||
|
||||
(defface org-agenda-calendar-event '((t :inherit default))
|
||||
"Face used to show events and appointments in the agenda."
|
||||
:group 'org-faces)
|
||||
|
|
|
@ -475,7 +475,7 @@ This will find DRAWER and extract the alist."
|
|||
(goto-char pos)
|
||||
(let ((end (save-excursion (org-end-of-subtree t t))))
|
||||
(if (re-search-forward
|
||||
(concat "^[ \t]*:" drawer ":[ \t]*\n\\([^\000]*?\\)\n[ \t]*:END:")
|
||||
(concat "^[ \t]*:" drawer ":[ \t]*\n\\(\\(?:.\\|\n\\)*?\\)\n[ \t]*:END:")
|
||||
end t)
|
||||
(read (match-string 1))
|
||||
nil))))
|
||||
|
@ -495,7 +495,7 @@ This will find DRAWER and extract the alist."
|
|||
(match-beginning 0)))))
|
||||
(outline-next-heading)
|
||||
(insert " :" drawer ":\n :END:\n")
|
||||
(beginning-of-line 0))
|
||||
(forward-line -1))
|
||||
(insert (pp-to-string status)))))
|
||||
|
||||
(defun org-feed-add-items (pos entries)
|
||||
|
@ -508,7 +508,7 @@ This will find DRAWER and extract the alist."
|
|||
(setq level (org-get-valid-level (length (match-string 1)) 1))
|
||||
(org-end-of-subtree t t)
|
||||
(skip-chars-backward " \t\n")
|
||||
(beginning-of-line 2)
|
||||
(forward-line 1)
|
||||
(setq pos (point))
|
||||
(while (setq entry (pop entries))
|
||||
(org-paste-subtree level entry 'yank))
|
||||
|
@ -565,7 +565,7 @@ If that property is already present, nothing changes."
|
|||
(let ((v (plist-get entry (intern (concat ":" name)))))
|
||||
(save-excursion
|
||||
(save-match-data
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(if (looking-at
|
||||
(concat "^\\([ \t]*\\)%" name "[ \t]*$"))
|
||||
(org-feed-make-indented-block
|
||||
|
@ -633,7 +633,7 @@ containing the properties `:guid' and `:item-full-text'."
|
|||
end (and (re-search-forward "</item>" nil t)
|
||||
(match-beginning 0)))
|
||||
(setq item (buffer-substring beg end)
|
||||
guid (if (string-match "<guid\\>.*?>\\([^\000]*?\\)</guid>" item)
|
||||
guid (if (string-match "<guid\\>.*?>\\(\\(?:.\\|\n\\)*?\\)</guid>" item)
|
||||
(xml-substitute-special (match-string-no-properties 1 item))))
|
||||
(setq entry (list :guid guid :item-full-text item))
|
||||
(push entry entries)
|
||||
|
@ -647,7 +647,7 @@ containing the properties `:guid' and `:item-full-text'."
|
|||
(with-temp-buffer
|
||||
(insert (plist-get entry :item-full-text))
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "<\\([a-zA-Z]+\\>\\).*?>\\([^\000]*?\\)</\\1>"
|
||||
(while (re-search-forward "<\\([a-zA-Z]+\\>\\).*?>\\(\\(?:.\\|\n\\)*?\\)</\\1>"
|
||||
nil t)
|
||||
(setq entry (plist-put entry
|
||||
(intern (concat ":" (match-string 1)))
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
;;
|
||||
;; Copyright (C) 2020-2024 Free Software Foundation, Inc.
|
||||
;;
|
||||
;; Author: Ihor Radchenko <yantar92 at gmail dot com>
|
||||
;; Author: Ihor Radchenko <yantar92 at posteo dot net>
|
||||
;; Keywords: folding, invisible text
|
||||
;; URL: https://orgmode.org
|
||||
;;
|
||||
|
@ -280,16 +280,17 @@
|
|||
|
||||
;;; Customization
|
||||
|
||||
(defcustom org-fold-core-style 'text-properties
|
||||
(defcustom org-fold-core-style (if (version< emacs-version "29")
|
||||
'text-properties
|
||||
'overlays)
|
||||
"Internal implementation detail used to hide folded text.
|
||||
Can be either `text-properties' or `overlays'.
|
||||
The former is faster on large files, while the latter is generally
|
||||
less error-prone with regard to third-party packages that haven't yet
|
||||
adapted to the new folding implementation.
|
||||
The former is faster on large files in Emacs <29, while the latter is
|
||||
generally less error-prone with regard to third-party packages.
|
||||
|
||||
Important: This variable must be set before loading Org."
|
||||
:group 'org
|
||||
:package-version '(Org . "9.6")
|
||||
:package-version '(Org . "9.7")
|
||||
:type '(choice
|
||||
(const :tag "Overlays" overlays)
|
||||
(const :tag "Text properties" text-properties)))
|
||||
|
@ -380,6 +381,9 @@ The following properties are known:
|
|||
`buffer-invisibility-spec' will be used as is.
|
||||
Note that changing this property from nil to t may
|
||||
clear the setting in `buffer-invisibility-spec'.
|
||||
- :font-lock :: non-nil means that newlines after the fold should
|
||||
be re-fontified upon folding/unfolding. See
|
||||
`org-activate-folds'.
|
||||
- :alias :: a list of aliases for the SPEC-SYMBOL.
|
||||
- :fragile :: Must be a function accepting two arguments.
|
||||
Non-nil means that changes in region may cause
|
||||
|
@ -424,7 +428,7 @@ Return nil when there is no matching folding spec."
|
|||
(unless org-fold-core--spec-symbols
|
||||
(dolist (spec (org-fold-core-folding-spec-list))
|
||||
(push (cons spec spec) org-fold-core--spec-symbols)
|
||||
(dolist (alias (assq :alias (assq spec org-fold-core--specs)))
|
||||
(dolist (alias (cdr (assq :alias (assq spec org-fold-core--specs))))
|
||||
(push (cons alias spec) org-fold-core--spec-symbols))))
|
||||
(alist-get spec-or-alias org-fold-core--spec-symbols)))
|
||||
|
||||
|
@ -553,7 +557,10 @@ and the setup appears to be created for different buffer,
|
|||
copy the old invisibility state into new buffer-local text properties,
|
||||
unless RETURN-ONLY is non-nil."
|
||||
(if (eq org-fold-core-style 'overlays)
|
||||
(org-fold-core-get-folding-property-symbol spec nil 'global)
|
||||
(or (gethash (cons 'global spec) org-fold-core--property-symbol-cache)
|
||||
(puthash (cons 'global spec)
|
||||
(org-fold-core-get-folding-property-symbol spec nil 'global)
|
||||
org-fold-core--property-symbol-cache))
|
||||
(let* ((buf (or buffer (current-buffer))))
|
||||
;; Create unique property symbol for SPEC in BUFFER
|
||||
(let ((local-prop (or (gethash (cons buf spec) org-fold-core--property-symbol-cache)
|
||||
|
@ -574,15 +581,6 @@ unless RETURN-ONLY is non-nil."
|
|||
;; would contain folding properties, which are not
|
||||
;; matching the generated `local-prop'.
|
||||
(unless (member local-prop (cdr (assq 'invisible char-property-alias-alist)))
|
||||
;; Add current buffer to the list of indirect buffers in the base buffer.
|
||||
(when (buffer-base-buffer)
|
||||
(with-current-buffer (buffer-base-buffer)
|
||||
(setq-local org-fold-core--indirect-buffers
|
||||
(let (bufs)
|
||||
(org-fold-core-cycle-over-indirect-buffers
|
||||
(push (current-buffer) bufs))
|
||||
(push buf bufs)
|
||||
(delete-dups bufs)))))
|
||||
;; Copy all the old folding properties to preserve the folding state
|
||||
(with-silent-modifications
|
||||
(dolist (old-prop (cdr (assq 'invisible char-property-alias-alist)))
|
||||
|
@ -633,14 +631,27 @@ unless RETURN-ONLY is non-nil."
|
|||
text-property-default-nonsticky
|
||||
full-prop-list))))))))))))))
|
||||
|
||||
(defun org-fold-core--update-buffer-folds ()
|
||||
"Copy folding state in a new buffer with text copied from old buffer."
|
||||
(org-fold-core--property-symbol-get-create (car (org-fold-core-folding-spec-list))))
|
||||
|
||||
(defun org-fold-core-decouple-indirect-buffer-folds ()
|
||||
"Copy and decouple folding state in a newly created indirect buffer.
|
||||
This function is mostly intended to be used in
|
||||
`clone-indirect-buffer-hook'."
|
||||
;; Add current buffer to the list of indirect buffers in the base buffer.
|
||||
(when (buffer-base-buffer)
|
||||
(with-current-buffer (buffer-base-buffer)
|
||||
(setq-local org-fold-core--indirect-buffers
|
||||
(let (bufs)
|
||||
(org-fold-core-cycle-over-indirect-buffers
|
||||
(push (current-buffer) bufs))
|
||||
(push (current-buffer) bufs)
|
||||
(delete-dups bufs)))))
|
||||
(when (and (buffer-base-buffer)
|
||||
(eq org-fold-core-style 'text-properties)
|
||||
(not (memql 'ignore-indirect org-fold-core--optimise-for-huge-buffers)))
|
||||
(org-fold-core--property-symbol-get-create (car (org-fold-core-folding-spec-list)))))
|
||||
(org-fold-core--update-buffer-folds)))
|
||||
|
||||
;;; API
|
||||
|
||||
|
@ -694,7 +705,7 @@ The folding spec properties will be set to PROPERTIES (see
|
|||
(let* ((full-properties (mapcar (lambda (prop) (cons prop (cdr (assq prop properties))))
|
||||
'( :visible :ellipsis :isearch-ignore
|
||||
:global :isearch-open :front-sticky
|
||||
:rear-sticky :fragile :alias)))
|
||||
:rear-sticky :fragile :alias :font-lock)))
|
||||
(full-spec (cons spec full-properties)))
|
||||
(add-to-list 'org-fold-core--specs full-spec append)
|
||||
(mapc (lambda (prop-cons) (org-fold-core-set-folding-spec-property spec (car prop-cons) (cdr prop-cons) 'force)) full-properties)
|
||||
|
@ -783,16 +794,19 @@ corresponding folding spec (if the text is folded using that spec)."
|
|||
(when (and spec (not (eq spec 'all))) (org-fold-core--check-spec spec))
|
||||
(org-with-point-at pom
|
||||
(cond
|
||||
((eq spec 'all)
|
||||
(let ((result))
|
||||
(dolist (spec (org-fold-core-folding-spec-list))
|
||||
(let ((val (get-char-property (point) (org-fold-core--property-symbol-get-create spec nil t))))
|
||||
(when val (push val result))))
|
||||
(reverse result)))
|
||||
((null spec)
|
||||
(let ((result (get-char-property (point) 'invisible)))
|
||||
(when (org-fold-core-folding-spec-p result) result)))
|
||||
(t (get-char-property (point) (org-fold-core--property-symbol-get-create spec nil t)))))))
|
||||
((or (null spec) (eq spec 'all))
|
||||
(catch :single-spec
|
||||
(let ((result))
|
||||
(dolist (lspec (org-fold-core-folding-spec-list))
|
||||
(let ((val (if (eq org-fold-core-style 'text-properties)
|
||||
(get-text-property (point) (org-fold-core--property-symbol-get-create lspec nil t))
|
||||
(get-char-property (point) (org-fold-core--property-symbol-get-create lspec nil t)))))
|
||||
(when (and val (null spec)) (throw :single-spec val))
|
||||
(when val (push val result))))
|
||||
(reverse result))))
|
||||
(t (if (eq org-fold-core-style 'text-properties)
|
||||
(get-text-property (point) (org-fold-core--property-symbol-get-create spec nil t))
|
||||
(get-char-property (point) (org-fold-core--property-symbol-get-create spec nil t))))))))
|
||||
|
||||
(defun org-fold-core-get-folding-specs-in-region (beg end)
|
||||
"Get all folding specs in region from BEG to END."
|
||||
|
@ -843,13 +857,20 @@ If PREVIOUS-P is non-nil, search backwards."
|
|||
(next-change (if previous-p
|
||||
(if ignore-hidden-p
|
||||
(lambda (p) (org-fold-core-previous-folding-state-change (org-fold-core-get-folding-spec nil p) p limit))
|
||||
(lambda (p) (max limit (1- (previous-single-char-property-change p 'invisible nil limit)))))
|
||||
(lambda (p) (max limit (previous-single-char-property-change p 'invisible nil limit))))
|
||||
(if ignore-hidden-p
|
||||
(lambda (p) (org-fold-core-next-folding-state-change (org-fold-core-get-folding-spec nil p) p limit))
|
||||
(lambda (p) (next-single-char-property-change p 'invisible nil limit)))))
|
||||
(next pos))
|
||||
(while (and (funcall cmp next limit)
|
||||
(not (org-xor invisible-initially? (funcall invisible-p next))))
|
||||
(not (org-xor
|
||||
invisible-initially?
|
||||
(funcall invisible-p
|
||||
(if previous-p
|
||||
;; NEXT-1 -> NEXT is the change.
|
||||
(max limit (1- next))
|
||||
;; NEXT -> NEXT+1 is the change.
|
||||
next)))))
|
||||
(setq next (funcall next-change next)))
|
||||
next))
|
||||
|
||||
|
@ -897,14 +918,19 @@ Search backwards when PREVIOUS-P is non-nil."
|
|||
(unless spec-or-alias
|
||||
(setq spec-or-alias (org-fold-core-folding-spec-list)))
|
||||
(setq pos (or pos (point)))
|
||||
(apply (if previous-p
|
||||
#'max
|
||||
#'min)
|
||||
(mapcar (if previous-p
|
||||
(lambda (prop) (max (or limit (point-min)) (previous-single-char-property-change pos prop nil (or limit (point-min)))))
|
||||
(lambda (prop) (next-single-char-property-change pos prop nil (or limit (point-max)))))
|
||||
(mapcar (lambda (el) (org-fold-core--property-symbol-get-create el nil t))
|
||||
spec-or-alias))))
|
||||
(let ((limit (or limit (if previous-p (point-min) (point-max)))))
|
||||
(catch :limit
|
||||
(dolist (prop (mapcar
|
||||
(lambda (el)
|
||||
(org-fold-core--property-symbol-get-create el nil t))
|
||||
spec-or-alias))
|
||||
(when (= limit pos) (throw :limit limit))
|
||||
(setq
|
||||
limit
|
||||
(if previous-p
|
||||
(previous-single-char-property-change pos prop nil limit)
|
||||
(next-single-char-property-change pos prop nil limit))))
|
||||
limit)))
|
||||
|
||||
(defun org-fold-core-previous-folding-state-change (&optional spec-or-alias pos limit)
|
||||
"Call `org-fold-core-next-folding-state-change' searching backwards."
|
||||
|
@ -985,6 +1011,24 @@ WITH-MARKERS must be nil when RELATIVE is non-nil."
|
|||
|
||||
;;;;; Region visibility
|
||||
|
||||
(defvar org-fold-core--keep-overlays nil
|
||||
"When non-nil, `org-fold-core-region' will not remove existing overlays.")
|
||||
(defvar org-fold-core--isearch-overlays) ; defined below
|
||||
(defmacro org-fold-core--keep-overlays (&rest body)
|
||||
"Run BODY with `org-fold-core--keep-overlays' set to t."
|
||||
(declare (debug (body)))
|
||||
`(let ((org-fold-core--keep-overlays t))
|
||||
,@body))
|
||||
|
||||
(defvar org-fold-core--isearch-active nil
|
||||
"When non-nil, `org-fold-core-region' records created overlays.
|
||||
New overlays will be added to `org-fold-core--isearch-overlays'.")
|
||||
(defmacro org-fold-core--with-isearch-active (&rest body)
|
||||
"Run BODY with `org-fold-core--isearch-active' set to t."
|
||||
(declare (debug (body)))
|
||||
`(let ((org-fold-core--isearch-active t))
|
||||
,@body))
|
||||
|
||||
;; This is the core function performing actual folding/unfolding. The
|
||||
;; folding state is stored in text property (folding property)
|
||||
;; returned by `org-fold-core--property-symbol-get-create'. The value of the
|
||||
|
@ -997,7 +1041,43 @@ If SPEC-OR-ALIAS is omitted and FLAG is nil, unfold everything in the region."
|
|||
(when spec (org-fold-core--check-spec spec))
|
||||
(with-silent-modifications
|
||||
(org-with-wide-buffer
|
||||
(when (eq org-fold-core-style 'overlays) (remove-overlays from to 'invisible spec))
|
||||
;; Arrange fontifying newlines after all the folds between FROM
|
||||
;; and TO to match the first character before the fold; not the
|
||||
;; last as per Emacs defaults. This makes :extend faces span
|
||||
;; past the ellipsis. See bug#65896. The face properties are
|
||||
;; assigned via `org-activate-folds'.
|
||||
(when (or (not spec) (org-fold-core-get-folding-spec-property spec :font-lock))
|
||||
(when (equal ?\n (char-after from))
|
||||
(font-lock-flush from (1+ from)))
|
||||
(when (equal ?\n (char-after to))
|
||||
(font-lock-flush to (1+ to)))
|
||||
(dolist (region (org-fold-core-get-regions :from from :to to :specs spec))
|
||||
(when (equal ?\n (char-after (cadr region)))
|
||||
(font-lock-flush (cadr region) (1+ (cadr region))))
|
||||
;; Re-fontify beginning of the fold - we may
|
||||
;; unfold inside an existing fold, with FROM begin a newline
|
||||
;; after spliced fold.
|
||||
(when (equal ?\n (char-after (car region)))
|
||||
(font-lock-flush (car region) (1+ (car region))))))
|
||||
(when (eq org-fold-core-style 'overlays)
|
||||
(if org-fold-core--keep-overlays
|
||||
(mapc
|
||||
(lambda (ov)
|
||||
(when (or (not spec)
|
||||
(eq spec (overlay-get ov 'invisible)))
|
||||
(when (and org-fold-core--isearch-active
|
||||
(overlay-get ov 'invisible)
|
||||
(org-fold-core-get-folding-spec-property
|
||||
(overlay-get ov 'invisible) :isearch-open))
|
||||
(when (overlay-get ov 'invisible)
|
||||
(overlay-put ov 'org-invisible (overlay-get ov 'invisible)))
|
||||
(overlay-put ov 'invisible nil)
|
||||
(when org-fold-core--isearch-active
|
||||
(cl-pushnew ov org-fold-core--isearch-overlays)))))
|
||||
(overlays-in from to))
|
||||
(when spec
|
||||
(remove-overlays from to 'org-invisible spec)
|
||||
(remove-overlays from to 'invisible spec))))
|
||||
(if flag
|
||||
(if (not spec)
|
||||
(error "Calling `org-fold-core-region' with missing SPEC")
|
||||
|
@ -1007,17 +1087,14 @@ If SPEC-OR-ALIAS is omitted and FLAG is nil, unfold everything in the region."
|
|||
(let ((o (make-overlay from to nil
|
||||
(org-fold-core-get-folding-spec-property spec :front-sticky)
|
||||
(org-fold-core-get-folding-spec-property spec :rear-sticky))))
|
||||
(when org-fold-core--isearch-active
|
||||
(push o org-fold-core--isearch-overlays))
|
||||
(overlay-put o 'evaporate t)
|
||||
(overlay-put o (org-fold-core--property-symbol-get-create spec) spec)
|
||||
(overlay-put o 'invisible spec)
|
||||
(overlay-put o 'isearch-open-invisible #'org-fold-core--isearch-show)
|
||||
;; FIXME: Disabling to work around Emacs bug#60399
|
||||
;; and https://orgmode.org/list/87zgb6tk6h.fsf@localhost.
|
||||
;; The proper fix will require making sure that
|
||||
;; `org-fold-core-isearch-open-function' does not
|
||||
;; delete the overlays used by isearch.
|
||||
;; (overlay-put o 'isearch-open-invisible-temporary #'org-fold-core--isearch-show-temporary)
|
||||
)
|
||||
;; Preserve priority.
|
||||
(overlay-put o 'priority (length (member spec (org-fold-core-folding-spec-list))))
|
||||
(overlay-put o 'isearch-open-invisible #'org-fold-core--isearch-show))
|
||||
(put-text-property from to (org-fold-core--property-symbol-get-create spec) spec)
|
||||
(put-text-property from to 'isearch-open-invisible #'org-fold-core--isearch-show)
|
||||
(put-text-property from to 'isearch-open-invisible-temporary #'org-fold-core--isearch-show-temporary)
|
||||
|
@ -1041,7 +1118,13 @@ If SPEC-OR-ALIAS is omitted and FLAG is nil, unfold everything in the region."
|
|||
(setq pos next))
|
||||
(setq pos (next-single-char-property-change pos 'invisible nil to)))))))
|
||||
(when (eq org-fold-core-style 'text-properties)
|
||||
(remove-text-properties from to (list (org-fold-core--property-symbol-get-create spec) nil)))))))))
|
||||
(remove-text-properties from to (list (org-fold-core--property-symbol-get-create spec) nil)))))
|
||||
;; Re-calculate trailing faces for all the folds revealed
|
||||
;; by unfolding or created by folding.
|
||||
(when (or (not spec) (org-fold-core-get-folding-spec-property spec :font-lock))
|
||||
(dolist (region (org-fold-core-get-regions :from from :to to :specs spec))
|
||||
(when (equal ?\n (char-after (cadr region)))
|
||||
(font-lock-flush (cadr region) (1+ (cadr region))))))))))
|
||||
|
||||
(cl-defmacro org-fold-core-regions (regions &key override clean-markers relative)
|
||||
"Fold every region in REGIONS list in current buffer.
|
||||
|
@ -1104,13 +1187,19 @@ TYPE can be either `text-properties' or `overlays'."
|
|||
(setq-local isearch-filter-predicate #'org-fold-core--isearch-filter-predicate-text-properties))
|
||||
(`overlays
|
||||
(when (eq org-fold-core-style 'text-properties)
|
||||
(setq-local isearch-filter-predicate #'org-fold-core--isearch-filter-predicate-overlays)
|
||||
(add-hook 'isearch-mode-end-hook #'org-fold-core--clear-isearch-overlays nil 'local)))
|
||||
(add-function :before (local 'isearch-filter-predicate) #'org-fold-core--create-isearch-overlays)
|
||||
;; When `isearch-filter-predicate' is called outside isearch,
|
||||
;; it is common that `isearch-mode-end-hook' does not get
|
||||
;; executed, but `isearch-clean-overlays' usually does.
|
||||
(advice-add
|
||||
'isearch-clean-overlays :after
|
||||
#'org-fold-core--clear-isearch-overlays
|
||||
'((name . isearch-clean-overlays@org-fold-core)))))
|
||||
(_ (error "%s: Unknown type of setup for `org-fold-core--isearch-setup'" type))))
|
||||
|
||||
(defun org-fold-core--isearch-reveal (pos)
|
||||
"Default function used to reveal hidden text at POS for isearch."
|
||||
(let ((region (org-fold-core-get-region-at-point pos)))
|
||||
(let ((region (org-fold-core-get-region-at-point nil pos)))
|
||||
(org-fold-core-region (car region) (cdr region) nil)))
|
||||
|
||||
(defun org-fold-core--isearch-filter-predicate-text-properties (beg end)
|
||||
|
@ -1145,34 +1234,37 @@ This function is intended to be used as `isearch-filter-predicate'."
|
|||
"Clear `org-fold-core--isearch-local-regions'."
|
||||
(clrhash org-fold-core--isearch-local-regions))
|
||||
|
||||
(defun org-fold-core--isearch-show (_)
|
||||
"Reveal text at point found by isearch."
|
||||
(funcall org-fold-core-isearch-open-function (point)))
|
||||
(defun org-fold-core--isearch-show (overlay-or-region)
|
||||
"Reveal text at OVERLAY-OR-REGION found by isearch."
|
||||
(let (beg end)
|
||||
(if (overlayp overlay-or-region)
|
||||
(setq beg (overlay-start overlay-or-region)
|
||||
end (overlay-end overlay-or-region))
|
||||
(setq beg (car overlay-or-region)
|
||||
end (cdr overlay-or-region)))
|
||||
;; FIXME: Reveal the match (usually point, but may sometimes go beyond the region).
|
||||
(when (< beg (point) end)
|
||||
(funcall org-fold-core-isearch-open-function (point)))
|
||||
(if (overlayp overlay-or-region)
|
||||
(delete-overlay overlay-or-region)
|
||||
(org-fold-core-region beg end nil))))
|
||||
|
||||
(defun org-fold-core--isearch-show-temporary (region hide-p)
|
||||
"Temporarily reveal text in REGION.
|
||||
Hide text instead if HIDE-P is non-nil.
|
||||
REGION can also be an overlay in current buffer."
|
||||
(when (overlayp region)
|
||||
(setq region (cons (overlay-start region)
|
||||
(overlay-end region))))
|
||||
(if (not hide-p)
|
||||
(let ((pos (car region)))
|
||||
(while (< pos (cdr region))
|
||||
(let ((spec-no-open
|
||||
(catch :found
|
||||
(dolist (spec (org-fold-core-get-folding-spec 'all pos))
|
||||
(unless (org-fold-core-get-folding-spec-property spec :isearch-open)
|
||||
(throw :found spec))))))
|
||||
(if spec-no-open
|
||||
;; Skip regions folded with folding specs that cannot be opened.
|
||||
(setq pos (org-fold-core-next-folding-state-change spec-no-open pos (cdr region)))
|
||||
(dolist (spec (org-fold-core-get-folding-spec 'all pos))
|
||||
(push (cons spec (org-fold-core-get-region-at-point spec pos)) (gethash region org-fold-core--isearch-local-regions)))
|
||||
(org-fold-core--isearch-show region)
|
||||
(setq pos (org-fold-core-next-folding-state-change nil pos (cdr region)))))))
|
||||
(mapc (lambda (val) (org-fold-core-region (cadr val) (cddr val) t (car val))) (gethash region org-fold-core--isearch-local-regions))
|
||||
(remhash region org-fold-core--isearch-local-regions)))
|
||||
(save-match-data ; match data must not be modified.
|
||||
(let ((org-fold-core-style (if (overlayp region) 'overlays 'text-properties)))
|
||||
(if hide-p
|
||||
(if (not (overlayp region))
|
||||
nil ;; FIXME: after isearch supports text properties.
|
||||
(when (overlay-get region 'org-invisible)
|
||||
(overlay-put region 'invisible (overlay-get region 'org-invisible))))
|
||||
;; isearch expects all the temporarily opened overlays to exist.
|
||||
;; See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=60399
|
||||
(org-fold-core--keep-overlays
|
||||
(org-fold-core--with-isearch-active
|
||||
(org-fold-core--isearch-show region)))))))
|
||||
|
||||
(defvar-local org-fold-core--isearch-special-specs nil
|
||||
"List of specs that can break visibility state when converted to overlays.
|
||||
|
@ -1187,49 +1279,28 @@ instead of text properties. The created overlays will be stored in
|
|||
(while (< pos end)
|
||||
;; We need loop below to make sure that we clean all invisible
|
||||
;; properties, which may be nested.
|
||||
(dolist (spec (org-fold-core-get-folding-spec 'all pos))
|
||||
(unless (org-fold-core-get-folding-spec-property spec :isearch-ignore)
|
||||
(let* ((region (org-fold-core-get-region-at-point spec pos)))
|
||||
(when (memq spec org-fold-core--isearch-special-specs)
|
||||
(setq pos (min pos (car region)))
|
||||
(setq end (max end (cdr region))))
|
||||
;; Changing text properties is considered buffer modification.
|
||||
;; We do not want it here.
|
||||
(with-silent-modifications
|
||||
(org-fold-core-region (car region) (cdr region) nil spec)
|
||||
;; The overlay is modeled after `outline-flag-region'
|
||||
;; [2020-05-09 Sat] overlay for 'outline blocks.
|
||||
(let ((o (make-overlay (car region) (cdr region) nil 'front-advance)))
|
||||
(overlay-put o 'evaporate t)
|
||||
(overlay-put o 'invisible spec)
|
||||
(overlay-put o 'org-invisible spec)
|
||||
;; Make sure that overlays are applied in the same order
|
||||
;; with the folding specs.
|
||||
;; Note: `memq` returns cdr with car equal to the first
|
||||
;; found matching element.
|
||||
(overlay-put o 'priority (length (memq spec (org-fold-core-folding-spec-list))))
|
||||
;; `delete-overlay' here means that spec information will be lost
|
||||
;; for the region. The region will remain visible.
|
||||
(if (org-fold-core-get-folding-spec-property spec :isearch-open)
|
||||
(overlay-put o 'isearch-open-invisible #'delete-overlay)
|
||||
(overlay-put o 'isearch-open-invisible #'ignore)
|
||||
(overlay-put o 'isearch-open-invisible-temporary #'ignore))
|
||||
(push o org-fold-core--isearch-overlays))))))
|
||||
(setq pos (org-fold-core-next-folding-state-change nil pos end)))))
|
||||
|
||||
(defun org-fold-core--isearch-filter-predicate-overlays (beg end)
|
||||
"Return non-nil if text between BEG and END is deemed visible by isearch.
|
||||
This function is intended to be used as `isearch-filter-predicate'."
|
||||
(org-fold-core--create-isearch-overlays beg end) ;; trick isearch by creating overlays in place of invisible text
|
||||
(isearch-filter-visible beg end))
|
||||
(catch :repeat
|
||||
(dolist (spec (org-fold-core-get-folding-spec 'all pos))
|
||||
(unless (org-fold-core-get-folding-spec-property spec :isearch-ignore)
|
||||
(let* ((region (org-fold-core-get-region-at-point spec pos)))
|
||||
(when (memq spec org-fold-core--isearch-special-specs)
|
||||
(setq end (max end (cdr region)))
|
||||
(when (< (car region) beg)
|
||||
(setq beg (car region))
|
||||
(setq pos beg)
|
||||
(throw :repeat t)))
|
||||
;; Changing text properties is considered buffer modification.
|
||||
;; We do not want it here.
|
||||
(with-silent-modifications
|
||||
(org-fold-core-region (car region) (cdr region) nil spec)
|
||||
(let ((org-fold-core-style 'overlays))
|
||||
(org-fold-core--with-isearch-active
|
||||
(org-fold-core-region (car region) (cdr region) t spec)))))))
|
||||
(setq pos (org-fold-core-next-folding-state-change nil pos end))))))
|
||||
|
||||
(defun org-fold-core--clear-isearch-overlay (ov)
|
||||
"Convert OV region back into using text properties."
|
||||
(let ((spec (if isearch-mode-end-hook-quit
|
||||
;; Restore all folds.
|
||||
(overlay-get ov 'org-invisible)
|
||||
;; Leave opened folds open.
|
||||
(overlay-get ov 'invisible))))
|
||||
(let ((spec (overlay-get ov 'invisible)))
|
||||
;; Ignore deleted overlays.
|
||||
(when (and spec
|
||||
(overlay-buffer ov))
|
||||
|
@ -1238,8 +1309,6 @@ This function is intended to be used as `isearch-filter-predicate'."
|
|||
(with-silent-modifications
|
||||
(when (<= (overlay-end ov) (point-max))
|
||||
(org-fold-core-region (overlay-start ov) (overlay-end ov) t spec)))))
|
||||
(when (member ov isearch-opened-overlays)
|
||||
(setq isearch-opened-overlays (delete ov isearch-opened-overlays)))
|
||||
(delete-overlay ov))
|
||||
|
||||
(defun org-fold-core--clear-isearch-overlays ()
|
||||
|
@ -1254,6 +1323,8 @@ This function is intended to be used as `isearch-filter-predicate'."
|
|||
"Non-nil: skip processing modifications in `org-fold-core--fix-folded-region'.")
|
||||
(defvar org-fold-core--ignore-fragility-checks nil
|
||||
"Non-nil: skip fragility checks in `org-fold-core--fix-folded-region'.")
|
||||
(defvar org-fold-core--suppress-folding-fix nil
|
||||
"Non-nil: skip folding fix in `org-fold-core--fix-folded-region'.")
|
||||
|
||||
(defmacro org-fold-core-ignore-modifications (&rest body)
|
||||
"Run BODY ignoring buffer modifications in `org-fold-core--fix-folded-region'."
|
||||
|
@ -1262,12 +1333,47 @@ This function is intended to be used as `isearch-filter-predicate'."
|
|||
(unwind-protect (progn ,@body)
|
||||
(setq org-fold-core--last-buffer-chars-modified-tick (buffer-chars-modified-tick)))))
|
||||
|
||||
(defmacro org-fold-core-suppress-folding-fix (&rest body)
|
||||
"Run BODY skipping re-folding checks in `org-fold-core--fix-folded-region'."
|
||||
(declare (debug (form body)) (indent 0))
|
||||
`(let ((org-fold-core--suppress-folding-fix t))
|
||||
(progn ,@body)))
|
||||
|
||||
(defmacro org-fold-core-ignore-fragility-checks (&rest body)
|
||||
"Run BODY skipping :fragility checks in `org-fold-core--fix-folded-region'."
|
||||
(declare (debug (form body)) (indent 0))
|
||||
`(let ((org-fold-core--ignore-fragility-checks t))
|
||||
(progn ,@body)))
|
||||
|
||||
(defvar org-fold-core--region-delayed-list nil
|
||||
"List holding (MKFROM MKTO FLAG SPEC-OR-ALIAS) arguments to process.
|
||||
The list is used by `org-fold-core--region-delayed'.")
|
||||
(defun org-fold-core--region-delayed (from to flag &optional spec-or-alias)
|
||||
"Call `org-fold-core-region' after current command.
|
||||
Pass the same FROM, TO, FLAG, and SPEC-OR-ALIAS."
|
||||
;; Setup delayed folding.
|
||||
(add-hook 'post-command-hook #'org-fold-core--process-delayed)
|
||||
(let ((frommk (make-marker))
|
||||
(tomk (make-marker)))
|
||||
(set-marker frommk from (current-buffer))
|
||||
(set-marker tomk to (current-buffer))
|
||||
(push (list frommk tomk flag spec-or-alias) org-fold-core--region-delayed-list)))
|
||||
|
||||
(defun org-fold-core--process-delayed ()
|
||||
"Perform folding for `org-fold-core--region-delayed-list'."
|
||||
(when org-fold-core--region-delayed-list
|
||||
(mapc (lambda (args)
|
||||
(when (and (buffer-live-p (marker-buffer (nth 0 args)))
|
||||
(buffer-live-p (marker-buffer (nth 1 args)))
|
||||
(< (nth 0 args) (nth 1 args)))
|
||||
(org-with-point-at (car args)
|
||||
(apply #'org-fold-core-region args))))
|
||||
;; Restore the initial folding order.
|
||||
(nreverse org-fold-core--region-delayed-list))
|
||||
;; Cleanup `post-command-hook'.
|
||||
(remove-hook 'post-command-hook #'org-fold-core--process-delayed)
|
||||
(setq org-fold-core--region-delayed-list nil)))
|
||||
|
||||
(defvar-local org-fold-core--last-buffer-chars-modified-tick nil
|
||||
"Variable storing the last return value of `buffer-chars-modified-tick'.")
|
||||
|
||||
|
@ -1295,7 +1401,7 @@ property, unfold the region if the :fragile function returns non-nil."
|
|||
;; buffer. Work around Emacs bug#46982.
|
||||
;; Re-hide text inserted in the middle/front/back of a folded
|
||||
;; region.
|
||||
(unless (equal from to) ; Ignore deletions.
|
||||
(unless (or org-fold-core--suppress-folding-fix (equal from to)) ; Ignore deletions.
|
||||
(when (eq org-fold-core-style 'text-properties)
|
||||
(org-fold-core-cycle-over-indirect-buffers
|
||||
(dolist (spec (org-fold-core-folding-spec-list))
|
||||
|
@ -1385,7 +1491,10 @@ property, unfold the region if the :fragile function returns non-nil."
|
|||
(cons fold-begin fold-end)
|
||||
spec))
|
||||
;; Reveal completely, not just from the SPEC.
|
||||
(org-fold-core-region fold-begin fold-end nil)))))
|
||||
;; Do it only after command is finished -
|
||||
;; some Emacs commands assume that
|
||||
;; visibility is not altered by `after-change-functions'.
|
||||
(org-fold-core--region-delayed fold-begin fold-end nil)))))
|
||||
;; Move to next fold.
|
||||
(setq pos (org-fold-core-next-folding-state-change spec pos local-to)))))))))))))
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
;;
|
||||
;; Copyright (C) 2020-2024 Free Software Foundation, Inc.
|
||||
;;
|
||||
;; Author: Ihor Radchenko <yantar92 at gmail dot com>
|
||||
;; Author: Ihor Radchenko <yantar92 at posteo dot net>
|
||||
;; Keywords: folding, invisible text
|
||||
;; URL: https://orgmode.org
|
||||
;;
|
||||
|
@ -49,8 +49,6 @@
|
|||
(require 'org-fold-core)
|
||||
|
||||
(defvar org-inlinetask-min-level)
|
||||
(defvar org-link--link-folding-spec)
|
||||
(defvar org-link--description-folding-spec)
|
||||
(defvar org-odd-levels-only)
|
||||
(defvar org-drawer-regexp)
|
||||
(defvar org-property-end-re)
|
||||
|
@ -61,11 +59,12 @@
|
|||
(defvar org-element-headline-re)
|
||||
|
||||
(declare-function isearch-filter-visible "isearch" (beg end))
|
||||
(declare-function org-element-type "org-element" (element))
|
||||
(declare-function org-element-type "org-element-ast" (node &optional anonymous))
|
||||
(declare-function org-element-at-point "org-element" (&optional pom cached-only))
|
||||
(declare-function org-element-property "org-element" (property element))
|
||||
(declare-function org-element-property "org-element-ast" (property node))
|
||||
(declare-function org-element-end "org-element" (node))
|
||||
(declare-function org-element-post-affiliated "org-element" (node))
|
||||
(declare-function org-element--current-element "org-element" (limit &optional granularity mode structure))
|
||||
(declare-function org-element--cache-active-p "org-element" ())
|
||||
(declare-function org-toggle-custom-properties-visibility "org" ())
|
||||
(declare-function org-item-re "org-list" ())
|
||||
(declare-function org-up-heading-safe "org" ())
|
||||
|
@ -189,7 +188,10 @@ smart Make point visible, and do insertion/deletion if it is
|
|||
Never delete a previously invisible character or add in the
|
||||
middle or right after an invisible region. Basically, this
|
||||
allows insertion and backward-delete right before ellipses.
|
||||
FIXME: maybe in this case we should not even show?"
|
||||
FIXME: maybe in this case we should not even show?
|
||||
|
||||
This variable only affects commands listed in
|
||||
`org-fold-catch-invisible-edits-commands'."
|
||||
:group 'org-edit-structure
|
||||
:version "24.1"
|
||||
:type '(choice
|
||||
|
@ -199,6 +201,33 @@ smart Make point visible, and do insertion/deletion if it is
|
|||
(const :tag "Show invisible part and do the edit" show)
|
||||
(const :tag "Be smart and do the right thing" smart)))
|
||||
|
||||
(defcustom org-fold-catch-invisible-edits-commands
|
||||
;; We do not add non-Org commands here by default to avoid advising
|
||||
;; globally. See `org-fold--advice-edit-commands'.
|
||||
'((org-self-insert-command . insert)
|
||||
(org-delete-backward-char . delete-backward)
|
||||
(org-delete-char . delete)
|
||||
(org-meta-return . insert)
|
||||
(org-return . insert))
|
||||
"Alist of commands where Org checks for invisible edits.
|
||||
Each element is (COMMAND . KIND), where COMMAND is symbol representing
|
||||
command as stored in `this-command' and KIND is symbol `insert',
|
||||
symbol `delete', or symbol `delete-backward'.
|
||||
|
||||
The checks are performed around `point'.
|
||||
|
||||
This variable must be set before loading Org in order to take effect.
|
||||
|
||||
Also, see `org-fold-catch-invisible-edits'."
|
||||
:group 'org-edit-structure
|
||||
:package-version '("Org" . "9.7")
|
||||
:type '(alist
|
||||
:key-type symbol
|
||||
:value-type (choice
|
||||
(const insert)
|
||||
(const delete)
|
||||
(const delete-backward))))
|
||||
|
||||
;;; Core functionality
|
||||
|
||||
;;; API
|
||||
|
@ -224,6 +253,7 @@ smart Make point visible, and do insertion/deletion if it is
|
|||
(:ellipsis . ,ellipsis)
|
||||
(:fragile . ,#'org-fold--reveal-outline-maybe)
|
||||
(:isearch-open . t)
|
||||
(:font-lock . t)
|
||||
;; This is needed to make sure that inserting a
|
||||
;; new planning line in folded heading is not
|
||||
;; revealed. Also, the below combination of :front-sticky and
|
||||
|
@ -236,6 +266,7 @@ smart Make point visible, and do insertion/deletion if it is
|
|||
(:ellipsis . ,ellipsis)
|
||||
(:fragile . ,#'org-fold--reveal-drawer-or-block-maybe)
|
||||
(:isearch-open . t)
|
||||
(:font-lock . t)
|
||||
(:front-sticky . t)
|
||||
(:alias . ( block center-block comment-block
|
||||
dynamic-block example-block export-block
|
||||
|
@ -245,10 +276,9 @@ smart Make point visible, and do insertion/deletion if it is
|
|||
(:ellipsis . ,ellipsis)
|
||||
(:fragile . ,#'org-fold--reveal-drawer-or-block-maybe)
|
||||
(:isearch-open . t)
|
||||
(:font-lock . t)
|
||||
(:front-sticky . t)
|
||||
(:alias . (drawer property-drawer)))
|
||||
,org-link--description-folding-spec
|
||||
,org-link--link-folding-spec)))
|
||||
(:alias . (drawer property-drawer))))))
|
||||
|
||||
;;;; Searching and examining folded text
|
||||
|
||||
|
@ -358,7 +388,7 @@ of the current heading, or to 1 if the current line is not a heading."
|
|||
(interactive (list
|
||||
(cond
|
||||
(current-prefix-arg (prefix-numeric-value current-prefix-arg))
|
||||
((save-excursion (beginning-of-line)
|
||||
((save-excursion (forward-line 0)
|
||||
(looking-at outline-regexp))
|
||||
(funcall outline-level))
|
||||
(t 1))))
|
||||
|
@ -419,20 +449,21 @@ Show the heading too, if it is currently invisible."
|
|||
|
||||
(defun org-fold-show-children (&optional level)
|
||||
"Show all direct subheadings of this heading.
|
||||
Prefix arg LEVEL is how many levels below the current level
|
||||
should be shown. Default is enough to cause the following
|
||||
heading to appear."
|
||||
Prefix arg LEVEL is how many levels below the current level should be
|
||||
shown. If direct subheadings are deeper than LEVEL, they are still
|
||||
displayed."
|
||||
(interactive "p")
|
||||
(unless (org-before-first-heading-p)
|
||||
(save-excursion
|
||||
(org-with-limited-levels (org-back-to-heading t))
|
||||
(let* ((current-level (funcall outline-level))
|
||||
(parent-level current-level)
|
||||
(max-level (org-get-valid-level
|
||||
current-level
|
||||
parent-level
|
||||
(if level (prefix-numeric-value level) 1)))
|
||||
(min-level-direct-child most-positive-fixnum)
|
||||
(end (save-excursion (org-end-of-subtree t t)))
|
||||
(regexp-fmt "^\\*\\{%d,%s\\}\\(?: \\|$\\)")
|
||||
(past-first-child nil)
|
||||
;; Make sure to skip inlinetasks.
|
||||
(re (format regexp-fmt
|
||||
current-level
|
||||
|
@ -448,11 +479,12 @@ heading to appear."
|
|||
;; MAX-LEVEL. Since we want to display it anyway, adjust
|
||||
;; MAX-LEVEL accordingly.
|
||||
(while (re-search-forward re end t)
|
||||
(unless past-first-child
|
||||
(setq re (format regexp-fmt
|
||||
current-level
|
||||
(max (funcall outline-level) max-level)))
|
||||
(setq past-first-child t))
|
||||
(setq current-level (funcall outline-level))
|
||||
(when (< current-level min-level-direct-child)
|
||||
(setq min-level-direct-child current-level
|
||||
re (format regexp-fmt
|
||||
parent-level
|
||||
(max min-level-direct-child max-level))))
|
||||
(org-fold-heading nil))))))
|
||||
|
||||
(defun org-fold-show-subtree ()
|
||||
|
@ -496,12 +528,12 @@ Return a non-nil value when toggling is successful."
|
|||
comment-block dynamic-block example-block export-block
|
||||
quote-block special-block src-block verse-block))
|
||||
(_ (error "Unknown category: %S" category))))
|
||||
(let* ((post (org-element-property :post-affiliated element))
|
||||
(let* ((post (org-element-post-affiliated element))
|
||||
(start (save-excursion
|
||||
(goto-char post)
|
||||
(line-end-position)))
|
||||
(end (save-excursion
|
||||
(goto-char (org-element-property :end element))
|
||||
(goto-char (org-element-end element))
|
||||
(skip-chars-backward " \t\n")
|
||||
(line-end-position))))
|
||||
;; Do nothing when not before or at the block opening line or
|
||||
|
@ -560,10 +592,12 @@ Return a non-nil value when toggling is successful."
|
|||
(interactive)
|
||||
(org-block-map (apply-partially #'org-fold-hide-block-toggle 'hide)))
|
||||
|
||||
(defun org-fold-hide-drawer-all ()
|
||||
"Fold all drawers in the current buffer."
|
||||
(let ((begin (point-min))
|
||||
(end (point-max)))
|
||||
(defun org-fold-hide-drawer-all (&optional begin end)
|
||||
"Fold all drawers in the current buffer or active region BEGIN..END."
|
||||
(interactive (list (and (use-region-p) (region-beginning))
|
||||
(and (use-region-p) (region-end))))
|
||||
(let ((begin (or begin (point-min)))
|
||||
(end (or end (point-max))))
|
||||
(org-fold--hide-drawers begin end)))
|
||||
|
||||
(defun org-fold--hide-drawers (begin end)
|
||||
|
@ -582,7 +616,7 @@ Return a non-nil value when toggling is successful."
|
|||
;; Make sure to skip drawer entirely or we might flag it
|
||||
;; another time when matching its ending line with
|
||||
;; `org-drawer-regexp'.
|
||||
(goto-char (org-element-property :end drawer))))))))
|
||||
(goto-char (org-element-end drawer))))))))
|
||||
|
||||
(defun org-fold-hide-archived-subtrees (beg end)
|
||||
"Re-hide all archived subtrees after a visibility state change."
|
||||
|
@ -591,7 +625,7 @@ Return a non-nil value when toggling is successful."
|
|||
(re (concat org-outline-regexp-bol ".*:" org-archive-tag ":")))
|
||||
(goto-char beg)
|
||||
;; Include headline point is currently on.
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(while (and (< (point) end) (re-search-forward re end t))
|
||||
(when (member org-archive-tag (org-get-tags nil t))
|
||||
(org-fold-subtree t)
|
||||
|
@ -626,33 +660,27 @@ DETAIL is either nil, `minimal', `local', `ancestors',
|
|||
(when (org-invisible-p)
|
||||
;; FIXME: No clue why, but otherwise the following might not work.
|
||||
(redisplay)
|
||||
(let ((region (org-fold-get-region-at-point)))
|
||||
;; Reveal emphasis markers.
|
||||
(when (eq detail 'local)
|
||||
(let (org-hide-emphasis-markers
|
||||
org-link-descriptive
|
||||
org-pretty-entities
|
||||
(org-hide-macro-markers nil)
|
||||
(region (or (org-find-text-property-region (point) 'org-emphasis)
|
||||
(org-find-text-property-region (point) 'org-macro)
|
||||
(org-find-text-property-region (point) 'invisible)
|
||||
region)))
|
||||
;; Silence byte-compiler.
|
||||
(ignore org-hide-macro-markers)
|
||||
(when region
|
||||
(org-with-point-at (car region)
|
||||
(beginning-of-line)
|
||||
(let (font-lock-extend-region-functions)
|
||||
(font-lock-fontify-region (max (point-min) (1- (car region))) (cdr region))))))
|
||||
;; Unfold links.
|
||||
;; Reveal emphasis markers.
|
||||
(when (eq detail 'local)
|
||||
(let (org-hide-emphasis-markers
|
||||
org-link-descriptive
|
||||
org-pretty-entities
|
||||
(org-hide-macro-markers nil)
|
||||
(region (or (org-find-text-property-region (point) 'org-emphasis)
|
||||
(org-find-text-property-region (point) 'org-macro)
|
||||
(org-find-text-property-region (point) 'invisible))))
|
||||
;; Silence byte-compiler.
|
||||
(ignore org-hide-macro-markers)
|
||||
(when region
|
||||
(dolist (spec '(org-link org-link-description))
|
||||
(org-fold-region (car region) (cdr region) nil spec))))
|
||||
(when region
|
||||
(dolist (spec (org-fold-core-folding-spec-list))
|
||||
;; Links are taken care by above.
|
||||
(unless (memq spec '(org-link org-link-description))
|
||||
(org-fold-region (car region) (cdr region) nil spec))))))
|
||||
(org-with-point-at (car region)
|
||||
(forward-line 0)
|
||||
(let (font-lock-extend-region-functions)
|
||||
(font-lock-fontify-region (max (point-min) (1- (car region))) (cdr region)))))))
|
||||
(let (region)
|
||||
(dolist (spec (org-fold-core-folding-spec-list))
|
||||
(setq region (org-fold-get-region-at-point spec))
|
||||
(when region
|
||||
(org-fold-region (car region) (cdr region) nil spec)))))
|
||||
(unless (org-before-first-heading-p)
|
||||
(org-with-limited-levels
|
||||
(cl-case detail
|
||||
|
@ -697,9 +725,10 @@ go to the parent and show the entire tree."
|
|||
|
||||
;;; Make isearch search in some text hidden via text properties.
|
||||
|
||||
(defun org-fold--isearch-reveal (&rest _)
|
||||
(defun org-fold--isearch-reveal (pos)
|
||||
"Reveal text at POS found by isearch."
|
||||
(org-fold-show-context 'isearch))
|
||||
(org-with-point-at pos
|
||||
(org-fold-show-context 'isearch)))
|
||||
|
||||
;;; Handling changes in folded elements
|
||||
|
||||
|
@ -724,7 +753,7 @@ the contents consists of blank lines.
|
|||
|
||||
Assume that point is located at the header line."
|
||||
(org-with-wide-buffer
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(org-fold-region
|
||||
(max (point-min) (1- (point)))
|
||||
(let ((endl (line-end-position)))
|
||||
|
@ -735,7 +764,7 @@ Assume that point is located at the header line."
|
|||
(if (equal (point)
|
||||
(save-excursion
|
||||
(goto-char endl)
|
||||
(org-end-of-subtree)
|
||||
(org-end-of-subtree t)
|
||||
(skip-chars-forward "\n\t\r ")))
|
||||
(point)
|
||||
endl)))
|
||||
|
@ -752,7 +781,7 @@ This function is intended to be used as :fragile property of
|
|||
;; The line before beginning of the fold should be either a
|
||||
;; headline or a list item.
|
||||
(backward-char)
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
;; Make sure that headline is not partially hidden.
|
||||
(unless (org-fold-folded-p nil 'headline)
|
||||
(org-fold--reveal-headline-at-point))
|
||||
|
@ -764,14 +793,14 @@ This function is intended to be used as :fragile property of
|
|||
(org-fold--reveal-headline-at-point))))
|
||||
;; Make sure that headline after is not partially hidden.
|
||||
(goto-char (cdr region))
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(unless (org-fold-folded-p nil 'headline)
|
||||
(when (looking-at-p org-element-headline-re)
|
||||
(org-fold--reveal-headline-at-point)))
|
||||
;; Check the validity of headline
|
||||
(goto-char (car region))
|
||||
(backward-char)
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(unless (let ((case-fold-search t))
|
||||
(looking-at (rx-to-string
|
||||
`(or (regex ,(org-item-re))
|
||||
|
@ -807,7 +836,7 @@ This function is intended to be used as :fragile property of
|
|||
;; The line before beginning of the fold should be the
|
||||
;; first line of the drawer/block.
|
||||
(backward-char)
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(unless (let ((case-fold-search t))
|
||||
(looking-at begin-re)) ; the match-data will be used later
|
||||
(throw :exit (setq unfold? t))))
|
||||
|
@ -827,7 +856,7 @@ This function is intended to be used as :fragile property of
|
|||
;; The last line of the folded text should match `end-re'.
|
||||
(save-excursion
|
||||
(goto-char fold-end)
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(unless (let ((case-fold-search t))
|
||||
(looking-at end-re))
|
||||
(throw :exit (setq unfold? t))))
|
||||
|
@ -901,6 +930,19 @@ The detailed reaction depends on the user option
|
|||
;; Don't do the edit, make the user repeat it in full visibility
|
||||
(user-error "Edit in invisible region aborted, repeat to confirm with text visible"))))))))
|
||||
|
||||
(defun org-fold-check-before-invisible-edit-maybe (&rest _)
|
||||
"Check before invisible command by `this-command'."
|
||||
(when (derived-mode-p 'org-mode)
|
||||
(pcase (alist-get this-command org-fold-catch-invisible-edits-commands)
|
||||
((pred null) nil)
|
||||
(kind (org-fold-check-before-invisible-edit kind)))))
|
||||
|
||||
(defun org-fold--advice-edit-commands ()
|
||||
"Advice editing commands according to `org-fold-catch-invisible-edits-commands'.
|
||||
The advices are installed in current buffer."
|
||||
(dolist (command (mapcar #'car org-fold-catch-invisible-edits-commands))
|
||||
(advice-add command :before #'org-fold-check-before-invisible-edit-maybe)))
|
||||
|
||||
(provide 'org-fold)
|
||||
|
||||
;;; org-fold.el ends here
|
||||
|
|
|
@ -45,9 +45,10 @@
|
|||
(declare-function org-element-at-point "org-element" (&optional pom cached-only))
|
||||
(declare-function org-element-class "org-element" (datum &optional parent))
|
||||
(declare-function org-element-context "org-element" (&optional element))
|
||||
(declare-function org-element-lineage "org-element" (blob &optional types with-self))
|
||||
(declare-function org-element-property "org-element" (property element))
|
||||
(declare-function org-element-type "org-element" (element))
|
||||
(declare-function org-element-lineage "org-element-ast" (blob &optional types with-self))
|
||||
(declare-function org-element-property "org-element-ast" (property node))
|
||||
(declare-function org-element-type "org-element-ast" (node &optional anonymous))
|
||||
(declare-function org-element-type-p "org-element-ast" (node types))
|
||||
(declare-function org-end-of-subtree "org" (&optional invisible-ok to-heading))
|
||||
(declare-function org-fill-paragraph "org" (&optional justify region))
|
||||
(declare-function org-in-block-p "org" (names))
|
||||
|
@ -136,15 +137,18 @@ Possible values are:
|
|||
|
||||
nil Prompt the user for each label.
|
||||
t Create unique labels of the form [fn:1], [fn:2], etc.
|
||||
anonymous Create anonymous footnotes
|
||||
confirm Like t, but let the user edit the created value.
|
||||
The label can be removed from the minibuffer to create
|
||||
an anonymous footnote.
|
||||
random Automatically generate a unique, random label."
|
||||
:group 'org-footnote
|
||||
:package-version '(Org . "9.7")
|
||||
:type '(choice
|
||||
(const :tag "Prompt for label" nil)
|
||||
(const :tag "Create automatic [fn:N]" t)
|
||||
(const :tag "Offer automatic [fn:N] for editing" confirm)
|
||||
(const :tag "Create anoymous [fn::]" anonymous)
|
||||
(const :tag "Create a random label" random))
|
||||
:safe #'symbolp)
|
||||
|
||||
|
@ -183,21 +187,21 @@ extracted will be filled again."
|
|||
"Is point in a context where footnotes are allowed?"
|
||||
(save-match-data
|
||||
(not (or (org-at-comment-p)
|
||||
(org-inside-LaTeX-fragment-p)
|
||||
;; Avoid literal example.
|
||||
(org-in-verbatim-emphasis)
|
||||
(save-excursion
|
||||
(beginning-of-line)
|
||||
(looking-at "[ \t]*:[ \t]+"))
|
||||
;; Avoid forbidden blocks.
|
||||
(org-in-block-p org-footnote-forbidden-blocks)))))
|
||||
(org-inside-LaTeX-fragment-p)
|
||||
;; Avoid literal example.
|
||||
(org-in-verbatim-emphasis)
|
||||
(save-excursion
|
||||
(forward-line 0)
|
||||
(looking-at "[ \t]*:[ \t]+"))
|
||||
;; Avoid forbidden blocks.
|
||||
(org-in-block-p org-footnote-forbidden-blocks)))))
|
||||
|
||||
(defun org-footnote-at-reference-p ()
|
||||
"Non-nil if point is at a footnote reference.
|
||||
If so, return a list containing its label, beginning and ending
|
||||
positions, and the definition, when inline."
|
||||
(let ((reference (org-element-context)))
|
||||
(when (eq 'footnote-reference (org-element-type reference))
|
||||
(when (org-element-type-p reference 'footnote-reference)
|
||||
(let ((end (save-excursion
|
||||
(goto-char (org-element-property :end reference))
|
||||
(skip-chars-backward " \t")
|
||||
|
@ -223,7 +227,7 @@ defined locally.
|
|||
The return value is nil if not at a footnote definition, and
|
||||
a list with label, start, end and definition of the footnote
|
||||
otherwise."
|
||||
(pcase (org-element-lineage (org-element-at-point) '(footnote-definition) t)
|
||||
(pcase (org-element-lineage (org-element-at-point) 'footnote-definition t)
|
||||
(`nil nil)
|
||||
(definition
|
||||
(let* ((label (org-element-property :label definition))
|
||||
|
@ -269,7 +273,7 @@ otherwise."
|
|||
((memq type '(headline inlinetask))
|
||||
(or (not (org-at-heading-p))
|
||||
(and (save-excursion
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(and (let ((case-fold-search t))
|
||||
(not (looking-at-p "\\*+ END[ \t]*$")))
|
||||
(let ((case-fold-search nil))
|
||||
|
@ -281,10 +285,10 @@ otherwise."
|
|||
;; White spaces after an object or blank lines after an element
|
||||
;; are OK.
|
||||
((>= (point)
|
||||
(save-excursion (goto-char (org-element-property :end context))
|
||||
(skip-chars-backward " \r\t\n")
|
||||
(if (eq (org-element-class context) 'object) (point)
|
||||
(line-beginning-position 2)))))
|
||||
(save-excursion (goto-char (org-element-property :end context))
|
||||
(skip-chars-backward " \r\t\n")
|
||||
(if (eq (org-element-class context) 'object) (point)
|
||||
(line-beginning-position 2)))))
|
||||
;; At the beginning of a footnote definition, right after the
|
||||
;; label, is OK.
|
||||
((eq type 'footnote-definition) (looking-at (rx space)))
|
||||
|
@ -298,7 +302,7 @@ otherwise."
|
|||
;; :contents-begin is not reliable on empty cells, so special
|
||||
;; case it.
|
||||
(<= (save-excursion (skip-chars-backward " \t") (point))
|
||||
(org-element-property :contents-end context)))
|
||||
(org-element-property :contents-end context)))
|
||||
((let ((cbeg (org-element-property :contents-begin context))
|
||||
(cend (org-element-property :contents-end context)))
|
||||
(and cbeg (>= (point) cbeg) (<= (point) cend))))))))
|
||||
|
@ -368,14 +372,14 @@ References are sorted according to a deep-reading order."
|
|||
;; Ensure point is within the reference before parsing it.
|
||||
(backward-char)
|
||||
(let ((object (org-element-context)))
|
||||
(when (eq (org-element-type object) 'footnote-reference)
|
||||
(when (org-element-type-p object 'footnote-reference)
|
||||
(let* ((label (org-element-property :label object))
|
||||
(begin (org-element-property :begin object))
|
||||
(size
|
||||
(and (eq (org-element-property :type object) 'inline)
|
||||
(- (org-element-property :contents-end object)
|
||||
(org-element-property :contents-begin object)))))
|
||||
(let ((d (org-element-lineage object '(footnote-definition))))
|
||||
(let ((d (org-element-lineage object 'footnote-definition)))
|
||||
(push (list label (copy-marker begin) (not d) size)
|
||||
references)
|
||||
(when d
|
||||
|
@ -420,7 +424,7 @@ while collecting them."
|
|||
(backward-char)
|
||||
(let ((element (org-element-at-point)))
|
||||
(let ((label (org-element-property :label element)))
|
||||
(when (and (eq (org-element-type element) 'footnote-definition)
|
||||
(when (and (org-element-type-p element 'footnote-definition)
|
||||
(not (member label seen)))
|
||||
(push label seen)
|
||||
(let* ((beg (progn
|
||||
|
@ -516,7 +520,7 @@ This function is meant to be used for fontification only."
|
|||
;; Definition: also grab the last square bracket, matched in
|
||||
;; `org-footnote-re' for non-inline footnotes.
|
||||
((and (save-excursion
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(save-match-data (org-footnote-in-valid-context-p)))
|
||||
(save-excursion
|
||||
(end-of-line)
|
||||
|
@ -633,8 +637,8 @@ This function ignores narrowing, if any."
|
|||
(while (re-search-forward org-footnote-re nil t)
|
||||
(backward-char)
|
||||
(let ((context (org-element-context)))
|
||||
(when (memq (org-element-type context)
|
||||
'(footnote-definition footnote-reference))
|
||||
(when (org-element-type-p
|
||||
context '(footnote-definition footnote-reference))
|
||||
(let ((label (org-element-property :label context)))
|
||||
(when label (cl-pushnew label all :test #'equal))))))
|
||||
all)))
|
||||
|
@ -665,15 +669,16 @@ or new, let the user edit the definition of the footnote."
|
|||
(user-error "Cannot insert a footnote here"))
|
||||
(let* ((all (org-footnote-all-labels))
|
||||
(label
|
||||
(if (eq org-footnote-auto-label 'random)
|
||||
(format "%x" (abs (random)))
|
||||
(org-footnote-normalize-label
|
||||
(let ((propose (org-footnote-unique-label all)))
|
||||
(if (eq org-footnote-auto-label t) propose
|
||||
(completing-read
|
||||
"Label (leave empty for anonymous): "
|
||||
(mapcar #'list all) nil nil
|
||||
(and (eq org-footnote-auto-label 'confirm) propose))))))))
|
||||
(unless (eq org-footnote-auto-label 'anonymous)
|
||||
(if (eq org-footnote-auto-label 'random)
|
||||
(format "%x" (abs (random)))
|
||||
(org-footnote-normalize-label
|
||||
(let ((propose (org-footnote-unique-label all)))
|
||||
(if (eq org-footnote-auto-label t) propose
|
||||
(completing-read
|
||||
"Label (leave empty for anonymous): "
|
||||
(mapcar #'list all) nil nil
|
||||
(and (eq org-footnote-auto-label 'confirm) propose)))))))))
|
||||
(cond ((not label)
|
||||
(insert "[fn::]")
|
||||
(backward-char 1))
|
||||
|
|
|
@ -102,7 +102,11 @@ When nil, you can use these keybindings to navigate the buffer:
|
|||
mouse-drag-region universal-argument org-occur)))
|
||||
(dolist (cmd cmds)
|
||||
(substitute-key-definition cmd cmd map global-map)))
|
||||
(suppress-keymap map)
|
||||
(if org-goto-auto-isearch
|
||||
;; Suppress 0-9 interpreted as digital arguments.
|
||||
;; Make them initiate isearch instead.
|
||||
(suppress-keymap map t)
|
||||
(suppress-keymap map))
|
||||
(org-defkey map "\C-m" 'org-goto-ret)
|
||||
(org-defkey map [(return)] 'org-goto-ret)
|
||||
(org-defkey map [(left)] 'org-goto-left)
|
||||
|
@ -145,7 +149,7 @@ When nil, you can use these keybindings to navigate the buffer:
|
|||
(search-backward string bound noerror))
|
||||
(when (save-match-data
|
||||
(and (save-excursion
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(looking-at org-complex-heading-regexp))
|
||||
(or (not (match-beginning 5))
|
||||
(< (point) (match-beginning 5)))))
|
||||
|
@ -172,7 +176,7 @@ When nil, you can use these keybindings to navigate the buffer:
|
|||
(interactive)
|
||||
(if (org-at-heading-p)
|
||||
(progn
|
||||
(beginning-of-line 1)
|
||||
(forward-line 0)
|
||||
(setq org-goto-selected-point (point)
|
||||
org-goto-exit-command 'left)
|
||||
(throw 'exit nil))
|
||||
|
@ -211,12 +215,12 @@ position or nil."
|
|||
(help (or help org-goto-help)))
|
||||
(save-excursion
|
||||
(save-window-excursion
|
||||
(delete-other-windows)
|
||||
(and (get-buffer "*org-goto*") (kill-buffer "*org-goto*"))
|
||||
(pop-to-buffer-same-window
|
||||
(condition-case nil
|
||||
(pop-to-buffer
|
||||
(condition-case nil
|
||||
(make-indirect-buffer (current-buffer) "*org-goto*" t)
|
||||
(error (make-indirect-buffer (current-buffer) "*org-goto*" t))))
|
||||
(error (make-indirect-buffer (current-buffer) "*org-goto*" t)))
|
||||
'(org-display-buffer-full-frame))
|
||||
(let (temp-buffer-show-function temp-buffer-show-hook)
|
||||
(with-output-to-temp-buffer "*Org Help*"
|
||||
(princ (format help (if org-goto-auto-isearch
|
||||
|
@ -234,8 +238,10 @@ position or nil."
|
|||
(let (org-special-ctrl-a/e) (org-beginning-of-line))
|
||||
(message "Select location and press RET")
|
||||
(use-local-map org-goto-map)
|
||||
(recursive-edit)))
|
||||
(kill-buffer "*org-goto*")
|
||||
(unwind-protect (recursive-edit)
|
||||
(when-let ((window (get-buffer-window "*Org Help*" t)))
|
||||
(quit-window 'kill window)))))
|
||||
(when (get-buffer "*org-goto*") (kill-buffer "*org-goto*"))
|
||||
(cons org-goto-selected-point org-goto-exit-command)))
|
||||
|
||||
;;;###autoload
|
||||
|
|
|
@ -168,9 +168,10 @@ means of creating calendar-based reminders."
|
|||
("m" . 30.4) ("y" . 365.25))))))
|
||||
(error "Invalid duration string: %s" ts)))
|
||||
|
||||
(defun org-is-habit-p (&optional pom)
|
||||
"Is the task at POM or point a habit?"
|
||||
(string= "habit" (org-entry-get (or pom (point)) "STYLE")))
|
||||
(defun org-is-habit-p (&optional epom)
|
||||
"Is the task at EPOM or point a habit?
|
||||
EPOM is an element, marker, or buffer position."
|
||||
(string= "habit" (org-entry-get epom "STYLE" 'selective)))
|
||||
|
||||
(defun org-habit-parse-todo (&optional pom)
|
||||
"Parse the TODO surrounding point for its habit-related data.
|
||||
|
@ -263,8 +264,8 @@ This list represents a \"habit\" for the rest of this module."
|
|||
(defsubst org-habit-repeat-type (habit)
|
||||
(nth 5 habit))
|
||||
|
||||
(defsubst org-habit-get-priority (habit &optional moment)
|
||||
"Determine the relative priority of a habit.
|
||||
(defsubst org-habit-get-urgency (habit &optional moment)
|
||||
"Determine the relative urgency of a habit.
|
||||
This must take into account not just urgency, but consistency as well."
|
||||
(let ((pri 1000)
|
||||
(now (if moment (time-to-days moment) (org-today)))
|
||||
|
|
|
@ -29,13 +29,13 @@
|
|||
;; are provided that create and retrieve such identifiers, and that find
|
||||
;; entries based on the identifier.
|
||||
|
||||
;; Identifiers consist of a prefix (default "Org" given by the variable
|
||||
;; Identifiers consist of a prefix (given by the variable
|
||||
;; `org-id-prefix') and a unique part that can be created by a number
|
||||
;; of different methods, see the variable `org-id-method'.
|
||||
;; Org has a builtin method that uses a compact encoding of the creation
|
||||
;; time of the ID, with microsecond accuracy. This virtually
|
||||
;; guarantees globally unique identifiers, even if several people are
|
||||
;; creating IDs at the same time in files that will eventually be used
|
||||
;; of different methods, see the variable `org-id-method'. Org has a
|
||||
;; builtin method that uses a compact encoding of the creation time of
|
||||
;; the ID, with microsecond accuracy. This virtually guarantees
|
||||
;; globally unique identifiers, even if several people are creating
|
||||
;; IDs at the same time in files that will eventually be used
|
||||
;; together.
|
||||
;;
|
||||
;; By default Org uses UUIDs as global unique identifiers.
|
||||
|
@ -74,6 +74,7 @@
|
|||
(org-assert-version)
|
||||
|
||||
(require 'org)
|
||||
(require 'org-element-ast)
|
||||
(require 'org-refile)
|
||||
(require 'ol)
|
||||
|
||||
|
@ -128,6 +129,46 @@ nil Never use an ID to make a link, instead link using a text search for
|
|||
(const :tag "Only use existing" use-existing)
|
||||
(const :tag "Do not use ID to create link" nil)))
|
||||
|
||||
(defcustom org-id-link-consider-parent-id nil
|
||||
"Non-nil means storing a link to an Org entry considers inherited IDs.
|
||||
|
||||
When this option is non-nil and `org-id-link-use-context' is
|
||||
enabled, ID properties inherited from parent entries will be
|
||||
considered when storing an ID link. If no ID is found in this
|
||||
way, a new one may be created as normal (see
|
||||
`org-id-link-to-org-use-id').
|
||||
|
||||
For example, given this org file:
|
||||
|
||||
* Parent
|
||||
:PROPERTIES:
|
||||
:ID: abc
|
||||
:END:
|
||||
** Child 1
|
||||
** Child 2
|
||||
|
||||
With `org-id-link-consider-parent-id' and
|
||||
`org-id-link-use-context' both enabled, storing a link with point
|
||||
at \"Child 1\" will produce a link \"<id:abc::*Child 1>\". This
|
||||
allows linking to uniquely-named sub-entries within a parent
|
||||
entry with an ID, without requiring every sub-entry to have its
|
||||
own ID."
|
||||
:group 'org-link-store
|
||||
:group 'org-id
|
||||
:package-version '(Org . "9.7")
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom org-id-link-use-context t
|
||||
"Non-nil means enables search string context in org-id links.
|
||||
|
||||
Search strings are added by `org-id-store-link' when both the
|
||||
general option `org-link-context-for-files' and the org-id option
|
||||
`org-id-link-use-context' are non-nil."
|
||||
:group 'org-link-store
|
||||
:group 'org-id
|
||||
:package-version '(Org . "9.7")
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom org-id-uuid-program "uuidgen"
|
||||
"The uuidgen program."
|
||||
:group 'org-id
|
||||
|
@ -225,6 +266,8 @@ systems."
|
|||
|
||||
(defvar org-id-locations nil
|
||||
"List of files with IDs in those files.")
|
||||
(defvar org-id--locations-checksum nil
|
||||
"Last checksum corresponding to ID files and their modifications.")
|
||||
|
||||
(defvar org-id-files nil
|
||||
"List of files that contain IDs.")
|
||||
|
@ -277,25 +320,32 @@ This is useful when working with contents in a temporary buffer
|
|||
that will be copied back to the original.")
|
||||
|
||||
;;;###autoload
|
||||
(defun org-id-get (&optional pom create prefix)
|
||||
"Get the ID property of the entry at point-or-marker POM.
|
||||
If POM is nil, refer to the entry at point.
|
||||
If the entry does not have an ID, the function returns nil.
|
||||
However, when CREATE is non-nil, create an ID if none is present already.
|
||||
PREFIX will be passed through to `org-id-new'.
|
||||
In any case, the ID of the entry is returned."
|
||||
(org-with-point-at pom
|
||||
(let ((id (org-entry-get nil "ID")))
|
||||
(cond
|
||||
((and id (stringp id) (string-match "\\S-" id))
|
||||
id)
|
||||
(create
|
||||
(setq id (org-id-new prefix))
|
||||
(org-entry-put pom "ID" id)
|
||||
(org-id-add-location id
|
||||
(defun org-id-get (&optional epom create prefix inherit)
|
||||
"Get the ID of the entry at EPOM.
|
||||
|
||||
EPOM is an element, marker, or buffer position. If EPOM is nil,
|
||||
refer to the entry at point.
|
||||
|
||||
If INHERIT is non-nil, ID properties inherited from parent
|
||||
entries are considered. Otherwise, only ID properties on the
|
||||
entry itself are considered.
|
||||
|
||||
When CREATE is nil, return the ID of the entry if found,
|
||||
otherwise nil. When CREATE is non-nil, create an ID if none has
|
||||
been found, and return the new ID. PREFIX will be passed through
|
||||
to `org-id-new'."
|
||||
(let ((id (org-entry-get epom "ID" (and inherit t))))
|
||||
(cond
|
||||
((and id (stringp id) (string-match "\\S-" id))
|
||||
id)
|
||||
(create
|
||||
(setq id (org-id-new prefix))
|
||||
(org-entry-put epom "ID" id)
|
||||
(org-with-point-at epom
|
||||
(org-id-add-location id
|
||||
(or org-id-overriding-file-name
|
||||
(buffer-file-name (buffer-base-buffer))))
|
||||
id)))))
|
||||
(buffer-file-name (buffer-base-buffer)))))
|
||||
id))))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-id-get-with-outline-path-completion (&optional targets)
|
||||
|
@ -399,30 +449,6 @@ So a typical ID could look like \"Org:4nd91V40HI\"."
|
|||
(t (error "Invalid `org-id-method'")))
|
||||
(concat prefix unique)))
|
||||
|
||||
(defun org-id-uuid ()
|
||||
"Return string with random (version 4) UUID."
|
||||
(let ((rnd (md5 (format "%s%s%s%s%s%s%s"
|
||||
(random)
|
||||
(org-time-convert-to-list nil)
|
||||
(user-uid)
|
||||
(emacs-pid)
|
||||
(user-full-name)
|
||||
user-mail-address
|
||||
(recent-keys)))))
|
||||
(format "%s-%s-4%s-%s%s-%s"
|
||||
(substring rnd 0 8)
|
||||
(substring rnd 8 12)
|
||||
(substring rnd 13 16)
|
||||
(format "%x"
|
||||
(logior
|
||||
#b10000000
|
||||
(logand
|
||||
#b10111111
|
||||
(string-to-number
|
||||
(substring rnd 16 18) 16))))
|
||||
(substring rnd 18 20)
|
||||
(substring rnd 20 32))))
|
||||
|
||||
(defun org-id-int-to-b36-one-digit (integer)
|
||||
"Convert INTEGER between 0 and 61 into a single character 0..9, A..Z, a..z."
|
||||
(cond
|
||||
|
@ -500,7 +526,6 @@ If SILENT is non-nil, messages are suppressed."
|
|||
(interactive)
|
||||
(unless org-id-track-globally
|
||||
(error "Please turn on `org-id-track-globally' if you want to track IDs"))
|
||||
(setq org-id-locations nil)
|
||||
(let* ((files
|
||||
(delete-dups
|
||||
(mapcar #'file-truename
|
||||
|
@ -524,11 +549,18 @@ If SILENT is non-nil, messages are suppressed."
|
|||
(nfiles (length files))
|
||||
(id-regexp
|
||||
(rx (seq bol (0+ (any "\t ")) ":ID:" (1+ " ") (not (any " ")))))
|
||||
(seen-ids nil)
|
||||
(seen-ids (make-hash-table :test #'equal))
|
||||
(ndup 0)
|
||||
(i 0))
|
||||
(with-temp-buffer
|
||||
(org-element-with-disabled-cache
|
||||
(i 0)
|
||||
(checksum
|
||||
(mapcar
|
||||
(lambda (f)
|
||||
(when (file-exists-p f)
|
||||
(list f (file-attribute-modification-time (file-attributes f)))))
|
||||
(sort (copy-sequence files) #'string<))))
|
||||
(unless (equal checksum org-id--locations-checksum) ; Files have changed since the last update.
|
||||
(setq org-id-locations nil)
|
||||
(with-temp-buffer
|
||||
(delay-mode-hooks
|
||||
(org-mode)
|
||||
(dolist (file files)
|
||||
|
@ -538,29 +570,32 @@ If SILENT is non-nil, messages are suppressed."
|
|||
(message "Finding ID locations (%d/%d files): %s" i nfiles file))
|
||||
(insert-file-contents file nil nil nil 'replace)
|
||||
(let ((ids nil)
|
||||
node
|
||||
(case-fold-search t))
|
||||
(org-with-point-at 1
|
||||
(while (re-search-forward id-regexp nil t)
|
||||
(when (org-at-property-p)
|
||||
(push (org-entry-get (point) "ID") ids)))
|
||||
(setq node (org-element-at-point))
|
||||
(when (org-element-type-p node 'node-property)
|
||||
(push (org-element-property :value node) ids)))
|
||||
(when ids
|
||||
(push (cons (abbreviate-file-name file) ids)
|
||||
org-id-locations)
|
||||
(dolist (id ids)
|
||||
(cond
|
||||
((not (member id seen-ids)) (push id seen-ids))
|
||||
((not (gethash id seen-ids)) (puthash id t seen-ids))
|
||||
(silent nil)
|
||||
(t
|
||||
(message "Duplicate ID %S" id)
|
||||
(cl-incf ndup))))))))))))
|
||||
(setq org-id-files (mapcar #'car org-id-locations))
|
||||
(org-id-locations-save)
|
||||
;; Now convert to a hash table.
|
||||
(setq org-id-locations (org-id-alist-to-hash org-id-locations))
|
||||
(when (and (not silent) (> ndup 0))
|
||||
(warn "WARNING: %d duplicate IDs found, check *Messages* buffer" ndup))
|
||||
(message "%d files scanned, %d files contains IDs, and %d IDs found."
|
||||
nfiles (length org-id-files) (hash-table-count org-id-locations))
|
||||
(cl-incf ndup)))))))))))
|
||||
(setq org-id-files (mapcar #'car org-id-locations))
|
||||
(org-id-locations-save)
|
||||
;; Now convert to a hash table.
|
||||
(setq org-id-locations (org-id-alist-to-hash org-id-locations))
|
||||
(setq org-id--locations-checksum checksum)
|
||||
(when (and (not silent) (> ndup 0))
|
||||
(warn "WARNING: %d duplicate IDs found, check *Messages* buffer" ndup))
|
||||
(message "%d files scanned, %d files contains IDs, and %d IDs found."
|
||||
nfiles (length org-id-files) (hash-table-count org-id-locations)))
|
||||
org-id-locations))
|
||||
|
||||
(defun org-id-locations-save ()
|
||||
|
@ -686,34 +721,81 @@ optional argument MARKERP, return the position as a new marker."
|
|||
((not (file-exists-p file)) nil)
|
||||
(t
|
||||
(let* ((visiting (find-buffer-visiting file))
|
||||
(buffer (or visiting (find-file-noselect file))))
|
||||
(buffer (or visiting
|
||||
(if markerp (find-file-noselect file)
|
||||
(org-get-buffer-create " *Org ID temp*" t)))))
|
||||
(unwind-protect
|
||||
(with-current-buffer buffer
|
||||
(unless (derived-mode-p 'org-mode) (org-mode))
|
||||
(unless (or visiting markerp)
|
||||
(buffer-disable-undo)
|
||||
;; FIXME: In Emacs 27, `insert-file-contents' seemingly
|
||||
;; does not trigger modification hooks in some
|
||||
;; scenarios. This is manifested in test failures due
|
||||
;; to element cache losing track of the modifications.
|
||||
(org-element-cache-reset)
|
||||
(insert-file-contents file nil nil nil 'replace))
|
||||
(let ((pos (org-find-entry-with-id id)))
|
||||
(cond
|
||||
((null pos) nil)
|
||||
(markerp (move-marker (make-marker) pos buffer))
|
||||
(t (cons file pos)))))
|
||||
;; Remove opened buffer in the process.
|
||||
(unless (or visiting markerp) (kill-buffer buffer)))))))
|
||||
;; Clean temporarily buffer if we don't need to keep it.
|
||||
(unless (or visiting markerp)
|
||||
(with-current-buffer buffer (erase-buffer))))))))
|
||||
|
||||
;; id link type
|
||||
|
||||
;; Calling the following function is hard-coded into `org-store-link',
|
||||
;; so we do have to add it to `org-store-link-functions'.
|
||||
(defun org-id--get-id-to-store-link (&optional create)
|
||||
"Get or create the relevant ID for storing a link.
|
||||
|
||||
Optional argument CREATE is passed to `org-id-get'.
|
||||
|
||||
Inherited IDs are only considered when
|
||||
`org-id-link-consider-parent-id', `org-id-link-use-context' and
|
||||
`org-link-context-for-files' are all enabled, since inherited IDs
|
||||
are confusing without the additional search string context.
|
||||
|
||||
Note that this function resets the
|
||||
`org-entry-property-inherited-from' marker: it will either point
|
||||
to nil (if the id was not inherited) or to the point it was
|
||||
inherited from."
|
||||
(let* ((inherit-id (and org-id-link-consider-parent-id
|
||||
org-id-link-use-context
|
||||
org-link-context-for-files)))
|
||||
(move-marker org-entry-property-inherited-from nil)
|
||||
(org-id-get nil create nil inherit-id)))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-id-store-link ()
|
||||
"Store a link to the current entry, using its ID.
|
||||
|
||||
If before first heading store first title-keyword as description
|
||||
or filename if no title."
|
||||
The link description is based on the heading, or if before the
|
||||
first heading, the title keyword if available, or else the
|
||||
filename.
|
||||
|
||||
When `org-link-context-for-files' and `org-id-link-use-context'
|
||||
are non-nil, add a search string to the link. The link
|
||||
description is then based on the search string target.
|
||||
|
||||
When in addition `org-id-link-consider-parent-id' is non-nil, the
|
||||
ID can be inherited from a parent entry, with the search string
|
||||
used to still link to the current location."
|
||||
(interactive)
|
||||
(when (and (buffer-file-name (buffer-base-buffer)) (derived-mode-p 'org-mode))
|
||||
(let* ((link (concat "id:" (org-id-get-create)))
|
||||
(when (and (buffer-file-name (buffer-base-buffer))
|
||||
(derived-mode-p 'org-mode))
|
||||
;; Get the precise target first, in case looking for an id causes
|
||||
;; a properties drawer to be added at the current location.
|
||||
(let* ((precise-target (and org-link-context-for-files
|
||||
org-id-link-use-context
|
||||
(org-link-precise-link-target)))
|
||||
(link (concat "id:" (org-id--get-id-to-store-link 'create)))
|
||||
(id-location (or (and org-entry-property-inherited-from
|
||||
(marker-position org-entry-property-inherited-from))
|
||||
(save-excursion (org-back-to-heading-or-point-min t) (point))))
|
||||
(case-fold-search nil)
|
||||
(desc (save-excursion
|
||||
(org-back-to-heading-or-point-min t)
|
||||
(goto-char id-location)
|
||||
(cond ((org-before-first-heading-p)
|
||||
(let ((keywords (org-collect-keywords '("TITLE"))))
|
||||
(if keywords
|
||||
|
@ -725,14 +807,59 @@ or filename if no title."
|
|||
(match-string 4)
|
||||
(match-string 0)))
|
||||
(t link)))))
|
||||
;; Precise targets should be after id-location to avoid
|
||||
;; duplicating the current headline as a search string
|
||||
(when (and precise-target
|
||||
(> (nth 2 precise-target) id-location))
|
||||
(setq link (concat link "::" (nth 0 precise-target)))
|
||||
(setq desc (nth 1 precise-target)))
|
||||
(org-link-store-props :link link :description desc :type "id")
|
||||
link)))
|
||||
|
||||
(defun org-id-open (id _)
|
||||
"Go to the entry with id ID."
|
||||
(org-mark-ring-push)
|
||||
(let ((m (org-id-find id 'marker))
|
||||
cmd)
|
||||
;;;###autoload
|
||||
(defun org-id-store-link-maybe (&optional interactive?)
|
||||
"Store a link to the current entry using its ID if enabled.
|
||||
|
||||
The value of `org-id-link-to-org-use-id' determines whether an ID
|
||||
link should be stored, using `org-id-store-link'.
|
||||
|
||||
Assume the function is called interactively if INTERACTIVE? is
|
||||
non-nil."
|
||||
(when (and (buffer-file-name (buffer-base-buffer))
|
||||
(derived-mode-p 'org-mode)
|
||||
(or (eq org-id-link-to-org-use-id t)
|
||||
(and interactive?
|
||||
(or (eq org-id-link-to-org-use-id 'create-if-interactive)
|
||||
(and (eq org-id-link-to-org-use-id
|
||||
'create-if-interactive-and-no-custom-id)
|
||||
(not (org-entry-get nil "CUSTOM_ID")))))
|
||||
;; 'use-existing
|
||||
(and org-id-link-to-org-use-id
|
||||
(org-id--get-id-to-store-link))))
|
||||
(org-id-store-link)))
|
||||
|
||||
(defun org-id-open (link _)
|
||||
"Go to the entry indicated by id link LINK.
|
||||
|
||||
The link can include a search string after \"::\", which is
|
||||
passed to `org-link-search'.
|
||||
|
||||
For backwards compatibility with IDs that contain \"::\", if no
|
||||
match is found for the ID, the full link string including \"::\"
|
||||
will be tried as an ID."
|
||||
(let* ((option (and (string-match "::\\(.*\\)\\'" link)
|
||||
(match-string 1 link)))
|
||||
(id (if (not option) link
|
||||
(substring link 0 (match-beginning 0))))
|
||||
m cmd)
|
||||
(org-mark-ring-push)
|
||||
(setq m (org-id-find id 'marker))
|
||||
(when (and (not m) option)
|
||||
;; Backwards compatibility: if id is not found, try treating
|
||||
;; whole link as an id.
|
||||
(setq m (org-id-find link 'marker))
|
||||
(when m
|
||||
(setq option nil)))
|
||||
(unless m
|
||||
(error "Cannot find entry with ID \"%s\"" id))
|
||||
;; Use a buffer-switching command in analogy to finding files
|
||||
|
@ -749,9 +876,17 @@ or filename if no title."
|
|||
(funcall cmd (marker-buffer m)))
|
||||
(goto-char m)
|
||||
(move-marker m nil)
|
||||
(when option
|
||||
(save-restriction
|
||||
(unless (org-before-first-heading-p)
|
||||
(org-narrow-to-subtree))
|
||||
(org-link-search option nil nil
|
||||
(org-element-lineage (org-element-at-point) 'headline t))))
|
||||
(org-fold-show-context)))
|
||||
|
||||
(org-link-set-parameters "id" :follow #'org-id-open)
|
||||
(org-link-set-parameters "id"
|
||||
:follow #'org-id-open
|
||||
:store #'org-id-store-link-maybe)
|
||||
|
||||
(provide 'org-id)
|
||||
|
||||
|
|
|
@ -103,6 +103,14 @@ For details see the variable `org-adapt-indentation'."
|
|||
:group 'org-indent
|
||||
:type 'integer)
|
||||
|
||||
(defcustom org-indent-post-buffer-init-functions nil
|
||||
"Hook run after org-indent finishes initializing a buffer.
|
||||
The function(s) in in this hook must accept a single argument representing
|
||||
the initialized buffer."
|
||||
:group 'org-indent
|
||||
:package-version '(Org . "9.7")
|
||||
:type 'hook)
|
||||
|
||||
(defface org-indent '((t (:inherit org-hide)))
|
||||
"Face for outline indentation.
|
||||
The default is to make it look like whitespace. But you may find it
|
||||
|
@ -290,7 +298,8 @@ a time value."
|
|||
;; Job is complete: un-agentize buffer.
|
||||
(unless interruptp
|
||||
(setq org-indent-agentized-buffers
|
||||
(delq buffer org-indent-agentized-buffers))))))))
|
||||
(delq buffer org-indent-agentized-buffers))
|
||||
(run-hook-with-args 'org-indent-post-buffer-init-functions buffer)))))))
|
||||
|
||||
(defun org-indent-set-line-properties (level indentation &optional heading)
|
||||
"Set prefix properties on current line an move to next one.
|
||||
|
@ -328,7 +337,7 @@ stopped."
|
|||
(save-match-data
|
||||
(org-with-wide-buffer
|
||||
(goto-char beg)
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
;; Initialize prefix at BEG, according to current entry's level.
|
||||
(let* ((case-fold-search t)
|
||||
(limited-re (org-get-limited-outline-regexp))
|
||||
|
@ -410,7 +419,7 @@ This function is meant to be called by `after-change-functions'."
|
|||
(if (or org-indent-modified-headline-flag
|
||||
(save-excursion
|
||||
(goto-char beg)
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(re-search-forward
|
||||
(org-with-limited-levels org-outline-regexp-bol)
|
||||
(save-excursion
|
||||
|
|
|
@ -94,9 +94,8 @@ Don't set it to something higher than `29' or clocking will break since this
|
|||
is the hardcoded maximum number of stars `org-clock-sum' will work with.
|
||||
|
||||
It is strongly recommended that you set `org-cycle-max-level' not at all,
|
||||
or to a number smaller than this one. In fact, when `org-cycle-max-level' is
|
||||
not set, it will be assumed to be one less than the value of smaller than
|
||||
the value of this variable."
|
||||
or to a number smaller than this one. See `org-cycle-max-level'
|
||||
docstring for more details."
|
||||
:group 'org-inlinetask
|
||||
:type '(choice
|
||||
(const :tag "Off" nil)
|
||||
|
@ -175,7 +174,7 @@ The number of levels is controlled by `org-inlinetask-min-level'."
|
|||
(defun org-inlinetask-in-task-p ()
|
||||
"Return true if point is inside an inline task."
|
||||
(save-excursion
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(let ((case-fold-search t))
|
||||
(or (looking-at-p (concat (org-inlinetask-outline-regexp) "\\(?:.*\\)"))
|
||||
(and (re-search-forward "^\\*+[ \t]+" nil t)
|
||||
|
@ -194,7 +193,7 @@ The number of levels is controlled by `org-inlinetask-min-level'."
|
|||
"Go to the end of the inline task at point.
|
||||
Return point."
|
||||
(save-match-data
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(let ((case-fold-search t)
|
||||
(inlinetask-re (org-inlinetask-outline-regexp)))
|
||||
(cond
|
||||
|
@ -242,7 +241,7 @@ going below `org-inlinetask-min-level'."
|
|||
(replace-match down-task nil t nil 1)
|
||||
(org-inlinetask-goto-end)
|
||||
(if (and (eobp) (looking-back "END\\s-*" (line-beginning-position)))
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(forward-line -1))
|
||||
(unless (= (point) beg)
|
||||
(looking-at (org-inlinetask-outline-regexp))
|
||||
|
@ -268,7 +267,7 @@ If the task has an end part, also demote it."
|
|||
(replace-match down-task nil t nil 1)
|
||||
(org-inlinetask-goto-end)
|
||||
(if (and (eobp) (looking-back "END\\s-*" (line-beginning-position)))
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(forward-line -1))
|
||||
(unless (= (point) beg)
|
||||
(looking-at (org-inlinetask-outline-regexp))
|
||||
|
|
|
@ -85,11 +85,26 @@
|
|||
(declare-function org-down-element "org" ())
|
||||
(declare-function org-edit-special "org" (&optional arg))
|
||||
(declare-function org-element-at-point "org-element" (&optional pom cached-only))
|
||||
(declare-function org-element-type "org-element" (element))
|
||||
(declare-function org-element-type-p "org-element-ast" (node types))
|
||||
(declare-function org-emphasize "org" (&optional char))
|
||||
(declare-function org-end-of-line "org" (&optional n))
|
||||
(declare-function org-entry-put "org" (pom property value))
|
||||
(declare-function org-eval-in-calendar "org" (form &optional keepdate))
|
||||
(declare-function org-calendar-goto-today-or-insert-dot "org" ())
|
||||
(declare-function org-calendar-goto-today "org" ())
|
||||
(declare-function org-calendar-backward-month "org" ())
|
||||
(declare-function org-calendar-forward-month "org" ())
|
||||
(declare-function org-calendar-backward-year "org" ())
|
||||
(declare-function org-calendar-forward-year "org" ())
|
||||
(declare-function org-calendar-backward-week "org" ())
|
||||
(declare-function org-calendar-forward-week "org" ())
|
||||
(declare-function org-calendar-backward-day "org" ())
|
||||
(declare-function org-calendar-forward-day "org" ())
|
||||
(declare-function org-calendar-view-entries "org" ())
|
||||
(declare-function org-calendar-scroll-month-left "org" ())
|
||||
(declare-function org-calendar-scroll-month-right "org" ())
|
||||
(declare-function org-calendar-scroll-three-months-left "org" ())
|
||||
(declare-function org-calendar-scroll-three-months-right "org" ())
|
||||
(declare-function org-evaluate-time-range "org" (&optional to-buffer))
|
||||
(declare-function org-export-dispatch "org" (&optional arg))
|
||||
(declare-function org-feed-goto-inbox "org" (feed))
|
||||
|
@ -190,8 +205,8 @@
|
|||
(declare-function org-table-sum "org" (&optional beg end nlast))
|
||||
(declare-function org-table-toggle-coordinate-overlays "org" ())
|
||||
(declare-function org-table-toggle-formula-debugger "org" ())
|
||||
(declare-function org-time-stamp "org" (arg &optional inactive))
|
||||
(declare-function org-time-stamp-inactive "org" (&optional arg))
|
||||
(declare-function org-timestamp "org" (arg &optional inactive))
|
||||
(declare-function org-timestamp-inactive "org" (&optional arg))
|
||||
(declare-function org-timer "org" (&optional restart no-insert))
|
||||
(declare-function org-timer-item "org" (&optional arg))
|
||||
(declare-function org-timer-pause-or-continue "org" (&optional stop))
|
||||
|
@ -210,7 +225,7 @@
|
|||
(declare-function org-toggle-ordered-property "org" ())
|
||||
(declare-function org-toggle-pretty-entities "org" ())
|
||||
(declare-function org-toggle-tags-groups "org" ())
|
||||
(declare-function org-toggle-time-stamp-overlays "org" ())
|
||||
(declare-function org-toggle-timestamp-overlays "org" ())
|
||||
(declare-function org-transpose-element "org" ())
|
||||
(declare-function org-transpose-words "org" ())
|
||||
(declare-function org-tree-to-indirect-buffer "org" (&optional arg))
|
||||
|
@ -273,7 +288,7 @@ therefore you'll have to restart Emacs to apply it after changing."
|
|||
|
||||
(defcustom org-mouse-1-follows-link
|
||||
(if (boundp 'mouse-1-click-follows-link) mouse-1-click-follows-link t)
|
||||
"Non-nil means mouse-1 on a link will follow the link.
|
||||
"Non-nil means Mouse-1 on a link will follow the link.
|
||||
A longer mouse click will still set point. Needs to be set
|
||||
before org.el is loaded."
|
||||
:group 'org-link-follow
|
||||
|
@ -298,7 +313,7 @@ implementation is bad."
|
|||
:type 'hook)
|
||||
|
||||
(defcustom org-return-follows-link nil
|
||||
"Non-nil means on links RET will follow the link.
|
||||
"Non-nil means on links RET will open links, timestamps, and citations.
|
||||
In tables, the special behavior of RET has precedence."
|
||||
:group 'org-link-follow
|
||||
:type 'boolean
|
||||
|
@ -309,7 +324,7 @@ In tables, the special behavior of RET has precedence."
|
|||
|
||||
;;;; Base functions
|
||||
(defun org-key (key)
|
||||
"Select key according to `org-replace-disputed-keys' and `org-disputed-keys'.
|
||||
"Select KEY according to `org-replace-disputed-keys' and `org-disputed-keys'.
|
||||
Or return the original if not disputed."
|
||||
(when org-replace-disputed-keys
|
||||
(let* ((nkey (key-description key))
|
||||
|
@ -319,7 +334,7 @@ Or return the original if not disputed."
|
|||
key)
|
||||
|
||||
(defun org-defkey (keymap key def)
|
||||
"Define a key, possibly translated, as returned by `org-key'."
|
||||
"Define KEY, possibly translated, as returned by `org-key' in KEYMAP to DEF."
|
||||
(define-key keymap (org-key key) def))
|
||||
|
||||
(defun org-remap (map &rest commands)
|
||||
|
@ -349,71 +364,25 @@ COMMANDS is a list of alternating OLDDEF NEWDEF command names."
|
|||
(defvar org-read-date-minibuffer-local-map
|
||||
(let* ((map (make-sparse-keymap)))
|
||||
(set-keymap-parent map minibuffer-local-map)
|
||||
(org-defkey map (kbd ".")
|
||||
(lambda () (interactive)
|
||||
;; Are we at the beginning of the prompt?
|
||||
(if (looking-back "^[^:]+: "
|
||||
(let ((inhibit-field-text-motion t))
|
||||
(line-beginning-position)))
|
||||
(org-eval-in-calendar '(calendar-goto-today))
|
||||
(insert "."))))
|
||||
(org-defkey map (kbd "C-.")
|
||||
(lambda () (interactive)
|
||||
(org-eval-in-calendar '(calendar-goto-today))))
|
||||
(org-defkey map (kbd "M-S-<left>")
|
||||
(lambda () (interactive)
|
||||
(org-eval-in-calendar '(calendar-backward-month 1))))
|
||||
(org-defkey map (kbd "ESC S-<left>")
|
||||
(lambda () (interactive)
|
||||
(org-eval-in-calendar '(calendar-backward-month 1))))
|
||||
(org-defkey map (kbd "M-S-<right>")
|
||||
(lambda () (interactive)
|
||||
(org-eval-in-calendar '(calendar-forward-month 1))))
|
||||
(org-defkey map (kbd "ESC S-<right>")
|
||||
(lambda () (interactive)
|
||||
(org-eval-in-calendar '(calendar-forward-month 1))))
|
||||
(org-defkey map (kbd "M-S-<up>")
|
||||
(lambda () (interactive)
|
||||
(org-eval-in-calendar '(calendar-backward-year 1))))
|
||||
(org-defkey map (kbd "ESC S-<up>")
|
||||
(lambda () (interactive)
|
||||
(org-eval-in-calendar '(calendar-backward-year 1))))
|
||||
(org-defkey map (kbd "M-S-<down>")
|
||||
(lambda () (interactive)
|
||||
(org-eval-in-calendar '(calendar-forward-year 1))))
|
||||
(org-defkey map (kbd "ESC S-<down>")
|
||||
(lambda () (interactive)
|
||||
(org-eval-in-calendar '(calendar-forward-year 1))))
|
||||
(org-defkey map (kbd "S-<up>")
|
||||
(lambda () (interactive)
|
||||
(org-eval-in-calendar '(calendar-backward-week 1))))
|
||||
(org-defkey map (kbd "S-<down>")
|
||||
(lambda () (interactive)
|
||||
(org-eval-in-calendar '(calendar-forward-week 1))))
|
||||
(org-defkey map (kbd "S-<left>")
|
||||
(lambda () (interactive)
|
||||
(org-eval-in-calendar '(calendar-backward-day 1))))
|
||||
(org-defkey map (kbd "S-<right>")
|
||||
(lambda () (interactive)
|
||||
(org-eval-in-calendar '(calendar-forward-day 1))))
|
||||
(org-defkey map (kbd "!")
|
||||
(lambda () (interactive)
|
||||
(org-eval-in-calendar '(diary-view-entries))
|
||||
(message "")))
|
||||
(org-defkey map (kbd ">")
|
||||
(lambda () (interactive)
|
||||
(org-eval-in-calendar '(calendar-scroll-left 1))))
|
||||
(org-defkey map (kbd "<")
|
||||
(lambda () (interactive)
|
||||
(org-eval-in-calendar '(calendar-scroll-right 1))))
|
||||
(org-defkey map (kbd "C-v")
|
||||
(lambda () (interactive)
|
||||
(org-eval-in-calendar
|
||||
'(calendar-scroll-left-three-months 1))))
|
||||
(org-defkey map (kbd "M-v")
|
||||
(lambda () (interactive)
|
||||
(org-eval-in-calendar
|
||||
'(calendar-scroll-right-three-months 1))))
|
||||
(org-defkey map (kbd ".") #'org-calendar-goto-today-or-insert-dot)
|
||||
(org-defkey map (kbd "C-.") #'org-calendar-goto-today)
|
||||
(org-defkey map (kbd "M-S-<left>") #'org-calendar-backward-month)
|
||||
(org-defkey map (kbd "ESC S-<left>") #'org-calendar-backward-month)
|
||||
(org-defkey map (kbd "M-S-<right>") #'org-calendar-forward-month)
|
||||
(org-defkey map (kbd "ESC S-<right>") #'org-calendar-forward-month)
|
||||
(org-defkey map (kbd "M-S-<up>") #'org-calendar-backward-year)
|
||||
(org-defkey map (kbd "ESC S-<up>") #'org-calendar-backward-year)
|
||||
(org-defkey map (kbd "M-S-<down>") #'org-calendar-forward-year)
|
||||
(org-defkey map (kbd "ESC S-<down>") #'org-calendar-forward-year)
|
||||
(org-defkey map (kbd "S-<up>") #'org-calendar-backward-week)
|
||||
(org-defkey map (kbd "S-<down>") #'org-calendar-forward-week)
|
||||
(org-defkey map (kbd "S-<left>") #'org-calendar-backward-day)
|
||||
(org-defkey map (kbd "S-<right>") #'org-calendar-forward-day)
|
||||
(org-defkey map (kbd "!") #'org-calendar-view-entries)
|
||||
(org-defkey map (kbd ">") #'org-calendar-scroll-month-left)
|
||||
(org-defkey map (kbd "<") #'org-calendar-scroll-month-right)
|
||||
(org-defkey map (kbd "C-v") #'org-calendar-scroll-three-months-left)
|
||||
(org-defkey map (kbd "M-v") #'org-calendar-scroll-three-months-right)
|
||||
map)
|
||||
"Keymap for minibuffer commands when using `org-read-date'.")
|
||||
|
||||
|
@ -503,6 +472,7 @@ COMMANDS is a list of alternating OLDDEF NEWDEF command names."
|
|||
(org-defkey org-mode-map (kbd "C-c C-x c") #'org-table-copy-down)
|
||||
(org-defkey org-mode-map (kbd "C-c C-x m") #'org-meta-return)
|
||||
(org-defkey org-mode-map (kbd "C-c C-x M") #'org-insert-todo-heading)
|
||||
(org-defkey org-mode-map (kbd "C-c C-x s") #'org-insert-structure-template)
|
||||
(org-defkey org-mode-map (kbd "C-c C-x RET") #'org-meta-return)
|
||||
(org-defkey org-mode-map (kbd "ESC RET") #'org-meta-return)
|
||||
(org-defkey org-mode-map (kbd "ESC <left>") #'org-metaleft)
|
||||
|
@ -593,8 +563,8 @@ COMMANDS is a list of alternating OLDDEF NEWDEF command names."
|
|||
(org-defkey org-mode-map (kbd "C-c %") #'org-mark-ring-push)
|
||||
(org-defkey org-mode-map (kbd "C-c &") #'org-mark-ring-goto)
|
||||
(org-defkey org-mode-map (kbd "C-c C-z") #'org-add-note) ;alternative binding
|
||||
(org-defkey org-mode-map (kbd "C-c .") #'org-time-stamp) ;minor-mode reserved
|
||||
(org-defkey org-mode-map (kbd "C-c !") #'org-time-stamp-inactive) ;minor-mode r.
|
||||
(org-defkey org-mode-map (kbd "C-c .") #'org-timestamp) ;minor-mode reserved
|
||||
(org-defkey org-mode-map (kbd "C-c !") #'org-timestamp-inactive) ;minor-mode r.
|
||||
(org-defkey org-mode-map (kbd "C-c ,") #'org-priority) ;minor-mode reserved
|
||||
(org-defkey org-mode-map (kbd "C-c C-y") #'org-evaluate-time-range)
|
||||
(org-defkey org-mode-map (kbd "C-c >") #'org-goto-calendar)
|
||||
|
@ -638,7 +608,7 @@ COMMANDS is a list of alternating OLDDEF NEWDEF command names."
|
|||
(org-defkey org-mode-map (kbd "C-c C-x C-w") #'org-cut-special)
|
||||
(org-defkey org-mode-map (kbd "C-c C-x M-w") #'org-copy-special)
|
||||
(org-defkey org-mode-map (kbd "C-c C-x C-y") #'org-paste-special)
|
||||
(org-defkey org-mode-map (kbd "C-c C-x C-t") #'org-toggle-time-stamp-overlays)
|
||||
(org-defkey org-mode-map (kbd "C-c C-x C-t") #'org-toggle-timestamp-overlays)
|
||||
(org-defkey org-mode-map (kbd "C-c C-x C-i") #'org-clock-in)
|
||||
(org-defkey org-mode-map (kbd "C-c C-x C-x") #'org-clock-in-last)
|
||||
(org-defkey org-mode-map (kbd "C-c C-x C-z") #'org-resolve-clocks)
|
||||
|
@ -788,19 +758,21 @@ command."
|
|||
(function)
|
||||
(sexp))))))
|
||||
|
||||
(defun org-print-speed-command (e)
|
||||
(if (> (length (car e)) 1)
|
||||
(defun org--print-speed-command (speed-command)
|
||||
"Print information about SPEED-COMMAND in help buffer.
|
||||
SPEED-COMMAND is an element of `org-speed-commands'."
|
||||
(if (> (length (car speed-command)) 1)
|
||||
(progn
|
||||
(princ "\n")
|
||||
(princ (car e))
|
||||
(princ (car speed-command))
|
||||
(princ "\n")
|
||||
(princ (make-string (length (car e)) ?-))
|
||||
(princ (make-string (length (car speed-command)) ?-))
|
||||
(princ "\n"))
|
||||
(princ (car e))
|
||||
(princ (car speed-command))
|
||||
(princ " ")
|
||||
(if (symbolp (cdr e))
|
||||
(princ (symbol-name (cdr e)))
|
||||
(prin1 (cdr e)))
|
||||
(if (symbolp (cdr speed-command))
|
||||
(princ (symbol-name (cdr speed-command)))
|
||||
(prin1 (cdr speed-command)))
|
||||
(princ "\n")))
|
||||
|
||||
(defun org-speed-command-help ()
|
||||
|
@ -810,12 +782,7 @@ command."
|
|||
(user-error "Speed commands are not activated, customize `org-use-speed-commands'"))
|
||||
(with-output-to-temp-buffer "*Help*"
|
||||
(princ "Speed commands\n==============\n")
|
||||
(mapc #'org-print-speed-command
|
||||
;; FIXME: don't check `org-speed-commands-user' past 9.6
|
||||
(if (boundp 'org-speed-commands-user)
|
||||
(append org-speed-commands
|
||||
org-speed-commands-user)
|
||||
org-speed-commands)))
|
||||
(mapc #'org--print-speed-command org-speed-commands))
|
||||
(with-current-buffer "*Help*"
|
||||
(setq truncate-lines t)))
|
||||
|
||||
|
@ -831,16 +798,12 @@ If not, return to the original position and throw an error."
|
|||
|
||||
(defun org-speed-command-activate (keys)
|
||||
"Hook for activating single-letter speed commands.
|
||||
KEYS is the keys vector as returned by `this-command-keys-vector'.
|
||||
See `org-speed-commands' for configuring them."
|
||||
(when (or (and (bolp) (looking-at org-outline-regexp))
|
||||
(and (functionp org-use-speed-commands)
|
||||
(funcall org-use-speed-commands)))
|
||||
(cdr (assoc keys
|
||||
;; FIXME: don't check `org-speed-commands-user' past 9.6
|
||||
(if (boundp 'org-speed-commands-user)
|
||||
(append org-speed-commands
|
||||
org-speed-commands-user)
|
||||
org-speed-commands)))))
|
||||
(cdr (assoc keys org-speed-commands))))
|
||||
|
||||
|
||||
;;; Babel speed keys
|
||||
|
@ -910,10 +873,11 @@ a-list placed behind the generic `org-babel-key-prefix'.")
|
|||
(define-key org-babel-map key def))
|
||||
|
||||
(defun org-babel-speed-command-activate (keys)
|
||||
"Hook for activating single-letter code block commands."
|
||||
"Hook for activating single-letter code block commands.
|
||||
KEYS is the keys vector as returned by `this-command-keys-vector'."
|
||||
(when (and (bolp)
|
||||
(let ((case-fold-search t)) (looking-at "[ \t]*#\\+begin_src"))
|
||||
(eq 'src-block (org-element-type (org-element-at-point))))
|
||||
(org-element-type-p (org-element-at-point) 'src-block))
|
||||
(cdr (assoc keys org-babel-key-bindings))))
|
||||
|
||||
;;;###autoload
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -111,15 +111,22 @@
|
|||
(declare-function org-element-at-point "org-element" (&optional pom cached-only))
|
||||
(declare-function org-element-context "org-element" (&optional element))
|
||||
(declare-function org-element-interpret-data "org-element" (data))
|
||||
(declare-function org-element-lineage "org-element" (blob &optional types with-self))
|
||||
(declare-function org-element-lineage "org-element-ast" (blob &optional types with-self))
|
||||
(declare-function org-element-macro-interpreter "org-element" (macro ##))
|
||||
(declare-function org-element-map "org-element" (data types fun &optional info first-match no-recursion with-affiliated))
|
||||
(declare-function org-element-normalize-string "org-element" (s))
|
||||
(declare-function org-element-parse-buffer "org-element" (&optional granularity visible-only))
|
||||
(declare-function org-element-property "org-element" (property element))
|
||||
(declare-function org-element-put-property "org-element" (element property value))
|
||||
(declare-function org-element-set-element "org-element" (old new))
|
||||
(declare-function org-element-type "org-element" (element))
|
||||
(declare-function org-element-parse-buffer "org-element" (&optional granularity visible-only keep-deferred))
|
||||
(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-contents-begin "org-element" (node))
|
||||
(declare-function org-element-contents-end "org-element" (node))
|
||||
(declare-function org-element-post-affiliated "org-element" (node))
|
||||
(declare-function org-element-post-blank "org-element" (node))
|
||||
(declare-function org-element-parent "org-element-ast" (node))
|
||||
(declare-function org-element-put-property "org-element-ast" (node property value))
|
||||
(declare-function org-element-set "org-element-ast" (old new))
|
||||
(declare-function org-element-type-p "org-element-ast" (node types))
|
||||
(declare-function org-element-update-syntax "org-element" ())
|
||||
(declare-function org-end-of-meta-data "org" (&optional full))
|
||||
(declare-function org-entry-get "org" (pom property &optional inherit literal-nil))
|
||||
|
@ -364,16 +371,32 @@ group 2: counter
|
|||
group 3: checkbox
|
||||
group 4: description tag")
|
||||
|
||||
(defun org-item-re ()
|
||||
(defvar org--item-re-cache nil
|
||||
"Results cache for `org-item-re'.")
|
||||
(defsubst org-item-re ()
|
||||
"Return the correct regular expression for plain lists."
|
||||
(let ((term (cond
|
||||
((eq org-plain-list-ordered-item-terminator t) "[.)]")
|
||||
((= org-plain-list-ordered-item-terminator ?\)) ")")
|
||||
((= org-plain-list-ordered-item-terminator ?.) "\\.")
|
||||
(t "[.)]")))
|
||||
(alpha (if org-list-allow-alphabetical "\\|[A-Za-z]" "")))
|
||||
(concat "\\([ \t]*\\([-+]\\|\\(\\([0-9]+" alpha "\\)" term
|
||||
"\\)\\)\\|[ \t]+\\*\\)\\([ \t]+\\|$\\)")))
|
||||
(or (plist-get
|
||||
(plist-get org--item-re-cache
|
||||
org-list-allow-alphabetical)
|
||||
org-plain-list-ordered-item-terminator)
|
||||
(let* ((term (cond
|
||||
((eq org-plain-list-ordered-item-terminator t) "[.)]")
|
||||
((= org-plain-list-ordered-item-terminator ?\)) ")")
|
||||
((= org-plain-list-ordered-item-terminator ?.) "\\.")
|
||||
(t "[.)]")))
|
||||
(alpha (if org-list-allow-alphabetical "\\|[A-Za-z]" ""))
|
||||
(re (concat "\\([ \t]*\\([-+]\\|\\(\\([0-9]+" alpha "\\)" term
|
||||
"\\)\\)\\|[ \t]+\\*\\)\\([ \t]+\\|$\\)")))
|
||||
(setq org--item-re-cache
|
||||
(plist-put
|
||||
org--item-re-cache
|
||||
org-list-allow-alphabetical
|
||||
(plist-put
|
||||
(plist-get org--item-re-cache
|
||||
org-list-allow-alphabetical)
|
||||
org-plain-list-ordered-item-terminator
|
||||
re)))
|
||||
re)))
|
||||
|
||||
(defsubst org-item-beginning-re ()
|
||||
"Regexp matching the beginning of a plain list item."
|
||||
|
@ -400,7 +423,7 @@ group 4: description tag")
|
|||
(defun org-in-item-p ()
|
||||
"Return item beginning position when in a plain list, nil otherwise."
|
||||
(save-excursion
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(let* ((case-fold-search t)
|
||||
(context (org-list-context))
|
||||
(lim-up (car context))
|
||||
|
@ -448,7 +471,7 @@ group 4: description tag")
|
|||
(re-search-backward "^[ \t]*#\\+begin_" lim-up t)))
|
||||
((and (looking-at "^[ \t]*:END:")
|
||||
(re-search-backward org-drawer-regexp lim-up t))
|
||||
(beginning-of-line))
|
||||
(forward-line 0))
|
||||
((and inlinetask-re (looking-at inlinetask-re))
|
||||
(org-inlinetask-goto-beginning)
|
||||
(forward-line -1))
|
||||
|
@ -462,11 +485,18 @@ group 4: description tag")
|
|||
(forward-line -1))
|
||||
(t (forward-line -1)))))))))))
|
||||
|
||||
;; FIXME: We should make use of org-element API in more places here.
|
||||
(defun org-at-item-p ()
|
||||
"Is point in a line starting a hand-formatted item?"
|
||||
"Is point in a line starting a hand-formatted item?
|
||||
Modify match data, matching against `org-item-re'."
|
||||
(save-excursion
|
||||
(beginning-of-line)
|
||||
(and (looking-at (org-item-re)) (org-list-in-valid-context-p))))
|
||||
(forward-line 0)
|
||||
(and
|
||||
(org-element-type-p
|
||||
(org-element-at-point)
|
||||
'(plain-list item))
|
||||
;; Set match data.
|
||||
(looking-at (org-item-re)))))
|
||||
|
||||
(defun org-at-item-bullet-p ()
|
||||
"Is point at the bullet of a plain list item?"
|
||||
|
@ -508,7 +538,7 @@ Contexts `block' and `invalid' refer to `org-list-forbidden-blocks'."
|
|||
(save-match-data
|
||||
(save-excursion
|
||||
(org-with-limited-levels
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(let ((case-fold-search t) (pos (point)) beg end context-type
|
||||
;; Get positions of surrounding headings. This is the
|
||||
;; default context.
|
||||
|
@ -595,7 +625,7 @@ will get the following structure:
|
|||
|
||||
Assume point is at an item."
|
||||
(save-excursion
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(let* ((case-fold-search t)
|
||||
(context (org-list-context))
|
||||
(lim-up (car context))
|
||||
|
@ -663,7 +693,7 @@ Assume point is at an item."
|
|||
(re-search-backward "^[ \t]*#\\+begin_" lim-up t)))
|
||||
((and (looking-at "^[ \t]*:END:")
|
||||
(re-search-backward org-drawer-regexp lim-up t))
|
||||
(beginning-of-line))
|
||||
(forward-line 0))
|
||||
((and inlinetask-re (looking-at inlinetask-re))
|
||||
(org-inlinetask-goto-beginning)
|
||||
(forward-line -1))
|
||||
|
@ -1122,7 +1152,7 @@ This function modifies STRUCT."
|
|||
(org-fold-core-regions (cdr folds) :relative beg-A)
|
||||
(org-fold-core-regions
|
||||
(car folds)
|
||||
:relative (+ beg-B (- size-B size-A (length between-A-no-blank-and-B))))
|
||||
:relative (+ beg-A size-B (length between-A-no-blank-and-B)))
|
||||
;; 2. Now modify struct. No need to re-read the list, the
|
||||
;; transformation is just a shift of positions. Some special
|
||||
;; attention is required for items ending at END-A and END-B
|
||||
|
@ -1831,7 +1861,7 @@ Initial position of cursor is restored after the changes."
|
|||
(lambda (end beg delta)
|
||||
(goto-char end)
|
||||
(skip-chars-backward " \r\t\n")
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(while (or (> (point) beg)
|
||||
(and (= (point) beg)
|
||||
(not (looking-at item-re))))
|
||||
|
@ -2218,7 +2248,7 @@ item is invisible."
|
|||
(setq struct (org-list-insert-item pos struct prevs checkbox desc))
|
||||
(org-list-write-struct struct (org-list-parents-alist struct))
|
||||
(when checkbox (org-update-checkbox-count-maybe))
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(looking-at org-list-full-item-re)
|
||||
(goto-char (if (and (match-beginning 4)
|
||||
(save-match-data
|
||||
|
@ -2248,7 +2278,7 @@ is an integer, 0 means `-', 1 means `+' etc. If WHICH is
|
|||
(interactive "P")
|
||||
(unless (org-at-item-p) (error "Not at an item"))
|
||||
(let ((origin (point-marker)))
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(let* ((struct (org-list-struct))
|
||||
(parents (org-list-parents-alist struct))
|
||||
(prevs (org-list-prevs-alist struct))
|
||||
|
@ -2310,14 +2340,14 @@ is an integer, 0 means `-', 1 means `+' etc. If WHICH is
|
|||
(setq struct (org-list-struct))
|
||||
(cond
|
||||
((>= origin-offset2 0)
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(move-marker origin (+ (point)
|
||||
(org-list-get-ind (point) struct)
|
||||
(length (org-list-get-bullet (point) struct))
|
||||
origin-offset2))
|
||||
(goto-char origin))
|
||||
((>= origin-offset 0)
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(move-marker origin (+ (point)
|
||||
(org-list-get-ind (point) struct)
|
||||
origin-offset))
|
||||
|
@ -2362,15 +2392,15 @@ is an integer, 0 means `-', 1 means `+' etc. If WHICH is
|
|||
(defun org-at-radio-list-p ()
|
||||
"Is point at a list item with radio buttons?"
|
||||
(when (org-match-line (org-item-re)) ;short-circuit
|
||||
(let* ((e (save-excursion (beginning-of-line) (org-element-at-point))))
|
||||
(let* ((e (save-excursion (forward-line 0) (org-element-at-point))))
|
||||
;; Check we're really on a line with a bullet.
|
||||
(when (memq (org-element-type e) '(item plain-list))
|
||||
(when (org-element-type-p e '(item plain-list))
|
||||
;; Look for ATTR_ORG attribute in the current plain list.
|
||||
(let ((plain-list (org-element-lineage e '(plain-list) t)))
|
||||
(org-with-point-at (org-element-property :post-affiliated plain-list)
|
||||
(let ((plain-list (org-element-lineage e 'plain-list t)))
|
||||
(org-with-point-at (org-element-post-affiliated plain-list)
|
||||
(let ((case-fold-search t)
|
||||
(regexp "^[ \t]*#\\+attr_org:.* :radio \\(\\S-+\\)")
|
||||
(begin (org-element-property :begin plain-list)))
|
||||
(begin (org-element-begin plain-list)))
|
||||
(and (re-search-backward regexp begin t)
|
||||
(not (string-equal "nil" (match-string 1)))))))))))
|
||||
|
||||
|
@ -2408,7 +2438,7 @@ subtree, ignoring planning line and any drawer following it."
|
|||
(setq lim-down (copy-marker limit))))
|
||||
((org-at-heading-p)
|
||||
;; On a heading, start at first item after drawers and
|
||||
;; time-stamps (scheduled, etc.).
|
||||
;; timestamps (scheduled, etc.).
|
||||
(let ((limit (save-excursion (outline-next-heading) (point))))
|
||||
(org-end-of-meta-data t)
|
||||
(if (org-list-search-forward (org-item-beginning-re) limit t)
|
||||
|
@ -2492,8 +2522,8 @@ subtree, ignoring planning line and any drawer following it."
|
|||
(while (< (point) end)
|
||||
(when (org-at-item-checkbox-p)
|
||||
(replace-match "[ ]" t t nil 1))
|
||||
(beginning-of-line 2)))
|
||||
(org-update-checkbox-count-maybe 'all)))))
|
||||
(forward-line 1)))
|
||||
(org-update-checkbox-count-maybe 'narrow)))))
|
||||
|
||||
(defun org-update-checkbox-count (&optional all)
|
||||
"Update the checkbox statistics in the current section.
|
||||
|
@ -2501,126 +2531,131 @@ subtree, ignoring planning line and any drawer following it."
|
|||
This will find all statistic cookies like [57%] and [6/12] and
|
||||
update them with the current numbers.
|
||||
|
||||
With optional prefix argument ALL, do this for the whole buffer."
|
||||
With optional prefix argument ALL, do this for the whole buffer.
|
||||
When ALL is symbol `narrow', update statistics only in the accessible
|
||||
portion of the buffer."
|
||||
(interactive "P")
|
||||
(org-with-wide-buffer
|
||||
(let* ((cookie-re "\\(\\(\\[[0-9]*%\\]\\)\\|\\(\\[[0-9]*/[0-9]*\\]\\)\\)")
|
||||
(box-re "^[ \t]*\\([-+*]\\|\\([0-9]+\\|[A-Za-z]\\)[.)]\\)[ \t]+\
|
||||
(save-excursion
|
||||
(save-restriction
|
||||
(unless (eq all 'narrow) (widen))
|
||||
(let* ((cookie-re "\\(\\(\\[[0-9]*%\\]\\)\\|\\(\\[[0-9]*/[0-9]*\\]\\)\\)")
|
||||
(box-re "^[ \t]*\\([-+*]\\|\\([0-9]+\\|[A-Za-z]\\)[.)]\\)[ \t]+\
|
||||
\\(?:\\[@\\(?:start:\\)?\\([0-9]+\\|[A-Za-z]\\)\\][ \t]*\\)?\\(\\[[- X]\\]\\)")
|
||||
(cookie-data (or (org-entry-get nil "COOKIE_DATA") ""))
|
||||
(recursivep
|
||||
(or (not org-checkbox-hierarchical-statistics)
|
||||
(string-match-p "\\<recursive\\>" cookie-data)))
|
||||
(within-inlinetask (and (not all)
|
||||
(featurep 'org-inlinetask)
|
||||
(org-inlinetask-in-task-p)))
|
||||
(end (cond (all (point-max))
|
||||
(within-inlinetask
|
||||
(save-excursion (outline-next-heading) (point)))
|
||||
(t (save-excursion
|
||||
(org-with-limited-levels (outline-next-heading))
|
||||
(point)))))
|
||||
(count-boxes
|
||||
(lambda (item structs recursivep)
|
||||
;; Return number of checked boxes and boxes of all types
|
||||
;; in all structures in STRUCTS. If RECURSIVEP is
|
||||
;; non-nil, also count boxes in sub-lists. If ITEM is
|
||||
;; nil, count across the whole structure, else count only
|
||||
;; across subtree whose ancestor is ITEM.
|
||||
(let ((c-on 0) (c-all 0))
|
||||
(dolist (s structs (list c-on c-all))
|
||||
(let* ((pre (org-list-prevs-alist s))
|
||||
(par (org-list-parents-alist s))
|
||||
(items
|
||||
(cond
|
||||
((and recursivep item) (org-list-get-subtree item s))
|
||||
(recursivep (mapcar #'car s))
|
||||
(item (org-list-get-children item s par))
|
||||
(t (org-list-get-all-items
|
||||
(org-list-get-top-point s) s pre))))
|
||||
(cookies (delq nil (mapcar
|
||||
(lambda (e)
|
||||
(org-list-get-checkbox e s))
|
||||
items))))
|
||||
(cl-incf c-all (length cookies))
|
||||
(cl-incf c-on (cl-count "[X]" cookies :test #'equal)))))))
|
||||
cookies-list cache)
|
||||
;; Move to start.
|
||||
(cond (all (goto-char (point-min)))
|
||||
(within-inlinetask (org-back-to-heading t))
|
||||
(t (org-with-limited-levels (outline-previous-heading))))
|
||||
;; Build an alist for each cookie found. The key is the position
|
||||
;; at beginning of cookie and values ending position, format of
|
||||
;; cookie, number of checked boxes to report and total number of
|
||||
;; boxes.
|
||||
(while (re-search-forward cookie-re end t)
|
||||
(let ((context (save-excursion (backward-char)
|
||||
(save-match-data (org-element-context)))))
|
||||
(when (and (eq (org-element-type context) 'statistics-cookie)
|
||||
(not (string-match-p "\\<todo\\>" cookie-data)))
|
||||
(push
|
||||
(append
|
||||
(list (match-beginning 1) (match-end 1) (match-end 2))
|
||||
(let* ((container
|
||||
(org-element-lineage
|
||||
context
|
||||
'(drawer center-block dynamic-block inlinetask item
|
||||
quote-block special-block verse-block)))
|
||||
(beg (if container
|
||||
(org-element-property :contents-begin container)
|
||||
(save-excursion
|
||||
(org-with-limited-levels
|
||||
(outline-previous-heading))
|
||||
(cookie-data (or (org-entry-get nil "COOKIE_DATA") ""))
|
||||
(recursivep
|
||||
(or (not org-checkbox-hierarchical-statistics)
|
||||
(string-match-p "\\<recursive\\>" cookie-data)))
|
||||
(within-inlinetask (and (not all)
|
||||
(featurep 'org-inlinetask)
|
||||
(org-inlinetask-in-task-p)))
|
||||
(end (cond (all (point-max))
|
||||
(within-inlinetask
|
||||
(save-excursion (outline-next-heading) (point)))
|
||||
(t (save-excursion
|
||||
(org-with-limited-levels (outline-next-heading))
|
||||
(point)))))
|
||||
(or (cdr (assq beg cache))
|
||||
(save-excursion
|
||||
(goto-char beg)
|
||||
(let ((end
|
||||
(if container
|
||||
(org-element-property :contents-end container)
|
||||
(count-boxes
|
||||
(lambda (item structs recursivep)
|
||||
;; Return number of checked boxes and boxes of all types
|
||||
;; in all structures in STRUCTS. If RECURSIVEP is
|
||||
;; non-nil, also count boxes in sub-lists. If ITEM is
|
||||
;; nil, count across the whole structure, else count only
|
||||
;; across subtree whose ancestor is ITEM.
|
||||
(let ((c-on 0) (c-all 0))
|
||||
(dolist (s structs (list c-on c-all))
|
||||
(let* ((pre (org-list-prevs-alist s))
|
||||
(par (org-list-parents-alist s))
|
||||
(items
|
||||
(cond
|
||||
((and recursivep item) (org-list-get-subtree item s))
|
||||
(recursivep (mapcar #'car s))
|
||||
(item (org-list-get-children item s par))
|
||||
(t (org-list-get-all-items
|
||||
(org-list-get-top-point s) s pre))))
|
||||
(cookies (delq nil (mapcar
|
||||
(lambda (e)
|
||||
(org-list-get-checkbox e s))
|
||||
items))))
|
||||
(cl-incf c-all (length cookies))
|
||||
(cl-incf c-on (cl-count "[X]" cookies :test #'equal)))))))
|
||||
cookies-list cache)
|
||||
;; Move to start.
|
||||
(cond (all (goto-char (point-min)))
|
||||
(within-inlinetask (org-back-to-heading t))
|
||||
(t (org-with-limited-levels (outline-previous-heading))))
|
||||
;; Build an alist for each cookie found. The key is the position
|
||||
;; at beginning of cookie and values ending position, format of
|
||||
;; cookie, number of checked boxes to report and total number of
|
||||
;; boxes.
|
||||
(while (re-search-forward cookie-re end t)
|
||||
(let ((context (save-excursion (backward-char)
|
||||
(save-match-data (org-element-context)))))
|
||||
(when (and (org-element-type-p context 'statistics-cookie)
|
||||
(not (string-match-p "\\<todo\\>" cookie-data)))
|
||||
(push
|
||||
(append
|
||||
(list (match-beginning 1) (match-end 1) (match-end 2))
|
||||
(let* ((container
|
||||
(org-element-lineage
|
||||
context
|
||||
'(drawer center-block dynamic-block inlinetask item
|
||||
quote-block special-block verse-block)))
|
||||
(beg (if container
|
||||
(org-element-contents-begin container)
|
||||
(save-excursion
|
||||
(org-with-limited-levels (outline-next-heading))
|
||||
(point))))
|
||||
structs)
|
||||
(while (re-search-forward box-re end t)
|
||||
(let ((element (org-element-at-point)))
|
||||
(when (eq (org-element-type element) 'item)
|
||||
(push (org-element-property :structure element)
|
||||
structs)
|
||||
;; Skip whole list since we have its
|
||||
;; structure anyway.
|
||||
(while (setq element (org-element-lineage
|
||||
element '(plain-list)))
|
||||
(goto-char
|
||||
(min (org-element-property :end element)
|
||||
end))))))
|
||||
;; Cache count for cookies applying to the same
|
||||
;; area. Then return it.
|
||||
(let ((count
|
||||
(funcall count-boxes
|
||||
(and (eq (org-element-type container)
|
||||
'item)
|
||||
(org-element-property
|
||||
:begin container))
|
||||
structs
|
||||
recursivep)))
|
||||
(push (cons beg count) cache)
|
||||
count))))))
|
||||
cookies-list))))
|
||||
;; Apply alist to buffer.
|
||||
(dolist (cookie cookies-list)
|
||||
(let* ((beg (car cookie))
|
||||
(end (nth 1 cookie))
|
||||
(percent (nth 2 cookie))
|
||||
(checked (nth 3 cookie))
|
||||
(total (nth 4 cookie)))
|
||||
(goto-char beg)
|
||||
(insert
|
||||
(if percent (format "[%d%%]" (floor (* 100.0 checked)
|
||||
(max 1 total)))
|
||||
(format "[%d/%d]" checked total)))
|
||||
(delete-region (point) (+ (point) (- end beg)))
|
||||
(when org-auto-align-tags (org-fix-tags-on-the-fly)))))))
|
||||
(org-with-limited-levels
|
||||
(outline-previous-heading))
|
||||
(point)))))
|
||||
(or (cdr (assq beg cache))
|
||||
(save-excursion
|
||||
(goto-char beg)
|
||||
(let ((end
|
||||
(if container
|
||||
(org-element-contents-end container)
|
||||
(save-excursion
|
||||
(org-with-limited-levels (outline-next-heading))
|
||||
(point))))
|
||||
structs)
|
||||
(while (re-search-forward box-re end t)
|
||||
(let ((element (org-element-at-point)))
|
||||
(when (org-element-type-p element 'item)
|
||||
(push (org-element-property :structure element)
|
||||
structs)
|
||||
;; Skip whole list since we have its
|
||||
;; structure anyway.
|
||||
(while (setq element (org-element-lineage
|
||||
element 'plain-list))
|
||||
(goto-char
|
||||
(min (org-element-end element)
|
||||
end))))))
|
||||
;; Cache count for cookies applying to the same
|
||||
;; area. Then return it.
|
||||
(let ((count
|
||||
(funcall count-boxes
|
||||
(and (org-element-type-p
|
||||
container 'item)
|
||||
(org-element-property
|
||||
:begin container))
|
||||
structs
|
||||
recursivep)))
|
||||
(push (cons beg count) cache)
|
||||
count))))))
|
||||
cookies-list))))
|
||||
;; Apply alist to buffer.
|
||||
(dolist (cookie cookies-list)
|
||||
(let* ((beg (car cookie))
|
||||
(end (nth 1 cookie))
|
||||
(percent (nth 2 cookie))
|
||||
(checked (nth 3 cookie))
|
||||
(total (nth 4 cookie)))
|
||||
(goto-char beg)
|
||||
(org-fold-core-ignore-modifications
|
||||
(insert-and-inherit
|
||||
(if percent (format "[%d%%]" (floor (* 100.0 checked)
|
||||
(max 1 total)))
|
||||
(format "[%d/%d]" checked total)))
|
||||
(delete-region (point) (+ (point) (- end beg))))
|
||||
(when org-auto-align-tags (org-fix-tags-on-the-fly))))))))
|
||||
|
||||
(defun org-get-checkbox-statistics-face ()
|
||||
"Select the face for checkbox statistics.
|
||||
|
@ -2637,7 +2672,9 @@ Otherwise it will be `org-todo'."
|
|||
|
||||
(defun org-update-checkbox-count-maybe (&optional all)
|
||||
"Update checkbox statistics unless turned off by user.
|
||||
With an optional argument ALL, update them in the whole buffer."
|
||||
With an optional argument ALL, update them in the whole buffer.
|
||||
When ALL is symbol `narrow', update statistics only in the accessible
|
||||
portion of the buffer."
|
||||
(when (cdr (assq 'checkbox org-list-automatic-rules))
|
||||
(org-update-checkbox-count all))
|
||||
(run-hooks 'org-checkbox-statistics-hook))
|
||||
|
@ -2688,7 +2725,8 @@ Return t if successful."
|
|||
(no-subtree (1+ (line-beginning-position)))
|
||||
(t (org-list-get-item-end (line-beginning-position) struct))))))
|
||||
(let* ((beg (marker-position org-last-indent-begin-marker))
|
||||
(end (marker-position org-last-indent-end-marker)))
|
||||
(end (marker-position org-last-indent-end-marker))
|
||||
(deactivate-mark nil))
|
||||
(cond
|
||||
;; Special case: moving top-item with indent rule.
|
||||
(specialp
|
||||
|
@ -2941,7 +2979,7 @@ function is being called interactively."
|
|||
(error "Missing key extractor"))))
|
||||
(sort-func
|
||||
(cond
|
||||
((= dcst ?a) #'string-collate-lessp)
|
||||
((= dcst ?a) #'org-string<)
|
||||
((= dcst ?f)
|
||||
(or compare-func
|
||||
(and interactive?
|
||||
|
@ -2959,7 +2997,7 @@ function is being called interactively."
|
|||
(now (current-time))
|
||||
(next-record (lambda ()
|
||||
(skip-chars-forward " \r\t\n")
|
||||
(or (eobp) (beginning-of-line))))
|
||||
(or (eobp) (forward-line 0))))
|
||||
(end-record (lambda ()
|
||||
(goto-char (org-list-get-item-end-before-blank
|
||||
(point) struct))))
|
||||
|
@ -3030,28 +3068,25 @@ With a prefix argument ARG, change the region in a single item."
|
|||
(save-excursion
|
||||
(while (re-search-forward org-footnote-definition-re end t)
|
||||
(setq element (org-element-at-point))
|
||||
(when (eq 'footnote-definition
|
||||
(org-element-type element))
|
||||
(when (org-element-type-p element 'footnote-definition)
|
||||
(push (buffer-substring-no-properties
|
||||
(org-element-property :begin element)
|
||||
(org-element-property :end element))
|
||||
(org-element-begin element)
|
||||
(org-element-end element))
|
||||
definitions)
|
||||
;; Ensure at least 2 blank lines after the last
|
||||
;; footnote definition, thus not slurping the
|
||||
;; following element.
|
||||
(unless (<= 2 (org-element-property
|
||||
:post-blank
|
||||
(org-element-at-point)))
|
||||
(unless (<= 2 (org-element-post-blank
|
||||
(org-element-at-point)))
|
||||
(setf (car definitions)
|
||||
(concat (car definitions)
|
||||
(make-string
|
||||
(- 2 (org-element-property
|
||||
:post-blank
|
||||
(- 2 (org-element-post-blank
|
||||
(org-element-at-point)))
|
||||
?\n))))
|
||||
(delete-region
|
||||
(org-element-property :begin element)
|
||||
(org-element-property :end element))))
|
||||
(org-element-begin element)
|
||||
(org-element-end element))))
|
||||
definitions))))
|
||||
(shift-text
|
||||
(lambda (ind end)
|
||||
|
@ -3158,8 +3193,8 @@ With a prefix argument ARG, change the region in a single item."
|
|||
"[X]"
|
||||
"[ ]"))
|
||||
(org-list-write-struct struct
|
||||
(org-list-parents-alist struct)
|
||||
old)))
|
||||
(org-list-parents-alist struct)
|
||||
old)))
|
||||
;; Ensure all text down to END (or SECTION-END) belongs
|
||||
;; to the newly created item.
|
||||
(let ((section-end (save-excursion
|
||||
|
@ -3171,7 +3206,7 @@ With a prefix argument ARG, change the region in a single item."
|
|||
(when footnote-definitions
|
||||
(goto-char end)
|
||||
;; Insert footnote definitions after the list.
|
||||
(unless (bolp) (beginning-of-line 2))
|
||||
(unless (bolp) (forward-line 1))
|
||||
;; At (point-max).
|
||||
(unless (bolp) (insert "\n"))
|
||||
(dolist (def footnote-definitions)
|
||||
|
@ -3198,13 +3233,12 @@ With a prefix argument ARG, change the region in a single item."
|
|||
(when footnote-definitions
|
||||
;; If the new list is followed by same-level items,
|
||||
;; move past them as well.
|
||||
(goto-char (org-element-property
|
||||
:end
|
||||
(goto-char (org-element-end
|
||||
(org-element-lineage
|
||||
(org-element-at-point (1- end))
|
||||
'(plain-list) t)))
|
||||
'plain-list t)))
|
||||
;; Insert footnote definitions after the list.
|
||||
(unless (bolp) (beginning-of-line 2))
|
||||
(unless (bolp) (forward-line 1))
|
||||
;; At (point-max).
|
||||
(unless (bolp) (insert "\n"))
|
||||
(dolist (def footnote-definitions)
|
||||
|
@ -3333,7 +3367,7 @@ Valid parameters are:
|
|||
|
||||
:backend, :raw
|
||||
|
||||
Export back-end used as a basis to transcode elements of the
|
||||
Export backend used as a basis to transcode elements of the
|
||||
list, when no specific parameter applies to it. It is also
|
||||
used to translate its contents. You can prevent this by
|
||||
setting :raw property to a non-nil value.
|
||||
|
@ -3421,7 +3455,7 @@ Valid parameters are:
|
|||
(if (consp e) (funcall insert-list e)
|
||||
(insert e)
|
||||
(insert "\n")))
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(save-excursion
|
||||
(let ((ind (if (eq type 'ordered) 3 2)))
|
||||
(while (> (point) start)
|
||||
|
@ -3441,7 +3475,7 @@ Valid parameters are:
|
|||
(when (and backend (plist-get params :raw))
|
||||
(org-element-map data org-element-all-objects
|
||||
(lambda (object)
|
||||
(org-element-set-element
|
||||
(org-element-set
|
||||
object (org-element-interpret-data object)))))
|
||||
;; We use a low-level mechanism to export DATA so as to skip all
|
||||
;; usual pre-processing and post-processing, i.e., hooks, filters,
|
||||
|
@ -3454,7 +3488,7 @@ Valid parameters are:
|
|||
(defun org-list--depth (element)
|
||||
"Return the level of ELEMENT within current plain list.
|
||||
ELEMENT is either an item or a plain list."
|
||||
(cl-count-if (lambda (ancestor) (eq (org-element-type ancestor) 'plain-list))
|
||||
(cl-count-if (lambda (ancestor) (org-element-type-p ancestor 'plain-list))
|
||||
(org-element-lineage element nil t)))
|
||||
|
||||
(defun org-list--trailing-newlines (string)
|
||||
|
@ -3531,7 +3565,7 @@ PARAMS is a plist used to tweak the behavior of the transcoder."
|
|||
(ddend (plist-get params :ddend)))
|
||||
(lambda (item contents info)
|
||||
(let* ((type
|
||||
(org-element-property :type (org-element-property :parent item)))
|
||||
(org-element-property :type (org-element-parent item)))
|
||||
(tag (org-element-property :tag item))
|
||||
(depth (org-list--depth item))
|
||||
(separator (and (org-export-get-next-element item info)
|
||||
|
|
|
@ -57,14 +57,17 @@
|
|||
(declare-function org-collect-keywords "org" (keywords &optional unique directory))
|
||||
(declare-function org-element-at-point "org-element" (&optional pom cached-only))
|
||||
(declare-function org-element-context "org-element" (&optional element))
|
||||
(declare-function org-element-copy "org-element" (datum))
|
||||
(declare-function org-element-copy "org-element-ast" (datum))
|
||||
(declare-function org-element-macro-parser "org-element" ())
|
||||
(declare-function org-element-keyword-parser "org-element" (limit affiliated))
|
||||
(declare-function org-element-put-property "org-element" (element property value))
|
||||
(declare-function org-element-put-property "org-element-ast" (node property value))
|
||||
(declare-function org-element-parse-secondary-string "org-element" (string restriction &optional parent))
|
||||
(declare-function org-element-property "org-element" (property element))
|
||||
(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-restriction "org-element" (element))
|
||||
(declare-function org-element-type "org-element" (element))
|
||||
(declare-function org-element-type "org-element-ast" (node &optional anonymous))
|
||||
(declare-function org-element-type-p "org-element-ast" (node types))
|
||||
(declare-function org-entry-get "org" (pom property &optional inherit literal-nil))
|
||||
(declare-function org-file-contents "org" (file &optional noerror nocache))
|
||||
(declare-function org-in-commented-heading-p "org" (&optional no-inheritance element))
|
||||
|
@ -261,7 +264,7 @@ a definition in TEMPLATES."
|
|||
(org-element-put-property macro :parent nil)
|
||||
(let* ((key (org-element-property :key macro))
|
||||
(value (org-macro-expand macro templates))
|
||||
(begin (org-element-property :begin macro))
|
||||
(begin (org-element-begin macro))
|
||||
(signature (list begin
|
||||
macro
|
||||
(org-element-property :args macro))))
|
||||
|
@ -275,7 +278,7 @@ a definition in TEMPLATES."
|
|||
(delete-region
|
||||
begin
|
||||
;; Preserve white spaces after the macro.
|
||||
(progn (goto-char (org-element-property :end macro))
|
||||
(progn (goto-char (org-element-end macro))
|
||||
(skip-chars-backward " \t")
|
||||
(point)))
|
||||
;; Leave point before replacement in case of
|
||||
|
@ -337,14 +340,14 @@ Return a list of arguments, as strings. This is the opposite of
|
|||
"Find PROPERTY's value at LOCATION.
|
||||
PROPERTY is a string. LOCATION is a search string, as expected
|
||||
by `org-link-search', or the empty string."
|
||||
(save-excursion
|
||||
(when (org-string-nw-p location)
|
||||
(condition-case _
|
||||
(let ((org-link-search-must-match-exact-headline t))
|
||||
(org-link-search location nil t))
|
||||
(error
|
||||
(error "Macro property failed: cannot find location %s" location))))
|
||||
(org-entry-get nil property 'selective)))
|
||||
(org-with-wide-buffer
|
||||
(when (org-string-nw-p location)
|
||||
(condition-case _
|
||||
(let ((org-link-search-must-match-exact-headline t))
|
||||
(org-link-search location nil t))
|
||||
(error
|
||||
(error "Macro property failed: cannot find location %s" location))))
|
||||
(org-entry-get nil property 'selective)))
|
||||
|
||||
(defun org-macro--find-keyword-value (name &optional collect)
|
||||
"Find value for keyword NAME in current buffer.
|
||||
|
@ -359,7 +362,7 @@ in the buffer."
|
|||
(catch :exit
|
||||
(while (re-search-forward regexp nil t)
|
||||
(let ((element (org-with-point-at (match-beginning 0) (org-element-keyword-parser (line-end-position) (list (match-beginning 0))))))
|
||||
(when (eq 'keyword (org-element-type element))
|
||||
(when (org-element-type-p element 'keyword)
|
||||
(let ((value (org-element-property :value element)))
|
||||
(if (not collect) (throw :exit value)
|
||||
(setq result (concat result " " value)))))))
|
||||
|
@ -373,10 +376,13 @@ Return value as a string."
|
|||
value (org-element-restriction 'keyword))))
|
||||
(if (and (consp date)
|
||||
(not (cdr date))
|
||||
(eq 'timestamp (org-element-type (car date))))
|
||||
(org-element-type-p (car date) 'timestamp))
|
||||
(format "(eval (if (org-string-nw-p $1) %s %S))"
|
||||
(format "(org-format-timestamp '%S $1)"
|
||||
(org-element-copy (car date)))
|
||||
(org-element-put-property
|
||||
(org-element-copy (car date))
|
||||
;; Remove non-printable.
|
||||
:buffer nil))
|
||||
value)
|
||||
value)))
|
||||
|
||||
|
|
|
@ -113,16 +113,24 @@ Version mismatch is commonly encountered in the following situations:
|
|||
(declare-function org-fold-next-visibility-change "org-fold" (&optional pos limit ignore-hidden-p previous-p))
|
||||
(declare-function org-fold-core-with-forced-fontification "org-fold" (&rest body))
|
||||
(declare-function org-fold-folded-p "org-fold" (&optional pos limit ignore-hidden-p previous-p))
|
||||
(declare-function string-collate-lessp "org-compat" (s1 s2 &optional locale ignore-case))
|
||||
(declare-function org-time-convert-to-integer "org-compat" (time))
|
||||
(declare-function org-time-convert-to-list "org-compat" (time))
|
||||
(declare-function org-buffer-text-pixel-width "org-compat" ())
|
||||
|
||||
(defvar org-ts-regexp0)
|
||||
(defvar ffap-url-regexp)
|
||||
(defvar org-fold-core-style)
|
||||
|
||||
|
||||
;;; Macros
|
||||
|
||||
(defmacro org-require-package (symbol &optional name noerror)
|
||||
"Try to load library SYMBOL and display error otherwise.
|
||||
With optional parameter NAME, use NAME as package name instead of
|
||||
SYMBOL. Show warning instead of error when NOERROR is non-nil."
|
||||
`(unless (require ,symbol nil t)
|
||||
(,(if noerror 'warn 'user-error)
|
||||
"`%s' failed to load required package \"%s\""
|
||||
this-command ,(or name symbol))))
|
||||
|
||||
(defmacro org-with-gensyms (symbols &rest body)
|
||||
(declare (debug (sexp body)) (indent 1))
|
||||
`(let ,(mapcar (lambda (s)
|
||||
|
@ -151,19 +159,29 @@ If BUFFER is nil, use base buffer for `current-buffer'."
|
|||
(or ,buffer (current-buffer)))
|
||||
,@body))
|
||||
|
||||
(defmacro org-with-point-at (pom &rest body)
|
||||
"Move to buffer and point of point-or-marker POM for the duration of BODY."
|
||||
(defmacro org-with-point-at (epom &rest body)
|
||||
"Move to buffer and point of EPOM for the duration of BODY.
|
||||
EPOM is an element, point, or marker."
|
||||
(declare (debug (form body)) (indent 1))
|
||||
(org-with-gensyms (mpom)
|
||||
`(let ((,mpom ,pom))
|
||||
(require 'org-element-ast)
|
||||
(org-with-gensyms (mepom)
|
||||
`(let ((,mepom ,epom))
|
||||
(save-excursion
|
||||
(when (markerp ,mpom) (set-buffer (marker-buffer ,mpom)))
|
||||
(cond
|
||||
((markerp ,mepom)
|
||||
(set-buffer (marker-buffer ,mepom)))
|
||||
((numberp ,mepom))
|
||||
(t
|
||||
(when (org-element-property :buffer ,mepom)
|
||||
(set-buffer (org-element-property :buffer ,mepom)))
|
||||
(setq ,mepom (org-element-property :begin ,mepom))))
|
||||
(org-with-wide-buffer
|
||||
(goto-char (or ,mpom (point)))
|
||||
(goto-char (or ,mepom (point)))
|
||||
,@body)))))
|
||||
|
||||
(defmacro org-with-remote-undo (buffer &rest body)
|
||||
"Execute BODY while recording undo information in two buffers."
|
||||
"Execute BODY while recording undo information in current buffer and BUFFER.
|
||||
This function is only useful when called from Agenda buffer."
|
||||
(declare (debug (form body)) (indent 1))
|
||||
(org-with-gensyms (cline cmd buf1 buf2 undo1 undo2 c1 c2)
|
||||
`(let ((,cline (org-current-line))
|
||||
|
@ -195,7 +213,7 @@ If BUFFER is nil, use base buffer for `current-buffer'."
|
|||
(defalias 'org-save-outline-visibility #'org-fold-save-outline-visibility)
|
||||
|
||||
(defmacro org-with-wide-buffer (&rest body)
|
||||
"Execute body while temporarily widening the buffer."
|
||||
"Execute BODY while temporarily widening the buffer."
|
||||
(declare (debug (body)))
|
||||
`(save-excursion
|
||||
(save-restriction
|
||||
|
@ -213,7 +231,7 @@ If BUFFER is nil, use base buffer for `current-buffer'."
|
|||
(let* ((org-called-with-limited-levels t)
|
||||
(org-outline-regexp (org-get-limited-outline-regexp))
|
||||
(outline-regexp org-outline-regexp)
|
||||
(org-outline-regexp-bol (concat "^" org-outline-regexp)))
|
||||
(org-outline-regexp-bol (org-get-limited-outline-regexp t)))
|
||||
,@body)))
|
||||
|
||||
(defmacro org-eval-in-environment (environment form)
|
||||
|
@ -249,11 +267,7 @@ If BUFFER is nil, use base buffer for `current-buffer'."
|
|||
(unless modified
|
||||
(restore-buffer-modified-p nil))))))))
|
||||
|
||||
(defmacro org-no-popups (&rest body)
|
||||
"Suppress popup windows and evaluate BODY."
|
||||
`(let (pop-up-frames pop-up-windows)
|
||||
,@body))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro org-element-with-disabled-cache (&rest body)
|
||||
"Run BODY without active org-element-cache."
|
||||
(declare (debug (form body)) (indent 0))
|
||||
|
@ -270,17 +284,36 @@ If BUFFER is nil, use base buffer for `current-buffer'."
|
|||
buffer)))
|
||||
|
||||
(defun org-find-base-buffer-visiting (file)
|
||||
"Like `find-buffer-visiting' but always return the base buffer and
|
||||
not an indirect buffer."
|
||||
"Like `find-buffer-visiting' but always return the base buffer.
|
||||
FILE is the file name passed to `find-buffer-visiting'."
|
||||
(let ((buf (or (get-file-buffer file)
|
||||
(find-buffer-visiting file))))
|
||||
(org-base-buffer buf)))
|
||||
|
||||
(defun org-switch-to-buffer-other-window (&rest args)
|
||||
"Switch to buffer in a second window on the current frame.
|
||||
In particular, do not allow pop-up frames.
|
||||
Returns the newly created buffer."
|
||||
(org-no-popups (apply #'switch-to-buffer-other-window args)))
|
||||
(defvar-local org-file-buffer-created nil
|
||||
"Non-nil when current buffer is created from `org-with-file-buffer'.
|
||||
The value is FILE argument passed to `org-with-file-buffer'.")
|
||||
(defmacro org-with-file-buffer (file &rest body)
|
||||
"Evaluate BODY with current buffer visiting FILE.
|
||||
When no live buffer is visiting FILE, create one and kill after
|
||||
evaluating BODY.
|
||||
During evaluation, when the buffer was created, `org-file-buffer-created'
|
||||
variable is set to FILE."
|
||||
(declare (debug (form body)) (indent 1))
|
||||
(org-with-gensyms (mark-function filename buffer)
|
||||
`(let ((,mark-function (lambda () (setq-local org-file-buffer-created ,file)))
|
||||
(,filename ,file)
|
||||
,buffer)
|
||||
(add-hook 'find-file-hook ,mark-function)
|
||||
(unwind-protect
|
||||
(progn
|
||||
(setq ,buffer (find-file-noselect ,filename t))
|
||||
(with-current-buffer ,buffer
|
||||
(prog1 (progn ,@body)
|
||||
(with-current-buffer ,buffer
|
||||
(when (equal ,filename org-file-buffer-created)
|
||||
(kill-buffer))))))
|
||||
(remove-hook 'find-file-hook ,mark-function)))))
|
||||
|
||||
(defun org-fit-window-to-buffer (&optional window max-height min-height
|
||||
shrink-only)
|
||||
|
@ -358,72 +391,6 @@ in target-prerequisite files relation."
|
|||
(let ((mtime (file-attribute-modification-time (file-attributes file))))
|
||||
(and mtime (or (not time) (time-less-p time mtime)))))
|
||||
|
||||
(defun org-compile-file (source process ext &optional err-msg log-buf spec)
|
||||
"Compile a SOURCE file using PROCESS.
|
||||
|
||||
PROCESS is either a function or a list of shell commands, as
|
||||
strings. EXT is a file extension, without the leading dot, as
|
||||
a string. It is used to check if the process actually succeeded.
|
||||
|
||||
PROCESS must create a file with the same base name and directory
|
||||
as SOURCE, but ending with EXT. The function then returns its
|
||||
filename. Otherwise, it raises an error. The error message can
|
||||
then be refined by providing string ERR-MSG, which is appended to
|
||||
the standard message.
|
||||
|
||||
If PROCESS is a function, it is called with a single argument:
|
||||
the SOURCE file.
|
||||
|
||||
If it is a list of commands, each of them is called using
|
||||
`shell-command'. By default, in each command, %b, %f, %F, %o and
|
||||
%O are replaced with, respectively, SOURCE base name, name, full
|
||||
name, directory and absolute output file name. It is possible,
|
||||
however, to use more place-holders by specifying them in optional
|
||||
argument SPEC, as an alist following the pattern
|
||||
|
||||
(CHARACTER . REPLACEMENT-STRING).
|
||||
|
||||
When PROCESS is a list of commands, optional argument LOG-BUF can
|
||||
be set to a buffer or a buffer name. `shell-command' then uses
|
||||
it for output."
|
||||
(let* ((base-name (file-name-base source))
|
||||
(full-name (file-truename source))
|
||||
(relative-name (file-relative-name source))
|
||||
(out-dir (if (file-name-directory source)
|
||||
;; Expand "~". Shell expansion will be disabled
|
||||
;; in the shell command call.
|
||||
(file-name-directory full-name)
|
||||
"./"))
|
||||
(output (expand-file-name (concat base-name "." ext) out-dir))
|
||||
(time (file-attribute-modification-time (file-attributes output)))
|
||||
(err-msg (if (stringp err-msg) (concat ". " err-msg) "")))
|
||||
(save-window-excursion
|
||||
(pcase process
|
||||
((pred functionp) (funcall process (shell-quote-argument relative-name)))
|
||||
((pred consp)
|
||||
(let ((log-buf (and log-buf (get-buffer-create log-buf)))
|
||||
(spec (append spec
|
||||
`((?b . ,(shell-quote-argument base-name))
|
||||
(?f . ,(shell-quote-argument relative-name))
|
||||
(?F . ,(shell-quote-argument full-name))
|
||||
(?o . ,(shell-quote-argument out-dir))
|
||||
(?O . ,(shell-quote-argument output))))))
|
||||
;; Combine output of all commands in PROCESS.
|
||||
(with-current-buffer log-buf
|
||||
(let (buffer-read-only)
|
||||
(erase-buffer)))
|
||||
(let ((shell-command-dont-erase-buffer t))
|
||||
(dolist (command process)
|
||||
(shell-command (format-spec command spec) log-buf)))
|
||||
(when log-buf (with-current-buffer log-buf (compilation-mode)))))
|
||||
(_ (error "No valid command to process %S%s" source err-msg))))
|
||||
;; Check for process failure. Output file is expected to be
|
||||
;; located in the same directory as SOURCE.
|
||||
(unless (org-file-newer-than-p output time)
|
||||
(error (format "File %S wasn't produced%s" output err-msg)))
|
||||
output))
|
||||
|
||||
|
||||
|
||||
;;; Indentation
|
||||
|
||||
|
@ -434,6 +401,8 @@ it for output."
|
|||
|
||||
(defun org-do-remove-indentation (&optional n skip-fl)
|
||||
"Remove the maximum common indentation from the buffer.
|
||||
Do not consider invisible text when calculating indentation.
|
||||
|
||||
When optional argument N is a positive integer, remove exactly
|
||||
that much characters from indentation, if possible. When
|
||||
optional argument SKIP-FL is non-nil, skip the first
|
||||
|
@ -454,10 +423,14 @@ line. Return nil if it fails."
|
|||
;; Remove exactly N indentation, but give up if not possible.
|
||||
(when skip-fl (forward-line))
|
||||
(while (not (eobp))
|
||||
(let ((ind (progn (skip-chars-forward " \t") (current-column))))
|
||||
(cond ((eolp) (delete-region (line-beginning-position) (point)))
|
||||
((< ind n) (throw :exit nil))
|
||||
(t (indent-line-to (- ind n))))
|
||||
(let* ((buffer-invisibility-spec nil) ; do not treat invisible text specially
|
||||
(ind (progn (skip-chars-forward " \t") (current-column))))
|
||||
(cond ((< ind n)
|
||||
(if (eolp) (delete-region (line-beginning-position) (point))
|
||||
(throw :exit nil)))
|
||||
(t (delete-region (line-beginning-position)
|
||||
(progn (move-to-column n t)
|
||||
(point)))))
|
||||
(forward-line)))
|
||||
;; Signal success.
|
||||
t))))
|
||||
|
@ -476,7 +449,7 @@ error when the user input is empty."
|
|||
(allow-empty? nil)
|
||||
(t (user-error "Empty input is not valid")))))
|
||||
|
||||
(declare-function org-time-stamp-inactive "org" (&optional arg))
|
||||
(declare-function org-timestamp-inactive "org" (&optional arg))
|
||||
|
||||
(defun org-completing-read (&rest args)
|
||||
"Completing-read with SPACE being a normal character."
|
||||
|
@ -486,7 +459,7 @@ error when the user input is empty."
|
|||
(define-key minibuffer-local-completion-map " " #'self-insert-command)
|
||||
(define-key minibuffer-local-completion-map "?" #'self-insert-command)
|
||||
(define-key minibuffer-local-completion-map (kbd "C-c !")
|
||||
#'org-time-stamp-inactive)
|
||||
#'org-timestamp-inactive)
|
||||
(apply #'completing-read args)))
|
||||
|
||||
(defun org--mks-read-key (allowed-keys prompt navigation-keys)
|
||||
|
@ -535,7 +508,7 @@ alist with (\"key\" \"description\") entries. When one of these
|
|||
is selected, only the bare key is returned."
|
||||
(save-window-excursion
|
||||
(let ((inhibit-quit t)
|
||||
(buffer (org-switch-to-buffer-other-window "*Org Select*"))
|
||||
(buffer (switch-to-buffer-other-window "*Org Select*"))
|
||||
(prompt (or prompt "Select: "))
|
||||
case-fold-search
|
||||
current)
|
||||
|
@ -599,7 +572,10 @@ is selected, only the bare key is returned."
|
|||
;; selection prefix.
|
||||
((assoc current specials) (throw 'exit current))
|
||||
(t (error "No entry available")))))))
|
||||
(when buffer (kill-buffer buffer))))))
|
||||
(when buffer
|
||||
(when-let ((window (get-buffer-window buffer t)))
|
||||
(quit-window 'kill window))
|
||||
(kill-buffer buffer))))))
|
||||
|
||||
|
||||
;;; List manipulation
|
||||
|
@ -781,46 +757,100 @@ get an unnecessary O(N²) space complexity, so you're usually better off using
|
|||
|
||||
(defun org-eval (form)
|
||||
"Eval FORM and return result."
|
||||
(condition-case error
|
||||
(condition-case-unless-debug error
|
||||
(eval form t)
|
||||
(error (format "%%![Error: %s]" error))))
|
||||
|
||||
(defvar org--headline-re-cache-no-bol nil
|
||||
"Plist holding association between headline level regexp.")
|
||||
(defvar org--headline-re-cache-bol nil
|
||||
"Plist holding association between headline level regexp.")
|
||||
(defsubst org-headline-re (true-level &optional no-bol)
|
||||
"Generate headline regexp for TRUE-LEVEL.
|
||||
When NO-BOL is non-nil, regexp will not demand the regexp to start at
|
||||
beginning of line."
|
||||
(or (plist-get
|
||||
(if no-bol
|
||||
org--headline-re-cache-no-bol
|
||||
org--headline-re-cache-bol)
|
||||
true-level)
|
||||
(let ((re (rx-to-string
|
||||
(if no-bol
|
||||
`(seq (** 1 ,true-level "*") " ")
|
||||
`(seq line-start (** 1 ,true-level "*") " ")))))
|
||||
(if no-bol
|
||||
(setq org--headline-re-cache-no-bol
|
||||
(plist-put
|
||||
org--headline-re-cache-no-bol
|
||||
true-level re))
|
||||
(setq org--headline-re-cache-bol
|
||||
(plist-put
|
||||
org--headline-re-cache-bol
|
||||
true-level re)))
|
||||
re)))
|
||||
|
||||
(defvar org-outline-regexp) ; defined in org.el
|
||||
(defvar org-outline-regexp-bol) ; defined in org.el
|
||||
(defvar org-odd-levels-only) ; defined in org.el
|
||||
(defvar org-inlinetask-min-level) ; defined in org-inlinetask.el
|
||||
(defun org-get-limited-outline-regexp ()
|
||||
(defun org-get-limited-outline-regexp (&optional with-bol)
|
||||
"Return outline-regexp with limited number of levels.
|
||||
The number of levels is controlled by `org-inlinetask-min-level'."
|
||||
The number of levels is controlled by `org-inlinetask-min-level'.
|
||||
Match at beginning of line when WITH-BOL is non-nil."
|
||||
(cond ((not (derived-mode-p 'org-mode))
|
||||
outline-regexp)
|
||||
(if (string-prefix-p "^" outline-regexp)
|
||||
(if with-bol outline-regexp (substring outline-regexp 1))
|
||||
(if with-bol (concat "^" outline-regexp) outline-regexp)))
|
||||
((not (featurep 'org-inlinetask))
|
||||
org-outline-regexp)
|
||||
(if with-bol org-outline-regexp-bol org-outline-regexp))
|
||||
(t
|
||||
(let* ((limit-level (1- org-inlinetask-min-level))
|
||||
(nstars (if org-odd-levels-only
|
||||
(1- (* limit-level 2))
|
||||
limit-level)))
|
||||
(format "\\*\\{1,%d\\} " nstars)))))
|
||||
(org-headline-re nstars (not with-bol))))))
|
||||
|
||||
(defun org--line-empty-p (n)
|
||||
"Is the Nth next line empty?
|
||||
Counts the current line as N = 1 and the previous line as N = 0;
|
||||
see `beginning-of-line'."
|
||||
"Is the Nth next line empty?"
|
||||
(and (not (bobp))
|
||||
(save-excursion
|
||||
(beginning-of-line n)
|
||||
(looking-at-p "[ \t]*$"))))
|
||||
(forward-line n)
|
||||
(skip-chars-forward "[ \t]")
|
||||
(eolp))))
|
||||
|
||||
(defun org-previous-line-empty-p ()
|
||||
"Is the previous line a blank line?
|
||||
When NEXT is non-nil, check the next line instead."
|
||||
(org--line-empty-p 0))
|
||||
(org--line-empty-p -1))
|
||||
|
||||
(defun org-next-line-empty-p ()
|
||||
"Is the previous line a blank line?
|
||||
When NEXT is non-nil, check the next line instead."
|
||||
(org--line-empty-p 2))
|
||||
(org--line-empty-p 1))
|
||||
|
||||
(defun org-id-uuid ()
|
||||
"Return string with random (version 4) UUID."
|
||||
(let ((rnd (md5 (format "%s%s%s%s%s%s%s"
|
||||
(random)
|
||||
(org-time-convert-to-list nil)
|
||||
(user-uid)
|
||||
(emacs-pid)
|
||||
(user-full-name)
|
||||
user-mail-address
|
||||
(recent-keys)))))
|
||||
(format "%s-%s-4%s-%s%s-%s"
|
||||
(substring rnd 0 8)
|
||||
(substring rnd 8 12)
|
||||
(substring rnd 13 16)
|
||||
(format "%x"
|
||||
(logior
|
||||
#b10000000
|
||||
(logand
|
||||
#b10111111
|
||||
(string-to-number
|
||||
(substring rnd 16 18) 16))))
|
||||
(substring rnd 18 20)
|
||||
(substring rnd 20 32))))
|
||||
|
||||
|
||||
;;; Motion
|
||||
|
@ -887,14 +917,14 @@ Return nil when PROP is not set at POS."
|
|||
(<= (match-beginning n) pos)
|
||||
(>= (match-end n) pos)))
|
||||
|
||||
(defun org-skip-whitespace ()
|
||||
(defsubst org-skip-whitespace ()
|
||||
"Skip over space, tabs and newline characters."
|
||||
(skip-chars-forward " \t\n\r"))
|
||||
|
||||
(defun org-match-line (regexp)
|
||||
"Match REGEXP at the beginning of the current line."
|
||||
(save-excursion
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(looking-at regexp)))
|
||||
|
||||
(defun org-match-any-p (re list)
|
||||
|
@ -916,7 +946,7 @@ match."
|
|||
(let ((pos (point))
|
||||
(eol (line-end-position (if nlines (1+ nlines) 1))))
|
||||
(save-excursion
|
||||
(beginning-of-line (- 1 (or nlines 0)))
|
||||
(forward-line (- (or nlines 0)))
|
||||
(while (and (re-search-forward regexp eol t)
|
||||
(<= (match-beginning 0) pos))
|
||||
(let ((end (match-end 0)))
|
||||
|
@ -940,23 +970,79 @@ return nil."
|
|||
(require 'ffap)
|
||||
(and ffap-url-regexp (string-match-p ffap-url-regexp s)))
|
||||
|
||||
(defconst org-uuid-regexp
|
||||
"\\`[0-9a-f]\\{8\\}-[0-9a-f]\\{4\\}-[0-9a-f]\\{4\\}-[0-9a-f]\\{4\\}-[0-9a-f]\\{12\\}\\'"
|
||||
"Regular expression matching a universal unique identifier (UUID).")
|
||||
|
||||
(defun org-uuidgen-p (s)
|
||||
"Is S an ID created by UUIDGEN?"
|
||||
(string-match org-uuid-regexp (downcase s)))
|
||||
|
||||
|
||||
|
||||
;;; String manipulation
|
||||
|
||||
(defun org-string< (a b)
|
||||
(string-collate-lessp a b))
|
||||
(defcustom org-sort-function #'string-collate-lessp
|
||||
"Function used to compare strings when sorting.
|
||||
This function affects how Org mode sorts headlines, agenda items,
|
||||
table lines, etc.
|
||||
|
||||
(defun org-string<= (a b)
|
||||
(or (string= a b) (string-collate-lessp a b)))
|
||||
The function must accept either 2 or 4 arguments: strings to compare
|
||||
and, optionally, LOCALE and IGNORE-CASE - locale name and flag to make
|
||||
comparison case-insensitive.
|
||||
|
||||
(defun org-string>= (a b)
|
||||
(not (string-collate-lessp a b)))
|
||||
The default value uses sorting rules according to OS language. Users
|
||||
who want to make sorting language-independent, may customize the value
|
||||
to `org-sort-function-fallback'.
|
||||
|
||||
(defun org-string> (a b)
|
||||
Note that some string sorting rules are known to be not accurate on
|
||||
MacOS. See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=59275.
|
||||
MacOS users may customize the value to
|
||||
`org-sort-function-fallback'."
|
||||
:group 'org
|
||||
:package-version '(Org . "9.7")
|
||||
:type '(choice
|
||||
(const :tag "According to OS language" string-collate-lessp)
|
||||
(const :tag "Using string comparison" org-sort-function-fallback)
|
||||
(function :tag "Custom function")))
|
||||
|
||||
(defun org-sort-function-fallback (a b &optional _ ignore-case)
|
||||
"Return non-nil when downcased string A < string B.
|
||||
Use `compare-strings' for comparison. Honor IGNORE-CASE."
|
||||
(let ((ans (compare-strings a nil nil b nil nil ignore-case)))
|
||||
(cond
|
||||
((and (numberp ans) (< ans 0)) t)
|
||||
(t nil))))
|
||||
|
||||
(defun org-string< (a b &optional locale ignore-case)
|
||||
"Return non-nil when string A < string B.
|
||||
LOCALE is the locale name. IGNORE-CASE, when non-nil, makes comparison
|
||||
ignore case."
|
||||
(if (= 4 (cdr (func-arity org-sort-function)))
|
||||
(funcall org-sort-function a b locale ignore-case)
|
||||
(funcall org-sort-function a b)))
|
||||
|
||||
(defun org-string<= (a b &optional locale ignore-case)
|
||||
"Return non-nil when string A <= string B.
|
||||
LOCALE is the locale name. IGNORE-CASE, when non-nil, makes comparison
|
||||
ignore case."
|
||||
(or (string= a b) (org-string< a b locale ignore-case)))
|
||||
|
||||
(defun org-string>= (a b &optional locale ignore-case)
|
||||
"Return non-nil when string A >= string B.
|
||||
LOCALE is the locale name. IGNORE-CASE, when non-nil, makes comparison
|
||||
ignore case."
|
||||
(not (org-string< a b locale ignore-case)))
|
||||
|
||||
(defun org-string> (a b &optional locale ignore-case)
|
||||
"Return non-nil when string A > string B.
|
||||
LOCALE is the locale name. IGNORE-CASE, when non-nil, makes comparison
|
||||
ignore case."
|
||||
(and (not (string= a b))
|
||||
(not (string-collate-lessp a b))))
|
||||
(not (org-string< a b locale ignore-case))))
|
||||
|
||||
(defun org-string<> (a b)
|
||||
"Return non-nil when string A and string B are not equal."
|
||||
(not (string= a b)))
|
||||
|
||||
(defsubst org-trim (s &optional keep-lead)
|
||||
|
@ -1065,9 +1151,11 @@ Results may be off sometimes if it cannot handle a given
|
|||
`display' value."
|
||||
(org--string-from-props string 'display 0 (length string)))
|
||||
|
||||
(defun org-string-width (string &optional pixels)
|
||||
(defun org-string-width (string &optional pixels default-face)
|
||||
"Return width of STRING when displayed in the current buffer.
|
||||
Return width in pixels when PIXELS is non-nil."
|
||||
Return width in pixels when PIXELS is non-nil.
|
||||
When PIXELS is nil, DEFAULT-FACE is the face used to calculate relative
|
||||
STRING width. When REFERENCE-FACE is nil, `default' face is used."
|
||||
(if (and (version< emacs-version "28") (not pixels))
|
||||
;; FIXME: Fallback to old limited version, because
|
||||
;; `window-pixel-width' is buggy in older Emacs.
|
||||
|
@ -1082,7 +1170,7 @@ Return width in pixels when PIXELS is non-nil."
|
|||
;; is critical to get right string width from pixel width (not needed
|
||||
;; when PIXELS are requested though).
|
||||
(unless pixels
|
||||
(remove-text-properties 0 (length string) '(face t) string))
|
||||
(put-text-property 0 (length string) 'face (or default-face 'default) string))
|
||||
(let (;; We need to remove the folds to make sure that folded table
|
||||
;; alignment is not messed up.
|
||||
(current-invisibility-spec
|
||||
|
@ -1102,8 +1190,10 @@ Return width in pixels when PIXELS is non-nil."
|
|||
(push el result)))
|
||||
result)))
|
||||
(current-char-property-alias-alist char-property-alias-alist))
|
||||
(with-temp-buffer
|
||||
(with-current-buffer (get-buffer-create " *Org string width*")
|
||||
(setq-local display-line-numbers nil)
|
||||
(setq-local line-prefix nil)
|
||||
(setq-local wrap-prefix nil)
|
||||
(setq-local buffer-invisibility-spec
|
||||
(if (listp current-invisibility-spec)
|
||||
(mapcar (lambda (el)
|
||||
|
@ -1121,52 +1211,26 @@ Return width in pixels when PIXELS is non-nil."
|
|||
(with-silent-modifications
|
||||
(erase-buffer)
|
||||
(insert string)
|
||||
(setq pixel-width
|
||||
(if (get-buffer-window (current-buffer))
|
||||
(car (window-text-pixel-size
|
||||
;; FIXME: 10000 because
|
||||
;; `most-positive-fixnum' ain't working
|
||||
;; (tests failing) and this call will be
|
||||
;; removed after we drop Emacs 28 support
|
||||
;; anyway.
|
||||
nil (line-beginning-position) (point-max) 10000))
|
||||
(let ((dedicatedp (window-dedicated-p))
|
||||
(oldbuffer (window-buffer)))
|
||||
(unwind-protect
|
||||
(progn
|
||||
;; Do not throw error in dedicated windows.
|
||||
(set-window-dedicated-p nil nil)
|
||||
(set-window-buffer nil (current-buffer))
|
||||
(car (window-text-pixel-size
|
||||
nil (line-beginning-position) (point-max) 10000)))
|
||||
(set-window-buffer nil oldbuffer)
|
||||
(set-window-dedicated-p nil dedicatedp)))))
|
||||
(setq pixel-width (org-buffer-text-pixel-width))
|
||||
(unless pixels
|
||||
(erase-buffer)
|
||||
(insert "a")
|
||||
(setq symbol-width
|
||||
(if (get-buffer-window (current-buffer))
|
||||
(car (window-text-pixel-size
|
||||
nil (line-beginning-position) (point-max) 10000))
|
||||
(let ((dedicatedp (window-dedicated-p))
|
||||
(oldbuffer (window-buffer)))
|
||||
(unwind-protect
|
||||
(progn
|
||||
;; Do not throw error in dedicated windows.
|
||||
(set-window-dedicated-p nil nil)
|
||||
(set-window-buffer nil (current-buffer))
|
||||
(car (window-text-pixel-size
|
||||
nil (line-beginning-position) (point-max) 10000)))
|
||||
(set-window-buffer nil oldbuffer)
|
||||
(set-window-dedicated-p nil dedicatedp)))))))
|
||||
(insert (propertize "a" 'face (or default-face 'default)))
|
||||
(setq symbol-width (org-buffer-text-pixel-width))))
|
||||
(if pixels
|
||||
pixel-width
|
||||
(/ pixel-width symbol-width)))))))
|
||||
(ceiling pixel-width symbol-width)))))))
|
||||
|
||||
(defmacro org-current-text-column ()
|
||||
"Like `current-column' but ignore display properties."
|
||||
`(string-width (buffer-substring-no-properties
|
||||
(line-beginning-position) (point))))
|
||||
"Like `current-column' but ignore display properties.
|
||||
Throw an error when `tab-width' is not 8.
|
||||
|
||||
This function forces `tab-width' value because it is used as a part of
|
||||
the parser, to ensure parser consistency when calculating list
|
||||
indentation."
|
||||
`(progn
|
||||
(unless (= 8 tab-width) (error "Tab width in Org files must be 8, not %d. Please adjust your `tab-width' settings for Org mode." tab-width))
|
||||
(string-width (buffer-substring-no-properties
|
||||
(line-beginning-position) (point)))))
|
||||
|
||||
(defun org-not-nil (v)
|
||||
"If V not nil, and also not the string \"nil\", then return V.
|
||||
|
@ -1227,6 +1291,10 @@ Assumes that s is a single line, starting in column 0."
|
|||
t t s)))
|
||||
s)
|
||||
|
||||
(defun org-remove-blank-lines (s)
|
||||
"Remove blank lines in S."
|
||||
(replace-regexp-in-string (rx "\n" (1+ (0+ space) "\n")) "\n" s))
|
||||
|
||||
(defun org-wrap (string &optional width lines)
|
||||
"Wrap string to either a number of lines, or a width in characters.
|
||||
If WIDTH is non-nil, the string is wrapped to that width, however many lines
|
||||
|
@ -1553,6 +1621,9 @@ Return 0. if S is not recognized as a valid value."
|
|||
((string-match org-ts-regexp0 s) (org-2ft s))
|
||||
(t 0.)))))
|
||||
|
||||
|
||||
;;; Misc
|
||||
|
||||
(defun org-scroll (key &optional additional-keys)
|
||||
"Receive KEY and scroll the current window accordingly.
|
||||
When ADDITIONAL-KEYS is not nil, also include SPC and DEL in the
|
||||
|
@ -1589,6 +1660,158 @@ Credit: https://stackoverflow.com/questions/11871245/knuth-multiplicative-hash#4
|
|||
(cl-assert (and (<= 0 base 32)))
|
||||
(ash (* number 2654435769) (- base 32)))
|
||||
|
||||
(defvar org-sxhash-hashes (make-hash-table :weakness 'key :test 'equal))
|
||||
(defvar org-sxhash-objects (make-hash-table :weakness 'value))
|
||||
(defun org-sxhash-safe (obj &optional counter)
|
||||
"Like `sxhash' for OBJ, but collision-free for in-memory objects.
|
||||
When COUNTER is non-nil, return safe hash for (COUNTER . OBJ)."
|
||||
;; Note: third-party code may modify OBJ by side effect.
|
||||
;; Should not affect anything as long as `org-sxhash-safe'
|
||||
;; is used to calculate hash.
|
||||
(or (and (not counter) (gethash obj org-sxhash-hashes))
|
||||
(let* ((hash (sxhash (if counter (cons counter obj) obj)))
|
||||
(obj-old (gethash hash org-sxhash-objects)))
|
||||
(if obj-old ; collision
|
||||
(org-sxhash-safe obj (if counter (1+ counter) 1))
|
||||
;; No collision. Remember and return normal hash.
|
||||
(puthash hash obj org-sxhash-objects)
|
||||
(puthash obj hash org-sxhash-hashes)))))
|
||||
|
||||
(defun org-compile-file (source process ext &optional err-msg log-buf spec)
|
||||
"Compile a SOURCE file using PROCESS.
|
||||
|
||||
See `org-compile-file-commands' for information on PROCESS, EXT, and SPEC.
|
||||
If PROCESS fails, an error will be raised. The error message can
|
||||
then be refined by providing string ERR-MSG, which is appended to
|
||||
the standard message.
|
||||
|
||||
PROCESS must create a file with the same base name and directory
|
||||
as SOURCE, but ending with EXT. The function then returns its
|
||||
filename. Otherwise, it raises an error.
|
||||
|
||||
When PROCESS is a list of commands, optional argument LOG-BUF can
|
||||
be set to a buffer or a buffer name. `shell-command' then uses
|
||||
it for output."
|
||||
(let* ((commands (org-compile-file-commands source process ext spec err-msg))
|
||||
(output (concat (file-name-sans-extension source) "." ext))
|
||||
;; Resolve symlinks in default-directory to correctly handle
|
||||
;; absolute source paths or relative paths with ..
|
||||
(relname (if (file-name-absolute-p source)
|
||||
(let ((pwd (file-truename default-directory)))
|
||||
(file-relative-name source pwd))
|
||||
source))
|
||||
(log-buf (and log-buf (get-buffer-create log-buf)))
|
||||
(time (file-attribute-modification-time (file-attributes output))))
|
||||
(save-window-excursion
|
||||
(dolist (command commands)
|
||||
(cond
|
||||
((functionp command)
|
||||
(funcall command (shell-quote-argument relname)))
|
||||
((stringp command)
|
||||
(let ((shell-command-dont-erase-buffer t))
|
||||
(shell-command command log-buf))))))
|
||||
;; Check for process failure. Output file is expected to be
|
||||
;; located in the same directory as SOURCE.
|
||||
(unless (org-file-newer-than-p output time)
|
||||
(ignore (defvar org-batch-test))
|
||||
;; Display logs when running tests.
|
||||
(when (bound-and-true-p org-batch-test)
|
||||
(message "org-compile-file log ::\n-----\n%s\n-----\n"
|
||||
(with-current-buffer log-buf (buffer-string))))
|
||||
(error
|
||||
(format
|
||||
"File %S wasn't produced%s"
|
||||
output
|
||||
(if (org-string-nw-p err-msg)
|
||||
(concat " " (org-trim err-msg))
|
||||
err-msg))))
|
||||
output))
|
||||
|
||||
(defun org-compile-file-commands (source process ext &optional spec err-msg)
|
||||
"Return list of commands used to compile SOURCE file.
|
||||
|
||||
The commands are formed from PROCESS, which is either a function or
|
||||
a list of shell commands, as strings. EXT is a file extension, without
|
||||
the leading dot, as a string. After PROCESS has been executed,
|
||||
a file with the same basename and directory as SOURCE but with the
|
||||
file extension EXT is expected to be produced.
|
||||
Failure to produce this file will be interpreted as PROCESS failing.
|
||||
|
||||
If PROCESS is a function, it is called with a single argument:
|
||||
the SOURCE file.
|
||||
|
||||
If PROCESS is a list of commands, each of them is called using
|
||||
`shell-command'. By default, in each command, %b, %f, %F, %o and
|
||||
%O are replaced with, respectively, SOURCE base name, relative
|
||||
file name, absolute file name, relative directory and absolute
|
||||
output file name. It is possible, however, to use more
|
||||
place-holders by specifying them in optional argument SPEC, as an
|
||||
alist following the pattern
|
||||
|
||||
(CHARACTER . REPLACEMENT-STRING).
|
||||
|
||||
Throw an error if PROCESS does not satisfy the described patterns.
|
||||
The error string will be appended with ERR-MSG, when it is a string."
|
||||
(let* ((basename (file-name-base source))
|
||||
;; Resolve symlinks in default-directory to correctly handle
|
||||
;; absolute source paths or relative paths with ..
|
||||
(pwd (file-truename default-directory))
|
||||
(absname (expand-file-name source pwd))
|
||||
(relname (if (file-name-absolute-p source)
|
||||
(file-relative-name source pwd)
|
||||
source))
|
||||
(relpath (or (file-name-directory relname) "./"))
|
||||
(output (concat (file-name-sans-extension absname) "." ext))
|
||||
(err-msg (if (stringp err-msg) (concat ". " err-msg) "")))
|
||||
(pcase process
|
||||
((pred functionp) (list process))
|
||||
((pred consp)
|
||||
(let ((spec (append spec
|
||||
`((?b . ,(shell-quote-argument basename))
|
||||
(?f . ,(shell-quote-argument relname))
|
||||
(?F . ,(shell-quote-argument absname))
|
||||
(?o . ,(shell-quote-argument relpath))
|
||||
(?O . ,(shell-quote-argument output))))))
|
||||
(mapcar (lambda (command) (format-spec command spec)) process)))
|
||||
(_ (error "No valid command to process %S%s" source err-msg)))))
|
||||
|
||||
(defun org-display-buffer-split (buffer alist)
|
||||
"Display BUFFER in the current frame split in two parts.
|
||||
The frame will display two buffers - current buffer and BUFFER.
|
||||
ALIST is an association list of action symbols and values. See
|
||||
Info node `(elisp) Buffer Display Action Alists' for details of
|
||||
such alists.
|
||||
|
||||
Use `display-buffer-in-direction' internally.
|
||||
|
||||
This is an action function for buffer display, see Info
|
||||
node `(elisp) Buffer Display Action Functions'. It should be
|
||||
called only by `display-buffer' or a function directly or
|
||||
indirectly called by the latter."
|
||||
(let ((window-configuration (current-window-configuration)))
|
||||
(ignore-errors (delete-other-windows))
|
||||
(or (display-buffer-in-direction buffer alist)
|
||||
(display-buffer-pop-up-window buffer alist)
|
||||
(prog1 nil
|
||||
(set-window-configuration window-configuration)))))
|
||||
|
||||
(defun org-display-buffer-in-window (buffer alist)
|
||||
"Display BUFFER in specific window.
|
||||
The window is defined according to the `window' slot in the ALIST.
|
||||
Then `same-frame' slot in the ALIST is set, only display buffer when
|
||||
window is present in the current frame.
|
||||
|
||||
This is an action function for buffer display, see Info
|
||||
node `(elisp) Buffer Display Action Functions'. It should be
|
||||
called only by `display-buffer' or a function directly or
|
||||
indirectly called by the latter."
|
||||
(let ((window (alist-get 'window alist)))
|
||||
(when (and window
|
||||
(window-live-p window)
|
||||
(or (not (alist-get 'same-frame alist))
|
||||
(eq (window-frame) (window-frame window))))
|
||||
(window--display-buffer buffer window 'reuse alist))))
|
||||
|
||||
(provide 'org-macs)
|
||||
|
||||
;; Local variables:
|
||||
|
|
|
@ -470,7 +470,7 @@ agenda view showing the flagged items."
|
|||
(insert "#+TAGS: " (mapconcat 'identity tags " ") "\n")
|
||||
(insert "#+ALLPRIORITIES: " org-mobile-allpriorities "\n")
|
||||
(when (file-exists-p (expand-file-name
|
||||
org-mobile-directory "agendas.org"))
|
||||
"agendas.org" org-mobile-directory))
|
||||
(insert "* [[file:agendas.org][Agenda Views]]\n"))
|
||||
(pcase-dolist (`(,_ . ,link-name) files-alist)
|
||||
(insert (format "* [[file:%s][%s]]\n" link-name link-name)))
|
||||
|
@ -627,11 +627,11 @@ The table of checksums is written to the file mobile-checksums."
|
|||
(setq short (get-text-property (point) 'short-heading))
|
||||
(when (and short (looking-at ".+"))
|
||||
(replace-match short nil t)
|
||||
(beginning-of-line 1))
|
||||
(forward-line 0))
|
||||
(when app
|
||||
(end-of-line 1)
|
||||
(insert app)
|
||||
(beginning-of-line 1))
|
||||
(forward-line 0))
|
||||
(insert "* "))
|
||||
((get-text-property (point) 'org-agenda-date-header)
|
||||
(setq in-date t)
|
||||
|
@ -649,7 +649,7 @@ The table of checksums is written to the file mobile-checksums."
|
|||
(line-end-position))))
|
||||
(delete-region (line-beginning-position) (line-end-position))
|
||||
(insert line "<before>" prefix "</before>")
|
||||
(beginning-of-line 1))
|
||||
(forward-line 0))
|
||||
(and (looking-at "[ \t]+") (replace-match "")))
|
||||
(insert (if in-date "*** " "** "))
|
||||
(end-of-line 1)
|
||||
|
@ -666,7 +666,7 @@ The table of checksums is written to the file mobile-checksums."
|
|||
(org-mobile-get-outline-path-link m))))
|
||||
(insert " :PROPERTIES:\n :ORIGINAL_ID: " id
|
||||
"\n :END:\n")))))
|
||||
(beginning-of-line 2))
|
||||
(forward-line 1))
|
||||
(push (cons "agendas.org" (md5 (buffer-string)))
|
||||
org-mobile-checksum-files))
|
||||
(message "Agenda written to Org file %s" file)))
|
||||
|
@ -1057,7 +1057,7 @@ be returned that indicates what went wrong."
|
|||
(goto-char (match-beginning 4))
|
||||
(insert new)
|
||||
(delete-region (point) (+ (point) (length current)))
|
||||
(org-align-tags))
|
||||
(when org-auto-align-tags (org-align-tags)))
|
||||
(t
|
||||
(error
|
||||
"Heading changed in the mobile device and on the computer")))))))
|
||||
|
@ -1071,7 +1071,7 @@ be returned that indicates what went wrong."
|
|||
(end-of-line 1)
|
||||
(org-insert-heading-respect-content t)
|
||||
(org-demote))
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(insert "* "))
|
||||
(insert new))
|
||||
|
||||
|
|
|
@ -185,8 +185,8 @@ Changing this variable requires a restart of Emacs to get activated."
|
|||
(const :tag "Activate checkboxes" activate-checkboxes)))
|
||||
|
||||
(defun org-mouse-re-search-line (regexp)
|
||||
"Search the current line for a given regular expression."
|
||||
(beginning-of-line)
|
||||
"Search the current line for a given regular expression REGEXP."
|
||||
(forward-line 0)
|
||||
(re-search-forward regexp (line-end-position) t))
|
||||
|
||||
(defun org-mouse-end-headline ()
|
||||
|
@ -242,13 +242,13 @@ return `:middle'."
|
|||
|
||||
(defun org-mouse-empty-line ()
|
||||
"Return non-nil if the line contains only white space."
|
||||
(save-excursion (beginning-of-line) (looking-at "[ \t]*$")))
|
||||
(save-excursion (forward-line 0) (looking-at "[ \t]*$")))
|
||||
|
||||
(defun org-mouse-next-heading ()
|
||||
"Go to the next heading.
|
||||
If there is none, ensure that the point is at the beginning of an empty line."
|
||||
(unless (outline-next-heading)
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(unless (org-mouse-empty-line)
|
||||
(end-of-line)
|
||||
(newline))))
|
||||
|
@ -261,7 +261,7 @@ insert the new heading before the current line. Otherwise, insert it
|
|||
after the current heading."
|
||||
(interactive)
|
||||
(cl-case (org-mouse-line-position)
|
||||
(:beginning (beginning-of-line)
|
||||
(:beginning (forward-line 0)
|
||||
(org-insert-heading))
|
||||
(t (org-mouse-next-heading)
|
||||
(org-insert-heading))))
|
||||
|
@ -271,7 +271,7 @@ after the current heading."
|
|||
|
||||
For the acceptable UNITS, see `org-timestamp-change'."
|
||||
(interactive)
|
||||
(org-time-stamp nil)
|
||||
(org-timestamp nil)
|
||||
(when shift (org-timestamp-change shift units)))
|
||||
|
||||
(defun org-mouse-keyword-menu (keywords function &optional selected itemformat)
|
||||
|
@ -426,13 +426,14 @@ SCHEDULED: or DEADLINE: or ANYTHINGLIKETHIS:"
|
|||
(append
|
||||
(let ((tags (org-get-tags nil t)))
|
||||
(org-mouse-keyword-menu
|
||||
(sort (mapcar #'car (org-get-buffer-tags)) #'string-lessp)
|
||||
(sort (mapcar #'car (org-get-buffer-tags))
|
||||
(or org-tags-sort-function #'org-string<))
|
||||
(lambda (tag)
|
||||
(org-mouse-set-tags
|
||||
(sort (if (member tag tags)
|
||||
(delete tag tags)
|
||||
(cons tag tags))
|
||||
#'string-lessp)))
|
||||
(or org-tags-sort-function #'org-string<))))
|
||||
(lambda (tag) (member tag tags))
|
||||
))
|
||||
'("--"
|
||||
|
@ -473,7 +474,7 @@ SCHEDULED: or DEADLINE: or ANYTHINGLIKETHIS:"
|
|||
(sort (if (member ',name ',options)
|
||||
(delete ',name ',options)
|
||||
(cons ',name ',options))
|
||||
'string-lessp)
|
||||
#'org-string<)
|
||||
" ")
|
||||
nil nil nil 1)
|
||||
(when (functionp ',function) (funcall ',function)))
|
||||
|
@ -502,7 +503,8 @@ SCHEDULED: or DEADLINE: or ANYTHINGLIKETHIS:"
|
|||
["Check TODOs" org-show-todo-tree t]
|
||||
("Check Tags"
|
||||
,@(org-mouse-keyword-menu
|
||||
(sort (mapcar #'car (org-get-buffer-tags)) #'string-lessp)
|
||||
(sort (mapcar #'car (org-get-buffer-tags))
|
||||
(or org-tags-sort-function #'org-string<))
|
||||
(lambda (tag) (org-tags-sparse-tree nil tag)))
|
||||
"--"
|
||||
["Custom Tag ..." org-tags-sparse-tree t])
|
||||
|
@ -512,7 +514,8 @@ SCHEDULED: or DEADLINE: or ANYTHINGLIKETHIS:"
|
|||
["Display TODO List" org-todo-list t]
|
||||
("Display Tags"
|
||||
,@(org-mouse-keyword-menu
|
||||
(sort (mapcar #'car (org-get-buffer-tags)) #'string-lessp)
|
||||
(sort (mapcar #'car (org-get-buffer-tags))
|
||||
(or org-tags-sort-function #'org-string<))
|
||||
(lambda (tag) (org-tags-view nil tag)))
|
||||
"--"
|
||||
["Custom Tag ..." org-tags-view t])
|
||||
|
@ -566,7 +569,7 @@ This means, between the beginning of line and the point."
|
|||
(defun org-mouse-insert-item (text)
|
||||
(cl-case (org-mouse-line-position)
|
||||
(:beginning ; insert before
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(looking-at "[ \t]*")
|
||||
(open-line 1)
|
||||
(indent-to-column (- (match-end 0) (match-beginning 0)))
|
||||
|
@ -582,7 +585,7 @@ This means, between the beginning of line and the point."
|
|||
(unless (looking-back org-mouse-punctuation (line-beginning-position))
|
||||
(insert (concat org-mouse-punctuation " ")))))
|
||||
(insert text)
|
||||
(beginning-of-line))
|
||||
(forward-line 0))
|
||||
|
||||
(advice-add 'dnd-insert-text :around #'org--mouse-dnd-insert-text)
|
||||
(defun org--mouse-dnd-insert-text (orig-fun window action text &rest args)
|
||||
|
@ -632,7 +635,7 @@ This means, between the beginning of line and the point."
|
|||
(progn (save-excursion (goto-char (region-beginning)) (insert "[["))
|
||||
(save-excursion (goto-char (region-end)) (insert "]]")))]
|
||||
["Insert Link Here" (org-mouse-yank-link ',event)]))))
|
||||
((save-excursion (beginning-of-line) (looking-at "[ \t]*#\\+STARTUP: \\(.*\\)"))
|
||||
((save-excursion (forward-line 0) (looking-at "[ \t]*#\\+STARTUP: \\(.*\\)"))
|
||||
(popup-menu
|
||||
`(nil
|
||||
,@(org-mouse-list-options-menu (mapcar #'car org-startup-options)
|
||||
|
@ -713,7 +716,7 @@ This means, between the beginning of line and the point."
|
|||
(popup-menu
|
||||
'(nil
|
||||
["Show Day" org-open-at-point t]
|
||||
["Change Timestamp" org-time-stamp t]
|
||||
["Change Timestamp" org-timestamp t]
|
||||
["Delete Timestamp" (org-mouse-delete-timestamp) t]
|
||||
["Compute Time Range" org-evaluate-time-range (org-at-date-range-p)]
|
||||
"--"
|
||||
|
@ -823,8 +826,8 @@ This means, between the beginning of line and the point."
|
|||
:active (not (save-excursion
|
||||
(org-mouse-re-search-line org-scheduled-regexp)))]
|
||||
["Insert Timestamp"
|
||||
(progn (org-mouse-end-headline) (insert " ") (org-time-stamp nil)) t]
|
||||
; ["Timestamp (inactive)" org-time-stamp-inactive t]
|
||||
(progn (org-mouse-end-headline) (insert " ") (org-timestamp nil)) t]
|
||||
; ["Timestamp (inactive)" org-timestamp-inactive t]
|
||||
"--"
|
||||
["Archive Subtree" org-archive-subtree]
|
||||
["Cut Subtree" org-cut-special]
|
||||
|
@ -980,7 +983,7 @@ This means, between the beginning of line and the point."
|
|||
(org-back-to-heading)
|
||||
(let ((minlevel 1000)
|
||||
(replace-text (concat (make-string (org-current-level) ?*) "* ")))
|
||||
(beginning-of-line 2)
|
||||
(forward-line 1)
|
||||
(save-excursion
|
||||
(while (not (or (eobp) (looking-at org-outline-regexp)))
|
||||
(when (looking-at org-mouse-plain-list-regexp)
|
||||
|
@ -1028,7 +1031,7 @@ This means, between the beginning of line and the point."
|
|||
(unless (eq (marker-position marker) (marker-position endmarker))
|
||||
(setq newhead (org-get-heading))))
|
||||
|
||||
(beginning-of-line 1)
|
||||
(forward-line 1)
|
||||
(save-excursion
|
||||
(org-agenda-change-all-lines newhead hdmarker 'fixface))))
|
||||
t))))
|
||||
|
|
|
@ -83,6 +83,7 @@
|
|||
|
||||
;;; Customization
|
||||
|
||||
;;;###autoload
|
||||
(defcustom org-num-face nil
|
||||
"Face to use for numbering.
|
||||
When nil, use the same face as the headline. This value is
|
||||
|
@ -104,6 +105,7 @@ Any `face' text property on the returned string overrides
|
|||
:package-version '(Org . "9.3")
|
||||
:type 'function)
|
||||
|
||||
;;;###autoload
|
||||
(defcustom org-num-max-level nil
|
||||
"Level below which headlines are not numbered.
|
||||
When set to nil, all headlines are numbered."
|
||||
|
@ -113,6 +115,7 @@ When set to nil, all headlines are numbered."
|
|||
(integer :tag "Stop numbering at level"))
|
||||
:safe (lambda (val) (or (null val) (wholenump val))))
|
||||
|
||||
;;;###autoload
|
||||
(defcustom org-num-skip-commented nil
|
||||
"Non-nil means commented sub-trees are not numbered."
|
||||
:group 'org-appearance
|
||||
|
@ -120,6 +123,7 @@ When set to nil, all headlines are numbered."
|
|||
:type 'boolean
|
||||
:safe #'booleanp)
|
||||
|
||||
;;;###autoload
|
||||
(defcustom org-num-skip-footnotes nil
|
||||
"Non-nil means footnotes sections are not numbered."
|
||||
:group 'org-appearance
|
||||
|
@ -127,6 +131,7 @@ When set to nil, all headlines are numbered."
|
|||
:type 'boolean
|
||||
:safe #'booleanp)
|
||||
|
||||
;;;###autoload
|
||||
(defcustom org-num-skip-tags nil
|
||||
"List of tags preventing the numbering of sub-trees.
|
||||
|
||||
|
@ -141,6 +146,7 @@ control tag inheritance."
|
|||
:type '(repeat (string :tag "Tag"))
|
||||
:safe (lambda (val) (and (listp val) (cl-every #'stringp val))))
|
||||
|
||||
;;;###autoload
|
||||
(defcustom org-num-skip-unnumbered nil
|
||||
"Non-nil means numbering obeys to UNNUMBERED property."
|
||||
:group 'org-appearance
|
||||
|
@ -214,7 +220,7 @@ Assume point is at a headline."
|
|||
(let ((after-edit-functions
|
||||
(list (lambda (o &rest _) (org-num--invalidate-overlay o))))
|
||||
(o (save-excursion
|
||||
(beginning-of-line)
|
||||
(forward-line 0)
|
||||
(skip-chars-forward "*")
|
||||
(make-overlay (line-beginning-position) (1+ (point))))))
|
||||
(overlay-put o 'org-num t)
|
||||
|
@ -267,7 +273,7 @@ otherwise."
|
|||
tags)
|
||||
t)
|
||||
(and org-num-skip-unnumbered
|
||||
(org-entry-get (point) "UNNUMBERED")
|
||||
(org-entry-get (point) "UNNUMBERED" 'selective)
|
||||
t))))
|
||||
|
||||
(defun org-num--current-numbering (level skip)
|
||||
|
|
|
@ -22,6 +22,10 @@
|
|||
;; 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:
|
||||
|
||||
;; This library implementes completion support in Org mode buffers.
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;;; Require other packages
|
||||
|
@ -39,8 +43,9 @@
|
|||
(declare-function org-before-first-heading-p "org" ())
|
||||
(declare-function org-buffer-property-keys "org" (&optional specials defaults columns))
|
||||
(declare-function org-element-at-point "org-element" (&optional pom cached-only))
|
||||
(declare-function org-element-property "org-element" property element)
|
||||
(declare-function org-element-type "org-element" (element))
|
||||
(declare-function org-element-property "org-element-ast" (property node &optional dflt force-undefer))
|
||||
(declare-function org-element-end "org-element" (node))
|
||||
(declare-function org-element-type-p "org-element-ast" (node types))
|
||||
(declare-function org-end-of-meta-data "org" (&optional full))
|
||||
(declare-function org-entry-properties "org" (&optional pom which))
|
||||
(declare-function org-export-backend-options "ox" (cl-x) t)
|
||||
|
@ -171,21 +176,29 @@ When completing for #+STARTUP, for example, this function returns
|
|||
|
||||
(defun org-parse-arguments ()
|
||||
"Parse whitespace separated arguments in the current region."
|
||||
(let ((begin (line-beginning-position))
|
||||
(end (line-end-position))
|
||||
begins args)
|
||||
(save-restriction
|
||||
(narrow-to-region begin end)
|
||||
(if (equal (cons "searchhead" nil) (org-thing-at-point))
|
||||
;; [[* foo<point> bar link::search option.
|
||||
;; Arguments are not simply space-separated.
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(while (not (eobp))
|
||||
(skip-chars-forward " \t\n[")
|
||||
(setq begins (cons (point) begins))
|
||||
(skip-chars-forward "^ \t\n[")
|
||||
(setq args (cons (buffer-substring-no-properties
|
||||
(car begins) (point))
|
||||
args)))
|
||||
(cons (reverse args) (reverse begins))))))
|
||||
(let ((origin (point)))
|
||||
(skip-chars-backward "^*" (line-beginning-position))
|
||||
(cons (list (buffer-substring-no-properties (point) origin))
|
||||
(list (point)))))
|
||||
(let ((begin (line-beginning-position))
|
||||
(end (line-end-position))
|
||||
begins args)
|
||||
(save-restriction
|
||||
(narrow-to-region begin end)
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(while (not (eobp))
|
||||
(skip-chars-forward " \t\n[")
|
||||
(setq begins (cons (point) begins))
|
||||
(skip-chars-forward "^ \t\n[")
|
||||
(setq args (cons (buffer-substring-no-properties
|
||||
(car begins) (point))
|
||||
args)))
|
||||
(cons (reverse args) (reverse begins)))))))
|
||||
|
||||
(defun org-pcomplete-initial ()
|
||||
"Call the right completion function for first argument completions."
|
||||
|
@ -306,7 +319,7 @@ When completing for #+STARTUP, for example, this function returns
|
|||
"creator:" "date:" "d:" "email:" "*:" "e:" "::" "f:"
|
||||
"inline:" "tex:" "p:" "pri:" "':" "-:" "stat:" "^:" "toc:"
|
||||
"|:" "tags:" "tasks:" "<:" "todo:")
|
||||
;; OPTION items from registered back-ends.
|
||||
;; OPTION items from registered backends.
|
||||
(let (items)
|
||||
(dolist (backend (bound-and-true-p
|
||||
org-export-registered-backends))
|
||||
|
@ -361,14 +374,7 @@ This needs more work, to handle headings with lots of spaces in them."
|
|||
;; Remove the leading asterisk from
|
||||
;; `org-link-heading-search-string' result.
|
||||
(push (substring (org-link-heading-search-string) 1) tbl))
|
||||
(pcomplete-uniquify-list tbl)))
|
||||
;; When completing a bracketed link, i.e., "[[*", argument
|
||||
;; starts at the star, so remove this character.
|
||||
;; Also, if the completion is done inside [[*head<point>]],
|
||||
;; drop the closing parentheses.
|
||||
(replace-regexp-in-string
|
||||
"\\]+$" ""
|
||||
(substring pcomplete-stub 1)))))
|
||||
(pcomplete-uniquify-list tbl))))))
|
||||
|
||||
(defun pcomplete/org-mode/tag ()
|
||||
"Complete a tag name. Omit tags already set."
|
||||
|
@ -397,10 +403,9 @@ This needs more work, to handle headings with lots of spaces in them."
|
|||
(goto-char (point-min))
|
||||
(while (re-search-forward org-drawer-regexp nil t)
|
||||
(let ((drawer (org-element-at-point)))
|
||||
(when (memq (org-element-type drawer)
|
||||
'(drawer property-drawer))
|
||||
(when (org-element-type-p drawer '(drawer property-drawer))
|
||||
(push (org-element-property :drawer-name drawer) names)
|
||||
(goto-char (org-element-property :end drawer))))))
|
||||
(goto-char (org-element-end drawer))))))
|
||||
(pcomplete-uniquify-list names))))
|
||||
(substring pcomplete-stub 1))) ;remove initial colon
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue