all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: jack-mac <duthen.mac@gmail.com>
To: help-gnu-emacs@gnu.org
Subject: complex query replace using perform-replace with replace-re-search-function
Date: Fri, 15 Jun 2012 06:49:05 -0700 (PDT)	[thread overview]
Message-ID: <51b588c0-c619-4466-926e-91b26a2c7ad6@d17g2000vbv.googlegroups.com> (raw)

Hello!

I'm using GNU Emacs 23.1.1 (i686-pc-linux-gnu, GTK+ Version 2.22.0) of
2011-03-04 on roseapple, modified by Debian

[1] I need some help for my function `jd-sh-format-pipes' which is
described below.

It works *almost* correctly!

The query process just asks for the correct occurrences (the one
recognized by my function `jd-sh-re-search-pipe'), but *all* the
occurrences of the regexp are semi-highlighted (including what I call
exceptions to the regexp).  Nevertheless, the perform-replace process
skips these exceptions and full-highlights only the correct ones.

Is this a bug?

If it's normal, how is it possible to have *only* the 'correct'
occurrences semi-highlighted?


BTW, is there any place where I could find any examples of how to use
`perform-replace' with a customized `replace-re-search-function'
and/or `replacements' being a cons cell with a function?

================================================================
[2] Also, when reading the code of `perform-replace', I found
something strange (NOT related to my problem, I think, since I don't
use the `delimited-flag').

It changes twice the `search-function' variable:

Once is ok for me (since it takes into account the value of the
variable `replace-re-search-function'):

  (let* ([snip]
         (search-function
	  (if regexp-flag
	      replace-re-search-function
	    replace-search-function))
         [snip])

but the second one (when `delimited-flag' is t) seems to erase the
previous value of `search-function' and does NOT take into account the
value of the variable `replace-re-search-function'):

    (if delimited-flag
	(setq search-function 're-search-forward
	      search-string (concat "\\b"
				    (if regexp-flag from-string
				      (regexp-quote from-string))
				    "\\b")))

Is this correct?

================================================================
Here is the description of my function `jd-sh-format-pipes'
with a sample file to reformat.

Thanks in advance

)jack(

;;; [jack] 120610 I want each pipe in my ksh files to be surrounded by
exactly one space,
;;; i.e. basically replace  "<cm1> *| *<cmd2>"  by  "<cm1> | <cmd2>"
;;; but there are some exceptions:
;;; - `good_pipe'
;;;   <cm1> | <cmd2>
;;;   when the pipe is already surrounded by exactly one space, leave
it
;;; - `comment'
;;;   # r1238 | vtgk1446 (Jacques)    | 2012-01-31 10:26:23
;;;   Don't change a comment
;;; - `string'
;;;   sed -e 's|x|y|g' -e "s|$x|$y|g"
;;;   Don't change a string
;;; - `double_pipe'
;;;   <cmd1>  ||  <cmd2>
;;;   Don't separate a double pipe: don't change it into "<cmd1> | |
<cmd2>"
;;;   Don't squeeze the spaces:     don't change it into "<cmd1> ||
<cmd2>"
;;; - `case_clause'
;;;   case <x> in
;;;       <val>|<val>)
;;;   Don't change a case clause:   don't change it into "<val> |
<val>)"
;;; - `pipe_at_beginning-of-line'
;;;   <cmd1>   \
;;;     | <cmd2>
;;;   Don't squeeze the leading spaces, squeeze only the trailing ones
;;;
;;; As regexps don't like exceptions, it's probably nearly impossible
;;; to use `query-replace-regexp' with a regexp.
;;; So, I'll use a customized `replace-re-search-function'.

(defvar jd-sh-format-pipes-any-pipe-re  "[ \t]*| *")
(defvar jd-sh-format-pipes-good-pipe-re " | ")

