Improvements.

This commit is contained in:
Rik van der Kleij 2016-03-07 21:50:27 +01:00
parent a96ae7b76a
commit c41c0ae36b
22 changed files with 575 additions and 606 deletions

View File

@ -20,4 +20,4 @@ lazy val intellijHaskell = (project in file(".")).
unmanagedJars in Compile += baseDirectory.value / "idea"
)
ideaBuild in ThisBuild := "142.5239.7"
ideaBuild in ThisBuild := "143.1184.17"

View File

@ -86,9 +86,6 @@ public class HaskellParser implements PsiParser, LightPsiParser {
else if (t == HS_DOT_DOT_PARENS) {
r = dot_dot_parens(b, 0);
}
else if (t == HS_DUMMY_HEADER_PRAGMA) {
r = dummy_header_pragma(b, 0);
}
else if (t == HS_EXPORT) {
r = export(b, 0);
}
@ -236,6 +233,9 @@ public class HaskellParser implements PsiParser, LightPsiParser {
else if (t == HS_PARALLEL_ARRAY_TYPE) {
r = parallel_array_type(b, 0);
}
else if (t == HS_PRAGMA_RECOVER) {
r = pragma_recover(b, 0);
}
else if (t == HS_QCON) {
r = qcon(b, 0);
}
@ -1832,35 +1832,6 @@ public class HaskellParser implements PsiParser, LightPsiParser {
return r;
}
/* ********************************************************** */
// PRAGMA_START CONID_ID? PRAGMA_END? NEWLINE
public static boolean dummy_header_pragma(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "dummy_header_pragma")) return false;
if (!nextTokenIs(b, HS_PRAGMA_START)) return false;
boolean r;
Marker m = enter_section_(b);
r = consumeToken(b, HS_PRAGMA_START);
r = r && dummy_header_pragma_1(b, l + 1);
r = r && dummy_header_pragma_2(b, l + 1);
r = r && consumeToken(b, HS_NEWLINE);
exit_section_(b, m, HS_DUMMY_HEADER_PRAGMA, r);
return r;
}
// CONID_ID?
private static boolean dummy_header_pragma_1(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "dummy_header_pragma_1")) return false;
consumeToken(b, HS_CONID_ID);
return true;
}
// PRAGMA_END?
private static boolean dummy_header_pragma_2(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "dummy_header_pragma_2")) return false;
consumeToken(b, HS_PRAGMA_END);
return true;
}
/* ********************************************************** */
// export1 | export2 | export3
public static boolean export(PsiBuilder b, int l) {
@ -2227,7 +2198,7 @@ public class HaskellParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
// language_pragma | options_ghc_pragma | include_pragma | haddock_pragma | ann_pragma | dummy_header_pragma
// language_pragma | options_ghc_pragma | include_pragma | haddock_pragma | ann_pragma
public static boolean file_header_pragma(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "file_header_pragma")) return false;
if (!nextTokenIs(b, HS_PRAGMA_START)) return false;
@ -2238,7 +2209,6 @@ public class HaskellParser implements PsiParser, LightPsiParser {
if (!r) r = include_pragma(b, l + 1);
if (!r) r = haddock_pragma(b, l + 1);
if (!r) r = ann_pragma(b, l + 1);
if (!r) r = dummy_header_pragma(b, l + 1);
exit_section_(b, m, HS_FILE_HEADER_PRAGMA, r);
return r;
}
@ -2456,16 +2426,16 @@ public class HaskellParser implements PsiParser, LightPsiParser {
// PRAGMA_START onl "OPTIONS_HADDOCK" general_pragma_content PRAGMA_END
public static boolean haddock_pragma(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "haddock_pragma")) return false;
if (!nextTokenIs(b, HS_PRAGMA_START)) return false;
boolean r;
Marker m = enter_section_(b);
boolean r, p;
Marker m = enter_section_(b, l, _NONE_, "<haddock pragma>");
r = consumeToken(b, HS_PRAGMA_START);
r = r && onl(b, l + 1);
r = r && consumeToken(b, "OPTIONS_HADDOCK");
r = r && general_pragma_content(b, l + 1);
r = r && consumeToken(b, HS_PRAGMA_END);
exit_section_(b, m, HS_HADDOCK_PRAGMA, r);
return r;
p = r; // pin = 1
r = r && report_error_(b, onl(b, l + 1));
r = p && report_error_(b, consumeToken(b, "OPTIONS_HADDOCK")) && r;
r = p && report_error_(b, general_pragma_content(b, l + 1)) && r;
r = p && consumeToken(b, HS_PRAGMA_END) && r;
exit_section_(b, l, m, HS_HADDOCK_PRAGMA, r, p, pragma_recover_parser_);
return r || p;
}
/* ********************************************************** */
@ -2910,16 +2880,16 @@ public class HaskellParser implements PsiParser, LightPsiParser {
// PRAGMA_START onl "INCLUDE" general_pragma_content PRAGMA_END
public static boolean include_pragma(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "include_pragma")) return false;
if (!nextTokenIs(b, HS_PRAGMA_START)) return false;
boolean r;
Marker m = enter_section_(b);
boolean r, p;
Marker m = enter_section_(b, l, _NONE_, "<include pragma>");
r = consumeToken(b, HS_PRAGMA_START);
r = r && onl(b, l + 1);
r = r && consumeToken(b, "INCLUDE");
r = r && general_pragma_content(b, l + 1);
r = r && consumeToken(b, HS_PRAGMA_END);
exit_section_(b, m, HS_INCLUDE_PRAGMA, r);
return r;
p = r; // pin = 1
r = r && report_error_(b, onl(b, l + 1));
r = p && report_error_(b, consumeToken(b, "INCLUDE")) && r;
r = p && report_error_(b, general_pragma_content(b, l + 1)) && r;
r = p && consumeToken(b, HS_PRAGMA_END) && r;
exit_section_(b, l, m, HS_INCLUDE_PRAGMA, r, p, pragma_recover_parser_);
return r || p;
}
/* ********************************************************** */
@ -3608,19 +3578,19 @@ public class HaskellParser implements PsiParser, LightPsiParser {
// PRAGMA_START onl "LANGUAGE" onl qcon (onl COMMA onl qcon)* onl PRAGMA_END
public static boolean language_pragma(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "language_pragma")) return false;
if (!nextTokenIs(b, HS_PRAGMA_START)) return false;
boolean r;
Marker m = enter_section_(b);
boolean r, p;
Marker m = enter_section_(b, l, _NONE_, "<language pragma>");
r = consumeToken(b, HS_PRAGMA_START);
r = r && onl(b, l + 1);
r = r && consumeToken(b, "LANGUAGE");
r = r && onl(b, l + 1);
r = r && qcon(b, l + 1);
r = r && language_pragma_5(b, l + 1);
r = r && onl(b, l + 1);
r = r && consumeToken(b, HS_PRAGMA_END);
exit_section_(b, m, HS_LANGUAGE_PRAGMA, r);
return r;
p = r; // pin = 1
r = r && report_error_(b, onl(b, l + 1));
r = p && report_error_(b, consumeToken(b, "LANGUAGE")) && r;
r = p && report_error_(b, onl(b, l + 1)) && r;
r = p && report_error_(b, qcon(b, l + 1)) && r;
r = p && report_error_(b, language_pragma_5(b, l + 1)) && r;
r = p && report_error_(b, onl(b, l + 1)) && r;
r = p && consumeToken(b, HS_PRAGMA_END) && r;
exit_section_(b, l, m, HS_LANGUAGE_PRAGMA, r, p, pragma_recover_parser_);
return r || p;
}
// (onl COMMA onl qcon)*
@ -4166,16 +4136,16 @@ public class HaskellParser implements PsiParser, LightPsiParser {
// PRAGMA_START onl ("OPTIONS_GHC" | "OPTIONS") general_pragma_content PRAGMA_END
public static boolean options_ghc_pragma(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "options_ghc_pragma")) return false;
if (!nextTokenIs(b, HS_PRAGMA_START)) return false;
boolean r;
Marker m = enter_section_(b);
boolean r, p;
Marker m = enter_section_(b, l, _NONE_, "<options ghc pragma>");
r = consumeToken(b, HS_PRAGMA_START);
r = r && onl(b, l + 1);
r = r && options_ghc_pragma_2(b, l + 1);
r = r && general_pragma_content(b, l + 1);
r = r && consumeToken(b, HS_PRAGMA_END);
exit_section_(b, m, HS_OPTIONS_GHC_PRAGMA, r);
return r;
p = r; // pin = 1
r = r && report_error_(b, onl(b, l + 1));
r = p && report_error_(b, options_ghc_pragma_2(b, l + 1)) && r;
r = p && report_error_(b, general_pragma_content(b, l + 1)) && r;
r = p && consumeToken(b, HS_PRAGMA_END) && r;
exit_section_(b, l, m, HS_OPTIONS_GHC_PRAGMA, r, p, pragma_recover_parser_);
return r || p;
}
// "OPTIONS_GHC" | "OPTIONS"
@ -4288,6 +4258,17 @@ public class HaskellParser implements PsiParser, LightPsiParser {
return r;
}
/* ********************************************************** */
// !(PRAGMA_END)
public static boolean pragma_recover(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "pragma_recover")) return false;
boolean r;
Marker m = enter_section_(b, l, _NOT_, "<pragma recover>");
r = !consumeToken(b, HS_PRAGMA_END);
exit_section_(b, l, m, HS_PRAGMA_RECOVER, r, false, null);
return r;
}
/* ********************************************************** */
// onl file_header? onl module_body
static boolean program(PsiBuilder b, int l) {
@ -6047,4 +6028,9 @@ public class HaskellParser implements PsiParser, LightPsiParser {
return r;
}
final static Parser pragma_recover_parser_ = new Parser() {
public boolean parse(PsiBuilder b, int l) {
return pragma_recover(b, l + 1);
}
};
}

