unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
From: Michael Heerdegen <michael_heerdegen@web.de>
To: Chunyang Xu <mail@xuchunyang.me>
Cc: help-gnu-emacs@gnu.org
Subject: Re: [el-search] How to search string excluding docstring?
Date: Mon, 25 Dec 2017 15:56:14 +0100	[thread overview]
Message-ID: <87608u501d.fsf@web.de> (raw)
In-Reply-To: <m2h8sfje5v.fsf@xuchunyang.me> (Chunyang Xu's message of "Mon, 25 Dec 2017 18:27:24 +0800")

Chunyang Xu <mail@xuchunyang.me> writes:

> Hi Michael Heerdegen and other Emacs users,
>
> For example, with the following contents in a buffer
>
> (defun foo ()
>   "foo docstring"
>   (message "foo string"))
>
> (string "foo") matches both "foo docstring" and "foo string", I want a
> way to exclude the docstring, by "docstring", I just mean the string
> being checking should not be the fourth element in
>
>   (defun _ _ docstring . _)
>
> I am thinking a pattern like
>
>   (and (pred stringp) (guard (not (docstring-p))) (string "foo"))
>
> but I have no idea how to define 'docstring-p'.

The general task is context-sensitive matching.  You have no chance with
the current version of el-search, because all patterns there are not
context aware, as you have noticed.

I want to add that, but because there are some pitfalls, I've not yet
uploaded something like this.

Here is what I currently have:

#+begin_src emacs-lisp
(defun el-search--try-find-parent-beg ()
  ;; try to find beg of parent exp heuristically
  (unless (looking-at "^(")
    (let ((opoint (point)))
      (or (and (search-backward-regexp "[;\(\)\"]" (max (- (point) 300) (point-min)))
               (looking-at "\(")
               (and (or (eobp)) (not (= (char-before) ?\\)))
               (not (looking-back ";" (line-beginning-position))))
          (progn (goto-char opoint)
                 nil)))))

(el-search-defpattern parent (pattern &optional n)
  "Matches when PATTERN matches the (Nth) parent of the current expression.
N defaults to 1.  Slow."
  (let ((parent-end (make-symbol "parent-end"))
        (counter (make-symbol "ctr")))
    `(and
      (let ,counter (or ,n 1))
      (let (,'\` ((,'\, ,pattern)))
        (save-excursion
          (condition-case nil
              (progn
                (while (>= (cl-decf ,counter) 0)
                  (or
                   (el-search--try-find-parent-beg)
                   (cond
                    ((eq (char-before) ?`) (backward-char 1))
                    ((eq (char-before) ?,) (backward-char 1))
                    ((and (eq (char-before (1- (point))) ?,)
                          (eq (char-before) ?@))
                     (backward-char 2))
                    ((eq (char-before) ?') (backward-char 1))
                    ((and (eq (char-before (1- (point))) ?#)
                          (eq (char-before) ?'))
                     (backward-char 2))
                    (t (when-let* ((,parent-end (scan-lists (point) 1 1)))
                         (goto-char ,parent-end)
                         (backward-list))))))
                (list (read (current-buffer))))
            (scan-error nil)))))))
#+end_src

That should enable you to solve your task.  Note it's experimental, and
I only had a quick look again now - want to go hiking!

One thing you can definitely _not_ do with this is to use it recursively
- i.e. (parent (parent PATTERN)) won't work (that's why I added the
optional N argument) - `parent' is only valid when applied to the
current expression.

Please tell me if it works for you.

BTW, another not yet uploaded pattern for matching strings you may find
useful is

#+begin_src emacs-lisp
(el-search-defpattern string-lines (pattern)
  "Match any string whose line number is matched by PATTERN.

Examples: (string-lines 1) matches one-line strings.
\(string-lines (pred (>= 5))\) matches strings consisting of not
more than 5 lines."
  (let ((string (make-symbol "string")))
    `(and (string)
          ,string
          (let ,pattern
            (with-temp-buffer
              (insert ,string)
              (count-lines (point-min) (point-max)))))))
#+end_src

I don't know if it's useful enough to upload it.


Regards,

Michael.



  parent reply	other threads:[~2017-12-25 14:56 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-12-25 10:27 [el-search] How to search string excluding docstring? Chunyang Xu
2017-12-25 10:40 ` Jean-Christophe Helary
2017-12-25 12:00 ` Skip Montanaro
2017-12-25 18:04   ` Michael Heerdegen
2017-12-25 14:56 ` Michael Heerdegen [this message]
2017-12-25 16:58   ` Chunyang Xu
2017-12-25 17:51     ` Michael Heerdegen
     [not found] ` <mailman.6340.1514213787.27995.help-gnu-emacs@gnu.org>
2017-12-25 15:50   ` Emanuel Berg
2017-12-25 16:59     ` Michael Heerdegen
     [not found]     ` <mailman.6351.1514221174.27995.help-gnu-emacs@gnu.org>
2017-12-25 18:04       ` Emanuel Berg
     [not found] <mailman.6328.1514197667.27995.help-gnu-emacs@gnu.org>
2017-12-25 12:00 ` Emanuel Berg
2017-12-25 13:57   ` Chunyang Xu
2017-12-25 14:34     ` Michael Heerdegen
     [not found]   ` <mailman.6334.1514210258.27995.help-gnu-emacs@gnu.org>
2017-12-25 14:08     ` Emanuel Berg
2017-12-25 17:55       ` tomas
     [not found]       ` <mailman.6358.1514224565.27995.help-gnu-emacs@gnu.org>
2017-12-25 18:11         ` Emanuel Berg
2017-12-25 19:14           ` tomas
     [not found]           ` <mailman.6366.1514229270.27995.help-gnu-emacs@gnu.org>
2017-12-25 19:36             ` Emanuel Berg
2017-12-25 21:20               ` tomas
     [not found]               ` <mailman.6371.1514236843.27995.help-gnu-emacs@gnu.org>
2017-12-25 21:56                 ` Emanuel Berg
2017-12-26  2:44                   ` Emanuel Berg
2017-12-26 13:34                   ` Emanuel Berg
2017-12-26 13:48                     ` Jean-Christophe Helary
     [not found]                     ` <mailman.6381.1514296097.27995.help-gnu-emacs@gnu.org>
2017-12-26 15:19                       ` Emanuel Berg
2017-12-27  5:38                     ` Chunyang Xu
2017-12-27 13:58                       ` Michael Heerdegen
     [not found]                     ` <mailman.6406.1514353148.27995.help-gnu-emacs@gnu.org>
2017-12-27  6:58                       ` Emanuel Berg
2017-12-25 19:39             ` Emanuel Berg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87608u501d.fsf@web.de \
    --to=michael_heerdegen@web.de \
    --cc=help-gnu-emacs@gnu.org \
    --cc=mail@xuchunyang.me \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).