]> code.delx.au - gnu-emacs-elpa/blobdiff - packages/el-search/el-search.el
Tweak docstring of el-search--ensure-sexp-start
[gnu-emacs-elpa] / packages / el-search / el-search.el
index 2f69f5f87c6c100df8bac663ed71c14d0ffa68bc..dea74b280985e240bf781b64d57e6c97296b4696 100644 (file)
   :group 'lisp)
 
 (defcustom el-search-this-expression-identifier 'exp
-  "Name of the identifier referring to the current expression.
-The default value is `exp'.  You can use this name in the search
-prompt to refer to the value of the currently tested expression."
+  "Identifier referring to the current expression in pattern input.
+When entering a PATTERN in an interactive \"el-search\" command,
+the pattern actually used will be
+
+    `(and ,el-search-this-expression-identifier ,pattern)
+
+The default value is `exp'."
   :type 'symbol)
 
 (defface el-search-match '((((background dark)) (:background "#0000A0"))
@@ -249,9 +253,28 @@ prompt to refer to the value of the currently tested expression."
                                  (t                   (:background "DarkSlateGray1")))
   "Face for highlighting the other matches.")
 
+(defcustom el-search-smart-case-fold-search t
+  "Whether to use smart case folding in pattern matching.
+When an \"el-search\" pattern involves regexp matching (like for
+\"string\" or \"source\") and this option is non-nil,
+case-fold-search will be temporarily bound to t if the according
+regexp contains any upper case letter, and nil else.  This is
+done independently for every single matching operation.
+
+If nil, the value of `case-fold-search' is decisive."
+  :type 'boolean)
+
 
 ;;;; Helpers
 
+(defun el-search--smart-string-match-p (regexp string)
+  "`string-match-p' taking `el-search-smart-case-fold-search' into account."
+  (let ((case-fold-search (if el-search-smart-case-fold-search
+                              (not (let ((case-fold-search nil))
+                                     (string-match-p "[[:upper:]]" regexp)))
+                            case-fold-search)))
+    (string-match-p regexp string)))
+
 (defun el-search--print (expr)
   (let ((print-quoted t)
         (print-length nil)
@@ -269,44 +292,45 @@ prompt to refer to the value of the currently tested expression."
     map)
   "Map for reading input with `el-search-read-expression'.")
 
+(defun el-search--setup-minibuffer ()
+  (emacs-lisp-mode)
+  (use-local-map el-search-read-expression-map)
+  (setq font-lock-mode t)
+  (funcall font-lock-function 1)
+  (backward-sexp)
+  (indent-sexp)
+  (goto-char (point-max))
+  (when-let ((this-sexp (with-current-buffer (window-buffer (minibuffer-selected-window))
+                          (thing-at-point 'sexp))))
+    (let ((more-defaults (list (concat "'" this-sexp))))
+      (setq-local minibuffer-default-add-function
+                  (lambda () (if (listp minibuffer-default)
+                            (append minibuffer-default more-defaults)
+                          (cons minibuffer-default more-defaults)))))))
+
 ;; $$$$$FIXME: this should be in Emacs!  There is only a helper `read--expression'.
 (defun el-search-read-expression (prompt &optional initial-contents hist default read)
   "Read expression for `my-eval-expression'."
-  (minibuffer-with-setup-hook
-      (lambda ()
-        (emacs-lisp-mode)
-        (use-local-map el-search-read-expression-map)
-        (setq font-lock-mode t)
-        (funcall font-lock-function 1)
-        (backward-sexp)
-        (indent-sexp)
-        (goto-char (point-max)))
+  (minibuffer-with-setup-hook #'el-search--setup-minibuffer
     (read-from-minibuffer prompt initial-contents el-search-read-expression-map read
                           (or hist 'read-expression-history) default)))
 
 (defvar el-search--initial-mb-contents nil)
 
 (defun el-search--read-pattern (prompt &optional default read)
-  (let ((this-sexp (sexp-at-point)))
-    (minibuffer-with-setup-hook
-        (lambda ()
-          (when this-sexp
-            (let ((more-defaults (list (concat "'" (el-search--print this-sexp)))))
-              (setq-local minibuffer-default-add-function
-                          (lambda () (if (listp minibuffer-default)
-                                    (append minibuffer-default more-defaults)
-                                  (cons minibuffer-default more-defaults)))))))
-      (el-search-read-expression
-       prompt el-search--initial-mb-contents 'el-search-history default read))))
+  (let ((input (el-search-read-expression
+                prompt el-search--initial-mb-contents 'el-search-history default read)))
+    (if (or read (not (string= input ""))) input (car el-search-history))))
 
 (defun el-search--end-of-sexp ()
   ;;Point must be at sexp beginning
   (or (scan-sexps (point) 1) (point-max)))
 
 (defun el-search--ensure-sexp-start ()
-  "Move point to the beginning of the next sexp if necessary.
-Don't move if already at beginning of a sexp.
-Point must not be inside a string or comment."
+  "Move point to the next sexp beginning position.
+Don't move if already at beginning of a sexp.  Point must not be
+inside a string or comment.  `read' the expression at that point
+and return it."
   (let ((not-done t) res)
     (while not-done
       (let ((stop-here nil)
@@ -374,14 +398,15 @@ of the definitions is limited to \"el-search\"."
 
 (defun el-search--matcher (pattern &rest body)
   (eval ;use `eval' to allow for user defined pattern types at run time
-   `(el-search--with-additional-pcase-macros
-     (let ((byte-compile-debug t) ;make undefined pattern types raise an error
-           (warning-suppress-log-types '((bytecomp)))
-           (pcase--dontwarn-upats (cons '_ pcase--dontwarn-upats)))
-       (byte-compile (lambda (expression)
-                       (pcase expression
-                         (,pattern ,@(or body (list t)))
-                         (_        nil))))))))
+   (let ((expression (make-symbol "expression")))
+     `(el-search--with-additional-pcase-macros
+       (let ((byte-compile-debug t) ;make undefined pattern types raise an error
+             (warning-suppress-log-types '((bytecomp)))
+             (pcase--dontwarn-upats (cons '_ pcase--dontwarn-upats)))
+         (byte-compile (lambda (,expression)
+                         (pcase ,expression
+                           (,pattern ,@(or body (list t)))
+                           (_        nil)))))))))
 
 (defun el-search--match-p (matcher expression)
   (funcall matcher expression))
@@ -564,7 +589,7 @@ matches the list (1 2 3 4 5 6 7 8 9) and binds `x' to (4 5 6)."
     `(and (pred stringp)
           (pred (lambda (,string)
                   (cl-every
-                   (lambda (,regexp) (string-match-p ,regexp ,string))
+                   (lambda (,regexp) (el-search--smart-string-match-p ,regexp ,string))
                    (list ,@regexps)))))))
 
 (el-search-defpattern symbol (&rest regexps)
@@ -609,7 +634,7 @@ of any kind matched by all PATTERNs are also matched.
 (defun el-search--match-symbol-file (regexp symbol)
   (when-let ((symbol-file (and (symbolp symbol)
                                (symbol-file symbol))))
-    (string-match-p
+    (el-search--smart-string-match-p
      (if (symbolp regexp) (concat "\\`" (symbol-name regexp) "\\'") regexp)
      (file-name-sans-extension (file-name-nondirectory symbol-file)))))
 
@@ -663,7 +688,9 @@ matches any of these expressions:
 
 (defun el-search--s (expr)
   (cond
-   ((symbolp expr) `(symbol ,(symbol-name expr)))
+   ((symbolp expr) `(or (symbol ,(symbol-name expr))
+                        (,'\` (,'quote    (,'\, (symbol ,(symbol-name expr)))))
+                        (,'\` (,'function (,'\, (symbol ,(symbol-name expr)))))))
    ((stringp expr) `(string ,expr))
    (t expr)))
 
@@ -677,8 +704,8 @@ with very brief input by using a specialized syntax.
 
 An LPAT can take the following forms:
 
-SYMBOL  Matches any symbol matched by SYMBOL's name interpreted as
-        a regexp
+SYMBOL  Matches any symbol S matched by SYMBOL's name interpreted
+        as a regexp.  Matches also 'S and #'S for any such S.
 STRING  Matches any string matched by STRING interpreted as a
         regexp
 _       Matches any list element