Move anchor and cursor together

Is there a map I can do that will move the anchor with the cursor so the selection stays the same size?

The problem I’m trying to solve in case there are alternate solutions. I do a bit of diagramming and sometimes I need to move a bit of the diagram around to a new line and position. Example:

A.Offset
|      B.Offset
|      |      A.Length
|      |      |      B.Length
V      V      V      V
|------|------|------|------|------|------|------|------|------|
0      5      10     15     20     25     30     35     40     45

Now say I want to copy this diagram and update it so that B moves to the right 10 units. First I use C to select both B.Length and it’s V arrow and move them over 10 units by adding spaces.

A.Offset
|      B.Offset
|      |      A.Length
|      |      |      ..............B.Length
V      V      V      ..............V
|------|------|------|------|------|------|------|------|------|
0      5      10     15     20     25     30     35     40     45

Now I want to move B.Offset to the right of and below A.Length. What I’d like to do is select B.Offset and d yank and delete it, then move the whole selection (anchor and cursor) down two lines and to the right 14 columns so that it overlays the new spaces I just inserted. Then I can R replace the spaces with the yank.

A.Offset
|      
|      |      A.Length
|      |      |      B.Offset......B.Length
V      V      V      ..............V
|------|------|------|------|------|------|------|------|------|
0      5      10     15     20     25     30     35     40     45

Not moving the anchor means that I have to mentally keep track of how big the selection was and manually select that many spaces for R replacement. Or p paste the yank and then d delete the spaces until B.Length is re-aligned with the V arrow again.

Worst kind of reply incoming, fair warning.

Maybe a different tool would serve you better, like for ascii diagrams, ASCIIFlow

or, my personal favorite tool for doing diagrams in text is: https://d2lang.com/

… and now that I think about it, d2 have an ascii diagram output format would be cool.

… additially, sorry for no real help on your question :stuck_out_tongue:

2 Likes

It’s not the worst kind of reply, it’s actually a very valid point. I have used ASCIIFlow before, but I would like something that isn’t a webpage and also outputs ascii/unicode. I do most of my work in a terminal, so I’d like to stay there as much a possible. I’m actually writing a little terminal program to do art primitives, but it not ready for prime time yet.

D2 rocks and has a built in auto-formatter and is just done in text!

I am a bit of a D2 fanboy.

Hacked this together for sake of a challenge/practice:

define-command preview-replace %{
	remove-hooks window preview-replace

	hook -group preview-replace window RawKey <esc>|R %{
		remove-hooks window preview-replace
	}
	hook -group preview-replace window ModeChange '.*' %{
		remove-hooks window preview-replace
	}
	hook -group preview-replace window RawKey .* %{
		execute-keys ";%sh{echo ${#kak_reg_dquote}}<s-l><s-h><a-;>"
	}
}

Note that the selection will wrap over to the next line if the yanked text is too long.

2 Likes

Cheers, I’ll give it a try.

I’ve solved this exact problem for ̶a̶u̶t̶o̶-pairs release :

H<a-;>H<a-;>

and same with L. I’m not sure it works as well with j and k but I didn’t need it.

For your use case though, what I’d do is probably use a combination of

  • the & key which allows to align selections by adding spaces
  • C or <a-C> to Copy selection from one line to another, keeping alignement and size

Step by step :

/25<ret>Z
To quickly go to the pipe you want to align to and mark the selection
kk<a-C>
To select the beginning of V and B.length
<a-z>a&
To append back the 25 pipe to the selection and align the selections, inserting spaces
uUr.
Undo redo to select what’s just been added and replace it with points
/B\.O<ret>Ed
To select B.Offset and yankdelete it
(\.)\.
Or anything that gets you back to the beginning of …B.Length

Then you have a lot of options :

  • simply insert B.Offset, delete the dot and realign B.length with V using the & and uUr tricks. It is the most particular and hardest to turn into a mapping solution, but it may be fast enough that we don’t even need a mapping, especially if we think of aligning B.Length, V and 25 last rather than first.
  • Use an intermediate line to put work with what you copy, & and C
  • Shell out to get the length of the yank register (${#varl} or something, idk), and craft a selection accordingly, that you can then R replace.
  • plenty of other ways probably

Because I like solution 2 the most, here is my jab at it (remember, the cursor is at the beginning of what we want to replace) :
\<a-o>
to insert a new line without hook, so as to not trigger automatic indentation
ZjP<a-z>a
to save the selection, go to the empty line and paste what we want to insert, selecting it and append back our previous selection
<a-:><a-;>&
To align. We have to ensure the cursor is at the beginning of each selection, as & aligns cursors.
,
To keep only what we just pasted as selection
<a-C>
to select the corresponding chunk on the line to make the insertion on (with undesired consequences if there is no room ! There is probably a more robust and much more lengthy solution than <a-C> using <a-z>u)
<a-(>
to exchange the selections.
,x<a-d>
To clear the temporary line.
<a-U>(,
to select what you just inserted.

I had a passing thought that it could be solved by mapping with the <a-;>, I just hadn’t taken the time to dig into it. The H<a-;>H<a-;> works really well. It seems the hard part is finding a good mapping for it. H K L all have an available <c-*> mapping available ( I don’t use the history navigation ). But <c-j> is eaten by legacy VT codes and <a-j> is too useful to remap.

When mappings come short, it may be time to make a user mode. You can use -lock option of the enter-user-mode command to stay in a mode.

The on-key command may or may not come in handy if you want to factorize all the possible key mappings from this mode.

Another way to do this is using selections_desc. It contains each cursor/anchor position in the format 1.2,3.4. So you can write a script that computes the length of each selection in a register, then add it to the current selections desc.

For example:

  1. Press Z to save selections_desc to register caret
  2. Go somewhere else
  3. Find the lengths of each selection (1.2,3.4 => |2-4| = 2) and add it to the current selections_desc with :select

Sample code:

import os
lengths = list(map(lambda x: abs(int(x.split(",")[0].split(".")[1]) - int(x.split(",")[1].split(".")[1])), os.getenv('reg_caret').split(" ")[1:]))

def new_selection(sel_desc, new_width):
    sel_desc = list(map(lambda x: list(map(int, x.split("."))), sel_desc.split(",")))
    new_cursor_column = min(sel_desc[0][1], sel_desc[1][1]) + new_width
    return f"{sel_desc[0][0]}.{sel_desc[0][1]},{sel_desc[1][0]}.{new_cursor_column}"

new_ones = list(map(lambda x: new_selection(*x), zip(os.getenv('selection_descs').split(' '), lengths)))
print(':select ' + ' '.join(new_ones))
2 Likes