;; with point at the beginning of the currently tested expression.
;;
;;
-;; Example 3:
-;;
-;; I can be useful to use (guard EXP) patterns for side effects (note:
-;; this only works when applied to the top level expression).
-;;
-;; The following pattern will search for symbols defined in any
-;; library whose name starts with "cl". As a side effect, it prints
-;; the current line number, whether we have a macro or a function, and
-;; the defining file in the echo area for each match:
-;;
-;; (and (pred symbolp)
-;; (let file (symbol-file exp))
-;; (guard file)
-;; (let lib-name (file-name-sans-extension
-;; (file-name-nondirectory file)))
-;; (guard (string-match-p "^cl" lib-name))
-;; (or (and (pred macrop) (let type "macro "))
-;; (and (pred functionp) (let type "function "))
-;; (let type ""))
-;; (guard (message "Line %d: %s`%S' (from \"%s\")"
-;; (line-number-at-pos)
-;; type
-;; exp
-;; lib-name)))
-;;
-;; `message' never returns nil, so the last `guard' always "matches".
-;;
-;;
;; Convenience
;; ===========
;;
;; so that you can always refer to the whole currently tested
;; expression via the variable `exp'.
;;
-;; Example 4:
+;;
+;; Example 3:
;;
;; If you want to search a buffer for symbols that are defined in
;; "cl-lib", you can use this pattern
(mapc
(pcase-lambda (`(,symbol . ,fun))
(when-let ((doc (documentation fun)))
- (insert "\n\n-- ")
+ (insert "\n\n\n-- ")
(setq doc (help-fns--signature symbol doc fun fun nil))
(insert "\n" (or doc "Not documented."))))
(reverse el-search--pcase-macros))
(goto-char (match-end 0)))
(t (forward-char))))
-(defun el-search--search-pattern (pattern &optional noerror)
- "Search elisp buffer with `pcase' PATTERN.
-Set point to the beginning of the occurrence found and return
-point. Optional second argument, if non-nil, means if fail just
-return nil (no error)."
-
- (let ((matcher (el-search--matcher pattern)) (match-beg nil) (opoint (point)) current-expr)
+(defun el-search--search-pattern-1 (matcher &optional noerror)
+ (let ((match-beg nil) (opoint (point)) current-expr)
;; when inside a string or comment, move past it
(let ((syntax-here (syntax-ppss)))
(if noerror nil (signal 'end-of-buffer nil)))
match-beg))
+(defun el-search--search-pattern (pattern &optional noerror)
+ "Search elisp buffer with `pcase' PATTERN.
+Set point to the beginning of the occurrence found and return
+point. Optional second argument, if non-nil, means if fail just
+return nil (no error)."
+ (el-search--search-pattern-1 (el-search--matcher pattern) noerror))
+
(defun el-search--do-subsexps (pos do-fun &optional ret-fun bound)
;; In current buffer, for any expression start between POS and BOUND
;; or (point-max), in order, call two argument function DO-FUN with
`(and (pred symbolp)
(app symbol-name (string ,@regexps))))
+(defun el-search--contains-p (matcher exp)
+ "Return non-nil when tree EXP contains a match for MATCHER.
+Recurse on all types of sequences. In the positive case the
+return value is (t elt), where ELT is a matching element found in
+EXP."
+ (if (el-search--match-p matcher exp)
+ (list t exp)
+ (and (sequencep exp)
+ (let ((try-match (apply-partially #'el-search--contains-p matcher)))
+ (if (consp exp)
+ (or (funcall try-match (car exp))
+ (funcall try-match (cdr exp)))
+ (cl-some try-match exp))))))
+
+(el-search-defpattern contains (&rest patterns)
+ "Matches trees that contain a match for all PATTERNs.
+Searches any tree of sequences recursively for matches. Objects
+of any kind matched by all PATTERNs are also matched.
+
+ Example: (contains (string \"H\") 17) matches ((\"Hallo\") x (5 [1 17]))"
+ (cond
+ ((null patterns) '_)
+ ((null (cdr patterns))
+ (let ((pattern (car patterns)))
+ `(app ,(apply-partially #'el-search--contains-p (el-search--matcher pattern))
+ (,'\` (t (,'\, ,pattern))))))
+ (t `(and ,@(mapcar (lambda (pattern) `(contains ,pattern)) patterns)))))
+
+(el-search-defpattern not (pattern)
+ "Matches any object that is not matched by PATTERN."
+ `(app ,(apply-partially #'el-search--match-p (el-search--matcher pattern))
+ (pred not)))
+
(defun el-search--match-symbol-file (regexp symbol)
(when-let ((symbol-file (and (symbolp symbol)
(symbol-file symbol))))
Additional `pcase' pattern types to be used with this command can
be defined with `el-search-defpattern'.
-The following additional pattern types are currently defined:\n"
+The following additional pattern types are currently defined:"
(interactive (list (if (and (eq this-command last-command)
el-search-success)
el-search-current-pattern
(when (and (eq this-command last-command) el-search-success)
(el-search--skip-expression nil t))
(setq el-search-success nil)
- (message "%s" (substitute-command-keys "Type \\[el-search-pattern] to repeat"))
(when (condition-case nil
(el-search--search-pattern pattern)
(end-of-buffer (message "No match")
(el-search-search-and-replace-pattern from to mapping))
(defun el-search--take-over-from-isearch ()
- (let ((other-end isearch-other-end)
- (input isearch-string))
- (isearch-exit)
- (when (and other-end (< other-end (point)))
- (goto-char other-end))
- input))
+ (prog1 isearch-string (isearch-exit)))
;;;###autoload
(defun el-search-search-from-isearch ()