CoroutineScope issue
示例:
ShireCoroutineScope.scope(context.project).launch {
val suggestion = StringBuilder()
flow?.cancelWithConsole(context.console)?.cancellable()?.collect { char ->
suggestion.append(char)
invokeLater {
context.console?.print(char, ConsoleViewContentType.NORMAL_OUTPUT)
}
}
postExecute.invoke(suggestion.toString(), null)
}
Data Context
1. 从 AnAction 中获取 DataContext
如果你正在实现一个继承自 AnAction
的动作类,可以通过 AnActionEvent
直接获取 DataContext
。如下所示:
public class MyAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent e) {
DataContext dataContext = e.getDataContext();
// 你可以从 DataContext 获取更多数据
}
}
2. 从一个组件中获取 DataContext
如果你有一个 UI 组件,比如一个按钮,你可以使用 DataManager
来获取该组件的 DataContext
。例如:
JComponent component = ...; // 你的组件
DataContext dataContext = DataManager.getInstance().getDataContext(component);
3. 从当前焦点的组件获取 DataContext
如果你需要从当前焦点的组件获取 DataContext
,可以这样做:
DataContext dataContext = DataManager.getInstance().getDataContextFromFocus().getResult();
4. 使用 PlatformDataKeys
获取 DataContext
后,你可以使用 PlatformDataKeys
来提取特定的数据。例如,获取当前的 Editor
:
Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
Project project = CommonDataKeys.PROJECT.getData(dataContext);
VirtualFile file = CommonDataKeys.VIRTUAL_FILE.getData(dataContext);
5. 存储 Event 的 DataContext
在某些情况下,你可能需要在动作执行之前存储 DataContext
。你可以使用 VariableActionEventDataHolder
来存储数据。例如:
class ShireSonarLintAction : AnAction() {
// ...
override fun actionPerformed(e: AnActionEvent) {
val project = e.project ?: return
VariableActionEventDataHolder.putData(VariableActionEventDataHolder(e.dataContext))
val config = shireActionConfigs(project).firstOrNull() ?: return
ShireRunFileAction.executeShireFile(project, config, null)
}
}
使用 VariableActionEventDataHolder
存储 DataContext
后,你可以在动作执行时获取数据。例如:
fun getCommitWorkflowUi(): CommitWorkflowUi? {
VariableActionEventDataHolder.getData()?.vcsDataContext?.let {
val commitWorkflowUi = it.getData(VcsDataKeys.COMMIT_WORKFLOW_UI)
return commitWorkflowUi as CommitWorkflowUi?
}
val dataContext = DataManager.getInstance().dataContextFromFocus.result
val commitWorkflowUi = dataContext?.getData(VcsDataKeys.COMMIT_WORKFLOW_UI)
return commitWorkflowUi
}
自定义 ContextMenu 位置
普通方式
参考:ShireActionStartupActivity
中的实现,如:attachTerminalAction
方法
private fun attachTerminalAction() {
val actionManager = ActionManager.getInstance()
val toolsMenu = actionManager.getAction("TerminalToolwindowActionGroup") as? DefaultActionGroup ?: return
val action = actionManager.getAction("ShireTerminalAction")
if (!toolsMenu.containsAction(action)) {
toolsMenu.add(action)
}
}
- 从 ActionManager 中获取目标 ActionGroup
- 将自定义 Action 添加到目标 ActionGroup 中
动态方式
对于不对外提供的插件,可以尝试监听是否有对应的事件,诸如 Sonarlint 使用的是 Panel,因此可以监听 Panel 的事件,然后动态添加 Action。
private fun attachSonarLintAction(project: Project) {
project.messageBus.connect().subscribe(ToolWindowManagerListener.TOPIC, SonarLintToolWindowListener(project));
}
对应的 SonarLintToolWindowListener
实现如下:
class SonarLintToolWindowListener(private val project: Project) : ToolWindowManagerListener {
override fun toolWindowShown(toolWindow: ToolWindow) {
if (toolWindow.id != "SonarLint") return
val action = ActionManager.getInstance().getAction("ShireSonarLintAction")
val contentManager = toolWindow.contentManager
val content = contentManager.getContent(0) ?: return
val simpleToolWindowPanel = content.component as? SimpleToolWindowPanel
val actionToolbar = simpleToolWindowPanel?.toolbar?.components?.get(0) as? ActionToolbar ?: return
val actionGroup = actionToolbar.actionGroup as? DefaultActionGroup
if (actionGroup?.containsAction(action) == false) {
actionGroup.add(action)
}
}
}