Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

provide separate paste, paste and indent commands #3596

Merged
merged 4 commits into from Oct 8, 2018

Conversation

kevinushey
Copy link
Contributor

This PR provides for separate [Paste] and [Paste and Reindent] commands. With the PR, Ctrl + V pastes without indent, while Ctrl + Shift + V pastes and reindents. The implementation works with both RStudio Server and RStudio Desktop.

Some open questions if we take this PR:

  1. Do we want to change the default behavior so that Ctrl + V no longer reindents by default?

  2. Should we keep the 'reindent on paste' UI preference, or instead document that one should use Ctrl + Shift + V if they do want to reindent after pasting?

@jjallaire
Copy link
Member

I wonder if people have come to rely on the current behavior much more than they realize? (as it's extremely convenient that things are indented, and at the same time so subtle that you might not even realize it's happening).

So if we took this out from under people there might be a lot of unhappy users. Given this I'd probably prefer that re-indent remain the default and that the Shift variation do it w/o indent.

@kevinushey
Copy link
Contributor Author

That was my concern as well, but I was thinking about having that since it would then match the behavior of other IDEs / editors. That said, perhaps it's best for us to retain the current behavior and allow a shift-paste to perform a paste without indent to avoid breaking user's muscle memory.

@jjallaire
Copy link
Member

Yeah, I think users would be quite surprised at how much fixup they'd end up doing w/ a new default behavior.

@kevinushey
Copy link
Contributor Author

I think this PR is good to go. The existing paste behavior is preserved, and one can now by default use Ctrl + Shift + V to paste without indent.

If the 'paste on indent' UI pref is deselected, then the behavior is reversed: Ctrl + V will paste without indent, while Ctrl + Shift + V will paste and reindent. I think this should hopefully make all camps of users happy.

Copy link
Member

@jmcphers jmcphers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this for 1.2?

@@ -787,6 +787,8 @@ well as menu structures (for main menu and popup menus).
<shortcut refid="showOptions" value="Meta+," if="org.rstudio.core.client.BrowseCap.isMacintosh()"/>
<shortcut refid="projectOptions" value="Shift+Meta+," if="org.rstudio.core.client.BrowseCap.isMacintosh()"/>
<shortcut refid="goToHelp" value="Ctrl+C Ctrl+V" disableModes="default,vim,sublime"/>
<shortcut refid="pasteAndIndent" value="Ctrl+Shift+V" if="!org.rstudio.core.client.BrowseCap.isMacintoshDesktop()"/>
<shortcut refid="pasteAndIndent" value="Meta+Shift+V" if="org.rstudio.core.client.BrowseCap.isMacintoshDesktop()"/>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we also want this on the Mac in server mode?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The intention here was to only ever register these commands in Desktop mode, as the server will 'just do the right thing' without these bindings. (We need to register them explicitly for desktop as otherwise the key combination is ignored)

Perhaps I should make this more clear by adding the notion of a 'desktop' vs. 'server' scoped command binding (as a new XML attribute). Note that combining conditions with && doesn't work as the XML parser complains :-/

activeEditEvent_.getType() == EditEvent.TYPE_PASTE_AND_INDENT ||
monitor_.isShiftKeyDown();

reindent ^= uiPrefs_.reindentOnPaste().getValue();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Elegant use of ^=!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I call it the 'flip-if' operator :)

@@ -4082,6 +4105,7 @@ public void execute(double timestamp)
private CollabEditor collab_;
private Commands commands_;
private EventBus events_;
private KeyboardMonitor monitor_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: could be final

Range range = Range.fromPoints(start, getSelectionEnd());
indentPastedRange(range);
boolean reindent =
activeEditEvent_.getType() == EditEvent.TYPE_PASTE_AND_INDENT ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any risk at all of activeEditEvent_ or uiPrefs_ being null in this function (as paste will break if there is)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

activeEditEvent_ is set to a special 'none' event during initialization and is reset to that after the edit event completes, so it shouldn't ever be null. Similarly, uiPrefs_ is injected on initialization so shouldn't be null.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, that's very reassuring!

@@ -341,13 +343,22 @@ public void onPaste(PasteEvent event)

final Position start = getSelectionStart();

Scheduler.get().scheduleDeferred(new ScheduledCommand()
Scheduler.get().scheduleFinally(new ScheduledCommand()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How much time drift can occur between the time the paste event occurs and the time when the scheduler actually runs this? (wondering if we should sample the modifier key state at the time the event occurs rather than later)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scheduleFinally() basically ensures that the call is run at the end of the current event loop, whereas scheduleDeferred() runs it in the next event loop. This actually make sure the call is run before the current edit event completes, and also removes a visual 'flicker' where pasting would briefly show the un-indented text, and then quickly flash to the re-indented text.

Figuring out the active set of keys here is a bit tricky since Ace handles the actual paste event, then generates its own "paste" signal with the associated text data. For the reason, we do this dance with the KeyboardMonitor to see what modifiers were actually held during the time of paste. (In particular, the browser doesn't report the state of modifier keys as part of the paste event, so we need to explicitly track keydown / keyup events that occur to figure out what modifiers are actually down at the time of paste)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it feels a little weird that we have to be running code constantly in the background to get this right, but since Ace's paste signal doesn't include the originating event I realize it's hard to do better!

@kevinushey
Copy link
Contributor Author

I don't think we need this for v1.2 (I can squash and cherry-pick to v1.3 once we're happy)

@jmcphers
Copy link
Member

jmcphers commented Oct 4, 2018

Yes, given that we're churning paste code (and that's historically been a real minefield, even though this seems pretty safe) I think we should target this for 1.3.

Do we also want Shift to invert the paste with/without indent behavior when pasting is performed with the mouse (via e.g. right-click -> paste, or middle click)?

@kevinushey kevinushey changed the base branch from master to v1.3 October 8, 2018 18:47
@kevinushey kevinushey merged commit 9925fe5 into v1.3 Oct 8, 2018
@kevinushey
Copy link
Contributor Author

Merged into v1.3.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants