runConfig就是扩展运行的面板,可添加一个自定义的配置。可扩展的地方如图所示,这个界面点完+号后会有两个扩展点:1、类型-下图左侧红框内;2、配置工厂-比如Docker中会有多个子节点,这些子节点称为工厂;
当点完具体的扩展工厂后,会跳转到创建页面,比如Dockerfile,如下图所示:,扩展点称为:1、运行配置;2、设置编辑器;
一、配置
1、配置类型
“添加”操作后显示的可用配置类型列表,如果想自定义此处内容,需要扩展ConfigurationType接口也可继承ConfigurationTypeBase类,它接受(ID, name, description, and icon) 这几个参数,再通过addFactory()方法来添加配置工厂。然后在plugin.xml中进行配置,大概示例如下:
<configurationType
implementation="GradleExternalTaskConfigurationType"/>
2、配置工厂
所有的运行配置全是由ConfigurationFactory创建并注册给特定的ConfigurationType。一个ConfigurationType可能有多个ConfigurationFactory。需要复写createTemplateConfiguration()方法。当调用createConfiguration()方法创建一个运行配置时实际上也是克隆了模板方法中的内容。
3、运行配置
通过实现RunConfiguration接口、继承RunConfigurationBase类、LocatableConfigurationBase类、ModuleBasedConfiguration类几种方式自定义一个运行配置
4、配置编辑器
RunConfiguration的界面是由SettingsEditor来实现的,它有以下几个重要方法:
- getComponent()方法由 IDE 调用并显示运行配置特定的 UI。
- resetFrom()被调用以丢弃通过该 UI 所做的所有未确认的用户更改。
- applyTo()调用以确认更改,即将当前 UI 状态复制到目标设置对象中。
数据保存:所有配置的数据是由平台的RunnerAndConfigurationSettings类来持久化的,在自定义的RunConfiguration类中可以通过writeExternal()和readExternal()来读取:
- RunManager.createConfiguration():创建一个实例RunnerAndConfigurationSettings。
- RunManager.addConfiguration():通过将其添加到存储在项目中的共享配置列表或存储在工作区文件中的本地配置列表中,使其持久化。
重构更新:当代码有重构时,有时是需要更新配置的,此时就需要RefactoringListenerProvider实现,复写getRefactoringElementListener()方法,这个方法会把被修改的元素封装成一个RefactoringElementListener对象。
右键菜单:建议实现扩展的LocatableConfigurationBase的配置类,否则没有自动全名的功能,右键菜单功能要实现RunConfigurationProducer接口并将其注册为<runConfigurationProducer>,主要实现以下两个方法:
- setupConfigurationFromContext():得到类型的空白配置和包含有关源代码位置的信息ConfigurationContext的上下文(可通过调用getLocation()或访问getPsiLocation())
- isConfigurationFromContext():检查您的类型的指定配置是否是从指定上下文创建的。
二、运行
运行的内部逻辑是这样的,选择一个运行配置后就会创建一个ExecutionEnvironment对象,该对象聚合了执行流程所需的所有设置和选定的ProgramRunner。然后调用ProgramRunner.execute()就会接收执行器和执行环境。
在ProgramRunner.execute()内部,1、首先调用RunProfile.getState()创建一个RunProfileState对象,描述一个即将开始的过程。在此阶段,初始化启动进程所需的命令行参数、环境变量和其他信息;2、然后调用RunProfileState.execute()启动流程,此时会生成一个ProcessHandler的流程处理实现,创建一个console来显示流程输出并返回一个ExecutionResult对象;3、最后通过RunContentBuilder来打开工具窗口显示控制台;
1、Executor
idea默认提供了run、debug、Run with Coverage三个执行者,可通过扩展Executor接口来自定义一个按钮;
2、RunProcess
RunProfile.getState()会返回一个RunProfileState对象,这个对象描述了一个准备启动的进程,包含命令行、当前工作目录和要启动的进程的环境变量等信息,在这里也可以更改一些配置内容。RunProfileState的标准实现类是CommandLineState、GeneralCommandLine、JavaCommandLineState这三个。另外OSProcessHandler类可以监视进程的执行并捕获其输出,调用startNotify()方法来捕获其输出,如果在OSProcessHandler 中实现ProcessTerminatedListener逻辑就可以实时监听了。
3、Display
使用CommandLineState,控制台视图将自动创建并附加到进程的输出,也可以通过TextConsoleBuilderFactory.createBuilder(project).getConsole()创建一个ConsoleView实例,再通过ConsoleView.attachToProcess()将其附加到进程的输出。
在控制台上可用ColoredProcessHandler进行文字改颜色,也可通过CommandLineState.addConsoleFilters()和TextConsoleBuilder.addFilter()添加过滤器查找特定的输出内容再做功能增强,比如增加超链接,常用的工具类RegexpFilter和UrlFilter。
4、CodeRun
使用ProgramRunnerUtil.executeConfiguration(),这个方法接收三个参数:Project、RunnerAndConfigurationSettings、Executor:
- 获取RunnerAndConfigurationSettings:RunManager.getConfigurationSettings(ConfigurationType);
- 获取Executor:直接使用DefaultRunExecutor.getRunExecutorInstance()或或DefaultDebugExecutor.getDebugExecutorInstance()方法;
三、示例
实现的例子如下图所示,添加一个名为Demo的运行类型工厂:
1、注册ConfigurationType
org.jetbrains.sdk.runConfiguration.DemoRunConfigurationType
public class DemoRunConfigurationType implements ConfigurationType {
static final String ID = "DemoRunConfiguration";
@NotNull
@Override
public String getDisplayName() {
return "Demo";
}
@Override
public String getConfigurationTypeDescription() {
return "Demo run configuration type";
}
@Override
public Icon getIcon() {
return AllIcons.General.Information;
}
@NotNull
@Override
public String getId() {
return ID;
}
@Override
public ConfigurationFactory[] getConfigurationFactories() {
return new ConfigurationFactory[]{new DemoConfigurationFactory(this)};
}
}
<extensions defaultExtensionNs="com.intellij">
<configurationType
implementation="org.jetbrains.sdk.runConfiguration.DemoRunConfigurationType"/>
</extensions>
2、实现ConfigurationFactory
- 通过getId()这个方法来绑定的RunConfigurationType。
- 通过getOptionsClass()方法来连接数据存储RunConfigurationOptions
public class DemoConfigurationFactory extends ConfigurationFactory {
protected DemoConfigurationFactory(ConfigurationType type) {
super(type);
}
@Override
public @NotNull String getId() {
return DemoRunConfigurationType.ID;
}
@NotNull
@Override
public RunConfiguration createTemplateConfiguration(@NotNull Project project) {
return new DemoRunConfiguration(project, this, "Demo");
}
@Nullable
@Override
public Class<? extends BaseState> getOptionsClass() {
return DemoRunConfigurationOptions.class;
}
}
扩展RunConfigurationOptions实现settings设置存储。
public class DemoRunConfigurationOptions extends RunConfigurationOptions {
private final StoredProperty<String> myScriptName = string("").provideDelegate(this, "scriptName");
public String getScriptName() {
return myScriptName.getValue(this);
}
public void setScriptName(String scriptName) {
myScriptName.setValue(this, scriptName);
}
}
3、实现RunConfiguration
实现RunConfiguration
public class DemoRunConfiguration extends RunConfigurationBase<DemoRunConfigurationOptions> {
protected DemoRunConfiguration(Project project, ConfigurationFactory factory, String name) {
super(project, factory, name);
}
@NotNull
@Override
protected DemoRunConfigurationOptions getOptions() {
return (DemoRunConfigurationOptions) super.getOptions();
}
public String getScriptName() {
return getOptions().getScriptName();
}
public void setScriptName(String scriptName) {
getOptions().setScriptName(scriptName);
}
@NotNull
@Override
public SettingsEditor<? extends RunConfiguration> getConfigurationEditor() {
return new DemoSettingsEditor();
}
@Override
public void checkConfiguration() {
}
@Nullable
@Override
public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment executionEnvironment) {
return new CommandLineState(executionEnvironment) {
@NotNull
@Override
protected ProcessHandler startProcess() throws ExecutionException {
GeneralCommandLine commandLine = new GeneralCommandLine(getOptions().getScriptName());
OSProcessHandler processHandler = ProcessHandlerFactory.getInstance().createColoredProcessHandler(commandLine);
ProcessTerminatedListener.attach(processHandler);
return processHandler;
}
};
}
}
实现和绑定UI
通过extends SettingsEditor<DemoRunConfiguration> 方式来绑定的RunConfiguration。
public class DemoSettingsEditor extends SettingsEditor<DemoRunConfiguration> {
private JPanel myPanel;
private LabeledComponent<TextFieldWithBrowseButton> myScriptName;
@Override
protected void resetEditorFrom(DemoRunConfiguration demoRunConfiguration) {
myScriptName.getComponent().setText(demoRunConfiguration.getScriptName());
}
@Override
protected void applyEditorTo(@NotNull DemoRunConfiguration demoRunConfiguration) {
demoRunConfiguration.setScriptName(myScriptName.getComponent().getText());
}
@NotNull
@Override
protected JComponent createEditor() {
return myPanel;
}
private void createUIComponents() {
myScriptName = new LabeledComponent<>();
myScriptName.setComponent(new TextFieldWithBrowseButton());
}
}