[nvi] How do I move a block of text?

30 views
Skip to first unread message

Ottavio Caruso

unread,
Aug 6, 2020, 7:24:02 AM8/6/20
to
Hi,

$ type nvi
nvi is /usr/pkg/bin/nvi

:ver
Version nvi-1.81.6nb5 (2009-08-11) The CSRG, University of California,
Berkeley.

Assume I have text file like this:

------------

This is block 1
some text in block 1
some text in block 1
some text in block 1
some text in block 1
End block 1

This is block 2
some text in block 2
some text in block 2
some text in block 2
some text in block 2
End block 2

This is block 3
some text in block 3
some text in block 3
some text in block 3
some text in block 3
End block 3

------------

I want to move block 2 and paste it after block 3.

In vim, this is easy: put the cursor at the beginning of the block,
press "P", down arrow till the end of the block, "dd" and then "p" will
paste the text.

In nvi, the only user friendly way of doing it (that I know of) is:
manually count the lines in the block of text (in this case 6), then
"6dd", then "p".

This is ok if it's only a few lines, but it's a pain if it's many lines.

Is there a quicker, more elegant way of moving a block of text in nvi?

Is it possible to mark the beginning and the end of a block and then
"cut" it and put it in the buffer?

Thanks


--
Ottavio Caruso

Geoff Clare

unread,
Aug 6, 2020, 8:41:04 AM8/6/20
to
Ottavio Caruso wrote:

> I want to move block 2 and paste it after block 3.
>
> In vim, this is easy: put the cursor at the beginning of the block,
> press "P", down arrow till the end of the block, "dd" and then "p" will
> paste the text.
>
> In nvi, the only user friendly way of doing it (that I know of) is:
> manually count the lines in the block of text (in this case 6), then
> "6dd", then "p".
>
> This is ok if it's only a few lines, but it's a pain if it's many lines.
>
> Is there a quicker, more elegant way of moving a block of text in nvi?

If your "block" corresponds to what nvi treats as a paragraph (which
is true for your example), then you can use "d}" instead of "6dd" to
delete it.

Vi has a lot of special movement commands, such as { and } to move
one paragraph, ( and ) to move one sentence, [[ and ]] to move one
"section" (only useful for certain file types). You can delete
anything you can move over by preceding the movement command with
"d". E.g. to delete 2 paragraphs (while positioned at the start of
the first) you can use "d2}".

> Is it possible to mark the beginning and the end of a block and then
> "cut" it and put it in the buffer?

Yes, although you only need to make one mark. First move to the beginning
(or the end) of what you want to delete and mark the position using "m"
and a letter, then move to the end (or the beginning) and use "d'" and
the same letter. E.g.

mx
(move)
d'x

This deletes whole lines because "'x" is a line-oriented movement. To
start/stop within a line use "`x" instead of "'x".

To copy instead of moving use "y" instead of "d".

This is all standard stuff that works in all version of vi, so if
you learn it you can easily switch between nvi / vim / "real" vi (e.g.
on AIX, HP-UX, Solaris, etc.) without any problem.

--
Geoff Clare <net...@gclare.org.uk>

Ottavio Caruso

unread,
Aug 6, 2020, 9:17:28 AM8/6/20
to
Great stuff! Thank you very much.

--
Ottavio Caruso

Eli the Bearded

unread,
Aug 6, 2020, 1:21:43 PM8/6/20
to
In comp.editors, Ottavio Caruso <ottavio2006...@yahoo.com> wrote:

You've already gotten one response, just adding some other ideas.

> ------------
>
> This is block 1
> some text in block 1
> some text in block 1
> some text in block 1
> some text in block 1
> End block 1
>
> This is block 2
> some text in block 2
> some text in block 2
> some text in block 2
> some text in block 2
> End block 2
>
> This is block 3
> some text in block 3
> some text in block 3
> some text in block 3
> some text in block 3
> End block 3
>
> ------------
>
> I want to move block 2 and paste it after block 3.

Since your blocks are clearly marked at start and end, you can use the
ex move command very easily:

:/This is block 2/,/End block 2/ move /End block 3/

Or, to include the blank lines:

:/This is block 2/,/End block 2/+1 move /End block 3/+1

More generally:

: (start address), (end address) action (action arg)

Where start address defaults to current line, and if end address is
ommited will default to the start line (single line action).

> Is it possible to mark the beginning and the end of a block and then
> "cut" it and put it in the buffer?

I use ex commands with named marks very regularly. I have some
conventions for remembering what mark is what. To me:

'a a starting address
'e an ending address
'm an alternative to the unnamed mark, ''

