Insert non-rectangular selection

62 views
Skip to first unread message

Andre Tann

unread,
May 26, 2021, 2:00:34 AM5/26/21
to vim...@googlegroups.com
Hi all,

I repeatedly have the following situation, and wonder how it can be
handled better than I do it now. These lines must be merged

/path;text
/path;text
/path;text

with these:

/subdir
/longsubdir
/longlongsubdir

Result:

/path/subdir;text
/path/longsubdir;text
/path/longlongsubdir;text


What I do now is to mark and yank the second block, go to the first
semicolon, and press P. Result is:

/path/subdir ;text
/path/longsubdir ;text
/path/longlongsubdir;text

But this is obviously not what I want. How can I avoid the extra blanks?

--
Andre Tann

Michael Henry

unread,
May 26, 2021, 6:08:48 AM5/26/21
to vim...@googlegroups.com
One option might be to remove the spaces after pasting.
Assuming that none of the paths themselves contain a semi-colon,
you could visually select the lines of text and run this
substitute command::

  :'<,'>s/ *;/;/

This finds zero or more spaces followed by a semi-colon and
replaces with just the semi-colon.  It has no ``g`` flag, so
this applies only to the first semi-colon on each line (which
will always exist in your situation and by assumption won't be
found in the paths).

Michael Henry

aro...@vex.net

unread,
May 26, 2021, 9:49:25 AM5/26/21
to vim...@googlegroups.com

> this applies only to the first semi-colon on each line (which
> will always exist in your situation and by assumption won't be
> found in the paths).
>

That assumption is probably reasonable, but a semi-colon is a legal
character in a Unix/Linux filename. (But should be reagarded as evidence
of a psychopath loose in the department.) The only character not legal in
a filename is "/".

Andre Tann

unread,
May 26, 2021, 10:19:23 AM5/26/21
to v...@vim.org
Hi all,

I repeatedly have the following situation, and wonder how it can be
handled better than I do it now. These lines must be merged

/path;text
/path;text
/path;text

with these:

/subdir
/longsubdir
/longlongsubdir

Result:

/path/subdir;text
/path/longsubdir;text
/path/longlongsubdir;text


What I do now is to mark and yank the second block, go to the first
semicolon, and press P. Result is:

/path/subdir ;text
/path/longsubdir ;text
/path/longlongsubdir;text

But this is obviously not what I want. How can I avoid the extra blanks?

--
Andre Tann

Andre Tann

unread,
May 26, 2021, 10:19:25 AM5/26/21
to vim...@googlegroups.com


On 26.05.21 15:49, aro...@Vex.Net wrote:

> That assumption is probably reasonable, but a semi-colon is a legal
> character in a Unix/Linux filename. (But should be reagarded as evidence
> of a psychopath loose in the department.) The only character not legal in
> a filename is "/".

...and the null byte, \x00.

The manual cleanup of the whitespaces is what I'm doing currently. But
it's a pain in the ass because the situation is more complex than
described, and the whitespaces are a bit tricky to catch with a regex.

Further I'm often dealing with dozens, if not hundreds of lines at a
time, making it difficult to see if the regex really matches what it should.

--
Andre Tann

Eli the Bearded

unread,
May 26, 2021, 1:58:07 PM5/26/21
to vim...@googlegroups.com
:r! reply-body --top '/tmp/Re1BDLjSqOg3'
This is an interesting problem. I've personally found visual-block
yank / put most useful in ASCII art, where true rectangular blocks are a
feature. I see some tantalizing hints in the visual.txt help file about
padded with whitespace or not, but I can't get that to work for this
type of change.

Faced with a problem like this, I'd probably write a program to do the
change (possibly within the editor :'a,'e ! perl -wne '...' -- or
possibly as a separate true script), but I might also find a way to
do it with marks and macros. Maybe something like this tail-recursive
thing:

:map ## maf;'b"aDddmb`a"aPj0##

Set up mark b at the start of the /subdir area, move to the start of
the /path;text area and start

