Skip to content

Commit

Permalink
Merge pull request #3596 from rstudio/bugfix/paste-and-indent
Browse files Browse the repository at this point in the history
provide separate paste, paste and indent commands
  • Loading branch information
kevinushey committed Oct 8, 2018
2 parents 76f44fc + 274780f commit 9925fe5
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 16 deletions.
28 changes: 25 additions & 3 deletions src/gwt/src/org/rstudio/core/rebind/command/ShortcutsEmitter.java
Expand Up @@ -65,6 +65,7 @@ public void generate(SourceWriter writer) throws UnableToCompleteException
String title = childEl.getAttribute("title");
String disableModes = childEl.getAttribute("disableModes");
String handlesEventPropagation = childEl.getAttribute("handlesEventPropagation");
String platform = childEl.getAttribute("platform");

// Use null when we don't have a command associated with the shortcut,
// otherwise refer to the function that returns the command
Expand All @@ -81,7 +82,7 @@ public void generate(SourceWriter writer) throws UnableToCompleteException
{
printShortcut(writer, condition, shortcut,
command, groupName_, title, disableModes,
handlesEventPropagation);
handlesEventPropagation, platform);
}
}
}
Expand Down Expand Up @@ -113,7 +114,8 @@ private void printShortcut(SourceWriter writer,
String shortcutGroup,
String title,
String disableModes,
String handlesEventPropagation) throws UnableToCompleteException
String handlesEventPropagation,
String platform) throws UnableToCompleteException
{
List<Pair<Integer, String>> keys = new ArrayList<Pair<Integer, String>>();
for (String keyCombination : shortcut.split("\\s+"))
Expand Down Expand Up @@ -162,6 +164,20 @@ else if (m.equals("Meta"))
}

// Emit the relevant code registering these shortcuts.
if (!platform.isEmpty())
{
if (platform.equals("desktop"))
{
writer.println("if (org.rstudio.studio.client.application.Desktop.isDesktop()) {");
writer.indent();
}
else
{
writer.println("if (!org.rstudio.studio.client.application.Desktop.isDesktop()) {");
writer.indent();
}
}

if (!condition.isEmpty())
{
writer.println("if (" + condition + ") {");
Expand Down Expand Up @@ -216,6 +232,12 @@ else if (keys.size() == 2)
writer.outdent();
writer.println("}");
}

if (!platform.isEmpty())
{
writer.outdent();
writer.println("}");
}
}

private String toKey(String val)
Expand Down Expand Up @@ -305,4 +327,4 @@ private String elementToString(Element el) throws UnableToCompleteException
private final TreeLogger logger_;
private final Element shortcutsEl_;
private final String groupName_;
}
}
101 changes: 101 additions & 0 deletions src/gwt/src/org/rstudio/studio/client/KeyboardMonitor.java
@@ -0,0 +1,101 @@
/*
* KeyboardMonitor.java
*
* Copyright (C) 2009-18 by RStudio, Inc.
*
* Unless you have received this program directly from RStudio pursuant
* to the terms of a commercial license agreement with RStudio, then
* this program is licensed to you under the terms of version 3 of the
* GNU Affero General Public License. This program is distributed WITHOUT
* ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
* AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
*
*/
package org.rstudio.studio.client;

import org.rstudio.core.client.command.KeyboardShortcut;

import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Event.NativePreviewEvent;
import com.google.inject.Inject;
import com.google.inject.Singleton;

