diff --git a/java/java-tests/testSrc/com/intellij/openapi/roots/impl/DirectoryIndexTest.java b/java/java-tests/testSrc/com/intellij/openapi/roots/impl/DirectoryIndexTest.java index 8a19c58bcbd6..b8fcf06e88a9 100644 --- a/java/java-tests/testSrc/com/intellij/openapi/roots/impl/DirectoryIndexTest.java +++ b/java/java-tests/testSrc/com/intellij/openapi/roots/impl/DirectoryIndexTest.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. @@ -17,7 +17,6 @@ package com.intellij.openapi.roots.impl; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.fileTypes.ex.FileTypeManagerEx; import com.intellij.openapi.module.ModifiableModuleModel; @@ -46,8 +45,6 @@ import java.util.*; @PlatformTestCase.WrapInCommand public class DirectoryIndexTest extends IdeaTestCase { - private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.roots.impl.DirectoryIndexTest"); - private DirectoryIndexImpl myIndex; private Module myModule2, myModule3; @@ -460,7 +457,7 @@ public class DirectoryIndexTest extends IdeaTestCase { } public void testModuleSourceAsLibrarySource() throws Exception { - ModuleRootModificationUtil.addModuleLibrary(myModule, "someLib", Collections.emptyList(), Arrays.asList(mySrcDir1.getUrl())); + ModuleRootModificationUtil.addModuleLibrary(myModule, "someLib", Collections.emptyList(), Collections.singletonList(mySrcDir1.getUrl())); checkInfo(mySrcDir1, myModule, false, true, "", JavaSourceRootType.SOURCE, myModule, myModule); Collection entriesResult = myIndex.getOrderEntries(myIndex.getInfoForFile(mySrcDir1)); @@ -477,7 +474,7 @@ public class DirectoryIndexTest extends IdeaTestCase { } public void testModuleSourceAsLibraryClasses() throws Exception { - ModuleRootModificationUtil.addModuleLibrary(myModule, "someLib", Arrays.asList(mySrcDir1.getUrl()), Collections.emptyList()); + ModuleRootModificationUtil.addModuleLibrary(myModule, "someLib", Collections.singletonList(mySrcDir1.getUrl()), Collections.emptyList()); checkInfo(mySrcDir1, myModule, true, false, "", JavaSourceRootType.SOURCE, myModule); assertInstanceOf(assertOneElement(toArray(myIndex.getOrderEntries(assertInProject(mySrcDir1)))), ModuleSourceOrderEntry.class); } @@ -699,6 +696,7 @@ public class DirectoryIndexTest extends IdeaTestCase { assertIteratedContent(myFileIndex, null, Arrays.asList(fileRoot, fileSourceRoot, fileTestSourceRoot)); ContentEntry contentEntry = PsiTestUtil.addContentRoot(myModule, fileRoot); + assertNotNull(contentEntry); assertEquals(fileRoot, contentEntry.getFile()); checkInfo(fileRoot, myModule, false, false, "", null); assertTrue(myFileIndex.isInContent(fileRoot)); @@ -730,12 +728,12 @@ public class DirectoryIndexTest extends IdeaTestCase { assertNotInProject(fileRoot); assertFalse(myFileIndex.isInContent(fileRoot)); assertFalse(myFileIndex.isInSource(fileRoot)); - assertIteratedContent(myFileIndex, Arrays.asList(fileSourceRoot, fileTestSourceRoot), Arrays.asList(fileRoot)); + assertIteratedContent(myFileIndex, Arrays.asList(fileSourceRoot, fileTestSourceRoot), Collections.singletonList(fileRoot)); } - private void assertIteratedContent(ProjectFileIndex fileIndex, - @Nullable List contains, - @Nullable List doesntContain) { + private static void assertIteratedContent(ProjectFileIndex fileIndex, + @Nullable List contains, + @Nullable List doesntContain) { final Set collected = new THashSet(); fileIndex.iterateContent(new ContentIterator() { @Override @@ -768,7 +766,7 @@ public class DirectoryIndexTest extends IdeaTestCase { VirtualFile fileExcludeRoot = createChildData(mySrcDir1, "fileExcludeRoot.txt"); assertTrue(myFileIndex.isInContent(fileExcludeRoot)); assertTrue(myFileIndex.isInSource(fileExcludeRoot)); - assertIteratedContent(myFileIndex, Arrays.asList(fileExcludeRoot), null); + assertIteratedContent(myFileIndex, Collections.singletonList(fileExcludeRoot), null); PsiTestUtil.addExcludedRoot(myModule, fileExcludeRoot); assertFalse(myFileIndex.isInContent(fileExcludeRoot)); @@ -778,13 +776,13 @@ public class DirectoryIndexTest extends IdeaTestCase { assertNull(myFileIndex.getModuleForFile(fileExcludeRoot)); assertEquals(myModule, myFileIndex.getModuleForFile(fileExcludeRoot, false)); assertExcluded(fileExcludeRoot, myModule); - assertIteratedContent(myFileIndex, null, Arrays.asList(fileExcludeRoot)); + assertIteratedContent(myFileIndex, null, Collections.singletonList(fileExcludeRoot)); // removing file exclude root PsiTestUtil.removeExcludedRoot(myModule, fileExcludeRoot); assertTrue(myFileIndex.isInContent(fileExcludeRoot)); assertTrue(myFileIndex.isInSource(fileExcludeRoot)); - assertIteratedContent(myFileIndex, Arrays.asList(fileExcludeRoot), null); + assertIteratedContent(myFileIndex, Collections.singletonList(fileExcludeRoot), null); } public void testFileModuleExcludeRootUnderFileRoot() throws IOException { @@ -792,25 +790,25 @@ public class DirectoryIndexTest extends IdeaTestCase { PsiTestUtil.addContentRoot(myModule, fileRoot); checkInfo(fileRoot, myModule, false, false, "", null); assertTrue(myFileIndex.isInContent(fileRoot)); - assertIteratedContent(myFileIndex, Arrays.asList(fileRoot), null); + assertIteratedContent(myFileIndex, Collections.singletonList(fileRoot), null); PsiTestUtil.addExcludedRoot(myModule, fileRoot); assertFalse(myFileIndex.isInContent(fileRoot)); assertExcluded(fileRoot, myModule); - assertIteratedContent(myFileIndex, null, Arrays.asList(fileRoot)); + assertIteratedContent(myFileIndex, null, Collections.singletonList(fileRoot)); // removing file exclude root PsiTestUtil.removeExcludedRoot(myModule, fileRoot); checkInfo(fileRoot, myModule, false, false, "", null); assertTrue(myFileIndex.isInContent(fileRoot)); - assertIteratedContent(myFileIndex, Arrays.asList(fileRoot), null); + assertIteratedContent(myFileIndex, Collections.singletonList(fileRoot), null); } public void testFileLibraryInsideFolderLibrary() throws IOException { VirtualFile file = createChildData(myLibSrcDir, "empty.txt"); ModuleRootModificationUtil.addModuleLibrary(myModule2, "lib2", - Collections.emptyList(), Collections.singletonList(file.getUrl()), - Collections.emptyList(), DependencyScope.COMPILE, true); + Collections.emptyList(), Collections.singletonList(file.getUrl()), + Collections.emptyList(), DependencyScope.COMPILE, true); // same for the dir and for the file checkInfo(file, myModule, false, true, "", null, myModule2, myModule3); @@ -944,5 +942,4 @@ public class DirectoryIndexTest extends IdeaTestCase { assertEquals("Invalid package name for dir " + dir + ": " + packageName, packageName, actualName); } } - -} +} \ No newline at end of file diff --git a/python/helpers/pycharm/pycharm_load_entry_point.py b/python/helpers/pycharm/pycharm_load_entry_point.py index ecf4f905080f..5eadeb1a3516 100644 --- a/python/helpers/pycharm/pycharm_load_entry_point.py +++ b/python/helpers/pycharm/pycharm_load_entry_point.py @@ -4,6 +4,9 @@ from pkg_resources import load_entry_point if __name__ == '__main__': dist = os.environ.get("PYCHARM_EP_DIST") name = os.environ.get("PYCHARM_EP_NAME") - sys.exit( - load_entry_point(dist, "console_scripts", name)() - ) + if dist == "ipython" and name == "ipython": + from IPython import start_ipython + f = start_ipython + else: + f = load_entry_point(dist, "console_scripts", name) + sys.exit(f()) diff --git a/python/ipnb/lib/batik.jar b/python/ipnb/lib/batik.jar deleted file mode 100644 index 589328581963..000000000000 Binary files a/python/ipnb/lib/batik.jar and /dev/null differ diff --git a/python/ipnb/lib/jeuclid-core-3.1.9.jar b/python/ipnb/lib/jeuclid-core-3.1.9.jar deleted file mode 100644 index d6d8d2d4c764..000000000000 Binary files a/python/ipnb/lib/jeuclid-core-3.1.9.jar and /dev/null differ diff --git a/python/ipnb/lib/snuggletex-core-1.3-SNAPSHOT.jar b/python/ipnb/lib/snuggletex-core-1.3-SNAPSHOT.jar deleted file mode 100644 index e5677881a08b..000000000000 Binary files a/python/ipnb/lib/snuggletex-core-1.3-SNAPSHOT.jar and /dev/null differ diff --git a/python/ipnb/lib/xmlgraphics-commons-1.3.1.jar b/python/ipnb/lib/xmlgraphics-commons-1.3.1.jar deleted file mode 100644 index 81a485dc4e6f..000000000000 Binary files a/python/ipnb/lib/xmlgraphics-commons-1.3.1.jar and /dev/null differ diff --git a/python/ipnb/resources/META-INF/ipython-notebook.xml b/python/ipnb/resources/META-INF/ipython-notebook.xml index a508d381e352..81f696690c8c 100644 --- a/python/ipnb/resources/META-INF/ipython-notebook.xml +++ b/python/ipnb/resources/META-INF/ipython-notebook.xml @@ -52,6 +52,10 @@ + + + + diff --git a/python/ipnb/resources/fileTemplates/internal/IPython Notebook.ipynb.ft b/python/ipnb/resources/fileTemplates/internal/IPython Notebook.ipynb.ft new file mode 100644 index 000000000000..01c10b25b305 --- /dev/null +++ b/python/ipnb/resources/fileTemplates/internal/IPython Notebook.ipynb.ft @@ -0,0 +1,34 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/python/ipnb/resources/org/jetbrains/plugins/ipnb/math-characters.txt b/python/ipnb/resources/org/jetbrains/plugins/ipnb/math-characters.txt deleted file mode 100644 index 024394e18d7d..000000000000 --- a/python/ipnb/resources/org/jetbrains/plugins/ipnb/math-characters.txt +++ /dev/null @@ -1,4 +0,0 @@ -## This is hand-edited. Add all of the non-auto-generated definitions -3A6:varPhi:ALPHA -3C6:varphi:ALPHA -02248:thickapprox:REL \ No newline at end of file diff --git a/python/ipnb/resources/style/javaFXBrowserDarcula.css b/python/ipnb/resources/style/javaFXBrowserDarcula.css new file mode 100644 index 000000000000..b8039148afd0 --- /dev/null +++ b/python/ipnb/resources/style/javaFXBrowserDarcula.css @@ -0,0 +1,28 @@ +body { + background-color: #313335 !important; + color: #bababa !important; +} + +.MathJax_Display { + color: #bababa !important; + background-color: #313335 !important; +} + +#mydiv { + color: #bababa !important; + background-color: #313335 !important; +} + +.MathJax { + background-color: #313335 !important; + color: #bababa !important; +} + +a { + color: #589df6 !important; +} + +.MathJax_Preview { + color: #bababa !important; +} + diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/IpnbUtils.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/IpnbUtils.java index 84ed2d892b2e..604d4f248206 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/IpnbUtils.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/IpnbUtils.java @@ -1,243 +1,271 @@ package org.jetbrains.plugins.ipnb; +import com.intellij.ide.BrowserUtil; +import com.intellij.ide.ui.LafManager; +import com.intellij.ide.ui.laf.darcula.DarculaLookAndFeelInfo; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.ui.BrowserHyperlinkListener; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.text.MarkdownUtil; import com.intellij.util.ui.UIUtil; import com.petebevin.markdown.MarkdownProcessor; -import net.sourceforge.jeuclid.MathMLParserSupport; -import net.sourceforge.jeuclid.context.LayoutContextImpl; -import net.sourceforge.jeuclid.context.Parameter; -import net.sourceforge.jeuclid.converter.Converter; +import javafx.application.Platform; +import javafx.concurrent.Worker; +import javafx.embed.swing.JFXPanel; +import javafx.event.EventHandler; +import javafx.scene.Scene; +import javafx.scene.layout.BorderPane; +import javafx.scene.web.WebEngine; +import javafx.scene.web.WebEvent; +import javafx.scene.web.WebView; +import netscape.javascript.JSException; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.ipnb.editor.IpnbEditorUtil; -import org.jetbrains.plugins.ipnb.editor.panels.IpnbTexPackageDefinitions; import org.w3c.dom.Document; -import org.xml.sax.SAXException; -import uk.ac.ed.ph.snuggletex.SnuggleEngine; -import uk.ac.ed.ph.snuggletex.SnuggleInput; -import uk.ac.ed.ph.snuggletex.SnuggleSession; -import uk.ac.ed.ph.snuggletex.XMLStringOutputOptions; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.w3c.dom.events.Event; +import org.w3c.dom.events.EventListener; +import org.w3c.dom.events.EventTarget; import javax.swing.*; -import javax.swing.text.html.HTMLDocument; -import javax.swing.text.html.HTMLEditorKit; -import javax.swing.text.html.StyleSheet; -import javax.xml.parsers.ParserConfigurationException; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.net.MalformedURLException; +import java.awt.event.MouseWheelEvent; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; -import java.util.Dictionary; -import java.util.Hashtable; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class IpnbUtils { private static final Logger LOG = Logger.getInstance(IpnbUtils.class); + private static final String ourPrefix = "
"; + + private static final String ourPostfix = "
"; private static final MarkdownProcessor ourMarkdownProcessor = new MarkdownProcessor(); - private static final String ourImagePrefix = "http://image"; - private static final Font ourFont = new Font(Font.SERIF, Font.PLAIN, 16); - private static final String ourBodyRule = "body { font-family: \"DejaVu\"; " + - "font-size: " + ourFont.getSize() + "pt;}"; + private static URL ourStyleUrl; - private static final String ourCodeRule = "code { font-family: \"DejaVu\"; " + - "font-size: " + ourFont.getSize() + "pt;}"; + public static JComponent createLatexPane(@NotNull final String source, int width) { + final JComponent panel = createHtmlPanel(source, width); - private static final String ourAlertRule = ".alert{ background-color: #fcf8e3;" + - "color: #c09853;" + - "padding: 8px 35px 8px 14px;" + - "border: 1px solid #fbeed5;}"; - - private static final String ourAlertSuccessRule = ".alert-success{ background-color: #dff0d8;\n" + - "color: #468847;" + - "padding: 8px 35px 8px 14px;" + - "border: 1px solid #d6e9c6;}"; - - private static final String ourAlertErrorRule = ".alert-error{ background-color: #f2dede;\n" + - "color: #b94a48;" + - "padding: 8px 35px 8px 14px;" + - "border: 1px solid #eed3d7;}"; - - public static String markdown2Html(@NotNull String description) { - description = StringUtil.replace(description, "class=\"alert alert-success\"", "class=\"alert-success\""); - description = StringUtil.replace(description, "class=\"alert alert-error\"", "class=\"alert-error\""); - ArrayList lines = ContainerUtil.newArrayList(description.split("\n|\r|\r\n")); - MarkdownUtil.replaceHeaders(lines); - return ourMarkdownProcessor.markdown(StringUtil.join(lines, "\n")); - } - - public static JEditorPane createLatexPane(@NotNull final String source) { - final JEditorPane editorPane = new JEditorPane(); - editorPane.setBackground(IpnbEditorUtil.getBackground()); - editorPane.setContentType(new HTMLEditorKit().getContentType()); - editorPane.setEditorKit(new HTMLEditorKit()); - final HTMLDocument document = (HTMLDocument)editorPane.getDocument(); - final StyleSheet sheet = document.getStyleSheet(); - sheet.addRule(ourBodyRule); - sheet.addRule(ourCodeRule); - sheet.addRule(ourAlertRule); - sheet.addRule(ourAlertSuccessRule); - sheet.addRule(ourAlertErrorRule); - - editorPane.setEditable(false); - - final String html = convertToHtml(source, document); - editorPane.setText("" + html + ""); - - editorPane.addMouseListener(new MouseAdapter() { + panel.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { - final Container parent = editorPane.getParent(); - final MouseEvent parentEvent = SwingUtilities.convertMouseEvent(editorPane, e, parent); + final Container parent = panel.getParent(); + final MouseEvent parentEvent = SwingUtilities.convertMouseEvent(panel, e, parent); parent.dispatchEvent(parentEvent); } }); - editorPane.addHyperlinkListener(new BrowserHyperlinkListener()); //TODO: jump to the section (see User Interface#Utilities) - return editorPane; + return panel; } + public static JComponent createHtmlPanel(@NotNull final String source, int width) { + Platform.setImplicitExit(false); - private static String convertToHtml(@NotNull final String source, @NotNull final HTMLDocument document) { + final JFXPanel javafxPanel = new JFXPanel(){ + @Override + protected void processMouseWheelEvent(MouseWheelEvent e) { + final Container parent = getParent(); + final MouseEvent parentEvent = SwingUtilities.convertMouseEvent(this, e, parent); + parent.dispatchEvent(parentEvent); + } + }; + javafxPanel.setBackground(IpnbEditorUtil.getBackground()); + + Platform.runLater(() -> { + final WebView webView = new WebView(); + webView.setOnDragDetected(new EventHandler() { + @Override + public void handle(javafx.scene.input.MouseEvent event) { + } + }); + final WebEngine engine = webView.getEngine(); + initHyperlinkListener(engine); + engine.setOnStatusChanged(new EventHandler>() { + public void handle(WebEvent status) { + adjustHeight(webView, javafxPanel, source); + } + }); + + final String prefix = String.format(ourPrefix, EditorColorsManager.getInstance().getGlobalScheme().getEditorFontSize()); + engine.loadContent(prefix + convertToHtml(source) + ourPostfix); + final BorderPane pane = new BorderPane(webView); + final Scene scene = new Scene(pane, width != 0 ? width : 20, 20); + javafxPanel.setScene(scene); + Platform.runLater(() -> adjustHeight(webView, javafxPanel, source)); + updateLaf(LafManager.getInstance().getCurrentLookAndFeel() instanceof DarculaLookAndFeelInfo, + pane, engine, javafxPanel); + }); + + return javafxPanel; + } + + private static String convertToHtml(@NotNull String source) { + source = StringUtil.replace(source, "class=\"alert alert-success\"", "class=\"alert-success\""); + source = StringUtil.replace(source, "class=\"alert alert-error\"", "class=\"alert-error\""); + ArrayList lines = ContainerUtil.newArrayList(source.split("\n|\r|\r\n")); + + MarkdownUtil.replaceHeaders(lines); + source = StringUtil.join(lines, "\n"); final StringBuilder result = new StringBuilder(); - StringBuilder markdown = new StringBuilder(); - StringBuilder formula = new StringBuilder(); - boolean inCode = false; - int inMultiStringCode = 0; - boolean inEnd = false; + + source = replaceLinks(source); + source = ourMarkdownProcessor.markdown(source); + boolean escaped = false; - boolean backQuoted = false; - - int imageIndex = 0; - for (int i = 0; i != source.length(); ++i) { - final char charAt = source.charAt(i); - - if (charAt == '`') { - backQuoted = !backQuoted; - if (source.length() > i + 2 && source.charAt(i + 1) == '`' && source.charAt(i + 2) == '`') { - markdown.append(escaped ? "" : ""); - escaped = !escaped; - //noinspection AssignmentToForLoopParameter - i += 2; - continue; - } - } - if (escaped && charAt == '\n') { - markdown.append("
"); - continue; - } - - if (!escaped && !backQuoted) { - if (charAt == '$' && source.length() > i + 1 && source.charAt(i+1) != '$') { - inCode = !inCode; - } - - if (charAt == '\\' && source.substring(i).startsWith("\\begin")) { - inMultiStringCode += 1; - } - if (charAt == '\\' && source.substring(i).startsWith("\\end")) { - inEnd = true; - } - } - - final boolean doubleDollar = charAt == '$' && ((source.length() > i + 1 && source.charAt(i + 1) == '$') - || (i >= 1 && source.charAt(i - 1) == '$')); - if (inCode || inMultiStringCode != 0 || (!backQuoted && doubleDollar)) { - if (markdown.length() != 0) { - result.append(markdown.toString()); - markdown = new StringBuilder(); - } - formula.append(charAt); - } - else { - if (formula.length() != 0 && charAt == '$') { - formula.append(charAt); - } - else { - markdown.append(charAt); - } - if (formula.length() != 0) { - addFormula(formula.toString(), document, imageIndex, result); - - imageIndex += 1; - formula = new StringBuilder(); - } - } - - if (inEnd && charAt == '}') { - inMultiStringCode -= 1; - inEnd = false; - } - + int start = 0; + int end = StringUtil.indexOf(source, "```"); + while (end > 0) { + result.append(source.substring(start, end)); + result.append(escaped? "" : "
");
+      escaped = !escaped;
+      start = end + 3;
+      end = StringUtil.indexOf(source, "```", end + 1);
     }
