Use ReplState to implement completion in IDE REPL
Consider sucessfully evaluated lines as previous lines when analyzing console file
This commit is contained in:
+5
-3
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -20,7 +20,6 @@ import com.intellij.openapi.components.ServiceManager;
|
|||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.psi.PsiFile;
|
import com.intellij.psi.PsiFile;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.TestOnly;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -50,11 +49,14 @@ public class KotlinScriptDefinitionProvider {
|
|||||||
return findScriptDefinition(psiFile) != null;
|
return findScriptDefinition(psiFile) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestOnly
|
|
||||||
public void addScriptDefinition(@NotNull KotlinScriptDefinition scriptDefinition) {
|
public void addScriptDefinition(@NotNull KotlinScriptDefinition scriptDefinition) {
|
||||||
definitions.add(0, scriptDefinition);
|
definitions.add(0, scriptDefinition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void removeScriptDefinition(@NotNull KotlinScriptDefinition scriptDefinition) {
|
||||||
|
definitions.remove(scriptDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
public void setScriptDefinitions(@NotNull List<KotlinScriptDefinition> definitions) {
|
public void setScriptDefinitions(@NotNull List<KotlinScriptDefinition> definitions) {
|
||||||
this.definitions.clear();
|
this.definitions.clear();
|
||||||
this.definitions.addAll(definitions);
|
this.definitions.addAll(definitions);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -23,8 +23,6 @@ import com.intellij.execution.console.LanguageConsoleBuilder
|
|||||||
import com.intellij.execution.console.LanguageConsoleView
|
import com.intellij.execution.console.LanguageConsoleView
|
||||||
import com.intellij.execution.console.ProcessBackedConsoleExecuteActionHandler
|
import com.intellij.execution.console.ProcessBackedConsoleExecuteActionHandler
|
||||||
import com.intellij.execution.process.OSProcessHandler
|
import com.intellij.execution.process.OSProcessHandler
|
||||||
import com.intellij.execution.process.ProcessAdapter
|
|
||||||
import com.intellij.execution.process.ProcessEvent
|
|
||||||
import com.intellij.execution.runners.AbstractConsoleRunnerWithHistory
|
import com.intellij.execution.runners.AbstractConsoleRunnerWithHistory
|
||||||
import com.intellij.execution.ui.RunContentDescriptor
|
import com.intellij.execution.ui.RunContentDescriptor
|
||||||
import com.intellij.openapi.actionSystem.ActionManager
|
import com.intellij.openapi.actionSystem.ActionManager
|
||||||
@@ -32,6 +30,7 @@ import com.intellij.openapi.actionSystem.AnAction
|
|||||||
import com.intellij.openapi.actionSystem.CommonShortcuts
|
import com.intellij.openapi.actionSystem.CommonShortcuts
|
||||||
import com.intellij.openapi.actionSystem.DefaultActionGroup
|
import com.intellij.openapi.actionSystem.DefaultActionGroup
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
|
import com.intellij.openapi.application.runReadAction
|
||||||
import com.intellij.openapi.command.WriteCommandAction
|
import com.intellij.openapi.command.WriteCommandAction
|
||||||
import com.intellij.openapi.editor.colors.EditorColors
|
import com.intellij.openapi.editor.colors.EditorColors
|
||||||
import com.intellij.openapi.editor.ex.EditorEx
|
import com.intellij.openapi.editor.ex.EditorEx
|
||||||
@@ -43,7 +42,12 @@ import com.intellij.openapi.keymap.KeymapUtil
|
|||||||
import com.intellij.openapi.module.Module
|
import com.intellij.openapi.module.Module
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.util.Disposer
|
import com.intellij.openapi.util.Disposer
|
||||||
|
import com.intellij.openapi.vfs.CharsetToolkit
|
||||||
|
import com.intellij.psi.PsiFile
|
||||||
|
import com.intellij.psi.PsiFileFactory
|
||||||
import com.intellij.psi.PsiManager
|
import com.intellij.psi.PsiManager
|
||||||
|
import com.intellij.psi.impl.PsiFileFactoryImpl
|
||||||
|
import com.intellij.testFramework.LightVirtualFile
|
||||||
import org.jetbrains.annotations.TestOnly
|
import org.jetbrains.annotations.TestOnly
|
||||||
import org.jetbrains.kotlin.console.actions.BuildAndRestartConsoleAction
|
import org.jetbrains.kotlin.console.actions.BuildAndRestartConsoleAction
|
||||||
import org.jetbrains.kotlin.console.actions.KtExecuteCommandAction
|
import org.jetbrains.kotlin.console.actions.KtExecuteCommandAction
|
||||||
@@ -51,9 +55,21 @@ import org.jetbrains.kotlin.console.gutter.ConsoleGutterContentProvider
|
|||||||
import org.jetbrains.kotlin.console.gutter.ConsoleIndicatorRenderer
|
import org.jetbrains.kotlin.console.gutter.ConsoleIndicatorRenderer
|
||||||
import org.jetbrains.kotlin.console.gutter.IconWithTooltip
|
import org.jetbrains.kotlin.console.gutter.IconWithTooltip
|
||||||
import org.jetbrains.kotlin.console.gutter.ReplIcons
|
import org.jetbrains.kotlin.console.gutter.ReplIcons
|
||||||
|
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||||
import org.jetbrains.kotlin.idea.completion.doNotComplete
|
import org.jetbrains.kotlin.idea.caches.resolve.ModuleTestSourceInfo
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.psi.KtScript
|
||||||
|
import org.jetbrains.kotlin.psi.moduleInfo
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyScriptDescriptor
|
||||||
|
import org.jetbrains.kotlin.resolve.repl.ReplState
|
||||||
|
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||||
|
import org.jetbrains.kotlin.script.KotlinScriptDefinitionProvider
|
||||||
|
import org.jetbrains.kotlin.script.ScriptParameter
|
||||||
import java.awt.Color
|
import java.awt.Color
|
||||||
import java.awt.Font
|
import java.awt.Font
|
||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
@@ -68,7 +84,13 @@ class KotlinConsoleRunner(
|
|||||||
title: String,
|
title: String,
|
||||||
path: String?
|
path: String?
|
||||||
) : AbstractConsoleRunnerWithHistory<LanguageConsoleView>(myProject, title, path) {
|
) : AbstractConsoleRunnerWithHistory<LanguageConsoleView>(myProject, title, path) {
|
||||||
|
|
||||||
|
private val replState = ReplState()
|
||||||
|
|
||||||
override fun finishConsole() {
|
override fun finishConsole() {
|
||||||
|
KotlinConsoleKeeper.getInstance(project).removeConsole(consoleView.virtualFile)
|
||||||
|
KotlinScriptDefinitionProvider.getInstance(project).removeScriptDefinition(consoleScriptDefinition)
|
||||||
|
|
||||||
if (ApplicationManager.getApplication().isUnitTestMode) {
|
if (ApplicationManager.getApplication().isUnitTestMode) {
|
||||||
// Ignore super with myConsoleView.setEditable(false)
|
// Ignore super with myConsoleView.setEditable(false)
|
||||||
return
|
return
|
||||||
@@ -99,17 +121,22 @@ class KotlinConsoleRunner(
|
|||||||
val executor = CommandExecutor(this)
|
val executor = CommandExecutor(this)
|
||||||
var compilerHelper: ConsoleCompilerHelper by Delegates.notNull()
|
var compilerHelper: ConsoleCompilerHelper by Delegates.notNull()
|
||||||
|
|
||||||
|
private val consoleScriptDefinition = object : KotlinScriptDefinition {
|
||||||
|
override fun isScript(file: PsiFile) = file.originalFile.virtualFile == consoleView.virtualFile
|
||||||
|
override fun getScriptParameters(scriptDescriptor: ScriptDescriptor) = emptyList<ScriptParameter>()
|
||||||
|
override fun getScriptName(script: KtScript) = Name.identifier("REPL")
|
||||||
|
}
|
||||||
|
|
||||||
override fun createProcess() = cmdLine.createProcess()
|
override fun createProcess() = cmdLine.createProcess()
|
||||||
|
|
||||||
override fun createConsoleView(): LanguageConsoleView? {
|
override fun createConsoleView(): LanguageConsoleView? {
|
||||||
val consoleView = LanguageConsoleBuilder()
|
val builder = LanguageConsoleBuilder()
|
||||||
.gutterContentProvider(ConsoleGutterContentProvider())
|
|
||||||
.build(project, KotlinLanguage.INSTANCE)
|
val consoleView = builder.gutterContentProvider(ConsoleGutterContentProvider()).build(project, KotlinLanguage.INSTANCE)
|
||||||
|
|
||||||
|
|
||||||
consoleView.prompt = null
|
consoleView.prompt = null
|
||||||
|
|
||||||
disableCompletion(consoleView)
|
|
||||||
|
|
||||||
val consoleEditor = consoleView.consoleEditor
|
val consoleEditor = consoleView.consoleEditor
|
||||||
|
|
||||||
setupPlaceholder(consoleEditor)
|
setupPlaceholder(consoleEditor)
|
||||||
@@ -120,9 +147,17 @@ class KotlinConsoleRunner(
|
|||||||
val executeAction = KtExecuteCommandAction(consoleView.virtualFile)
|
val executeAction = KtExecuteCommandAction(consoleView.virtualFile)
|
||||||
executeAction.registerCustomShortcutSet(CommonShortcuts.CTRL_ENTER, consoleView.consoleEditor.component)
|
executeAction.registerCustomShortcutSet(CommonShortcuts.CTRL_ENTER, consoleView.consoleEditor.component)
|
||||||
|
|
||||||
|
KotlinScriptDefinitionProvider.getInstance(project).addScriptDefinition(consoleScriptDefinition)
|
||||||
|
enableCompletion(consoleView)
|
||||||
|
|
||||||
return consoleView
|
return consoleView
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun enableCompletion(consoleView: LanguageConsoleView) {
|
||||||
|
val consoleKtFile = PsiManager.getInstance(project).findFile(consoleView.virtualFile) as? KtFile ?: return
|
||||||
|
consoleKtFile.moduleInfo = ModuleTestSourceInfo(module)
|
||||||
|
}
|
||||||
|
|
||||||
override fun createProcessHandler(process: Process): OSProcessHandler {
|
override fun createProcessHandler(process: Process): OSProcessHandler {
|
||||||
val processHandler = ReplOutputHandler(
|
val processHandler = ReplOutputHandler(
|
||||||
this,
|
this,
|
||||||
@@ -133,11 +168,6 @@ class KotlinConsoleRunner(
|
|||||||
val keeper = KotlinConsoleKeeper.getInstance(project)
|
val keeper = KotlinConsoleKeeper.getInstance(project)
|
||||||
|
|
||||||
keeper.putVirtualFileToConsole(consoleFile, this)
|
keeper.putVirtualFileToConsole(consoleFile, this)
|
||||||
processHandler.addProcessListener(object : ProcessAdapter() {
|
|
||||||
override fun processTerminated(event: ProcessEvent) {
|
|
||||||
keeper.removeConsole(consoleFile)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return processHandler
|
return processHandler
|
||||||
}
|
}
|
||||||
@@ -180,12 +210,6 @@ class KotlinConsoleRunner(
|
|||||||
editor.setPlaceholderAttributes(placeholderAttrs)
|
editor.setPlaceholderAttributes(placeholderAttrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun disableCompletion(consoleView: LanguageConsoleView) {
|
|
||||||
val consoleFile = consoleView.virtualFile
|
|
||||||
val jetFile = PsiManager.getInstance(project).findFile(consoleFile) as? KtFile ?: return
|
|
||||||
jetFile.doNotComplete = true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setupGutters() {
|
fun setupGutters() {
|
||||||
fun configureEditorGutter(editor: EditorEx, color: Color, iconWithTooltip: IconWithTooltip): RangeHighlighter {
|
fun configureEditorGutter(editor: EditorEx, color: Color, iconWithTooltip: IconWithTooltip): RangeHighlighter {
|
||||||
editor.settings.isLineMarkerAreaShown = true // hack to show gutter
|
editor.settings.isLineMarkerAreaShown = true // hack to show gutter
|
||||||
@@ -225,4 +249,30 @@ class KotlinConsoleRunner(
|
|||||||
processHandler.destroyProcess()
|
processHandler.destroyProcess()
|
||||||
Disposer.dispose(disposableDescriptor)
|
Disposer.dispose(disposableDescriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun successfulLine(text: String) {
|
||||||
|
runReadAction {
|
||||||
|
val lineNumber = replState.successfulLinesCount + 1
|
||||||
|
val virtualFile =
|
||||||
|
LightVirtualFile("line$lineNumber${KotlinParserDefinition.STD_SCRIPT_EXT}", KotlinLanguage.INSTANCE, text).apply {
|
||||||
|
charset = CharsetToolkit.UTF8_CHARSET
|
||||||
|
}
|
||||||
|
val psiFile = (PsiFileFactory.getInstance(project) as PsiFileFactoryImpl).trySetupPsiForFile(virtualFile, KotlinLanguage.INSTANCE, true, false) as KtFile?
|
||||||
|
?: error("Failed to setup PSI for file:\n$text")
|
||||||
|
|
||||||
|
replState.submitLine(psiFile)
|
||||||
|
psiFile.moduleInfo = ModuleTestSourceInfo(module)
|
||||||
|
val scriptDescriptor = psiFile.script!!.resolveToDescriptor() as? LazyScriptDescriptor ?: error("Failed to analyze line:\n$text")
|
||||||
|
ForceResolveUtil.forceResolveAllContents(scriptDescriptor)
|
||||||
|
replState.lineSuccess(psiFile, scriptDescriptor)
|
||||||
|
|
||||||
|
replState.submitLine(consoleFile) // reset file scope customizer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val consoleFile: KtFile
|
||||||
|
get() {
|
||||||
|
val consoleFile = consoleView.virtualFile
|
||||||
|
return PsiManager.getInstance(project).findFile(consoleFile) as KtFile
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -89,7 +89,7 @@ class ReplOutputHandler(
|
|||||||
"COMPILE_ERROR" -> outputProcessor.highlightCompilerErrors(createCompilerMessages(content))
|
"COMPILE_ERROR" -> outputProcessor.highlightCompilerErrors(createCompilerMessages(content))
|
||||||
"RUNTIME_ERROR" -> outputProcessor.printRuntimeError("${content.trim()}\n")
|
"RUNTIME_ERROR" -> outputProcessor.printRuntimeError("${content.trim()}\n")
|
||||||
"INTERNAL_ERROR" -> outputProcessor.printInternalErrorMessage(content)
|
"INTERNAL_ERROR" -> outputProcessor.printInternalErrorMessage(content)
|
||||||
"SUCCESS" -> Unit
|
"SUCCESS" -> runner.commandHistory.lastUnprocessedEntry()?.entryText?.let { runner.successfulLine(it) }
|
||||||
else -> logError(ReplOutputHandler::class.java, "Unexpected output type:\n$outputType")
|
else -> logError(ReplOutputHandler::class.java, "Unexpected output type:\n$outputType")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user