Initial support for scratch files
This commit is contained in:
@@ -245,4 +245,8 @@ debugger.field.watchpoints.properties.panel.field.modification.label=Field &modi
|
||||
debugger.field.watchpoints.properties.panel.field.initialization.label=Field &initialization
|
||||
|
||||
# Android Lint
|
||||
android.klint.inspections.group.name=Android Lint for Kotlin
|
||||
android.klint.inspections.group.name=Android Lint for Kotlin
|
||||
|
||||
# Scratch Files
|
||||
scratch.run.button=Run Scratch File
|
||||
scratch.clear.button=Clear results
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.scratch
|
||||
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.PsiWhiteSpace
|
||||
import com.intellij.psi.util.PsiUtil
|
||||
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
||||
import org.jetbrains.kotlin.idea.refactoring.getLineNumber
|
||||
import org.jetbrains.kotlin.idea.refactoring.getLineStartOffset
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtImportDirective
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
|
||||
class KtScratchFile(psiFile: KtFile) : ScratchFile(psiFile) {
|
||||
|
||||
override fun getExpressions(): List<ScratchExpression> {
|
||||
// todo multiple expressions at one line
|
||||
val doc = PsiDocumentManager.getInstance(psiFile.project).getDocument(psiFile) ?: return emptyList()
|
||||
var line = 0
|
||||
val result = arrayListOf<ScratchExpression>()
|
||||
while (line < doc.lineCount) {
|
||||
val start = psiFile.getLineStartOffset(line) ?: continue
|
||||
val elementAtOffset = CodeInsightUtils.getTopmostElementAtOffset(
|
||||
PsiUtil.getElementAtOffset(psiFile, start),
|
||||
start,
|
||||
KtImportDirective::class.java,
|
||||
KtDeclaration::class.java
|
||||
)
|
||||
|
||||
if (elementAtOffset is PsiWhiteSpace) {
|
||||
line = doc.getLineNumber(elementAtOffset.endOffset) + 1
|
||||
continue
|
||||
}
|
||||
|
||||
if (elementAtOffset == null) {
|
||||
line += 1
|
||||
continue
|
||||
}
|
||||
|
||||
result.add(ScratchExpression(elementAtOffset, elementAtOffset.getLineNumber(true), elementAtOffset.getLineNumber(false)))
|
||||
line = elementAtOffset.getLineNumber(false) + 1
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.scratch
|
||||
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.idea.scratch.repl.KtScratchReplExecutor
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
|
||||
class KtScratchFileLanguageProvider: ScratchFileLanguageProvider() {
|
||||
override fun createFile(psiFile: PsiFile): ScratchFile? {
|
||||
return (psiFile as? KtFile)?.let { KtScratchFile(psiFile)}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.scratch
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
|
||||
abstract class ScratchFile(val psiFile: PsiFile) {
|
||||
abstract fun getExpressions(): List<ScratchExpression>
|
||||
}
|
||||
|
||||
data class ScratchExpression(val element: PsiElement, val lineStart: Int, val lineEnd: Int = lineStart)
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.scratch
|
||||
|
||||
import com.intellij.lang.Language
|
||||
import com.intellij.lang.LanguageExtension
|
||||
import com.intellij.openapi.fileTypes.FileType
|
||||
import com.intellij.openapi.fileTypes.LanguageFileType
|
||||
import com.intellij.psi.PsiFile
|
||||
|
||||
abstract class ScratchFileLanguageProvider {
|
||||
abstract fun createFile(psiFile: PsiFile): ScratchFile?
|
||||
|
||||
companion object {
|
||||
private val EXTENSION = LanguageExtension<ScratchFileLanguageProvider>("org.jetbrains.kotlin.scratchFileLanguageProvider")
|
||||
|
||||
fun get(language: Language): ScratchFileLanguageProvider? {
|
||||
return ScratchFileLanguageProvider.EXTENSION.forLanguage(language)
|
||||
}
|
||||
|
||||
fun get(fileType: FileType): ScratchFileLanguageProvider? {
|
||||
return (fileType as? LanguageFileType)?.language?.let { get(it) }
|
||||
}
|
||||
|
||||
fun createFile(psiFile: PsiFile): ScratchFile? {
|
||||
return get(psiFile.language)?.createFile(psiFile)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.scratch
|
||||
|
||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
|
||||
import com.intellij.ide.scratch.ScratchFileService
|
||||
import com.intellij.openapi.components.AbstractProjectComponent
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.fileEditor.FileEditorManagerListener
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.ProjectRootManager
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.NotUnderContentRootModuleInfo
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.productionSourceInfo
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.testSourceInfo
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.moduleInfo
|
||||
|
||||
class ScratchFileModuleInfoProvider(project: Project) : AbstractProjectComponent(project) {
|
||||
|
||||
override fun projectOpened() {
|
||||
myProject.messageBus.connect(myProject).subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, ScratchFileModuleListener())
|
||||
}
|
||||
|
||||
private inner class ScratchFileModuleListener : FileEditorManagerListener {
|
||||
override fun fileOpened(source: FileEditorManager, file: VirtualFile) {
|
||||
if (!file.isValid) return
|
||||
if (!ScratchFileService.isInScratchRoot(file)) return
|
||||
|
||||
val ktFile = PsiManager.getInstance(myProject).findFile(file) as? KtFile ?: return
|
||||
|
||||
getScratchPanel(ktFile)?.let { panel ->
|
||||
ktFile.moduleInfo = getModuleInfo(panel.getModule())
|
||||
|
||||
panel.addModuleListener {
|
||||
ktFile.moduleInfo = getModuleInfo(it)
|
||||
// Drop caches for old module
|
||||
ProjectRootManager.getInstance(myProject).incModificationCount()
|
||||
// Force re-highlighting
|
||||
DaemonCodeAnalyzer.getInstance(myProject).restart(ktFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getModuleInfo(it: Module?) =
|
||||
it?.testSourceInfo() ?: it?.productionSourceInfo() ?: NotUnderContentRootModuleInfo
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.scratch.actions
|
||||
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.scratch.ScratchFileLanguageProvider
|
||||
import org.jetbrains.kotlin.idea.scratch.getScratchPanelFromSelectedEditor
|
||||
|
||||
class ClearScratchAction : AnAction(
|
||||
KotlinBundle.message("scratch.clear.button"),
|
||||
KotlinBundle.message("scratch.clear.button"),
|
||||
AllIcons.Actions.GC
|
||||
) {
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
val project = e.project ?: return
|
||||
val panel = getScratchPanelFromSelectedEditor(project) ?: return
|
||||
val scratchFile = panel.scratchFile
|
||||
|
||||
ScratchFileLanguageProvider.get(scratchFile.psiFile.language)?.getOutputHandler()?.clear(scratchFile)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.scratch.actions
|
||||
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.compiler.CompilerManager
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.scratch.ScratchFileLanguageProvider
|
||||
import org.jetbrains.kotlin.idea.scratch.getScratchPanelFromSelectedEditor
|
||||
|
||||
class RunScratchAction : AnAction(
|
||||
KotlinBundle.message("scratch.run.button"),
|
||||
KotlinBundle.message("scratch.run.button"),
|
||||
AllIcons.Actions.Execute
|
||||
) {
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
val project = e.project ?: return
|
||||
|
||||
val scratchTopPanel = getScratchPanelFromSelectedEditor(project) ?: return
|
||||
val scratchFile = scratchTopPanel.scratchFile
|
||||
|
||||
val isMakeBeforeRun = false // todo use property from panel
|
||||
val isRepl = true //todo use property from panel
|
||||
|
||||
val provider = ScratchFileLanguageProvider.get(scratchFile.psiFile.language) ?: return
|
||||
|
||||
val module = scratchTopPanel.getModule()
|
||||
if (module == null) {
|
||||
return
|
||||
}
|
||||
|
||||
val runnable = r@ {
|
||||
// todo
|
||||
}
|
||||
|
||||
if (isMakeBeforeRun) {
|
||||
CompilerManager.getInstance(project)
|
||||
.make(module) { aborted, errors, _, _ -> if (!aborted && errors == 0) runnable() }
|
||||
} else {
|
||||
runnable()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.scratch
|
||||
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.fileEditor.TextEditor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.idea.scratch.ui.ScratchTopPanel
|
||||
import org.jetbrains.kotlin.psi.UserDataProperty
|
||||
|
||||
fun getEditorWithoutScratchPanel(project: Project, virtualFile: VirtualFile): TextEditor? {
|
||||
val allTextEditors = getAllTextEditors(project, virtualFile)
|
||||
for (editor in allTextEditors) {
|
||||
if (editor.scratchTopPanel != null) return null
|
||||
}
|
||||
return allTextEditors.firstOrNull()
|
||||
}
|
||||
|
||||
fun getEditorWithScratchPanel(project: Project, virtualFile: VirtualFile): Pair<TextEditor, ScratchTopPanel>? {
|
||||
val firstWithPanel = getAllTextEditors(project, virtualFile).firstOrNull { it.scratchTopPanel != null }
|
||||
return firstWithPanel?.let { firstWithPanel to firstWithPanel.scratchTopPanel!! }
|
||||
}
|
||||
|
||||
fun getScratchPanel(psiFile: PsiFile): ScratchTopPanel? {
|
||||
return getAllTextEditors(psiFile.project, psiFile.virtualFile).mapNotNull { it.scratchTopPanel }.firstOrNull()
|
||||
}
|
||||
|
||||
fun getAllEditorsWithScratchPanel(project: Project): List<Pair<TextEditor, ScratchTopPanel>> =
|
||||
FileEditorManager.getInstance(project).allEditors.filterIsInstance<TextEditor>().mapNotNull {
|
||||
val panel = it.scratchTopPanel
|
||||
if (panel != null) it to panel else null
|
||||
}
|
||||
|
||||
fun getScratchPanelFromSelectedEditor(project: Project): ScratchTopPanel? =
|
||||
FileEditorManager.getInstance(project).selectedEditors.asSequence()
|
||||
.filterIsInstance<TextEditor>()
|
||||
.mapNotNull { it.scratchTopPanel }
|
||||
.firstOrNull()
|
||||
|
||||
private fun getAllTextEditors(project: Project, virtualFile: VirtualFile) =
|
||||
FileEditorManager.getInstance(project).getAllEditors(virtualFile).filterIsInstance<TextEditor>().asSequence()
|
||||
|
||||
fun TextEditor.addScratchPanel(panel: ScratchTopPanel) {
|
||||
scratchTopPanel = panel
|
||||
FileEditorManager.getInstance(panel.scratchFile.psiFile.project).addTopComponent(this, panel)
|
||||
}
|
||||
|
||||
fun TextEditor.removeScratchPanel(panel: ScratchTopPanel) {
|
||||
scratchTopPanel = null
|
||||
FileEditorManager.getInstance(panel.scratchFile.psiFile.project).removeTopComponent(this, panel)
|
||||
}
|
||||
|
||||
private var TextEditor.scratchTopPanel: ScratchTopPanel? by UserDataProperty<TextEditor, ScratchTopPanel>(Key.create("scratch.panel"))
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.scratch.ui
|
||||
|
||||
import com.intellij.ide.scratch.ScratchFileService
|
||||
import com.intellij.openapi.components.AbstractProjectComponent
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.fileEditor.FileEditorManagerListener
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import org.jetbrains.kotlin.idea.scratch.*
|
||||
|
||||
class ScratchFileHook(project: Project) : AbstractProjectComponent(project) {
|
||||
|
||||
override fun projectOpened() {
|
||||
myProject.messageBus.connect(myProject).subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, ScratchEditorListener())
|
||||
}
|
||||
|
||||
override fun projectClosed() {
|
||||
getAllEditorsWithScratchPanel(myProject).forEach { (editor, panel) -> editor.removeScratchPanel(panel) }
|
||||
}
|
||||
|
||||
private inner class ScratchEditorListener : FileEditorManagerListener {
|
||||
private fun isPluggable(file: VirtualFile): Boolean {
|
||||
if (!file.isValid) return false
|
||||
if (!ScratchFileService.isInScratchRoot(file)) return false
|
||||
val psiFile = PsiManager.getInstance(myProject).findFile(file) ?: return false
|
||||
return ScratchFileLanguageProvider.get(psiFile.fileType) != null
|
||||
}
|
||||
|
||||
override fun fileOpened(source: FileEditorManager, file: VirtualFile) {
|
||||
if (!isPluggable(file)) return
|
||||
|
||||
val panel = ScratchTopPanel.createPanel(myProject, file) ?: return
|
||||
getEditorWithoutScratchPanel(myProject, file)?.let { editor ->
|
||||
editor.addScratchPanel(panel)
|
||||
}
|
||||
}
|
||||
|
||||
override fun fileClosed(source: FileEditorManager, file: VirtualFile) {
|
||||
if (!isPluggable(file)) return
|
||||
|
||||
getEditorWithScratchPanel(myProject, file)?.let { (editor, panel) ->
|
||||
editor.removeScratchPanel(panel)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.scratch.ui
|
||||
|
||||
|
||||
import com.intellij.application.options.ModulesComboBox
|
||||
import com.intellij.openapi.actionSystem.ActionManager
|
||||
import com.intellij.openapi.actionSystem.ActionPlaces
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.ui.components.panels.HorizontalLayout
|
||||
import com.intellij.uiDesigner.core.Spacer
|
||||
import org.jetbrains.kotlin.idea.scratch.ScratchFile
|
||||
import org.jetbrains.kotlin.idea.scratch.ScratchFileLanguageProvider
|
||||
import org.jetbrains.kotlin.idea.scratch.actions.ClearScratchAction
|
||||
import org.jetbrains.kotlin.idea.scratch.actions.RunScratchAction
|
||||
import org.jetbrains.kotlin.idea.scratch.getScratchPanel
|
||||
import javax.swing.JComponent
|
||||
import javax.swing.JLabel
|
||||
import javax.swing.JPanel
|
||||
import javax.swing.JSeparator
|
||||
|
||||
val ScratchFile.scratchTopPanel: ScratchTopPanel?
|
||||
get() = getScratchPanel(psiFile).firstOrNull { it.scratchFile == this@scratchTopPanel }
|
||||
|
||||
class ScratchTopPanel private constructor(val scratchFile: ScratchFile) : JPanel(HorizontalLayout(5)) {
|
||||
companion object {
|
||||
fun createPanel(project: Project, virtualFile: VirtualFile): ScratchTopPanel? {
|
||||
val psiFile = PsiManager.getInstance(project).findFile(virtualFile) ?: return null
|
||||
val scratchFile = ScratchFileLanguageProvider.createFile(psiFile) ?: return null
|
||||
return ScratchTopPanel(scratchFile)
|
||||
}
|
||||
}
|
||||
|
||||
private val moduleChooser: ModulesComboBox
|
||||
|
||||
init {
|
||||
add(createActionsToolbar())
|
||||
add(JSeparator())
|
||||
add(JLabel("Use classpath of module: "))
|
||||
moduleChooser = createModuleChooser(scratchFile.psiFile.project)
|
||||
add(moduleChooser)
|
||||
add(Spacer())
|
||||
}
|
||||
|
||||
fun getModule(): Module? = moduleChooser.selectedModule
|
||||
|
||||
fun addModuleListener(f: (Module) -> Unit) {
|
||||
moduleChooser.addActionListener {
|
||||
moduleChooser.selectedModule?.let { f(it) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun createActionsToolbar(): JComponent {
|
||||
val toolbarGroup = DefaultActionGroup().apply {
|
||||
add(RunScratchAction())
|
||||
addSeparator()
|
||||
add(ClearScratchAction())
|
||||
}
|
||||
|
||||
return ActionManager.getInstance().createActionToolbar(ActionPlaces.EDITOR_TOOLBAR, toolbarGroup, true).component
|
||||
}
|
||||
|
||||
private fun createModuleChooser(project: Project): ModulesComboBox {
|
||||
return ModulesComboBox().apply {
|
||||
fillModules(project)
|
||||
selectedIndex = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,11 @@
|
||||
|
||||
<extensionPoint qualifiedName="org.jetbrains.kotlin.highlighterExtension"
|
||||
interface="org.jetbrains.kotlin.idea.highlighter.HighlighterExtension"/>
|
||||
|
||||
<extensionPoint name="scratchFileLanguageProvider" beanClass="com.intellij.lang.LanguageExtensionPoint">
|
||||
<with attribute="implementationClass" implements="org.jetbrains.kotlin.idea.scratch.ScratchFileLanguageProvider"/>
|
||||
</extensionPoint>
|
||||
|
||||
<extensionPoint qualifiedName="org.jetbrains.kotlin.binaryExtension"
|
||||
interface="org.jetbrains.kotlin.idea.util.KotlinBinaryExtension"/>
|
||||
<extensionPoint qualifiedName="org.jetbrains.kotlin.facetValidatorCreator"
|
||||
@@ -48,5 +53,7 @@
|
||||
<idePlatformSupport implementation="org.jetbrains.kotlin.caches.resolve.JvmPlatformSupport"/>
|
||||
<idePlatformSupport implementation="org.jetbrains.kotlin.caches.resolve.JsPlatformSupport"/>
|
||||
<idePlatformSupport implementation="org.jetbrains.kotlin.caches.resolve.CommonPlatformSupport"/>
|
||||
|
||||
<scratchFileLanguageProvider language="kotlin" implementationClass="org.jetbrains.kotlin.idea.scratch.KtScratchFileLanguageProvider"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
|
||||
@@ -52,6 +52,12 @@
|
||||
<interface-class>org.jetbrains.kotlin.idea.completion.CompletionBindingContextProvider</interface-class>
|
||||
<implementation-class>org.jetbrains.kotlin.idea.completion.CompletionBindingContextProvider</implementation-class>
|
||||
</component>
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.kotlin.idea.scratch.ui.ScratchFileHook</implementation-class>
|
||||
</component>
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.kotlin.idea.scratch.ScratchFileModuleInfoProvider</implementation-class>
|
||||
</component>
|
||||
</project-components>
|
||||
|
||||
<application-components>
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import kotlin.collections.ArraysKt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind;
|
||||
@@ -361,9 +362,9 @@ public class CodeInsightUtils {
|
||||
|
||||
|
||||
@Nullable
|
||||
public static <T> T getTopmostElementAtOffset(@NotNull PsiElement element, int offset, @NotNull Class<T> klass) {
|
||||
public static <T> T getTopmostElementAtOffset(@NotNull PsiElement element, int offset, @NotNull Class<? extends T>... classes) {
|
||||
T lastElementOfType = null;
|
||||
if (klass.isInstance(element)) {
|
||||
if (anyIsInstance(element, classes)) {
|
||||
lastElementOfType = (T) element;
|
||||
}
|
||||
do {
|
||||
@@ -371,7 +372,7 @@ public class CodeInsightUtils {
|
||||
if (parent == null || (parent.getTextOffset() < offset) || parent instanceof KtBlockExpression) {
|
||||
break;
|
||||
}
|
||||
if (klass.isInstance(parent)) {
|
||||
if (anyIsInstance(parent, classes)) {
|
||||
lastElementOfType = (T) parent;
|
||||
}
|
||||
element = parent;
|
||||
@@ -380,4 +381,8 @@ public class CodeInsightUtils {
|
||||
|
||||
return lastElementOfType;
|
||||
}
|
||||
|
||||
private static <T> boolean anyIsInstance(PsiElement finalElement, @NotNull Class<? extends T>[] klass) {
|
||||
return ArraysKt.any(klass, aClass -> aClass.isInstance(finalElement));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,7 +321,10 @@ fun PsiFile.getLineStartOffset(line: Int): Int? {
|
||||
val startOffset = doc.getLineStartOffset(line)
|
||||
val element = findElementAt(startOffset) ?: return startOffset
|
||||
|
||||
return PsiTreeUtil.skipSiblingsForward(element, PsiWhiteSpace::class.java, PsiComment::class.java)?.startOffset ?: startOffset
|
||||
if (element is PsiWhiteSpace || element is PsiComment) {
|
||||
return PsiTreeUtil.skipSiblingsForward(element, PsiWhiteSpace::class.java, PsiComment::class.java)?.startOffset ?: startOffset
|
||||
}
|
||||
return startOffset
|
||||
}
|
||||
|
||||
return null
|
||||
|
||||
Reference in New Issue
Block a user