]> code.delx.au - gnu-emacs-elpa/blobdiff - packages/el-search/el-search.el
When coming from isearch, don't move to other end
[gnu-emacs-elpa] / packages / el-search / el-search.el
index 7d625f8ea4fa21c4509c3be756ad661eb909e3b3..0481fef73b62db4e227ae81c996e63a248e3780f 100644 (file)
 ;; 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
@@ -373,7 +346,7 @@ Point must not be inside a string or comment."
       (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))
@@ -436,13 +409,8 @@ of the definitions is limited to \"el-search\"."
     (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)))
@@ -468,6 +436,13 @@ return nil (no error)."
         (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
@@ -596,6 +571,39 @@ matches the list (1 2 3 4 5 6 7 8 9) and binds `x' to (4 5 6)."
   `(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))))
@@ -699,7 +707,7 @@ expressions.
 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
@@ -720,7 +728,6 @@ The following additional pattern types are currently defined:\n"
     (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")
@@ -841,12 +848,7 @@ Hit any key to proceed."
   (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 ()