Open PEZ opened 2 years ago
Hi! Thanks @riotrah for working on this awesome feature! ❤️ Of course I love to help with testing. Here's an issue I found:
Delete Forward to End of List only deletes for the first cursor, and loses the other cursors
Before
(|2a)(|1a)(|a)
Delete Forward to End of List
Expected
(|2)(|1)(|)
Actual
(a)(a)(|)
As this is also an example of the report format, let me elaborate some:
(a)(a)(a)
a
-> (a)(a)(|a)
a
-> (a)(|1a)(|a)
The command is written like <kbd>**Command**</kbd>
to make it look command-ish.
I'm having a great time testing this! Thanks again! 🙏
Delete Backward to Start of List only deletes for the first cursor, and loses the other cursors
Before
(a|)(a|1)(a|2)
Delete Backward to Start of List
Expected
(|)(|1)(|2)
Actual
(|)(a)(a)
Here's an interesting one. The edits are correct, then all but the leftmost cursor get offset. I've tried it on some more cases then below, and I think the offset is related to how much text is deleted by leftwards cursors.
Raise sexp wrong placement of cursor after the edit
Before 1
;; 1. Start two cursors left->right
(a (b|)) (a (b|1)) (a (b))
Raise sexp
Expect 1
(a b|) (a b|1) (a (b))
Actual 1
(a b|) (a b) |1(a (b))
Before 2
;; 1. Start two cursors left->right
(a (b|1)) (a (b|)) (a (b))
Raise sexp
Expect 2
(a b|1) (a b|) (a (b))
Actual 2 (not sure if it keeps the cursor order)
(a b|1) (a b) |(a (b))
Delete Sexp Forwards only deletes at primary cursor, loses the others
Before
(|2a) (|1a) (|a) (a)
Delete Sexp Forwards
Expect
(|2) (|1) (|) (a)
Actual
(a) (a) (|) (a)
Delete Sexp Backwards only deletes at primary cursor, loses the others
Before
(a|2) (a|1) (a|) (a)
Delete Sexp Backwards
Expect
(|2) (|1) (|) (a)
Actual
(a) (a) (|) (a)
Almost done with the ones posted so far. The text notation format in which you've posted these has made it very easy to test driven develop.
Along the way I learned:
Update:
Made the above pass. Added a docToTextNotation
unit test debugging helper and added test for it.
Now just making sure the changes I made are actually legible lol.
It's been interesting having to calculate these offsets and stuff, haven't done much like this before.
A question for @PEZ et al.:
Multicursor copy or "kill while adding to clipboard" is tricky. I'm not exactly sure how vscode does it natively, but if you have n cursors and copy text per cursor, and then paste at a later point with exactly n cursors, the cursors paste according to the original corresponding cursor's location. However, if you do not have exactly n cursors, the total sum of copied text is pasted at each cursor. For now I'm copying only the first (primary) cursor's content. Will have to see how that goes after
Stellar work, @riotrah! I can't thank you enough. 🙏 ❤️
Made the above pass. Added a docToTextNotation unit test debugging helper and added test for it.
So awesome! I made a user command from it. See updated issue description.
Actions that reduce the number of characters in the document - eg deletions - are not so trivial to make multi cursor compatible, as the document shortens each deletion!
😄 Happy you have discovered that it is easier if you work from the end of the document. (Not saying that it gets easy, but anyway.)
The next level of this is when edits overlap, like:
(|(a :a) (|1b :b))
Raise sexp
Now what?
In the latest build nothing happens, which might be the right call, and mean that you have thought of this.
Multicursor copy or "kill while adding to clipboard" is tricky.
Indeed! I think what you do makes sense for now. Add the behaviour to the paredit.md
doc, if you haven't.
Used this build all day at work today. Totally useful, even though some quirks remain of course. Here's one.
Expand selection when all text in a list is selected, doesn't select the list. It selects the opening paren:
Before
(|a|)
Expand Selection
Expected
|(a)|
Actual
|(|a)
This bug is now famous from this video: https://www.youtube.com/watch?v=Sy3arG-Degw 😄
Can TokenCursors (or any other API) tell us how "deep" a cursor or the form it's in is? That way, for Raise, we should go in order of cursor depth. It's not as efficient as short circuiting by doing shallower overlapping form raises first, but it's easier to implement and read, and is logically accurate.
For example, in the given example, the deepest symbol/form to raise is the b
at |1b
. We'd raise that first to get (|(a :a) b)
. Then we'd run it for the (a :a)
at |(a :a)
, which would give us the final output of (a :a)
.
Calva Highlight is doing this kind of work continuously. But only on visible forms, so maybe it's not the place to look...
Maybe just do cursorUp until at the top, with each cursor?
Maybe we can factor out the thing from Calva Highlight and run it on demand...
Paredit Delete Backward does not move cursor inside list when used from adjacent after the list:
Before
()|
Paredit Delete Backward
Expected
(|)
Actual
()|
We have the same error with Delete Forward.
@riotrah Did you remove the cursor contexts without updating the Paredit commands to handle it instead? 😄
Forward Sexp moves cursor out of line comment instead of moving by word:
Before
a§|; a b c§d e
Forward Sexp
Expected
a§;| a b c§d e
Actual
a§; a b c§d| e
Multi-cursor Paredit Delete Backward destroys structure when a cursor is at the beginning of a list:
Before
(a|)§(|1)
Paredit Delete Backward
Expected
(|)§|1
Actual
(|)§|1)
As well as:
Before
(|)§(|1)
Paredit Delete Backward
Expected
|§|1
Actual
|)§|1)
We have the same error with Delete Forward.
Now we are entering into tricky territory, indeed. Post-edit formatting! Paredit editing commands "spawns of” a formatting of the text after the editing has happened. But the formatter is not multi-cursor aware, so we loose all but the primary cursor after an edit. Illustrating here with Barf forward:
https://user-images.githubusercontent.com/30010/162610054-27a7221a-5c44-449c-b5e1-85b9a67c814c.mp4
Copying the before, expected, actual text-notation in here. Note that they can't be straightforwardly translated to unit tests because currently our Paredit unit tests do not capture the post-formatting step.
Before
([|a§ b])§([|1a§ b])
Barf forward
Expected
([|a]§ b)§([|1a]§ b)
Actual
([|a]§ b)§([a]§ b)
Calva checks if the formatter has changed the document and won't apply the changes if there is no change, so this retains the cursors:
https://user-images.githubusercontent.com/30010/162610582-206882d5-24c0-4f32-8a55-763508dd4a68.mp4
Before
([|a b])§([|1a b])
Barf forward
Expected
([|a] b)§([|1a] b)
✅
Some options for the formatting problem:
Splice sexp misplaces cursors when there more than one
Before
(|a)§(|1b)
Splice sexp
Expected
|a§|1b
Actual
|a§b|1
That is what I see in VS Code when I do this. In the unit tests I get even weirder results... And it get's weirder (with some pattern to it) with increasing amount of cursors. I've added failing tests and pointed out the weirdness I see in comments.
Wrap around commands only wraps primary cursor and loses the other cursors
Before
|a§|1b
Wrap around ()
Expected
(|a)§(|1b)
Actual
(|a)§b
Again there is a weird difference between what happens in VS Code and what I see in the unit tests...
Some interesting stuff in here, we are indeed entering tricky territory haha!
Will look into
Delete backward does not move into list from behind closing bracket
Before
()|
Delete backward
Expected
(|)
Actual
()|
The unit tests for this pass, though...
@riotrah , I notice that the failing tests I have been adding, now pass. Does that mean that some checkboxes should potentially be ticked in the issue description here. It takes me a lot of time to test things blindly, so some update on what I should be re-testing would be nice!
@PEZ I think I've updated the desc to reflect current local branch. Will push them shortly. Some of them are very strange as you've noted 😅
Multi-cursor Paredit Delete Backward destroys structure when a cursor is at the beginning of a list:
Before
(a|)§(|1)
Paredit Delete Backward
Expected
(|1)§|
Actual
(|)§|1)
Hi @PEZ, I wonder if the cursors in the first Expected are swapped?
Multi-cursor Paredit Delete Backward destroys structure when a cursor is at the beginning of a list:
Before
(a|)§(|1)
Paredit Delete Backward
Expected
(|1)§|
Actual
(|)§|1)
As well as:
Before
(|)§(|1)
Paredit Delete Backward
Expected
|§|1
Actual
|)§|1)
We have the same error with Delete Forward.
What does We have the same error with Delete Forward** mean here? Can you give me a unit test case?
Paredit Delete Backward does not move cursor inside list when used from adjacent after the list:
Before
()|
Paredit Delete Backward
Expected
(|)
Actual
()|
We have the same error with Delete Forward.
What is the "delete forward" equivalent of this test/feature?
Hi @PEZ, I wonder if the cursors in the first Expected are swapped?
Yes, I've updated the comment now.
What does We have the same error with Delete Forward** mean here? Can you give me a unit test case?
It means that the general problem of destroying structure goes for both deleting backwards and forwards. So if I pick your last question about this, it would be:
Before
|()
Paredit Delete Forward
Expected
(|)
Actual
|()
@riotrah is bringing something wonderful to Calva, multi cursor support to Paredit!
The way this beta test will work is that Calva Team members will maintain a checklist of known issues right here and all who participate in the testing can report findings in the comments. See How to test custom VSIX packaged on the Calva wiki if this is unfamiliar to you. (TL;DR: It is super easy.)
This is recorded April 3, 2022, with the build: calva-2.0.263-pull-1606-298af21c.vsix
https://user-images.githubusercontent.com/30010/161421143-7058384e-447d-4da9-b7f2-7dcb00f16e43.mp4
As you can see it is largely working! As you also can see, sometimes it doesn't do the right thing. So this is a call for help testing this to help us find bugs and to help us discover what is the right thing for certain cases.
See Paredit, a Visual Guide for how Calva Paredit works for a single cursor (and to appreciate what an effort this is for @riotrah to pull off, and why the rest of us should help with testing.
Test notation
In the Calva tests for structural navigation and editing we use a special document notation, which is easy to read for both the machine and for us humans:
See this CalvaTV video for tutorial: https://www.youtube.com/watch?v=Sy3arG-Degw
A typical report has
We try to keep the document descriptions as minimal as possible. See the first report in the comments for an example.
There's a command for it
The test VSIX has a command for printing the text notation from the state of the current document.
Which makes creating a report involve these steps:
Now you have the Before and Actual texts in the Output channel Calva says. You only need to add the Expected texts yoursefl.
Reported issues