vim replace a string when a change occurred in another place

37 views
Skip to first unread message

Rudra Banerjee

unread,
Jun 23, 2015, 6:52:54 AM6/23/15
to vim...@googlegroups.com
Hi,

Say, I have a file:
Program foo
<program text>
End Program foo

Is it possible that if I change the word "foo" in the first line to "bar" (which may not be the first line of the file), the last line's "foo" will also be changed to "bar" automatically?

Erik Christiansen

unread,
Jun 23, 2015, 9:14:24 AM6/23/15
to vim...@googlegroups.com
On 23.06.15 03:52, Rudra Banerjee wrote:
> Say, I have a file:
> Program bar
> <program text>
> End Program bar
>
> Is it possible that if I change the word "foo" in the first line to
> "bar" (which may not be the first line of the file), the last line's
> "foo" will also be changed to "bar" automatically?

From the shorter repost, I assume there were no replies to the longer
one, so I'll venture the simple semi-automatic method I use:

1) Place cursor on the first "foo", and hit '*'.
2) We're now on the second. Type "cebar<Esc>" to replace with bar.
3) Type "N." to replicate the replacement on the first.

Since the first and second steps (target identification and
replacement), remain manual input in even an automated method, the cost
of a manual "N." for repetition is so low that striving for full
automation seems low. After all, what is the worth of full automation of
2foo when the next use case involves 3foo?

That said, if you hit 'qa' beforehand, perform the above, then 'q',
followed by '"np' , then we can see that we have full automation in
register 'a':

*cebar N.

That could be reused on another target other than "foo", but it is
perhaps too automated, because the replacement text should doubtless
then differ.

My preferred solution for automated consistency enforcement would be a
couple of lines of awk, since that is an efficient text processing tool,
while vim is a text editor. E.g.:

$ cat /tmp/text
Program bar
<program text>
End Program foo

Program far
<program text>
End Program boo

erik@ratatosk:~$ gawk '/^[^End]+Program/ {tgt = $2}
/^ *End *Program/ {$3 = tgt} {print}' /tmp/text
Program bar
<program text>
End Program bar

Program far
<program text>
End Program far

For the given syntax, it'll reform a file of any length, in one step.
Add " > /some/file" to capture the output. Put it in a bash script
with a following overwrite of the original file if that's desired.
It's "horses for courses", I suggest. (And every step pretty simple)

Erik

--
I have long felt that most computers today do not use electricity.
They instead seem to be powered by the "pumping" motion of the mouse!
- William Shotts, Jr. on http://linuxcommand.org/learning_the_shell.ph
Message has been deleted

Erik Christiansen

unread,
Jun 24, 2015, 12:59:35 AM6/24/15
to vim...@googlegroups.com
On 23.06.15 08:00, Rudra Banerjee wrote:
> function! Edname()
> python<<EOF
> import vim
> import fileinput
> with open("i.f90") as inp:
> for line in inp:
> if line.startswith("Program"):
> var = line.rsplit(' ', 1)[-1].strip()
> if line.startswith("End Program"):
> v2 = line.strip()
> print v2
> inp.close()
> STR="End Program "+var
> print STR
> for line in fileinput.input("i.f90", inplace=True):
> print line.replace(v2, STR).strip()
> EOF
> endfunction
>
> Now it is not working. It is printing the v2 and STR properly, but the
> file is NOT getting updated. Any clue?

Caveat: Yours is the first python program I've ever seen.
IIRC, it is the weird language which uses indentation
in place of brackets.

Tentative thoughts:
You have two file-reading loops, one of which appears to detect the
initial "foo", then print it. The second seems intended to make a single
replacement. If "inplace=True" ought to empower python to implicitly modify
the input file, then hopefully it is also implicitly printing the lines
you do not modify, or they must surely be lost? (Based solely on your
expectation that the input file should be modified, despite no explicit
mechanism to do that.)

Possible causes of failure:
Does the "i." indicate that file "f90" is opened for input? If so, then
how can you write to it? (Does python hide writing to a temp file, with
subsequent overwriting of the input file?) Is some form of
output.close() needed instead when closing for write? If python still
permits printing to stdout while "inplace=True", then you would need to
print to "f90", I expect, to modify the file instead. Are you relying
on the "endfunction" to implicitly invoke an ???.close() and that the
file will then be written?

I'm afraid that there's too much that is implicit in python for more
detailed guessing than that.

Erik

Rudra Banerjee

unread,
Jun 24, 2015, 2:56:03 AM6/24/15
to vim...@googlegroups.com, dva...@internode.on.net
Erik,
Thanks for you comment....but it is solved. Now, another important thing....how to invoke it! Is it possible to have something like this:

if (getline(".")) startswith "Program"
au CursorMovedI call EdName()

i.e. calling a autocmd conditionally possible?

Erik Christiansen

unread,
Jun 24, 2015, 5:27:19 AM6/24/15
to vim...@googlegroups.com
One way is to add an extension to "Program" filenames, and then just use
the standard method described at ":h au". If you find that depressingly
M$-ish, then I'm forced to agree. The alternative of placing all the
files in one or a few directories, for detection by the pattern, may be
preferable.

Sadly, maddeningly, Vim's modelines only allow "set" commands, AFAICT.
That would otherwise be a delightfully elegant solution. (Though
doubtless not without security concerns, admittedly.)

Erik

KF

unread,
Jun 25, 2015, 2:03:53 AM6/25/15
to vim...@googlegroups.com

You can check out the multiple-cursors plug-in.
https://github.com/terryma/vim-multiple-cursors

Regards,
KF

Reply all
Reply to author
Forward
0 new messages