Minor: Allow running member generation actions without editor

This commit is contained in:
Alexey Sedunov
2015-10-15 12:24:30 +03:00
parent 915236a6ba
commit 127cb36602
4 changed files with 22 additions and 13 deletions
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.idea.util.ShortenReferences
import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.siblings import org.jetbrains.kotlin.psi.psiUtil.siblings
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.utils.ifEmpty import org.jetbrains.kotlin.utils.ifEmpty
public fun moveCaretIntoGeneratedElement(editor: Editor, element: PsiElement) { public fun moveCaretIntoGeneratedElement(editor: Editor, element: PsiElement) {
@@ -100,10 +101,10 @@ public fun Editor.moveCaret(offset: Int, scrollType: ScrollType = ScrollType.REL
getScrollingModel().scrollToCaret(scrollType) getScrollingModel().scrollToCaret(scrollType)
} }
private fun findInsertAfterAnchor(editor: Editor, body: JetClassBody): PsiElement? { private fun findInsertAfterAnchor(editor: Editor?, body: JetClassBody): PsiElement? {
val afterAnchor = body.lBrace ?: return null val afterAnchor = body.lBrace ?: return null
val offset = editor.caretModel.offset val offset = editor?.caretModel?.offset ?: body.startOffset
val offsetCursorElement = PsiTreeUtil.findFirstParent(body.containingFile.findElementAt(offset)) { val offsetCursorElement = PsiTreeUtil.findFirstParent(body.containingFile.findElementAt(offset)) {
it.parent == body it.parent == body
} }
@@ -143,7 +144,7 @@ private fun removeAfterOffset(offset: Int, whiteSpace: PsiWhiteSpace): PsiElemen
} }
public fun <T : JetDeclaration> insertMembersAfter( public fun <T : JetDeclaration> insertMembersAfter(
editor: Editor, editor: Editor?,
classOrObject: JetClassOrObject, classOrObject: JetClassOrObject,
members: Collection<T>, members: Collection<T>,
anchor: PsiElement? = null anchor: PsiElement? = null
@@ -161,7 +162,9 @@ public fun <T : JetDeclaration> insertMembersAfter(
ShortenReferences.DEFAULT.process(insertedMembers) ShortenReferences.DEFAULT.process(insertedMembers)
moveCaretIntoGeneratedElement(editor, insertedMembers.first()) if (editor != null) {
moveCaretIntoGeneratedElement(editor, insertedMembers.first())
}
insertedMembers insertedMembers
} }
@@ -125,7 +125,7 @@ class KotlinGenerateEqualsAndHashcodeAction : KotlinGenerateMemberActionBase<Kot
Messages.getQuestionIcon()) == Messages.YES Messages.getQuestionIcon()) == Messages.YES
} }
override fun prepareMembersInfo(klass: JetClassOrObject, project: Project, editor: Editor): Info? { override fun prepareMembersInfo(klass: JetClassOrObject, project: Project, editor: Editor?): Info? {
if (klass !is JetClass) throw AssertionError("Not a class: ${klass.getElementTextWithContext()}") if (klass !is JetClass) throw AssertionError("Not a class: ${klass.getElementTextWithContext()}")
val context = klass.analyzeFully() val context = klass.analyzeFully()
@@ -273,7 +273,7 @@ class KotlinGenerateEqualsAndHashcodeAction : KotlinGenerateMemberActionBase<Kot
} }
} }
override fun generateMembers(project: Project, editor: Editor, info: Info): List<JetDeclaration> { override fun generateMembers(project: Project, editor: Editor?, info: Info): List<JetDeclaration> {
val targetClass = info.classDescriptor.source.getPsi() as JetClass val targetClass = info.classDescriptor.source.getPsi() as JetClass
val prototypes = ArrayList<JetDeclaration>(2) val prototypes = ArrayList<JetDeclaration>(2)
.apply { .apply {
@@ -28,20 +28,26 @@ import org.jetbrains.kotlin.psi.JetClassOrObject
import org.jetbrains.kotlin.psi.JetDeclaration import org.jetbrains.kotlin.psi.JetDeclaration
abstract class KotlinGenerateMemberActionBase<Info : Any> : KotlinGenerateActionBase() { abstract class KotlinGenerateMemberActionBase<Info : Any> : KotlinGenerateActionBase() {
protected abstract fun prepareMembersInfo(klass: JetClassOrObject, project: Project, editor: Editor): Info? protected abstract fun prepareMembersInfo(klass: JetClassOrObject, project: Project, editor: Editor?): Info?
protected abstract fun generateMembers(project: Project, editor: Editor, info: Info): List<JetDeclaration> protected abstract fun generateMembers(project: Project, editor: Editor?, info: Info): List<JetDeclaration>
override fun invoke(project: Project, editor: Editor, file: PsiFile) { override fun invoke(project: Project, editor: Editor, file: PsiFile) {
if (!CodeInsightUtilBase.prepareEditorForWrite(editor)) return if (!CodeInsightUtilBase.prepareEditorForWrite(editor)) return
if (!FileDocumentManager.getInstance().requestWriting(editor.document, project)) return if (!FileDocumentManager.getInstance().requestWriting(editor.document, project)) return
val klass = getTargetClass(editor, file) ?: return val targetClass = getTargetClass(editor, file) ?: return
val membersInfo = prepareMembersInfo(klass, project, editor) ?: return doInvoke(project, editor, targetClass)
}
fun doInvoke(project: Project, editor: Editor?, targetClass: JetClassOrObject) {
val membersInfo = prepareMembersInfo(targetClass, project, editor) ?: return
project.executeWriteCommand(commandName, this) { project.executeWriteCommand(commandName, this) {
val newMembers = generateMembers(project, editor, membersInfo) val newMembers = generateMembers(project, editor, membersInfo)
GlobalInspectionContextBase.cleanupElements(project, null, *newMembers.toTypedArray()) GlobalInspectionContextBase.cleanupElements(project, null, *newMembers.toTypedArray())
newMembers.firstOrNull()?.let { GenerateMembersUtil.positionCaret(editor, it, false) } if (editor != null) {
newMembers.firstOrNull()?.let { GenerateMembersUtil.positionCaret(editor, it, false) }
}
} }
} }
} }
@@ -100,7 +100,7 @@ class KotlinGenerateSecondaryConstructorAction : KotlinGenerateMemberActionBase<
} }
} }
override fun prepareMembersInfo(klass: JetClassOrObject, project: Project, editor: Editor): Info? { override fun prepareMembersInfo(klass: JetClassOrObject, project: Project, editor: Editor?): Info? {
val context = klass.analyzeFully() val context = klass.analyzeFully()
val classDescriptor = context.get(BindingContext.CLASS, klass) ?: return null val classDescriptor = context.get(BindingContext.CLASS, klass) ?: return null
val superConstructors = chooseSuperConstructors(klass, classDescriptor).map { it.descriptor as ConstructorDescriptor } val superConstructors = chooseSuperConstructors(klass, classDescriptor).map { it.descriptor as ConstructorDescriptor }
@@ -108,7 +108,7 @@ class KotlinGenerateSecondaryConstructorAction : KotlinGenerateMemberActionBase<
return Info(propertiesToInitialize, superConstructors, classDescriptor) return Info(propertiesToInitialize, superConstructors, classDescriptor)
} }
override fun generateMembers(project: Project, editor: Editor, info: Info): List<JetDeclaration> { override fun generateMembers(project: Project, editor: Editor?, info: Info): List<JetDeclaration> {
val targetClass = info.classDescriptor.source.getPsi() as? JetClass ?: return emptyList() val targetClass = info.classDescriptor.source.getPsi() as? JetClass ?: return emptyList()
fun Info.findAnchor(): PsiElement? { fun Info.findAnchor(): PsiElement? {