Skip to content

Commit

Permalink
Fix bug with zk-backlinks; add zk--posix-regexp to sanitize regexps
Browse files Browse the repository at this point in the history
So far, functions like `zk--grep-file-list` have just passed Elisp-style regexp
to `grep` and hoped it works, which it does for zk-ID or other literal strings.
Changes to `zk-link-regexp` in PR localauthor#63 broke things because it introduced
explicit capture groups (`\(?1:...\)`), which is not supported by POSIX regexps
that `grep` uses.

The new function, `zk--posix-regexp`, does some basic conversion from
Elisp-style regexps to POSIX-style. There is package `pcre2el` that does it in a
more complete and sophisticated way, but for our purposes, this should be
enough.

Functions that pass regexps to `grep`, such as `zk--grep-file-list`,
`zk--grep-tag-list`, and `zk--grep-link-id-list` are updated to
sanitize ("POSIXize") the regexps they pass. The cost is minuscule ("Elapsed
time: 0.000379s" for 10,000 calls with a complex regexp).
  • Loading branch information
boyechko committed Jul 15, 2023
1 parent fd69c0b commit 7d3cce3
Showing 1 changed file with 41 additions and 15 deletions.
56 changes: 41 additions & 15 deletions zk.el
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,29 @@ file-paths."
(buffer-file-name x)))
(buffer-list))))

(defun zk--posix-regexp (regexp &optional basic)
"Convert Elisp-style REGEXP to extended POSIX 1003.2 regexp.
If BASIC is non-nil, convert as much as possible to basic
regexp instead. See manual page `re_format(7)' for details."
(let (result)
;; 1. For basic REs, warn the user about lack of \| (or) operator
(when (and basic (string-match "\\\\|" regexp))
;; FIXME: Basic REs don't have or (\|) operator, as in \(one\|two\); one
;; would need to pass multiple -e command line args to grep. So, just
;; treat the operator as normal text, but let the user know.
(warn "Operator \\| (or) cannot be used with basic regexps: %s" regexp)
(setq result regexp))
;; 2. Strip numbered groups for extended REs, numbered and shy groups for basic
(setq result
(if basic
(replace-regexp-in-string "\\\\(\\?[0-9]?:" "\\(" regexp nil 'literal)
(replace-regexp-in-string "\\\\(\\?[0-9]:" "\\(" regexp nil 'literal)))
;; 3. Un-escape special characters (){}|+ for extended REs
(unless basic
(setq result
(replace-regexp-in-string "\\\\\\([(){}+|]\\)" "\\1" result)))
result))

(defun zk--grep-file-list (str &optional extended invert)
"Return a list of files containing regexp STR.
If EXTENDED is non-nil, use egrep. If INVERT is non-nil,
Expand All @@ -438,7 +461,8 @@ return list of files not matching the regexp."
" --recursive"
" --ignore-case"
" --include=\\*." zk-file-extension
" --regexp=" (shell-quote-argument str)
" --regexp=" (shell-quote-argument
(zk--posix-regexp str (not extended)))
" " zk-directory
" 2>/dev/null"))
"\n" t))
Expand All @@ -451,14 +475,15 @@ return list of files not matching the regexp."

(defun zk--grep-tag-list ()
"Return list of tags from all notes in zk directory."
(let* ((files (shell-command-to-string (concat
"grep -ohir --include \\*."
zk-file-extension
" -e "
(shell-quote-argument
zk-tag-regexp)
" "
zk-directory " 2>/dev/null")))
(let* ((files
(shell-command-to-string (concat
"grep -ohir --include \\*."
zk-file-extension
" -e "
(shell-quote-argument
(zk--posix-regexp zk-tag-regexp 'basic))
" "
zk-directory " 2>/dev/null")))
(list (split-string files "\n" t "\s")))
(delete-dups list)))

Expand Down Expand Up @@ -1013,12 +1038,13 @@ Select TAG, with completion, from list of all tags in zk notes."

(defun zk--grep-link-id-list ()
"Return list of all ids that appear as links in `zk-directory' files."
(let* ((files (shell-command-to-string (concat
"grep -ohir -e "
(shell-quote-argument
(zk-link-regexp))
" "
zk-directory " 2>/dev/null")))
(let* ((files (shell-command-to-string
(concat
"grep -ohir -e "
(shell-quote-argument
(zk--posix-regexp (zk-link-regexp) 'basic))
" "
zk-directory " 2>/dev/null")))
(list (split-string files "\n" t))
(ids (mapcar
(lambda (x)
Expand Down

0 comments on commit 7d3cce3

Please sign in to comment.