@Singleton
public class KeyboardMonitor
{
@Inject
public KeyboardMonitor()
{
Event.addNativePreviewHandler((NativePreviewEvent preview) -> {

NativeEvent event = preview.getNativeEvent();

if (event.getType().equals("keydown"))
toggleState(event, true);
else if (event.getType().equals("keyup"))
toggleState(event, false);

});
}

public int getModifierValue()
{
return
(isCtrlKeyDown() ? KeyboardShortcut.CTRL : 0) +
(isAltKeyDown() ? KeyboardShortcut.ALT : 0) +
(isShiftKeyDown() ? KeyboardShortcut.SHIFT : 0) +
(isMetaKeyDown() ? KeyboardShortcut.META : 0);

}

public boolean isCtrlKeyDown()
{
return ctrl_;
}

public boolean isAltKeyDown()
{
return alt_;
}

public boolean isShiftKeyDown()
{
return shift_;
}

public boolean isMetaKeyDown()
{
return leftMeta_ || meta_ || rightMeta_;
}

private void toggleState(NativeEvent event, boolean enable)
{
int keyCode = event.getKeyCode();
switch (keyCode)
{
case CTRL: ctrl_ = enable; break;
case ALT: alt_ = enable; break;
case SHIFT: shift_ = enable; break;
case LEFT_META: leftMeta_ = enable; break;
case META: meta_ = enable; break;
case RIGHT_META: rightMeta_ = enable; break;
}
}

private boolean ctrl_;
private boolean alt_;
private boolean shift_;
private boolean meta_;
private boolean leftMeta_;
private boolean rightMeta_;

private static final int CTRL = KeyCodes.KEY_CTRL;
private static final int ALT = KeyCodes.KEY_ALT;
private static final int SHIFT = KeyCodes.KEY_SHIFT;
private static final int LEFT_META = 91;
private static final int META = 92;
private static final int RIGHT_META = 93;
}
Expand Up @@ -242,6 +242,14 @@ void onPasteDummy()
fireEditEvent(EditEvent.TYPE_PASTE);
Desktop.getFrame().clipboardPaste();
}

@Handler
void onPasteAndIndent()
{
fireEditEvent(EditEvent.TYPE_PASTE_AND_INDENT);
Desktop.getFrame().clipboardPaste();
}


@Handler
void onShowLogFiles()
Expand Down
11 changes: 7 additions & 4 deletions src/gwt/src/org/rstudio/studio/client/events/EditEvent.java
Expand Up @@ -38,11 +38,14 @@ public int getType()
private final boolean before_;
private final int type_;

public static final int TYPE_NONE = 0;
public static final int TYPE_CUT = 1;
public static final int TYPE_COPY = 2;
public static final int TYPE_PASTE = 4;
public static final int TYPE_NONE = 0;
public static final int TYPE_CUT = 1;
public static final int TYPE_COPY = 2;
public static final int TYPE_PASTE = 3;
public static final int TYPE_PASTE_AND_INDENT = 4;

public static final EditEvent NONE = new EditEvent(false, TYPE_NONE);

