Skip to content

Commit

Permalink
Don't rely on completion exit, detect completed tags manually (#153)
Browse files Browse the repository at this point in the history
* Don't rely on completion exit, detect completed tags manually

This fixes behavior on markdown-mode, and makes tag behavior in the metadata
work with typing as well as completion.

* Move to remove compile warning, plus use split-string for compat

* Fix metadata-read-only test, partially

* Fix test by making sure it can reproduce the original issue
  • Loading branch information
ahyatt authored Jul 21, 2024
1 parent c94d21c commit d54ddd2
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 29 deletions.
14 changes: 9 additions & 5 deletions doc/ekg.org
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ triples library is already installed.
#+end_src
* Changelog
** Version 0.7.0
- Use the global keymap in the note metadata region.
- Run tag hooks when a valid tag is typed, instead of relying on completion, which often doesn't work.
- Fix issue in =markdown-mode= where the beginning of the tag values was incorrectly read-only.
** Version 0.6.0
- Add tag and similar notes to the context when having LLMs add to or replace
Expand Down Expand Up @@ -405,9 +407,11 @@ of tags are also searched, so the same thing will happen if the tag you add is
long as it exists.

The adding of templates happens whether intially when setting up the capture
buffer, or later when the user completes a tag. Tags added without completion
won't trigger this behavior, since at the moment ekg will not be able to
understand that a tag has changed.
buffer, or later when the user types a tag that is a valid tag. Because of
this, it's best to avoid adding templates to tags that are prefixes of other
tags you'd like to use, but don't want the template on, because as soon as ekg
sees the prefix that's a valid tag being typed, it will trigger that tag's
templates.

You can choose a tag other than "template" as the trigger for this templating
behavior, by customizing ~ekg-template-tag~.
Expand Down Expand Up @@ -606,8 +610,8 @@ tags, you can enable this tag-based customization.
This works in a similar manner to [[#templates][templates]], except that a template tag only
takes effect when you add it, while a magic tag takes effect both when first
adding it and when editing a note with the tag. But they also share the same
shortcoming: you must add the tag via completion to get its effects to run. (It
will still take effect when editing the note though.)
shortcoming: if the tag is a prefix, it will trigger as soon as typed, even if
you wanted to use a different tag that is prefixed with the tag.

Creating magic tags is also like creating templates. You create a note and use
a special tag that indicates this tag is a magic tag. That special tag is
Expand Down
16 changes: 11 additions & 5 deletions doc/ekg.texi
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ triples library is already installed.

@itemize
@item
Use the global keymap in the note metadata region.
@item
Run tag hooks when a valid tag is typed, instead of relying on completion, which often doesn't work.
@item
Fix issue in @samp{markdown-mode} where the beginning of the tag values was incorrectly read-only.
@end itemize

Expand Down Expand Up @@ -737,9 +741,11 @@ of tags are also searched, so the same thing will happen if the tag you add is
long as it exists.

The adding of templates happens whether intially when setting up the capture
buffer, or later when the user completes a tag. Tags added without completion
won't trigger this behavior, since at the moment ekg will not be able to
understand that a tag has changed.
buffer, or later when the user types a tag that is a valid tag. Because of
this, it's best to avoid adding templates to tags that are prefixes of other
tags you'd like to use, but don't want the template on, because as soon as ekg
sees the prefix that's a valid tag being typed, it will trigger that tag's
templates.

You can choose a tag other than "template" as the trigger for this templating
behavior, by customizing @code{ekg-template-tag}.
Expand Down Expand Up @@ -965,8 +971,8 @@ tags, you can enable this tag-based customization.
This works in a similar manner to @ref{Templates, , templates}, except that a template tag only
takes effect when you add it, while a magic tag takes effect both when first
adding it and when editing a note with the tag. But they also share the same
shortcoming: you must add the tag via completion to get its effects to run. (It
will still take effect when editing the note though.)
shortcoming: if the tag is a prefix, it will trigger as soon as typed, even if
you wanted to use a different tag that is prefixed with the tag.

Creating magic tags is also like creating templates. You create a note and use
a special tag that indicates this tag is a magic tag. That special tag is
Expand Down
16 changes: 13 additions & 3 deletions ekg-test.el
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,17 @@
(should (string-match (rx (literal "ABC")) text))
(should (string-match (rx (literal "DEF")) text)))))

