diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java index d385c671dae7..cdb2f77c0238 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java @@ -672,12 +672,13 @@ public class BuildManager implements Disposable { return null; } - final DelegateFuture _future = new DelegateFuture<>(); + final DelegateFuture _future = new DelegateFuture<>(); // by using the same queue that processes events we ensure that // the build will be aware of all events that have happened before this request runCommand(new Runnable() { @Override public void run() { + final Pair, OSProcessHandler> preloaded = takePreloadedProcess(projectPath); final RequestFuture preloadedFuture = preloaded != null? preloaded.first : null; final boolean usingPreloadedProcess = preloadedFuture != null; @@ -692,7 +693,8 @@ public class BuildManager implements Disposable { sessionId = UUID.randomUUID(); } - final RequestFuture future = usingPreloadedProcess? preloadedFuture : new RequestFuture(handler, sessionId, new CancelBuildSessionAction()); + final RequestFuture future = usingPreloadedProcess? preloadedFuture : new RequestFuture<>(handler, sessionId, new CancelBuildSessionAction()); + _future.setDelegate(future); if (!usingPreloadedProcess && (future.isCancelled() || project.isDisposed())) { // in case of preloaded process the process was already running, so the handler will be notified upon process termination @@ -739,7 +741,7 @@ public class BuildManager implements Disposable { } try { - Future buildFuture = projectTaskQueue.submit(new Runnable() { + projectTaskQueue.submit(new Runnable() { @Override public void run() { Throwable execFailure = null; @@ -776,7 +778,7 @@ public class BuildManager implements Disposable { } }); } - catch (Throwable e) { + catch(Throwable e) { LOG.info(e); } } @@ -841,9 +843,6 @@ public class BuildManager implements Disposable { } } }); - TaskFutureAdapter adapter = new TaskFutureAdapter<>(buildFuture); - boolean set = _future.setDelegate(adapter); - assert set; } catch (Throwable e) { handleProcessExecutionFailure(sessionId, e); diff --git a/jps/jps-builders/src/org/jetbrains/jps/api/TaskFutureAdapter.java b/jps/jps-builders/src/org/jetbrains/jps/api/TaskFutureAdapter.java deleted file mode 100644 index 8d7fe84ffb8a..000000000000 --- a/jps/jps-builders/src/org/jetbrains/jps/api/TaskFutureAdapter.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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. - * 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.jps.api; - -import org.jetbrains.annotations.NotNull; - -import java.util.concurrent.*; - -/** - * Makes TaskFuture from the supplied Future - */ -public class TaskFutureAdapter implements TaskFuture { - @NotNull private final Future myFuture; - - public TaskFutureAdapter(@NotNull Future future) { - myFuture = future; - } - - @Override - public void waitFor() { - try { - get(); - } - catch (InterruptedException e) { - throw new RuntimeException(e); - } - catch (ExecutionException e) { - throw new RuntimeException(e); - } - catch (CancellationException ignored) { - } - } - - @Override - public boolean waitFor(long timeout, TimeUnit unit) { - try { - get(timeout, unit); - } - catch (InterruptedException e) { - throw new RuntimeException(e); - } - catch (ExecutionException e) { - throw new RuntimeException(e); - } - catch (TimeoutException ignored) { - } - catch (CancellationException ignored) { - } - return isDone(); - } - - // delegates - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - return myFuture.cancel(mayInterruptIfRunning); - } - - @Override - public boolean isCancelled() { - return myFuture.isCancelled(); - } - - @Override - public boolean isDone() { - return myFuture.isDone(); - } - - @Override - public T get() throws InterruptedException, ExecutionException { - return myFuture.get(); - } - - @Override - public T get(long timeout, @NotNull TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { - return myFuture.get(timeout, unit); - } -} diff --git a/platform/bootstrap/src/com/intellij/idea/Main.java b/platform/bootstrap/src/com/intellij/idea/Main.java index 0c01ce578785..5758f2c4db87 100644 --- a/platform/bootstrap/src/com/intellij/idea/Main.java +++ b/platform/bootstrap/src/com/intellij/idea/Main.java @@ -25,7 +25,6 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.util.ArrayUtilRt; import com.intellij.util.Restarter; -import com.intellij.util.SystemProperties; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; @@ -81,9 +80,7 @@ public class Main { System.exit(NO_GRAPHICS); } - //this property is temporary and will be removed when IntelliJ platform really migrates to Java 8 - boolean checkVersion = !SystemProperties.getBooleanProperty("idea.no.java.version.check", false); - if (checkVersion && !SystemInfo.isJavaVersionAtLeast("1.8")) { + if (!SystemInfo.isJavaVersionAtLeast("1.8")) { showMessage("Unsupported Java Version", "Cannot start under Java " + SystemInfo.JAVA_RUNTIME_VERSION + ": Java 1.8 or later is required.", true); System.exit(UNSUPPORTED_JAVA_VERSION); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index ee0653995ab5..bcbf56016ecd 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -883,6 +883,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi isReleased = true; clearSettingsCache(); + mySizeAdjustmentStrategy.cancelAllRequests(); myFoldingModel.dispose(); mySoftWrapModel.release(); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorSizeAdjustmentStrategy.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorSizeAdjustmentStrategy.java index 2a72d12a6002..82ab0aa7d2b4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorSizeAdjustmentStrategy.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorSizeAdjustmentStrategy.java @@ -103,6 +103,10 @@ class EditorSizeAdjustmentStrategy { scheduleSizeUpdate(editor); return result; } + + void cancelAllRequests() { + myAlarm.cancelAllRequests(); + } /** * Removes old timings. diff --git a/platform/platform-tests/testSrc/com/intellij/util/containers/ContainerUtilTest.java b/platform/platform-tests/testSrc/com/intellij/util/containers/ContainerUtilTest.java index 172afcafe4aa..c314f14fa168 100644 --- a/platform/platform-tests/testSrc/com/intellij/util/containers/ContainerUtilTest.java +++ b/platform/platform-tests/testSrc/com/intellij/util/containers/ContainerUtilTest.java @@ -252,6 +252,16 @@ public class ContainerUtilTest extends TestCase { assertSame(EmptyIterator.getInstance(), iterator); } + public void testIdenticalItemsInLockFreeCOW() { + List list = ContainerUtil.createLockFreeCopyOnWriteList(Arrays.asList("a", "b")); + list.add("a"); + assertEquals(3, list.size()); + list.remove("a"); + assertEquals(2, list.size()); + list.remove("a"); + assertEquals(1, list.size()); + } + public void testLockFreeCOWIteratorRemove() { List seq = Arrays.asList("0", "1", "2", "3", "4"); LockFreeCopyOnWriteArrayList my = (LockFreeCopyOnWriteArrayList)ContainerUtil.createLockFreeCopyOnWriteList(seq); diff --git a/plugins/terminal/lib/jediterm-pty-2.1.jar b/plugins/terminal/lib/jediterm-pty-2.1.jar index 966465cf0af2..4a5c8b3f41d9 100644 Binary files a/plugins/terminal/lib/jediterm-pty-2.1.jar and b/plugins/terminal/lib/jediterm-pty-2.1.jar differ diff --git a/plugins/terminal/src/org/jetbrains/plugins/terminal/JBTerminalWidget.java b/plugins/terminal/src/org/jetbrains/plugins/terminal/JBTerminalWidget.java index e4276dc3fdbf..ff96ce4d69fb 100644 --- a/plugins/terminal/src/org/jetbrains/plugins/terminal/JBTerminalWidget.java +++ b/plugins/terminal/src/org/jetbrains/plugins/terminal/JBTerminalWidget.java @@ -3,6 +3,7 @@ package org.jetbrains.plugins.terminal; import com.intellij.openapi.Disposable; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.wm.impl.IdeBackgroundUtil; +import com.intellij.ui.SearchTextField; import com.intellij.ui.components.JBScrollBar; import com.jediterm.terminal.TerminalStarter; import com.jediterm.terminal.TtyConnector; @@ -14,7 +15,9 @@ import com.jediterm.terminal.ui.settings.SettingsProvider; import org.jetbrains.annotations.NotNull; import javax.swing.*; +import javax.swing.event.DocumentListener; import java.awt.*; +import java.awt.event.KeyListener; public class JBTerminalWidget extends JediTermWidget implements Disposable{ @@ -53,4 +56,31 @@ public class JBTerminalWidget extends JediTermWidget implements Disposable{ @Override public void dispose() { } + + @Override + protected SearchComponent createSearchComponent() { + return new SearchComponent() { + private final SearchTextField myTextField = new SearchTextField(false); + @Override + public String getText() { + return myTextField.getText(); + } + + @Override + public JComponent getComponent() { + myTextField.setOpaque(false); + return myTextField; + } + + @Override + public void addDocumentChangeListener(DocumentListener listener) { + myTextField.addDocumentListener(listener); + } + + @Override + public void addKeyListener(KeyListener listener) { + myTextField.addKeyboardListener(listener); + } + }; + } } diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/actions/GenerateMainAction.java b/plugins/ui-designer/src/com/intellij/uiDesigner/actions/GenerateMainAction.java index a9996ba276d0..d1c3cd936d28 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/actions/GenerateMainAction.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/actions/GenerateMainAction.java @@ -21,6 +21,7 @@ import com.intellij.codeInsight.generation.PsiGenerationInfo; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.diagnostic.Logger; @@ -129,7 +130,10 @@ public class GenerateMainAction extends AnAction { @Override public void update(AnActionEvent e) { - e.getPresentation().setVisible(isActionEnabled(e)); + boolean enabled = isActionEnabled(e); + Presentation presentation = e.getPresentation(); + presentation.setEnabled(enabled); + presentation.setVisible(enabled); } private static boolean isActionEnabled(final AnActionEvent e) { diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/PropertyInspectorTable.java b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/PropertyInspectorTable.java index e4b7fccedbff..042860a3f9f1 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/PropertyInspectorTable.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/PropertyInspectorTable.java @@ -281,7 +281,7 @@ public final class PropertyInspectorTable extends Table implements DataProvider{ return myEditor; } else if (PlatformDataKeys.FILE_EDITOR.is(dataId)) { - GuiEditor designer = DesignerToolWindowManager.getInstance(myProject).getActiveFormEditor(); + GuiEditor designer = myProject.isDisposed() ? null : DesignerToolWindowManager.getInstance(myProject).getActiveFormEditor(); return designer == null ? null : designer.getEditor(); } else if (PlatformDataKeys.HELP_ID.is(dataId)) { diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/string/NewKeyDialog.form b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/string/NewKeyDialog.form index 4c38698bcafa..d39ff0d042b4 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/string/NewKeyDialog.form +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/string/NewKeyDialog.form @@ -1,54 +1,56 @@
- - + - - + - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/string/NewKeyDialog.java b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/string/NewKeyDialog.java index 2838cf1ebded..c6584a01f422 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/string/NewKeyDialog.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/string/NewKeyDialog.java @@ -17,6 +17,7 @@ package com.intellij.uiDesigner.propertyInspector.editors.string; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.uiDesigner.UIDesignerBundle; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.event.DocumentListener; @@ -63,6 +64,11 @@ public class NewKeyDialog extends DialogWrapper { return myPanel; } + @NotNull + protected String getDimensionServiceKey() { + return getClass().getName(); + } + public String getName() { return myKeyNameEdit.getText(); } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java index a97e979f06f6..a1ed979c5309 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java @@ -235,10 +235,17 @@ public class StudyUtils { if (course == null) { return null; } - final VirtualFile taskDir = file.getParent(); + VirtualFile taskDir = file.getParent(); if (taskDir == null) { return null; } + //need this because of multi-module generation + if ("src".equals(taskDir.getName())) { + taskDir = taskDir.getParent(); + if (taskDir == null) { + return null; + } + } final String taskDirName = taskDir.getName(); if (taskDirName.contains(EduNames.TASK)) { final VirtualFile lessonDir = taskDir.getParent(); @@ -392,6 +399,12 @@ public class StudyUtils { } if (taskDirectory != null) { VirtualFile taskTextFile = taskDirectory.findChild(EduNames.TASK_HTML); + if (taskTextFile == null) { + VirtualFile srcDir = taskDirectory.findChild("src"); + if (srcDir != null) { + taskTextFile = srcDir.findChild(EduNames.TASK_HTML); + } + } if (taskTextFile != null) { try { return FileUtil.loadTextAndClose(taskTextFile.getInputStream()); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyTaskNavigationAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyTaskNavigationAction.java index 54ede8fc64c7..b4e8d16905f0 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyTaskNavigationAction.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyTaskNavigationAction.java @@ -92,7 +92,8 @@ abstract public class StudyTaskNavigationAction extends DumbAwareAction { for (Map.Entry entry : nextTaskFiles.entrySet()) { String name = entry.getKey(); TaskFile taskFile = entry.getValue(); - VirtualFile vf = taskDir.findChild(name); + VirtualFile srcDir = taskDir.findChild("src"); + VirtualFile vf = srcDir == null ? taskDir.findChild(name) : srcDir.findChild(name); if (vf != null) { FileEditorManager.getInstance(project).openFile(vf, true); if (!taskFile.getAnswerPlaceholders().isEmpty()) { diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/courseGeneration/StudyProjectGenerator.java b/python/educational-core/student/src/com/jetbrains/edu/learning/courseGeneration/StudyProjectGenerator.java index 5d5c0f7b7799..dc0eb04cee57 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/courseGeneration/StudyProjectGenerator.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/courseGeneration/StudyProjectGenerator.java @@ -46,10 +46,10 @@ import java.util.Map; public class StudyProjectGenerator { private static final Logger LOG = Logger.getInstance(StudyProjectGenerator.class.getName()); private final List myListeners = ContainerUtil.newArrayList(); - private static final File ourCoursesDir = new File(PathManager.getConfigPath(), "courses"); + protected static final File ourCoursesDir = new File(PathManager.getConfigPath(), "courses"); private static final String CACHE_NAME = "courseNames.txt"; private List myCourses = new ArrayList<>(); - private CourseInfo mySelectedCourseInfo; + protected CourseInfo mySelectedCourseInfo; private static final String COURSE_NAME_ATTRIBUTE = "name"; private static final String COURSE_DESCRIPTION = "description"; public static final String AUTHOR_ATTRIBUTE = "authors"; @@ -82,7 +82,7 @@ public class StudyProjectGenerator { }))); } - private Course getCourse() { + protected Course getCourse() { Reader reader = null; try { final File courseFile = new File(new File(ourCoursesDir, mySelectedCourseInfo.getName()), EduNames.COURSE_META_FILE); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/projectView/StudyDirectoryNode.java b/python/educational-core/student/src/com/jetbrains/edu/learning/projectView/StudyDirectoryNode.java index 0a5e37c64709..92bb2dfad280 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/projectView/StudyDirectoryNode.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/projectView/StudyDirectoryNode.java @@ -41,7 +41,7 @@ public class StudyDirectoryNode extends PsiDirectoryNode { String valueName = myValue.getName(); StudyTaskManager studyTaskManager = StudyTaskManager.getInstance(myProject); Course course = studyTaskManager.getCourse(); - if (course == null || valueName == null) { + if (course == null) { return; } if (valueName.equals(myProject.getName())) { @@ -50,19 +50,17 @@ public class StudyDirectoryNode extends PsiDirectoryNode { data.addText(course.getName(), new SimpleTextAttributes(SimpleTextAttributes.STYLE_PLAIN, JBColor.BLACK)); } else if (valueName.contains(EduNames.TASK)) { - TaskFile file = null; - for (PsiElement child : myValue.getChildren()) { - VirtualFile virtualFile = child instanceof PsiDirectory ? ((PsiDirectory)child).getVirtualFile() : - child.getContainingFile().getVirtualFile(); - file = StudyUtils.getTaskFile(myProject, virtualFile); - if (file != null) { - break; + VirtualFile taskVirtualFile = myValue.getVirtualFile(); + VirtualFile lessonVirtualFile = taskVirtualFile.getParent(); + if (lessonVirtualFile != null) { + Lesson lesson = course.getLesson(lessonVirtualFile.getName()); + if (lesson != null) { + Task task = lesson.getTask(taskVirtualFile.getName()); + if (task != null) { + setStudyAttributes(task, data, task.getName()); + } } } - if (file != null) { - Task task = file.getTask(); - setStudyAttributes(task, data, task.getName()); - } } else if (valueName.contains(EduNames.LESSON)) { int lessonIndex = Integer.parseInt(valueName.substring(EduNames.LESSON.length())) - 1; @@ -73,7 +71,7 @@ public class StudyDirectoryNode extends PsiDirectoryNode { else if (valueName.contains(EduNames.SANDBOX_DIR)) { if (myValue.getParent() != null) { final String parentName = myValue.getParent().getName(); - if (parentName!= null && !parentName.contains(EduNames.SANDBOX_DIR)) { + if (!parentName.contains(EduNames.SANDBOX_DIR)) { data.setPresentableText(EduNames.SANDBOX_DIR); data.setIcon(InteractiveLearningIcons.Sandbox); } diff --git a/python/resources/liveTemplates/Python.xml b/python/resources/liveTemplates/Python.xml index 47928f82d8aa..c9447a67a333 100644 --- a/python/resources/liveTemplates/Python.xml +++ b/python/resources/liveTemplates/Python.xml @@ -4,61 +4,19 @@ - diff --git a/python/src/META-INF/python-core-common.xml b/python/src/META-INF/python-core-common.xml index 0fd613ce7bc0..8739c8f441f6 100644 --- a/python/src/META-INF/python-core-common.xml +++ b/python/src/META-INF/python-core-common.xml @@ -374,7 +374,9 @@ - + + + @@ -418,8 +420,6 @@ serviceImplementation="com.jetbrains.python.sdk.PySdkService"/> - - diff --git a/python/src/com/jetbrains/python/codeInsight/liveTemplates/PythonTemplateContextType.java b/python/src/com/jetbrains/python/codeInsight/liveTemplates/PythonTemplateContextType.java index a3146634ad4e..0877e0a8aaf9 100644 --- a/python/src/com/jetbrains/python/codeInsight/liveTemplates/PythonTemplateContextType.java +++ b/python/src/com/jetbrains/python/codeInsight/liveTemplates/PythonTemplateContextType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 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. @@ -15,15 +15,18 @@ */ package com.jetbrains.python.codeInsight.liveTemplates; -import com.intellij.codeInsight.template.FileTypeBasedContextType; +import com.intellij.codeInsight.template.EverywhereContextType; +import com.intellij.codeInsight.template.TemplateContextType; import com.intellij.patterns.PsiElementPattern; import com.intellij.psi.PsiComment; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.ProcessingContext; import com.jetbrains.python.PyTokenTypes; -import com.jetbrains.python.PythonFileType; +import com.jetbrains.python.PythonLanguage; +import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyParameterList; import com.jetbrains.python.psi.PyStringLiteralExpression; import org.jetbrains.annotations.NotNull; @@ -33,22 +36,37 @@ import static com.intellij.patterns.PlatformPatterns.psiElement; /** * @author yole */ -public class PythonTemplateContextType extends FileTypeBasedContextType { - public PythonTemplateContextType() { - super("Python", "Python", PythonFileType.INSTANCE); +public abstract class PythonTemplateContextType extends TemplateContextType { + + public PythonTemplateContextType(@NotNull String id, + @NotNull String presentableName, + @NotNull java.lang.Class baseContextType) { + super(id, presentableName, baseContextType); } @Override public boolean isInContext(@NotNull PsiFile file, int offset) { - if (super.isInContext(file, offset)) { + if (isPythonLanguage(file, offset)) { final PsiElement element = file.findElementAt(offset); + if (element != null) { - return !(isAfterDot(element) || element instanceof PsiComment || isInsideStringLiteral(element) || isInsideParameterList(element)); + if (isAfterDot(element) || element instanceof PsiComment || isInsideStringLiteral(element) || isInsideParameterList(element)) { + return false; + } + + return isInContext(element); } } + return false; } + protected abstract boolean isInContext(@NotNull PsiElement element); + + private static boolean isPythonLanguage(@NotNull PsiFile file, int offset) { + return PsiUtilCore.getLanguageAtOffset(file, offset).isKindOf(PythonLanguage.getInstance()); + } + private static boolean isInsideStringLiteral(@NotNull PsiElement element) { return PsiTreeUtil.getParentOfType(element, PyStringLiteralExpression.class, false) != null; } @@ -62,4 +80,28 @@ public class PythonTemplateContextType extends FileTypeBasedContextType { psiElement().withElementType(PyTokenTypes.DOT)); return capture.accepts(element, new ProcessingContext()); } + + public static class General extends PythonTemplateContextType { + + public General() { + super("Python", "Python", EverywhereContextType.class); + } + + @Override + protected boolean isInContext(@NotNull PsiElement element) { + return true; + } + } + + public static class Class extends PythonTemplateContextType { + + public Class() { + super("Python_Class", "Class", General.class); + } + + @Override + protected boolean isInContext(@NotNull PsiElement element) { + return PsiTreeUtil.getParentOfType(element, PyClass.class) != null; + } + } } diff --git a/python/testData/codeInsight/liveTemplates/context/afterDot.py b/python/testData/codeInsight/liveTemplates/context/afterDot.py new file mode 100644 index 000000000000..a3684aeaa3e4 --- /dev/null +++ b/python/testData/codeInsight/liveTemplates/context/afterDot.py @@ -0,0 +1 @@ +foo. \ No newline at end of file diff --git a/python/testData/codeInsight/liveTemplates/context/class.py b/python/testData/codeInsight/liveTemplates/context/class.py new file mode 100644 index 000000000000..d3457883a682 --- /dev/null +++ b/python/testData/codeInsight/liveTemplates/context/class.py @@ -0,0 +1,3 @@ +class C(object): + p + pass \ No newline at end of file diff --git a/python/testData/codeInsight/liveTemplates/context/general.py b/python/testData/codeInsight/liveTemplates/context/general.py new file mode 100644 index 000000000000..d4434b0ed9c0 --- /dev/null +++ b/python/testData/codeInsight/liveTemplates/context/general.py @@ -0,0 +1,2 @@ +p +pass \ No newline at end of file diff --git a/python/testData/codeInsight/liveTemplates/context/inComment.py b/python/testData/codeInsight/liveTemplates/context/inComment.py new file mode 100644 index 000000000000..fe147f0d6f5b --- /dev/null +++ b/python/testData/codeInsight/liveTemplates/context/inComment.py @@ -0,0 +1 @@ +# \ No newline at end of file diff --git a/python/testData/codeInsight/liveTemplates/context/inParameterList.py b/python/testData/codeInsight/liveTemplates/context/inParameterList.py new file mode 100644 index 000000000000..13808be9dd3a --- /dev/null +++ b/python/testData/codeInsight/liveTemplates/context/inParameterList.py @@ -0,0 +1,2 @@ +def foo(a, ): + pass \ No newline at end of file diff --git a/python/testData/codeInsight/liveTemplates/context/inStringLiteral.py b/python/testData/codeInsight/liveTemplates/context/inStringLiteral.py new file mode 100644 index 000000000000..69cbc30df5a6 --- /dev/null +++ b/python/testData/codeInsight/liveTemplates/context/inStringLiteral.py @@ -0,0 +1 @@ +"abc" \ No newline at end of file diff --git a/python/testData/codeInsight/liveTemplates/context/notPython.html b/python/testData/codeInsight/liveTemplates/context/notPython.html new file mode 100644 index 000000000000..12174c6449da --- /dev/null +++ b/python/testData/codeInsight/liveTemplates/context/notPython.html @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/codeInsight/liveTemplates/PyLiveTemplatesTest.java b/python/testSrc/com/jetbrains/python/codeInsight/liveTemplates/PyLiveTemplatesTest.java new file mode 100644 index 000000000000..338ed32906d6 --- /dev/null +++ b/python/testSrc/com/jetbrains/python/codeInsight/liveTemplates/PyLiveTemplatesTest.java @@ -0,0 +1,104 @@ +/* + * 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. + * 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 com.jetbrains.python.codeInsight.liveTemplates; + +import com.intellij.codeInsight.template.TemplateContextType; +import com.intellij.testFramework.UsefulTestCase; +import com.jetbrains.python.fixtures.PyTestCase; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class PyLiveTemplatesTest extends PyTestCase { + + @Override + protected String getTestDataPath() { + return super.getTestDataPath() + "/codeInsight/liveTemplates/context/"; + } + + public void testNotPython() { + doTest(Collections.emptyList(), "html"); + } + + // PY-12212 + public void testAfterDot() { + doTest(Collections.emptyList()); + } + + // PY-13076 + public void testInComment() { + doTest(Collections.emptyList()); + } + + // PY-12349 + public void testInStringLiteral() { + doTest(Collections.emptyList()); + } + + // PY-12395 + public void testInParameterList() { + doTest(Collections.emptyList()); + } + + public void testGeneral() { + doTest( + Collections.singletonList(PythonTemplateContextType.General.class) + ); + } + + // PY-12396 + public void testClass() { + doTest( + Arrays.asList(PythonTemplateContextType.Class.class, PythonTemplateContextType.General.class) + ); + } + + private void doTest(@NotNull List> expectedContextTypes) { + doTest(expectedContextTypes, "py"); + } + + private void doTest(@NotNull List> expectedContextTypes, @NotNull String extension) { + myFixture.configureByFile(getTestName(true) + "." + extension); + + UsefulTestCase.assertSameElements( + calculateEnabledContextTypes(getRegisteredContextTypes()), + expectedContextTypes + ); + } + + @NotNull + private List> calculateEnabledContextTypes(@NotNull List registeredContextTypes) { + //noinspection Convert2MethodRef + return registeredContextTypes + .stream() + .filter(type -> type.isInContext(myFixture.getFile(), myFixture.getCaretOffset())) + .map(type -> type.getClass()) + .sorted((o1, o2) -> o1.getSimpleName().compareTo(o2.getSimpleName())) + .collect(Collectors.toList()); + } + + @NotNull + private static List getRegisteredContextTypes() { + return Arrays + .stream(TemplateContextType.EP_NAME.getExtensions()) + .filter(type -> type instanceof PythonTemplateContextType) + .map(type -> (PythonTemplateContextType)type) + .collect(Collectors.toList()); + } +} \ No newline at end of file