View File

@ -10,9 +10,6 @@ public interface HaskellFileHeaderPragma extends HaskellCompositeElement {
@Nullable
HaskellAnnPragma getAnnPragma();
@Nullable
HaskellDummyHeaderPragma getDummyHeaderPragma();
@Nullable
HaskellHaddockPragma getHaddockPragma();

View File

@ -7,7 +7,7 @@ import com.intellij.psi.PsiElement;
public interface HaskellHaddockPragma extends HaskellCompositeElement {
@NotNull
@Nullable
HaskellGeneralPragmaContent getGeneralPragmaContent();
}

View File

@ -7,7 +7,7 @@ import com.intellij.psi.PsiElement;
public interface HaskellIncludePragma extends HaskellCompositeElement {
@NotNull
@Nullable
HaskellGeneralPragmaContent getGeneralPragmaContent();
}

View File

@ -7,7 +7,7 @@ import com.intellij.psi.PsiElement;
public interface HaskellOptionsGhcPragma extends HaskellCompositeElement {
@NotNull
@Nullable
HaskellGeneralPragmaContent getGeneralPragmaContent();
}

View File

@ -5,6 +5,6 @@ import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.psi.PsiElement;
public interface HaskellDummyHeaderPragma extends HaskellCompositeElement {
public interface HaskellPragmaRecover extends HaskellCompositeElement {
}

View File

@ -29,7 +29,6 @@ public interface HaskellTypes {
IElementType HS_DEPRECATED_WARN_PRAGMA = new HaskellCompositeElementType("HS_DEPRECATED_WARN_PRAGMA");
IElementType HS_DERIVING_DECLARATION = new HaskellCompositeElementType("HS_DERIVING_DECLARATION");
IElementType HS_DOT_DOT_PARENS = new HaskellCompositeElementType("HS_DOT_DOT_PARENS");
IElementType HS_DUMMY_HEADER_PRAGMA = new HaskellCompositeElementType("HS_DUMMY_HEADER_PRAGMA");
IElementType HS_EXPORT = new HaskellCompositeElementType("HS_EXPORT");
IElementType HS_EXPORTS = new HaskellCompositeElementType("HS_EXPORTS");
IElementType HS_EXPRESSION = new HaskellCompositeElementType("HS_EXPRESSION");
@ -79,6 +78,7 @@ public interface HaskellTypes {
IElementType HS_OPTIONS_GHC_PRAGMA = new HaskellCompositeElementType("HS_OPTIONS_GHC_PRAGMA");
IElementType HS_OTHER_PRAGMA = new HaskellCompositeElementType("HS_OTHER_PRAGMA");
IElementType HS_PARALLEL_ARRAY_TYPE = new HaskellCompositeElementType("HS_PARALLEL_ARRAY_TYPE");
IElementType HS_PRAGMA_RECOVER = new HaskellCompositeElementType("HS_PRAGMA_RECOVER");
IElementType HS_QCON = new HaskellCompositeElementType("HS_QCON");
IElementType HS_QCON_ID = new HaskellCompositeElementType("HS_QCON_ID");
IElementType HS_QCON_ID_QUALIFIER = new HaskellCompositeElementType("HS_QCON_ID_QUALIFIER");
@ -254,9 +254,6 @@ public interface HaskellTypes {
else if (type == HS_DOT_DOT_PARENS) {
return new HaskellDotDotParensImpl(node);
}
else if (type == HS_DUMMY_HEADER_PRAGMA) {
return new HaskellDummyHeaderPragmaImpl(node);
}
else if (type == HS_EXPORT) {
return new HaskellExportImpl(node);
}
@ -404,6 +401,9 @@ public interface HaskellTypes {
else if (type == HS_PARALLEL_ARRAY_TYPE) {
return new HaskellParallelArrayTypeImpl(node);
}
else if (type == HS_PRAGMA_RECOVER) {
return new HaskellPragmaRecoverImpl(node);
}
else if (type == HS_QCON) {
return new HaskellQconImpl(node);
}

View File

@ -90,10 +90,6 @@ public class HaskellVisitor extends PsiElementVisitor {
visitCompositeElement(o);
}
public void visitDummyHeaderPragma(@NotNull HaskellDummyHeaderPragma o) {
visitCompositeElement(o);
}
public void visitExport(@NotNull HaskellExport o) {
visitCompositeElement(o);
}
@ -290,6 +286,10 @@ public class HaskellVisitor extends PsiElementVisitor {
visitCompositeElement(o);
}
public void visitPragmaRecover(@NotNull HaskellPragmaRecover o) {
visitCompositeElement(o);
}
public void visitQcon(@NotNull HaskellQcon o) {
visitQVarConOpElement(o);
}

View File

@ -27,12 +27,6 @@ public class HaskellFileHeaderPragmaImpl extends HaskellCompositeElementImpl imp
return findChildByClass(HaskellAnnPragma.class);
}
@Override
@Nullable
public HaskellDummyHeaderPragma getDummyHeaderPragma() {
return findChildByClass(HaskellDummyHeaderPragma.class);
}
@Override
@Nullable
public HaskellHaddockPragma getHaddockPragma() {

View File

@ -22,9 +22,9 @@ public class HaskellHaddockPragmaImpl extends HaskellCompositeElementImpl implem
}
@Override
@NotNull
@Nullable
public HaskellGeneralPragmaContent getGeneralPragmaContent() {
return findNotNullChildByClass(HaskellGeneralPragmaContent.class);
return findChildByClass(HaskellGeneralPragmaContent.class);
}
}

View File

@ -22,9 +22,9 @@ public class HaskellIncludePragmaImpl extends HaskellCompositeElementImpl implem
}
@Override
@NotNull
@Nullable
public HaskellGeneralPragmaContent getGeneralPragmaContent() {
return findNotNullChildByClass(HaskellGeneralPragmaContent.class);
return findChildByClass(HaskellGeneralPragmaContent.class);
}
}

View File

@ -22,9 +22,9 @@ public class HaskellOptionsGhcPragmaImpl extends HaskellCompositeElementImpl imp
}
@Override
@NotNull
@Nullable
public HaskellGeneralPragmaContent getGeneralPragmaContent() {
return findNotNullChildByClass(HaskellGeneralPragmaContent.class);
return findChildByClass(HaskellGeneralPragmaContent.class);
}
}