(ekg-deftest ekg-test-template-completion ()
(ekg-save-note (ekg-note-create :text "ABC" :mode #'text-mode :tags '("test" "template")))
(let ((ekg-note-add-tag-hook '(ekg-on-add-tag-insert-template)))
(ekg-capture)
(goto-char (point-min))
(end-of-line)
(insert ", tes")
(ert-simulate-command '(completion-at-point)))
(should (string-match (rx (literal "ABC")) (substring-no-properties (buffer-string))))
(kill-buffer))

(ekg-deftest ekg-test-get-notes-with-tags ()
(ekg-save-note (ekg-note-create :text "ABC" :mode #'text-mode :tags '("foo" "bar")))
(should-not (ekg-get-notes-with-tags '("foo" "none")))
Expand Down Expand Up @@ -323,9 +334,8 @@
(cl-loop for i from 1 to 10
do
(ekg-capture)
;; TODO(ahyatt) Find out why this is necessary to reproduce bad
;; behavior.
(funcall mode)
;; Necessary to reproduce the original issue with markdown-mode.
(font-lock-ensure)
(goto-char i)
(cond
((= i 1)
Expand Down
33 changes: 17 additions & 16 deletions ekg.el
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,7 @@ ARG is the prefix argument, if used it opens in another window."
header-line-format (ekg--header-line-format))
(add-hook 'pre-command-hook #'ekg-narrow-for-command nil t)
(add-hook 'post-command-hook #'ekg-unnarrow-for-command nil t)

(when (eq major-mode 'markdown-mode)
(setq-local markdown-enable-wiki-links t
markdown-wiki-link-fontify-missing nil)
Expand Down Expand Up @@ -1309,6 +1310,7 @@ after the modification.
3) The user can't delete the metadata - if the user tries to
delete from the end of the metadata, we need to fix it back up."
(when after
(ekg-detect-tag-completion)
;; If we're at the end of the metadata, we need to make sure we don't delete
;; it from the previous line. Moving after is also suspicious, because we
;; don't know where to move it. It's easiest and clearest if we just do
Expand Down Expand Up @@ -1362,6 +1364,7 @@ delete from the end of the metadata, we need to fix it back up."
(overlay-put o 'modification-hooks '(ekg--metadata-modification))
(overlay-put o 'insert-behind-hooks '(ekg--metadata-on-insert-behind))
(overlay-put o 'face 'ekg-metadata)
(overlay-put o 'local-map global-map)
(buffer-enable-undo)
;; If org-mode is on, the metadata messes up the org-element-cache, so let's disable it.
(when (eq major-mode 'org-mode)
Expand Down Expand Up @@ -1559,20 +1562,6 @@ attempt the completion."
:exclusive t :exit-function (lambda (_completion finished)
(when finished (insert ": ")))))

(defun ekg--tags-cap-exit (completion finished)
"Cleanup after completion at point happened in a tag.
The cleanup now is just to always have a space after every comma.
Argument COMPLETION is the chosen completion.
Argument FINISHED is non-nil if the user has chosen a completion."
(when finished
(save-excursion
(when (search-backward (format ",%s" completion) (line-beginning-position) t)
(replace-match (format ", %s" completion)))
(when (search-backward (format ":%s" completion) (line-beginning-position) t)
(replace-match (format ": %s" completion)))
(run-hook-with-args 'ekg-note-add-tag-hook completion)
(ekg-maybe-function-tag completion))))

(defun ekg--tags-complete ()
"Completion function for tags, CAPF-style."
(let ((end (save-excursion
Expand All @@ -1585,9 +1574,21 @@ Argument FINISHED is non-nil if the user has chosen a completion."
(point))))
(list start end (completion-table-dynamic
(lambda (_)
(ekg--update-from-metadata)
(seq-difference (ekg-tags) (ekg-note-tags ekg-note))))
:exclusive t :exit-function #'ekg--tags-cap-exit)))
:exclusive t)))

(defun ekg-detect-tag-completion ()
"After a modification, check if the user has completed a tag.
If so, call the necessary hooks."
(let ((field (ekg--metadata-current-field)))
(when (equal "Tags" (car field))
(let ((current-tags (ekg-note-tags ekg-note))
(maybe-tag (car (last (split-string (cdr field))))))
(when (and (not (member maybe-tag current-tags))
(member maybe-tag (ekg-tags)))
(ekg--update-from-metadata)
(run-hook-with-args 'ekg-note-add-tag-hook maybe-tag)
(ekg-maybe-function-tag maybe-tag))))))

(defun ekg-save-draft ()
"Save the current note as a draft."
Expand Down

0 comments on commit d54ddd2

Please sign in to comment.