[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/annotate 7127180360 145/372: - added 'cl-' prefix to 'remo
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/annotate 7127180360 145/372: - added 'cl-' prefix to 'remove-if'; |
Date: |
Fri, 4 Feb 2022 16:58:37 -0500 (EST) |
branch: elpa/annotate
commit 712718036017a27ef6efab0ebdc4bb60165dadba
Author: cage <cage-invalid@invalid>
Commit: cage <cage-invalid@invalid>
- added 'cl-' prefix to 'remove-if';
- parenthesis can be escaped when filtering notes;
- fixed error message;
- added more comments, especially for the filtering annotation related
functions.
---
annotate.el | 366 ++++++++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 283 insertions(+), 83 deletions(-)
diff --git a/annotate.el b/annotate.el
index f1148092c5..6911ea16a5 100644
--- a/annotate.el
+++ b/annotate.el
@@ -946,28 +946,28 @@ file."
"Get the starting point of an annotation. The arg 'annotation' must be a
single
annotation field got from a file dump of all annotated buffers,
essentially what you get from:
-(annotate-annotations-from-dump (annotate-load-annotations))). "
+(annotate-annotations-from-dump (nth index (annotate-load-annotations)))). "
(cl-first annotation))
(defun annotate-ending-of-annotation (annotation)
"Get the ending point of an annotation. The arg 'annotation' must be a single
annotation field got from a file dump of all annotated buffers,
essentially what you get from:
-(annotate-annotations-from-dump (annotate-load-annotations))). "
+(annotate-annotations-from-dump (nth index (annotate-load-annotations))))."
(cl-second annotation))
(defun annotate-annotation-string (annotation)
"Get the text of an annotation. The arg 'annotation' must be a single
annotation field got from a file dump of all annotated buffers,
essentially what you get from:
-(annotate-annotations-from-dump (annotate-load-annotations))). "
+(annotate-annotations-from-dump (nth index (annotate-load-annotations))))."
(nth 2 annotation))
(defun annotate-annotated-text (annotation)
"Get the annotated text of an annotation. The arg 'annotation' must be a
single
annotation field got from a file dump of all annotated buffers,
essentially what you get from:
-(annotate-annotations-from-dump (annotate-load-annotations))). "
+(annotate-annotations-from-dump (nth index (annotate-load-annotations))))."
(and (> (length annotation) 3)
(nth 3 annotation)))
@@ -996,7 +996,43 @@ essentially what you get from:
(message "Annotations loaded."))))
(defun annotate-load-annotations ()
- "Load all annotations from disk."
+ "Load all annotations from disk.
+
+The format of the database is:
+
+(list record-1 record-2 ... record-n)
+
+Each record is:
+
+(list filename annotations checksum)
+
+where:
+
+filename: a string identifying a file on the file-system, or the
+string \"dir\" for top-level info file.
+
+checksum: a string used to fingerprint the annotate file above,
+used to check if a file has been modified.
+
+annotations:
+
+(list annotation-1 annotation-2 ... annotation-n) or nil
+
+finally annotation is:
+
+(list start end annotation-string annotated-text)
+
+start: the buffer position where annotated text start
+end: the buffer position where annotated text ends
+annotation-string: the text of annotation
+annotated-text: the substring of buffer starting from 'start' an ending
with 'end' (as above)
+
+example:
+
+'(\"/foo/bar\" ((0 9 \"note\" \"annotated\")) has-as-hex-string)
+
+"
+
(cl-labels ((old-format-p (annotation)
(not (stringp (cl-first (last annotation))))))
(interactive)
@@ -1401,11 +1437,11 @@ summary window is shown")
"Holds the next token of the query in `annotate-summary-query'")
(defun annotate-summary-query-lexer-symbol (res)
- "The symbol identifyng the token (e.g. 'and)"
+ "The symbol identifying the token (e.g. 'and)"
(elt res 0))
(defun annotate-summary-query-lexer-string (res)
- "The string associed with this token"
+ "The string associated with this token"
(elt res 1))
(defun annotate-summary-query-lexer-start (res)
@@ -1420,7 +1456,61 @@ summary window is shown")
(elt res 3))
(cl-defun annotate-summary-lexer (&optional (look-ahead-p nil))
- "The lexer for `annotate-summary-query'"
+ "The lexer for `annotate-summary-query'.
+
+This function, when called, will produce the next token from
+`annotate-summary-query'; a token is a substring with a well
+defined meaning according to our grammar.
+
+For example this string:
+
+p.* and (a or not b)'
+
+will be broken into these tokens:
+
+'(re \"p.*\" 0 3)
+'(and \"and\" 4 7)
+'(open-par \"(\" 8 9)
+'(re \"a\" 9 10)
+'(or \"or\" 11 12)
+'(not \"not\" 14 17)
+'(re \"b\" 18 19)
+'(close-par \"(\" 19 20)
+
+The format is a proper list where:
+- first element
+ a symbol representing the type of the token
+ - 're = regular expression
+ - 'and , 'or , 'not = logical operator
+ - 'open-par, close-par = open and closing parenthesis respectively
+- second element
+ the value (the actual substring for this token)
+
+- third and fourth element (currently unused)
+ the substring limits for this token (as returned by
+ `match-beginning' and `match-end'
+
+Note that spaces are ignored and all the tokens except `re' must
+not be prefixed with a backslash to match. So, for example not ->
+will match the token type 'not but \not will match the token 're;
+this way we can 'protect' a regexp that contains reserved
+keyword (aka escaping).
+
+the special value :no-more-token is returned after the whole
+input is processed.
+
+Calling this function with value of `look-ahead-p' nil will `consume' the
token from
+`annotate-summary-query' (i.e. that string is modified)
+
+example:
+'a and b' -> 'and b', '(re \"a\" 0 1)
+
+when `look-ahead-p' is not nil the token is recognized but not cut away from
+`annotate-summary-query'
+
+example:
+'a and b' -> 'a and b', '(re \"a\" 0 1)
+"
(cl-labels ((build-results (token-symbol register-num)
(list token-symbol
(match-string register-num
annotate-summary-query)
@@ -1430,7 +1520,7 @@ summary window is shown")
(setf annotate-summary-query
(cl-subseq annotate-summary-query
(annotate-summary-query-lexer-end match-results)))))
- (let ((re
"\\((\\)\\|\\()\\)\\|\\([^\\]?and\\)\\|\\([^\\]?not\\)\\|\\([^\\]?or\\)\\|\\([^[:space:]()]+\\)"))
+ (let ((re
"\\([^\\](\\)\\|\\([^\\])\\)\\|\\([^\\]?and\\)\\|\\([^\\]?not\\)\\|\\([^\\]?or\\)\\|\\([^[:space:]]+\\)"))
(save-match-data
(let* ((matchedp (string-match re annotate-summary-query))
(res (if matchedp
@@ -1455,39 +1545,57 @@ summary window is shown")
(cut-query res))
res)))))
-;;;; i feel this is very likely wrong in many ways, i hope linguists
-;;;; are going to forgive me :-)
-;;;;
-;;;; EXPRESSION := FILE-RE
-;;;; | FILE-RE AND NOTE-RE
-;;;; | FILE-RE OR NOTE-RE
-;;;; | epsilon
-;;;; NOTE := '(' NOTE ')'
-;;;; | NOTE OPERATOR NOTE
-;;;; | NOT NOTE
-;;;; | RE
-;;;; | epsilon
-;;;; OPERATOR := AND | OR
-;;;; RE := a regular expression
-;;;; AND := 'and'
-;;;; OR := 'or'
-;;;; NOT := 'not'
-
(defun annotate-summary-query-parse-end-input-p (token)
"Non nil if there are no more tokens in
`annotate-summary-query'"
(eq token :no-more-tokens))
(cl-defun annotate-summary-query-parse-note (filter-fn annotation &optional
(res nil))
- "Parser rule for note"
+ "Parser rule for note:
+
+This function will parse the following production rule
+
+NOTE := '(' NOTE ')'
+ | NOTE OPERATOR NOTE
+ | NOT NOTE
+ | RE
+ | epsilon
+
+OPERATOR := AND | OR
+RE := a regular expression
+AND := 'and'
+OR := 'or'
+NOT := 'not'
+
+- filter-fn is a function that accept two parameters: the regular
+ expression to match (a token of type 're, see the lexer
+ `annotate-summary-lexer' and a single annotation record (see
+ `annotate-load-annotations').
+
+ This function will reject (its value is nil) records that do
+ not match the annotation.
+
+- annotation
+ the annotation to test
+
+- res the results of this production rule (internal use only)
+
+"
(cl-labels ((token-symbol-match-p (looking-symbol token)
(eq looking-symbol
(annotate-summary-query-lexer-symbol
token)))
(unescape (escaped)
(replace-regexp-in-string
-
"\\\\\\(\\(not\\)\\|\\(and\\)\\|\\(or\\)\\)"
+
"\\\\\\(\\(not\\)\\|\\(and\\)\\|\\(or\\)\\|\\((\\)\\|\\()\\)\\)"
(lambda (a) (cl-subseq a 1))
escaped))
+ ;; this function will parse the rule operator
+ ;; OPERATOR := AND | OR
+ ;; where
+ ;; previous-token is the value of the token just matched in rule
+ ;; NOTE OPERATOR NOTE
+ ;; filter-fn see the docstring
+ ;; matchp non nil if (funcall filter-fn previous-token)
is not nil
(operator (previous-token filter-fn annotation
matchp)
(let ((look-ahead
(annotate-summary-lexer t)))
(if
(annotate-summary-query-parse-end-input-p look-ahead)
@@ -1506,102 +1614,194 @@ summary window is shown")
"found %S
instead")
look-ahead-string)))
(t
- ;; found operator, recurse
+ ;; found operator, recurse to
search for rhs of rule
+ ;; NOTE OPERATOR NOTE
(annotate-summary-query-parse-note
filter-fn
annotation
matchp))))))))
- (let* ((look-ahead (annotate-summary-lexer t)))
+ (let* ((look-ahead (annotate-summary-lexer t))) ; the next token that the
lexer *will* consume
+ ; note the second arg is
non nil
(if (not (annotate-summary-query-parse-end-input-p look-ahead))
(progn
(cond
- ((token-symbol-match-p 'close-par look-ahead) ;; ignore closing
parens
+ ((token-symbol-match-p 'close-par look-ahead) ; ignore closing
parens
res)
- ((token-symbol-match-p 'open-par look-ahead)
- (annotate-summary-lexer)
+ ((token-symbol-match-p 'open-par look-ahead) ; next token is an
open parens
+ ;; trying to match the rule:
+ ;; NOTE := '(' NOTE ')'
+ (annotate-summary-lexer) ; consume the token ')'
+ ;; match the note inside the parens
(let ((matchp (annotate-summary-query-parse-note
filter-fn
annotation)) ; recurse
+ ;; after the note there *must* be a closing parenthesis
(maybe-close-parens (annotate-summary-lexer)))
+ ;; if not this is an error
(when (or (annotate-summary-query-parse-end-input-p
maybe-close-parens)
(not (eq (annotate-summary-query-lexer-symbol
maybe-close-parens)
'close-par)))
(error "Unmatched parens"))
+ ;; continue parsing
(annotate-summary-query-parse-note filter-fn annotation
matchp))) ; recurse
((token-symbol-match-p 'not look-ahead)
- (annotate-summary-lexer)
+ (annotate-summary-lexer) ; consume the token 'not'
+ ;; the note after the 'not' operator in rule
+ ;; NOTE := NOT NOTE
+ ;; the third argument is the value to return if
+ ;; there are no more token left in the input string
(let ((res (annotate-summary-query-parse-note filter-fn
annotation :error))) ; recurse
+ ;; if there are no more tokens here this is an error
+ ;; because, according to the grammar, after a NOT a
+ ;; NOTE is non optional
(if (eq :error res)
(error "No more input after 'not'")
+ ;; if the last rule (saved in res) is not nil (and
+ ;; is not :error) return nil, return the last
+ ;; annotation otherwise remember that the user asked
+ ;; for an annotation that *not* matches a regex
(if (null res)
annotation
nil))))
+ ;; trying to match the rule:
+ ;; NOTE := NOTE AND NOTE
((token-symbol-match-p 'and look-ahead)
- (annotate-summary-lexer)
- (let ((lhs res)
+ (annotate-summary-lexer) ; consume the 'and' token
+ (let ((lhs res) ; the left side of this rule lhs AND rhs
(rhs (annotate-summary-query-parse-note filter-fn
annotation :error))) ; recurse
- (if (eq :error rhs)
+ (if (eq :error rhs) ; see the 'not' operator above
(error "No more input after 'and'")
- (and lhs rhs))))
+ (and lhs rhs)))) ; both rules must match as this is a logic
and
+ ;; trying to match the rule:
+ ;; NOTE := NOTE OR NOTE
((token-symbol-match-p 'or look-ahead)
- (annotate-summary-lexer)
- (let ((lhs res)
+ (annotate-summary-lexer) ; consume the 'or'
+ (let ((lhs res) ;; the left side of this rule lhs OR rhs
(rhs (annotate-summary-query-parse-note filter-fn
annotation :error))) ; recurse
(if (eq :error rhs)
(error "No more input after 'or'")
- (or lhs rhs))))
+ (or lhs rhs)))) ; either lhs or rhs match as this is a
logic or
(t
+ ;; here we match the rule:
+ ;; NOTE := RE
+ ;; RE := a regular expression
+ ;; we first unescape the protected tokens
+ ;; \not -> not, \( -> ( etc.
+ ;; then we apply the filter function (see the docstring)
(let* ((escaped (annotate-summary-query-lexer-string
(annotate-summary-lexer)))
(unescaped (unescape escaped))
(matchp (funcall filter-fn unescaped annotation)))
+ ;; and finally continue the parsing saving the results
+ ;; of applying the filter-fn function
(operator escaped filter-fn annotation matchp)))))
- res))))
-
-;; EXPRESSION := FILE-RE
-;; | FILE-RE AND NOTE-RE
-;; | FILE-RE OR NOTE-RE
+ ;; if we are here the lexer can not fine any more tokens in the query
+ ;; just return the value of res
+ res)))) ; end of (if (not (annotate-summary-query-parse-end-input-p
look-ahead))
(defun annotate-summary-query-parse-expression ()
- "Parse rule for expression"
+ "Parse rule for expression:
+
+I feel this is very likely wrong in many ways, i hope linguists
+are going to forgive me :-)
+
+EXPRESSION := FILE-MASK
+ | FILE-MASK AND NOTE
+ | FILE-MASK OR NOTE
+ | epsilon
+NOTE := '(' NOTE ')'
+ | NOTE OPERATOR NOTE
+ | NOT NOTE
+ | RE
+ | epsilon
+OPERATOR := AND | OR
+FILE-MASK := RE
+RE := a regular expression
+AND := 'and'
+OR := 'or'
+NOT := 'not'
+
+This function return the annotation of the record
+
+"
(lambda (annotation query file-filter-fn note-filter-fn)
- (let ((annotate-summary-query query)
- (query-notes-only nil))
- (let ((next-token (annotate-summary-lexer))) ;; get filemask
- (if (annotate-summary-query-parse-end-input-p next-token)
- (annotate-annotations-from-dump annotation)
- (let* ((filtered-annotation (funcall file-filter-fn
-
(annotate-summary-query-lexer-string next-token)
- annotation))
- (operator-token (annotate-summary-lexer)))
- (if (annotate-summary-query-parse-end-input-p operator-token)
- (annotate-annotations-from-dump filtered-annotation)
- (let ((operator (annotate-summary-query-lexer-symbol
operator-token)))
- (cond
- ((eq operator 'or)
- (if filtered-annotation
- (annotate-annotations-from-dump filtered-annotation)
- (let ((look-ahead (annotate-summary-lexer t)))
- (if (annotate-summary-query-parse-end-input-p
look-ahead)
- (error "No more input after 'or'")
- (progn
- (setf query-notes-only (concat
annotate-summary-query))
- (mapcar (lambda (a)
- (let ((annotate-summary-query (concat
query-notes-only)))
- (annotate-summary-query-parse-note
note-filter-fn
-
a)))
- (annotate-annotations-from-dump
annotation)))))))
- ((eq operator 'and)
+ (let ((annotate-summary-query query) ; save the query
+ (query-notes-only nil)) ; the query for just the notes
+ (let ((next-token (annotate-summary-lexer))) ;; get file-mask
+ ;; if there are no more tokes just return all the records
+ ;; these match the empty string as in rule
+ ;; EXPRESSION := epsilon
+ (if (annotate-summary-query-parse-end-input-p next-token)
+ (annotate-annotations-from-dump annotation)
+ ;; otherwise test the record with the file-mask
+ (let* ((filtered-annotation (funcall file-filter-fn
+
(annotate-summary-query-lexer-string next-token)
+ annotation))
+ ;; get the operator as in rule
+ (operator-token (annotate-summary-lexer)))
+ ;; if there are no operator just return the filtered (by file-mask)
+ ;; as in rule
+ ;; EXPRESSION := FILE-MASK
+ (if (annotate-summary-query-parse-end-input-p operator-token)
+ (annotate-annotations-from-dump filtered-annotation)
+ ;; otherwise get the operator and continue to parse the rule
+ ;; EXPRESSION := FILE-MASK AND NOTE
+ ;; or
+ ;; EXPRESSION := FILE-MASK OR NOTE
+ (let ((operator (annotate-summary-query-lexer-symbol
operator-token)))
+ (cond
+ ((eq operator 'or) ; operator is 'or
+ ;; try to parse with the rule
+ ;; EXPRESSION := FILE-MASK OR NOTE
+ ;; return only the list annotation filtered by
+ ;; file-mask the former is non nil
+ (if filtered-annotation
+ (annotate-annotations-from-dump filtered-annotation)
+ ;; the annotation filtered by file-mask is empty, try to
+ ;; match the NOTE rule
(let ((look-ahead (annotate-summary-lexer t)))
+ ;; no more input after operator this is wrong
+ ;; according to the rule we are trying to match:
+ ;; EXPRESSION := FILE-MASK OR NOTE
(if (annotate-summary-query-parse-end-input-p look-ahead)
- (error "No more input after 'and'")
+ (error "No more input after 'or'")
(progn
+ ;; copy the string for note parsing note
+ ;; that annotate-summary-query only contains
+ ;; the substring to match the NOTE rule
(setf query-notes-only (concat
annotate-summary-query))
+ ;; parse all the annotations, we get a list
+ ;; where non nil elements are the annotation
+ ;; that passes the note-filter-fn test
(mapcar (lambda (a)
(let ((annotate-summary-query (concat
query-notes-only)))
(annotate-summary-query-parse-note
note-filter-fn
a)))
- (annotate-annotations-from-dump
filtered-annotation))))))
- (t
- (error (format "Unkown operator: %s is not in '(and, or)"
- (annotate-summary-query-lexer-string
operator-token)))))))))))))
+ (annotate-annotations-from-dump
annotation)))))))
+ ((eq operator 'and)
+ ;; try to parse with the rule
+ ;; EXPRESSION := FILE-MASK OR NOTE
+ (let ((look-ahead (annotate-summary-lexer t)))
+ ;; no more input after operator, this is wrong
+ ;; according to the rule we are trying to match:
+ ;; EXPRESSION := FILE-MASK AND NOTE
+ (if (annotate-summary-query-parse-end-input-p look-ahead)
+ (error "No more input after 'and'")
+ (progn
+ ;; copy the string for note parsing note
+ ;; that annotate-summary-query only contains
+ ;; the substring to match the NOTE rule
+ (setf query-notes-only (concat annotate-summary-query))
+ ;; parse the already filtered by file-mask annotations
only
+ ;; we get a list where non nil elements are the
annotation
+ ;; that passes the note-filter-fn test
+ (mapcar (lambda (a)
+ (let ((annotate-summary-query (concat
query-notes-only)))
+ (annotate-summary-query-parse-note
note-filter-fn
+ a)))
+ (annotate-annotations-from-dump
filtered-annotation))))))
+ (t
+ ;; there is something after the file-mask in the
+ ;; input but it is not an operator
+ (error (format "Unknown operator: %s is not in '(and, or)"
+ (annotate-summary-query-lexer-string
operator-token)))))))))))))
(defun annotate-summary-filter-db (annotations-dump query)
"Filter an annotation database with a query.
@@ -1615,7 +1815,7 @@ where
- file-mask: is a regular expression that should match the filepath
the annotation refers to;
- and, or, not : you guess? Classics logical operators;
-- regex-note: the text of annotation must match this reguar expression.
+- regex-note: the text of annotation must match this regular expression.
Examples:
@@ -1656,7 +1856,7 @@ annotation, like this:
filter-file
filter-annotations)))
(setf filtered-annotations
- (remove-if 'null filtered-annotations))
+ (cl-remove-if 'null
filtered-annotations))
(when filtered-annotations
(let ((filename
(annotate-filename-from-dump
single-annotation))
@@ -1666,7 +1866,7 @@ annotation, like this:
filtered-annotations
checksum))))))
(filtered (mapcar filter annotations-dump)))
- (remove-if 'null filtered)))
+ (cl-remove-if 'null filtered)))
(provide 'annotate)
;;; annotate.el ends here
- [nongnu] elpa/annotate c42db2cdf9 034/372: don't mark buffer as modified on load or clear, (continued)
- [nongnu] elpa/annotate c42db2cdf9 034/372: don't mark buffer as modified on load or clear, ELPA Syncer, 2022/02/04
- [nongnu] elpa/annotate 38eb69da8b 107/372: - added a secondary color for highlight and annotation text, the two, ELPA Syncer, 2022/02/04
- [nongnu] elpa/annotate af6d1bd39a 055/372: tiny bugfix, ELPA Syncer, 2022/02/04
- [nongnu] elpa/annotate e77fc74bd2 036/372: change key binding to be more standard, ELPA Syncer, 2022/02/04
- [nongnu] elpa/annotate b032d2afe0 116/372: - changed function name: 'move-lines' -> 'beginning-of-nth-line'., ELPA Syncer, 2022/02/04
- [nongnu] elpa/annotate ce8dfa5ae9 110/372: - added docstrings., ELPA Syncer, 2022/02/04
- [nongnu] elpa/annotate 584f27cd7a 120/372: - fixed region's limit to break an annotation;, ELPA Syncer, 2022/02/04
- [nongnu] elpa/annotate d97139b566 121/372: - changed two function names and reworded 'annotate-create-annotation' docstring, ELPA Syncer, 2022/02/04
- [nongnu] elpa/annotate 8e8d5d125e 130/372: - fixed macro: "annotate-with-inhibit-modification-hooks"., ELPA Syncer, 2022/02/04
- [nongnu] elpa/annotate fbd21602e8 129/372: - refactored 'annotate-actual-file-name' and used where appropriate., ELPA Syncer, 2022/02/04
- [nongnu] elpa/annotate 7127180360 145/372: - added 'cl-' prefix to 'remove-if';,
ELPA Syncer <=
- [nongnu] elpa/annotate e43d2f9e65 069/372: - fixed left margin of annotation, ELPA Syncer, 2022/02/04
- [nongnu] elpa/annotate a51b5239b9 062/372: fixes incorrect annotation display for wide characters, ELPA Syncer, 2022/02/04
- [nongnu] elpa/annotate 0d315a806e 105/372: - fixed first argument of 'lwarn';, ELPA Syncer, 2022/02/04
- [nongnu] elpa/annotate 1ed168a79e 131/372: Merge pull request #47 from cage2/master, ELPA Syncer, 2022/02/04
- [nongnu] elpa/annotate c8aea8392d 135/372: - rewritten filename juggling to make it works with info file in, ELPA Syncer, 2022/02/04
- [nongnu] elpa/annotate 286646bc0c 137/372: - made recongnizable code that refers to info file annotation. (2/3), ELPA Syncer, 2022/02/04
- [nongnu] elpa/annotate 13391d9576 157/372: - expanded a comment and a docstring., ELPA Syncer, 2022/02/04
- [nongnu] elpa/annotate 0ae5752526 161/372: Merge pull request #54 from cage2/annotations-on-their-own-line, ELPA Syncer, 2022/02/04
- [nongnu] elpa/annotate c21b95273e 177/372: Merge pull request #57 from cage2/master, ELPA Syncer, 2022/02/04
- [nongnu] elpa/annotate 2ccdad1504 193/372: - starting with a new method to render multiline annotations, ELPA Syncer, 2022/02/04