Skip to content

Commit

Permalink
Improve TeX clean-up.
Browse files Browse the repository at this point in the history
Note creation would reuse the functions used for displaying BibTeX entries
in the entry buffer and with `ebib-jump-to-entry`. This would remove any
sign of font commands \textit, \textbf, \textsc and \emph. This update,
together with the update to parsebib 5.0, ensures that when creating a note
in Org format, those commands are rendered more appropriately using Org
markup.

Additionally, add functions for rendering field values using Markdown.
  • Loading branch information
Joost Kremers committed Oct 29, 2024
1 parent df815fa commit 1c69b40
Show file tree
Hide file tree
Showing 7 changed files with 316 additions and 84 deletions.
7 changes: 4 additions & 3 deletions docs/NEWS.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,15 @@
<!-- Google Fonts -->
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Merriweather+Sans&family=Roboto+Slab&display=swap" rel="stylesheet">
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
</head>
<body>
<header id="title-block-header">
<h1 class="title">Ebib News</h1>
</header>
<h2 id="version-2.45-october-2024">Version 2.45, October 2024</h2>
<ul>
<li>Handle TeX markup better when creating a note.</li>
</ul>
<h2 id="version-2.44-september-2024">Version 2.44, September 2024</h2>
<ul>
<li>New user option <code>ebib-doi-resolver</code>.</li>
Expand Down
85 changes: 72 additions & 13 deletions docs/ebib-manual.html
Original file line number Diff line number Diff line change
Expand Up @@ -2414,8 +2414,8 @@ <h1 id="notes-files">Notes files</h1>
in the index buffer, Ebib creates a note for the entry, which is saved
in a separate file. If an entry already has a note associated with it,
<span class="key"><code>N</code></span> opens it. By default, notes are
created as Org entries. (Changing that is possible, though it’s somewhat
involved.)</p>
created as Org entries. (Changing that is possible, though you may lose
some convenience. See below for some pointers.)</p>
<p>In the entry buffer, the first few lines of the note are shown under
a pseudo-field <code>external note</code>. This is not an actual field
in the <code>.bib</code> file, even though it is displayed as such. (You
Expand Down Expand Up @@ -2590,20 +2590,15 @@ <h2 class="unlisted unnumbered" id="hooks">Hooks</h2>
argument is set to the key of the current entry and the <code>db</code>
argument to the current database. With these arguments, it is possible
to, e.g., retrieve the value of a specific field in the entry:</p>
<pre><code>(ebib-get-field-value &lt;field&gt; key db &#39;noerror &#39;unbraced &#39;xref)</code></pre>
<pre><code>(ebib-get-field-value &lt;field&gt; key db &#39;noerror &#39;unbraced &#39;xref &#39;expand-strings &#39;org)</code></pre>
<p>where <code>&lt;field&gt;</code> is the field as a (case-insensitive)
string whose value is to be retrieved.</p>
string whose value is to be retrieved. The argument
<code>'noerror</code> is necessary to avoid triggering an error if
<code>field</code> does not exist in the entry. The other arguments
determine how the field value is returned. See the doc string of
<code>ebib-get-field-value</code> for details.</p>
<p>Instead of a function, you may also provide a variable. The
variable’s value is then used to replace the specifier.</p>
<p>Because the template can be customised and the major mode is
determined from the file extension, it is in principle possible to use
another format than Org for notes. In this case, it is easier to use
separate note files, but as long as you have a <code>%K</code> directive
in your template (and an appropriately defined function for it, see the
option <code>ebib-notes-template-specifiers</code>), it should still be
possible to use a single notes file. (Emphasis on <em>should</em>,
however, because this has not been tested.) You will also need to
customise the three hooks discussed above in this case.</p>
<h2 class="unlisted unnumbered" id="displaying-notes">Displaying
notes</h2>
<p>If an entry has an external note, the first few lines are shown in
Expand All @@ -2627,6 +2622,70 @@ <h2 class="unlisted unnumbered" id="displaying-notes">Displaying
section <a href="#window-management">Window Management</a> for details),
because that is the only window layout that ensures that the note can be
displayed without getting in the way.</p>
<h2 class="unlisted unnumbered" id="using-markdown-for-notes">Using
Markdown for notes</h2>
<p>Because the template can be customised and the major mode is
determined from the file extension, it is in principle possible to use
another format than Org for notes. In this case, it is easier to use
separate note files, because in a single notes file, Ebib needs to be
able to identify the location of a note. In Org files, this is fairly
straightforward using a <code>:PROPERTIES:</code> block, but there is no
similar ready-made option for other formats.</p>
<p>Provided you use a single file for each note, however, it is possible
to use another format. To do so, the following options will need to be
customised:</p>
<ul>
<li><p><code>ebib-note-file-extension</code>: set this to the extension
you use for your notes files, without the dot. The extension also
determines the major mode Emacs uses to open note files.</p></li>
<li><p><code>ebib-notes-directory</code>: this needs to be set to the
directory containing your notes. Ebib does not support single note files
in multiple directories, so you need to put all note files in a single
directory.</p></li>
<li><p><code>ebib-notes-name-transform-function</code>: this can be set
to a function that creates a name for a note file. It should return just
the base name, without the path and without the extension. If you don’t
customise it, the option <code>ebib-name-transform-function</code> will
be used instead. If you don’t customise that option either, the entry
key will be used as the file name.</p></li>
<li><p><code>ebib-notes-template</code>: this needs to be customised to
match the format you are using. By default, this template creates an Org
header with a properties block. Note that if you have one note per file,
the requirement that the template contain the <code>%K</code> specifier
does not apply, because the note is identified based on the file
name.</p></li>
<li><p><code>ebib-notes-template-specifiers</code>: create functions for
the specifiers that you use in <code>ebib-notes-template</code> and
customise this option to use them. Note that if you use Markdown, the
relevant functions are already defined. They are named with
<code>markdown</code> instead of <code>org</code>, so for the
<code>%T</code> specifier, the Markdown function is
<code>ebib-create-markdown-title</code>, etc.</p></li>
<li><p><code>ebib-notes-show-note-method</code>: the default value of
this option is only compatible with Org files. If you use a different
format, you must either unset it, or set it to the value
<code>all</code>. If you want to keep the default value
(<code>top-lines</code>), you need to customise
<code>ebib-notes-extract-text-function</code>, which would involve
writing a function that extracts the top N lines of a note.</p></li>
</ul>
<p>It should be possible to make Ebib work with multiple notes per file
in a format other than Org, but this has not been tested. If you wish to
try and make this work, two things are important: First, make sure to
include a unique identifier for each note. Unique in this case means not
only unique for the entry, but also unique in the notes file, because
Ebib searches for this identifier to locate the note. For example, using
just the entry key in a Markdown file does not guarantee uniqueness,
because the entry key can be used to insert a citation. (Ebib includes
the function <code>ebib-create-markdown-identifier</code>, which creates
a unique identifier by prepending <code>ID:</code> to the entry
key.)</p>
<p>Second, you will probably need to customise the hooks
<code>ebib-notes-search-note-before-hook</code>,
<code>ebib-notes-open-note-after-hook</code> and
<code>ebib-notes-new-note-hook</code> discussed above. They are needed
to ensure that Ebib positions point correctly when creating or editing a
note.</p>
<h2 class="unlisted unnumbered"
id="using-org-capture-to-record-notes">Using <code>org-capture</code> to
record notes</h2>
Expand Down
112 changes: 95 additions & 17 deletions ebib-utils.el
Original file line number Diff line number Diff line change
Expand Up @@ -1658,6 +1658,8 @@ error."
(setq url (match-string 1 url)))
url))