// Boilerplate ----
public interface Handler extends EventHandler
{
Expand Down
Expand Up @@ -34,6 +34,8 @@ well as menu structures (for main menu and popup menus).
This is primarily used by commands which may be active and dispatched to,
but opt not to handle the event, thereby allowing the browser default
behavior in response to the pressed key.
@platform: The platform (desktop or server) where this should be registered.
By default, commands are registered on all platforms.
-->
<commands>
<menu id="mainMenu" vertical="false">
Expand Down Expand Up @@ -787,6 +789,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" platform="desktop" if="!org.rstudio.core.client.BrowseCap.isMacintosh()"/>
<shortcut refid="pasteAndIndent" value="Meta+Shift+V" platform="desktop" if="org.rstudio.core.client.BrowseCap.isMacintosh()"/>
</shortcutgroup>
<shortcutgroup name="Console">
<shortcut refid="consoleClear" value="Ctrl+L" disableModes="emacs"/>
Expand Down Expand Up @@ -3004,6 +3008,10 @@ well as menu structures (for main menu and popup menus).
menuLabel="_Paste"
rebindable="false"/>

<cmd id="pasteAndIndent"
menuLabel="_Paste and Indent"
rebindable="false"/>

<cmd id="yankBeforeCursor"
label="Yank Before Cursor"
context="editor"/>
Expand Down
Expand Up @@ -506,6 +506,7 @@
public abstract AppCommand cutDummy();
public abstract AppCommand copyDummy();
public abstract AppCommand pasteDummy();
public abstract AppCommand pasteAndIndent();

// Placeholder for most recently used files
public abstract AppCommand mru0();
Expand Down
Expand Up @@ -62,6 +62,7 @@
import org.rstudio.core.client.regex.Pattern;
import org.rstudio.core.client.resources.StaticDataResource;
import org.rstudio.core.client.widget.DynamicIFrame;
import org.rstudio.studio.client.KeyboardMonitor;
import org.rstudio.studio.client.RStudioGinjector;
import org.rstudio.studio.client.application.Desktop;
import org.rstudio.studio.client.application.events.EventBus;
Expand All @@ -71,6 +72,7 @@
import org.rstudio.studio.client.common.filetypes.DocumentMode;
import org.rstudio.studio.client.common.filetypes.TextFileType;
import org.rstudio.studio.client.common.filetypes.DocumentMode.Mode;
import org.rstudio.studio.client.events.EditEvent;
import org.rstudio.studio.client.server.Void;
import org.rstudio.studio.client.workbench.MainWindowObject;
import org.rstudio.studio.client.workbench.commands.Commands;
Expand Down Expand Up @@ -341,13 +343,22 @@ public void onPaste(PasteEvent event)

final Position start = getSelectionStart();

Scheduler.get().scheduleDeferred(new ScheduledCommand()
Scheduler.get().scheduleFinally(new ScheduledCommand()
{
@Override
public void execute()
{
Range range = Range.fromPoints(start, getSelectionEnd());
indentPastedRange(range);
boolean reindent =
activeEditEvent_.getType() == EditEvent.TYPE_PASTE_AND_INDENT ||
monitor_.isShiftKeyDown();

reindent ^= uiPrefs_.reindentOnPaste().getValue();

if (reindent)
{
Range range = Range.fromPoints(start, getSelectionEnd());
indentPastedRange(range);
}
}
});
}
Expand Down Expand Up @@ -435,6 +446,20 @@ public void onFocus(FocusEvent event)
}
});

events_.addHandler(
EditEvent.TYPE,
new EditEvent.Handler()
{
@Override
public void onEdit(EditEvent event)
{
if (event.isBeforeEdit())
activeEditEvent_ = event;
else
activeEditEvent_ = EditEvent.NONE;
}
});

events_.addHandler(
AceEditorCommandEvent.TYPE,
new AceEditorCommandEvent.Handler()
Expand Down Expand Up @@ -623,12 +648,8 @@ public void insertPipeOperator()

private void indentPastedRange(Range range)
{
if (fileType_ == null ||
!fileType_.canAutoIndent() ||
!RStudioGinjector.INSTANCE.getUIPrefs().reindentOnPaste().getValue())
{
if (fileType_ == null || !fileType_.canAutoIndent())
return;
}

String firstLinePrefix = getSession().getTextRange(
Range.fromPoints(Position.create(range.getStart().getRow(), 0),
Expand Down Expand Up @@ -672,13 +693,15 @@ void initialize(CodeToolsServerOperations server,
UIPrefs uiPrefs,
CollabEditor collab,
Commands commands,
EventBus events)
EventBus events,
KeyboardMonitor monitor)
{
server_ = server;
uiPrefs_ = uiPrefs;
collab_ = collab;
commands_ = commands;
events_ = events;
monitor_ = monitor;
}

public TextFileType getFileType()
Expand Down Expand Up @@ -4103,6 +4126,7 @@ public void execute(double timestamp)
private CollabEditor collab_;
private Commands commands_;
private EventBus events_;
private KeyboardMonitor monitor_;
private TextFileType fileType_;
private boolean passwordMode_;
private boolean useEmacsKeybindings_ = false;
Expand All @@ -4123,6 +4147,7 @@ public void execute(double timestamp)
private int scrollTarget_ = 0;
private HandlerRegistration scrollCompleteReg_;
private final AceEditorMixins mixins_;
private EditEvent activeEditEvent_ = EditEvent.NONE;

private static final ExternalJavaScriptLoader getLoader(StaticDataResource release)
{
Expand Down

0 comments on commit 9925fe5

Please sign in to comment.