Skip to content

Commit dcd8c3f

Browse files
committed
feat!: make indicator affixes configurable
The current indicators are hard-coded, with the only configurable details being the symbols in `citar-symbols`. To make this all configurable, add a `citar-indicators` variable, which is a list of `citar-indicator` indicator specs. Also add the following functions: * `citar--make-indicator-processors` * `citar--make-indicator-symbols` * `citar--make-indicator-tags` BREAKING CHANGE: `citar-symbols` will be deprecated in favor of `citar-indicators` Signed-off-by: Bruce D'Arcus <bdarcus@gmail.com>
1 parent a94b32f commit dcd8c3f

File tree

3 files changed

+145
-61
lines changed

3 files changed

+145
-61
lines changed

README.org

+23-8
Original file line numberDiff line numberDiff line change
@@ -203,19 +203,34 @@ Note:
203203
5. The ~%~ character preceeds a token defined as a key in ~citar-display-transform-functions~, whose value is a list of functions and optional arguments.
204204
Note that if you include this, if you include this and a width specification, it must come after the width.
205205

206-
*** Icons
206+
*** Indicators
207207

208-
By default, this UI is plain text, but you can configure it to use icons instead.
209-
Here's how to configure it to use =all-the-icons= as in the screenshot at the top:
208+
The UI includes configurable indicators.
209+
By default, it includes plain text indicators for:
210+
211+
- Notes ::
212+
Indicates presence of notes related to the reference.
213+
- Files ::
214+
Indicates presence of library files related to the reference.
215+
- Links ::
216+
Indicates present of links associated to the reference.
217+
218+
For other indicators, see the [[https://github.com/emacs-citar/citar/wiki/Indicators][wiki]].
219+
220+
Here's a screenshot using this configuration, which remove the links indicator, and mixes plain text and an icon indicator using ~all-the-icons~.
210221

211222
#+begin_src emacs-lisp
212-
(setq citar-symbols
213-
`((file ,(all-the-icons-faicon "file-o" :face 'all-the-icons-green :v-adjust -0.1) . " ")
214-
(note ,(all-the-icons-material "speaker_notes" :face 'all-the-icons-blue :v-adjust -0.3) . " ")
215-
(link ,(all-the-icons-octicon "link" :face 'all-the-icons-orange :v-adjust 0.01) . " ")))
216-
(setq citar-symbol-separator " ")
223+
(setq citar-indicators
224+
(list citar-indicator-files ; plain text
225+
citar-indicator-notes-icons)) ; icon
217226
#+end_src
218227

228+
#+caption: UI with customized indicators.
229+
#+name: fig-indicators
230+
[[images/indicators.png]]
231+
232+
You can create your own indicators, of course, though important to keep in mind the included predicate functions must be performance optimized, since the completion UI runs them on your entire library every time to use it.
233+
219234
** Test Script
220235
:PROPERTIES:
221236
:CUSTOM_ID: test-script

citar.el

+122-53
Original file line numberDiff line numberDiff line change
@@ -201,10 +201,70 @@ and optional arguments on the string value."
201201
;; REVIEW is this OK for now?
202202
:value-type list))
203203

204+
;; Indicator defstruct
205+
206+
(cl-defstruct
207+
(citar-indicator (:constructor citar-indicator-create)
208+
(:copier nil))
209+
"A citar indicator specification."
210+
(tag
211+
nil
212+
:documentation
213+
"The string to include as hidden candidate text, and to then determine whether a
214+
candidate predicate function will return non-nil.")
215+
(symbol
216+
nil
217+
:type string
218+
:documentation
219+
"The symbol string to use in the UI when predicate function returns non-nil.")
220+
(emptysymbol
221+
" "
222+
:documentation
223+
"The symbol to use in the UI when predicate function returns nil. Can be useful
224+
in some cases when using icons.")
225+
(function
226+
nil
227+
:type function
228+
:documentation
229+
"A predicate function that takes a single CITEKEY argument.")
230+
(compiledfunction
231+
nil
232+
:type compiled-function
233+
:documentation
234+
"A compiled version of `function' used during processing."))
235+
236+
;; Indicator specs
237+
238+
(defvar citar-indicator-files
239+
(citar-indicator-create
240+
:symbol "F"
241+
:function #'citar-has-files
242+
:tag "has:files"))
243+
244+
(defvar citar-indicator-links
245+
(citar-indicator-create
246+
:symbol "L"
247+
:function #'citar-has-links
248+
:tag "has:links"))
249+
250+
(defvar citar-indicator-notes
251+
(citar-indicator-create
252+
:symbol "N"
253+
:function #'citar-has-notes
254+
:tag "has:notes"))
255+
256+
;; Indicator config
257+
258+
(defvar citar-indicators
259+
(list citar-indicator-links
260+
citar-indicator-files
261+
citar-indicator-notes))
262+
204263
(defcustom citar-symbols
205264
`((file . ("F" . " "))
206265
(note . ("N" . " "))
207266
(link . ("L" . " ")))
267+
;; DEPRECATED
208268
"Configuration alist specifying which symbol or icon to pick for a bib entry.
209269
This leaves room for configurations where the absense of an item
210270
may be indicated with the same icon but a different face.
@@ -222,6 +282,8 @@ the same width."
222282
:group 'citar
223283
:type 'string)
224284

285+
(make-obsolete 'citar-symbols nil "1.4")
286+
225287
;;;; Citar actions and other miscellany
226288

227289
(defcustom citar-default-action #'citar-open
@@ -770,6 +832,51 @@ only one resource and `citar-open-prompt' is t or contains
770832
resource
771833
nil))))
772834