;; Template specifiers for Org

(defun ebib-create-org-identifier (key _)
"Create a unique identifier for KEY for use in an org file.
The key is prepended with the string \"Custom_id:\", so that it
Expand All @@ -1666,24 +1668,18 @@ can be used in a :PROPERTIES: block."

(defun ebib-create-org-title (key db)
"Return a title for an Org mode note for KEY in DB.
The title is formed from the title of the entry. Newlines are
removed from the resulting string."
(ebib--ifstring (title (ebib-clean-TeX-markup-from-entry "title" key db))
(remove ?\n (format "%s" title))
"(No Title)"))
The title is formed from the title of the entry."
(ebib-get-field-value "title" key db "(No Title)" 'unbraced 'xref 'expand-strings 'org))

(defun ebib-create-org-description (key db)
"Return a description for an Org mode note for KEY in DB.
The title is formed from the author(s) or editor(s) of the entry,
its year and its title. Newlines are removed from the resulting
string."
(let ((author (or (ebib-get-field-value "author" key db 'noerror 'unbraced 'xref)
(ebib-get-field-value "editor" key db 'noerror 'unbraced 'xref)
"(No Author)"))
its year and its title."
(let ((author (or (ebib-get-field-value "author" key db 'noerror 'unbraced 'xref 'expand-strings 'org)
(ebib-get-field-value "editor" key db "(No Author)" 'unbraced 'xref 'expand-strings 'org)))
(year (ebib-get-year-for-display key db))
(title (or (ebib-get-field-value "title" key db 'noerror 'unbraced 'xref)
"(No Title)")))
(remove ?\n (format "%s (%s): %s" author year title))))
(title (ebib-get-field-value "title" key db "(No Title)" 'unbraced 'xref 'expand-strings 'org)))
(format "%s (%s): %s" author year title)))

(defun ebib-create-org-cite (key _db)
"Return a citation for an Org mode note for KEY in DB."
Expand Down Expand Up @@ -1744,6 +1740,79 @@ empty string."
(url (ebib--select-url urls nil)))
(if url (format "[[%s]]" url) "")))

;; Template specifiers for Markdown

(defun ebib-create-markdown-identifier (key _)
"Create a unique identifier for KEY for use in a Markdown file.
The identifier consists of the entry key, prepended with the
string \"ID:\", to avoid confusion with citations."
(format "ID:%s" key))

(defun ebib-create-markdown-title (key db)
"Return a title for a Markdown note for KEY in DB.
The title is formed from the title of the entry. Newlines are
removed from the resulting string."
(ebib-get-field-value "title" key db "(No Title)" 'unbraced 'xref 'expand-strings 'markdown))

(defun ebib-create-markdown-description (key db)
"Return a description for a Markdown note for KEY in DB.
The title is formed from the author(s) or editor(s) of the entry,
its year and its title. Newlines are removed from the resulting
string."
(let ((author (or (ebib-get-field-value "author" key db 'noerror 'unbraced 'xref 'expand-strings 'markdown)
(ebib-get-field-value "editor" key db "(No Author)" 'unbraced 'xref 'expand-strings 'markdown)))
(year (ebib-get-year-for-display key db))
(title (ebib-get-field-value "title" key db "(No Title)" 'unbraced 'xref 'expand-strings 'markdown)))
(format "%s (%s): %s" author year title)))

(defun ebib-create-markdown-cite (key _db)
"Return a citation for a Markdown note for KEY in DB."
(format "@%s" key))

(defun ebib-create-markdown-link (key db)
"Create a Markdown link for KEY in DB.
Check the entry designated by KEY whether it has a file, a DOI or
a URL (in that order) and use the first element found to create a
link. If none of these elements is found, return the empty
string."
(cond
((ebib-get-field-value "file" key db 'noerror 'unbraced 'xref)
(ebib-create-markdown-file-link key db))
((ebib-get-field-value "doi" key db 'noerror 'unbraced 'xref)
(ebib-create-markdown-doi-link key db))
((ebib-get-field-value "url" key db 'noerror 'unbraced 'xref)
(ebib-create-markdown-url-link key db))
(t "")))

(defun ebib-create-markdown-file-link (key db)
"Create an org link to the file in entry KEY in DB.
The file is taken from the \"file\" field in the entry designated
by KEY in the current database. If that field contains more than
one file name, the user is asked to select one. If
the \"file\" field is empty, return the empty string."
(let ((files (ebib-get-field-value "file" key db 'noerror 'unbraced 'xref)))
(if files
(format "<file://%s>" (ebib--expand-file-name (ebib--select-file files nil key)))
"")))

(defun ebib-create-markdown-doi-link (key db)
"Create an org link to the DOI in entry KEY in DB.
The file is taken from the \"doi\" in the entry designated by KEY
in the current database. If the \"doi\" field is empty, return
the empty string."
(let ((doi (ebib-get-field-value "doi" key db 'noerror 'unbraced 'xref)))
(if doi (format "<doi:%s>" doi) "")))

(defun ebib-create-markdown-url-link (key db)
"Create an org link to the URL in entry KEY in DB.
The URL is taken from \"url\" in the entry designated by KEY in
the current database. If that field contains more than one url,
the user is asked to select one. If \"url\" is empty, return the
empty string."
(let* ((urls (ebib-get-field-value "url" key db 'noerror 'unbraced 'xref))
(url (ebib--select-url urls nil)))
(if url (format "[[%s]]" url) "")))

(defun ebib-format-template (template specifiers &rest args)
"Format TEMPLATE using SPECIFIERS.
SPECIFIERS is an alist of characters and symbols. Each symbol
Expand Down Expand Up @@ -2102,7 +2171,7 @@ system."
,@(when crossref-key `(("crossref" . ,crossref-key)))
,@(when xref-key `(("xref" . ,xref-key)))))))

(defun ebib-get-field-value (field key db &optional noerror unbraced xref expand-strings)
(defun ebib-get-field-value (field key db &optional noerror unbraced xref expand-strings replace-TeX)
"Return the value of FIELD in entry KEY in database DB.
If FIELD or KEY does not exist, trigger an error, unless NOERROR
is non-nil. In this case, if NOERROR is a string, return NOERROR,
Expand All @@ -2114,13 +2183,19 @@ cross-referenced entry. If the result is non-nil, the returned
text has the text property `ebib--xref', which has as value the
key of the entry from which the field value was retrieved.
Similarly, the value can be retrieved from an alias field. (See
the variable `ebib--field-aliases'). In this case, the returned
string has the text property `ebib--alias' with value t.
If EXPAND-STRINGS is non-nil and the field is unbraced then
abbreviation strings and concatenation are expanded. The result
has the text property `ebib--expanded' with value t.
Similarly, the value can be retrieved from an alias field. (See
the variable `ebib--field-aliases'). In this case, the returned
string has the text property `ebib--alias' with value t."
If REPLACE-TEX is non-nil, TeX markup is cleaned up using the
function `parsebib-clean-TeX-markup'. The value of REPLACE-TEX
should be one of the symbols `display', `org' or `markdown',
indicating the type of clean-up to be done. See the variable
`parsebib-TeX-cleanup-target' for details."
(let* ((value (ebib-db-get-field-value field key db 'noerror))
(type (ebib-db-get-field-value "=type=" key db 'noerror))
(xref-key-alist)
Expand Down Expand Up @@ -2169,6 +2244,9 @@ string has the text property `ebib--alias' with value t."
(setq value (ebib--replace-granular-xdata-references value db)))
(when unbraced
(setq value (ebib-unbrace value)))
(when (memq replace-TeX '(display org markdown))
(let ((parsebib-TeX-cleanup-target replace-TeX))
(setq value (parsebib-clean-TeX-markup value))))
(when alias
(add-text-properties 0 (length value) '(ebib--alias t) value)))
(when (and (not value)
Expand Down
4 changes: 2 additions & 2 deletions ebib.el
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
;; Author: Joost Kremers <[email protected]>
;; Maintainer: Joost Kremers <[email protected]>
;; Created: 2003
;; Version: 2.44
;; Version: 2.45
;; Keywords: text bibtex
;; URL: http://joostkremers.github.io/ebib/
;; Package-Requires: ((parsebib "4.0") (emacs "27.1") (compat "29.1.4.3"))
;; Package-Requires: ((parsebib "5.0") (emacs "27.1") (compat "29.1.4.3"))

;; Redistribution and use in source and binary forms, with or without
;; modification, are permitted provided that the following conditions
Expand Down
Loading

0 comments on commit 1c69b40

Please sign in to comment.