mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-10-01 17:03:12 +07:00
IDEA-217039 custom commands handling for Terminal: provide tooltip and command highlighting
GitOrigin-RevId: 06934d52a02b9eee6988f1d2b5ef0e3dbcf8ec18
This commit is contained in:
committed by
intellij-monorepo-bot
parent
c5f20887ba
commit
3d3767cc38
@@ -101,7 +101,6 @@ public class JBTerminalPanel extends TerminalPanel implements FocusListener, Ter
|
||||
private final TerminalEventDispatcher myEventDispatcher = new TerminalEventDispatcher();
|
||||
private final JBTerminalSystemSettingsProviderBase mySettingsProvider;
|
||||
private final TerminalEscapeKeyListener myEscapeKeyListener;
|
||||
private final List<Consumer<KeyEvent>> myPostProcessKeyEventConsumers = new CopyOnWriteArrayList<>();
|
||||
private final List<Consumer<KeyEvent>> myPreKeyEventConsumers = new CopyOnWriteArrayList<>();
|
||||
|
||||
private List<AnAction> myActionsToSkip;
|
||||
@@ -200,10 +199,6 @@ public class JBTerminalPanel extends TerminalPanel implements FocusListener, Ter
|
||||
myPreKeyEventConsumers.add(preKeyEventHandler);
|
||||
}
|
||||
|
||||
public void addPostProcessKeyEventHandler(@NotNull Consumer<KeyEvent> preKeyEventHandler) {
|
||||
myPostProcessKeyEventConsumers.add(preKeyEventHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupAntialiasing(Graphics graphics) {
|
||||
UIUtil.setupComposite((Graphics2D)graphics);
|
||||
@@ -369,10 +364,6 @@ public class JBTerminalPanel extends TerminalPanel implements FocusListener, Ter
|
||||
}
|
||||
dispatchEvent(e);
|
||||
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
myPostProcessKeyEventConsumers.forEach(postProcessConsumer -> postProcessConsumer.accept(((KeyEvent)e)));
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -16,7 +16,7 @@ interface TerminalShellCommandHandler {
|
||||
@JvmStatic
|
||||
val EP = ExtensionPointName.create<TerminalShellCommandHandler>("com.intellij.terminal.shellCommandHandler")
|
||||
|
||||
fun isAvailable(project: Project, command: String): Boolean {
|
||||
fun matches(project: Project, command: String): Boolean {
|
||||
if (Experiments.getInstance().isFeatureEnabled("terminal.shell.command.handling")) {
|
||||
return EP.extensionList.any { it.isAvailable(project, command) }
|
||||
}
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
<experimentalFeature id="terminal.shell.command.handling" percentOfUsers="0"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.plugins.terminal">
|
||||
<localTerminalCustomizer implementation="org.jetbrains.plugins.terminal.TerminalCommandHandlerCustomizer"/>
|
||||
</extensions>
|
||||
|
||||
<extensionPoints>
|
||||
<extensionPoint qualifiedName="org.jetbrains.plugins.terminal.localTerminalCustomizer"
|
||||
interface="org.jetbrains.plugins.terminal.LocalTerminalCustomizer"/>
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
package org.jetbrains.plugins.terminal;
|
||||
|
||||
import com.google.common.base.Ascii;
|
||||
import com.intellij.ide.util.PropertiesComponent;
|
||||
import com.intellij.notification.*;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -10,14 +12,17 @@ import com.intellij.terminal.JBTerminalPanel;
|
||||
import com.intellij.terminal.JBTerminalSystemSettingsProviderBase;
|
||||
import com.intellij.terminal.JBTerminalWidget;
|
||||
import com.intellij.terminal.TerminalShellCommandHandler;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.jediterm.terminal.*;
|
||||
import com.jediterm.terminal.model.CharBuffer;
|
||||
import com.jediterm.terminal.model.TerminalLine;
|
||||
import com.jediterm.terminal.model.TerminalTextBuffer;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.terminal.arrangement.TerminalWorkingDirectoryManager;
|
||||
|
||||
import javax.swing.event.HyperlinkEvent;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.io.IOException;
|
||||
@@ -30,6 +35,9 @@ public class ShellTerminalWidget extends JBTerminalWidget {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(ShellTerminalWidget.class);
|
||||
|
||||
@NonNls String TERMINAL_CUSTOM_COMMANDS_GOT_IT = "TERMINAL_CUSTOM_COMMANDS_GOT_IT";
|
||||
@NonNls private static final String GOT_IT = "got_it";
|
||||
|
||||
private final Project myProject;
|
||||
private boolean myEscapePressed = false;
|
||||
private String myCommandHistoryFilePath;
|
||||
@@ -42,32 +50,71 @@ public class ShellTerminalWidget extends JBTerminalWidget {
|
||||
@NotNull Disposable parent) {
|
||||
super(project, settingsProvider, parent);
|
||||
myProject = project;
|
||||
Alarm alarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD);
|
||||
((JBTerminalPanel)getTerminalPanel()).addPreKeyEventHandler(e -> {
|
||||
if (e.getID() != KeyEvent.KEY_PRESSED) return;
|
||||
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
|
||||
myEscapePressed = true;
|
||||
}
|
||||
if (myPromptUpdateNeeded) {
|
||||
if (myPromptUpdateNeeded) {
|
||||
myPrompt = getLineAtCursor();
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.info("Guessed shell prompt: " + myPrompt);
|
||||
}
|
||||
myPromptUpdateNeeded = false;
|
||||
}
|
||||
|
||||
alarm.cancelAllRequests();
|
||||
alarm.addRequest(() -> {
|
||||
highlightMatchedCommand(project);
|
||||
}, 50);
|
||||
|
||||
if (e.getKeyCode() == KeyEvent.VK_ENTER && (e.getModifiers() & InputEvent.CTRL_MASK) != 0) {
|
||||
handleShellCommandBeforeExecution(getTypedShellCommand(), e);
|
||||
executeMatchedCommand(getTypedShellCommand(), e);
|
||||
myPromptUpdateNeeded = true;
|
||||
myEscapePressed = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
JBTerminalPanel terminalPanel = (JBTerminalPanel)getTerminalPanel();
|
||||
terminalPanel.addPostProcessKeyEventHandler(e -> {
|
||||
String command = getTypedShellCommand();
|
||||
SubstringFinder.FindResult result =
|
||||
TerminalShellCommandHandler.Companion.isAvailable(project, command) ? searchMatchedCommand(command, true) : null;
|
||||
terminalPanel.setFindResult(result);
|
||||
});
|
||||
private void highlightMatchedCommand(@NotNull Project project) {
|
||||
if (!PropertiesComponent.getInstance(project).getBoolean(TerminalCommandHandlerCustomizer.TERMINAL_CUSTOM_COMMAND_EXECUTION, true)) {
|
||||
getTerminalPanel().setFindResult(null);
|
||||
return;
|
||||
}
|
||||
|
||||
//highlight matched command
|
||||
String command = getTypedShellCommand();
|
||||
SubstringFinder.FindResult result =
|
||||
TerminalShellCommandHandler.Companion.matches(project, command) ? searchMatchedCommand(command, true) : null;
|
||||
getTerminalPanel().setFindResult(result);
|
||||
|
||||
//show notification
|
||||
if (PropertiesComponent.getInstance(project).getBoolean(TERMINAL_CUSTOM_COMMANDS_GOT_IT, false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (result != null) {
|
||||
String content =
|
||||
"Commands that have particular highlighting can be interpreted and launched by IDE in a smart way.<br>" +
|
||||
"Press <b>Ctrl+Enter</b> to try it or <b>Enter</b> to execute it in the console as usual.<br>" +
|
||||
"Any time you can turn it on/off on Preferences | Tools | Terminal.<br>" +
|
||||
"<a href=\"" + GOT_IT + "\"/>Got it!</a>";
|
||||
|
||||
new SingletonNotificationManager(
|
||||
NotificationGroup.toolWindowGroup("TerminalCustomCommandsHandling", TerminalToolWindowFactory.TOOL_WINDOW_ID),
|
||||
NotificationType.INFORMATION, null)
|
||||
.notify("Smart commands execution", content, project,
|
||||
new NotificationListener.Adapter() {
|
||||
@Override
|
||||
protected void hyperlinkActivated(@NotNull Notification notification, @NotNull HyperlinkEvent e) {
|
||||
if (GOT_IT.equals(e.getDescription())) {
|
||||
PropertiesComponent.getInstance(project)
|
||||
.setValue(TERMINAL_CUSTOM_COMMANDS_GOT_IT, true, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -96,12 +143,12 @@ public class ShellTerminalWidget extends JBTerminalWidget {
|
||||
return finder.getResult();
|
||||
}
|
||||
|
||||
private void handleShellCommandBeforeExecution(@NotNull String shellCommand, @NotNull KeyEvent enterEvent) {
|
||||
private void executeMatchedCommand(@NotNull String shellCommand, @NotNull KeyEvent enterEvent) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("typed shell command to execute: " + shellCommand);
|
||||
}
|
||||
|
||||
if (!TerminalShellCommandHandler.Companion.isAvailable(myProject, shellCommand)) {
|
||||
if (!TerminalShellCommandHandler.Companion.matches(myProject, shellCommand)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.plugins.terminal
|
||||
|
||||
import com.intellij.ide.util.PropertiesComponent
|
||||
import com.intellij.openapi.options.BeanConfigurable
|
||||
import com.intellij.openapi.options.Configurable
|
||||
import com.intellij.openapi.options.UnnamedConfigurable
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Getter
|
||||
import com.intellij.openapi.util.Setter
|
||||
|
||||
class TerminalCommandHandlerCustomizer : LocalTerminalCustomizer() {
|
||||
override fun getConfigurable(project: Project?): UnnamedConfigurable? {
|
||||
if (project == null) {
|
||||
return super.getConfigurable(project)
|
||||
}
|
||||
return TerminalCommandHandlerConfigurable(project)
|
||||
}
|
||||
|
||||
class TerminalCommandHandlerOptions(val project: Project) {
|
||||
var enabled: Boolean
|
||||
get() = PropertiesComponent.getInstance(project).getBoolean(TERMINAL_CUSTOM_COMMAND_EXECUTION, true)
|
||||
set(value) {
|
||||
PropertiesComponent.getInstance(project).setValue(TERMINAL_CUSTOM_COMMAND_EXECUTION, value, true)
|
||||
}
|
||||
}
|
||||
|
||||
class TerminalCommandHandlerConfigurable(project: Project) :
|
||||
BeanConfigurable<TerminalCommandHandlerOptions>(TerminalCommandHandlerOptions(project)), Configurable {
|
||||
init {
|
||||
checkBox("Smart commands handling",
|
||||
Getter<Boolean> { instance!!.enabled },
|
||||
Setter<Boolean> { instance!!.enabled = it })
|
||||
}
|
||||
|
||||
override fun getDisplayName(): String {
|
||||
return "TerminalCommandHandler"
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TERMINAL_CUSTOM_COMMAND_EXECUTION = "terminalCustomCommandExecutionTurnOff"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user