-    if (formula.length() != 0) {
-      addFormula(formula.toString(), document, imageIndex, result);
-    }
-    if (markdown.length() != 0) {
-      result.append(markdown.toString());
-    }
-    return markdown2Html(result.toString());
+    result.append(source.substring(start));
+
+    return result.toString();
   }
 
-  private static void addFormula(@NotNull final String formulaText, @NotNull final HTMLDocument editorDocument, int imageIndex, StringBuilder result) {
-    final SnuggleEngine engine = new SnuggleEngine();
-    engine.getPackages().add(0, IpnbTexPackageDefinitions.getPackage());
+  @NotNull
+  private static String replaceLinks(@NotNull String source) {
+    final Pattern inlineLink = Pattern.compile("(\\[(.*?)\\]\\([ \\t]*?[ \\t]*(([\'\"])(.*?)\\5)?\\))", 32);
+    final Matcher matcher = inlineLink.matcher(source);
+    final StringBuffer sb = new StringBuffer();
+    while (matcher.find()) {
+      String linkText = matcher.group(2);
+      String url = matcher.group(3);
+      String title = matcher.group(6);
+      StringBuilder link = new StringBuilder();
+      link.append("").append(linkText);
+      link.append("");
+      matcher.appendReplacement(sb, link.toString());
+    }
+    matcher.appendTail(sb);
 
-    final SnuggleInput input = new SnuggleInput(formulaText);
+    source = sb.toString();
+    return source;
+  }
 
+  private static void initHyperlinkListener(@NotNull final WebEngine engine) {
+    engine.getLoadWorker().stateProperty().addListener((ov, oldState, newState) -> {
+      if (newState == Worker.State.SUCCEEDED) {
+        final EventListener listener = new HyperlinkListener(engine);
+        addListenerToAllHyperlinkItems(engine, listener);
+      }
+    });
+  }
+
+  private static void addListenerToAllHyperlinkItems(WebEngine engine, EventListener listener) {
+    final Document doc = engine.getDocument();
+    if (doc != null) {
+      final NodeList nodeList = doc.getElementsByTagName("a");
+      for (int i = 0; i < nodeList.getLength(); i++) {
+        ((EventTarget)nodeList.item(i)).addEventListener("click", listener, false);
+      }
+    }
+  }
+
+  private static class HyperlinkListener implements EventListener {
+    @NotNull private final WebEngine myEngine;
+
+    public HyperlinkListener(@NotNull final WebEngine engine) {
+      myEngine = engine;
+    }
+
+    @Override
+    public void handleEvent(Event ev) {
+      String domEventType = ev.getType();
+      if (domEventType.equals("click")) {
+        myEngine.setJavaScriptEnabled(true);
+        myEngine.getLoadWorker().cancel();
+        ev.preventDefault();
+
+        UIUtil.invokeLaterIfNeeded(() -> {
+
+          final String href = ((Element)ev.getTarget()).getAttribute("href");
+          if (href == null) return;
+          final URI address;
+          try {
+            address = new URI(href);
+            BrowserUtil.browse(address);
+          }
+          catch (URISyntaxException e) {
+            LOG.warn(e.getMessage());
+          }
+        });
+
+      }
+    }
+  }
+
+  private static void adjustHeight(final WebView webView, final JFXPanel javafxPanel, String source) {
     try {
-      session.parseInput(input);
-      XMLStringOutputOptions options = new XMLStringOutputOptions();
-      options.setIndenting(true);
-      options.setAddingMathSourceAnnotations(false);
-      final String xmlString = session.buildXMLString(options);
-      if (xmlString == null) return;
-      final LayoutContextImpl context = (LayoutContextImpl)LayoutContextImpl.getDefaultLayoutContext();
-      context.setParameter(Parameter.MATHCOLOR, UIUtil.getTextAreaForeground());
-      context.setParameter(Parameter.MATHSIZE, 18);
+      Object result = webView.getEngine().executeScript("document.getElementById(\"mydiv\").offsetHeight");
+      if (result instanceof Integer) {
+        final int fontSize = EditorColorsManager.getInstance().getGlobalScheme().getEditorFontSize();
+        double x = (double)source.length() * 8 / (int)result;
+        final double height = (source.length() * fontSize) / x + 20;
+        final int width = (int)(webView.getWidth() == 0 ? 1500 : webView.getWidth());
+        final Dimension size = new Dimension(width, (int)height);
 
-      final Document document = MathMLParserSupport.parseString(xmlString);
-
-      final BufferedImage image = Converter.getInstance().render(document, context);
-
-      try {
-        @SuppressWarnings("unchecked")
-        Dictionary cache = (Dictionary)editorDocument.getProperty("imageCache");
-        if (cache == null) {
-          //noinspection UseOfObsoleteCollectionType
-          cache = new Hashtable();
-          editorDocument.putProperty("imageCache", cache);
-        }
-
-        final URL u = new URL(ourImagePrefix + imageIndex + ".jpg");
-        cache.put(u, image);
-      }
-      catch (MalformedURLException e) {
-        LOG.error(e);
+        UIUtil.invokeLaterIfNeeded(new Runnable() {
+          @Override
+          public void run() {
+            javafxPanel.setPreferredSize(size);
+            javafxPanel.revalidate();
+            javafxPanel.repaint();
+          }
+        });
       }
     }
-    catch (IOException e) {
-      LOG.error(e);
+    catch (JSException ignore) {
     }
-    catch (SAXException e) {
-      LOG.error(e);
-      LOG.info("formula text " + formulaText);
+  }
+
+  private static void updateLaf(boolean isDarcula, BorderPane pane, WebEngine engine, JFXPanel jfxPanel) {
+    if (isDarcula) {
+      updateLafDarcula(pane, engine, jfxPanel);
     }
-    catch (ParserConfigurationException e) {
-      LOG.error(e);
-    }
-    if (formulaText.startsWith("$$") || formulaText.startsWith("\\begin")) {
-      result.append("

"); - } - else - result.append(""); + } + + private static void updateLafDarcula(BorderPane pane, WebEngine engine, JFXPanel jfxPanel) { + Platform.runLater(() -> { + ourStyleUrl = IpnbFileType.class.getResource("/style/javaFXBrowserDarcula.css"); + engine.setUserStyleSheetLocation(ourStyleUrl.toExternalForm()); + pane.setStyle("-fx-background-color: #313335"); + jfxPanel.getScene().getStylesheets().add(ourStyleUrl.toExternalForm()); + engine.reload(); + }); } } diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/IpnbFileEditor.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/IpnbFileEditor.java index b72dd2c1403d..c392c7f0786d 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/IpnbFileEditor.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/IpnbFileEditor.java @@ -183,7 +183,7 @@ public class IpnbFileEditor extends UserDataHolderBase implements FileEditor { public void actionPerformed(ActionEvent e) { IpnbReloadKernelAction.reloadKernel(IpnbFileEditor.this); } - }, AllIcons.Actions.Refresh, "Restart kernel"); + }, AllIcons.Actions.Refresh, "Restart Kernel"); } private void addSaveButton(@NotNull final JPanel controlPanel) { diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/actions/IpnbCreateFileAction.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/actions/IpnbCreateFileAction.java new file mode 100644 index 000000000000..189ee133571d --- /dev/null +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/actions/IpnbCreateFileAction.java @@ -0,0 +1,41 @@ +/* + * 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.plugins.ipnb.editor.actions; + +import com.intellij.ide.actions.CreateFileFromTemplateAction; +import com.intellij.ide.actions.CreateFileFromTemplateDialog; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiDirectory; +import org.jetbrains.plugins.ipnb.IpnbFileType; + +public class IpnbCreateFileAction extends CreateFileFromTemplateAction implements DumbAware { + public IpnbCreateFileAction() { + super("IPython Notebook", "Creates an IPython Notebook file from the specified template", IpnbFileType.INSTANCE.getIcon()); + } + + @Override + protected void buildDialog(Project project, PsiDirectory directory, CreateFileFromTemplateDialog.Builder builder) { + builder + .setTitle("New IPython Notebook") + .addKind("IPython Notebook", IpnbFileType.INSTANCE.getIcon(), "IPython Notebook"); + } + + @Override + protected String getActionName(PsiDirectory directory, String newName, String templateName) { + return "Create IPython Notebook " + newName; + } +} diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/IpnbFilePanel.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/IpnbFilePanel.java index 0fd8853ed919..fb0a77a7ab44 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/IpnbFilePanel.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/IpnbFilePanel.java @@ -162,7 +162,7 @@ public class IpnbFilePanel extends JPanel implements Scrollable, DataProvider, D myIpnbPanels.add(panel); } else if (cell instanceof IpnbMarkdownCell) { - panel = new IpnbMarkdownPanel((IpnbMarkdownCell)cell); + panel = new IpnbMarkdownPanel((IpnbMarkdownCell)cell, this); addComponent(panel); } else if (cell instanceof IpnbHeadingCell) { @@ -369,7 +369,7 @@ public class IpnbFilePanel extends JPanel implements Scrollable, DataProvider, D panel = new IpnbCodePanel(myProject, myParent, (IpnbCodeCell)cell); } else if (cell instanceof IpnbMarkdownCell) { - panel = new IpnbMarkdownPanel((IpnbMarkdownCell)cell); + panel = new IpnbMarkdownPanel((IpnbMarkdownCell)cell, myParent.getIpnbFilePanel()); } else if (cell instanceof IpnbHeadingCell) { panel = new IpnbHeadingPanel((IpnbHeadingCell)cell); diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/IpnbHeadingPanel.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/IpnbHeadingPanel.java index 38c5cc4512f0..b5874d4a72ce 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/IpnbHeadingPanel.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/IpnbHeadingPanel.java @@ -1,5 +1,6 @@ package org.jetbrains.plugins.ipnb.editor.panels; +import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.ui.components.JBLabel; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.ipnb.editor.IpnbEditorUtil; @@ -18,7 +19,8 @@ public class IpnbHeadingPanel extends IpnbEditablePanel" + myCell.getSourceAsString() + "" + myCell.getSourceAsString() + ""; } diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/IpnbMarkdownPanel.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/IpnbMarkdownPanel.java index 918b22a2e08c..c462a6a2b24b 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/IpnbMarkdownPanel.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/IpnbMarkdownPanel.java @@ -6,10 +6,13 @@ import org.jetbrains.plugins.ipnb.format.cells.IpnbMarkdownCell; import javax.swing.*; -public class IpnbMarkdownPanel extends IpnbEditablePanel { +public class IpnbMarkdownPanel extends IpnbEditablePanel { - public IpnbMarkdownPanel(@NotNull final IpnbMarkdownCell cell) { + private final IpnbFilePanel myParent; + + public IpnbMarkdownPanel(@NotNull final IpnbMarkdownCell cell, @NotNull final IpnbFilePanel parent) { super(cell); + myParent = parent; initPanel(); } @@ -19,8 +22,9 @@ public class IpnbMarkdownPanel extends IpnbEditablePanel content = token.getArguments()[0].getContents(); - Element result = builder.appendMathMLElement(parentElement, "mover"); - builder.handleMathTokensAsSingleElement(result, content); - builder.appendMathMLOperatorElement(result, "\u02D9"); - } - }, null); - ourPackage.addComplexCommandSameArgMode("pi", false, 0, MATH_MODE_ONLY, new CommandHandler() { - @Override - public void handleCommand(DOMBuilder builder, Element parentElement, CommandToken token) throws SnuggleParseException { - builder.appendMathMLOperatorElement(parentElement, "\u03c0"); - } - }, null); - ourPackage.addEnvironment("eqnarray", ALL_MODES, MATH, Interpretation.TABULAR, new EqnArrayHandler(), START_NEW_XHTML_BLOCK); - ourPackage.addSimpleMathCommand("lt", new MathOperatorInterpretation("<")); - ourPackage.addSimpleMathCommand("gt", new MathOperatorInterpretation(">")); - - ourPackage.loadMathCharacterDefinitions(ourMathCharacters); - } -} diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbCodeOutputPanel.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbCodeOutputPanel.java index 4b65051a71bd..1bf847c81c6f 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbCodeOutputPanel.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbCodeOutputPanel.java @@ -1,7 +1,10 @@ package org.jetbrains.plugins.ipnb.editor.panels.code; +import com.intellij.openapi.editor.colors.EditorColorsManager; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.ipnb.editor.IpnbEditorUtil; +import org.jetbrains.plugins.ipnb.editor.panels.IpnbFilePanel; import org.jetbrains.plugins.ipnb.editor.panels.IpnbPanel; import org.jetbrains.plugins.ipnb.format.cells.output.IpnbOutputCell; @@ -9,9 +12,11 @@ import javax.swing.*; import java.awt.*; public class IpnbCodeOutputPanel extends IpnbPanel { + protected final IpnbFilePanel myParent; - public IpnbCodeOutputPanel(@NotNull final K cell) { + public IpnbCodeOutputPanel(@NotNull final K cell, @Nullable final IpnbFilePanel parent) { super(cell, new BorderLayout()); + myParent = parent; myViewPanel = createViewPanel(); add(myViewPanel); } @@ -20,6 +25,9 @@ public class IpnbCodeOutputPanel extends IpnbPanel { } else if (outputCell instanceof IpnbHtmlOutputCell) { addPromptPanel(panel, myCell.getPromptNumber(), promptType, - new IpnbHtmlPanel((IpnbHtmlOutputCell)outputCell)); + new IpnbHtmlPanel((IpnbHtmlOutputCell)outputCell, myParent.getIpnbFilePanel())); } else if (outputCell instanceof IpnbLatexOutputCell) { addPromptPanel(panel, myCell.getPromptNumber(), promptType, - new IpnbLatexPanel((IpnbLatexOutputCell)outputCell)); + new IpnbLatexPanel((IpnbLatexOutputCell)outputCell, myParent.getIpnbFilePanel())); } else if (outputCell instanceof IpnbErrorOutputCell) { addPromptPanel(panel, myCell.getPromptNumber(), promptType, @@ -101,7 +101,7 @@ public class IpnbCodePanel extends IpnbEditablePanel { } else if (outputCell.getSourceAsString() != null) { addPromptPanel(panel, myCell.getPromptNumber(), promptType, - new IpnbCodeOutputPanel(outputCell)); + new IpnbCodeOutputPanel(outputCell, myParent.getIpnbFilePanel())); } mainPanel.add(panel); } diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbErrorPanel.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbErrorPanel.java index fca3dd12eca4..34a5407aa539 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbErrorPanel.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbErrorPanel.java @@ -1,5 +1,6 @@ package org.jetbrains.plugins.ipnb.editor.panels.code; +import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.JBColor; import org.jetbrains.annotations.NotNull; @@ -16,7 +17,7 @@ import java.util.List; public class IpnbErrorPanel extends IpnbCodeOutputPanel { public IpnbErrorPanel(@NotNull final IpnbErrorOutputCell cell) { - super(cell); + super(cell, null); } @Override @@ -24,6 +25,9 @@ public class IpnbErrorPanel extends IpnbCodeOutputPanel { final List text = myCell.getText(); if (text == null) return new JLabel(); ColorPane ansiColoredPane = new ColorPane(); + final Font font = ansiColoredPane.getFont(); + final Font newFont = new Font(font.getName(), font.getStyle(), EditorColorsManager.getInstance().getGlobalScheme().getEditorFontSize()); + ansiColoredPane.setFont(newFont); ansiColoredPane.appendANSI(StringUtil.join(text, "")); ansiColoredPane.setBackground(IpnbEditorUtil.getBackground()); ansiColoredPane.setEditable(false); diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbHtmlPanel.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbHtmlPanel.java index 1e10546a9002..afce5d4567bf 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbHtmlPanel.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbHtmlPanel.java @@ -1,29 +1,22 @@ package org.jetbrains.plugins.ipnb.editor.panels.code; -import com.intellij.ui.components.JBLabel; +import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.plugins.ipnb.editor.IpnbEditorUtil; +import org.jetbrains.plugins.ipnb.IpnbUtils; +import org.jetbrains.plugins.ipnb.editor.panels.IpnbFilePanel; import org.jetbrains.plugins.ipnb.format.cells.output.IpnbHtmlOutputCell; import javax.swing.*; public class IpnbHtmlPanel extends IpnbCodeOutputPanel { - public IpnbHtmlPanel(@NotNull final IpnbHtmlOutputCell cell) { - super(cell); + + public IpnbHtmlPanel(@NotNull final IpnbHtmlOutputCell cell, @NotNull final IpnbFilePanel parent) { + super(cell, parent); } @Override protected JComponent createViewPanel() { - final StringBuilder text = new StringBuilder(""); - for (String html : myCell.getHtmls()) { - html = html.replace("\"", "'"); - text.append(html); - } - text.append(""); - - final JBLabel label = new JBLabel(text.toString()); - label.setBackground(IpnbEditorUtil.getBackground()); - label.setOpaque(true); - return label; + final int width = myParent.getWidth(); + return IpnbUtils.createLatexPane(StringUtil.join(myCell.getHtmls(), ""), width); } } diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbImagePanel.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbImagePanel.java index c57528359fa8..efd115cb9caf 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbImagePanel.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbImagePanel.java @@ -3,10 +3,10 @@ package org.jetbrains.plugins.ipnb.editor.panels.code; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.components.JBLabel; -import com.intellij.util.Base64; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.ipnb.editor.IpnbEditorUtil; import org.jetbrains.plugins.ipnb.format.cells.output.IpnbImageOutputCell; +import sun.misc.BASE64Decoder; import javax.imageio.ImageIO; import javax.swing.*; @@ -17,7 +17,7 @@ public class IpnbImagePanel extends IpnbCodeOutputPanel { private static final Logger LOG = Logger.getInstance(IpnbImagePanel.class); public IpnbImagePanel(@NotNull final IpnbImageOutputCell cell) { - super(cell); + super(cell, null); } @Override @@ -27,7 +27,7 @@ public class IpnbImagePanel extends IpnbCodeOutputPanel { final JBLabel label = new JBLabel(); if (!StringUtil.isEmptyOrSpaces(png)) { try { - byte[] btDataFile = Base64.decode(png); + byte[] btDataFile = new BASE64Decoder().decodeBuffer(png); BufferedImage image = ImageIO.read(new ByteArrayInputStream(btDataFile)); label.setIcon(new ImageIcon(image)); } @@ -41,4 +41,4 @@ public class IpnbImagePanel extends IpnbCodeOutputPanel { return label; } -} \ No newline at end of file +} diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbLatexPanel.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbLatexPanel.java index a8eab10e9a93..c8dbe9044c4d 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbLatexPanel.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbLatexPanel.java @@ -5,19 +5,22 @@ import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.ipnb.IpnbUtils; import org.jetbrains.plugins.ipnb.editor.IpnbEditorUtil; +import org.jetbrains.plugins.ipnb.editor.panels.IpnbFilePanel; import org.jetbrains.plugins.ipnb.format.cells.output.IpnbLatexOutputCell; import javax.swing.*; public class IpnbLatexPanel extends IpnbCodeOutputPanel { - public IpnbLatexPanel(@NotNull final IpnbLatexOutputCell cell) { - super(cell); + + public IpnbLatexPanel(@NotNull final IpnbLatexOutputCell cell, @NotNull final IpnbFilePanel parent) { + super(cell, parent); setLayout(new VerticalFlowLayout(VerticalFlowLayout.TOP)); setBackground(IpnbEditorUtil.getBackground()); } @Override protected JComponent createViewPanel() { - return IpnbUtils.createLatexPane(StringUtil.join(myCell.getLatex(), "")); + final int width = myParent.getWidth(); + return IpnbUtils.createLatexPane(StringUtil.join(myCell.getLatex(), ""), width); } } diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbStreamPanel.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbStreamPanel.java index 06f2c8d0d7ef..6b068f5e0dfe 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbStreamPanel.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/code/IpnbStreamPanel.java @@ -8,7 +8,7 @@ import javax.swing.*; public class IpnbStreamPanel extends IpnbCodeOutputPanel { public IpnbStreamPanel(@NotNull final IpnbStreamOutputCell cell) { - super(cell); + super(cell, null); } @Override diff --git a/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java b/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java index 9b22b33d8b48..b1016ef85ea8 100644 --- a/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java @@ -93,7 +93,7 @@ public class PyProtectedMemberInspection extends PyInspection { private boolean isImportFromTheSamePackage(PyReferenceExpression importSource) { PsiDirectory directory = importSource.getContainingFile().getContainingDirectory(); - if (PyUtil.isPackage(directory, true, importSource.getContainingFile()) && + if (directory != null && PyUtil.isPackage(directory, true, importSource.getContainingFile()) && directory.getName().equals(importSource.getName())) { return true; }