(defun jd-re-paren (&rest args)
  (apply 'concat (cons "\\(" (append args (list "\\)")))))

(defun jd-sh-format-pipes ()
  (interactive)
  (let ((replace-re-search-function 'jd-sh-re-search-pipe)
        (any-pipe  jd-sh-format-pipes-any-pipe-re)
        (good-pipe jd-sh-format-pipes-good-pipe-re))
    (query-replace-regexp any-pipe good-pipe)))

(defun jd-sh-re-search-pipe (regexp &optional bound noerror count)
  (let ((good-pipe jd-sh-format-pipes-good-pipe-re)
        (pipe-at-bol (concat "^[ \t]*" (jd-re-paren "|") " *"))
        (good-pipe-at-bol "| ")
        (double-pipe "[ \t]*||[ \t]*")
        bop bopo eop ppss
        (found (not 'true)))
    (while (and (not found)
                (re-search-forward regexp bound noerror))
      (setq bop (match-beginning 0)  bopo bop  eop (match-end 0))
      (setq ppss (syntax-ppss)) ; Thanks to Stefan!
      (when (not 'debug)
        (message "%s %s"
                 (save-excursion
                   (beginning-of-line)
                   (buffer-substring (point) (+ (point) 9)))
                 ppss))
      (cond
       ((nth 3 ppss))                           ; Inside a string
       ((nth 4 ppss))                           ; Inside a comment
       ((equal (buffer-substring bop eop) good-pipe)) ; Already ok
       ((save-excursion
          (goto-char bop)
          (save-match-data
            (looking-at double-pipe)))     ; E.g. <cmd1> || <cmd2>
        (forward-char))                    ; Just skip the second pipe
       ((save-excursion
          ;; E.g.:    <cmd1>   \
          ;;            | <cmd2>
          (beginning-of-line)
          (save-match-data
            (when (and (looking-at pipe-at-bol)
                       (= eop (match-end 0)))
              (cond
               ((equal (buffer-substring (match-beginning 1) eop)
                       good-pipe-at-bol)
                t)                              ; Already ok
               (t (setq bop (1- (match-beginning 1)))
                  nil))))))             ; Process it in another clause
       ;; E.g.:    case <x> in
       ;;            <val>|<val>)
       ((save-excursion
          (beginning-of-line)
          (save-match-data
            (and (looking-at "^[^()\n]*[)]")
                 (<= eop (match-end 0))))))     ; Skip it
       (t (setq found t)
          ;; Restore match data with a possibly different bop
          (goto-char bop)
          (if (looking-at regexp)
              (goto-char (match-end 0))
            (error "Something went wrong between %s and %s at %s"
                   bopo eop bop)))))
    found))

The following file should be opened with sh-mode to get correct
comment
and string syntax.
Then M-x jd-sh-format-pipes RET

$ cat jd-sh-format-pipes-example.ksh
#!/bin/ksh

normal |command|with  |  some|  pipes  ||  Some should | not | be
changed

# normal |comment|with  |  some|  pipes  ||  None should | be changed
# r1238 | vtgk1446 (Jacques)    | 2012-01-31 10:26:23

normal |string|with  |  pipes | sed -e 's|x|y|g' -e "s|$x|$y|g" dont
change

normal |command|with  |  pipes	\
    |some| be  ||  changed	\
    | some| should | not be  ||  changed	\
    |  some| should | not be  ||  changed

case $clause in
    dont|change) ;;
esac
# File "jd-sh-format-pipes-example.ksh" ends here


             reply	other threads:[~2012-06-15 13:49 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-06-15 13:49 jack-mac [this message]
2012-06-15 14:42 ` complex query replace using perform-replace with replace-re-search-function Barry Margolin

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

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

  git send-email \
    --in-reply-to=51b588c0-c619-4466-926e-91b26a2c7ad6@d17g2000vbv.googlegroups.com \
    --to=duthen.mac@gmail.com \
    --cc=help-gnu-emacs@gnu.org \
    /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.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.