View File

@ -10,14 +10,14 @@ import com.intellij.psi.util.PsiTreeUtil;
import static com.powertuple.intellij.haskell.psi.HaskellTypes.*;
import com.powertuple.intellij.haskell.psi.*;
public class HaskellDummyHeaderPragmaImpl extends HaskellCompositeElementImpl implements HaskellDummyHeaderPragma {
public class HaskellPragmaRecoverImpl extends HaskellCompositeElementImpl implements HaskellPragmaRecover {
public HaskellDummyHeaderPragmaImpl(ASTNode node) {
public HaskellPragmaRecoverImpl(ASTNode node) {
super(node);
}
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof HaskellVisitor) ((HaskellVisitor)visitor).visitDummyHeaderPragma(this);
if (visitor instanceof HaskellVisitor) ((HaskellVisitor)visitor).visitPragmaRecover(this);
else super.accept(visitor);
}

View File

@ -12,7 +12,7 @@
<p>0.95</p>
<ul>
<li>Support for IntelliJ 15</li>
<li>Building project with sbt</li>
<li>Building intellij-haskell project with sbt</li>
</ul>
<p>0.9</p>
<ul>
@ -87,7 +87,7 @@
</change-notes>
<!-- please see http://confluence.jetbrains.com/display/IDEADEV/Build+Number+Ranges for description -->
<idea-version since-build="142.0" until-build="142.9999"/>
<idea-version since-build="142.0" until-build="143.9999"/>
<extensions defaultExtensionNs="com.intellij">
<sdkType implementation="com.powertuple.intellij.haskell.sdk.HaskellSdkType"/>

View File

@ -4,7 +4,7 @@
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="IntelliJ IDEA Community Edition IC-142.5239.7" jdkType="IDEA JDK" />
<orderEntry type="jdk" jdkName="IntelliJ IDEA IU-143.1184.17" jdkType="IDEA JDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="intellijHaskell" />
</component>

View File

@ -1,4 +1,4 @@
resolvers += Resolver.url("dancingrobot84-bintray",
url("http://dl.bintray.com/dancingrobot84/sbt-plugins/"))(Resolver.ivyStylePatterns)
addSbtPlugin("com.dancingrobot84" % "sbt-idea-plugin" % "0.3.1")
addSbtPlugin("com.dancingrobot84" % "sbt-idea-plugin" % "0.4.1")

View File

@ -46,14 +46,6 @@ octal = 0[oO]{octit}+
float = [-+]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)([eE][-+]?[0-9]+)?
pragma_start = "{-#"
pragma_end = "#-}"
comment = ("--"[^\r\n]* | "\\begin{code}")
ncomment_start = "{-"
ncomment_end = "-}"
gap = \\({white_char}|{newline})*\\
cntrl = {large} | [@\[\\\]\^_]
charesc = [abfnrtv\\\"\'&]
@ -125,6 +117,15 @@ quasi_quote_end = {vertical_bar} {right_bracket}
shebang_line = {hash} {exclamation_mark} [^\r\n]*
pragma_start = "{-#"
pragma_end = "#-}"
comment = {dash}{dash}
ncomment_start = "{-"
ncomment_end = "-}"
comment = ({dash}{dash}[^\r\n]* | "\\begin{code}") {newline}
%%
<TEX> {
@ -134,7 +135,7 @@ shebang_line = {hash} {exclamation_mark} [^\r\n]*
}
<NCOMMENT> {
{ncomment_start} ({newline}| {white_char} | {vertical_bar} | {small} | {large} | {digit} | {dash})? {
{ncomment_start} {
commentDepth++;
}
@ -160,7 +161,7 @@ shebang_line = {hash} {exclamation_mark} [^\r\n]*
.|{white_char}|{newline} {}
}
{ncomment_start} ({vertical_bar} | {newline} | {white_char} | {small} | {large} | {digit} | {dash}) {
{ncomment_start}({white_char} | {newline} | [^#\-\}]) {
yybegin(NCOMMENT);
commentDepth = 0;
commentStart = getTokenStart();
@ -170,11 +171,11 @@ shebang_line = {hash} {exclamation_mark} [^\r\n]*
{comment} { return HS_COMMENT; }
{white_space} { return com.intellij.psi.TokenType.WHITE_SPACE; }
{ncomment_start} { return HS_NCOMMENT_START; }
{ncomment_end} { return HS_NCOMMENT_END; }
{pragma_start} { return HS_PRAGMA_START; }
{pragma_end} { return HS_PRAGMA_END; }
{ncomment_start} { return HS_NCOMMENT_START; }
{ncomment_end} { return HS_NCOMMENT_END; }
// not listed as reserved identifier but have meaning in certain context,
// let's say specialreservedid

View File

@ -20,6 +20,7 @@ import java.util.concurrent.{Executors, TimeUnit}
import com.intellij.codeInsight.completion._
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.patterns.PlatformPatterns
import com.intellij.psi.impl.source.tree.TreeUtil
@ -29,57 +30,60 @@ import com.intellij.util.ProcessingContext
import com.powertuple.intellij.haskell.external.{BrowseInfo, GhcMod}
import com.powertuple.intellij.haskell.psi.HaskellTypes._
import com.powertuple.intellij.haskell.psi._
import com.powertuple.intellij.haskell.util.{HaskellElementCondition, LineColumnPosition}
import com.powertuple.intellij.haskell.util.{HaskellElementCondition, LineColumnPosition, OSUtil}
import com.powertuple.intellij.haskell.{HaskellIcons, HaskellParserDefinition}
import scala.annotation.tailrec
import scala.collection.JavaConversions._
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, ExecutionContext, Future}
object HaskellCompletionContributor {
private final val ExecutorService = Executors.newCachedThreadPool()
implicit private final val ExecContext = ExecutionContext.fromExecutorService(ExecutorService)
}
class HaskellCompletionContributor extends CompletionContributor {
import com.powertuple.intellij.haskell.code.HaskellCompletionContributor._
private final val ExecutorService = Executors.newCachedThreadPool()
implicit private final val ExecContext = ExecutionContext.fromExecutorService(ExecutorService)
private final val ReservedIds = HaskellParserDefinition.ALL_RESERVED_IDS.getTypes.map(_.asInstanceOf[HaskellTokenType].getName).toSeq
private final val SpecialReservedIds = Seq("forall", "safe", "unsafe")
private final val PragmaStartEndIds = Seq("{-# ", "#-}")
private final val PragmaStartId = "{-#"
private final val PragmaEndId = "#-}"
private final val PragmaStartEndIds = Seq("{-#", "#-}")
private final val FileHeaderPragmaIds = Seq("LANGUAGE", "OPTIONS_HADDOCK", "INCLUDE", "OPTIONS", "OPTIONS_GHC", "ANN")
private final val ModulePragmaIds = Seq("ANN", "DEPRECATED", "WARING", "INLINE", "NOINLINE", "NOTINLINE", "INLINABEL", "LINE", "RULES",
"SPECIALIZE", "SPECIALISE", "MINIMAL", "SOURCE", "UNPACK", "NOUNPACK")
private final val InsideImportClauses = Seq("as", "hiding", "qualified")
private final val CommentIds = Seq("{-", "-}", "--")
private final val PlainPrefixElementTypes = Seq(HS_COMMENT, HS_NCOMMENT, HS_PRAGMA_START, HS_PRAGMA_END)
extend(CompletionType.BASIC, PlatformPatterns.psiElement(), new CompletionProvider[CompletionParameters] {
def addCompletions(parameters: CompletionParameters, context: ProcessingContext, originalResultSet: CompletionResultSet) {
val project = parameters.getPosition.getProject
val file = parameters.getOriginalFile
val resultSet = getNonEmptyElement(parameters.getOriginalPosition).orElse(getNonEmptyElement(parameters.getPosition)) match {
case Some(e) if PlainPrefixElementTypes.contains(e.getNode.getElementType) | e.getText.startsWith("{") | e.getText.startsWith("#") | e.getText.startsWith("-") => originalResultSet.withPrefixMatcher(new PlainPrefixMatcher(getTextAtCaret(parameters.getEditor, file)))
case Some(e) if e.getNode.getElementType == HS_CONID_ID && getTextAtCaret(parameters.getEditor, file).endsWith(".") => originalResultSet.withPrefixMatcher(new PlainPrefixMatcher(getTextAtCaret(parameters.getEditor, file)))
case _ => originalResultSet
}
val completionPosition = Option(parameters.getOriginalPosition).orElse(Option(parameters.getPosition))
completionPosition match {
case Some(p) if isPragmaInProgress(p) =>
resultSet.addAllElements(getModulePragmaIds)
resultSet.addAllElements(getPragmaStartEndIds)
case Some(p) if isFileHeaderPragmaInProgress(p) =>
resultSet.addAllElements(getLanguageExtensions(project).toSeq)
resultSet.addAllElements(getPragmaStartEndIds)
resultSet.addAllElements(getFileHeaderPragmaIds)
case Some(p) if isImportSpecInProgress(p) =>
resultSet.addAllElements(findIdsForInImportModuleSpec(project, p).toSeq)
case Some(p) if isImportModuleDeclarationInProgress(p) =>
resultSet.addAllElements(findModulesToImport(project).toSeq)
resultSet.addAllElements(getInsideImportClauses)
case Some(p) if isFileHeaderPragmaInProgress(p) =>
resultSet.addAllElements(getLanguageExtensions(project).toSeq)
resultSet.addAllElements(getPragmaStartEndIds)
resultSet.addAllElements(getFileHeaderPragmaIds)
case Some(p) if isNCommentInProgress(p) =>
resultSet.addAllElements(getPragmaStartEndIds)
resultSet.addAllElements(getCommentIds)
case Some(p) if isPragmaInProgress(p) =>
resultSet.addAllElements(getModulePragmaIds)
resultSet.addAllElements(getPragmaStartEndIds)
case Some(p) =>
val importDeclarations = findImportDeclarations(file)
getQualifiedIdentifierInProgress(p) match {
@ -116,11 +120,33 @@ class HaskellCompletionContributor extends CompletionContributor {
}
caretElement match {
case Some(e) if e.getText.trim.length > 0 => context.setDummyIdentifier(e.getText.trim)
case Some(e) if e.getNode.getElementType == HS_CONID_ID && Option(e.getNextSibling).map(_.getNode.getElementType == HS_DOT).isDefined =>
context.setDummyIdentifier(file.findElementAt(e.getTextOffset - 1).getText + ".")
case Some(e) if PlainPrefixElementTypes.contains(e.getNode.getElementType) => context.setDummyIdentifier(getTextAtCaret(context.getEditor, file))
case Some(e) if e.getText.trim.nonEmpty => context.setDummyIdentifier(e.getText.trim)
case _ => context.setDummyIdentifier("a")
}
}
private def getTextAtCaret(editor: Editor, file: PsiFile): String = {
val caretOffset = editor.getCaretModel.getOffset
getTextUntilNoChar(file.getText, if (caretOffset > 0) caretOffset - 1 else caretOffset, "")
}
@tailrec
private def getTextUntilNoChar(fileText: String, offset: Int, text: String): String = {
val c = fileText.charAt(offset)
if (c < ' ' || c == OSUtil.LineSeparator || c == '\r') {
text
} else {
if (offset > 0) {
getTextUntilNoChar(fileText, offset - 1, c.toString + text)
} else {
c.toString + text
}
}
}
private def getNonEmptyElement(element: PsiElement) = {
Option(element) match {
case Some(s) if !s.getText.trim.isEmpty => Some(s)
@ -130,8 +156,8 @@ class HaskellCompletionContributor extends CompletionContributor {
private def isImportSpecInProgress(position: PsiElement): Boolean = {
Option(TreeUtil.findParent(position.getNode, HS_IMPORT_ID)).isDefined ||
(Option(TreeUtil.findParent(position.getNode, HS_IMPORT_SPEC)).isDefined &&
Option(TreeUtil.findSiblingBackward(position.getNode, HS_LEFT_PAREN)).isDefined)
(Option(TreeUtil.findParent(position.getNode, HS_IMPORT_SPEC)).isDefined &&
Option(TreeUtil.findSiblingBackward(position.getNode, HS_LEFT_PAREN)).isDefined)
}
private def findIdsForInImportModuleSpec(project: Project, position: PsiElement) = {
@ -143,7 +169,7 @@ class HaskellCompletionContributor extends CompletionContributor {
private def isImportModuleDeclarationInProgress(position: PsiElement): Boolean = {
Option(TreeUtil.findSiblingBackward(position.getNode, HS_IMPORT)).
orElse(Option(TreeUtil.findParent(position.getNode, HS_IMPORT_DECLARATION))).isDefined
orElse(Option(TreeUtil.findParent(position.getNode, HS_IMPORT_DECLARATION))).isDefined
}
private def findModulesToImport(project: Project) = {
@ -156,8 +182,8 @@ class HaskellCompletionContributor extends CompletionContributor {
private def isFileHeaderPragmaInProgress(position: PsiElement): Boolean = {
Option(TreeUtil.findParent(position.getNode, HaskellTypes.HS_FILE_HEADER_PRAGMA)).isDefined ||
Option(TreeUtil.findSiblingBackward(position.getNode, HS_COMMA)).isDefined &&
Option(TreeUtil.findSibling(position.getNode, HS_PRAGMA_END)).isDefined
Option(TreeUtil.findSiblingBackward(position.getNode, HS_COMMA)).isDefined &&
Option(TreeUtil.findSibling(position.getNode, HS_PRAGMA_END)).isDefined
}
private def isPragmaInProgress(position: PsiElement): Boolean = {
@ -166,25 +192,23 @@ class HaskellCompletionContributor extends CompletionContributor {
private def getQualifiedIdentifierInProgress(position: PsiElement): Option[String] = {
val qualifiedElement = Option(PsiTreeUtil.findFirstParent(position, HaskellElementCondition.QualifiedElementCondition))
qualifiedElement match {
case Some(e: HaskellQvarId) => Some(e.getQualifier.getName)
case Some(e: HaskellQconId) => Some(e.getQconIdQualifier.getText)
case Some(e: HaskellQvarSym) => Some(e.getQualifier.getName)
case Some(e: HaskellQconSym) => Some(e.getQualifier.getName)
case _ =>
val elementType = position.getNode.getElementType
if (elementType == HS_NEWLINE || elementType == TokenType.WHITE_SPACE || elementType == HS_DOT) {
Option(position.getPrevSibling).flatMap(ps => {
val qcon = Option(PsiTreeUtil.findChildOfType(ps, classOf[HaskellQcon]))
if (qcon.exists(qcon => Option(TreeUtil.findLastLeaf(qcon.getNextSibling.getNode)).exists(_.getElementType == HS_DOT))) {
qcon.map(_.getName)
} else {
None
}
})
} else {
None
}
qualifiedElement.map(qe => {
qe match {
case qe: HaskellQvarId => qe.getQualifier.getName
case qe: HaskellQconId => qe.getQconIdQualifier.getText
case qe: HaskellQvarSym => qe.getQualifier.getName
case qe: HaskellQconSym => qe.getQualifier.getName
}
}).orElse {
val elementType = position.getNode.getElementType
if (elementType == HS_NEWLINE || elementType == TokenType.WHITE_SPACE || elementType == HS_DOT) {
Option(position.getPrevSibling).flatMap(ps => {
val qcon = Option(PsiTreeUtil.findChildOfType(ps, classOf[HaskellQcon]))
qcon.filter(qc => Option(qc.getNextSibling).map(_.getNode).flatMap(n => Option(TreeUtil.findLastLeaf(n))).exists(_.getElementType == HS_DOT)).map(_.getName)
})
} else {
None
}
}
}
@ -200,6 +224,10 @@ class HaskellCompletionContributor extends CompletionContributor {
PragmaStartEndIds.map(p => LookupElementBuilder.create(p).withIcon(HaskellIcons.HaskellSmallBlueLogo).withTailText(" pragma", true))
}
private def getPragmaStartId = {
LookupElementBuilder.create(PragmaStartId).withIcon(HaskellIcons.HaskellSmallBlueLogo).withTailText(" pragma", true)
}
private def getFileHeaderPragmaIds = {
FileHeaderPragmaIds.map(p => LookupElementBuilder.create(p).withIcon(HaskellIcons.HaskellSmallBlueLogo).withTailText(" pragma", true))
}
@ -214,7 +242,7 @@ class HaskellCompletionContributor extends CompletionContributor {
private def getImportedModulesWithFullScope(psiFile: PsiFile, importDeclarations: Iterable[HaskellImportDeclaration]): Iterable[ImportFullSpec] = {
val moduleNames = importDeclarations.filter(i => Option(i.getImportSpec).isEmpty).
map(i => ImportFullSpec(i.getModuleName, Option(i.getImportQualified).isDefined, Option(i.getImportQualifiedAs).map(_.getQualifier).map(_.getName)))
map(i => ImportFullSpec(i.getModuleName, Option(i.getImportQualified).isDefined, Option(i.getImportQualifiedAs).map(_.getQualifier).map(_.getName)))
if (importDeclarations.exists(_.getModuleName == "Prelude")) {
moduleNames
} else {
@ -250,9 +278,9 @@ class HaskellCompletionContributor extends CompletionContributor {
val importFullSpecs = getImportedModulesWithFullScope(file, importDeclarations).toSeq
val browseInfosWithImportSpecFutures = importFullSpecs.
map(ifs => Future {
BrowseInfosForImportFullSpec(ifs, GhcMod.browseInfo(project, ifs.moduleName, removeParensFromOperator = true))
}.map(bifs => createLookupElements(bifs.importSpec, bifs.browseInfos, qualifier)))
map(ifs => Future {
BrowseInfosForImportFullSpec(ifs, GhcMod.browseInfo(project, ifs.moduleName, removeParensFromOperator = true))
}.map(bi => createLookupElements(bi.importSpec, bi.browseInfos, qualifier)))
Await.result(Future.sequence(browseInfosWithImportSpecFutures), Duration.create(5, TimeUnit.SECONDS)).flatten
}
@ -261,9 +289,9 @@ class HaskellCompletionContributor extends CompletionContributor {
val importHidingIdsSpec = getImportedModulesWithHidingIdsSpec(file, importDeclarations).toSeq
val browseInfosWithImportHidingIdsSpecFutures = importHidingIdsSpec.
map(ihis => Future {
BrowseInfosForImportHidingIdsSpec(ihis, GhcMod.browseInfo(project, ihis.moduleName, removeParensFromOperator = true))
}.map(bihis => createLookupElements(bihis.importSpec, bihis.browseInfos.filterNot(bi => bihis.importSpec.ids.contains(bi.name)), None)))
map(bi => Future {
BrowseInfosForImportHidingIdsSpec(bi, GhcMod.browseInfo(project, bi.moduleName, removeParensFromOperator = true))
}.map(bis => createLookupElements(bis.importSpec, bis.browseInfos.filterNot(bi => bis.importSpec.ids.contains(bi.name)), None)))
Await.result(Future.sequence(browseInfosWithImportHidingIdsSpecFutures), Duration.create(5, TimeUnit.SECONDS)).flatten
}
@ -272,9 +300,9 @@ class HaskellCompletionContributor extends CompletionContributor {
val importIdsSpec = getImportedModulesWithSpecIds(file, importDeclarations).toSeq
val browseInfosWithImportIdsSpecFutures = importIdsSpec.
map(iis => Future {
BrowseInfosForImportIdsSpec(iis, GhcMod.browseInfo(project, iis.moduleName, removeParensFromOperator = true))
}.map(biis => createLookupElements(biis.importSpec, biis.browseInfos.filter(bi => biis.importSpec.ids.contains(bi.name)), qualifier)))
map(iis => Future {
BrowseInfosForImportIdsSpec(iis, GhcMod.browseInfo(project, iis.moduleName, removeParensFromOperator = true))
}.map(bis => createLookupElements(bis.importSpec, bis.browseInfos.filter(bi => bis.importSpec.ids.contains(bi.name)), qualifier)))
Await.result(Future.sequence(browseInfosWithImportIdsSpecFutures), Duration.create(5, TimeUnit.SECONDS)).flatten
}

View File

@ -40,15 +40,15 @@
mixin("first_line_expression|line_expression|last_line_expression")="com.powertuple.intellij.haskell.psi.impl.HaskellLineExpressionElementImpl"
}
program ::= onl file_header? onl module_body
program ::= onl SHEBANG_LINE? onl file_header? onl module_body
file_header ::= SHEBANG_LINE? onl (file_header_pragma onl)+
file_header ::= (file_header_pragma onl)+
file_header_pragma ::= language_pragma | options_ghc_pragma | include_pragma | haddock_pragma | ann_pragma | dummy_header_pragma
language_pragma ::= PRAGMA_START onl "LANGUAGE" onl qcon (onl COMMA onl qcon)* onl PRAGMA_END
options_ghc_pragma ::= PRAGMA_START onl ("OPTIONS_GHC" | "OPTIONS") general_pragma_content PRAGMA_END
include_pragma ::= PRAGMA_START onl "INCLUDE" general_pragma_content PRAGMA_END
haddock_pragma ::= PRAGMA_START onl "OPTIONS_HADDOCK" general_pragma_content PRAGMA_END
dummy_header_pragma ::= PRAGMA_START CONID_ID? PRAGMA_END? NEWLINE
language_pragma ::= PRAGMA_START onl "LANGUAGE" onl qcon (onl COMMA onl qcon)* onl PRAGMA_END NEWLINE?
options_ghc_pragma ::= PRAGMA_START onl ("OPTIONS_GHC" | "OPTIONS") general_pragma_content PRAGMA_END NEWLINE?
include_pragma ::= PRAGMA_START onl "INCLUDE" general_pragma_content PRAGMA_END NEWLINE?
haddock_pragma ::= PRAGMA_START onl "OPTIONS_HADDOCK" general_pragma_content PRAGMA_END NEWLINE?
dummy_header_pragma ::= PRAGMA_START CONID_ID? PRAGMA_END? NEWLINE?
other_pragma ::= ann_pragma | deprecated_warn_pragma | noinline_pragma | inlinable_pragma | line_pragma | rules_pragma |
specialize_pragma | inline_pragma | minimal_pragma

View File

@ -18,8 +18,7 @@ package com.powertuple.intellij.haskell.highlighter
import com.intellij.lang.{BracePair, PairedBraceMatcher}
import com.intellij.psi.PsiFile
import com.intellij.psi.tree.{TokenSet, IElementType}
import com.powertuple.intellij.haskell.HaskellParserDefinition
import com.intellij.psi.tree.IElementType
import com.powertuple.intellij.haskell.psi.HaskellTypes
object HaskellBraceMatcher {