835+
;; Indicator functions
836+
837+
(defun citar--make-indicator-processors (ispecs)
838+
"Return a list of indicator processors from ISPECS."
839+
(mapc
840+
(lambda (ispec)
841+
(let ((fnsym (citar-indicator-function ispec)))
842+
(setf (citar-indicator-compiledfunction ispec)
843+
(funcall fnsym))))
844+
ispecs))
845+
846+
(defun citar--make-indicator-tags (citekey iprocs)
847+
"Return indicator tags string for CITEKEY, using IPROCS.
848+
849+
This string is incorporated in the candidates as hidden text, so
850+
it can be searched against, and to contruct the indicator symbols
851+
visible in the completion UI."
852+
(mapconcat
853+
(lambda (iproc)
854+
(when (funcall (citar-indicator-compiledfunction iproc) citekey)
855+
(propertize
856+
(concat " " (citar-indicator-tag iproc))
857+
'invisible t)))
858+
iprocs ""))
859+
860+
(defun citar--make-indicator-symbols (candidate)
861+
"Return indicator string for CANDIDATE display."
862+
(seq-reduce
863+
(lambda (constructed ispec)
864+
;; first arg is the accumulated string
865+
(let* ((matchtext (citar-indicator-tag ispec))
866+
(matchtagp (string-match-p matchtext candidate))
867+
(sym (citar-indicator-symbol ispec))
868+
(emptysym (citar-indicator-emptysymbol ispec))
869+
(str (concat
870+
constructed
871+
(if matchtagp sym emptysym)
872+
citar-symbol-separator))
873+
(pos (length str)))
874+
(put-text-property (- pos 1) pos 'display
875+
(cons 'space (list :align-to (string-width str)))
876+
str)
877+
str))
878+
citar-indicators ""))
879+
773880
(defun citar--format-candidates ()
774881
"Format completion candidates for bibliography entries.
775882
@@ -781,32 +888,21 @@ Return nil if `citar-bibliographies' returns nil."
781888
(when-let ((bibs (citar--bibliographies)))
782889
(let* ((citar--entries (citar-cache--entries bibs))
783890
(preformatted (citar-cache--preformatted bibs))
784-
(hasfilesp (citar-has-files))
785-
(hasnotesp (citar-has-notes))
786-
(haslinksp (citar-has-links))
787-
(hasfilestag (propertize " has:files" 'invisible t))
788-
(hasnotestag (propertize " has:notes" 'invisible t))
789-
(haslinkstag (propertize " has:links" 'invisible t))
790-
(symbolswidth (string-width (citar--symbols-string t t t)))
891+
(indicatorprocs (citar--make-indicator-processors citar-indicators))
892+
(symbolswidth (string-width
893+
(citar--make-indicator-symbols "")))
791894
(width (- (frame-width) symbolswidth 2))
792895
(completions (make-hash-table :test 'equal :size (hash-table-count citar--entries))))
793896
(prog1 completions
794897
(maphash
795898
(lambda (citekey _entry)
796-
(let* ((hasfiles (and hasfilesp (funcall hasfilesp citekey)))
797-
(hasnotes (and hasnotesp (funcall hasnotesp citekey)))
798-
(haslinks (and haslinksp (funcall haslinksp citekey)))
799-
(preform (or (gethash citekey preformatted)
899+
(let* ((preform (or (gethash citekey preformatted)
800900
(error "No preformatted candidate string: %s" citekey)))
801901
(display (citar-format--star-widths
802902
(- width (car preform)) (cdr preform)
803903
t citar-ellipsis))
804-
(tagged (if (not (or hasfiles hasnotes haslinks))
805-
display
806-
(concat display
807-
(when hasfiles hasfilestag)
808-
(when hasnotes hasnotestag)
809-
(when haslinks haslinkstag)))))
904+
(tagged (concat display
905+
(citar--make-indicator-tags citekey indicatorprocs))))
810906
(puthash tagged citekey completions)))
811907
citar--entries)))))
812908

@@ -1217,46 +1313,19 @@ replace last comma."
12171313

12181314
;;; Affixations and annotations
12191315

1220-
(defun citar--ref-affix (cands)
1221-
"Add affixation prefix to CANDS."
1316+
(defun citar--ref-affix (candidates)
1317+
"Add affixation prefix to CANDIDATES."
12221318
(seq-map
12231319
(lambda (candidate)
1224-
(let ((symbols (citar--ref-make-symbols candidate)))
1320+
(let ((symbols
1321+
(citar--make-indicator-symbols candidate)))
12251322
(list candidate symbols "")))
1226-
cands))
1227-
1228-
(defun citar--ref-make-symbols (cand)
1229-
"Make CAND annotation or affixation string for has-symbols."
1230-
(let ((candidate-symbols (citar--symbols-string
1231-
(string-match-p "has:files" cand)
1232-
(string-match-p "has:notes" cand)
1233-
(string-match-p "has:links" cand))))
1234-
candidate-symbols))
1235-
1236-
(defun citar--ref-annotate (cand)
1237-
"Add annotation to CAND."
1323+
candidates))
1324+
1325+
(defun citar--ref-annotate (candidate)
1326+
"Add annotation to CANDIDATE."
12381327
;; REVIEW/TODO we don't currently use this, but could, for Emacs 27.
1239-
(citar--ref-make-symbols cand))
1240-
1241-
(defun citar--symbols-string (has-files has-note has-link)
1242-
"String for display from booleans HAS-FILES HAS-LINK HAS-NOTE."
1243-
(cl-flet ((thing-string (has-thing thing-symbol)
1244-
(if has-thing
1245-
(cadr (assoc thing-symbol citar-symbols))
1246-
(cddr (assoc thing-symbol citar-symbols)))))
1247-
(seq-reduce (lambda (constructed newpart)
1248-
(let* ((str (concat constructed newpart
1249-
citar-symbol-separator))
1250-
(pos (length str)))
1251-
(put-text-property (- pos 1) pos 'display
1252-
(cons 'space (list :align-to (string-width str)))
1253-
str)
1254-
str))
1255-
(list (thing-string has-files 'file)
1256-
(thing-string has-note 'note)
1257-
(thing-string has-link 'link)
1258-
"")
1259-
"")))
1328+
(citar--make-indicator-symbols candidate))
12601329

12611330
(defun citar--get-template (template-name)
12621331
"Return template string for TEMPLATE-NAME."

images/indicators.png

186 KB
Loading

0 commit comments

Comments
 (0)