Skip to content

Commit

Permalink
Basic suggested migration
Browse files Browse the repository at this point in the history
  • Loading branch information
aperfilyev committed May 10, 2021
1 parent 5e34e13 commit dd1fbd5
Show file tree
Hide file tree
Showing 15 changed files with 695 additions and 116 deletions.
6 changes: 6 additions & 0 deletions sqldelight-idea-plugin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ changelog {
path = "$rootDir/CHANGELOG.md"
}

compileKotlin {
kotlinOptions {
freeCompilerArgs = ['-Xjvm-default=enable']
}
}

def isReleaseBuild() {
return VERSION_NAME.contains("SNAPSHOT") == false
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.squareup.sqldelight.intellij

import com.intellij.openapi.fileEditor.FileEditorManagerEvent
import com.intellij.openapi.fileEditor.FileEditorManagerListener
import com.intellij.openapi.fileEditor.TextEditor
import com.intellij.psi.PsiDocumentManager
import com.squareup.sqldelight.core.lang.SqlDelightFile

internal class ActiveEditorChangeListener : FileEditorManagerListener {

override fun selectionChanged(event: FileEditorManagerEvent) {
val editor = (event.oldEditor as TextEditor?)?.editor ?: return
val project = editor.project ?: return
val file = PsiDocumentManager.getInstance(project).getPsiFile(editor.document) as? SqlDelightFile? ?: return

FileGeneratorService.getInstance(project).generateFiles(file)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package com.squareup.sqldelight.intellij

import com.alecstrong.sql.psi.core.SqlAnnotationHolder
import com.alecstrong.sql.psi.core.psi.SqlAnnotatedElement
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.module.ModuleUtil
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Condition
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiErrorElement
import com.intellij.psi.util.PsiTreeUtil
import com.squareup.sqldelight.core.SqlDelightFileIndex
import com.squareup.sqldelight.core.compiler.SqlDelightCompiler
import com.squareup.sqldelight.core.lang.MigrationFile
import com.squareup.sqldelight.core.lang.SqlDelightFile
import com.squareup.sqldelight.core.lang.SqlDelightQueriesFile
import com.squareup.sqldelight.intellij.util.GeneratedVirtualFile
import java.io.PrintStream
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicBoolean

interface FileGeneratorService {
fun generateFiles(file: SqlDelightFile)

companion object {
fun getInstance(project: Project): FileGeneratorService {
return project.getService(FileGeneratorService::class.java)
}
}
}

class FileGeneratorServiceImpl : FileGeneratorService {

private val threadPool = Executors.newScheduledThreadPool(1)

private var filesGenerated = emptyList<VirtualFile>()
set(value) {
(field - value).forEach { it.delete(this) }
field = value
}

private var condition = WriteCondition()

override fun generateFiles(file: SqlDelightFile) {
val module = ModuleUtil.findModuleForFile(file) ?: return
if (!SqlDelightFileIndex.getInstance(module).isConfigured ||
SqlDelightFileIndex.getInstance(module).sourceFolders(file).isEmpty()
) {
return
}

condition.invalidated.set(true)

if (ApplicationManager.getApplication().isUnitTestMode) {
generateSqlDelightCode(file)
return
}

val thisCondition = WriteCondition()
condition = thisCondition
threadPool.schedule(
{
ApplicationManager.getApplication().invokeLater(
{
try {
generateSqlDelightCode(file)
} catch (e: Throwable) {
// IDE generating code should be best effort - source of truth is always the gradle
// build, and its better to ignore the error and try again than crash and require
// the IDE restarts.
e.printStackTrace()
}
},
thisCondition
)
},
1, TimeUnit.SECONDS
)
}

/**
* Attempt to generate the SQLDelight code for the file represented by the view provider.
*/
private fun generateSqlDelightCode(file: SqlDelightFile) {
val module = ModuleUtil.findModuleForFile(file) ?: return
var shouldGenerate = true
val annotationHolder = object : SqlAnnotationHolder {
override fun createErrorAnnotation(element: PsiElement, s: String) {
shouldGenerate = false
}
}

// File is mutable so create a copy that wont be mutated.
val file = file.copy() as SqlDelightFile

shouldGenerate = try {
PsiTreeUtil.processElements(file) { element ->
when (element) {
is PsiErrorElement -> return@processElements false
is SqlAnnotatedElement -> element.annotate(annotationHolder)
}
return@processElements shouldGenerate
}
} catch (e: Throwable) {
// If we encountered an exception while looking for errors, assume it was an error.
false
}

if (shouldGenerate && !ApplicationManager.getApplication().isUnitTestMode) ApplicationManager.getApplication().runWriteAction {
val files = mutableListOf<VirtualFile>()
val fileAppender = { filePath: String ->
val vFile: VirtualFile by GeneratedVirtualFile(filePath, module)
files.add(vFile)
PrintStream(vFile.getOutputStream(this))
}
if (file is SqlDelightQueriesFile) {
SqlDelightCompiler.writeInterfaces(module, file, fileAppender)
} else if (file is MigrationFile) {
SqlDelightCompiler.writeInterfaces(file, fileAppender)
}
this.filesGenerated = files
}
}

private class WriteCondition : Condition<Any> {
var invalidated = AtomicBoolean(false)

override fun value(t: Any?) = invalidated.get()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import com.alecstrong.sql.psi.core.DialectPreset
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.fileEditor.FileEditorManagerListener
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectRootManager
Expand Down Expand Up @@ -67,6 +68,11 @@ class ProjectService(val project: Project) : SqlDelightProjectService, Disposabl
}
}
)

project.messageBus.connect().subscribe(
FileEditorManagerListener.FILE_EDITOR_MANAGER,
ActiveEditorChangeListener()
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,14 @@

package com.squareup.sqldelight.intellij.lang

import com.alecstrong.sql.psi.core.SqlAnnotationHolder
import com.alecstrong.sql.psi.core.psi.SqlAnnotatedElement
import com.intellij.lang.Language
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.module.Module
import com.intellij.openapi.util.Condition
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.FileViewProvider
import com.intellij.psi.FileViewProviderFactory
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiErrorElement
import com.intellij.psi.PsiManager
import com.intellij.psi.SingleRootFileViewProvider
import com.intellij.psi.util.PsiTreeUtil
import com.squareup.sqldelight.core.SqlDelightFileIndex
import com.squareup.sqldelight.core.SqlDelightProjectService
import com.squareup.sqldelight.core.compiler.SqlDelightCompiler
import com.squareup.sqldelight.core.lang.MigrationFile
import com.squareup.sqldelight.core.lang.SqlDelightFile
import com.squareup.sqldelight.core.lang.SqlDelightQueriesFile
import com.squareup.sqldelight.intellij.util.GeneratedVirtualFile
import java.io.PrintStream
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicBoolean
import com.squareup.sqldelight.intellij.FileGeneratorService

class SqlDelightFileViewProviderFactory : FileViewProviderFactory {
override fun createFileViewProvider(
Expand All @@ -49,116 +32,23 @@ class SqlDelightFileViewProviderFactory : FileViewProviderFactory {
manager: PsiManager,
eventSystemEnabled: Boolean
): FileViewProvider {
val module = SqlDelightProjectService.getInstance(manager.project).module(file)
?: return SingleRootFileViewProvider(manager, file, eventSystemEnabled)
return SqlDelightFileViewProvider(manager, file, eventSystemEnabled, language, module)
return SqlDelightFileViewProvider(manager, file, eventSystemEnabled, language)
}
}

private class SqlDelightFileViewProvider(
manager: PsiManager,
virtualFile: VirtualFile,
eventSystemEnabled: Boolean,
private val language: Language,
private val module: Module
private val language: Language
) : SingleRootFileViewProvider(manager, virtualFile, eventSystemEnabled, language) {
private val threadPool = Executors.newScheduledThreadPool(1)

private val file: SqlDelightFile
get() = getPsiInner(language) as SqlDelightFile

private var filesGenerated = emptyList<VirtualFile>()
set(value) {
(field - value).forEach { it.delete(this) }
field = value
}

private var condition = WriteCondition()

override fun contentsSynchronized() {
super.contentsSynchronized()

if (!SqlDelightFileIndex.getInstance(module).isConfigured ||
SqlDelightFileIndex.getInstance(module).sourceFolders(file).isEmpty()
) {
return
}

condition.invalidated.set(true)

if (ApplicationManager.getApplication().isUnitTestMode) {
generateSqlDelightCode()
return
}

val thisCondition = WriteCondition()
condition = thisCondition
threadPool.schedule(
{
ApplicationManager.getApplication().invokeLater(
{
try {
generateSqlDelightCode()
} catch (e: Throwable) {
// IDE generating code should be best effort - source of truth is always the gradle
// build, and its better to ignore the error and try again than crash and require
// the IDE restarts.
e.printStackTrace()
}
},
thisCondition
)
},
1, TimeUnit.SECONDS
)
}

/**
* Attempt to generate the SQLDelight code for the file represented by the view provider.
*/
private fun generateSqlDelightCode() {
var shouldGenerate = true
val annotationHolder = object : SqlAnnotationHolder {
override fun createErrorAnnotation(element: PsiElement, s: String) {
shouldGenerate = false
}
}

// File is mutable so create a copy that wont be mutated.
val file = file.copy() as SqlDelightFile

shouldGenerate = try {
PsiTreeUtil.processElements(file) { element ->
when (element) {
is PsiErrorElement -> return@processElements false
is SqlAnnotatedElement -> element.annotate(annotationHolder)
}
return@processElements shouldGenerate
}
} catch (e: Throwable) {
// If we encountered an exception while looking for errors, assume it was an error.
false
}

if (shouldGenerate && !ApplicationManager.getApplication().isUnitTestMode) ApplicationManager.getApplication().runWriteAction {
val files = mutableListOf<VirtualFile>()
val fileAppender = { filePath: String ->
val vFile: VirtualFile by GeneratedVirtualFile(filePath, module)
files.add(vFile)
PrintStream(vFile.getOutputStream(this))
}
if (file is SqlDelightQueriesFile) {
SqlDelightCompiler.writeInterfaces(module, file, fileAppender)
} else if (file is MigrationFile) {
SqlDelightCompiler.writeInterfaces(file, fileAppender)
}
this.filesGenerated = files
}
}

private class WriteCondition : Condition<Any> {
var invalidated = AtomicBoolean(false)

override fun value(t: Any?) = invalidated.get()
FileGeneratorService.getInstance(file.project).generateFiles(file)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.squareup.sqldelight.intellij.refactoring

import com.intellij.refactoring.suggested.SignatureChangePresentationModel.TextFragment.Leaf
import com.intellij.refactoring.suggested.SignaturePresentationBuilder
import com.intellij.refactoring.suggested.SuggestedRefactoringSupport

class SqlDelightSignaturePresentationBuilder(
signature: SuggestedRefactoringSupport.Signature,
otherSignature: SuggestedRefactoringSupport.Signature,
isOldSignature: Boolean
) : SignaturePresentationBuilder(signature, otherSignature, isOldSignature) {
override fun buildPresentation() {

fragments += leaf(signature.name, otherSignature.name)

buildParameterList { fragments, parameter, correspondingParameter ->
fragments += leaf(parameter.name, correspondingParameter?.name ?: parameter.name)

fragments += Leaf(" ")

fragments += leaf(parameter.type, correspondingParameter?.type ?: parameter.type)

val additionalData = parameter.additionalData
if (additionalData != null) {
fragments += Leaf(" ")

fragments += leaf(additionalData.toString(), correspondingParameter?.additionalData?.toString() ?: additionalData.toString())
}
}
}
}
Loading

0 comments on commit dd1fbd5

Please sign in to comment.