From be04dfb5aaf8cc66aee915f8bf53f093488395fc Mon Sep 17 00:00:00 2001 From: Alexander Zolotov Date: Thu, 14 Apr 2016 14:24:11 +0300 Subject: [PATCH] Live Templates: finish template if completion insert handler moved caret outside of current segment (WEB-20592) --- .../template/impl/TemplateState.java | 48 ++++++++++++++++--- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java index bf2f53af6360..5eee2d0acc8b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -46,6 +46,7 @@ import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; @@ -66,6 +67,8 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.util.*; public class TemplateState implements Disposable { @@ -89,6 +92,7 @@ public class TemplateState implements Disposable { @Nullable private CommandAdapter myCommandListener; @Nullable private CaretListener myCaretListener; + @Nullable private LookupListener myLookupListener; private final List myListeners = ContainerUtil.createLockFreeCopyOnWriteList(); private DocumentAdapter myEditorDocumentListener; @@ -113,7 +117,25 @@ public class TemplateState implements Disposable { myDocumentChanged = true; } }; - + myLookupListener = new LookupAdapter() { + @Override + public void itemSelected(LookupEvent event) { + if (isCaretOutsideCurrentSegment()) { + gotoEnd(true); + } + } + }; + LookupManager.getInstance(myProject).addPropertyChangeListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (LookupManager.PROP_ACTIVE_LOOKUP.equals(evt.getPropertyName())) { + Lookup lookup = (Lookup)evt.getNewValue(); + if (lookup != null) { + lookup.addLookupListener(myLookupListener); + } + } + } + }, this); myCommandListener = new CommandAdapter() { boolean started = false; @@ -180,6 +202,14 @@ public class TemplateState implements Disposable { @Override public synchronized void dispose() { + if (myLookupListener != null) { + final LookupImpl lookup = myEditor != null ? (LookupImpl)LookupManager.getActiveLookup(myEditor) : null; + if (lookup != null) { + lookup.removeLookupListener(myLookupListener); + } + myLookupListener = null; + } + myEditorDocumentListener = null; myCommandListener = null; myCaretListener = null; @@ -285,6 +315,7 @@ public class TemplateState implements Disposable { } myPrevTemplate = myTemplate; myTemplate = null; + myProject = null; releaseEditor(); } @@ -680,6 +711,9 @@ public class TemplateState implements Disposable { WriteCommandAction.runWriteCommandAction(myProject, new Runnable() { @Override public void run() { + if (isDisposed()) { + return; + } BitSet calcedSegments = new BitSet(); int maxAttempts = (myTemplate.getVariableCount() + 1) * 3; @@ -931,7 +965,7 @@ public class TemplateState implements Disposable { } public void gotoEnd(boolean brokenOff) { - if (myTemplate == null) return; + if (isDisposed()) return; LookupManager.getInstance(myProject).hideActiveLookup(); calcResults(false); if (!brokenOff) { @@ -949,13 +983,13 @@ public class TemplateState implements Disposable { * @deprecated use this#gotoEnd(true) */ public void cancelTemplate() { - if (myTemplate == null) return; + if (isDisposed()) return; LookupManager.getInstance(myProject).hideActiveLookup(); cleanupTemplateState(true); } private void finishTemplateEditing() { - if (myTemplate == null) return; + if (isDisposed()) return; LookupManager.getInstance(myProject).hideActiveLookup(); setFinalEditorState(false); cleanupTemplateState(false); @@ -1008,7 +1042,7 @@ public class TemplateState implements Disposable { fireTemplateFinished(brokenOff); } myListeners.clear(); - myProject = null; + Disposer.dispose(this); } private int getNextVariableNumber(int currentVariableNumber) { @@ -1310,7 +1344,7 @@ public class TemplateState implements Disposable { if (myCurrentVariableNumber >= 0) { LOG.error("A variable with no segment: " + myCurrentVariableNumber + "; " + presentTemplate(myTemplate)); } - releaseAll(); + Disposer.dispose(this); } }