To create a mark in vi mode: use "mn" where "m" starts the mark action
and "n" is the name of the mark. "mm" is super easy to type, hence my
use as the alternative alternative to the unnamed mark (ie a very
short lived mark for some particular need).

Other marks as needed, usually some initial as a mnemonic, eg
'v variable init
'f start of sub foo
'z zookeeper config

> In vim, this is easy: put the cursor at the beginning of the block,
> press "P", down arrow till the end of the block, "dd" and then "p" will
> paste the text.

In any vi or vi clone:

This is easy: put the cursor at the beginning of the block,
press "ma" to create mark a, move to the end of the block eg "}"
works well for blank line delimited blocks, "d'a" to delete to
mark a (storing in unnamed buffer) and then move to desired new
location and "p" will paste the text.

For the ex style interface you can ":mark a" to put mark a on the
current line and dereference the marks in a manner similar to vi:

:'a, 'e move 'm

The 'move' and 'mark' ex commands can both be abbreviated, to 'm' and
'ma' respectively, but that might be harder to remember.

Marks will be cleared when the line they are on is deleted or moved.
Marks will not be cleared, and will follow the line when other lines
are added or deleted.

line 1
line 2 mark a
line 3
line 4 mark e
line 5
line 6 mark m
line 7
line 8 mark z
line 9

Delete line 1, and all the marks shift up:

new line 1 mark a
new line 2
new line 3 mark e
new line 4
new line 5 mark m
new line 6
new line 7 mark z
new line 8

: 'a, 'e move 'm

post-move line 1
post-move line 2 mark m
post-move line 3 old mark a, no mark now
post-move line 4
post-move line 5 old mark e, no mark now
post-move line 6
post-move line 7 mark z
post-move line 8

Because so many commands operate based on movements, learning and using
a variety of movements (eg the paragraph move "{" and "}" I mentioned
earlier) can make your time in vi go faster. But if those various
commands are too hard to remember or mentally calculate, then using the
named marks becomes a powerful substitute.

Elijah
------
is friends with all the movements

sehnsucht

unread,
Feb 5, 2022, 10:00:25 AMFeb 5
to
Sul meriggio di 060820 11:24,
Ottavio Caruso <ottavio2006...@yahoo.com> enarrava tali parole:
> Hi,
> $ type nvi
> nvi is /usr/pkg/bin/nvi

I assume you're using pkgsrc on NetBSD given binary path.
You don't need to install a nvi package on NetBSD, since the editor is
already included in base, man 1 vi.

> [...]
>
> I want to move block 2 and paste it after block 3.
>
> Is there a quicker, more elegant way of moving a block of text in nvi?
>
> Is it possible to mark the beginning and the end of a block and then
> "cut" it and put it in the buffer?

Yes there is. vi(1) reads the ~/.exrc configuration file upon start up.
You can bind macros to keyboard shortcuts there. I have:

""Manipulating Buffers
" display vi buffers
map K :display buffers
" cut current line to buffer '1'
map C "1Y$dd
" paste '1' after current position
map V "1PASTE
" mark current position as begin of new buffer
map # ma
" mark current position as end of new buffer
map * mb
" append new buffer to next line
map bv :'a,'b co .
" delete marked buffer
map be :'a,'b del .
" move marked buffer to 'n' line
map bm :'a,'b mo .
" convert marked buffer to UPPERCASE
map bc :'a,'bs/.*/\U&/
" convert marked buffer to LOWERCASE
map bl :'a,'bs/.*/\L&/
" trim white space from marked buffer
map bt :'a,'bs/[ ^I][ ^I]*$//g
" write marked buffer to file
map bw :'a;'bw

So, with my bindings, you select a text block by pressing 'ma' and 'mb'
in command-mode, yank it with 'C' and paste it with 'V'

Cheers
--
sehnsucht ~ http://sehnsucht.multics.org

sehnsucht

unread,
Feb 5, 2022, 10:42:20 AMFeb 5
to
> So, with my bindings, you select a text block by pressing 'ma' and 'mb'
> in command-mode, yank it with 'C' and paste it with 'V'

sorry, I meant '#' and '*' which map ma and mb functions respectively.

sehnsucht

unread,
Feb 5, 2022, 10:47:31 AMFeb 5
to
Finally, 'bm' in command mode is to move the marked buffer it to the
line currently occupied by the cursor.
The position naturally needs to be outside of the boundaries of the
marked buffer, otherwise vi will return 'Destination line is inside the
move range'.
Reply all
Reply to author
Forward
0 new messages