mirror of
https://github.com/ilyakooo0/intellij-haskell.git
synced 2024-09-11 14:56:19 +03:00
Initial version.
This commit is contained in:
commit
a737fbc1e1
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
/gen
|
||||
/dist
|
||||
/out
|
||||
/target
|
||||
/.idea/workspace.xml
|
||||
/.idea/vcs.xml
|
||||
/.idea/rik.xml
|
||||
/.idea/dictionaries/rik.xml
|
||||
*~
|
1
.idea/.name
Normal file
1
.idea/.name
Normal file
@ -0,0 +1 @@
|
||||
intellij-haskell
|
23
.idea/compiler.xml
Normal file
23
.idea/compiler.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<option name="DEFAULT_COMPILER" value="Javac" />
|
||||
<resourceExtensions />
|
||||
<wildcardResourcePatterns>
|
||||
<entry name="!?*.java" />
|
||||
<entry name="!?*.form" />
|
||||
<entry name="!?*.class" />
|
||||
<entry name="!?*.groovy" />
|
||||
<entry name="!?*.scala" />
|
||||
<entry name="!?*.flex" />
|
||||
<entry name="!?*.kt" />
|
||||
<entry name="!?*.clj" />
|
||||
</wildcardResourcePatterns>
|
||||
<annotationProcessing>
|
||||
<profile default="true" name="Default" enabled="false">
|
||||
<processorPath useClasspath="true" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
</component>
|
||||
</project>
|
||||
|
3
.idea/copyright/profiles_settings.xml
Normal file
3
.idea/copyright/profiles_settings.xml
Normal file
@ -0,0 +1,3 @@
|
||||
<component name="CopyrightManager">
|
||||
<settings default="" />
|
||||
</component>
|
5
.idea/encodings.xml
Normal file
5
.idea/encodings.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
|
||||
</project>
|
||||
|
8
.idea/highlighting.xml
Normal file
8
.idea/highlighting.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="HighlightingAdvisor">
|
||||
<option name="SUGGEST_TYPE_AWARE_HIGHLIGHTING" value="false" />
|
||||
<option name="TYPE_AWARE_HIGHLIGHTING_ENABLED" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
|
10
.idea/libraries/scala_compiler.xml
Normal file
10
.idea/libraries/scala_compiler.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<component name="libraryTable">
|
||||
<library name="scala-compiler">
|
||||
<CLASSES>
|
||||
<root url="file:///usr/share/scala/lib" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
<jarDirectory url="file:///usr/share/scala/lib" recursive="false" />
|
||||
</library>
|
||||
</component>
|
21
.idea/libraries/scala_library.xml
Normal file
21
.idea/libraries/scala_library.xml
Normal file
@ -0,0 +1,21 @@
|
||||
<component name="libraryTable">
|
||||
<library name="scala-library">
|
||||
<CLASSES>
|
||||
<root url="jar:///usr/share/scala/lib/akka-actor_2.11-2.3.2.jar!/" />
|
||||
<root url="jar:///usr/share/scala/lib/config-1.2.0.jar!/" />
|
||||
<root url="jar:///usr/share/scala/lib/jline-2.11.jar!/" />
|
||||
<root url="jar:///usr/share/scala/lib/scala-actors-2.11.0.jar!/" />
|
||||
<root url="jar:///usr/share/scala/lib/scala-compiler.jar!/" />
|
||||
<root url="jar:///usr/share/scala/lib/scala-continuations-library_2.11-1.0.1.jar!/" />
|
||||
<root url="jar:///usr/share/scala/lib/scala-library.jar!/" />
|
||||
<root url="jar:///usr/share/scala/lib/scala-parser-combinators_2.11-1.0.1.jar!/" />
|
||||
<root url="jar:///usr/share/scala/lib/scala-reflect.jar!/" />
|
||||
<root url="jar:///usr/share/scala/lib/scala-swing_2.11-1.0.1.jar!/" />
|
||||
<root url="jar:///usr/share/scala/lib/scala-xml_2.11-1.0.1.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$USER_HOME$/scala/scala-library-2.11.0-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
11
.idea/libraries/scalatest.xml
Normal file
11
.idea/libraries/scalatest.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<component name="libraryTable">
|
||||
<library name="scalatest">
|
||||
<CLASSES>
|
||||
<root url="jar://$USER_HOME$/scala/scalatest/scalatest_2.11-2.1.5.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$USER_HOME$/scala/scalatest/scalatest_2.11-2.1.5-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
10
.idea/misc.xml
Normal file
10
.idea/misc.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="EntryPointsManager">
|
||||
<entry_points version="2.0" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="IDEA IU-135.690" project-jdk-type="IDEA JDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
|
9
.idea/modules.xml
Normal file
9
.idea/modules.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/intellij-haskell.iml" filepath="$PROJECT_DIR$/intellij-haskell.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
|
5
.idea/scopes/scope_settings.xml
Normal file
5
.idea/scopes/scope_settings.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<component name="DependencyValidationManager">
|
||||
<state>
|
||||
<option name="SKIP_IMPORT_STATEMENTS" value="false" />
|
||||
</state>
|
||||
</component>
|
125
.idea/uiDesigner.xml
Normal file
125
.idea/uiDesigner.xml
Normal file
@ -0,0 +1,125 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Palette2">
|
||||
<group name="Swing">
|
||||
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
||||
</item>
|
||||
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
|
||||
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
||||
<initial-values>
|
||||
<property name="text" value="Button" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="RadioButton" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="CheckBox" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="Label" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
||||
<preferred-size width="-1" height="20" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
||||
</item>
|
||||
</group>
|
||||
</component>
|
||||
</project>
|
||||
|
46
META-INF/plugin.xml
Normal file
46
META-INF/plugin.xml
Normal file
@ -0,0 +1,46 @@
|
||||
<idea-plugin version="2">
|
||||
<id>com.powertuple.intellij.haskell</id>
|
||||
<name>Haskell plugin for IntelliJ</name>
|
||||
<version>0.1</version>
|
||||
<vendor email="rikvdkleij@gmail.com" url="http://www.powertuple.com">PowerTuple</vendor>
|
||||
|
||||
<description><![CDATA[
|
||||
Haskell support.
|
||||
]]></description>
|
||||
|
||||
<change-notes><![CDATA[
|
||||
First version.
|
||||
]]>
|
||||
</change-notes>
|
||||
|
||||
<!-- please see http://confluence.jetbrains.com/display/IDEADEV/Build+Number+Ranges for description -->
|
||||
<idea-version since-build="135"/>
|
||||
|
||||
<!-- please see http://confluence.jetbrains.com/display/IDEADEV/Plugin+Compatibility+with+IntelliJ+Platform+Products
|
||||
on how to target different products -->
|
||||
<!-- uncomment to enable plugin in all products
|
||||
<depends>com.intellij.modules.lang</depends>
|
||||
-->
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<fileTypeFactory implementation="com.powertuple.intellij.haskell.HaskellFileTypeFactory"/>
|
||||
<lang.parserDefinition language="Haskell" implementationClass="com.powertuple.intellij.haskell.HaskellParserDefinition"/>
|
||||
<lang.syntaxHighlighterFactory key="Haskell"
|
||||
implementationClass="com.powertuple.intellij.haskell.highlighter.HaskellSyntaxHighlighterFactory"/>
|
||||
|
||||
<externalAnnotator language="Haskell" implementationClass="com.powertuple.intellij.haskell.annotator.GhcModExternalAnnotator"/>
|
||||
</extensions>
|
||||
|
||||
<application-components>
|
||||
<!-- Add your application components here -->
|
||||
</application-components>
|
||||
|
||||
<project-components>
|
||||
<!-- Add your project components here -->
|
||||
</project-components>
|
||||
|
||||
<actions>
|
||||
<!-- Add your actions here -->
|
||||
</actions>
|
||||
|
||||
</idea-plugin>
|
27
intellij-haskell.iml
Normal file
27
intellij-haskell.iml
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PLUGIN_MODULE" version="4">
|
||||
<component name="DevKit.ModuleBuildProperties" url="file://$MODULE_DIR$/META-INF/plugin.xml" />
|
||||
<component name="FacetManager">
|
||||
<facet type="scala" name="Scala">
|
||||
<configuration>
|
||||
<option name="compilerLibraryLevel" value="Project" />
|
||||
<option name="compilerLibraryName" value="scala-compiler" />
|
||||
<option name="languageLevel" value="Scala 2.11" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="scala-library" level="project" />
|
||||
<orderEntry type="library" name="scalatest" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
|
BIN
resources/icons/._haskell-small-logo.png
Normal file
BIN
resources/icons/._haskell-small-logo.png
Normal file
Binary file not shown.
BIN
resources/icons/haskell-small-logo.png
Normal file
BIN
resources/icons/haskell-small-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
BIN
resources/icons/haskell_24x24.png
Normal file
BIN
resources/icons/haskell_24x24.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 866 B |
39
src/com/powertuple/intellij/haskell/HaskellFileType.java
Normal file
39
src/com/powertuple/intellij/haskell/HaskellFileType.java
Normal file
@ -0,0 +1,39 @@
|
||||
package com.powertuple.intellij.haskell;
|
||||
|
||||
import com.intellij.openapi.fileTypes.LanguageFileType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public class HaskellFileType extends LanguageFileType {
|
||||
public static final HaskellFileType INSTANCE = new HaskellFileType();
|
||||
|
||||
private HaskellFileType() {
|
||||
super(com.powertuple.intellij.haskell.HaskellLanguage.INSTANCE);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Haskell file";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Haskell language file";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getDefaultExtension() {
|
||||
return "hs";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
return HaskellIcons.HASKELL_SMALL_LOGO;
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.powertuple.intellij.haskell;
|
||||
|
||||
import com.intellij.openapi.fileTypes.FileTypeConsumer;
|
||||
import com.intellij.openapi.fileTypes.FileTypeFactory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class HaskellFileTypeFactory extends FileTypeFactory {
|
||||
@Override
|
||||
public void createFileTypes(@NotNull FileTypeConsumer consumer) {
|
||||
consumer.consume(HaskellFileType.INSTANCE, "Haskell");
|
||||
}
|
||||
}
|
9
src/com/powertuple/intellij/haskell/HaskellIcons.java
Normal file
9
src/com/powertuple/intellij/haskell/HaskellIcons.java
Normal file
@ -0,0 +1,9 @@
|
||||
package com.powertuple.intellij.haskell;
|
||||
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public class HaskellIcons {
|
||||
public static final Icon HASKELL_SMALL_LOGO = IconLoader.getIcon("/icons/haskell-small-logo.png");
|
||||
}
|
21
src/com/powertuple/intellij/haskell/HaskellLanguage.java
Normal file
21
src/com/powertuple/intellij/haskell/HaskellLanguage.java
Normal file
@ -0,0 +1,21 @@
|
||||
package com.powertuple.intellij.haskell;
|
||||
|
||||
import com.intellij.lang.Language;
|
||||
|
||||
public class HaskellLanguage extends Language {
|
||||
public static final HaskellLanguage INSTANCE = new HaskellLanguage();
|
||||
|
||||
public HaskellLanguage() {
|
||||
super("Haskell");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "Haskell language";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCaseSensitive() {
|
||||
return true;
|
||||
}
|
||||
}
|
9
src/com/powertuple/intellij/haskell/HaskellLexer.java
Normal file
9
src/com/powertuple/intellij/haskell/HaskellLexer.java
Normal file
@ -0,0 +1,9 @@
|
||||
package com.powertuple.intellij.haskell;
|
||||
|
||||
import com.intellij.lexer.FlexAdapter;
|
||||
|
||||
public class HaskellLexer extends FlexAdapter {
|
||||
public HaskellLexer() {
|
||||
super(new _HaskellLexer());
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.powertuple.intellij.haskell;
|
||||
|
||||
import com.intellij.lexer.FlexAdapter;
|
||||
|
||||
public class HaskellLexerAdapter extends FlexAdapter {
|
||||
public HaskellLexerAdapter() {
|
||||
super(new _HaskellLexer());
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package com.powertuple.intellij.haskell;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.lang.ParserDefinition;
|
||||
import com.intellij.lang.PsiParser;
|
||||
import com.intellij.lexer.Lexer;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.FileViewProvider;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.TokenType;
|
||||
import com.intellij.psi.tree.IFileElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.powertuple.intellij.haskell.parser.HaskellParser;
|
||||
import com.powertuple.intellij.haskell.psi.HaskellFile;
|
||||
import com.powertuple.intellij.haskell.psi.HaskellTypes;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class HaskellParserDefinition implements ParserDefinition {
|
||||
public static final TokenSet WHITE_SPACES = TokenSet.create(TokenType.WHITE_SPACE);
|
||||
public static final TokenSet COMMENTS = TokenSet.create(HaskellTypes.HS_COMMENT, HaskellTypes.HS_NCOMMENT);
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Lexer createLexer(Project project) {
|
||||
return new HaskellLexerAdapter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiParser createParser(Project project) {
|
||||
return new HaskellParser();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IFileElementType getFileNodeType() {
|
||||
return new IFileElementType(Language.findInstance(HaskellLanguage.class));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public TokenSet getWhitespaceTokens() {
|
||||
return WHITE_SPACES;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public TokenSet getCommentTokens() {
|
||||
return COMMENTS;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public TokenSet getStringLiteralElements() {
|
||||
return TokenSet.create(
|
||||
HaskellTypes.HS_CHARACTER_LITERAL,
|
||||
HaskellTypes.HS_STRING_LITERAL
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElement createElement(ASTNode node) {
|
||||
return HaskellTypes.Factory.createElement(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiFile createFile(FileViewProvider viewProvider) {
|
||||
return new HaskellFile(viewProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpaceRequirements spaceExistanceTypeBetweenTokens(ASTNode left, ASTNode right) {
|
||||
return SpaceRequirements.MAY;
|
||||
}
|
||||
}
|
19
src/com/powertuple/intellij/haskell/HaskellParserUtil.java
Normal file
19
src/com/powertuple/intellij/haskell/HaskellParserUtil.java
Normal file
@ -0,0 +1,19 @@
|
||||
package com.powertuple.intellij.haskell;
|
||||
|
||||
import com.intellij.lang.PsiBuilder;
|
||||
import com.intellij.lang.parser.GeneratedParserUtilBase;
|
||||
|
||||
public class HaskellParserUtil extends GeneratedParserUtilBase {
|
||||
|
||||
public static boolean ghcMod(PsiBuilder builder_, int level_) {
|
||||
// if (builder_.eof()) return true;
|
||||
System.out.println("test rik van rikkie");
|
||||
// IElementType one = builder_.rawLookup(1);
|
||||
// IElementType two = builder_.rawLookup(2);
|
||||
// if (one == TokenType.WHITE_SPACE && (two == HaskellTypes.HS_DOT || two == null) || one == null && builder_.getTokenType() == HaskellTypes.HS_DOT) {
|
||||
// builder_.remapCurrentToken(TokenType.ERROR_ELEMENT);
|
||||
// return true;
|
||||
// }
|
||||
return false;
|
||||
}
|
||||
}
|
110
src/com/powertuple/intellij/haskell/_HaskellLexer.flex
Normal file
110
src/com/powertuple/intellij/haskell/_HaskellLexer.flex
Normal file
@ -0,0 +1,110 @@
|
||||
package com.powertuple.intellij.haskell;
|
||||
import com.intellij.lexer.*;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import static com.powertuple.intellij.haskell.psi.HaskellTypes.*;
|
||||
|
||||
%%
|
||||
|
||||
%{
|
||||
public _HaskellLexer() {
|
||||
this((java.io.Reader)null);
|
||||
}
|
||||
%}
|
||||
|
||||
%public
|
||||
%class _HaskellLexer
|
||||
%implements FlexLexer
|
||||
%function advance
|
||||
%type IElementType
|
||||
%unicode
|
||||
|
||||
ControlCharacter = [\000 - \037]
|
||||
Whitespace = ([ \t\n] | {ControlCharacter})+
|
||||
|
||||
SMALL=[a-z_] // ignoring any unicode lowercase letter for now
|
||||
LARGE=[A-Z] // ignoring any unicode uppercase letter for now
|
||||
DIGIT=[0-9] // ignoring any unicode decimal digit for now
|
||||
DECIMAL={DIGIT}+
|
||||
HEXADECIMAL=0[xX][0-9A-Fa-f]+
|
||||
OCTAL=0[oO][0-7]+
|
||||
FLOAT=[-+]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)([eE][-+]?[0-9]+)?
|
||||
COMMENT="--"[^\r\n]*
|
||||
|
||||
EOL=\r|\n|\r\n
|
||||
NCOMMENT="{-" (.|{EOL})* "-}"
|
||||
|
||||
CHARACTER_LITERAL = \' [^\'\\\r\n]* \'
|
||||
STRING_LITERAL = \" [^\"\\\r\n]* \"
|
||||
|
||||
%%
|
||||
<YYINITIAL> {
|
||||
{COMMENT} { return HS_COMMENT; }
|
||||
{NCOMMENT} { return HS_NCOMMENT; }
|
||||
|
||||
{Whitespace} { return com.intellij.psi.TokenType.WHITE_SPACE; }
|
||||
|
||||
|
||||
|
||||
// "{" { return HS_LEFT_BRACE; }
|
||||
// "}" { return HS_RIGHT_BRACE; }
|
||||
// "[" { return HS_LEFT_BRACKET; }
|
||||
// "]" { return HS_RIGHT_BRACKET; }
|
||||
// "(" { return HS_LEFT_PAREN; }
|
||||
// ")" { return HS_RIGHT_PAREN; }
|
||||
// ":" { return HS_COLON;}
|
||||
// ";" { return HS_SEMICOLON;}
|
||||
// "." { return HS_DOT; }
|
||||
// "," { return HS_COMMA; }
|
||||
// "|" { return HS_VERTICAL_BAR;}
|
||||
"=" { return HS_DEFINED_BY; }
|
||||
"<-" { return HS_DRAW_FROM_OR_MATCHES_OR_IN; }
|
||||
"=>" { return HS_INSTANCE_CONTEXTS; }
|
||||
|
||||
|
||||
"<" { return HS_LT; }
|
||||
">" { return HS_GT; }
|
||||
|
||||
// not listed as reserved identifier but have meaning in certain context
|
||||
// "as" { return HS_AS; }
|
||||
// "hiding" { return HS_HIDING; }
|
||||
// "qualified" { return HS_QUALIFIED; }
|
||||
|
||||
// reserved identifiers
|
||||
"case" { return HS_CASE_KEYWORD; }
|
||||
"class" { return HS_CLASS_KEYWORD; }
|
||||
"data" { return HS_DATA_KEYWORD; }
|
||||
"default" { return HS_DEFAULT_KEYWORD; }
|
||||
"deriving" { return HS_DERIVING_KEYWORD; }
|
||||
// "do" { return HS_DO_KEYWORD; }
|
||||
// "else" { return HS_ELSE_KEYWORD; }
|
||||
// "hiding" { return HS_HIDING_KEYWORD; }
|
||||
// "if" { return HS_IF_KEYWORD; }
|
||||
// "import" { return HS_IMPORT_KEYWORD; }
|
||||
// "in" { return HS_IN_KEYWORD; }
|
||||
// "infix" { return HS_INFIX_KEYWORD; }
|
||||
// "infixl" { return HS_INFIXL_KEYWORD; }
|
||||
// "infixr" { return HS_INFIXR_KEYWORD; }
|
||||
// "instance" { return HS_INSTANCE_KEYWORD; }
|
||||
// "let" { return HS_LET_KEYWORD; }
|
||||
"module" { return HS_MODULE_KEYWORD; }
|
||||
// "newtype" { return HS_NEWTYPE_KEYWORD; }
|
||||
// "of" { return HS_OF_KEYWORD; }
|
||||
// "then" { return HS_THEN_KEYWORD; }
|
||||
// "type" { return HS_TYPE_KEYWORD; }
|
||||
"where" { return HS_WHERE_KEYWORD; }
|
||||
|
||||
// "_" { return HS___KEYWORD; }
|
||||
|
||||
{CHARACTER_LITERAL} { return HS_CHARACTER_LITERAL; }
|
||||
{STRING_LITERAL} { return HS_STRING_LITERAL; }
|
||||
|
||||
{SMALL} { return HS_SMALL; }
|
||||
{LARGE} { return HS_LARGE; }
|
||||
{DECIMAL} { return HS_DECIMAL; }
|
||||
{HEXADECIMAL} { return HS_HEXADECIMAL; }
|
||||
{OCTAL} { return HS_OCTAL; }
|
||||
{FLOAT} { return HS_FLOAT; }
|
||||
|
||||
|
||||
[^] { return com.intellij.psi.TokenType.BAD_CHARACTER; }
|
||||
}
|
603
src/com/powertuple/intellij/haskell/_HaskellLexer.java
Normal file
603
src/com/powertuple/intellij/haskell/_HaskellLexer.java
Normal file
@ -0,0 +1,603 @@
|
||||
/* The following code was generated by JFlex 1.4.3 on 5/12/14 10:37 AM */
|
||||
|
||||
package com.powertuple.intellij.haskell;
|
||||
import com.intellij.lexer.*;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import static com.powertuple.intellij.haskell.psi.HaskellTypes.*;
|
||||
|
||||
|
||||
/**
|
||||
* This class is a scanner generated by
|
||||
* <a href="http://www.jflex.de/">JFlex</a> 1.4.3
|
||||
* on 5/12/14 10:37 AM from the specification file
|
||||
* <tt>/home/rik/idea/intellij-haskell/src/com/powertuple/intellij/haskell/_HaskellLexer.flex</tt>
|
||||
*/
|
||||
public class _HaskellLexer implements FlexLexer {
|
||||
/** initial size of the lookahead buffer */
|
||||
private static final int ZZ_BUFFERSIZE = 16384;
|
||||
|
||||
/** lexical states */
|
||||
public static final int YYINITIAL = 0;
|
||||
|
||||
/**
|
||||
* ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l
|
||||
* ZZ_LEXSTATE[l+1] is the state in the DFA for the lexical state l
|
||||
* at the beginning of a line
|
||||
* l is of the form l = 2*k, k a non negative integer
|
||||
*/
|
||||
private static final int ZZ_LEXSTATE[] = {
|
||||
0, 0
|
||||
};
|
||||
|
||||
/**
|
||||
* Translates characters to character classes
|
||||
*/
|
||||
private static final String ZZ_CMAP_PACKED =
|
||||
"\1\1\10\0\1\1\1\17\2\0\1\23\21\0\1\1\1\1\1\0"+
|
||||
"\1\27\4\0\1\26\3\0\1\15\1\0\1\22\2\0\1\5\7\14"+
|
||||
"\2\4\2\0\1\31\1\30\1\32\2\0\4\11\1\21\1\11\10\3"+
|
||||
"\1\13\10\3\1\7\2\3\1\0\1\16\2\0\1\2\1\0\1\34"+
|
||||
"\1\10\1\33\1\37\1\20\1\41\1\47\1\52\1\44\2\2\1\36"+
|
||||
"\1\50\1\46\1\12\2\2\1\43\1\35\1\40\1\42\1\45\1\51"+
|
||||
"\1\6\2\2\1\24\1\0\1\25\uff82\0";
|
||||
|
||||
/**
|
||||
* Translates characters to character classes
|
||||
*/
|
||||
private static final char [] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED);
|
||||
|
||||
/**
|
||||
* Translates DFA states to action switch labels.
|
||||
*/
|
||||
private static final int [] ZZ_ACTION = zzUnpackAction();
|
||||
|
||||
private static final String ZZ_ACTION_PACKED_0 =
|
||||
"\1\0\1\1\1\2\1\3\1\4\2\5\6\1\1\6"+
|
||||
"\1\7\1\10\4\3\4\0\1\11\2\0\1\12\2\0"+
|
||||
"\1\13\1\0\1\14\1\15\1\16\6\0\2\11\1\0"+
|
||||
"\1\17\1\20\10\0\1\21\1\22\3\0\1\23\2\0"+
|
||||
"\1\24\3\0\1\25\2\0\1\26\1\27\1\0\1\30";
|
||||
|
||||
private static int [] zzUnpackAction() {
|
||||
int [] result = new int[73];
|
||||
int offset = 0;
|
||||
offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int zzUnpackAction(String packed, int offset, int [] result) {
|
||||
int i = 0; /* index in packed string */
|
||||
int j = offset; /* index in unpacked array */
|
||||
int l = packed.length();
|
||||
while (i < l) {
|
||||
int count = packed.charAt(i++);
|
||||
int value = packed.charAt(i++);
|
||||
do result[j++] = value; while (--count > 0);
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Translates a state to a row index in the transition table
|
||||
*/
|
||||
private static final int [] ZZ_ROWMAP = zzUnpackRowMap();
|
||||
|
||||
private static final String ZZ_ROWMAP_PACKED_0 =
|
||||
"\0\0\0\53\0\126\0\53\0\53\0\201\0\254\0\327"+
|
||||
"\0\u0102\0\u012d\0\u0158\0\u0183\0\u01ae\0\u01d9\0\u0204\0\53"+
|
||||
"\0\u022f\0\u025a\0\u0285\0\u02b0\0\u02db\0\u0306\0\u0331\0\u035c"+
|
||||
"\0\u0387\0\u0102\0\u03b2\0\u03dd\0\u0408\0\u0183\0\53\0\u01ae"+
|
||||
"\0\53\0\53\0\53\0\u0433\0\u045e\0\u0489\0\u04b4\0\u04df"+
|
||||
"\0\u050a\0\u0535\0\u0560\0\u0560\0\u0331\0\u035c\0\u058b\0\u05b6"+
|
||||
"\0\u05e1\0\u060c\0\u0637\0\u0662\0\u068d\0\u06b8\0\u0408\0\53"+
|
||||
"\0\u06e3\0\u070e\0\u0739\0\53\0\u0764\0\u078f\0\53\0\u07ba"+
|
||||
"\0\u07e5\0\u0810\0\53\0\u083b\0\u0866\0\53\0\53\0\u0891"+
|
||||
"\0\53";
|
||||
|
||||
private static int [] zzUnpackRowMap() {
|
||||
int [] result = new int[73];
|
||||
int offset = 0;
|
||||
offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int zzUnpackRowMap(String packed, int offset, int [] result) {
|
||||
int i = 0; /* index in packed string */
|
||||
int j = offset; /* index in unpacked array */
|
||||
int l = packed.length();
|
||||
while (i < l) {
|
||||
int high = packed.charAt(i++) << 16;
|
||||
result[j++] = high | packed.charAt(i++);
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
/**
|
||||
* The transition table of the DFA
|
||||
*/
|
||||
private static final int [] ZZ_TRANS = zzUnpackTrans();
|
||||
|
||||
private static final String ZZ_TRANS_PACKED_0 =
|
||||
"\1\2\1\3\1\4\1\5\1\6\1\7\1\4\1\5"+
|
||||
"\1\4\1\5\1\4\1\5\1\6\1\10\1\11\1\3"+
|
||||
"\1\4\1\5\1\12\1\2\1\13\1\2\1\14\1\15"+
|
||||
"\1\16\1\17\1\20\1\21\3\4\1\22\10\4\1\23"+
|
||||
"\1\24\1\4\54\0\1\3\15\0\1\3\37\0\2\6"+
|
||||
"\6\0\1\6\1\0\1\25\1\0\2\26\35\0\2\6"+
|
||||
"\2\27\2\0\2\30\1\6\1\0\1\25\1\0\2\26"+
|
||||
"\35\0\2\31\6\0\1\31\1\0\1\32\34\0\17\33"+
|
||||
"\1\0\33\33\4\0\2\31\6\0\1\31\1\0\1\32"+
|
||||
"\3\0\1\34\52\0\1\35\30\0\16\36\2\0\3\36"+
|
||||
"\1\0\2\36\1\37\24\36\16\40\2\0\3\40\1\0"+
|
||||
"\3\40\1\41\23\40\32\0\1\42\42\0\1\43\64\0"+
|
||||
"\1\44\1\0\1\45\34\0\1\46\13\0\1\47\30\0"+
|
||||
"\1\50\112\0\1\51\17\52\1\0\33\52\4\0\2\53"+
|
||||
"\6\0\1\53\1\54\4\0\1\54\34\0\2\55\2\0"+
|
||||
"\2\55\2\0\1\55\3\0\2\55\11\0\2\55\2\0"+
|
||||
"\1\55\1\0\1\55\16\0\1\56\6\0\1\56\42\0"+
|
||||
"\2\31\6\0\1\31\1\0\1\25\1\0\2\26\35\0"+
|
||||
"\2\52\6\0\1\52\36\0\17\34\1\0\3\34\1\0"+
|
||||
"\27\34\22\35\1\57\30\35\35\0\1\60\51\0\1\61"+
|
||||
"\57\0\1\62\1\0\1\63\47\0\1\64\51\0\1\65"+
|
||||
"\33\0\1\66\36\0\2\52\6\0\1\52\3\0\2\26"+
|
||||
"\35\0\2\53\6\0\1\53\36\0\22\35\1\57\2\35"+
|
||||
"\1\67\25\35\20\0\1\70\67\0\1\71\51\0\1\72"+
|
||||
"\62\0\1\73\42\0\1\74\60\0\1\75\53\0\1\76"+
|
||||
"\44\0\1\77\57\0\1\100\55\0\1\101\43\0\1\102"+
|
||||
"\34\0\1\103\70\0\1\104\60\0\1\105\26\0\1\106"+
|
||||
"\72\0\1\107\60\0\1\110\53\0\1\111\3\0";
|
||||
|
||||
private static int [] zzUnpackTrans() {
|
||||
int [] result = new int[2236];
|
||||
int offset = 0;
|
||||
offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int zzUnpackTrans(String packed, int offset, int [] result) {
|
||||
int i = 0; /* index in packed string */
|
||||
int j = offset; /* index in unpacked array */
|
||||
int l = packed.length();
|
||||
while (i < l) {
|
||||
int count = packed.charAt(i++);
|
||||
int value = packed.charAt(i++);
|
||||
value--;
|
||||
do result[j++] = value; while (--count > 0);
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
|
||||
/* error codes */
|
||||
private static final int ZZ_UNKNOWN_ERROR = 0;
|
||||
private static final int ZZ_NO_MATCH = 1;
|
||||
private static final int ZZ_PUSHBACK_2BIG = 2;
|
||||
private static final char[] EMPTY_BUFFER = new char[0];
|
||||
private static final int YYEOF = -1;
|
||||
private static java.io.Reader zzReader = null; // Fake
|
||||
|
||||
/* error messages for the codes above */
|
||||
private static final String ZZ_ERROR_MSG[] = {
|
||||
"Unkown internal scanner error",
|
||||
"Error: could not match input",
|
||||
"Error: pushback value was too large"
|
||||
};
|
||||
|
||||
/**
|
||||
* ZZ_ATTRIBUTE[aState] contains the attributes of state <code>aState</code>
|
||||
*/
|
||||
private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute();
|
||||
|
||||
private static final String ZZ_ATTRIBUTE_PACKED_0 =
|
||||
"\1\0\1\11\1\1\2\11\12\1\1\11\4\1\4\0"+
|
||||
"\1\1\2\0\1\1\2\0\1\11\1\0\3\11\6\0"+
|
||||
"\2\1\1\0\2\1\10\0\1\1\1\11\3\0\1\11"+
|
||||
"\2\0\1\11\3\0\1\11\2\0\2\11\1\0\1\11";
|
||||
|
||||
private static int [] zzUnpackAttribute() {
|
||||
int [] result = new int[73];
|
||||
int offset = 0;
|
||||
offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int zzUnpackAttribute(String packed, int offset, int [] result) {
|
||||
int i = 0; /* index in packed string */
|
||||
int j = offset; /* index in unpacked array */
|
||||
int l = packed.length();
|
||||
while (i < l) {
|
||||
int count = packed.charAt(i++);
|
||||
int value = packed.charAt(i++);
|
||||
do result[j++] = value; while (--count > 0);
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
/** the current state of the DFA */
|
||||
private int zzState;
|
||||
|
||||
/** the current lexical state */
|
||||
private int zzLexicalState = YYINITIAL;
|
||||
|
||||
/** this buffer contains the current text to be matched and is
|
||||
the source of the yytext() string */
|
||||
private CharSequence zzBuffer = "";
|
||||
|
||||
/** this buffer may contains the current text array to be matched when it is cheap to acquire it */
|
||||
private char[] zzBufferArray;
|
||||
|
||||
/** the textposition at the last accepting state */
|
||||
private int zzMarkedPos;
|
||||
|
||||
/** the textposition at the last state to be included in yytext */
|
||||
private int zzPushbackPos;
|
||||
|
||||
/** the current text position in the buffer */
|
||||
private int zzCurrentPos;
|
||||
|
||||
/** startRead marks the beginning of the yytext() string in the buffer */
|
||||
private int zzStartRead;
|
||||
|
||||
/** endRead marks the last character in the buffer, that has been read
|
||||
from input */
|
||||
private int zzEndRead;
|
||||
|
||||
/**
|
||||
* zzAtBOL == true <=> the scanner is currently at the beginning of a line
|
||||
*/
|
||||
private boolean zzAtBOL = true;
|
||||
|
||||
/** zzAtEOF == true <=> the scanner is at the EOF */
|
||||
private boolean zzAtEOF;
|
||||
|
||||
/* user code: */
|
||||
public _HaskellLexer() {
|
||||
this((java.io.Reader)null);
|
||||
}
|
||||
|
||||
|
||||
public _HaskellLexer(java.io.Reader in) {
|
||||
this.zzReader = in;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new scanner.
|
||||
* There is also java.io.Reader version of this constructor.
|
||||
*
|
||||
* @param in the java.io.Inputstream to read input from.
|
||||
*/
|
||||
public _HaskellLexer(java.io.InputStream in) {
|
||||
this(new java.io.InputStreamReader(in));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpacks the compressed character translation table.
|
||||
*
|
||||
* @param packed the packed character translation table
|
||||
* @return the unpacked character translation table
|
||||
*/
|
||||
private static char [] zzUnpackCMap(String packed) {
|
||||
char [] map = new char[0x10000];
|
||||
int i = 0; /* index in packed string */
|
||||
int j = 0; /* index in unpacked array */
|
||||
while (i < 132) {
|
||||
int count = packed.charAt(i++);
|
||||
char value = packed.charAt(i++);
|
||||
do map[j++] = value; while (--count > 0);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public final int getTokenStart(){
|
||||
return zzStartRead;
|
||||
}
|
||||
|
||||
public final int getTokenEnd(){
|
||||
return getTokenStart() + yylength();
|
||||
}
|
||||
|
||||
public void reset(CharSequence buffer, int start, int end,int initialState){
|
||||
zzBuffer = buffer;
|
||||
zzBufferArray = com.intellij.util.text.CharArrayUtil.fromSequenceWithoutCopying(buffer);
|
||||
zzCurrentPos = zzMarkedPos = zzStartRead = start;
|
||||
zzPushbackPos = 0;
|
||||
zzAtEOF = false;
|
||||
zzAtBOL = true;
|
||||
zzEndRead = end;
|
||||
yybegin(initialState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refills the input buffer.
|
||||
*
|
||||
* @return <code>false</code>, iff there was new input.
|
||||
*
|
||||
* @exception java.io.IOException if any I/O-Error occurs
|
||||
*/
|
||||
private boolean zzRefill() throws java.io.IOException {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current lexical state.
|
||||
*/
|
||||
public final int yystate() {
|
||||
return zzLexicalState;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enters a new lexical state
|
||||
*
|
||||
* @param newState the new lexical state
|
||||
*/
|
||||
public final void yybegin(int newState) {
|
||||
zzLexicalState = newState;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the text matched by the current regular expression.
|
||||
*/
|
||||
public final CharSequence yytext() {
|
||||
return zzBuffer.subSequence(zzStartRead, zzMarkedPos);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the character at position <tt>pos</tt> from the
|
||||
* matched text.
|
||||
*
|
||||
* It is equivalent to yytext().charAt(pos), but faster
|
||||
*
|
||||
* @param pos the position of the character to fetch.
|
||||
* A value from 0 to yylength()-1.
|
||||
*
|
||||
* @return the character at position pos
|
||||
*/
|
||||
public final char yycharat(int pos) {
|
||||
return zzBufferArray != null ? zzBufferArray[zzStartRead+pos]:zzBuffer.charAt(zzStartRead+pos);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the length of the matched text region.
|
||||
*/
|
||||
public final int yylength() {
|
||||
return zzMarkedPos-zzStartRead;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reports an error that occured while scanning.
|
||||
*
|
||||
* In a wellformed scanner (no or only correct usage of
|
||||
* yypushback(int) and a match-all fallback rule) this method
|
||||
* will only be called with things that "Can't Possibly Happen".
|
||||
* If this method is called, something is seriously wrong
|
||||
* (e.g. a JFlex bug producing a faulty scanner etc.).
|
||||
*
|
||||
* Usual syntax/scanner level error handling should be done
|
||||
* in error fallback rules.
|
||||
*
|
||||
* @param errorCode the code of the errormessage to display
|
||||
*/
|
||||
private void zzScanError(int errorCode) {
|
||||
String message;
|
||||
try {
|
||||
message = ZZ_ERROR_MSG[errorCode];
|
||||
}
|
||||
catch (ArrayIndexOutOfBoundsException e) {
|
||||
message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR];
|
||||
}
|
||||
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pushes the specified amount of characters back into the input stream.
|
||||
*
|
||||
* They will be read again by then next call of the scanning method
|
||||
*
|
||||
* @param number the number of characters to be read again.
|
||||
* This number must not be greater than yylength()!
|
||||
*/
|
||||
public void yypushback(int number) {
|
||||
if ( number > yylength() )
|
||||
zzScanError(ZZ_PUSHBACK_2BIG);
|
||||
|
||||
zzMarkedPos -= number;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resumes scanning until the next regular expression is matched,
|
||||
* the end of input is encountered or an I/O-Error occurs.
|
||||
*
|
||||
* @return the next token
|
||||
* @exception java.io.IOException if any I/O-Error occurs
|
||||
*/
|
||||
public IElementType advance() throws java.io.IOException {
|
||||
int zzInput;
|
||||
int zzAction;
|
||||
|
||||
// cached fields:
|
||||
int zzCurrentPosL;
|
||||
int zzMarkedPosL;
|
||||
int zzEndReadL = zzEndRead;
|
||||
CharSequence zzBufferL = zzBuffer;
|
||||
char[] zzBufferArrayL = zzBufferArray;
|
||||
char [] zzCMapL = ZZ_CMAP;
|
||||
|
||||
int [] zzTransL = ZZ_TRANS;
|
||||
int [] zzRowMapL = ZZ_ROWMAP;
|
||||
int [] zzAttrL = ZZ_ATTRIBUTE;
|
||||
|
||||
while (true) {
|
||||
zzMarkedPosL = zzMarkedPos;
|
||||
|
||||
zzAction = -1;
|
||||
|
||||
zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL;
|
||||
|
||||
zzState = ZZ_LEXSTATE[zzLexicalState];
|
||||
|
||||
|
||||
zzForAction: {
|
||||
while (true) {
|
||||
|
||||
if (zzCurrentPosL < zzEndReadL)
|
||||
zzInput = (zzBufferArrayL != null ? zzBufferArrayL[zzCurrentPosL++] : zzBufferL.charAt(zzCurrentPosL++));
|
||||
else if (zzAtEOF) {
|
||||
zzInput = YYEOF;
|
||||
break zzForAction;
|
||||
}
|
||||
else {
|
||||
// store back cached positions
|
||||
zzCurrentPos = zzCurrentPosL;
|
||||
zzMarkedPos = zzMarkedPosL;
|
||||
boolean eof = zzRefill();
|
||||
// get translated positions and possibly new buffer
|
||||
zzCurrentPosL = zzCurrentPos;
|
||||
zzMarkedPosL = zzMarkedPos;
|
||||
zzBufferL = zzBuffer;
|
||||
zzEndReadL = zzEndRead;
|
||||
if (eof) {
|
||||
zzInput = YYEOF;
|
||||
break zzForAction;
|
||||
}
|
||||
else {
|
||||
zzInput = (zzBufferArrayL != null ? zzBufferArrayL[zzCurrentPosL++] : zzBufferL.charAt(zzCurrentPosL++));
|
||||
}
|
||||
}
|
||||
int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMapL[zzInput] ];
|
||||
if (zzNext == -1) break zzForAction;
|
||||
zzState = zzNext;
|
||||
|
||||
int zzAttributes = zzAttrL[zzState];
|
||||
if ( (zzAttributes & 1) == 1 ) {
|
||||
zzAction = zzState;
|
||||
zzMarkedPosL = zzCurrentPosL;
|
||||
if ( (zzAttributes & 8) == 8 ) break zzForAction;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// store back cached position
|
||||
zzMarkedPos = zzMarkedPosL;
|
||||
|
||||
switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) {
|
||||
case 22:
|
||||
{ return HS_MODULE_KEYWORD;
|
||||
}
|
||||
case 25: break;
|
||||
case 6:
|
||||
{ return HS_DEFINED_BY;
|
||||
}
|
||||
case 26: break;
|
||||
case 1:
|
||||
{ return com.intellij.psi.TokenType.BAD_CHARACTER;
|
||||
}
|
||||
case 27: break;
|
||||
case 3:
|
||||
{ return HS_SMALL;
|
||||
}
|
||||
case 28: break;
|
||||
case 14:
|
||||
{ return HS_DRAW_FROM_OR_MATCHES_OR_IN;
|
||||
}
|
||||
case 29: break;
|
||||
case 21:
|
||||
{ return HS_WHERE_KEYWORD;
|
||||
}
|
||||
case 30: break;
|
||||
case 19:
|
||||
{ return HS_DATA_KEYWORD;
|
||||
}
|
||||
case 31: break;
|
||||
case 16:
|
||||
{ return HS_OCTAL;
|
||||
}
|
||||
case 32: break;
|
||||
case 4:
|
||||
{ return HS_LARGE;
|
||||
}
|
||||
case 33: break;
|
||||
case 5:
|
||||
{ return HS_DECIMAL;
|
||||
}
|
||||
case 34: break;
|
||||
case 23:
|
||||
{ return HS_DEFAULT_KEYWORD;
|
||||
}
|
||||
case 35: break;
|
||||
case 13:
|
||||
{ return HS_INSTANCE_CONTEXTS;
|
||||
}
|
||||
case 36: break;
|
||||
case 18:
|
||||
{ return HS_CASE_KEYWORD;
|
||||
}
|
||||
case 37: break;
|
||||
case 15:
|
||||
{ return HS_HEXADECIMAL;
|
||||
}
|
||||
case 38: break;
|
||||
case 7:
|
||||
{ return HS_LT;
|
||||
}
|
||||
case 39: break;
|
||||
case 11:
|
||||
{ return HS_CHARACTER_LITERAL;
|
||||
}
|
||||
case 40: break;
|
||||
case 20:
|
||||
{ return HS_CLASS_KEYWORD;
|
||||
}
|
||||
case 41: break;
|
||||
case 9:
|
||||
{ return HS_FLOAT;
|
||||
}
|
||||
case 42: break;
|
||||
case 12:
|
||||
{ return HS_STRING_LITERAL;
|
||||
}
|
||||
case 43: break;
|
||||
case 10:
|
||||
{ return HS_COMMENT;
|
||||
}
|
||||
case 44: break;
|
||||
case 17:
|
||||
{ return HS_NCOMMENT;
|
||||
}
|
||||
case 45: break;
|
||||
case 2:
|
||||
{ return com.intellij.psi.TokenType.WHITE_SPACE;
|
||||
}
|
||||
case 46: break;
|
||||
case 24:
|
||||
{ return HS_DERIVING_KEYWORD;
|
||||
}
|
||||
case 47: break;
|
||||
case 8:
|
||||
{ return HS_GT;
|
||||
}
|
||||
case 48: break;
|
||||
default:
|
||||
if (zzInput == YYEOF && zzStartRead == zzCurrentPos) {
|
||||
zzAtEOF = true;
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
zzScanError(ZZ_NO_MATCH);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
package com.powertuple.intellij.haskell.annotator
|
||||
|
||||
import com.intellij.lang.annotation.{AnnotationHolder, ExternalAnnotator}
|
||||
import com.intellij.notification.NotificationGroup
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
|
||||
|
||||
import com.intellij.psi.PsiFile
|
||||
|
||||
import com.powertuple.intellij.haskell.HaskellFileType
|
||||
import com.powertuple.intellij.haskell.util.HaskellSystemUtil
|
||||
|
||||
import scala.collection.JavaConversions._
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.openapi.application.{ModalityState, ApplicationManager}
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||
import com.intellij.execution.process.ProcessOutput
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
|
||||
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl
|
||||
import com.intellij.openapi.ui.MessageType
|
||||
|
||||
class GhcModExternalAnnotator extends ExternalAnnotator[GhcModInitialInfo, GhcModResult] {
|
||||
private val Log = Logger.getInstance(classOf[GhcModExternalAnnotator])
|
||||
|
||||
private val GhcModNotificationGroup = NotificationGroup.balloonGroup("Ghc-mod inspections")
|
||||
|
||||
/**
|
||||
* Collects initial information required for ghc-mod.
|
||||
*
|
||||
* Returning null will cause doAnnotate() not to be called by Intellij API.
|
||||
*/
|
||||
override def collectInformation(psiFile: PsiFile): GhcModInitialInfo = {
|
||||
val vFile = psiFile.getVirtualFile
|
||||
vFile match {
|
||||
case null => null // can be case if file is in memory only (just created file)
|
||||
case f if f.getFileType != HaskellFileType.INSTANCE => null
|
||||
case f if f.getCanonicalPath == null => null
|
||||
case f => GhcModInitialInfo(psiFile, f.getCanonicalPath)
|
||||
}
|
||||
}
|
||||
|
||||
override def doAnnotate(initialInfoGhcMod: GhcModInitialInfo): GhcModResult = {
|
||||
ApplicationManager.getApplication.invokeAndWait(new Runnable() {
|
||||
override def run() {
|
||||
FileDocumentManager.getInstance.saveDocument(FileDocumentManager.getInstance().getDocument(initialInfoGhcMod.psiFile.getVirtualFile))
|
||||
}
|
||||
}, ModalityState.any())
|
||||
|
||||
val ghcModOutput = HaskellSystemUtil.getProcessOutput(initialInfoGhcMod.psiFile.getProject.getBasePath, "/home/rik/.cabal/bin/ghc-mod", Seq("check", initialInfoGhcMod.filePath))
|
||||
|
||||
new GhcModResult(parseGhcModOutput(ghcModOutput))
|
||||
}
|
||||
|
||||
override def apply(psiFile: PsiFile, ghcModResult: GhcModResult, holder: AnnotationHolder) {
|
||||
if (!psiFile.isValid) {
|
||||
return
|
||||
}
|
||||
|
||||
if (ghcModResult.problems.isEmpty) {
|
||||
markFileDirty(psiFile)
|
||||
return
|
||||
}
|
||||
|
||||
for (annotation <- createAnnotations(ghcModResult, psiFile.getText)) {
|
||||
Log.info("annotation: " + annotation)
|
||||
annotation match {
|
||||
case ErrorAnnotation(textRange, message) => holder.createErrorAnnotation(textRange, message)
|
||||
case WarningAnnotation(textRange, message) => holder.createWarningAnnotation(textRange, message)
|
||||
}
|
||||
}
|
||||
markFileDirty(psiFile)
|
||||
}
|
||||
|
||||
private def markFileDirty(psiFile: PsiFile) {
|
||||
val fileStatusMap = DaemonCodeAnalyzer.getInstance(psiFile.getProject).asInstanceOf[DaemonCodeAnalyzerImpl].getFileStatusMap
|
||||
val document = FileDocumentManager.getInstance().getDocument(psiFile.getVirtualFile)
|
||||
fileStatusMap.markFileScopeDirty(document, new TextRange(0, document.getTextLength), psiFile.getTextLength)
|
||||
}
|
||||
|
||||
private def startOffSetForProblem(lengthPerLine: Array[Int], problem: GhcModProblem): Int = {
|
||||
val lineNr = problem.lineNr
|
||||
(if (lineNr <= 1) {
|
||||
0
|
||||
} else {
|
||||
lengthPerLine.take(lineNr - 1).sum
|
||||
}) + problem.columnNr - 1
|
||||
}
|
||||
|
||||
private[annotator] def createAnnotations(ghcModResult: GhcModResult, text: String): Seq[Annotation] = {
|
||||
val lengthPerLine = StringUtil.splitByLines(text, false).map(_.size + 1)
|
||||
for (problem <- ghcModResult.problems) yield {
|
||||
Log.info("problem: " + problem)
|
||||
val startOffSet = startOffSetForProblem(lengthPerLine, problem)
|
||||
val textRange = TextRange.create(startOffSet, startOffSet + 1)
|
||||
if (problem.description.startsWith("Warning:")) {
|
||||
WarningAnnotation(textRange, problem.description)
|
||||
} else {
|
||||
ErrorAnnotation(textRange, problem.description)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private[annotator] def parseGhcModOutput(ghcModOutput: ProcessOutput): Seq[GhcModProblem] = {
|
||||
ghcModOutput match {
|
||||
case gmo if !gmo.getStderrLines.isEmpty => GhcModNotificationGroup.createNotification(s"Ghc-mod error output: ${gmo.getStderr}", MessageType.ERROR); Seq()
|
||||
case gmo => gmo.getStdoutLines.map(parseGhcModOutputLine)
|
||||
}
|
||||
}
|
||||
|
||||
private def parseGhcModOutputLine(ghcModOutput: String): GhcModProblem = {
|
||||
val ghcModProblemPattern = """.+:([\d]+):([\d]+):(.+)""".r
|
||||
|
||||
val ghcModProblemPattern(lineNr, columnNr, description) = ghcModOutput
|
||||
new GhcModProblem(lineNr.toInt, columnNr.toInt, description)
|
||||
}
|
||||
}
|
||||
|
||||
case class GhcModInitialInfo(psiFile: PsiFile, filePath: String)
|
||||
|
||||
case class GhcModResult(problems: Seq[GhcModProblem] = Seq())
|
||||
|
||||
case class GhcModProblem(lineNr: Int, columnNr: Int, description: String)
|
||||
|
||||
abstract class Annotation
|
||||
|
||||
case class ErrorAnnotation(textRange: TextRange, message: String) extends Annotation
|
||||
|
||||
case class WarningAnnotation(textRange: TextRange, message: String) extends Annotation
|
257
src/com/powertuple/intellij/haskell/haskell.bnf
Normal file
257
src/com/powertuple/intellij/haskell/haskell.bnf
Normal file
@ -0,0 +1,257 @@
|
||||
// Derived from http://www.haskell.org/onlinereport/haskell2010/haskellch10.html
|
||||
{
|
||||
parserClass="com.powertuple.intellij.haskell.parser.HaskellParser"
|
||||
|
||||
extends="com.intellij.extapi.psi.ASTWrapperPsiElement"
|
||||
|
||||
psiClassPrefix="Haskell"
|
||||
psiImplClassSuffix="Impl"
|
||||
psiPackage="com.powertuple.intellij.haskell.psi"
|
||||
psiImplPackage="com.powertuple.intellij.haskell.psi.impl"
|
||||
|
||||
elementTypeHolderClass="com.powertuple.intellij.haskell.psi.HaskellTypes"
|
||||
elementTypeClass="com.powertuple.intellij.haskell.psi.HaskellElementType"
|
||||
tokenTypeClass="com.powertuple.intellij.haskell.psi.HaskellTokenType"
|
||||
|
||||
elementTypePrefix="HS_"
|
||||
|
||||
parserUtilClass="com.powertuple.intellij.haskell.HaskellParserUtil"
|
||||
|
||||
tokens = [
|
||||
]
|
||||
|
||||
name(".*")='varide'
|
||||
// extends(".*")=lexeme
|
||||
}
|
||||
|
||||
program ::= (lexeme | COMMENT | NCOMMENT)*
|
||||
private lexeme ::= qvarid | qconid | qvarsym | qconsym | literal | special | reservedop | reservedid
|
||||
private literal ::= DECIMAL | HEXADECIMAL | OCTAL | FLOAT | CHARACTER_LITERAL | STRING_LITERAL
|
||||
|
||||
special ::= '(' | ')' | ',' | ';' | '[' | ']' | '`' | '{' | '}'
|
||||
ascSymbolExceptBackslash ::= '!' | '#' | '$' | '%' | '&' | '*' | '+' | '.' | '/' | LT | '=' | GT | '?' | '@'
|
||||
| '\' | '^' | '|' | '-' | '~' | ':'
|
||||
ascSymbol ::= ascSymbolExceptBackslash | '\'
|
||||
symbol ::= ascSymbol // ignoring non ascii
|
||||
|
||||
tyvar ::= varid
|
||||
tycon ::= conid
|
||||
tycls ::= conid
|
||||
modid ::= (conid '.')* conid
|
||||
|
||||
qvarid ::= (modid '.')? varid
|
||||
qconid ::= (modid '.')? conid
|
||||
qtycon ::= (modid '.')? tycon
|
||||
qtycls ::= (modid '.')? tycls
|
||||
qvarsym ::= (modid '.')? varsym
|
||||
qconsym ::= (modid '.')? consym
|
||||
|
||||
conid ::= LARGE (SMALL | LARGE)*
|
||||
varid ::= SMALL (SMALL | LARGE)*
|
||||
|
||||
varsym ::= (symbol (symbol | ':')*)
|
||||
consym ::= (':' (symbol | ':')*)
|
||||
|
||||
reservedid ::= CASE_KEYWORD | CLASS_KEYWORD | DATA_KEYWORD | DEFAULT_KEYWORD | DERIVING_KEYWORD | 'do' | 'else'
|
||||
| 'if' | 'import' | 'in' | 'infix' | 'infixl' | 'infixr' | 'instance'
|
||||
| 'let' | MODULE_KEYWORD | 'newtype' | 'of' | 'then' | 'type' | WHERE_KEYWORD | '_'
|
||||
|
||||
reservedop ::= '..' | ':' | '::' | DEFINED_BY | '\' | '|' | DRAW_FROM_OR_MATCHES_OR_IN | '->' | '@'
|
||||
| '~' | INSTANCE_CONTEXTS
|
||||
|
||||
|
||||
// Context-Free Syntax (under construction because left-recursion is not supported by generator)
|
||||
//module ::= 'module' modid (exports)? 'where' body
|
||||
// | body
|
||||
//
|
||||
//body ::= impdecls *
|
||||
// | topdecls *
|
||||
// | (impdecls ';' topdecls) *
|
||||
//
|
||||
//impdecls ::= impdecl(';' impdecl)*
|
||||
//
|
||||
//exports ::= '(' export(',' export)* ')'
|
||||
//
|
||||
//export ::= qvar
|
||||
// | qtycon (('..') | ((cname(',' cname)* )?))?
|
||||
// | qtycls (('..') | ((qvar (',' qvar)* )?))?
|
||||
// | module modid
|
||||
//
|
||||
//impdecl ::= import ('qualified')? modid ('as' modid)? (impspec)?
|
||||
//
|
||||
//impspec ::= '(' (import (',' import )* (',' )?)? ')'
|
||||
// | 'hiding' ((import (',' import )* (',' )?)?)
|
||||
//import ::= var
|
||||
// | tycon (('..') | ((cname (',' cname )*)?))?
|
||||
//cname ::= var | con
|
||||
//topdecls ::= (topdecl (';' topdecl)*)?
|
||||
//topdecl ::= 'type' simpletype DEFINED_BY type
|
||||
// | 'data' ( context '=>' )? simpletype DEFINED_BY constrs ( deriving )?
|
||||
// | 'newtype' ( context '=>' )? simpletype DEFINED_BY newconstr ( deriving )?
|
||||
// | 'class' ( scontext '=>' )? tycls tyvar ('where' cdecls)?
|
||||
// | 'instance' ( scontext '=>' )? qtycls inst ('where' idecls)?
|
||||
// | 'default' (( type (',' type)* )? )
|
||||
// | 'foreign' fdecl
|
||||
// | decl
|
||||
//decls ::= '{' (decl (';' decl )*)? '}'
|
||||
//decl ::= gendecl
|
||||
// | (funlhs | pat) rhs
|
||||
//cdecls ::= '{' (cdecl (';' cdecl )*)? '}'
|
||||
//cdecl ::= gendecl
|
||||
// | (funlhs | var) rhs
|
||||
//idecls ::= '{' (idecl ( ';' idecl)* )? '}'
|
||||
//idecl ::= (funlhs | var ) rhs
|
||||
//gendecl ::= vars '::' (context '=>')? type // type signature
|
||||
// | fixity (integer)? ops // fixity signature
|
||||
// | // empty declaration
|
||||
//
|
||||
//ops ::= op (',' op )*
|
||||
//vars ::= var (',' var)*
|
||||
//fixity ::= 'infixl' | 'infixr' | 'infix'
|
||||
//
|
||||
//type ::= btype ('->' type)? // function type
|
||||
//
|
||||
//btype ::= (btype)? atype // type application
|
||||
//
|
||||
//atype ::= gtycon
|
||||
// | tyvar
|
||||
// | (type(',' type )+) // tuple type
|
||||
// | '['type']' // list type
|
||||
// | '('type')' // parenthesized constructor
|
||||
//
|
||||
//gtycon ::= qtycon
|
||||
// | '()' // unit type
|
||||
// | '[]' // list constructor
|
||||
// | '(->)' // function constructor
|
||||
// | '(,' (',')* ')' // tupling constructor
|
||||
//
|
||||
//context ::= class
|
||||
// | '(' (class (',' class)* )? ')'
|
||||
//class ::= qtycls tyvar
|
||||
// | qtycls (tyvar (atype)+ )
|
||||
//scontext ::= simpleclass
|
||||
// | '(' (simpleclass (',' simpleclass)* )? ')'
|
||||
//simpleclass ::= qtycls tyvar
|
||||
//
|
||||
//simpletype ::= tycon (tyvar)*
|
||||
//constrs ::= constr (| constr)*
|
||||
//constr ::= con (('!')? atype)*
|
||||
// | (btype | '!' atype) conop (btype | '!' atype)
|
||||
// | con '{' (fielddecl (',' fielddecl)* )? '}'
|
||||
//newconstr ::= con atype
|
||||
// | con '{' var '::' type '}'
|
||||
//fielddecl ::= vars '::' (type | '!' atype)
|
||||
//deriving ::= 'deriving' (dclass | '(' (dclass (',' dclass)* )? ')' )
|
||||
//dclass ::= qtycls
|
||||
//
|
||||
//inst ::= gtycon
|
||||
// | '(' gtycon ( tyvar )* ')'
|
||||
// | '(' tyvar ( ',' tyvar )+ ')'
|
||||
// | '(' tyvar '->' tyvar ')'
|
||||
// | (tyvar)?
|
||||
//
|
||||
//fdecl ::= 'import' callconv (safety)? impent var '::' ftype
|
||||
// | 'export' callconv expent var '::' ftype
|
||||
//callconv ::= 'ccall' | 'stdcall' | 'cplusplus' // (calling convention)
|
||||
// | 'jvm' | 'dotnet' // | 'system-specific calling conventions'????
|
||||
//impent ::= (string_)?
|
||||
//expent ::= (string_)?
|
||||
//safety ::= 'unsafe' | 'safe'
|
||||
//
|
||||
//ftype ::= frtype
|
||||
// | fatype ::= ftype // do not know how to handle this
|
||||
//
|
||||
//frtype ::= fatype
|
||||
// | '()'
|
||||
//fatype ::= qtycon (atype)*
|
||||
//
|
||||
//funlhs ::= var (apat)+
|
||||
// | pat varop pat
|
||||
// | '(' funlhs ')' (apat)+
|
||||
//rhs ::= DEFINED_BY exp ('where' decls)?
|
||||
// | gdrhs ('where' decls)?
|
||||
//gdrhs ::= guards DEFINED_BY exp (gdrhs)?
|
||||
//guards ::= '|' guard+
|
||||
//guard ::= pat '<-' infixexp
|
||||
// | 'let' decls
|
||||
// | infixexp
|
||||
//
|
||||
//exp ::= infixexp '::' (context '=>')? type
|
||||
// | infixexp
|
||||
//
|
||||
//infixexp ::= lexp qop infixexp
|
||||
// | '-' infixexp
|
||||
// | lexp
|
||||
//
|
||||
//lexp ::= '\' (apat)+ '->' exp
|
||||
// | 'let' decls 'in' exp
|
||||
// | 'if' exp 'then' exp 'else' exp
|
||||
// | 'case' exp 'of' '{' alts '}'
|
||||
// | 'do' '{' stmts '}'
|
||||
// | fexp
|
||||
//
|
||||
//fexp ::= (fexp)? aexp
|
||||
//
|
||||
//aexp ::= qvar
|
||||
// | gcon
|
||||
// | literal
|
||||
// | '(' exp ')'
|
||||
// | '(' exp (',' exp )+ ')'
|
||||
// | '[' exp (',' exp )* ']'
|
||||
// | '[' exp (',' exp )? '..' ( exp )? ']'
|
||||
// | '[' exp | qual (',' qual )* ']'
|
||||
// | '(' infixexp qop ')'
|
||||
// | '(' qop infixexp ')'
|
||||
// | qcon '{' (fbind ( ',' fbind)* )? '}'
|
||||
// | aexp '{' fbind (',' fbind)* '}'
|
||||
//
|
||||
//qual ::= pat '<-' exp
|
||||
// | 'let' decls
|
||||
// | exp
|
||||
//
|
||||
//alts ::= (alt (';' alt )* )?
|
||||
//alt ::= pat '->' exp ('where' decls)?
|
||||
// | pat gdpat ('where' decls)?
|
||||
// | // (empty alternative)
|
||||
//gdpat ::= guards '->' exp (gdpat)?
|
||||
//stmts ::= (stmt)* exp (';')?
|
||||
//stmt ::= exp ';'
|
||||
// | pat '<-' exp ';'
|
||||
// | 'let' decls ';'
|
||||
// | ';' // (empty statement)
|
||||
//fbind ::= qvar DEFINED_BY exp
|
||||
//pat ::= lpat qconop pat // (infix constructor)
|
||||
// | lpat
|
||||
//
|
||||
//left lpat ::= apat
|
||||
// | '-' (integer | float) // (negative literal)
|
||||
// | gcon (apat)+
|
||||
//
|
||||
//apat ::= var ('@' apat)? // (as pattern)
|
||||
// | gcon // (arity gcon = 0)
|
||||
// | qcon (fpat)* // (labeled pattern, k ≥ 0)
|
||||
// | literal
|
||||
// | '_' // (wildcard)
|
||||
// | '('pat')' // (parenthesized pattern)
|
||||
// | '('pat (',' pat)+ ')' // (tuple pattern, k ≥ 2)
|
||||
// | '['pat (',' pat)* ']' // (list pattern, k ≥ 1)
|
||||
// | '~' apat
|
||||
//
|
||||
//fpat ::= qvar DEFINED_BY pat
|
||||
//
|
||||
//gcon ::= '()'
|
||||
// | '[]'
|
||||
// | '(' (',')* ')'
|
||||
// | qcon
|
||||
//
|
||||
//var ::= varid | '(' varsym ')' // variable
|
||||
//qvar ::= qvarid | '(' qvarsym ')'
|
||||
//con ::= conid | '(' consym ')'
|
||||
//qcon ::= qconid | '(' gconsym ')'
|
||||
//varop ::= varsym | '`' varid '`'
|
||||
//qvarop ::= qvarsym | '`' qvarid '`'
|
||||
//conop ::= consym | '`' conid '`'
|
||||
//qconop ::= gconsym | '`' qconid '`'
|
||||
//op ::= varop | conop
|
||||
//qop ::= qvarop | qconop
|
||||
//gconsym ::= ':' | qconsym
|
@ -0,0 +1,57 @@
|
||||
package com.powertuple.intellij.haskell.highlighter;
|
||||
|
||||
import com.intellij.lexer.Lexer;
|
||||
import com.intellij.openapi.editor.DefaultLanguageHighlighterColors;
|
||||
import com.intellij.openapi.editor.colors.TextAttributesKey;
|
||||
import com.intellij.openapi.fileTypes.SyntaxHighlighterBase;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.powertuple.intellij.haskell.HaskellLexer;
|
||||
import com.powertuple.intellij.haskell.psi.HaskellTypes;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class HaskellSyntaxHighlighter extends SyntaxHighlighterBase {
|
||||
|
||||
private static final Map<IElementType, TextAttributesKey> ATTRIBUTES = new HashMap<IElementType, TextAttributesKey>();
|
||||
|
||||
static final TokenSet LINE_COMMENTS = TokenSet.create(
|
||||
HaskellTypes.HS_COMMENT
|
||||
);
|
||||
|
||||
static final TokenSet NESTED_COMMENTS = TokenSet.create(
|
||||
HaskellTypes.HS_NCOMMENT
|
||||
);
|
||||
|
||||
static final TokenSet KEYWORDS = TokenSet.create(
|
||||
HaskellTypes.HS_CASE_KEYWORD,
|
||||
HaskellTypes.HS_MODULE_KEYWORD,
|
||||
HaskellTypes.HS_WHERE_KEYWORD
|
||||
);
|
||||
|
||||
static final TokenSet OPERATORS = TokenSet.create(
|
||||
HaskellTypes.HS_DEFINED_BY,
|
||||
HaskellTypes.HS_DRAW_FROM_OR_MATCHES_OR_IN
|
||||
);
|
||||
|
||||
static {
|
||||
SyntaxHighlighterBase.fillMap(ATTRIBUTES, KEYWORDS, DefaultLanguageHighlighterColors.KEYWORD);
|
||||
SyntaxHighlighterBase.fillMap(ATTRIBUTES, LINE_COMMENTS, DefaultLanguageHighlighterColors.LINE_COMMENT);
|
||||
SyntaxHighlighterBase.fillMap(ATTRIBUTES, NESTED_COMMENTS, DefaultLanguageHighlighterColors.BLOCK_COMMENT);
|
||||
SyntaxHighlighterBase.fillMap(ATTRIBUTES, OPERATORS, DefaultLanguageHighlighterColors.OPERATION_SIGN);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Lexer getHighlightingLexer() {
|
||||
return new HaskellLexer();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public TextAttributesKey[] getTokenHighlights(IElementType tokenType) {
|
||||
return pack(ATTRIBUTES.get(tokenType));
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.powertuple.intellij.haskell.highlighter;
|
||||
|
||||
import com.intellij.openapi.fileTypes.SyntaxHighlighter;
|
||||
import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class HaskellSyntaxHighlighterFactory extends SyntaxHighlighterFactory {
|
||||
@NotNull
|
||||
@Override
|
||||
public SyntaxHighlighter getSyntaxHighlighter(@Nullable Project project, @Nullable VirtualFile virtualFile) {
|
||||
return new HaskellSyntaxHighlighter();
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.powertuple.intellij.haskell.psi;
|
||||
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.powertuple.intellij.haskell.HaskellLanguage;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class HaskellElementType extends IElementType {
|
||||
public HaskellElementType(@NotNull @NonNls String debugName) {
|
||||
super(debugName, HaskellLanguage.INSTANCE);
|
||||
}
|
||||
}
|
32
src/com/powertuple/intellij/haskell/psi/HaskellFile.java
Normal file
32
src/com/powertuple/intellij/haskell/psi/HaskellFile.java
Normal file
@ -0,0 +1,32 @@
|
||||
package com.powertuple.intellij.haskell.psi;
|
||||
|
||||
import com.intellij.extapi.psi.PsiFileBase;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.psi.FileViewProvider;
|
||||
import com.powertuple.intellij.haskell.HaskellFileType;
|
||||
import com.powertuple.intellij.haskell.HaskellLanguage;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public class HaskellFile extends PsiFileBase {
|
||||
public HaskellFile(@NotNull FileViewProvider viewProvider) {
|
||||
super(viewProvider, HaskellLanguage.INSTANCE);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FileType getFileType() {
|
||||
return HaskellFileType.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Haskell File";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon(int flags) {
|
||||
return super.getIcon(flags);
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.powertuple.intellij.haskell.psi;
|
||||
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.powertuple.intellij.haskell.HaskellLanguage;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class HaskellTokenType extends IElementType {
|
||||
public HaskellTokenType(@NotNull @NonNls String debugName) {
|
||||
super(debugName, HaskellLanguage.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HaskellTokenType." + super.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package com.powertuple.intellij.haskell.psi.impl;
|
||||
|
||||
public class HaskellPsiImplUtil {
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.powertuple.intellij.haskell.util
|
||||
|
||||
import com.intellij.execution.configurations.GeneralCommandLine
|
||||
import com.intellij.execution.process.CapturingProcessHandler
|
||||
import com.intellij.execution.process.ProcessOutput
|
||||
import java.io.File
|
||||
import scala.collection.JavaConversions._
|
||||
|
||||
object HaskellSystemUtil {
|
||||
val StandardTimeout = 10 * 1000
|
||||
|
||||
def getProcessOutput(workDir: String, exePath: String, arguments: Seq[String], timeout: Int = StandardTimeout): ProcessOutput = {
|
||||
if (!new File(workDir).isDirectory || !new File(exePath).canExecute) {
|
||||
new ProcessOutput
|
||||
}
|
||||
val cmd: GeneralCommandLine = new GeneralCommandLine
|
||||
cmd.setWorkDirectory(workDir)
|
||||
cmd.setExePath(exePath)
|
||||
cmd.addParameters(arguments)
|
||||
execute(cmd, timeout)
|
||||
}
|
||||
|
||||
def execute(cmd: GeneralCommandLine): ProcessOutput = {
|
||||
execute(cmd, StandardTimeout)
|
||||
}
|
||||
|
||||
def execute(cmd: GeneralCommandLine, timeout: Int): ProcessOutput = {
|
||||
val processHandler: CapturingProcessHandler = new CapturingProcessHandler(cmd.createProcess)
|
||||
if (timeout < 0) processHandler.runProcess else processHandler.runProcess(timeout)
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package com.powertuple.intellij.haskell.annotator
|
||||
|
||||
import org.scalatest.{BeforeAndAfterEach, GivenWhenThen, Matchers, FunSpec}
|
||||
import com.intellij.execution.process.ProcessOutput
|
||||
|
||||
class GhcModExternalAnnotatorSpec extends FunSpec with Matchers with GivenWhenThen with BeforeAndAfterEach {
|
||||
|
||||
val ghcModExternalAnnotator = new GhcModExternalAnnotator
|
||||
|
||||
describe("Parsing ghc-mod output") {
|
||||
Given("output of ghc-mod")
|
||||
val output = new ProcessOutput()
|
||||
output.appendStdout("file/path/HaskellFile.hs:1:11:parse error on input\n")
|
||||
output.appendStdout("file/path/HaskellFile.hs:12:5:another parse error on input")
|
||||
|
||||
When("parsed to problem list")
|
||||
val problems = ghcModExternalAnnotator.parseGhcModOutput(output)
|
||||
|
||||
Then("list should have size 2")
|
||||
problems should have size 2
|
||||
val problem1 = problems(0)
|
||||
val problem2 = problems(1)
|
||||
|
||||
And("contain right data")
|
||||
problem1.lineNr should equal(1)
|
||||
problem1.columnNr should equal(11)
|
||||
problem1.description should equal("parse error on input")
|
||||
|
||||
problem2.lineNr should equal(12)
|
||||
problem2.columnNr should equal(5)
|
||||
problem2.description should equal("another parse error on input")
|
||||
}
|
||||
|
||||
describe("Determine annotation offset when compile error") {
|
||||
Given("some Haskell code which gives compile errors")
|
||||
val someCode =
|
||||
"""
|
||||
|Some Haskell code
|
||||
|which does not
|
||||
|
|
||||
|com pile
|
||||
""".stripMargin
|
||||
|
||||
When("ghc-mod is executed")
|
||||
val ghcModResult = GhcModResult(Seq(GhcModProblem(4, 3, "something wrong")))
|
||||
val annotations = ghcModExternalAnnotator.createAnnotations(ghcModResult, someCode)
|
||||
|
||||
Then("annotation holder should contain right annotation")
|
||||
annotations should have length 1
|
||||
|
||||
val annotation = annotations(0)
|
||||
annotation.asInstanceOf[ErrorAnnotation].textRange.getStartOffset should equal(36)
|
||||
}
|
||||
|
||||
describe("Determine annotation offset when compile warning") {
|
||||
Given("some Haskell code which gives compile warnings")
|
||||
val someCode =
|
||||
"""
|
||||
|some code
|
||||
""".stripMargin
|
||||
|
||||
When("ghc-mod is executed")
|
||||
val ghcModResult = GhcModResult(Seq(GhcModProblem(1, 1, "Warning: some warning")))
|
||||
val annotations = ghcModExternalAnnotator.createAnnotations(ghcModResult, someCode)
|
||||
|
||||
Then("annotation holder should contain right annotation")
|
||||
annotations should have length 1
|
||||
|
||||
val annotation = annotations(0)
|
||||
annotation.asInstanceOf[WarningAnnotation].textRange.getStartOffset should equal(0)
|
||||
}
|
||||
}
|
231
test/com/powertuple/intellij/haskell/annotator/PsiTestCase.java
Normal file
231
test/com/powertuple/intellij/haskell/annotator/PsiTestCase.java
Normal file
@ -0,0 +1,231 @@
|
||||
package com.powertuple.intellij.haskell.annotator;
|
||||
|
||||
import com.intellij.openapi.application.Result;
|
||||
import com.intellij.openapi.application.WriteAction;
|
||||
import com.intellij.openapi.application.ex.PathManagerEx;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.FileTypeRegistry;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.roots.ModuleRootManager;
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.util.DefaultJDOMExternalizer;
|
||||
import com.intellij.openapi.util.JDOMUtil;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.PsiManagerImpl;
|
||||
import com.intellij.testFramework.IdeaTestUtil;
|
||||
import com.intellij.testFramework.ModuleTestCase;
|
||||
import com.intellij.testFramework.PsiTestData;
|
||||
import com.intellij.testFramework.PsiTestUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.powertuple.intellij.haskell.HaskellFileType;
|
||||
import org.jdom.Document;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* @author Mike
|
||||
*/
|
||||
public abstract class PsiTestCase extends ModuleTestCase {
|
||||
protected PsiManagerImpl myPsiManager;
|
||||
protected PsiFile myFile;
|
||||
protected PsiTestData myTestDataBefore;
|
||||
protected PsiTestData myTestDataAfter;
|
||||
private String myDataRoot;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
myPsiManager = (PsiManagerImpl) PsiManager.getInstance(myProject);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
myPsiManager = null;
|
||||
myFile = null;
|
||||
myTestDataBefore = null;
|
||||
myTestDataAfter = null;
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
protected PsiFile createDummyFile(String fileName, String text) throws IncorrectOperationException {
|
||||
return PsiFileFactory.getInstance(myProject).createFileFromText(fileName, HaskellFileType.INSTANCE, text);
|
||||
}
|
||||
|
||||
protected PsiFile createFile(@NonNls String fileName, String text) throws Exception {
|
||||
return createFile(myModule, fileName, text);
|
||||
}
|
||||
protected PsiFile createFile(Module module, String fileName, String text) throws Exception {
|
||||
File dir = createTempDirectory();
|
||||
VirtualFile vDir = LocalFileSystem.getInstance().refreshAndFindFileByPath(dir.getCanonicalPath().replace(File.separatorChar, '/'));
|
||||
|
||||
return createFile(module, vDir, fileName, text);
|
||||
}
|
||||
|
||||
protected PsiFile createFile(final Module module, final VirtualFile vDir, final String fileName, final String text) throws IOException {
|
||||
return new WriteAction<PsiFile>() {
|
||||
@Override
|
||||
protected void run(Result<PsiFile> result) throws Throwable {
|
||||
if (!ModuleRootManager.getInstance(module).getFileIndex().isInSourceContent(vDir)) {
|
||||
addSourceContentToRoots(module, vDir);
|
||||
}
|
||||
|
||||
final VirtualFile vFile = vDir.createChildData(vDir, fileName);
|
||||
VfsUtil.saveText(vFile, text);
|
||||
assertNotNull(vFile);
|
||||
final PsiFile file = myPsiManager.findFile(vFile);
|
||||
assertNotNull(file);
|
||||
result.setResult(file);
|
||||
}
|
||||
}.execute().getResultObject();
|
||||
}
|
||||
|
||||
protected void addSourceContentToRoots(final Module module, final VirtualFile vDir) {
|
||||
PsiTestUtil.addSourceContentToRoots(module, vDir);
|
||||
}
|
||||
|
||||
protected PsiElement configureByFileWithMarker(String filePath, String marker) throws Exception{
|
||||
final VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(filePath.replace(File.separatorChar, '/'));
|
||||
assertNotNull("file " + filePath + " not found", vFile);
|
||||
|
||||
String fileText = VfsUtil.loadText(vFile);
|
||||
fileText = StringUtil.convertLineSeparators(fileText);
|
||||
|
||||
int offset = fileText.indexOf(marker);
|
||||
assertTrue(offset >= 0);
|
||||
fileText = fileText.substring(0, offset) + fileText.substring(offset + marker.length());
|
||||
|
||||
myFile = createFile(vFile.getName(), fileText);
|
||||
|
||||
return myFile.findElementAt(offset);
|
||||
}
|
||||
|
||||
protected void configure(@NotNull String path, String dataName) throws Exception {
|
||||
myDataRoot = getTestDataPath() + path;
|
||||
|
||||
myTestDataBefore = loadData(dataName);
|
||||
|
||||
PsiTestUtil.removeAllRoots(myModule, IdeaTestUtil.getMockJdk17());
|
||||
VirtualFile vDir = PsiTestUtil.createTestProjectStructure(myProject, myModule, myDataRoot, myFilesToDelete);
|
||||
|
||||
final VirtualFile vFile = vDir.findChild(myTestDataBefore.getTextFile());
|
||||
myFile = myPsiManager.findFile(vFile);
|
||||
}
|
||||
|
||||
protected String getTestDataPath() {
|
||||
return PathManagerEx.getTestDataPath();
|
||||
}
|
||||
|
||||
protected String loadFile(String name) throws Exception {
|
||||
String result = FileUtil.loadFile(new File(getTestDataPath() + File.separatorChar + name));
|
||||
return StringUtil.convertLineSeparators(result);
|
||||
}
|
||||
|
||||
private PsiTestData loadData(String dataName) throws Exception {
|
||||
Document document = JDOMUtil.loadDocument(new File(myDataRoot + "/" + "data.xml"));
|
||||
|
||||
PsiTestData data = createData();
|
||||
Element documentElement = document.getRootElement();
|
||||
|
||||
final List nodes = documentElement.getChildren("data");
|
||||
|
||||
for (Object node1 : nodes) {
|
||||
Element node = (Element)node1;
|
||||
String value = node.getAttributeValue("name");
|
||||
|
||||
if (value.equals(dataName)) {
|
||||
DefaultJDOMExternalizer.readExternal(data, node);
|
||||
data.loadText(myDataRoot);
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Cannot find data chunk '" + dataName + "'");
|
||||
}
|
||||
|
||||
protected PsiTestData createData() {
|
||||
return new PsiTestData();
|
||||
}
|
||||
|
||||
protected void checkResult(String dataName) throws Exception {
|
||||
myTestDataAfter = loadData(dataName);
|
||||
|
||||
final String textExpected = myTestDataAfter.getText();
|
||||
final String actualText = myFile.getText();
|
||||
|
||||
if (!textExpected.equals(actualText)) {
|
||||
System.out.println("Text mismatch: " + getName() + "(" + getClass().getName() + ")");
|
||||
System.out.println("Text expected:");
|
||||
printText(textExpected);
|
||||
System.out.println("Text found:");
|
||||
printText(actualText);
|
||||
|
||||
fail("text");
|
||||
}
|
||||
|
||||
// assertEquals(myTestDataAfter.getText(), myFile.getText());
|
||||
}
|
||||
|
||||
protected static void printText(String text) {
|
||||
final String q = "\"";
|
||||
System.out.print(q);
|
||||
|
||||
text = StringUtil.convertLineSeparators(text);
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(text, "\n", true);
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
final String token = tokenizer.nextToken();
|
||||
|
||||
if (token.equals("\n")) {
|
||||
System.out.print(q);
|
||||
System.out.println();
|
||||
System.out.print(q);
|
||||
continue;
|
||||
}
|
||||
|
||||
System.out.print(token);
|
||||
}
|
||||
|
||||
System.out.print(q);
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
protected void addLibraryToRoots(final VirtualFile jarFile, OrderRootType rootType) {
|
||||
addLibraryToRoots(myModule, jarFile, rootType);
|
||||
}
|
||||
|
||||
protected static void addLibraryToRoots(final Module module, final VirtualFile root, final OrderRootType rootType) {
|
||||
assertEquals(OrderRootType.CLASSES, rootType);
|
||||
ModuleRootModificationUtil.addModuleLibrary(module, root.getUrl());
|
||||
}
|
||||
|
||||
|
||||
public PsiFile getFile() {
|
||||
return myFile;
|
||||
}
|
||||
|
||||
public com.intellij.openapi.editor.Document getDocument(PsiFile file) {
|
||||
return PsiDocumentManager.getInstance(getProject()).getDocument(file);
|
||||
}
|
||||
|
||||
public com.intellij.openapi.editor.Document getDocument(VirtualFile file) {
|
||||
return FileDocumentManager.getInstance().getDocument(file);
|
||||
}
|
||||
|
||||
public void commitDocument(com.intellij.openapi.editor.Document document) {
|
||||
PsiDocumentManager.getInstance(getProject()).commitDocument(document);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user