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
next 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.