f; find the ;, hopefully will error out at end
ma set mark a
'b jump to mark b (start of line)
"pD delete to end of line, stored in p
dd delete now blank line
mb set a new mark b
`a return to mark a (mid line, on ; )
"pP put buffer p
j0 move to start of next line
## recurse

(Untested.)

Elijah

Christian Brabandt

unread,
May 27, 2021, 3:59:09 AM5/27/21
to vim...@googlegroups.com, vim-dev Mailingliste
I have this annoyance a few times as well. I would go with the already
mentioned `:s` approach to remove the whitespace, afterwards. However, I
was wondering, if we not could do any better any perhaps have something
like a `zp` command, that does not add any trailing spaces.

diff --git a/src/normal.c b/src/normal.c
index 92135c18c..25f8233bb 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -2973,6 +2973,10 @@ dozet:
}
break;

+ // "zp", "zP" in block mode put without addind trailing spaces
+ case 'P':
+ case 'p': nv_put(cap);
+ break;
#ifdef FEAT_FOLDING
// "zF": create fold command
// "zf": create fold operator
@@ -7407,11 +7411,13 @@ nv_put_opt(cmdarg_T *cap, int fix_indent)
}
else
dir = (cap->cmdchar == 'P'
- || (cap->cmdchar == 'g' && cap->nchar == 'P'))
- ? BACKWARD : FORWARD;
+ || ((cap->cmdchar == 'g' || cap->cmdchar == 'z')
+ && cap->nchar == 'P')) ? BACKWARD : FORWARD;
prep_redo_cmd(cap);
if (cap->cmdchar == 'g')
flags |= PUT_CURSEND;
+ else if (cap->cmdchar == 'z')
+ flags |= PUT_BLOCK_INNER;

if (VIsual_active)
{
diff --git a/src/register.c b/src/register.c
index 6ba4e896d..afa83cba8 100644
--- a/src/register.c
+++ b/src/register.c
@@ -1497,6 +1497,7 @@ copy_yank_reg(yankreg_T *reg)
* "flags": PUT_FIXINDENT make indent look nice
* PUT_CURSEND leave cursor after end of new text
* PUT_LINE force linewise put (":put")
+ * PUT_BLOCK_INNER in block mode, do not add trailing spaces
*/
void
do_put(
@@ -1845,12 +1846,17 @@ do_put(

yanklen = (int)STRLEN(y_array[i]);

- // calculate number of spaces required to fill right side of block
- spaces = y_width + 1;
- for (j = 0; j < yanklen; j++)
- spaces -= lbr_chartabsize(NULL, &y_array[i][j], 0);
- if (spaces < 0)
+ if (flags & PUT_BLOCK_INNER)
spaces = 0;
+ else
+ {
+ // calculate number of spaces required to fill right side of block
+ spaces = y_width + 1;
+ for (j = 0; j < yanklen; j++)
+ spaces -= lbr_chartabsize(NULL, &y_array[i][j], 0);
+ if (spaces < 0)
+ spaces = 0;
+ }

// insert the new text
totlen = count * (yanklen + spaces) + bd.startspaces + bd.endspaces;
diff --git a/src/vim.h b/src/vim.h
index 368cf3256..ef86312da 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -1068,6 +1068,7 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring);
#define PUT_LINE 8 // put register as lines
#define PUT_LINE_SPLIT 16 // split line for linewise register
#define PUT_LINE_FORWARD 32 // put linewise register below Visual sel.
+#define PUT_BLOCK_INNER 64 // in block mode, do not add trailing spaces

// flags for set_indent()
#define SIN_CHANGED 1 // call changed_bytes() when line changed

Mit freundlichen Grüßen
Christian
--
Werfen Sie leere Konservendosen nicht weg! Bewahren Sie sie auf! Nach
einigen Jahren haben Sie dann eine schöne Sammlung alter Konservendosen.

Bram Moolenaar

unread,
May 27, 2021, 7:29:17 AM5/27/21
to vim...@googlegroups.com, Christian Brabandt, vim-dev Mailingliste

Christian wrote:

> On Di, 25 Mai 2021, Andre Tann wrote:
>
> > Hi all,
> >
> > I repeatedly have the following situation, and wonder how it can be handled
> > better than I do it now. These lines must be merged
> >
> > /path/subdir ;text
> > /path/longsubdir ;text
> > /path/longlongsubdir;text
> >
> > with these:
> >
> > /subdir
> > /longsubdir
> > /longlongsubdir
> >
> > Result:
> >
> > /path/subdir;text
> > /path/longsubdir;text
> > /path/longlongsubdir;text
> >
> >
> > What I do now is to mark and yank the second block, go to the first
> > semicolon, and press P. Result is:
> >
> > /path/subdir ;text
> > /path/longsubdir ;text
> > /path/longlongsubdir;text
> >
> > But this is obviously not what I want. How can I avoid the extra blanks?
>
> I have this annoyance a few times as well. I would go with the already
> mentioned `:s` approach to remove the whitespace, afterwards. However, I
> was wondering, if we not could do any better any perhaps have something
> like a `zp` command, that does not add any trailing spaces.

This makes a lot of sense. I don't see a problem using "zp" and "zP"
for this.

Can you turn this into a pull request and add a test?


The example yanks until the end of the line, thus the register does not
contain trailing spaces. I wonder what to do when yanking halfway a
line, e.g. a column in a table:

texttext /subdir columntext
texttext /longsubdir columntext
texttext /longlongsubdir columntext

Here you can only yank a block including the spaces, and they would also
be inserted with "zp". Perhaps we should also have a "zy" command to
exclude the trailing spaces when yanking. I think that's better than
having "zp" drop spaces that were yanked.


--
5 out of 4 people have trouble with fractions.

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///

Steve Litt

unread,
May 28, 2021, 8:24:36 AM5/28/21
to vim...@googlegroups.com, v...@vim.org
Andre Tann said on Tue, 25 May 2021 23:00:25 +0200
I'd write a Python program to do this. Here's pseudocode of the main
loop:

until eof filea
read filea into stringa
read fileb into stringb
stringc = stringa + stringb
write stringc to filec

You'd also need to open and close the files, and you'd need an error
condition for the situation where the two files have a different number
of lines. But a different number of lines would be a horror movie for
the Vim solution too.

SteveT

Steve Litt
Spring 2021 featured book: Troubleshooting Techniques of the Successful
Technologist http://www.troubleshooters.com/techniques

Christian Brabandt

unread,
May 30, 2021, 1:42:37 PM5/30/21
to vim...@googlegroups.com, vim-dev Mailingliste
Okay done.

>
>
> The example yanks until the end of the line, thus the register does not
> contain trailing spaces. I wonder what to do when yanking halfway a
> line, e.g. a column in a table:
>
> texttext /subdir columntext
> texttext /longsubdir columntext
> texttext /longlongsubdir columntext
>
> Here you can only yank a block including the spaces, and they would also
> be inserted with "zp". Perhaps we should also have a "zy" command to
> exclude the trailing spaces when yanking. I think that's better than
> having "zp" drop spaces that were yanked.

Okay, I'll have a look at adding a zy command as well (this will be a
separate PR).

Best,
Christian
--
Wer irgendeine Art von Religion zur Stütze seiner Sittlichkeit bedarf,
dessen Moralität ist nicht rein, denn diese muß ihrer Natur nach in
sich selbst bestehen.
-- Karoline von Günderode

Christian Brabandt

unread,
May 31, 2021, 1:39:17 AM5/31/21
to vim...@googlegroups.com

On Di, 25 Mai 2021, Andre Tann wrote:

With the latest Vim 8.2.2914 you can now paste using `zp` that will not
add any padding.

Best,
Christian
--
Männer verlangen von den Frauen immer das Gleiche.
Frauen verlangen von den Männern etwas Besonderes.
-- Sarah Bernhardt

Andre Tann

unread,
Jul 25, 2021, 5:04:23 AM7/25/21
to vim...@googlegroups.com
Hi Christian, all,

On 31.05.21 07:39, Christian Brabandt wrote:

> With the latest Vim 8.2.2914 you can now paste using `zp` that will not
> add any padding.

I completely missed this one. That's great news, and I just cloned this
version & it works exactly as expected.

Thanks very much to add this feature so fast - and sorry again for not
answering that long.

All the best
Andre

--
Andre Tann

Andre Tann

unread,
Jul 22, 2023, 3:58:55 PM7/22/23
to vim...@googlegroups.com
Hi Christian, all,

On 31.05.21 07:39, Christian Brabandt wrote:
>> /path/subdir ;text
>> /path/longsubdir ;text
>> /path/longlongsubdir;text
>>
>> But this is obviously not what I want. How can I avoid the extra blanks?
> With the latest Vim 8.2.2914 you can now paste using `zp` that will not
> add any padding.

Probably a bit late, but I have just found that I never responded to
this improvement. It does exactly what I need, and it is great to have
it working.

So thanks Christian & Bram, better late than never :D

--
Andre Tann

Christian Brabandt

unread,
Jul 23, 2023, 6:19:14 AM7/23/23
to vim...@googlegroups.com

On Sa, 22 Jul 2023, Andre Tann wrote:

> Probably a bit late, but I have just found that I never responded to this
> improvement. It does exactly what I need, and it is great to have it
> working.
>
> So thanks Christian & Bram, better late than never :D

No problem :) Please check also out the zy normal mode command.

Best,
Christian
--
Der Mann braucht zum vollkommenen Glück einen zuverlässigen Freund,
die Frau eine zuverlässige Feindin.
-- Tennessee Williams
Reply all
Reply to author
Forward
0 new messages