pkg update and first config fix
org-brain not working, add org-roam
This commit is contained in:
396
lisp/org-roam-bibtex/orb-anystyle.el
Normal file
396
lisp/org-roam-bibtex/orb-anystyle.el
Normal file
@@ -0,0 +1,396 @@
|
||||
;;; orb-anystyle.el --- Orb Roam BibTeX: Elisp interface to Anystyle -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright © 2020-2022 Mykhailo Shevchuk
|
||||
|
||||
;; Author: Mykhailo Shevchuk <mail@mshevchuk.com>
|
||||
;; URL: https://github.com/org-roam/org-roam-bibtex
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 3, or (at your option)
|
||||
;; any later version.
|
||||
;;
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU General Public License along with
|
||||
;; this program; see the file LICENSE. If not, visit
|
||||
;; <https://www.gnu.org/licenses/>.
|
||||
|
||||
;; N.B. This file contains code snippets adopted from other
|
||||
;; open-source projects. These snippets are explicitly marked as such
|
||||
;; in place. They are not subject to the above copyright and
|
||||
;; authorship claims.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
;; * Library requires
|
||||
|
||||
(require 'orb-core)
|
||||
|
||||
(eval-when-compile
|
||||
(require 'subr-x)
|
||||
(require 'cl-macs))
|
||||
|
||||
;; * Customize definitions
|
||||
|
||||
(defcustom orb-anystyle-executable "anystyle"
|
||||
"Anystyle executable path or program name."
|
||||
:type '(choice (const "anystyle")
|
||||
(file :tag "Path to executable" :must-match t))
|
||||
:group 'orb-anystyle)
|
||||
|
||||
(defcustom orb-anystyle-pdfinfo-executable nil
|
||||
"Path to pdfinfo executable to be passed to anystyle.
|
||||
When this is nil, anystyle will look for it in the system path."
|
||||
:type '(choice
|
||||
(file :tag "Path to executable")
|
||||
(const nil))
|
||||
:group 'orb-anystyle)
|
||||
|
||||
(defcustom orb-anystyle-pdftotext-executable nil
|
||||
"Path to pdftotext executable to be passed to anystyle.
|
||||
When this is nil, anystyle will look for it in the system path."
|
||||
:type '(choice
|
||||
(file :tag "Path to executable")
|
||||
(const nil))
|
||||
:group 'orb-anystyle)
|
||||
|
||||
(defcustom orb-anystyle-parser-model nil
|
||||
"Path to anystyle custom parser model."
|
||||
:type '(choice
|
||||
(file :tag "Path to file" :must-match t)
|
||||
(const :tag "Built-in" nil))
|
||||
:group 'orb-anystyle)
|
||||
|
||||
(defcustom orb-anystyle-finder-model nil
|
||||
"Path to anystyle custom finder model."
|
||||
:type '(choice
|
||||
(file :tag "Path to file" :must-match t)
|
||||
(const :tag "Built-in" nil))
|
||||
:group 'orb-anystyle)
|
||||
|
||||
;; --crop is currently broken upstream
|
||||
|
||||
(defcustom orb-anystyle-find-crop nil
|
||||
"Crop value in pt to be passed to `anystyle find'.
|
||||
An integer or a conc cell of integers."
|
||||
:type '(choice (integer :tag "Top and bottom")
|
||||
(cons :tag "Top, bottom, left and right"
|
||||
(integer :tag "Top and bottom")
|
||||
(integer :tag "Left and right"))
|
||||
(const :tag "Do not crop" nil))
|
||||
:group 'orb-anystyle)
|
||||
|
||||
(defcustom orb-anystyle-find-solo nil
|
||||
"Non-nil to pass the `--solo' flag."
|
||||
:type '(choice (const :tag "Yes" t)
|
||||
(const :tag "No" nil))
|
||||
:group 'orb-anystyle)
|
||||
|
||||
(defcustom orb-anystyle-find-layout nil
|
||||
"Non-nil to pass the `--layout' flag."
|
||||
:type '(choice (const :tag "Yes" t)
|
||||
(const :tag "No" nil))
|
||||
:group 'orb-anystyle)
|
||||
|
||||
(defcustom orb-anystyle-default-buffer "*Orb Anystyle Output*"
|
||||
"Default buffer name for anystyle output."
|
||||
:type 'string
|
||||
:group 'orb-anystyle)
|
||||
|
||||
(defcustom orb-anystyle-user-directory
|
||||
(concat (file-name-as-directory user-emacs-directory) "anystyle")
|
||||
"Directory to keep anystyle user files."
|
||||
:type 'directory
|
||||
:group 'orb-anystyle)
|
||||
|
||||
(defcustom orb-anystyle-parser-training-set
|
||||
(concat (file-name-as-directory orb-anystyle-user-directory) "core.xml")
|
||||
"XML file containing parser training data."
|
||||
:type '(file :must-match t)
|
||||
:group 'anystyle)
|
||||
|
||||
(defcustom orb-anystyle-finder-training-set
|
||||
(f-join (file-name-as-directory orb-anystyle-user-directory) "ttx/")
|
||||
"Directory containing finder training data (.ttx files)."
|
||||
:type 'directory
|
||||
:group 'anystyle)
|
||||
|
||||
;; * Main functions
|
||||
|
||||
;;;###autoload
|
||||
(cl-defun orb-anystyle (command
|
||||
&key (exec orb-anystyle-executable)
|
||||
verbose help version adapter
|
||||
((:finder-model fmodel) orb-anystyle-finder-model)
|
||||
((:parser-model pmodel) orb-anystyle-parser-model)
|
||||
(pdfinfo orb-anystyle-pdfinfo-executable)
|
||||
(pdftotext orb-anystyle-pdftotext-executable)
|
||||
format stdout overwrite
|
||||
(crop orb-anystyle-find-crop)
|
||||
(solo orb-anystyle-find-solo)
|
||||
(layout orb-anystyle-find-layout)
|
||||
input output
|
||||
(buffer orb-anystyle-default-buffer))
|
||||
"Run anystyle COMMAND with `shell-command'.
|
||||
ARGS is a plist with the following recognized keys:
|
||||
|
||||
Anystyle CLI options
|
||||
==========
|
||||
1) EXEC :exec => string (valid executable)
|
||||
- default value can be set through `orb-anystyle-executable'
|
||||
|
||||
2) COMMAND :command => symbol or string
|
||||
- valid values: find parse help check license train
|
||||
|
||||
3) Global options can be passed with the following keys.
|
||||
|
||||
FMODEL :finder-model => string (valid file path)
|
||||
PMODEL :parser-model => string (valid file path)
|
||||
PDFINFO :pdfinfo => string (valid executable)
|
||||
PDFTOTEXT :pdftotext => string (valid executable)
|
||||
ADAPTER :adapter => anything
|
||||
STDOUT :stdout => boolean
|
||||
HELP :help => boolean
|
||||
VERBOSE :verbose => boolean
|
||||
VERSION :version => boolean
|
||||
OVERWRITE :overwrite => boolean
|
||||
FORMAT :format => string, symbol or list of unquoted symbols
|
||||
|
||||
- FORMAT must be one or more output formats accepted by anystyle commands:
|
||||
parse => bib csl json ref txt xml
|
||||
find => bib csl json ref txt ttx xml
|
||||
- string must be space- or comma-separated, additional spaces are
|
||||
ignored
|
||||
|
||||
Default values for some of these options can be set globally via
|
||||
the following variables: `orb-anystyle-finder-model',
|
||||
`orb-anystyle-parser-model', `orb-anystyle-pdfinfo-executable',
|
||||
`orb-anystyle-pdftotext-executable'.
|
||||
|
||||
4) Command options can be passed with the following keys:
|
||||
|
||||
CROP :crop => integer or cons cell of integers
|
||||
LAYOUT :layout => boolean
|
||||
SOLO :solo => boolean
|
||||
|
||||
- Command options are ignored for commands other than find
|
||||
- anystyle help -c flag is not supported
|
||||
|
||||
Default values for these options can be set globally via the
|
||||
following variables: `orb-anystyle-find-crop',
|
||||
`orb-anystyle-find-layout', `orb-anystyle-find-solo'.
|
||||
|
||||
5) INPUT :input => string (file path)
|
||||
|
||||
6) OUTPUT :output => string (file path)
|
||||
|
||||
`shell-command'-related options
|
||||
==========
|
||||
|
||||
7) BUFFER :buffer => buffer-or-name
|
||||
|
||||
- `shell-command''s OUTPUT-BUFFER
|
||||
- can be a cons cell (OUTPUT-BUFFER . ERROR-BUFFER)
|
||||
- when nil, defaults to `orb-anystyle-default-buffer'
|
||||
|
||||
anystyle CLI command synopsis:
|
||||
anystyle [global options] command [command options] [arguments...].
|
||||
|
||||
Homepage: https://anystyle.io
|
||||
Github: https://github.com/inukshuk/anystyle-cli
|
||||
Courtesy of its authors."
|
||||
(declare (indent 1))
|
||||
(let* ((commands '(list find parse check train help license))
|
||||
(exec (executable-find exec))
|
||||
(buf (if (consp buffer) buffer (list buffer)))
|
||||
;; '(a b c) => "a,b,c"
|
||||
(to-string (lambda (str)
|
||||
(--reduce-from
|
||||
(format "%s,%s" acc it)
|
||||
(car str) (cdr str))))
|
||||
;; debug
|
||||
;; (anystyle-run (lambda (str)
|
||||
;; (message "command: %s \nbuffers: %s and %s" str (car buf) (cdr buf))))
|
||||
(anystyle-run (lambda (str)
|
||||
(if (eq command 'train)
|
||||
;; train can take minutes, so run it in a sub-process
|
||||
(start-process-shell-command
|
||||
"anystyle" (car buf) str)
|
||||
(shell-command str
|
||||
(car buf) (cdr buf)))))
|
||||
global-options command-options anystyle)
|
||||
;; executable is a must
|
||||
(unless exec
|
||||
(user-error "Anystyle executable not found! \
|
||||
Install anystyle-cli before running Orb PDF Scrapper"))
|
||||
;; we process :version and :help before checking command
|
||||
;; since with this global flag command is not required
|
||||
(cond
|
||||
;; help flag takes priority
|
||||
(help
|
||||
(setq global-options " --help"
|
||||
command-options ""
|
||||
input nil
|
||||
output nil))
|
||||
;; anystyle ignores everything with --version flag except the
|
||||
;; --help flag, which we've just resolved above
|
||||
(version
|
||||
(setq global-options "--version"
|
||||
command nil
|
||||
command-options ""
|
||||
input nil
|
||||
output nil))
|
||||
;; otherwise command is a must
|
||||
((not command)
|
||||
(user-error "Anystyle command required: \
|
||||
find, parse, check, train, help or license")))
|
||||
(when (stringp command)
|
||||
(setq command (intern command)))
|
||||
;; command must be a valid command
|
||||
(unless (memq command commands)
|
||||
(user-error "Invalid command %s. Valid commands are \
|
||||
find, parse, check, train, help and license" command))
|
||||
;;
|
||||
;; command specific arguments
|
||||
(cl-case command
|
||||
('help
|
||||
(when (stringp input)
|
||||
(setq input (intern input)))
|
||||
(unless (or (and global-options
|
||||
(string= global-options " --help"))
|
||||
(memq input commands))
|
||||
(user-error "Invalid input %s. Valid input for 'anystyle help': \
|
||||
find, parse, check, train, help or license" input)))
|
||||
('license
|
||||
(setq input nil
|
||||
output nil
|
||||
global-options ""
|
||||
command-options ""))
|
||||
('check
|
||||
(setq output nil))
|
||||
('find
|
||||
;; pdfinfo and pdftotext must be present in the system
|
||||
(when (and pdfinfo (not (executable-find pdfinfo)))
|
||||
(user-error "Executable not found: pdfinfo, %s" pdfinfo))
|
||||
(when (and pdftotext (not (executable-find pdftotext)))
|
||||
(user-error "Executable not found: pdftotext, %s" pdftotext))
|
||||
(setq global-options
|
||||
(orb-format "%s" global-options
|
||||
" --pdfinfo=\"%s\"" pdfinfo
|
||||
" --pdftotext=\"%s\"" pdftotext))
|
||||
;; Command options
|
||||
;; N.B. Help command accepts a command option -c but it's totally
|
||||
;; irrelevant for us:
|
||||
;;
|
||||
;; [COMMAND OPTIONS]
|
||||
;; -c - List commands one per line, to assist with shell completion
|
||||
;; so we do not implement it
|
||||
;;
|
||||
;; :crop value should be integer; if no value was explicitly supplied,
|
||||
;; use the default from `orb-anystyle-find-crop'
|
||||
(when crop
|
||||
(unless (consp crop)
|
||||
(setq crop (list crop)))
|
||||
(let ((x (car crop))
|
||||
(y (or (cdr crop) 0)))
|
||||
(unless (and (integerp x)
|
||||
(integerp y))
|
||||
(user-error "Invalid value %s,%y. Number expected" x y))
|
||||
(setq crop (format "%s,%s" x y))))
|
||||
;; parse only accepts --[no]-layout, so we ignore the rest
|
||||
;; append command options to command
|
||||
(setq command-options
|
||||
(orb-format " --crop=%s" crop
|
||||
" --layout" (cons layout " --no-layout")
|
||||
" --solo" (cons solo " --no-solo"))))
|
||||
('train
|
||||
(unless output
|
||||
(setq output
|
||||
(concat (or (file-name-directory orb-anystyle-parser-training-set)
|
||||
(file-name-as-directory orb-anystyle-user-directory))
|
||||
"parser.mod")))))
|
||||
;; Arguments relevant for more than one command
|
||||
;;
|
||||
;; find, parse:
|
||||
;; format option should be one of accepted types if present
|
||||
(when (and (memq command '(find parse))
|
||||
format)
|
||||
(when (stringp format)
|
||||
(setq format
|
||||
(-map #'intern
|
||||
(split-string (string-trim format)
|
||||
"[, ]" t " "))))
|
||||
(unless (listp format)
|
||||
(setq format (list format)))
|
||||
(let ((accepted-formats
|
||||
(cl-case command
|
||||
('find '(bib csl json ref txt ttx xml))
|
||||
('parse '(bib csl json ref txt xml)))))
|
||||
(when (--none? (memq it accepted-formats) format)
|
||||
(user-error
|
||||
"Invalid format(s) %s. Valid formats for command %s: %s"
|
||||
(funcall to-string format)
|
||||
command
|
||||
(funcall to-string accepted-formats)))
|
||||
;; convert format to a comma-separated string and append
|
||||
;; it to global options
|
||||
(setq global-options
|
||||
(orb-format "%s" global-options
|
||||
" -f %s" (funcall to-string format)))))
|
||||
;; find, parse, check accept
|
||||
;; finder and parser models
|
||||
(when (memq command '(find parse check))
|
||||
(when (and fmodel (not (f-exists? fmodel)))
|
||||
(display-warning 'org-roam-bibtex
|
||||
"Finder model file not found: %s, \
|
||||
using the default one" fmodel)
|
||||
(setq fmodel nil))
|
||||
(when (and pmodel (not (f-exists? pmodel)))
|
||||
(display-warning 'org-roam-bibtex
|
||||
"Finder model file not found: %s, \
|
||||
using the default one" pmodel)
|
||||
(setq pmodel nil))
|
||||
(setq global-options (orb-format "%s" global-options
|
||||
" -F \"%s\"" fmodel
|
||||
" -P \"%s\"" pmodel)))
|
||||
;; find, train, parse and check:
|
||||
;; 1) require input, which should be a valid path
|
||||
;; 2) something called ruby adapter, probably a right place here
|
||||
;; 3) --verbose, --stdout, --overwrite if non-nil
|
||||
(when (memq command '(find train parse check))
|
||||
(unless input
|
||||
(user-error "Input required for command %s" command))
|
||||
(unless (and (stringp input) (f-exists? input))
|
||||
(user-error "Invalid input file or directory %s" input))
|
||||
(setq global-options
|
||||
(orb-format
|
||||
"%s" global-options
|
||||
" --verbose" (cons verbose " --no-verbose")
|
||||
;; this flag does nothing for check
|
||||
" --stdout" (cons stdout " --no-stdout")
|
||||
" --adapter=\"%s\"" adapter
|
||||
" --overwrite" (cons overwrite " --no-overwrite"))))
|
||||
;; Set arguments and run the program
|
||||
;;
|
||||
(setq anystyle (orb-format "%s" exec
|
||||
"%s" global-options
|
||||
" %s" command
|
||||
"%s" command-options
|
||||
" \"%s\"" (when input (file-truename input))
|
||||
" \"%s\"" (when output (file-truename output))))
|
||||
(funcall anystyle-run anystyle)))
|
||||
|
||||
(provide 'orb-anystyle)
|
||||
;;; orb-anystyle.el ends here
|
||||
;; Local Variables:
|
||||
;; coding: utf-8
|
||||
;; fill-column: 79
|
||||
;; End:
|
||||
48
lisp/org-roam-bibtex/orb-compat.el
Normal file
48
lisp/org-roam-bibtex/orb-compat.el
Normal file
@@ -0,0 +1,48 @@
|
||||
;;; org-roam-bibtex-compat.el --- Org Roam BibTeX: obsolete definitions -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright © 2020-2022 Mykhailo Shevchuk
|
||||
;; Copyright © 2020 Leo Vivier
|
||||
|
||||
;; Author: Mykhailo Shevchuk <mail@mshevchuk.com>
|
||||
;; Leo Vivier <leo.vivier+dev@gmail.com>
|
||||
;; URL: https://github.com/org-roam/org-roam-bibtex
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 3, or (at your option)
|
||||
;; any later version.
|
||||
;;
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU General Public License along with
|
||||
;; this program; see the file LICENSE. If not, visit
|
||||
;; <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Obsolete definitions live here. For a while.
|
||||
|
||||
;;; Code:
|
||||
|
||||
;; * org-roam-bibtex.el
|
||||
|
||||
(define-obsolete-variable-alias
|
||||
'orb-citekey-format 'orb-roam-ref-format "0.6.1")
|
||||
|
||||
(define-obsolete-variable-alias
|
||||
'orb-file-field-extensions 'orb-attached-file-extensions "0.6.1")
|
||||
|
||||
(define-obsolete-function-alias
|
||||
'orb-process-file-field 'orb-get-attached-file "0.6.1")
|
||||
|
||||
(provide 'orb-compat)
|
||||
;;; orb-compat.el ends here
|
||||
;; Local Variables:
|
||||
;; coding: utf-8
|
||||
;; fill-column: 79
|
||||
;; End:
|
||||
609
lisp/org-roam-bibtex/orb-core.el
Normal file
609
lisp/org-roam-bibtex/orb-core.el
Normal file
@@ -0,0 +1,609 @@
|
||||
;;; orb-core.el --- Org Roam BibTeX: core library -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright © 2020-2022 Mykhailo Shevchuk
|
||||
;; Copyright © 2020 Leo Vivier
|
||||
|
||||
;; Author: Mykhailo Shevchuk <mail@mshevchuk.com>
|
||||
;; Leo Vivier <leo.vivier+dev@gmail.com>
|
||||
;; URL: https://github.com/org-roam/org-roam-bibtex
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 3, or (at your option)
|
||||
;; any later version.
|
||||
;;
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU General Public License along with
|
||||
;; this program; see the file LICENSE. If not, visit
|
||||
;; <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; This file provides org-roam-bibtex' dependencies and thus should
|
||||
;; normally be required by org-roam-bibtex feature libraries. It
|
||||
;; defines customize groups and provides general utility functions
|
||||
;; that depend on extra features provided through org-roam,
|
||||
;; bibtex-completion and their dependencies.
|
||||
|
||||
;;; Code:
|
||||
|
||||
;; ============================================================================
|
||||
;;; Dependencies
|
||||
;; ============================================================================
|
||||
|
||||
(require 'orb-utils)
|
||||
(require 'orb-compat)
|
||||
|
||||
(eval-when-compile
|
||||
(require 'cl-macs)
|
||||
(require 'subr-x)
|
||||
(require 'rx))
|
||||
|
||||
(declare-function
|
||||
bibtex-completion-get-entry "bibtex-completion" (entry-key))
|
||||
(declare-function
|
||||
bibtex-completion-get-value "bibtex-completion" (field entry &optional default))
|
||||
(declare-function
|
||||
bibtex-completion-find-pdf (key-or-entry &optional find-additional))
|
||||
|
||||
|
||||
;; ============================================================================
|
||||
;;; Customize groups
|
||||
;; ============================================================================
|
||||
;;
|
||||
;; All modules should put their `defgroup' definitions here
|
||||
;; Defcustom definitions should stay in respective files
|
||||
|
||||
(defgroup org-roam-bibtex nil
|
||||
"Org-roam integration with BibTeX software."
|
||||
:group 'org-roam
|
||||
:prefix "orb-")
|
||||
|
||||
(defgroup orb-note-actions nil
|
||||
"Orb Note Actions - run actions in note's context."
|
||||
:group 'org-roam-bibtex
|
||||
:prefix "orb-note-actions-")
|
||||
|
||||
(defgroup orb-pdf-scrapper nil
|
||||
"Orb PDF Scrapper - retrieve references from PDF."
|
||||
:group 'org-roam-bibtex
|
||||
:prefix "orb-pdf-scrapper-")
|
||||
|
||||
(defgroup orb-anystyle nil
|
||||
"Elisp interface to `anystyle-cli`."
|
||||
:group 'org-roam-bibtex
|
||||
:prefix "orb-anystyle-")
|
||||
|
||||
(defgroup orb-autokey nil
|
||||
"Automatic generation of BibTeX citation keys."
|
||||
:group 'org-roam-bibtex
|
||||
:prefix "orb-autokey-")
|
||||
|
||||
|
||||
;; ============================================================================
|
||||
;;; BibTeX fields and their special handling
|
||||
;; ============================================================================
|
||||
|
||||
(defcustom orb-bibtex-field-aliases
|
||||
'(("=type=" . "entry-type")
|
||||
("=key=" . "citekey")
|
||||
("=has-pdf=" . "pdf?")
|
||||
("=has-note=" . "note?")
|
||||
("citation-number" . "#"))
|
||||
"Alist of ORB-specific field aliases of the form (FIELD . ALIAS).
|
||||
The ALIAS can be used instead of the FIELD anywhere in ORB's
|
||||
configuration. This variable is useful to replace
|
||||
`bibtex-completion''s internal '='-embraced virtual fields with
|
||||
more casual alternatives."
|
||||
:group 'org-roam-bibtex
|
||||
:type '(repeat
|
||||
(cons (string :tag "Field name")
|
||||
(string :tag "Alias name"))))
|
||||
|
||||
(defcustom orb-attached-file-extensions '("pdf")
|
||||
"When retrieving an attached file, keep files with only these extensions.
|
||||
This is a list of file extensions without a dot as case-insensitive
|
||||
strings.
|
||||
|
||||
Set it to nil to keep all file names regardless of their extensions.
|
||||
|
||||
BibTeX entries are searched for attached files according to
|
||||
`bibtex-completion-pdf-field' (default `file') and in
|
||||
BibDesk-specific `Bdsk-File-N' fields."
|
||||
:group 'org-roam-bibtex
|
||||
:type '(repeat :tag "List of extensions" (string)))
|
||||
|
||||
(defcustom orb-abbreviate-file-name t
|
||||
"Non-nil to force abbreviation of file names by `orb-get-attached-file'.
|
||||
When this option is set to a non-nil value, the filename returned
|
||||
by `orb-get-attached-file' will get the home directory part
|
||||
abbreviated to `~/'. Symlinked directories will be abbreviated
|
||||
according to `directory-abbrev-alist', see `abbreviate-file-name'
|
||||
for details.
|
||||
|
||||
An as-is value will be used otherwise."
|
||||
:group 'org-roam-bibtex
|
||||
:type '(choice
|
||||
(const :tag "Yes" t)
|
||||
(const :tag "No" nil)))
|
||||
|
||||
(defcustom orb-open-attached-file-as-truename t
|
||||
"Non-nil to open attached files with their true names.
|
||||
When this option is set non-nil, `orb-open-attached-file' will
|
||||
open files using their true names. You may want to set it to nil
|
||||
if using file symlinks and experiencing problems such as
|
||||
discussed here:
|
||||
|
||||
https://github.com/org-roam/org-roam-bibtex/issues/259
|
||||
|
||||
An as-is value will be used otherwise."
|
||||
:group 'org-roam-bibtex
|
||||
:type '(choice
|
||||
(const :tag "Yes" t)
|
||||
(const :tag "No" nil)))
|
||||
|
||||
|
||||
(defcustom orb-use-bibdesk-attachments nil
|
||||
"Whether to look up BibDesk-specific file fields `Bdsk-File'.
|
||||
If this is non-nil, attachments given in BibDesk-specific file
|
||||
fields will be considered in addition to those found through the
|
||||
`bibtex-completion-find-pdf' mechanism when performing a template
|
||||
expansion, opening an attachment with `orb-note-actions' or
|
||||
scraping a PDF with `orb-pdf-scrapper'.
|
||||
|
||||
Duplicates will be resolved, but since duplicate comparison is
|
||||
performed using `file-truename', this will lead to expansion of
|
||||
symlink paths if such are used in the normal BibTeX `file' field,
|
||||
for example. See also `orb-abbreviate-file-name' on how to
|
||||
abbreviate the retrieved filenames.
|
||||
|
||||
Set this to symbol `only' to look up only BibDesk attachments and
|
||||
do not use `bibtex-completion-find-pdf'."
|
||||
:group 'org-roam-bibtex
|
||||
:type '(choice
|
||||
(const :tag "Yes" t)
|
||||
(const :tag "BibDesk only" only)
|
||||
(const :tag "No" nil)))
|
||||
|
||||
(defsubst orb-resolve-field-alias (alias)
|
||||
"Return ALIAS association from `orb-bibtex-field-aliases'.
|
||||
Return ALIAS if association was not found."
|
||||
(or (car (rassoc alias orb-bibtex-field-aliases)) alias))
|
||||
|
||||
(defun orb-get-bibdesk-filenames (entry)
|
||||
"Return filenames stored in BibDesk file fields \"Bdsk-File-N\".
|
||||
ENTRY is a BibTeX entry as returned by `bibtex-completion-get-entry'.
|
||||
|
||||
The variable `orb-attached-file-extensions' is respected."
|
||||
;; NOTE: Mac-specific, hard-coded
|
||||
(let* ((bdsk-file-fields
|
||||
(seq-filter (lambda (cell)
|
||||
(string-match-p "Bdsk-File" (car cell)))
|
||||
entry))
|
||||
(strip-value-rx
|
||||
(rx (seq (opt (in "\"{"))
|
||||
(group (* (not (in "\"{}"))))
|
||||
(opt (in "\"}")))))
|
||||
(filename-rx
|
||||
(concat
|
||||
(rx (seq "Users/" (* anychar)))
|
||||
(if orb-attached-file-extensions
|
||||
(regexp-opt orb-attached-file-extensions t)
|
||||
"pdf")))
|
||||
(bdsk-files
|
||||
(mapcar
|
||||
(lambda (cell)
|
||||
(let ((val (cdr cell))
|
||||
file)
|
||||
(when (string-match strip-value-rx val)
|
||||
(setq file (base64-decode-string (match-string 1 val)))
|
||||
(when (string-match filename-rx file)
|
||||
(concat "/" (match-string 0 file))))))
|
||||
bdsk-file-fields)))
|
||||
(seq-filter (lambda (val) val) bdsk-files)))
|
||||
|
||||
;;;###autoload
|
||||
(defun orb-get-attached-file (citekey)
|
||||
"Look up files associated with a BibTeX entry identified by CITEKEY.
|
||||
Files are searched for using `bibtex-completion-find-pdf',
|
||||
meaning that Mendeley, Zotero and plain file paths are all
|
||||
supported, and variables `bibtex-completion-pdf-field' and
|
||||
`bibtex-completion-library-path' are respected. Additionally,
|
||||
the BibTeX entry is searched for BibDesk-specific file fields
|
||||
`Bdsk-File-N'.
|
||||
|
||||
If `orb-attached-file-extensions' is non-nil, return only file paths
|
||||
matching the respective extensions.
|
||||
|
||||
If `orb-abbreviate-file-name' is non-nil, force an abbreviated
|
||||
file name.
|
||||
|
||||
Depending on the value of `orb-use-bibdesk-attachments', the
|
||||
BibDesk-specific file fields `Bdsk-File-N' may or may not be used
|
||||
for the lookup.
|
||||
|
||||
If multiple files have been found, the user will be prompted to
|
||||
select one."
|
||||
(condition-case err
|
||||
(when-let* ((entry (bibtex-completion-get-entry citekey))
|
||||
(paths
|
||||
(--> (pcase orb-use-bibdesk-attachments
|
||||
(`nil (bibtex-completion-find-pdf
|
||||
entry bibtex-completion-find-additional-pdfs))
|
||||
(`only (orb-get-bibdesk-filenames entry))
|
||||
(_
|
||||
(-->
|
||||
(nconc (bibtex-completion-find-pdf entry)
|
||||
(orb-get-bibdesk-filenames entry))
|
||||
(-map #'file-truename it)
|
||||
(-uniq it))))
|
||||
(if (not orb-attached-file-extensions)
|
||||
it ; do not filter by extensions
|
||||
;; filter by extensions
|
||||
(--filter
|
||||
(when-let ((ext (file-name-extension it)))
|
||||
(member-ignore-case ext orb-attached-file-extensions))
|
||||
it))))
|
||||
(path (if (cdr paths)
|
||||
(completing-read "File to use: " paths)
|
||||
(car paths))))
|
||||
(if orb-abbreviate-file-name
|
||||
(abbreviate-file-name path)
|
||||
path))
|
||||
;; ignore any errors that may be thrown by `bibtex-completion-find-pdf'
|
||||
;; don't stop the capture process
|
||||
(error
|
||||
(orb-warning
|
||||
(format "error in `orb-get-attached-file`: %s %s"
|
||||
(car err) (cdr err))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun orb-open-attached-file (citekey)
|
||||
"Open a file associated with CITEKEY.
|
||||
CITEKEY must be a list for compatibility with `bibtex-completion'
|
||||
functions, which also expect a list.
|
||||
|
||||
This is a modified and simplified version of `bibtex-completion-open-pdf',
|
||||
which uses `orb-get-bibdesk-filenames' under the hood and is therefore
|
||||
compatible with BibDesk. The file is opened with the function set in
|
||||
`bibtex-completion-pdf-open-function'.
|
||||
|
||||
The intended primary use is with `orb-note-actions'."
|
||||
(let* ((key (car citekey))
|
||||
(attachment (orb-get-attached-file key)))
|
||||
(if attachment
|
||||
(funcall bibtex-completion-pdf-open-function
|
||||
(if orb-open-attached-file-as-truename
|
||||
(file-truename attachment)
|
||||
attachment))
|
||||
(message "No PDF(s) found for this entry: %s" key))))
|
||||
|
||||
;; ============================================================================
|
||||
;;;; Orb autokey
|
||||
;; ============================================================================
|
||||
|
||||
(defcustom orb-autokey-format "%a%y%T[4][1]"
|
||||
"Format string for automatically generated citation keys.
|
||||
|
||||
Supported wildcards:
|
||||
|
||||
Basic
|
||||
==========
|
||||
|
||||
%a |author| - first author's (or editor's) last name
|
||||
%t |title | - first word of title
|
||||
%f{field} |field | - first word of arbitrary field
|
||||
%y |year | - year YYYY
|
||||
%p |page | - first page
|
||||
%e{(expr)} |elisp | - execute elisp expression
|
||||
|
||||
Extended
|
||||
==========
|
||||
|
||||
1. Capitalized versions:
|
||||
|
||||
%A |author| >
|
||||
%T |title | > Same as %a,%t,%f{field} but
|
||||
%F{field} |field | > preserve original capitalization
|
||||
|
||||
2. Starred versions
|
||||
|
||||
%a*, %A* |author| - include author's (editor's) initials
|
||||
%t*, %T* |title | - do not ignore words in `orb-autokey-titlewords-ignore'
|
||||
%y* |year | - year's last two digits __YY
|
||||
%p* |page | - use \"pagetotal\" field instead of default \"pages\"
|
||||
|
||||
3. Optional parameters
|
||||
|
||||
%a[N][M][D] |author| >
|
||||
%t[N][M][D] |title | > include first N words/names
|
||||
%f{field}[N][M][D] |field | > include at most M first characters of word/name
|
||||
%p[D] |page | > put delimiter D between words
|
||||
|
||||
N and M should be a single digit 1-9. Putting more digits or any
|
||||
other symbols will lead to ignoring the optional parameter and
|
||||
those following it altogether. D should be a single alphanumeric
|
||||
symbol or one of `-_.:|'.
|
||||
|
||||
Optional parameters work both with capitalized and starred
|
||||
versions where applicable.
|
||||
|
||||
4. Elisp expression
|
||||
|
||||
- can be anything
|
||||
- should return a string or nil
|
||||
- will be evaluated before expanding other wildcards and therefore
|
||||
can insert other wildcards
|
||||
- will have `entry' variable bound to the value of BibTeX entry the key
|
||||
is being generated for, as returned by `bibtex-completion-get-entry'.
|
||||
The variable may be safely manipulated in a destructive manner.
|
||||
|
||||
%e{(or (bibtex-completion-get-value \"volume\" entry) \"N/A\")}
|
||||
%e{(my-function entry)}
|
||||
|
||||
Key generation is performed by `orb-autokey-generate-key'."
|
||||
:risky t
|
||||
:type 'string
|
||||
:group 'org-roam-bibtex)
|
||||
|
||||
(defcustom orb-autokey-titlewords-ignore
|
||||
'("A" "An" "On" "The" "Eine?" "Der" "Die" "Das"
|
||||
"[^[:upper:]].*" ".*[^[:upper:][:lower:]0-9].*")
|
||||
"Patterns from title that will be ignored during key generation.
|
||||
Every element is a regular expression to match parts of the title
|
||||
that should be ignored during automatic key generation. Case
|
||||
sensitive."
|
||||
;; Default value was take from `bibtex-autokey-titleword-ignore'.
|
||||
:type '(repeat :tag "Regular expression" regexp)
|
||||
:group 'orb-autokey)
|
||||
|
||||
(defcustom orb-autokey-empty-field-token "N/A"
|
||||
"String to use when BibTeX field is nil or empty."
|
||||
:type 'string
|
||||
:group 'orb-autokey)
|
||||
|
||||
(defcustom orb-autokey-invalid-symbols
|
||||
" \"'()={},~#%\\"
|
||||
"Characters not allowed in a BibTeX key.
|
||||
The key will be stripped of these characters."
|
||||
:type 'string
|
||||
:group 'orb-autokey)
|
||||
|
||||
(defun orb--autokey-format-field (field &rest specs)
|
||||
"Return BibTeX FIELD formatted according to plist SPECS.
|
||||
|
||||
Recognized keys:
|
||||
==========
|
||||
:entry - BibTeX entry to use
|
||||
:value - Value of BibTeX field to use
|
||||
instead retrieving it from :entry
|
||||
:capital - capitalized version
|
||||
:starred - starred version
|
||||
:words - first optional parameter (number of words)
|
||||
:characters - second optional parameter (number of characters)
|
||||
:delimiter - third optional parameter (delimiter)
|
||||
|
||||
All values should be strings, including those representing numbers.
|
||||
|
||||
This function is used internally by `orb-autokey-generate-key'."
|
||||
(declare (indent 1))
|
||||
(-let* (((&plist :entry entry
|
||||
:value value
|
||||
:capital capital
|
||||
:starred starred
|
||||
:words words
|
||||
:characters chars
|
||||
:delimiter delim) specs)
|
||||
;; field values will be split into a list of words. `separator' is a
|
||||
;; regexp for word separators: either a whitespace, one or more
|
||||
;; dashes, or en dash, or em dash
|
||||
(separator "\\([ \n\t]\\|[-]+\\|[—–]\\)")
|
||||
(invalid-chars-rx
|
||||
(rx-to-string `(any ,orb-autokey-invalid-symbols) t))
|
||||
(delim (or delim ""))
|
||||
result)
|
||||
;; 0. virtual field "=name=" is used internally here and in
|
||||
;; `orb-autokey-generate-key'; it stands for author or editor
|
||||
(if (string= field "=name=")
|
||||
;; in name fields, logical words are full names consisting of several
|
||||
;; words and containing spaces and punctuation, separated by a logical
|
||||
;; separator, the word "and"
|
||||
(setq separator " and "
|
||||
value (or value
|
||||
(bibtex-completion-get-value "author" entry)
|
||||
(bibtex-completion-get-value "editor" entry)))
|
||||
;; otherwise proceed with value or get it from entry
|
||||
(setq value (or value
|
||||
(bibtex-completion-get-value field entry))))
|
||||
(if (or (not value)
|
||||
(string-empty-p value))
|
||||
(setq result orb-autokey-empty-field-token)
|
||||
(when (> (length value) 0)
|
||||
(save-match-data
|
||||
;; 1. split field into words
|
||||
(setq result (split-string value separator t "[ ,.;:-]+"))
|
||||
;; 1a) only for title;
|
||||
;; STARRED = include words from `orb-autokey-titlewords-ignore
|
||||
;; unstarred version filters the keywords, starred ignores this block
|
||||
(when (and (string= field "title")
|
||||
(not starred))
|
||||
(let ((ignore-rx (concat "\\`\\(:?"
|
||||
(mapconcat #'identity
|
||||
orb-autokey-titlewords-ignore
|
||||
"\\|") "\\)\\'"))
|
||||
(words ()))
|
||||
(setq result (dolist (word result (nreverse words))
|
||||
(unless (string-match-p ignore-rx word)
|
||||
(push word words))))))
|
||||
;; 2. take number of words equal to WORDS if that is set
|
||||
;; or just the first word; also 0 = 1.
|
||||
(if words
|
||||
(setq words (string-to-number words)
|
||||
result (-take (if (> words (length result))
|
||||
(length result)
|
||||
words)
|
||||
result))
|
||||
(setq result (list (car result))))
|
||||
;; 2a) only for "=name=" field, i.e. author or editor
|
||||
;; STARRED = include initials
|
||||
(when (string= field "=name=")
|
||||
;; NOTE: here we expect name field 'Doe, J. B.'
|
||||
;; should ideally be able to handle 'Doe, John M. Longname, Jr'
|
||||
(let ((r-x (if starred
|
||||
"[ ,.\t\n]"
|
||||
"\\`\\(.*?\\),.*\\'"))
|
||||
(rep (if starred "" "\\1"))
|
||||
(words ()))
|
||||
(setq result
|
||||
(dolist (name result (nreverse words))
|
||||
(push (s-replace-regexp r-x rep name) words)))))
|
||||
;; 3. take at most CHARS number of characters from every word
|
||||
(when chars
|
||||
(let ((words ()))
|
||||
(setq chars (string-to-number chars)
|
||||
result (dolist (word result (nreverse words))
|
||||
(push
|
||||
(substring word 0
|
||||
(if (< chars (length word))
|
||||
chars
|
||||
(length word)))
|
||||
words)))))
|
||||
;; 4. almost there: concatenate words, include DELIMiter
|
||||
(setq result (mapconcat #'identity result delim))
|
||||
;; 5. CAPITAL = preserve case
|
||||
(unless capital
|
||||
(setq result (downcase result))))))
|
||||
;; return result stripped of the invalid characters
|
||||
(s-replace-regexp invalid-chars-rx "" result t)))
|
||||
|
||||
(defun orb--autokey-evaluate-expression (expr &optional entry)
|
||||
"Evaluate arbitrary elisp EXPR passed as readable string.
|
||||
The expression will have value of ENTRY bound to `entry' variable
|
||||
at its disposal. ENTRY should be a BibTeX entry as returned by
|
||||
`bibtex-completion-get-entry'. The result returned should be a
|
||||
string or nil."
|
||||
(let ((result (eval `(let ((entry (quote ,(copy-tree entry))))
|
||||
,(read expr)))))
|
||||
(unless (or (stringp result)
|
||||
(not result))
|
||||
(user-error "Result: %s, invalid type. \
|
||||
Expression must be string or nil" result))
|
||||
(or result "")))
|
||||
|
||||
;;;###autoload
|
||||
(defun orb-autokey-generate-key (entry &optional control-string)
|
||||
"Generate citation key from ENTRY according to `orb-autokey-format'.
|
||||
Return a string. If optional CONTROL-STRING is non-nil, use it
|
||||
instead of `orb-autokey-format'."
|
||||
(let* ((case-fold-search nil)
|
||||
(str (or control-string orb-autokey-format))
|
||||
;; star regexp: group 3!
|
||||
(star '(opt (group-n 3 "*")))
|
||||
;; optional parameters: regexp groups 4-6!
|
||||
(opt1 '(opt (and "[" (opt (group-n 4 digit)) "]")))
|
||||
(opt2 '(opt (and "[" (opt (group-n 5 digit)) "]")))
|
||||
(opt3 '(opt (and "[" (opt (group-n 6 (any alnum "_.:|-"))) "]")))
|
||||
;; capital letters: regexp group 2!
|
||||
;; author wildcard regexp
|
||||
(a-rx (macroexpand
|
||||
`(rx (group-n 1 (or "%a" (group-n 2 "%A"))
|
||||
,star ,opt1 ,opt2 ,opt3))))
|
||||
;; title wildcard regexp
|
||||
(t-rx (macroexpand
|
||||
`(rx (group-n 1 (or "%t" (group-n 2 "%T"))
|
||||
,star ,opt1 ,opt2 ,opt3))))
|
||||
;; any field wildcard regexp
|
||||
;; required parameter: group 7!
|
||||
(f-rx (macroexpand
|
||||
`(rx (group-n 1 (or "%f" (group-n 2 "%F"))
|
||||
(and "{" (group-n 7 (1+ letter)) "}")
|
||||
,opt1 ,opt2 ,opt3))))
|
||||
;; year wildcard regexp
|
||||
(y-rx (rx (group-n 1 "%y" (opt (group-n 3 "*")))))
|
||||
;; page wildcard regexp
|
||||
(p-rx (macroexpand `(rx (group-n 1 "%p" ,star ,opt3))))
|
||||
;; elisp expression wildcard regexp
|
||||
;; elisp sexp: group 8!
|
||||
(e-rx (rx (group-n 1 "%e"
|
||||
"{" (group-n 8 "(" (1+ ascii) ")") "}"))))
|
||||
;; Evaluating elisp expression should go the first because it can produce
|
||||
;; additional wildcards
|
||||
(while (string-match e-rx str)
|
||||
(setq str (replace-match
|
||||
(save-match-data
|
||||
(orb--autokey-evaluate-expression
|
||||
(match-string 8 str) entry)) t nil str 1)))
|
||||
;; Expanding all other wildcards are actually
|
||||
;; variations of calls to `orb--autokey-format-field' with many
|
||||
;; commonalities, so we wrap it into a macro
|
||||
(cl-macrolet
|
||||
((expand
|
||||
(wildcard &key field value entry capital
|
||||
starred words characters delimiter)
|
||||
(let ((cap (or capital '(match-string 2 str)))
|
||||
(star (or starred '(match-string 3 str)))
|
||||
(opt1 (or words '(match-string 4 str)))
|
||||
(opt2 (or characters '(match-string 5 str)))
|
||||
(opt3 (or delimiter '(match-string 6 str))))
|
||||
`(while (string-match ,wildcard str)
|
||||
(setq str (replace-match
|
||||
;; we can safely pass nil values
|
||||
;; `orb--autokey-format-field' should
|
||||
;; handle them correctly
|
||||
(orb--autokey-format-field ,field
|
||||
:entry ,entry :value ,value
|
||||
:capital ,cap :starred ,star
|
||||
:words ,opt1 :characters ,opt2 :delimiter ,opt3)
|
||||
t nil str 1))))))
|
||||
;; Handle author wildcards
|
||||
(expand a-rx
|
||||
:field "=name="
|
||||
:value (or (bibtex-completion-get-value "author" entry)
|
||||
(bibtex-completion-get-value "editor" entry)))
|
||||
;; Handle title wildcards
|
||||
(expand t-rx
|
||||
:field "title"
|
||||
:value (or (bibtex-completion-get-value "title" entry) ""))
|
||||
;; Handle custom field wildcards
|
||||
(expand f-rx
|
||||
:field (match-string 7 str)
|
||||
:entry entry)
|
||||
;; Handle pages wildcards %p*[-]
|
||||
(expand p-rx
|
||||
:field (if (match-string 3 str)
|
||||
"pagetotal" "pages")
|
||||
:entry entry
|
||||
:words "1"))
|
||||
;; Handle year wildcards
|
||||
;; it's simple, so we do not use `orb--autokey-format-field' here
|
||||
;; year should be well-formed: YYYY
|
||||
;; TODO: put year into cl-macrolet
|
||||
(let ((year (or (bibtex-completion-get-value "year" entry)
|
||||
(bibtex-completion-get-value "date" entry))))
|
||||
(if (or (not year)
|
||||
(string-empty-p year)
|
||||
(string= year orb-autokey-empty-field-token))
|
||||
(while (string-match y-rx str)
|
||||
(setq str (replace-match orb-autokey-empty-field-token
|
||||
t nil str 1)))
|
||||
(while (string-match y-rx str)
|
||||
(setq year (format "%04d" (string-to-number year))
|
||||
str (replace-match
|
||||
(format "%s" (if (match-string 3 str)
|
||||
(substring year 2 4)
|
||||
(substring year 0 4)))
|
||||
t nil str 1)))))
|
||||
str))
|
||||
|
||||
(provide 'orb-core)
|
||||
;;; orb-core.el ends here
|
||||
;; Local Variables:
|
||||
;; coding: utf-8
|
||||
;; fill-column: 79
|
||||
;; End:
|
||||
98
lisp/org-roam-bibtex/orb-helm.el
Normal file
98
lisp/org-roam-bibtex/orb-helm.el
Normal file
@@ -0,0 +1,98 @@
|
||||
;;; orb-helm.el --- ORB support form Helm -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright © 2020-2022 Mykhailo Shevchuk
|
||||
|
||||
;; Author: Mykhailo Shevchuk <mail@mshevchuk.com>
|
||||
;; URL: https://github.com/org-roam/org-roam-bibtex
|
||||
|
||||
;; Soft dependencies: projectile, persp-mode, helm, ivy, hydra
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 3, or (at your option)
|
||||
;; any later version.
|
||||
;;
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU General Public License along with
|
||||
;; this program; see the file LICENSE. If not, visit
|
||||
;; <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;;; Code:
|
||||
|
||||
;; ============================================================================
|
||||
;;;; Dependencies
|
||||
;; ============================================================================
|
||||
|
||||
(require 'orb-utils)
|
||||
|
||||
(require 'helm-bibtex)
|
||||
(require 'helm-source)
|
||||
|
||||
(declare-function orb-insert-edit-note "org-roam-bibtex" (citekey))
|
||||
|
||||
(defvar orb-note-actions-default)
|
||||
(defvar orb-note-actions-extra)
|
||||
(defvar orb-note-actions-user)
|
||||
|
||||
;; ============================================================================
|
||||
;;;; Note actions
|
||||
;; ============================================================================
|
||||
|
||||
(orb-note-actions-defun helm
|
||||
(helm :sources
|
||||
`(((name . ,name)
|
||||
(candidates . ,candidates)
|
||||
(action . (lambda (f)
|
||||
(funcall f (list ,citekey))))))))
|
||||
|
||||
;; ============================================================================
|
||||
;;;; Orb insert
|
||||
;; ============================================================================
|
||||
|
||||
(defvar helm-source-orb-insert
|
||||
(helm-build-sync-source "BibTeX entries"
|
||||
:header-name (lambda (name)
|
||||
(format "%s: " name))
|
||||
:candidates 'helm-bibtex-candidates
|
||||
:filtered-candidate-transformer 'helm-bibtex-candidates-formatter
|
||||
:action (helm-make-actions
|
||||
"Edit note & insert a link" 'helm-orb-insert-edit-note
|
||||
"Open PDF, URL or DOI" 'helm-bibtex-open-any
|
||||
"Open URL or DOI in browser" 'helm-bibtex-open-url-or-doi
|
||||
"Insert citation" 'helm-bibtex-insert-citation
|
||||
"Insert reference" 'helm-bibtex-insert-reference
|
||||
"Insert BibTeX key" 'helm-bibtex-insert-key
|
||||
"Insert BibTeX entry" 'helm-bibtex-insert-bibtex
|
||||
"Attach PDF to email" 'helm-bibtex-add-PDF-attachment
|
||||
"Show entry" 'helm-bibtex-show-entry
|
||||
"Add PDF to library" 'helm-bibtex-add-pdf-to-library))
|
||||
"Helm source to use with `orb-insert'.
|
||||
A copy of `helm-source-bibtex', in which \"Edit notes\" is made
|
||||
the first (default) action. This action calls `helm-orb-insert-edit-note'.
|
||||
Only relevant when `orb-insert-interface' is `helm-bibtex'.")
|
||||
|
||||
(helm-bibtex-helmify-action orb-insert-edit-note helm-orb-insert-edit-note)
|
||||
|
||||
(defun orb-helm-insert (&optional clear-cache)
|
||||
"Run `helm-bibtex'.
|
||||
If optional CLEAR-CACHE is non-nil, re-create `bibtex-completion-cache'.
|
||||
|
||||
This is a simple wrapper to be run from `orb-insert'."
|
||||
(let ((helm-source-bibtex helm-source-orb-insert))
|
||||
(helm-bibtex clear-cache)))
|
||||
|
||||
(provide 'orb-helm)
|
||||
|
||||
;;; orb-helm.el ends here
|
||||
;; Local Variables:
|
||||
;; coding: utf-8
|
||||
;; fill-column: 79
|
||||
;; End:
|
||||
97
lisp/org-roam-bibtex/orb-ivy.el
Normal file
97
lisp/org-roam-bibtex/orb-ivy.el
Normal file
@@ -0,0 +1,97 @@
|
||||
;;; orb-ivy.el --- ORB support for Ivy -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright © 2020-2022 Mykhailo Shevchuk
|
||||
|
||||
;; Author: Mykhailo Shevchuk <mail@mshevchuk.com>
|
||||
;; URL: https://github.com/org-roam/org-roam-bibtex
|
||||
|
||||
;; Soft dependencies: projectile, persp-mode, helm, ivy, hydra
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 3, or (at your option)
|
||||
;; any later version.
|
||||
;;
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU General Public License along with
|
||||
;; this program; see the file LICENSE. If not, visit
|
||||
;; <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;;; Code:
|
||||
|
||||
;; ============================================================================
|
||||
;;;; Dependencies
|
||||
;; ============================================================================
|
||||
|
||||
(require 'orb-utils)
|
||||
|
||||
(require 'ivy-bibtex)
|
||||
|
||||
(declare-function orb-insert-edit-note "org-roam-bibtex" (citekey))
|
||||
|
||||
(defvar orb-note-actions-default)
|
||||
(defvar orb-note-actions-extra)
|
||||
(defvar orb-note-actions-user)
|
||||
|
||||
;; ============================================================================
|
||||
;;;; Note actions
|
||||
;; ============================================================================
|
||||
|
||||
(orb-note-actions-defun ivy
|
||||
(ivy-read name
|
||||
candidates
|
||||
:require-match t
|
||||
:caller 'orb-note-actions-ivy
|
||||
:action (lambda (c)
|
||||
(funcall (cdr c) (list citekey)))))
|
||||
|
||||
;; ============================================================================
|
||||
;;;; Orb insert
|
||||
;; ============================================================================
|
||||
|
||||
(defvar orb-insert--ivy-actions
|
||||
'(("e" ivy-orb-insert-edit-note "Edit note & insert a link")
|
||||
("p" ivy-bibtex-open-pdf "Open PDF file (if present)")
|
||||
("u" ivy-bibtex-open-url-or-doi "Open URL or DOI in browser")
|
||||
("c" ivy-bibtex-insert-citation "Insert citation")
|
||||
("r" ivy-bibtex-insert-reference "Insert reference")
|
||||
("k" ivy-bibtex-insert-key "Insert BibTeX key")
|
||||
("b" ivy-bibtex-insert-bibtex "Insert BibTeX entry")
|
||||
("a" ivy-bibtex-add-PDF-attachment "Attach PDF to email")
|
||||
("s" ivy-bibtex-show-entry "Show entry")
|
||||
("l" ivy-bibtex-add-pdf-to-library "Add PDF to library")
|
||||
("f" (lambda (_candidate) (ivy-bibtex-fallback ivy-text)) "Fallback options"))
|
||||
"Ivy actions to use with `orb-insert'.
|
||||
A copy of Ivy-bibtex's alist defining Ivy actions, in which
|
||||
\"Edit note & insert a link\" is made first (default) action.
|
||||
This action calls `orb-insert-edit-note'. Only relevant when
|
||||
`orb-insert-interface' is `ivy-bibtex'.")
|
||||
|
||||
(ivy-bibtex-ivify-action orb-insert-edit-note ivy-orb-insert-edit-note)
|
||||
|
||||
(defun orb-ivy-insert (&optional clear-cache)
|
||||
"Run `ivy-bibtex'.
|
||||
If optional CLEAR-CACHE is non-nil, re-create `bibtex-completion-cache'.
|
||||
|
||||
This is a simple wrapper to be run from `orb-insert'."
|
||||
(let* ((ivy-actions (copy-tree ivy--actions-list))
|
||||
(ivy--actions-list
|
||||
(plist-put ivy-actions 'ivy-bibtex orb-insert--ivy-actions))
|
||||
(ivy-bibtex-default-action 'ivy-orb-insert-edit-note))
|
||||
(ivy-bibtex clear-cache)))
|
||||
|
||||
(provide 'orb-ivy)
|
||||
|
||||
;;; orb-ivy.el ends here
|
||||
;; Local Variables:
|
||||
;; coding: utf-8
|
||||
;; fill-column: 79
|
||||
;; End:
|
||||
1793
lisp/org-roam-bibtex/orb-pdf-scrapper.el
Normal file
1793
lisp/org-roam-bibtex/orb-pdf-scrapper.el
Normal file
File diff suppressed because it is too large
Load Diff
12
lisp/org-roam-bibtex/orb-pkg.el
Normal file
12
lisp/org-roam-bibtex/orb-pkg.el
Normal file
@@ -0,0 +1,12 @@
|
||||
(define-package "orb" "0.6.2"
|
||||
"Org Roam meets BibTeX"
|
||||
'((emacs "27.1")
|
||||
(org-roam "2.2.0")
|
||||
(bibtex-completion "2.0.0"))
|
||||
:homepage "https://github.com/org-roam/org-roam-bibtex"
|
||||
:keywords '("bib" "hypermedia" "outlines" "wp"))
|
||||
|
||||
;; Local Variables:
|
||||
;; flycheck-disabled-checkers: (emacs-list-checkdoc)
|
||||
;; package-lint-main-file: nil
|
||||
;; End:
|
||||
173
lisp/org-roam-bibtex/orb-section.el
Normal file
173
lisp/org-roam-bibtex/orb-section.el
Normal file
@@ -0,0 +1,173 @@
|
||||
;;; orb-section.el --- Org Roam BibTeX: Sections for org-roam-mode -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright © 2022 Samuel W. Flint
|
||||
|
||||
;; Author: Samuel W. Flint <swflint@flintfam.org>
|
||||
|
||||
;; URL: https://github.com/org-roam/org-roam-bibtex
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 3, or (at your option)
|
||||
;; any later version.
|
||||
;;
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU General Public License along with
|
||||
;; this program; see the file LICENSE. If not, visit
|
||||
;; <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; This file provides org-roam-bibtex' dependencies and thus should
|
||||
;; normally be required by org-roam-bibtex feature libraries. It
|
||||
;; defines customize groups and provides general utility functions
|
||||
;; that depend on extra features provided through org-roam,
|
||||
;; bibtex-completion and their dependencies.
|
||||
|
||||
;;; Code:
|
||||
|
||||
;; ============================================================================
|
||||
;;; Dependencies
|
||||
;; ============================================================================
|
||||
|
||||
(require 'org-roam-node)
|
||||
(require 'org-roam-utils)
|
||||
(require 's)
|
||||
(require 'magit-section)
|
||||
(require 'bibtex-completion)
|
||||
|
||||
(require 'orb-utils)
|
||||
(defvar orb-abbreviate-file-name)
|
||||
|
||||
;; ============================================================================
|
||||
;;; Configuration Variables
|
||||
;; ============================================================================
|
||||
|
||||
(defgroup orb-section nil
|
||||
"Org-roam buffer sections for BibTeX."
|
||||
:group 'org-roam-bibtex
|
||||
:prefix "orb-section-")
|
||||
|
||||
(defcustom orb-section-reference-format-method
|
||||
'bibtex-completion-apa-format-reference
|
||||
"How to format the ORB citation.
|
||||
Either a function taking a bibtex key and returning a string, or
|
||||
an alist from type to format string. For formatting information,
|
||||
see `bibtex-completion-display-formats'."
|
||||
:type '(choice (const :tag "Use BibTeX-Completion APA Format"
|
||||
'bibtex-completion-apa-format-reference)
|
||||
(symbol :tag "Use a function")
|
||||
(alist :key-type (choice (string :tag "Type Name :")
|
||||
(const :tag "Default" t))
|
||||
:value-type (string :tag "Format String:"))))
|
||||
|
||||
(defcustom orb-section-abstract-format-method :org-format
|
||||
"How to format ORB abstract.
|
||||
A function taking a key and returning a string, or one of:
|
||||
|
||||
- `:org-format' Assume that the content is org-formatted, and
|
||||
format accordingly.
|
||||
- `:pandoc-from-tex' Assume that the content is tex/latex
|
||||
formatted and use `pandoc' to format accordingly."
|
||||
:type '(choice (const :tag "Format as Org Text" :org-format)
|
||||
(const :tag "Format from LaTeX" :pandoc-from-tex)
|
||||
(symbol :tag "Use function.")))
|
||||
|
||||
|
||||
;; ============================================================================
|
||||
;;; Utility functions
|
||||
;; ============================================================================
|
||||
|
||||
(defun orb-section-reference-format (key)
|
||||
"Format reference for KEY according to `orb-section-reference-format-method'."
|
||||
(if (functionp orb-section-reference-format-method)
|
||||
(funcall orb-section-reference-format-method key)
|
||||
(when-let ((entry (bibtex-completion-get-entry key))
|
||||
(format-string (cdr (or (assoc-string (bibtex-completion-get-value "=type=" entry) orb-section-reference-format-method)
|
||||
(assoc t orb-section-reference-format-method))))
|
||||
(formatted-reference (s-format format-string 'bibtex-completion-apa-get-value entry)))
|
||||
(replace-regexp-in-string "\\([.?!]\\)\\." "\\1" formatted-reference))))
|
||||
|
||||
(defun orb-section-unfill-region (beg end)
|
||||
"Unfill the region from BEG to END.
|
||||
Joining text paragraphs into a single logical line.
|
||||
|
||||
Taken from https://www.emacswiki.org/emacs/UnfillRegion"
|
||||
(interactive "*r")
|
||||
(let ((fill-column (point-max)))
|
||||
(fill-region beg end)))
|
||||
|
||||
(defun orb-section-abstract-format (key)
|
||||
"Format abstract for KEY per `orb-section-abstract-format-method'."
|
||||
(if (functionp orb-section-abstract-format-method)
|
||||
(funcall orb-section-abstract-format-method key)
|
||||
(when-let ((entry (bibtex-completion-get-entry key))
|
||||
(abstract (bibtex-completion-get-value "abstract" entry)))
|
||||
(pcase orb-section-abstract-format-method
|
||||
(:org-format
|
||||
(org-roam-fontify-like-in-org-mode
|
||||
(with-temp-buffer
|
||||
(insert abstract)
|
||||
(org-mode)
|
||||
(orb-section-unfill-region (point-min) (point-max))
|
||||
(save-match-data "\n\n" "\n" (string-trim (buffer-string))))))
|
||||
(:pandoc-from-tex
|
||||
(org-roam-fontify-like-in-org-mode
|
||||
(with-temp-buffer
|
||||
(insert abstract)
|
||||
(shell-command-on-region (point-min) (point-max)
|
||||
"pandoc -f latex -t org" (current-buffer) t)
|
||||
(org-mode)
|
||||
(orb-section-unfill-region (point-min) (point-max))
|
||||
(save-match-data "\n\n" "\n" (string-trim (buffer-string))))))))))
|
||||
|
||||
|
||||
;; ============================================================================
|
||||
;;; Section Implementation
|
||||
;; ============================================================================
|
||||
|
||||
;;;###autoload
|
||||
(defun orb-section-reference (node)
|
||||
"Show BibTeX reference for NODE if it exists."
|
||||
(when-let ((cite-key (orb-get-node-citekey node))
|
||||
(formatted-reference (orb-section-reference-format cite-key)))
|
||||
(magit-insert-section (orb-section-reference)
|
||||
(magit-insert-heading "Reference:")
|
||||
(insert formatted-reference)
|
||||
(insert "\n\n"))))
|
||||
|
||||
;;;###autoload
|
||||
(defun orb-section-abstract (node)
|
||||
"Show BibTeX entry abstract for NODE if it exists."
|
||||
(when-let ((cite-key (orb-get-node-citekey node))
|
||||
(formatted-abstract (orb-section-abstract-format cite-key)))
|
||||
(magit-insert-section (orb-section-abstract)
|
||||
(magit-insert-heading "Abstract:")
|
||||
(insert formatted-abstract)
|
||||
(insert "\n\n"))))
|
||||
|
||||
;;;###autoload
|
||||
(defun orb-section-file (node)
|
||||
"Show a link to entry file for NODE if it exists."
|
||||
(when-let ((cite-key (orb-get-node-citekey node))
|
||||
(file-name (let ((orb-abbreviate-file-name nil))
|
||||
(orb-get-attached-file cite-key))))
|
||||
(magit-insert-section (orb-section-file)
|
||||
(magit-insert-heading "File:")
|
||||
(insert-text-button (file-name-nondirectory file-name)
|
||||
'action (lambda (_button) (orb-open-attached-file cite-key)))
|
||||
(insert "\n\n"))))
|
||||
|
||||
(provide 'orb-section)
|
||||
;;; orb-section.el ends here
|
||||
;;
|
||||
;; Local Variables:
|
||||
;; coding: utf-8
|
||||
;; fill-column: 79
|
||||
;; End:
|
||||
382
lisp/org-roam-bibtex/orb-utils.el
Normal file
382
lisp/org-roam-bibtex/orb-utils.el
Normal file
@@ -0,0 +1,382 @@
|
||||
;;; orb-utils.el --- Org Roam BibTeX: utility macros and functions -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright © 2020-2022 Mykhailo Shevchuk
|
||||
;; Copyright © 2020 Leo Vivier
|
||||
|
||||
;; Author: Mykhailo Shevchuk <mail@mshevchuk.com>
|
||||
;; Leo Vivier <leo.vivier+dev@gmail.com>
|
||||
;; URL: https://github.com/org-roam/org-roam-bibtex
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 3, or (at your option)
|
||||
;; any later version.
|
||||
;;
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU General Public License along with
|
||||
;; this program; see the file LICENSE. If not, visit
|
||||
;; <https://www.gnu.org/licenses/>.
|
||||
|
||||
;; N.B. This file contains code snippets adopted from other
|
||||
;; open-source projects. These snippets are explicitly marked as such
|
||||
;; in place. They are not subject to the above copyright and
|
||||
;; authorship claims.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; This file contains utility macros and helper functions used accross
|
||||
;; different org-mode-bibtex modules. This library may be required
|
||||
;; directly or through orb-core.el. Definitions in this file should
|
||||
;; only depend on built-in Emacs libraries.
|
||||
|
||||
;;; Code:
|
||||
|
||||
;; ============================================================================
|
||||
;;;; Dependencies
|
||||
;; ============================================================================
|
||||
;;
|
||||
;; org-roam requires org,org-element, dash, f, s, emacsql, emacsql-sqlite,
|
||||
;; so all these libraries are always at our disposal
|
||||
|
||||
(require 'org-roam)
|
||||
(require 'bibtex-completion)
|
||||
|
||||
(require 'warnings)
|
||||
|
||||
(eval-when-compile
|
||||
(require 'subr-x))
|
||||
|
||||
(defvar org-ref-cite-types)
|
||||
|
||||
;; Adopted from `org-roam-version'
|
||||
(defun orb-version (&optional message)
|
||||
"Return `orb-roam' version.
|
||||
Interactively, or when MESSAGE is non-nil, show in the echo area."
|
||||
(interactive)
|
||||
(let* ((toplib (or load-file-name buffer-file-name))
|
||||
gitdir topdir version)
|
||||
(unless (and toplib (equal (file-name-nondirectory toplib) "orb-utils.el"))
|
||||
(setq toplib (locate-library "orb-utils.el")))
|
||||
(setq toplib (and toplib (org-roam--straight-chase-links toplib)))
|
||||
(when toplib
|
||||
(setq topdir (file-name-directory toplib)
|
||||
gitdir (expand-file-name ".git" topdir)))
|
||||
(when (file-exists-p gitdir)
|
||||
(setq version
|
||||
(let ((default-directory topdir))
|
||||
(shell-command-to-string
|
||||
"git describe --tags --dirty --always"))))
|
||||
(unless version
|
||||
(setq version (with-temp-buffer
|
||||
(insert-file-contents-literally
|
||||
(locate-library "org-roam-bibtex.el"))
|
||||
(goto-char (point-min))
|
||||
(save-match-data
|
||||
(if (re-search-forward
|
||||
"\\(?:;; Version: \\([^z-a]*?$\\)\\)" nil nil)
|
||||
(substring-no-properties (match-string 1))
|
||||
"N/A")))))
|
||||
(if (or message (called-interactively-p 'interactive))
|
||||
(message "%s" version)
|
||||
version)))
|
||||
|
||||
;; ============================================================================
|
||||
;;;; Macros
|
||||
;; ============================================================================
|
||||
|
||||
(defmacro orb--with-message! (message &rest body)
|
||||
"Put MESSAGE before and after BODY.
|
||||
Append \"...\" to the first message and \"...done\" to the second.
|
||||
Return result of evaluating the BODY."
|
||||
(declare (indent 1) (debug (stringp &rest form)))
|
||||
(let ((reporter (gensym "orb")))
|
||||
`(let ((,reporter (make-progress-reporter ,message)))
|
||||
,@body
|
||||
(progress-reporter-done ,reporter))))
|
||||
|
||||
(defmacro orb-note-actions-defun (interface &rest body)
|
||||
"Return a function definition for INTERFACE.
|
||||
Function name takes a form of orb-note-actions--INTERFACE. A
|
||||
simple docstring is constructed and BODY is injected into a `let'
|
||||
form, which has two variables bound, NAME and CANDIDATES. NAME
|
||||
is a string formatted with `orb-format-entry' and CANDIDATES
|
||||
is a cons cell alist constructed from `orb-note-actions-default',
|
||||
`orb-note-actions-extra', and `orb-note-actions-user'."
|
||||
(declare (indent 1) (debug (symbolp &rest form)))
|
||||
(let* ((interface-name (symbol-name interface))
|
||||
(fun-name (intern (concat "orb-note-actions-" interface-name))))
|
||||
`(defun ,fun-name (citekey)
|
||||
,(format "Provide note actions using %s interface.
|
||||
CITEKEY is the citekey." (capitalize interface-name))
|
||||
(let ((name (orb-format-entry citekey)) ;; TODO: make a native format function
|
||||
(candidates
|
||||
,(unless (eq interface 'hydra)
|
||||
'(append orb-note-actions-default
|
||||
orb-note-actions-extra
|
||||
orb-note-actions-user))))
|
||||
,@body))))
|
||||
|
||||
;; ============================================================================
|
||||
;;;; General utilities
|
||||
;; ============================================================================
|
||||
|
||||
(defun orb-warning (warning &optional citekey)
|
||||
"Display a WARNING message. Return nil.
|
||||
Include CITEKEY if it is non-nil."
|
||||
(display-warning
|
||||
:warning (concat "ORB: " (when citekey (format "%s :" citekey)) warning))
|
||||
nil)
|
||||
|
||||
(defun orb-buffer-string (&optional start end)
|
||||
"Retun buffer (sub)string with no text porperties.
|
||||
Like `buffer-substring-no-properties' but START and END are
|
||||
optional and equal to (`point-min') and (`point-max'),
|
||||
respectively, if nil."
|
||||
(buffer-substring-no-properties (or start (point-min))
|
||||
(or end (point-max))))
|
||||
|
||||
(defun orb-format (&rest args)
|
||||
"Format ARGS conditionally and return a string.
|
||||
ARGS must be a plist, whose keys are `format' control strings and
|
||||
values are `format' objects. Thus only one object per control
|
||||
string is allowed. The result will be concatenated into a single
|
||||
string.
|
||||
|
||||
In the simplest case, it behaves as a sort of interleaved `format':
|
||||
==========
|
||||
|
||||
\(orb-format \"A: %s\" 'hello
|
||||
\" B: %s\" 'world
|
||||
\" C: %s\" \"!\")
|
||||
|
||||
=> 'A: hello B: world C: !'
|
||||
|
||||
If format object is nil, it will be formatted as empty string:
|
||||
==========
|
||||
|
||||
\(orb-format \"A: %s\" 'hello
|
||||
\" B: %s\" nil
|
||||
\" C: %s\" \"!\")
|
||||
=> 'A: hello C: !'
|
||||
|
||||
Object can also be a cons cell. If its car is nil then its cdr
|
||||
will be treated as default value and formatted as \"%s\":
|
||||
==========
|
||||
|
||||
\(orb-format \"A: %s\" 'hello
|
||||
\" B: %s\" '(nil . dworl)
|
||||
\" C: %s\" \"!\")
|
||||
=> 'A: hellodworl C: !'
|
||||
|
||||
Finally, if the control string is nil, the object will be formatted as \"%s\":
|
||||
==========
|
||||
|
||||
\(orb-format \"A: %s\" 'hello
|
||||
\" B: %s\" '(nil . \" world\")
|
||||
nil \"!\")
|
||||
=> 'A: hello world!'."
|
||||
(let ((res ""))
|
||||
(while args
|
||||
(let ((str (pop args))
|
||||
(obj (pop args)))
|
||||
(unless (consp obj)
|
||||
(setq obj (cons obj nil)))
|
||||
(setq res
|
||||
(concat res
|
||||
(format (or (and (car obj) str) "%s")
|
||||
(or (car obj) (cdr obj) ""))))))
|
||||
res))
|
||||
|
||||
;; ============================================================================
|
||||
;;;; Temporary files
|
||||
;; ============================================================================
|
||||
|
||||
;;;;; Code in this section was adopted from ob-core.el
|
||||
;;
|
||||
;; Copyright (C) 2009-2020 Free Software Foundation, Inc.
|
||||
;;
|
||||
;; Authors: Eric Schulte
|
||||
;; Dan Davison
|
||||
|
||||
(defvar orb--temp-dir)
|
||||
(unless (or noninteractive (boundp 'orb--temp-dir))
|
||||
(defvar orb--temp-dir
|
||||
(or (and (boundp 'orb--temp-dir)
|
||||
(file-exists-p orb--temp-dir)
|
||||
orb--temp-dir)
|
||||
(make-temp-file "orb-" t))
|
||||
"Directory to hold temporary files created during reference parsing.
|
||||
Used by `orb-temp-file'. This directory will be removed on Emacs
|
||||
shutdown."))
|
||||
|
||||
(defun orb-temp-file (prefix &optional suffix)
|
||||
"Create a temporary file in the `orb--temp-dir'.
|
||||
Passes PREFIX and SUFFIX directly to `make-temp-file' with the
|
||||
value of variable `temporary-file-directory' temporarily set to
|
||||
the value of `orb--temp-dir'."
|
||||
(let ((temporary-file-directory
|
||||
(or (and (boundp 'orb--temp-dir)
|
||||
(file-exists-p orb--temp-dir)
|
||||
orb--temp-dir)
|
||||
temporary-file-directory)))
|
||||
(make-temp-file prefix nil suffix)))
|
||||
|
||||
(defun orb--remove-temp-dir ()
|
||||
"Remove `orb--temp-dir' on Emacs shutdown."
|
||||
(when (and (boundp 'orb--temp-dir)
|
||||
(file-exists-p orb--temp-dir))
|
||||
;; taken from `delete-directory' in files.el
|
||||
(condition-case nil
|
||||
(progn
|
||||
(mapc (lambda (file)
|
||||
;; This test is equivalent to
|
||||
;; (and (file-directory-p fn) (not (file-symlink-p fn)))
|
||||
;; but more efficient
|
||||
(if (eq t (car (file-attributes file)))
|
||||
(delete-directory file)
|
||||
(delete-file file)))
|
||||
(directory-files orb--temp-dir 'full
|
||||
directory-files-no-dot-files-regexp))
|
||||
(delete-directory orb--temp-dir))
|
||||
(error
|
||||
(message "Failed to remove temporary Org-roam-bibtex directory %s"
|
||||
(if (boundp 'orb--temp-dir)
|
||||
orb--temp-dir
|
||||
"[directory not defined]"))))))
|
||||
|
||||
(add-hook 'kill-emacs-hook 'orb--remove-temp-dir)
|
||||
|
||||
;;;;; End of code adopted from ob-core.el
|
||||
|
||||
;; ============================================================================
|
||||
;;;; Document properties
|
||||
;; ============================================================================
|
||||
|
||||
(defvar orb-utils-citekey-re
|
||||
;; NOTE: Not tested thoroughly
|
||||
(rx
|
||||
(or
|
||||
(seq (group-n 2 (regexp
|
||||
;; If Org-ref is available, use its types
|
||||
;; default to "cite"
|
||||
(if (boundp 'org-ref-cite-types)
|
||||
(regexp-opt
|
||||
(mapcar
|
||||
(lambda (el)
|
||||
;; Org-ref v3 cite type is a list of strings
|
||||
;; Org-ref v2 cite type is a plain string
|
||||
(or (car-safe el) el))
|
||||
org-ref-cite-types))
|
||||
"cite")))
|
||||
":"
|
||||
(or
|
||||
;; Org-ref v2 style `cite:links'
|
||||
(group-n 1 (+ (any "a-zA-Z0-9_:.-")))
|
||||
;; Org-ref v3 style `cite:Some&key'
|
||||
(seq (*? (not "&")) "&"
|
||||
(group-n 1 (+ (any "!#-+./:<>-@^-`{-~-" word))))))
|
||||
;; Org-cite [cite/@citations]
|
||||
(seq "@" (group-n 1 (+ (any "!#-+./:<>-@^-`{-~-" word))))))
|
||||
"Universal regexp to match citations in `ROAM_REFS'.
|
||||
Supports Org-ref v2 and v3 and Org-cite.")
|
||||
|
||||
(defun orb-get-db-cite-refs ()
|
||||
"Get a list of `cite` refs from Org Roam database."
|
||||
(let* ((types "cite")
|
||||
(refs (org-roam-db-query
|
||||
[:select [ref nodes:file id pos title type]
|
||||
:from refs
|
||||
:left-join nodes
|
||||
:on (= refs:node-id nodes:id)
|
||||
:where (= type $s1)]
|
||||
types))
|
||||
result)
|
||||
(dolist (ref refs result)
|
||||
(push (-interleave '(:ref :file :id :pos :title :type) ref) result))))
|
||||
|
||||
(defvar orb-notes-cache nil
|
||||
"Cache of ORB notes.")
|
||||
|
||||
(defun orb-make-notes-cache ()
|
||||
"Update ORB notes hash table `orb-notes-cache'."
|
||||
(let* ((db-entries (orb-get-db-cite-refs))
|
||||
(size (round (/ (length db-entries) 0.8125))) ;; ht oversize
|
||||
(ht (make-hash-table :test #'equal :size size)))
|
||||
(dolist (entry db-entries)
|
||||
(puthash (plist-get entry :ref)
|
||||
(org-roam-node-create
|
||||
:id (plist-get entry :id)
|
||||
:file (plist-get entry :file)
|
||||
:title (plist-get entry :title)
|
||||
:point (plist-get entry :pos))
|
||||
ht))
|
||||
(setq orb-notes-cache ht)))
|
||||
|
||||
(defun orb-find-note-file (citekey)
|
||||
"Find note file associated with CITEKEY.
|
||||
Returns the path to the note file, or nil if it doesn’t exist."
|
||||
(when-let ((node (gethash citekey (or orb-notes-cache
|
||||
(orb-make-notes-cache)))))
|
||||
(org-roam-node-file node)))
|
||||
|
||||
(defun orb-get-buffer-keyword (keyword &optional buffer)
|
||||
"Return the value of Org KEYWORD in-buffer directive.
|
||||
The KEYWORD should be given as a string without \"#+\", e.g. \"title\".
|
||||
|
||||
If optional BUFFER is non-nil, return the value from that buffer
|
||||
instead of `current-buffer'."
|
||||
;; NOTE: does not work with `org-element-multiple-keywords' keywords
|
||||
;; if that will somewhen be required, `org-element' should be used.
|
||||
(with-current-buffer (or buffer (current-buffer))
|
||||
(let ((case-fold-search t))
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(re-search-forward
|
||||
(format "^[ ]*#\\+%s:[ ]*\\(.*\\)$" keyword) nil t)
|
||||
(match-string-no-properties 1)))))
|
||||
|
||||
(defun orb-note-exists-p (citekey)
|
||||
"Check if a note exists whose citekey is CITEKEY.
|
||||
Return Org Roam node or nil."
|
||||
;; NOTE: This function can be made more general.
|
||||
(gethash citekey (or orb-notes-cache
|
||||
(orb-make-notes-cache))))
|
||||
|
||||
(defun orb-get-node-citekey (&optional node assert)
|
||||
"Return citation key associated with NODE.
|
||||
If optional NODE is nil, return the citekey for node at point.
|
||||
ASSERT will be passed to `org-roam-node-at-point'. If it is
|
||||
non-nil, an error will be thrown if there is no node at point."
|
||||
(when-let ((node (or node (org-roam-node-at-point assert)))
|
||||
(node-refs (cdr (assoc-string
|
||||
"ROAM_REFS"
|
||||
(org-roam-node-properties node) t))))
|
||||
(let* ((ref-list (split-string-and-unquote node-refs)))
|
||||
(catch 'found
|
||||
(dolist (ref ref-list)
|
||||
(when (string-match orb-utils-citekey-re ref)
|
||||
(throw 'found (match-string 1 ref))))))))
|
||||
|
||||
(defun orb-format-entry (citekey)
|
||||
"Format a BibTeX entry for display, whose citation key is CITEKEY.
|
||||
Uses `bibtex-completion-format-entry' internally and so the
|
||||
display can be tweaked in the `bibtex-completion-display-formats'
|
||||
variable."
|
||||
;; NOTE: A drop-in replacement for `org-ref-format-entry' which was removed
|
||||
;; in Org-ref v3. Still waiting for a native solution.
|
||||
(bibtex-completion-init)
|
||||
(bibtex-completion-format-entry
|
||||
(bibtex-completion-get-entry citekey) (1- (frame-width))))
|
||||
|
||||
(provide 'orb-utils)
|
||||
;;; orb-utils.el ends here
|
||||
;; Local Variables:
|
||||
;; coding: utf-8
|
||||
;; fill-column: 79
|
||||
;; End:
|
||||
15
lisp/org-roam-bibtex/org-roam-bibtex-pkg.el
Normal file
15
lisp/org-roam-bibtex/org-roam-bibtex-pkg.el
Normal file
@@ -0,0 +1,15 @@
|
||||
(define-package "org-roam-bibtex" "20221104.2139" "Org Roam meets BibTeX"
|
||||
'((emacs "27.1")
|
||||
(org-roam "2.2.0")
|
||||
(bibtex-completion "2.0.0"))
|
||||
:commit "3810ddcd9d69ab27a40d5ba88b553df8db1b4884" :authors
|
||||
'(("Mykhailo Shevchuk" . "mail@mshevchuk.com")
|
||||
("Leo Vivier" . "leo.vivier+dev@gmail.com"))
|
||||
:maintainer
|
||||
'("Mykhailo Shevchuk" . "mail@mshevchuk.com")
|
||||
:keywords
|
||||
'("bib" "hypermedia" "outlines" "wp")
|
||||
:url "https://github.com/org-roam/org-roam-bibtex")
|
||||
;; Local Variables:
|
||||
;; no-byte-compile: t
|
||||
;; End:
|
||||
1180
lisp/org-roam-bibtex/org-roam-bibtex.el
Normal file
1180
lisp/org-roam-bibtex/org-roam-bibtex.el
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user