diff --git a/simple_language/build.gradle b/simple_language/build.gradle new file mode 100644 index 000000000..34c2bd394 --- /dev/null +++ b/simple_language/build.gradle @@ -0,0 +1,37 @@ +plugins { + id 'java' + id 'org.jetbrains.intellij' version '0.4.15' +} + +group 'com.intellij.sdk' +version '2.0.0' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +test { + // Set idea.home.path to the absolute path to the intellij-community source + // on your local machine. + systemProperty "idea.home.path", "/Users/jhake/Documents/source/comm" +} + +// Include the generated files in the source set +sourceSets.main.java.srcDirs 'src/main/gen' + +dependencies { + testCompile group: 'junit', name: 'junit', version: '4.12' +} + +// See https://github.com/JetBrains/gradle-intellij-plugin/ +intellij { + version '2019.3.2' + type = 'IC' + plugins 'java' + updateSinceUntilBuild = false +} +patchPluginXml { + version = project.version +} diff --git a/simple_language/gradle/wrapper/gradle-wrapper.jar b/simple_language/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..cc4fdc293 Binary files /dev/null and b/simple_language/gradle/wrapper/gradle-wrapper.jar differ diff --git a/simple_language/gradle/wrapper/gradle-wrapper.properties b/simple_language/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..94920145f --- /dev/null +++ b/simple_language/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/simple_language/gradlew b/simple_language/gradlew new file mode 100755 index 000000000..2fe81a7d9 --- /dev/null +++ b/simple_language/gradlew @@ -0,0 +1,183 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/simple_language/gradlew.bat b/simple_language/gradlew.bat new file mode 100644 index 000000000..9618d8d96 --- /dev/null +++ b/simple_language/gradlew.bat @@ -0,0 +1,100 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/simple_language/settings.gradle b/simple_language/settings.gradle new file mode 100644 index 000000000..8a3935957 --- /dev/null +++ b/simple_language/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'language' + diff --git a/simple_language/src/main/gen/com/intellij/sdk/language/SimpleLexer.java b/simple_language/src/main/gen/com/intellij/sdk/language/SimpleLexer.java new file mode 100644 index 000000000..d29665ebe --- /dev/null +++ b/simple_language/src/main/gen/com/intellij/sdk/language/SimpleLexer.java @@ -0,0 +1,535 @@ +/* The following code was generated by JFlex 1.7.0 tweaked for IntelliJ platform */ + +package com.intellij.sdk.language; + +import com.intellij.lexer.FlexLexer; +import com.intellij.psi.tree.IElementType; +import com.intellij.sdk.language.psi.SimpleTypes; +import com.intellij.psi.TokenType; + + +/** + * This class is a scanner generated by + * JFlex 1.7.0 + * from the specification file Simple.flex + */ +class SimpleLexer implements FlexLexer { + + /** This character denotes the end of file */ + public static final int YYEOF = -1; + + /** initial size of the lookahead buffer */ + private static final int ZZ_BUFFERSIZE = 16384; + + /** lexical states */ + public static final int YYINITIAL = 0; + public static final int WAITING_VALUE = 2; + + /** + * 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, 1, 1 + }; + + /** + * Translates characters to character classes + * Chosen bits are [9, 6, 6] + * Total runtime size is 1568 bytes + */ + public static int ZZ_CMAP(int ch) { + return ZZ_CMAP_A[(ZZ_CMAP_Y[ZZ_CMAP_Z[ch>>12]|((ch>>6)&0x3f)]<<6)|(ch&0x3f)]; + } + + /* The ZZ_CMAP_Z table has 272 entries */ + static final char ZZ_CMAP_Z[] = zzUnpackCMap( + "\1\0\1\100\1\200\u010d\100"); + + /* The ZZ_CMAP_Y table has 192 entries */ + static final char ZZ_CMAP_Y[] = zzUnpackCMap( + "\1\0\1\1\1\2\175\3\1\4\77\3"); + + /* The ZZ_CMAP_A table has 320 entries */ + static final char ZZ_CMAP_A[] = zzUnpackCMap( + "\11\0\1\4\1\2\1\1\1\5\1\3\22\0\1\7\1\10\1\0\1\10\26\0\1\11\2\0\1\11\36\0\1"+ + "\6\50\0\1\1\242\0\2\1\26\0"); + + /** + * Translates DFA states to action switch labels. + */ + private static final int [] ZZ_ACTION = zzUnpackAction(); + + private static final String ZZ_ACTION_PACKED_0 = + "\2\0\2\1\1\2\1\3\1\4\1\5\2\6\2\7"+ + "\1\3\1\7\1\0\2\4\1\0\1\2\2\6"; + + private static int [] zzUnpackAction() { + int [] result = new int[21]; + 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\12\0\24\0\36\0\50\0\62\0\74\0\106"+ + "\0\120\0\132\0\50\0\144\0\156\0\170\0\62\0\202"+ + "\0\214\0\156\0\132\0\226\0\240"; + + private static int [] zzUnpackRowMap() { + int [] result = new int[21]; + 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\3\1\4\1\5\1\4\2\5\1\6\1\5\1\7"+ + "\1\10\1\11\1\12\1\13\1\12\1\14\1\13\1\15"+ + "\1\16\2\11\2\3\1\0\1\3\2\0\1\17\1\0"+ + "\1\3\1\0\1\3\1\4\1\5\1\4\2\5\1\17"+ + "\1\5\1\3\2\0\5\5\1\0\1\5\11\0\1\3"+ + "\2\0\2\7\1\0\1\3\2\20\1\21\1\20\1\7"+ + "\1\20\12\0\2\11\1\0\2\11\1\0\1\22\4\11"+ + "\1\23\1\5\2\23\1\5\1\22\1\23\3\11\1\24"+ + "\1\16\1\24\1\14\1\16\1\22\1\14\5\11\1\25"+ + "\6\11\1\0\1\5\1\16\1\5\2\16\1\0\1\16"+ + "\2\0\2\20\2\0\10\20\2\0\3\20\1\7\2\20"+ + "\1\11\1\24\1\5\2\24\1\5\1\22\1\24\7\11"+ + "\1\0\1\22\3\11"; + + private static int [] zzUnpackTrans() { + int [] result = new int[170]; + 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; + + /* error messages for the codes above */ + private static final String[] ZZ_ERROR_MSG = { + "Unknown internal scanner error", + "Error: could not match input", + "Error: pushback value was too large" + }; + + /** + * ZZ_ATTRIBUTE[aState] contains the attributes of state aState + */ + private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); + + private static final String ZZ_ATTRIBUTE_PACKED_0 = + "\2\0\5\1\1\11\6\1\1\0\2\1\1\0\3\1"; + + private static int [] zzUnpackAttribute() { + int [] result = new int[21]; + 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 input device */ + private java.io.Reader zzReader; + + /** 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 = ""; + + /** the textposition at the last accepting state */ + private int zzMarkedPos; + + /** 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; + + /** denotes if the user-EOF-code has already been executed */ + private boolean zzEOFDone; + + + /** + * Creates a new scanner + * + * @param in the java.io.Reader to read input from. + */ + SimpleLexer(java.io.Reader in) { + this.zzReader = 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) { + int size = 0; + for (int i = 0, length = packed.length(); i < length; i += 2) { + size += packed.charAt(i); + } + char[] map = new char[size]; + int i = 0; /* index in packed string */ + int j = 0; /* index in unpacked array */ + while (i < packed.length()) { + 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; + zzCurrentPos = zzMarkedPos = zzStartRead = start; + zzAtEOF = false; + zzAtBOL = true; + zzEndRead = end; + yybegin(initialState); + } + + /** + * Refills the input buffer. + * + * @return {@code false}, 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 {@code pos} 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 zzBuffer.charAt(zzStartRead+pos); + } + + + /** + * Returns the length of the matched text region. + */ + public final int yylength() { + return zzMarkedPos-zzStartRead; + } + + + /** + * Reports an error that occurred 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; + } + + + /** + * Contains user EOF-code, which will be executed exactly once, + * when the end of file is reached + */ + private void zzDoEOF() { + if (!zzEOFDone) { + zzEOFDone = true; + + } + } + + + /** + * 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; + + 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]; + + // set up zzAction for empty match case: + int zzAttributes = zzAttrL[zzState]; + if ( (zzAttributes & 1) == 1 ) { + zzAction = zzState; + } + + + zzForAction: { + while (true) { + + if (zzCurrentPosL < zzEndReadL) { + zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL/*, zzEndReadL*/); + zzCurrentPosL += Character.charCount(zzInput); + } + 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 = Character.codePointAt(zzBufferL, zzCurrentPosL/*, zzEndReadL*/); + zzCurrentPosL += Character.charCount(zzInput); + } + } + int zzNext = zzTransL[ zzRowMapL[zzState] + ZZ_CMAP(zzInput) ]; + if (zzNext == -1) break zzForAction; + zzState = zzNext; + + zzAttributes = zzAttrL[zzState]; + if ( (zzAttributes & 1) == 1 ) { + zzAction = zzState; + zzMarkedPosL = zzCurrentPosL; + if ( (zzAttributes & 8) == 8 ) break zzForAction; + } + + } + } + + // store back cached position + zzMarkedPos = zzMarkedPosL; + + if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { + zzAtEOF = true; + zzDoEOF(); + return null; + } + else { + switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { + case 1: + { yybegin(YYINITIAL); return SimpleTypes.KEY; + } + // fall through + case 8: break; + case 2: + { yybegin(YYINITIAL); return TokenType.WHITE_SPACE; + } + // fall through + case 9: break; + case 3: + { return TokenType.BAD_CHARACTER; + } + // fall through + case 10: break; + case 4: + { yybegin(YYINITIAL); return SimpleTypes.COMMENT; + } + // fall through + case 11: break; + case 5: + { yybegin(WAITING_VALUE); return SimpleTypes.SEPARATOR; + } + // fall through + case 12: break; + case 6: + { yybegin(YYINITIAL); return SimpleTypes.VALUE; + } + // fall through + case 13: break; + case 7: + { yybegin(WAITING_VALUE); return TokenType.WHITE_SPACE; + } + // fall through + case 14: break; + default: + zzScanError(ZZ_NO_MATCH); + } + } + } + } + + +} diff --git a/simple_language/src/main/gen/com/intellij/sdk/language/parser/SimpleParser.java b/simple_language/src/main/gen/com/intellij/sdk/language/parser/SimpleParser.java new file mode 100644 index 000000000..a70231e85 --- /dev/null +++ b/simple_language/src/main/gen/com/intellij/sdk/language/parser/SimpleParser.java @@ -0,0 +1,127 @@ +// This is a generated file. Not intended for manual editing. +package com.intellij.sdk.language.parser; + +import com.intellij.lang.PsiBuilder; +import com.intellij.lang.PsiBuilder.Marker; +import static com.intellij.sdk.language.psi.SimpleTypes.*; +import static com.intellij.lang.parser.GeneratedParserUtilBase.*; +import com.intellij.psi.tree.IElementType; +import com.intellij.lang.ASTNode; +import com.intellij.psi.tree.TokenSet; +import com.intellij.lang.PsiParser; +import com.intellij.lang.LightPsiParser; + +@SuppressWarnings({"SimplifiableIfStatement", "UnusedAssignment"}) +public class SimpleParser implements PsiParser, LightPsiParser { + + public ASTNode parse(IElementType t, PsiBuilder b) { + parseLight(t, b); + return b.getTreeBuilt(); + } + + public void parseLight(IElementType t, PsiBuilder b) { + boolean r; + b = adapt_builder_(t, b, this, null); + Marker m = enter_section_(b, 0, _COLLAPSE_, null); + r = parse_root_(t, b); + exit_section_(b, 0, m, t, r, true, TRUE_CONDITION); + } + + protected boolean parse_root_(IElementType t, PsiBuilder b) { + return parse_root_(t, b, 0); + } + + static boolean parse_root_(IElementType t, PsiBuilder b, int l) { + return simpleFile(b, l + 1); + } + + /* ********************************************************** */ + // property|COMMENT|CRLF + static boolean item_(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "item_")) return false; + boolean r; + Marker m = enter_section_(b); + r = property(b, l + 1); + if (!r) r = consumeToken(b, COMMENT); + if (!r) r = consumeToken(b, CRLF); + exit_section_(b, m, null, r); + return r; + } + + /* ********************************************************** */ + // (KEY? SEPARATOR VALUE?) | KEY + public static boolean property(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "property")) return false; + boolean r; + Marker m = enter_section_(b, l, _NONE_, PROPERTY, ""); + r = property_0(b, l + 1); + if (!r) r = consumeToken(b, KEY); + exit_section_(b, l, m, r, false, recover_property_parser_); + return r; + } + + // KEY? SEPARATOR VALUE? + private static boolean property_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "property_0")) return false; + boolean r; + Marker m = enter_section_(b); + r = property_0_0(b, l + 1); + r = r && consumeToken(b, SEPARATOR); + r = r && property_0_2(b, l + 1); + exit_section_(b, m, null, r); + return r; + } + + // KEY? + private static boolean property_0_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "property_0_0")) return false; + consumeToken(b, KEY); + return true; + } + + // VALUE? + private static boolean property_0_2(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "property_0_2")) return false; + consumeToken(b, VALUE); + return true; + } + + /* ********************************************************** */ + // !(KEY|SEPARATOR|COMMENT) + static boolean recover_property(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "recover_property")) return false; + boolean r; + Marker m = enter_section_(b, l, _NOT_); + r = !recover_property_0(b, l + 1); + exit_section_(b, l, m, r, false, null); + return r; + } + + // KEY|SEPARATOR|COMMENT + private static boolean recover_property_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "recover_property_0")) return false; + boolean r; + r = consumeToken(b, KEY); + if (!r) r = consumeToken(b, SEPARATOR); + if (!r) r = consumeToken(b, COMMENT); + return r; + } + + /* ********************************************************** */ + // item_* + static boolean simpleFile(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "simpleFile")) return false; + while (true) { + int c = current_position_(b); + if (!item_(b, l + 1)) break; + if (!empty_element_parsed_guard_(b, "simpleFile", c)) break; + } + return true; + } + + static final Parser recover_property_parser_ = new Parser() { + public boolean parse(PsiBuilder b, int l) { + return recover_property(b, l + 1); + } + }; +} diff --git a/simple_language/src/main/gen/com/intellij/sdk/language/psi/SimpleProperty.java b/simple_language/src/main/gen/com/intellij/sdk/language/psi/SimpleProperty.java new file mode 100644 index 000000000..75a0af3b5 --- /dev/null +++ b/simple_language/src/main/gen/com/intellij/sdk/language/psi/SimpleProperty.java @@ -0,0 +1,23 @@ +// This is a generated file. Not intended for manual editing. +package com.intellij.sdk.language.psi; + +import java.util.List; +import org.jetbrains.annotations.*; +import com.intellij.psi.PsiElement; +import com.intellij.navigation.ItemPresentation; + +public interface SimpleProperty extends SimpleNamedElement { + + String getKey(); + + String getValue(); + + String getName(); + + PsiElement setName(String newName); + + PsiElement getNameIdentifier(); + + ItemPresentation getPresentation(); + +} diff --git a/simple_language/src/main/gen/com/intellij/sdk/language/psi/SimpleTypes.java b/simple_language/src/main/gen/com/intellij/sdk/language/psi/SimpleTypes.java new file mode 100644 index 000000000..558678ca9 --- /dev/null +++ b/simple_language/src/main/gen/com/intellij/sdk/language/psi/SimpleTypes.java @@ -0,0 +1,28 @@ +// This is a generated file. Not intended for manual editing. +package com.intellij.sdk.language.psi; + +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.PsiElement; +import com.intellij.lang.ASTNode; +import com.intellij.sdk.language.psi.impl.*; + +public interface SimpleTypes { + + IElementType PROPERTY = new SimpleElementType("PROPERTY"); + + IElementType COMMENT = new SimpleTokenType("COMMENT"); + IElementType CRLF = new SimpleTokenType("CRLF"); + IElementType KEY = new SimpleTokenType("KEY"); + IElementType SEPARATOR = new SimpleTokenType("SEPARATOR"); + IElementType VALUE = new SimpleTokenType("VALUE"); + + class Factory { + public static PsiElement createElement(ASTNode node) { + IElementType type = node.getElementType(); + if (type == PROPERTY) { + return new SimplePropertyImpl(node); + } + throw new AssertionError("Unknown element type: " + type); + } + } +} diff --git a/simple_language/src/main/gen/com/intellij/sdk/language/psi/SimpleVisitor.java b/simple_language/src/main/gen/com/intellij/sdk/language/psi/SimpleVisitor.java new file mode 100644 index 000000000..aeacbe65d --- /dev/null +++ b/simple_language/src/main/gen/com/intellij/sdk/language/psi/SimpleVisitor.java @@ -0,0 +1,22 @@ +// This is a generated file. Not intended for manual editing. +package com.intellij.sdk.language.psi; + +import org.jetbrains.annotations.*; +import com.intellij.psi.PsiElementVisitor; +import com.intellij.psi.PsiElement; + +public class SimpleVisitor extends PsiElementVisitor { + + public void visitProperty(@NotNull SimpleProperty o) { + visitNamedElement(o); + } + + public void visitNamedElement(@NotNull SimpleNamedElement o) { + visitPsiElement(o); + } + + public void visitPsiElement(@NotNull PsiElement o) { + visitElement(o); + } + +} diff --git a/simple_language/src/main/gen/com/intellij/sdk/language/psi/impl/SimplePropertyImpl.java b/simple_language/src/main/gen/com/intellij/sdk/language/psi/impl/SimplePropertyImpl.java new file mode 100644 index 000000000..e9fc3a070 --- /dev/null +++ b/simple_language/src/main/gen/com/intellij/sdk/language/psi/impl/SimplePropertyImpl.java @@ -0,0 +1,59 @@ +// This is a generated file. Not intended for manual editing. +package com.intellij.sdk.language.psi.impl; + +import java.util.List; +import org.jetbrains.annotations.*; +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiElementVisitor; +import com.intellij.psi.util.PsiTreeUtil; +import static com.intellij.sdk.language.psi.SimpleTypes.*; +import com.intellij.sdk.language.psi.*; +import com.intellij.navigation.ItemPresentation; + +public class SimplePropertyImpl extends SimpleNamedElementImpl implements SimpleProperty { + + public SimplePropertyImpl(@NotNull ASTNode node) { + super(node); + } + + public void accept(@NotNull SimpleVisitor visitor) { + visitor.visitProperty(this); + } + + public void accept(@NotNull PsiElementVisitor visitor) { + if (visitor instanceof SimpleVisitor) accept((SimpleVisitor)visitor); + else super.accept(visitor); + } + + @Override + public String getKey() { + return SimplePsiImplUtil.getKey(this); + } + + @Override + public String getValue() { + return SimplePsiImplUtil.getValue(this); + } + + @Override + public String getName() { + return SimplePsiImplUtil.getName(this); + } + + @Override + public PsiElement setName(String newName) { + return SimplePsiImplUtil.setName(this, newName); + } + + @Override + public PsiElement getNameIdentifier() { + return SimplePsiImplUtil.getNameIdentifier(this); + } + + @Override + public ItemPresentation getPresentation() { + return SimplePsiImplUtil.getPresentation(this); + } + +} diff --git a/simple_language/src/main/java/com/intellij/sdk/language/Simple.bnf b/simple_language/src/main/java/com/intellij/sdk/language/Simple.bnf new file mode 100644 index 000000000..3ae45df60 --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/Simple.bnf @@ -0,0 +1,30 @@ +{ + parserClass="com.intellij.sdk.language.parser.SimpleParser" + + extends="com.intellij.extapi.psi.ASTWrapperPsiElement" + + psiClassPrefix="Simple" + psiImplClassSuffix="Impl" + psiPackage="com.intellij.sdk.language.psi" + psiImplPackage="com.intellij.sdk.language.psi.impl" + + elementTypeHolderClass="com.intellij.sdk.language.psi.SimpleTypes" + elementTypeClass="com.intellij.sdk.language.psi.SimpleElementType" + tokenTypeClass="com.intellij.sdk.language.psi.SimpleTokenType" + + psiImplUtilClass="com.intellij.sdk.language.psi.impl.SimplePsiImplUtil" +} + +simpleFile ::= item_* + +private item_ ::= (property|COMMENT|CRLF) + +property ::= (KEY? SEPARATOR VALUE?) | KEY { + pin=3 + recoverWhile="recover_property" + mixin="com.intellij.sdk.language.psi.impl.SimpleNamedElementImpl" + implements="com.intellij.sdk.language.psi.SimpleNamedElement" + methods=[getKey getValue getName setName getNameIdentifier getPresentation] +} + +private recover_property ::= !(KEY|SEPARATOR|COMMENT) \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/Simple.flex b/simple_language/src/main/java/com/intellij/sdk/language/Simple.flex new file mode 100644 index 000000000..d71c2a4a9 --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/Simple.flex @@ -0,0 +1,44 @@ +package com.intellij.sdk.language; + +import com.intellij.lexer.FlexLexer; +import com.intellij.psi.tree.IElementType; +import com.intellij.sdk.language.psi.SimpleTypes; +import com.intellij.psi.TokenType; + +%% + +%class SimpleLexer +%implements FlexLexer +%unicode +%function advance +%type IElementType +%eof{ return; +%eof} + +CRLF=\R +WHITE_SPACE=[\ \n\t\f] +FIRST_VALUE_CHARACTER=[^ \n\f\\] | "\\"{CRLF} | "\\". +VALUE_CHARACTER=[^\n\f\\] | "\\"{CRLF} | "\\". +END_OF_LINE_COMMENT=("#"|"!")[^\r\n]* +SEPARATOR=[:=] +KEY_CHARACTER=[^:=\ \n\t\f\\] | "\\ " + +%state WAITING_VALUE + +%% + + {END_OF_LINE_COMMENT} { yybegin(YYINITIAL); return SimpleTypes.COMMENT; } + + {KEY_CHARACTER}+ { yybegin(YYINITIAL); return SimpleTypes.KEY; } + + {SEPARATOR} { yybegin(WAITING_VALUE); return SimpleTypes.SEPARATOR; } + + {CRLF}({CRLF}|{WHITE_SPACE})+ { yybegin(YYINITIAL); return TokenType.WHITE_SPACE; } + + {WHITE_SPACE}+ { yybegin(WAITING_VALUE); return TokenType.WHITE_SPACE; } + + {FIRST_VALUE_CHARACTER}{VALUE_CHARACTER}* { yybegin(YYINITIAL); return SimpleTypes.VALUE; } + +({CRLF}|{WHITE_SPACE})+ { yybegin(YYINITIAL); return TokenType.WHITE_SPACE; } + +[^] { return TokenType.BAD_CHARACTER; } diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleAnnotator.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleAnnotator.java new file mode 100644 index 000000000..2ab72f2b4 --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleAnnotator.java @@ -0,0 +1,59 @@ +package com.intellij.sdk.language; + +import com.intellij.lang.annotation.*; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.*; +import com.intellij.sdk.language.psi.SimpleProperty; +import org.jetbrains.annotations.NotNull; +import com.intellij.openapi.editor.DefaultLanguageHighlighterColors; + +import java.util.List; + + +public class SimpleAnnotator implements Annotator { + // Define strings for the Simple language prefix - used for annotations, line markers, etc. + public static final String SIMPLE_PREFIX_STR = "simple"; + public static final String SIMPLE_SEPARATOR_STR = ":"; + + @Override + public void annotate(@NotNull final PsiElement element, @NotNull AnnotationHolder holder) { + // Ensure the Psi element is an expression + if ( !( element instanceof PsiLiteralExpression ) ) return; + + // Ensure the Psi element contains a string that starts with the key and separator + PsiLiteralExpression literalExpression = (PsiLiteralExpression) element; + String value = literalExpression.getValue() instanceof String ? (String) literalExpression.getValue() : null; + if ( ( value == null ) || !value.startsWith( SIMPLE_PREFIX_STR + SIMPLE_SEPARATOR_STR ) ) return; + + // Define the text ranges (start is inclusive, end is exclusive) + // "simple:key" + // 01234567890 + TextRange prefixRange = TextRange.from( element.getTextRange().getStartOffset(), SIMPLE_PREFIX_STR.length() + 1 ); + TextRange separatorRange = TextRange.from( prefixRange.getEndOffset(), SIMPLE_SEPARATOR_STR.length() ); + TextRange keyRange = new TextRange( separatorRange.getEndOffset(), element.getTextRange().getEndOffset() - 1 ); + + // Get the list of properties from the Project + String possibleProperties = value.substring( SIMPLE_PREFIX_STR.length() + SIMPLE_SEPARATOR_STR.length() ); + Project project = element.getProject(); + List< SimpleProperty > properties = SimpleUtil.findProperties( project, possibleProperties ); + + // Set the annotations using the text ranges. + Annotation keyAnnotation = holder.createInfoAnnotation( prefixRange, null ); + keyAnnotation.setTextAttributes( DefaultLanguageHighlighterColors.KEYWORD ); + Annotation separatorAnnotation = holder.createInfoAnnotation( separatorRange, null ); + separatorAnnotation.setTextAttributes( SimpleSyntaxHighlighter.SEPARATOR ); + if ( properties.isEmpty() ) { + // No well-formed property found following the key-separator + Annotation badProperty = holder.createErrorAnnotation( keyRange, "Unresolved property" ); + badProperty.setTextAttributes( SimpleSyntaxHighlighter.BAD_CHARACTER ); + // ** Tutorial step 18.3 - Add a quick fix for the string containing possible properties + badProperty.registerFix(new SimpleCreatePropertyQuickFix(possibleProperties)); + } else { + // Found at least one property + Annotation annotation = holder.createInfoAnnotation( keyRange, null ); + annotation.setTextAttributes( SimpleSyntaxHighlighter.VALUE ); + } + } + +} diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleBlock.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleBlock.java new file mode 100644 index 000000000..1e7b05f7f --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleBlock.java @@ -0,0 +1,54 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package com.intellij.sdk.language; + +import com.intellij.formatting.*; +import com.intellij.lang.ASTNode; +import com.intellij.psi.TokenType; +import com.intellij.psi.formatter.common.AbstractBlock; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class SimpleBlock extends AbstractBlock { + private SpacingBuilder spacingBuilder; + + protected SimpleBlock(@NotNull ASTNode node, @Nullable Wrap wrap, @Nullable Alignment alignment, + SpacingBuilder spacingBuilder) { + super(node, wrap, alignment); + this.spacingBuilder = spacingBuilder; + } + + @Override + protected List buildChildren() { + List blocks = new ArrayList(); + ASTNode child = myNode.getFirstChildNode(); + while (child != null) { + if (child.getElementType() != TokenType.WHITE_SPACE) { + Block block = new SimpleBlock(child, Wrap.createWrap(WrapType.NONE, false), Alignment.createAlignment(), + spacingBuilder); + blocks.add(block); + } + child = child.getTreeNext(); + } + return blocks; + } + + @Override + public Indent getIndent() { + return Indent.getNoneIndent(); + } + + @Nullable + @Override + public Spacing getSpacing(@Nullable Block child1, @NotNull Block child2) { + return spacingBuilder.getSpacing(this, child1, child2); + } + + @Override + public boolean isLeaf() { + return myNode.getFirstChildNode() == null; + } +} diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleChooseByNameContributor.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleChooseByNameContributor.java new file mode 100644 index 000000000..e172c0bdd --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleChooseByNameContributor.java @@ -0,0 +1,33 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package com.intellij.sdk.language; + +import com.intellij.navigation.*; +import com.intellij.openapi.project.Project; +import com.intellij.sdk.language.psi.SimpleProperty; +import org.jetbrains.annotations.NotNull; + +import java.util.*; + +public class SimpleChooseByNameContributor implements ChooseByNameContributor { + @NotNull + @Override + public String[] getNames(Project project, boolean includeNonProjectItems) { + List properties = SimpleUtil.findProperties(project); + List names = new ArrayList(properties.size()); + for (SimpleProperty property : properties) { + if (property.getKey() != null && property.getKey().length() > 0) { + names.add(property.getKey()); + } + } + return names.toArray(new String[names.size()]); + } + + @NotNull + @Override + public NavigationItem[] getItemsByName(String name, String pattern, Project project, boolean includeNonProjectItems) { + // TODO: include non project items + List properties = SimpleUtil.findProperties(project, name); + return properties.toArray(new NavigationItem[properties.size()]); + } +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleCodeStyleSettings.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleCodeStyleSettings.java new file mode 100644 index 000000000..35c41c8a8 --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleCodeStyleSettings.java @@ -0,0 +1,11 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package com.intellij.sdk.language; + +import com.intellij.psi.codeStyle.*; + +public class SimpleCodeStyleSettings extends CustomCodeStyleSettings { + public SimpleCodeStyleSettings(CodeStyleSettings settings) { + super("SimpleCodeStyleSettings", settings); + } +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleCodeStyleSettingsProvider.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleCodeStyleSettingsProvider.java new file mode 100644 index 000000000..27823e310 --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleCodeStyleSettingsProvider.java @@ -0,0 +1,37 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package com.intellij.sdk.language; + +import com.intellij.application.options.*; +import com.intellij.psi.codeStyle.*; +import org.jetbrains.annotations.*; + +public class SimpleCodeStyleSettingsProvider extends CodeStyleSettingsProvider { + @Override + public CustomCodeStyleSettings createCustomSettings(CodeStyleSettings settings) { + return new SimpleCodeStyleSettings(settings); + } + + @Nullable + @Override + public String getConfigurableDisplayName() { + return "Simple"; + } + + + @NotNull + public CodeStyleConfigurable createConfigurable(@NotNull CodeStyleSettings settings, @NotNull CodeStyleSettings modelSettings) { + return new CodeStyleAbstractConfigurable(settings, modelSettings, this.getConfigurableDisplayName()) { + @Override + protected CodeStyleAbstractPanel createPanel(CodeStyleSettings settings) { + return new SimpleCodeStyleMainPanel(getCurrentSettings(), settings); + } + }; + } + + private static class SimpleCodeStyleMainPanel extends TabbedLanguageCodeStylePanel { + public SimpleCodeStyleMainPanel(CodeStyleSettings currentSettings, CodeStyleSettings settings) { + super(SimpleLanguage.INSTANCE, currentSettings, settings); + } + } +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleColorSettingsPage.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleColorSettingsPage.java new file mode 100644 index 000000000..a0ee3f616 --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleColorSettingsPage.java @@ -0,0 +1,73 @@ +package com.intellij.sdk.language; + +import com.intellij.openapi.editor.colors.TextAttributesKey; +import com.intellij.openapi.fileTypes.SyntaxHighlighter; +import com.intellij.openapi.options.colors.*; +import org.jetbrains.annotations.*; + +import javax.swing.*; +import java.util.Map; + +import static com.intellij.sdk.language.SimpleLanguage.*; + +public class SimpleColorSettingsPage implements ColorSettingsPage { + private static final AttributesDescriptor[] DESCRIPTORS = new AttributesDescriptor[]{ + new AttributesDescriptor("Key", SimpleSyntaxHighlighter.KEY), + new AttributesDescriptor("Separator", SimpleSyntaxHighlighter.SEPARATOR), + new AttributesDescriptor("Value", SimpleSyntaxHighlighter.VALUE), + new AttributesDescriptor("Bad Value", SimpleSyntaxHighlighter.BAD_CHARACTER) + }; + + @Nullable + @Override + public Icon getIcon() { + return SimpleIcons.FILE; + } + + @NotNull + @Override + public SyntaxHighlighter getHighlighter() { + return new SimpleSyntaxHighlighter(); + } + + @NotNull + @Override + public String getDemoText() { + return "# You are reading the \".properties\" entry.\n" + + "! The exclamation mark can also mark text as comments.\n" + + "website = http://en.wikipedia.org/\n" + + "language = English\n" + + "# The backslash below tells the application to continue reading\n" + + "# the value onto the next line.\n" + + "message = Welcome to \\\n" + + " Wikipedia!\n" + + "# Add spaces to the key\n" + + "key\\ with\\ spaces = This is the value that could be looked up with the key \"key with spaces\".\n" + + "# Unicode\n" + + "tab : \\u0009"; + } + + @Nullable + @Override + public Map getAdditionalHighlightingTagToDescriptorMap() { + return null; + } + + @NotNull + @Override + public AttributesDescriptor[] getAttributeDescriptors() { + return DESCRIPTORS; + } + + @NotNull + @Override + public ColorDescriptor[] getColorDescriptors() { + return ColorDescriptor.EMPTY_ARRAY; + } + + @NotNull + @Override + public String getDisplayName() { + return "Simple"; + } +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleCommenter.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleCommenter.java new file mode 100644 index 000000000..a8c5be9de --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleCommenter.java @@ -0,0 +1,38 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package com.intellij.sdk.language; + +import com.intellij.lang.Commenter; +import org.jetbrains.annotations.Nullable; + +public class SimpleCommenter implements Commenter { + @Nullable + @Override + public String getLineCommentPrefix() { + return "#"; + } + + @Nullable + @Override + public String getBlockCommentPrefix() { + return ""; + } + + @Nullable + @Override + public String getBlockCommentSuffix() { + return null; + } + + @Nullable + @Override + public String getCommentedBlockCommentPrefix() { + return null; + } + + @Nullable + @Override + public String getCommentedBlockCommentSuffix() { + return null; + } +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleCompletionContributor.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleCompletionContributor.java new file mode 100644 index 000000000..ec29657ef --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleCompletionContributor.java @@ -0,0 +1,28 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package com.intellij.sdk.language; + +import com.intellij.codeInsight.completion.*; +import com.intellij.codeInsight.lookup.LookupElementBuilder; +import com.intellij.patterns.PlatformPatterns; +import com.intellij.util.ProcessingContext; +import com.intellij.sdk.language.psi.SimpleTypes; +import org.jetbrains.annotations.NotNull; + +public class SimpleCompletionContributor extends CompletionContributor { + public SimpleCompletionContributor() { + // Register the completion providers + extend( CompletionType.BASIC, + PlatformPatterns.psiElement(SimpleTypes.VALUE).withLanguage(SimpleLanguage.INSTANCE), + new CompletionProvider() { + // Define candidate completions + public void addCompletions(@NotNull CompletionParameters parameters, + ProcessingContext context, + @NotNull CompletionResultSet resultSet) { + // Create a completion independent of context for Simple language + resultSet.addElement(LookupElementBuilder.create("Hello")); + } + } + ); + } +} diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleCreatePropertyQuickFix.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleCreatePropertyQuickFix.java new file mode 100644 index 000000000..bdb3d0f12 --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleCreatePropertyQuickFix.java @@ -0,0 +1,92 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package com.intellij.sdk.language; + +import com.intellij.codeInsight.intention.impl.BaseIntentionAction; +import com.intellij.lang.ASTNode; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.fileChooser.FileChooser; +import com.intellij.openapi.fileChooser.FileChooserDescriptor; +import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.pom.Navigatable; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.intellij.psi.search.FileTypeIndex; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.util.IncorrectOperationException; +import com.intellij.sdk.language.psi.SimpleElementFactory; +import com.intellij.sdk.language.psi.SimpleFile; +import com.intellij.sdk.language.psi.SimpleProperty; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; + +class SimpleCreatePropertyQuickFix extends BaseIntentionAction { + private String key; + + SimpleCreatePropertyQuickFix(String key) { + this.key = key; + } + + @NotNull + @Override + public String getText() { + return "Create property"; + } + + @NotNull + @Override + public String getFamilyName() { + return "Simple properties"; + } + + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + return true; + } + + @Override + public void invoke(@NotNull final Project project, final Editor editor, PsiFile file) throws + IncorrectOperationException { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + Collection virtualFiles = + FileTypeIndex.getFiles(SimpleFileType.INSTANCE, GlobalSearchScope.allScope(project) ); + if (virtualFiles.size() == 1) { + createProperty(project, virtualFiles.iterator().next()); + } else { + final FileChooserDescriptor descriptor = + FileChooserDescriptorFactory.createSingleFileDescriptor(SimpleFileType.INSTANCE); + descriptor.setRoots(ProjectUtil.guessProjectDir(project)); + final VirtualFile file = FileChooser.chooseFile(descriptor, project, null); + if (file != null) { + createProperty(project, file); + } + } + } + }); + } + + private void createProperty(final Project project, final VirtualFile file) { + WriteCommandAction.writeCommandAction(project).run(() -> { + SimpleFile simpleFile = (SimpleFile) PsiManager.getInstance(project).findFile(file); + ASTNode lastChildNode = simpleFile.getNode().getLastChildNode(); + // TODO: Add another check for CRLF + if (lastChildNode != null/* && !lastChildNode.getElementType().equals(SimpleTypes.CRLF)*/) { + simpleFile.getNode().addChild(SimpleElementFactory.createCRLF(project).getNode()); + } + // IMPORTANT: change spaces to escaped spaces or the new node will only have the first word for the key + SimpleProperty property = SimpleElementFactory.createProperty(project, key.replaceAll(" ", "\\\\ "), ""); + simpleFile.getNode().addChild(property.getNode()); + ((Navigatable) property.getLastChild().getNavigationElement()).navigate(true); + FileEditorManager.getInstance(project).getSelectedTextEditor().getCaretModel().moveCaretRelatively(2, 0, false, false, false); + }); + } +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleFileType.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleFileType.java new file mode 100644 index 000000000..f1564fe64 --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleFileType.java @@ -0,0 +1,39 @@ +package com.intellij.sdk.language; + +import com.intellij.openapi.fileTypes.LanguageFileType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +public class SimpleFileType extends LanguageFileType { + public static final SimpleFileType INSTANCE = new SimpleFileType(); + + private SimpleFileType() { + super(SimpleLanguage.INSTANCE); + } + + @NotNull + @Override + public String getName() { + return "Simple file"; + } + + @NotNull + @Override + public String getDescription() { + return "Simple language file"; + } + + @NotNull + @Override + public String getDefaultExtension() { + return "simple"; + } + + @Nullable + @Override + public Icon getIcon() { + return SimpleIcons.FILE; + } +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleFileTypeFactory.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleFileTypeFactory.java new file mode 100644 index 000000000..6d823c42c --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleFileTypeFactory.java @@ -0,0 +1,16 @@ +package com.intellij.sdk.language; + +import com.intellij.openapi.fileTypes.FileTypeConsumer; +import com.intellij.openapi.fileTypes.FileTypeFactory; +import org.jetbrains.annotations.NotNull; + +/** + * Note: This class is only used with the fileTypeFactory extension point + * for versions of the IntelliJ Platform prior to v2019.2 + */ +public class SimpleFileTypeFactory extends FileTypeFactory { + @Override + public void createFileTypes(@NotNull FileTypeConsumer fileTypeConsumer) { + fileTypeConsumer.consume(SimpleFileType.INSTANCE); + } +} diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleFindUsagesProvider.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleFindUsagesProvider.java new file mode 100644 index 000000000..aa308a388 --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleFindUsagesProvider.java @@ -0,0 +1,63 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package com.intellij.sdk.language; + +import com.intellij.lang.cacheBuilder.*; +import com.intellij.lang.findUsages.FindUsagesProvider; +import com.intellij.psi.*; +import com.intellij.psi.tree.TokenSet; +import com.intellij.sdk.language.psi.*; +import org.jetbrains.annotations.*; +import static com.intellij.sdk.language.SimpleAnnotator.*; + +public class SimpleFindUsagesProvider implements FindUsagesProvider { + @Nullable + @Override + public WordsScanner getWordsScanner() { + return new DefaultWordsScanner(new SimpleLexerAdapter(), + TokenSet.create(SimpleTypes.KEY), + TokenSet.create(SimpleTypes.COMMENT), + TokenSet.EMPTY); + } + + @Override + public boolean canFindUsagesFor(@NotNull PsiElement psiElement) { + return psiElement instanceof PsiNamedElement; + } + + @Nullable + @Override + public String getHelpId(@NotNull PsiElement psiElement) { + return null; + } + + @NotNull + @Override + public String getType(@NotNull PsiElement element) { + if (element instanceof SimpleProperty) { + return "simple property"; + } else { + return ""; + } + } + + @NotNull + @Override + public String getDescriptiveName(@NotNull PsiElement element) { + if (element instanceof SimpleProperty) { + return ((SimpleProperty) element).getKey(); + } else { + return ""; + } + } + + @NotNull + @Override + public String getNodeText(@NotNull PsiElement element, boolean useFullName) { + if (element instanceof SimpleProperty) { + return ((SimpleProperty) element).getKey() + SIMPLE_SEPARATOR_STR + ((SimpleProperty) element).getValue(); + } else { + return ""; + } + } +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleFoldingBuilder.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleFoldingBuilder.java new file mode 100644 index 000000000..457f835bd --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleFoldingBuilder.java @@ -0,0 +1,78 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package com.intellij.sdk.language; + +import com.intellij.lang.ASTNode; +import com.intellij.lang.folding.*; +import com.intellij.openapi.editor.*; +import com.intellij.openapi.project.*; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.sdk.language.psi.SimpleProperty; +import org.jetbrains.annotations.*; + +import static com.intellij.sdk.language.SimpleAnnotator.*; + +import java.util.*; + +public class SimpleFoldingBuilder extends FoldingBuilderEx implements DumbAware { + @NotNull + @Override + public FoldingDescriptor[] buildFoldRegions(@NotNull PsiElement root, @NotNull Document document, boolean quick) { + // Initialize the group of folding regions that will expand/collapse together. + FoldingGroup group = FoldingGroup.newGroup(SIMPLE_PREFIX_STR); + // Initialize the list of folding regions + List< FoldingDescriptor > descriptors = new ArrayList< FoldingDescriptor >(); + // Get a collection of the literal expressions in the document below root + Collection< PsiLiteralExpression > literalExpressions = + PsiTreeUtil.findChildrenOfType(root, PsiLiteralExpression.class); + // Evaluate the collection, using only Simple language literalExpressions + for ( final PsiLiteralExpression literalExpression : literalExpressions ) { + String value = literalExpression.getValue() instanceof String ? (String) literalExpression.getValue() : null; + if ( value != null && value.startsWith(SIMPLE_PREFIX_STR + SIMPLE_SEPARATOR_STR) ) { + Project project = literalExpression.getProject(); + String key = value.substring(SIMPLE_PREFIX_STR.length() + SIMPLE_SEPARATOR_STR.length()); + // Get a list of properties for the project + final List< SimpleProperty > properties = SimpleUtil.findProperties(project, key); + if ( properties.size() == 1 ) { + // Add a folding descriptor for the literal expression at this node. + descriptors.add(new FoldingDescriptor(literalExpression.getNode(), + new TextRange(literalExpression.getTextRange().getStartOffset() + 1, + literalExpression.getTextRange().getEndOffset() - 1), + group) ); + } + } + } + return descriptors.toArray(new FoldingDescriptor[descriptors.size()]); + } + + /** + * Gets the Simple Language 'value' string corresponding to the 'key' + * @param node Node corresponding to PsiLiteralExpression containing a string in the format + * SIMPLE_PREFIX_STR + SIMPLE_SEPARATOR_STR + Key, where Key is + * defined by the Simple language file. + * @return String corresponding to the "website" key. + */ + @Nullable + @Override + public String getPlaceholderText(@NotNull ASTNode node) { + String retTxt = "..."; + if ( node.getPsi() instanceof PsiLiteralExpression ) { + PsiLiteralExpression nodeElement = (PsiLiteralExpression) node.getPsi(); + String key = ((String) nodeElement.getValue()).substring(SIMPLE_PREFIX_STR.length() + SIMPLE_SEPARATOR_STR.length()); + final List< SimpleProperty > properties = SimpleUtil.findProperties(nodeElement.getProject(), key); + String place = properties.get(0).getValue(); + // IMPORTANT: keys can come with no values, so a test for null is needed + // IMPORTANT: Convert embedded \n to backslash n, so that the string will look + // like it has LF embedded in it and embedded " to escaped " + return place == null ? retTxt : place.replaceAll("\n", "\\n").replaceAll("\"", "\\\\\""); + } + return retTxt; + } + + @Override + public boolean isCollapsedByDefault(@NotNull ASTNode node) { + return true; + } +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleFormattingModelBuilder.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleFormattingModelBuilder.java new file mode 100644 index 000000000..31e179678 --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleFormattingModelBuilder.java @@ -0,0 +1,39 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package com.intellij.sdk.language; + +import com.intellij.formatting.*; +import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleSettings; +import com.intellij.sdk.language.psi.SimpleTypes; +import org.jetbrains.annotations.*; + +public class SimpleFormattingModelBuilder implements FormattingModelBuilder { + @NotNull + @Override + public FormattingModel createModel(PsiElement element, CodeStyleSettings settings) { + return FormattingModelProvider + .createFormattingModelForPsiFile(element.getContainingFile(), + new SimpleBlock(element.getNode(), + Wrap.createWrap(WrapType.NONE, false), + Alignment.createAlignment(), + createSpaceBuilder(settings)), + settings); + } + + private static SpacingBuilder createSpaceBuilder(CodeStyleSettings settings) { + return new SpacingBuilder(settings, SimpleLanguage.INSTANCE) + .around(SimpleTypes.SEPARATOR) + .spaceIf(settings.getCommonSettings(SimpleLanguage.INSTANCE.getID()).SPACE_AROUND_ASSIGNMENT_OPERATORS) + .before(SimpleTypes.PROPERTY) + .none(); + } + + @Nullable + @Override + public TextRange getRangeAffectingIndent(PsiFile file, int offset, ASTNode elementAtOffset) { + return null; + } +} diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleIcons.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleIcons.java new file mode 100644 index 000000000..f891e06af --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleIcons.java @@ -0,0 +1,9 @@ +package com.intellij.sdk.language; + +import com.intellij.openapi.util.IconLoader; + +import javax.swing.*; + +public class SimpleIcons { + public static final Icon FILE = IconLoader.getIcon("/icons/jar-gray.png"); +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleLanguage.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleLanguage.java new file mode 100644 index 000000000..49e3d2eda --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleLanguage.java @@ -0,0 +1,11 @@ +package com.intellij.sdk.language; + +import com.intellij.lang.Language; + +public class SimpleLanguage extends Language { + public static final SimpleLanguage INSTANCE = new SimpleLanguage(); + + private SimpleLanguage() { + super("Simple"); + } +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleLanguageCodeStyleSettingsProvider.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleLanguageCodeStyleSettingsProvider.java new file mode 100644 index 000000000..974c1e223 --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleLanguageCodeStyleSettingsProvider.java @@ -0,0 +1,42 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package com.intellij.sdk.language; + +import com.intellij.lang.Language; +import com.intellij.psi.codeStyle.*; +import org.jetbrains.annotations.NotNull; + +public class SimpleLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSettingsProvider { + @NotNull + @Override + public Language getLanguage() { + return SimpleLanguage.INSTANCE; + } + + @Override + public void customizeSettings(@NotNull CodeStyleSettingsCustomizable consumer, @NotNull SettingsType settingsType) { + if (settingsType == SettingsType.SPACING_SETTINGS) { + consumer.showStandardOptions("SPACE_AROUND_ASSIGNMENT_OPERATORS"); + consumer.renameStandardOption("SPACE_AROUND_ASSIGNMENT_OPERATORS", "Separator"); + } else if (settingsType == SettingsType.BLANK_LINES_SETTINGS) { + consumer.showStandardOptions("KEEP_BLANK_LINES_IN_CODE"); + } + } + + @Override + public String getCodeSample(@NotNull SettingsType settingsType) { + return "# You are reading the \".properties\" entry.\n" + + "! The exclamation mark can also mark text as comments.\n" + + "website = http://en.wikipedia.org/\n" + + "\n" + + "language = English\n" + + "# The backslash below tells the application to continue reading\n" + + "# the value onto the next line.\n" + + "message = Welcome to \\\n" + + " Wikipedia!\n" + + "# Add spaces to the key\n" + + "key\\ with\\ spaces = This is the value that could be looked up with the key \"key with spaces\".\n" + + "# Unicode\n" + + "tab : \\u0009"; + } +} diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleLexerAdapter.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleLexerAdapter.java new file mode 100644 index 000000000..426ac5226 --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleLexerAdapter.java @@ -0,0 +1,11 @@ +package com.intellij.sdk.language; + +import com.intellij.lexer.FlexAdapter; + +import java.io.Reader; + +public class SimpleLexerAdapter extends FlexAdapter { + public SimpleLexerAdapter() { + super(new SimpleLexer((Reader) null)); + } +} diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleLineMarkerProvider.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleLineMarkerProvider.java new file mode 100644 index 000000000..a70ec514e --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleLineMarkerProvider.java @@ -0,0 +1,40 @@ +package com.intellij.sdk.language; + +import com.intellij.codeInsight.daemon.*; +import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.impl.source.tree.java.PsiJavaTokenImpl; +import com.intellij.sdk.language.psi.SimpleProperty; +import org.jetbrains.annotations.NotNull; +import static com.intellij.sdk.language.SimpleAnnotator.*; + +import java.util.*; + +public class SimpleLineMarkerProvider extends RelatedItemLineMarkerProvider { + @Override + protected void collectNavigationMarkers( @NotNull PsiElement element, + @NotNull Collection< ? super RelatedItemLineMarkerInfo > result ) { + // This must be an element with a literal expression as a parent + if ( !(element instanceof PsiJavaTokenImpl) || !(element.getParent() instanceof PsiLiteralExpression) ) return; + + // The literal expression must start with the Simple language literal expression + PsiLiteralExpression literalExpression = (PsiLiteralExpression) element.getParent(); + String value = literalExpression.getValue() instanceof String ? (String) literalExpression.getValue() : null; + if ( ( value == null ) || !value.startsWith( SIMPLE_PREFIX_STR + SIMPLE_SEPARATOR_STR ) ) return; + + // Get the Simple language property usage + Project project = element.getProject(); + String possibleProperties = value.substring( SIMPLE_PREFIX_STR.length()+SIMPLE_SEPARATOR_STR.length() ); + final List< SimpleProperty > properties = SimpleUtil.findProperties( project, possibleProperties ); + if ( properties.size() > 0 ) { + // Add the property to a collection of line marker info + NavigationGutterIconBuilder< PsiElement > builder = + NavigationGutterIconBuilder.create( SimpleIcons.FILE ) + .setTargets( properties ) + .setTooltipText( "Navigate to Simple language property" ); + result.add( builder.createLineMarkerInfo( element ) ); + } + } + +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleParserDefinition.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleParserDefinition.java new file mode 100644 index 000000000..838c1b9fd --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleParserDefinition.java @@ -0,0 +1,68 @@ +package com.intellij.sdk.language; + +import com.intellij.lang.*; +import com.intellij.lexer.Lexer; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.tree.*; +import com.intellij.sdk.language.parser.SimpleParser; +import com.intellij.sdk.language.psi.*; +import org.jetbrains.annotations.NotNull; + +public class SimpleParserDefinition implements ParserDefinition { + public static final TokenSet WHITE_SPACES = TokenSet.create(TokenType.WHITE_SPACE); + public static final TokenSet COMMENTS = TokenSet.create(SimpleTypes.COMMENT); + + public static final IFileElementType FILE = new IFileElementType(SimpleLanguage.INSTANCE); + + @NotNull + @Override + public Lexer createLexer(Project project) { + return new SimpleLexerAdapter(); + } + + @NotNull + @Override + public TokenSet getWhitespaceTokens() { + return WHITE_SPACES; + } + + @NotNull + @Override + public TokenSet getCommentTokens() { + return COMMENTS; + } + + @NotNull + @Override + public TokenSet getStringLiteralElements() { + return TokenSet.EMPTY; + } + + @NotNull + @Override + public PsiParser createParser(final Project project) { + return new SimpleParser(); + } + + @Override + public IFileElementType getFileNodeType() { + return FILE; + } + + @Override + public PsiFile createFile(FileViewProvider viewProvider) { + return new SimpleFile(viewProvider); + } + + @Override + public SpaceRequirements spaceExistenceTypeBetweenTokens(ASTNode left, ASTNode right) { + return SpaceRequirements.MAY; + } + + @NotNull + @Override + public PsiElement createElement(ASTNode node) { + return SimpleTypes.Factory.createElement(node); + } +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleRefactoringSupportProvider.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleRefactoringSupportProvider.java new file mode 100644 index 000000000..95da8b291 --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleRefactoringSupportProvider.java @@ -0,0 +1,20 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package com.intellij.sdk.language; + +import com.intellij.lang.refactoring.RefactoringSupportProvider; +import com.intellij.psi.PsiElement; +import com.intellij.sdk.language.psi.SimpleProperty; +import org.jetbrains.annotations.*; + +public class SimpleRefactoringSupportProvider extends RefactoringSupportProvider { + @Override + public boolean isMemberInplaceRenameAvailable(@NotNull PsiElement elementToRename, @Nullable PsiElement context) { + return (elementToRename instanceof SimpleProperty); + } +} + +/* +2020-01-10 21:59:36,392 [ 74521] WARN - name.RenamePsiElementProcessor - org.jetbrains.kotlin.idea.refactoring.rename.RenameKotlinTypeParameterProcessor overrides deprecated findReferences(..). +Override findReferences(PsiElement, SearchScope, boolean) instead. +*/ \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleReference.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleReference.java new file mode 100644 index 000000000..859ddbaf0 --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleReference.java @@ -0,0 +1,57 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package com.intellij.sdk.language; + +import com.intellij.codeInsight.lookup.*; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.*; +import com.intellij.sdk.language.psi.SimpleProperty; +import org.jetbrains.annotations.*; + +import java.util.*; + +public class SimpleReference extends PsiReferenceBase implements PsiPolyVariantReference { + private String key; + + public SimpleReference(@NotNull PsiElement element, TextRange textRange) { + super(element, textRange); + key = element.getText().substring(textRange.getStartOffset(), textRange.getEndOffset()); + } + + @NotNull + @Override + public ResolveResult[] multiResolve(boolean incompleteCode) { + Project project = myElement.getProject(); + final List properties = SimpleUtil.findProperties(project, key); + List results = new ArrayList(); + for (SimpleProperty property : properties) { + results.add(new PsiElementResolveResult(property)); + } + return results.toArray(new ResolveResult[results.size()]); + } + + @Nullable + @Override + public PsiElement resolve() { + ResolveResult[] resolveResults = multiResolve(false); + return resolveResults.length == 1 ? resolveResults[0].getElement() : null; + } + + @NotNull + @Override + public Object[] getVariants() { + Project project = myElement.getProject(); + List properties = SimpleUtil.findProperties(project); + List variants = new ArrayList(); + for (final SimpleProperty property : properties) { + if (property.getKey() != null && property.getKey().length() > 0) { + variants.add(LookupElementBuilder + .create(property).withIcon(SimpleIcons.FILE) + .withTypeText(property.getContainingFile().getName()) + ); + } + } + return variants.toArray(); + } +} diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleReferenceContributor.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleReferenceContributor.java new file mode 100644 index 000000000..886111cfa --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleReferenceContributor.java @@ -0,0 +1,34 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package com.intellij.sdk.language; + +import com.intellij.openapi.util.TextRange; +import com.intellij.patterns.PlatformPatterns; +import com.intellij.psi.*; +import com.intellij.util.ProcessingContext; +import org.jetbrains.annotations.NotNull; + +import static com.intellij.sdk.language.SimpleAnnotator.*; + +public class SimpleReferenceContributor extends PsiReferenceContributor { + @Override + public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) { + registrar.registerReferenceProvider( PlatformPatterns.psiElement( PsiLiteralExpression.class ), + new PsiReferenceProvider() { + @NotNull + @Override + public PsiReference[] getReferencesByElement(@NotNull PsiElement element, + @NotNull ProcessingContext context) { + PsiLiteralExpression literalExpression = (PsiLiteralExpression) element; + String value = literalExpression.getValue() instanceof String ? + (String) literalExpression.getValue() : null; + if ( ( value != null && value.startsWith( SIMPLE_PREFIX_STR + SIMPLE_SEPARATOR_STR ) ) ) { + TextRange property = new TextRange( SIMPLE_PREFIX_STR.length() + SIMPLE_SEPARATOR_STR.length() + 1, + value.length() + 1 ); + return new PsiReference[]{ new SimpleReference( element, property ) }; + } + return PsiReference.EMPTY_ARRAY; + } + } ); + } +} diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleStructureViewElement.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleStructureViewElement.java new file mode 100644 index 000000000..8d3629202 --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleStructureViewElement.java @@ -0,0 +1,74 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package com.intellij.sdk.language; + +import com.intellij.ide.projectView.PresentationData; +import com.intellij.ide.structureView.StructureViewTreeElement; +import com.intellij.ide.util.treeView.smartTree.SortableTreeElement; +import com.intellij.ide.util.treeView.smartTree.TreeElement; +import com.intellij.navigation.ItemPresentation; +import com.intellij.psi.NavigatablePsiElement; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.sdk.language.psi.SimpleFile; +import com.intellij.sdk.language.psi.SimpleProperty; +import com.intellij.sdk.language.psi.impl.SimplePropertyImpl; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +public class SimpleStructureViewElement implements StructureViewTreeElement, SortableTreeElement { + private NavigatablePsiElement element; + + public SimpleStructureViewElement(NavigatablePsiElement element) { + this.element = element; + } + + @Override + public Object getValue() { + return element; + } + + @Override + public void navigate(boolean requestFocus) { + element.navigate(requestFocus); + } + + @Override + public boolean canNavigate() { + return element.canNavigate(); + } + + @Override + public boolean canNavigateToSource() { + return element.canNavigateToSource(); + } + + @NotNull + @Override + public String getAlphaSortKey() { + String name = element.getName(); + return name != null ? name : ""; + } + + @NotNull + @Override + public ItemPresentation getPresentation() { + ItemPresentation presentation = element.getPresentation(); + return presentation != null ? presentation : new PresentationData(); + } + + @Override + public TreeElement[] getChildren() { + if (element instanceof SimpleFile) { + SimpleProperty[] properties = PsiTreeUtil.getChildrenOfType(element, SimpleProperty.class); + List treeElements = new ArrayList(properties.length); + for (SimpleProperty property : properties) { + treeElements.add(new SimpleStructureViewElement((SimplePropertyImpl) property)); + } + return treeElements.toArray(new TreeElement[treeElements.size()]); + } else { + return EMPTY_ARRAY; + } + } +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleStructureViewFactory.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleStructureViewFactory.java new file mode 100644 index 000000000..4ef9a11d9 --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleStructureViewFactory.java @@ -0,0 +1,23 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package com.intellij.sdk.language; + +import com.intellij.ide.structureView.*; +import com.intellij.lang.PsiStructureViewFactory; +import com.intellij.openapi.editor.Editor; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.*; + +public class SimpleStructureViewFactory implements PsiStructureViewFactory { + @Nullable + @Override + public StructureViewBuilder getStructureViewBuilder(final PsiFile psiFile) { + return new TreeBasedStructureViewBuilder() { + @NotNull + @Override + public StructureViewModel createStructureViewModel(@Nullable Editor editor) { + return new SimpleStructureViewModel(psiFile); + } + }; + } +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleStructureViewModel.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleStructureViewModel.java new file mode 100644 index 000000000..e7352cf82 --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleStructureViewModel.java @@ -0,0 +1,32 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package com.intellij.sdk.language; + +import com.intellij.ide.structureView.*; +import com.intellij.ide.util.treeView.smartTree.Sorter; +import com.intellij.psi.PsiFile; +import com.intellij.sdk.language.psi.SimpleFile; +import org.jetbrains.annotations.NotNull; + +public class SimpleStructureViewModel extends StructureViewModelBase implements + StructureViewModel.ElementInfoProvider { + public SimpleStructureViewModel(PsiFile psiFile) { + super(psiFile, new SimpleStructureViewElement(psiFile)); + } + + @NotNull + public Sorter[] getSorters() { + return new Sorter[]{Sorter.ALPHA_SORTER}; + } + + + @Override + public boolean isAlwaysShowsPlus(StructureViewTreeElement element) { + return false; + } + + @Override + public boolean isAlwaysLeaf(StructureViewTreeElement element) { + return element instanceof SimpleFile; + } +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleSyntaxHighlighter.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleSyntaxHighlighter.java new file mode 100644 index 000000000..44ea221ab --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleSyntaxHighlighter.java @@ -0,0 +1,57 @@ +package com.intellij.sdk.language; + +import com.intellij.lexer.Lexer; +import com.intellij.openapi.editor.*; +import com.intellij.openapi.editor.colors.TextAttributesKey; +import com.intellij.openapi.fileTypes.SyntaxHighlighterBase; +import com.intellij.psi.TokenType; +import com.intellij.psi.tree.IElementType; +import com.intellij.sdk.language.psi.SimpleTypes; +import org.jetbrains.annotations.NotNull; + +import static com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey; + +public class SimpleSyntaxHighlighter extends SyntaxHighlighterBase { + public static final TextAttributesKey SEPARATOR = + createTextAttributesKey("SIMPLE_SEPARATOR", DefaultLanguageHighlighterColors.OPERATION_SIGN); + public static final TextAttributesKey KEY = + createTextAttributesKey("SIMPLE_KEY", DefaultLanguageHighlighterColors.KEYWORD); + public static final TextAttributesKey VALUE = + createTextAttributesKey("SIMPLE_VALUE", DefaultLanguageHighlighterColors.STRING); + public static final TextAttributesKey COMMENT = + createTextAttributesKey("SIMPLE_COMMENT", DefaultLanguageHighlighterColors.LINE_COMMENT); + public static final TextAttributesKey BAD_CHARACTER = + createTextAttributesKey("SIMPLE_BAD_CHARACTER", HighlighterColors.BAD_CHARACTER); + + + private static final TextAttributesKey[] BAD_CHAR_KEYS = new TextAttributesKey[]{BAD_CHARACTER}; + private static final TextAttributesKey[] SEPARATOR_KEYS = new TextAttributesKey[]{SEPARATOR}; + private static final TextAttributesKey[] KEY_KEYS = new TextAttributesKey[]{KEY}; + private static final TextAttributesKey[] VALUE_KEYS = new TextAttributesKey[]{VALUE}; + private static final TextAttributesKey[] COMMENT_KEYS = new TextAttributesKey[]{COMMENT}; + private static final TextAttributesKey[] EMPTY_KEYS = new TextAttributesKey[0]; + + @NotNull + @Override + public Lexer getHighlightingLexer() { + return new SimpleLexerAdapter(); + } + + @NotNull + @Override + public TextAttributesKey[] getTokenHighlights(IElementType tokenType) { + if (tokenType.equals(SimpleTypes.SEPARATOR)) { + return SEPARATOR_KEYS; + } else if (tokenType.equals(SimpleTypes.KEY)) { + return KEY_KEYS; + } else if (tokenType.equals(SimpleTypes.VALUE)) { + return VALUE_KEYS; + } else if (tokenType.equals(SimpleTypes.COMMENT)) { + return COMMENT_KEYS; + } else if (tokenType.equals(TokenType.BAD_CHARACTER)) { + return BAD_CHAR_KEYS; + } else { + return EMPTY_KEYS; + } + } +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleSyntaxHighlighterFactory.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleSyntaxHighlighterFactory.java new file mode 100644 index 000000000..d8fd3732b --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleSyntaxHighlighterFactory.java @@ -0,0 +1,14 @@ +package com.intellij.sdk.language; + +import com.intellij.openapi.fileTypes.*; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; + +public class SimpleSyntaxHighlighterFactory extends SyntaxHighlighterFactory { + @NotNull + @Override + public SyntaxHighlighter getSyntaxHighlighter(Project project, VirtualFile virtualFile) { + return new SimpleSyntaxHighlighter(); + } +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/SimpleUtil.java b/simple_language/src/main/java/com/intellij/sdk/language/SimpleUtil.java new file mode 100644 index 000000000..3511323d0 --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/SimpleUtil.java @@ -0,0 +1,54 @@ +package com.intellij.sdk.language; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiManager; +import com.intellij.psi.search.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.indexing.FileBasedIndex; +import com.intellij.sdk.language.psi.*; + +import java.util.*; + +public class SimpleUtil { + + // Searches the entire project for Simple language files with instances of the Simple property + public static List findProperties(Project project, String key) { + List result = null; + Collection virtualFiles = + FileTypeIndex.getFiles(SimpleFileType.INSTANCE, GlobalSearchScope.allScope(project)); + for (VirtualFile virtualFile : virtualFiles) { + SimpleFile simpleFile = (SimpleFile) PsiManager.getInstance(project).findFile(virtualFile); + if (simpleFile != null) { + SimpleProperty[] properties = PsiTreeUtil.getChildrenOfType(simpleFile, SimpleProperty.class); + if (properties != null) { + for (SimpleProperty property : properties) { + if (key.equals(property.getKey())) { + if (result == null) { + result = new ArrayList(); + } + result.add(property); + } + } + } + } + } + return result != null ? result : Collections.emptyList(); + } + + public static List findProperties(Project project) { + List result = new ArrayList(); + Collection virtualFiles = + FileTypeIndex.getFiles(SimpleFileType.INSTANCE, GlobalSearchScope.allScope(project)); + for (VirtualFile virtualFile : virtualFiles) { + SimpleFile simpleFile = (SimpleFile) PsiManager.getInstance(project).findFile(virtualFile); + if (simpleFile != null) { + SimpleProperty[] properties = PsiTreeUtil.getChildrenOfType(simpleFile, SimpleProperty.class); + if (properties != null) { + Collections.addAll(result, properties); + } + } + } + return result; + } +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/psi/SimpleElementFactory.java b/simple_language/src/main/java/com/intellij/sdk/language/psi/SimpleElementFactory.java new file mode 100644 index 000000000..5789a7f1e --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/psi/SimpleElementFactory.java @@ -0,0 +1,29 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package com.intellij.sdk.language.psi; + +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.sdk.language.SimpleFileType; + +public class SimpleElementFactory { + public static SimpleProperty createProperty(Project project, String name) { + final SimpleFile file = createFile(project, name); + return (SimpleProperty) file.getFirstChild(); + } + + public static SimpleProperty createProperty(Project project, String name, String value) { + final SimpleFile file = createFile(project, name + " = " + value); + return (SimpleProperty) file.getFirstChild(); + } + + public static PsiElement createCRLF(Project project) { + final SimpleFile file = createFile(project, "\n"); + return file.getFirstChild(); + } + + public static SimpleFile createFile(Project project, String text) { + String name = "dummy.simple"; + return (SimpleFile) PsiFileFactory.getInstance( project).createFileFromText(name, SimpleFileType.INSTANCE, text); + } +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/psi/SimpleElementType.java b/simple_language/src/main/java/com/intellij/sdk/language/psi/SimpleElementType.java new file mode 100644 index 000000000..cbc6b76d8 --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/psi/SimpleElementType.java @@ -0,0 +1,12 @@ +package com.intellij.sdk.language.psi; + +import com.intellij.psi.tree.IElementType; +import com.intellij.sdk.language.SimpleLanguage; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +public class SimpleElementType extends IElementType { + public SimpleElementType( @NotNull @NonNls String debugName) { + super(debugName, SimpleLanguage.INSTANCE); + } +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/psi/SimpleFile.java b/simple_language/src/main/java/com/intellij/sdk/language/psi/SimpleFile.java new file mode 100644 index 000000000..3d012cd5a --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/psi/SimpleFile.java @@ -0,0 +1,31 @@ +package com.intellij.sdk.language.psi; + +import com.intellij.extapi.psi.PsiFileBase; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.psi.FileViewProvider; +import com.intellij.sdk.language.*; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; + +public class SimpleFile extends PsiFileBase { + public SimpleFile(@NotNull FileViewProvider viewProvider) { + super(viewProvider, SimpleLanguage.INSTANCE); + } + + @NotNull + @Override + public FileType getFileType() { + return SimpleFileType.INSTANCE; + } + + @Override + public String toString() { + return "Simple File"; + } + + @Override + public Icon getIcon(int flags) { + return super.getIcon(flags); + } +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/psi/SimpleNamedElement.java b/simple_language/src/main/java/com/intellij/sdk/language/psi/SimpleNamedElement.java new file mode 100644 index 000000000..0cb18830a --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/psi/SimpleNamedElement.java @@ -0,0 +1,8 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package com.intellij.sdk.language.psi; + +import com.intellij.psi.PsiNameIdentifierOwner; + +public interface SimpleNamedElement extends PsiNameIdentifierOwner { +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/psi/SimpleTokenType.java b/simple_language/src/main/java/com/intellij/sdk/language/psi/SimpleTokenType.java new file mode 100644 index 000000000..3300afdc0 --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/psi/SimpleTokenType.java @@ -0,0 +1,16 @@ +package com.intellij.sdk.language.psi; + +import com.intellij.psi.tree.IElementType; +import com.intellij.sdk.language.SimpleLanguage; +import org.jetbrains.annotations.*; + +public class SimpleTokenType extends IElementType { + public SimpleTokenType(@NotNull @NonNls String debugName) { + super(debugName, SimpleLanguage.INSTANCE); + } + + @Override + public String toString() { + return "SimpleTokenType." + super.toString(); + } +} diff --git a/simple_language/src/main/java/com/intellij/sdk/language/psi/impl/SimpleNamedElementImpl.java b/simple_language/src/main/java/com/intellij/sdk/language/psi/impl/SimpleNamedElementImpl.java new file mode 100644 index 000000000..367dd8f99 --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/psi/impl/SimpleNamedElementImpl.java @@ -0,0 +1,14 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package com.intellij.sdk.language.psi.impl; + +import com.intellij.extapi.psi.ASTWrapperPsiElement; +import com.intellij.lang.ASTNode; +import com.intellij.sdk.language.psi.SimpleNamedElement; +import org.jetbrains.annotations.NotNull; + +public abstract class SimpleNamedElementImpl extends ASTWrapperPsiElement implements SimpleNamedElement { + public SimpleNamedElementImpl(@NotNull ASTNode node) { + super(node); + } +} \ No newline at end of file diff --git a/simple_language/src/main/java/com/intellij/sdk/language/psi/impl/SimplePsiImplUtil.java b/simple_language/src/main/java/com/intellij/sdk/language/psi/impl/SimplePsiImplUtil.java new file mode 100644 index 000000000..25ccc748c --- /dev/null +++ b/simple_language/src/main/java/com/intellij/sdk/language/psi/impl/SimplePsiImplUtil.java @@ -0,0 +1,79 @@ +package com.intellij.sdk.language.psi.impl; + +import com.intellij.lang.ASTNode; +import com.intellij.navigation.ItemPresentation; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.sdk.language.SimpleIcons; +import com.intellij.sdk.language.psi.*; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +public class SimplePsiImplUtil { + public static String getKey(SimpleProperty element) { + ASTNode keyNode = element.getNode().findChildByType(SimpleTypes.KEY); + if (keyNode != null) { + // IMPORTANT: Convert embedded escaped spaces to simple spaces + return keyNode.getText().replaceAll("\\\\ ", " "); + } else { + return null; + } + } + + public static String getValue(SimpleProperty element) { + ASTNode valueNode = element.getNode().findChildByType(SimpleTypes.VALUE); + if (valueNode != null) { + return valueNode.getText(); + } else { + return null; + } + } + + public static String getName(SimpleProperty element) { + return getKey(element); + } + + public static PsiElement setName(SimpleProperty element, String newName) { + ASTNode keyNode = element.getNode().findChildByType(SimpleTypes.KEY); + if (keyNode != null) { + SimpleProperty property = SimpleElementFactory.createProperty(element.getProject(), newName); + ASTNode newKeyNode = property.getFirstChild().getNode(); + element.getNode().replaceChild(keyNode, newKeyNode); + } + return element; + } + + public static PsiElement getNameIdentifier( SimpleProperty element) { + ASTNode keyNode = element.getNode().findChildByType(SimpleTypes.KEY); + if (keyNode != null) { + return keyNode.getPsi(); + } else { + return null; + } + } + + public static ItemPresentation getPresentation( final SimpleProperty element) { + return new ItemPresentation() { + @Nullable + @Override + public String getPresentableText() { + return element.getKey(); + } + + @Nullable + @Override + public String getLocationString() { + PsiFile containingFile = element.getContainingFile(); + return containingFile == null ? null : containingFile.getName(); + } + + @Nullable + @Override + public Icon getIcon( boolean unused) { + return SimpleIcons.FILE; + } + }; + } + +} \ No newline at end of file diff --git a/simple_language/src/main/resources/META-INF/plugin.xml b/simple_language/src/main/resources/META-INF/plugin.xml new file mode 100644 index 000000000..d822c4b6f --- /dev/null +++ b/simple_language/src/main/resources/META-INF/plugin.xml @@ -0,0 +1,66 @@ + + + + + + com.intellij.sdk.simple_language + + + SDK: Simple Language Sample Project + + + 2.0.0 + + + + + + com.intellij.modules.platform + com.intellij.modules.java + + + + Defines a new language, Simple language with support for syntax highlighting, annotations, code completion, and other features. +
See the Custom Language Tutorial for more information. + ]]> +
+ + +
  • 2.0.0 Convert to Gradle-based plugin.
  • +
  • 1.0.0 Release 2018.3 and earlier.
  • + + ]]> +
    + + + IntelliJ Platform SDK + + + + + + + + + + + + + + + + + + + + + + +
    \ No newline at end of file diff --git a/simple_language/src/main/resources/META-INF/pluginIcon.svg b/simple_language/src/main/resources/META-INF/pluginIcon.svg new file mode 100644 index 000000000..613290897 --- /dev/null +++ b/simple_language/src/main/resources/META-INF/pluginIcon.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/simple_language/src/main/resources/icons/jar-gray.png b/simple_language/src/main/resources/icons/jar-gray.png new file mode 100644 index 000000000..2642d51e5 Binary files /dev/null and b/simple_language/src/main/resources/icons/jar-gray.png differ diff --git a/simple_language/src/test/java/com/intellij/sdk/language/SimpleCodeInsightTest.java b/simple_language/src/test/java/com/intellij/sdk/language/SimpleCodeInsightTest.java new file mode 100644 index 000000000..1dc8048b0 --- /dev/null +++ b/simple_language/src/test/java/com/intellij/sdk/language/SimpleCodeInsightTest.java @@ -0,0 +1,83 @@ +package com.intellij.sdk.language; + +import com.intellij.application.options.CodeStyle; +import com.intellij.codeInsight.completion.CompletionType; +import com.intellij.codeInsight.generation.actions.CommentByLineCommentAction; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.psi.PsiElement; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase; +import com.intellij.usageView.UsageInfo; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.sdk.language.psi.SimpleProperty; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +public class SimpleCodeInsightTest extends LightJavaCodeInsightFixtureTestCase { + + /** + * + * @return path to test data file directory relative to working directory in the run configuration for this test. + */ + @Override + protected String getTestDataPath() { + return "src/test/testData"; + } + + public void testCompletion() { + myFixture.configureByFiles("CompleteTestData.java", "DefaultTestData.simple"); + myFixture.complete(CompletionType.BASIC, 1); + List strings = myFixture.getLookupElementStrings(); + assertTrue(strings.containsAll(Arrays.asList("key with spaces", "language", "message", "tab", "website"))); + assertEquals(5, strings.size()); + } + + public void testAnnotator() { + myFixture.configureByFiles("AnnotatorTestData.java", "DefaultTestData.simple"); + myFixture.checkHighlighting(false, false, true, true); + } + + public void testFormatter() { + myFixture.configureByFiles("FormatterTestData.simple"); + CodeStyle.getLanguageSettings(myFixture.getFile()).SPACE_AROUND_ASSIGNMENT_OPERATORS = true; + CodeStyle.getLanguageSettings(myFixture.getFile()).KEEP_BLANK_LINES_IN_CODE = 2; + WriteCommandAction.writeCommandAction(getProject()).run(() -> { + CodeStyleManager.getInstance(getProject()).reformatText(myFixture.getFile(), + ContainerUtil.newArrayList(myFixture.getFile().getTextRange())); + }); + myFixture.checkResultByFile("DefaultTestData.simple"); + } + + public void testRename() { + myFixture.configureByFiles("RenameTestData.java", "RenameTestData.simple"); + myFixture.renameElementAtCaret("websiteUrl"); + myFixture.checkResultByFile("RenameTestData.simple", "RenameTestDataAfter.simple", false); + } + + public void testFolding() { + myFixture.configureByFiles("DefaultTestData.simple"); + myFixture.testFolding(getTestDataPath() + "/FoldingTestData.java"); + } + + public void testFindUsages() { + Collection usageInfos = myFixture.testFindUsages("FindUsagesTestData.simple", "FindUsagesTestData.java"); + assertEquals(1, usageInfos.size()); + } + + public void testCommenter() { + myFixture.configureByText(SimpleFileType.INSTANCE, "website = http://en.wikipedia.org/"); + CommentByLineCommentAction commentAction = new CommentByLineCommentAction(); + commentAction.actionPerformedImpl(getProject(), myFixture.getEditor()); + myFixture.checkResult("#website = http://en.wikipedia.org/"); + commentAction.actionPerformedImpl(getProject(), myFixture.getEditor()); + myFixture.checkResult("website = http://en.wikipedia.org/"); + } + + public void testReference() { + myFixture.configureByFiles("ReferenceTestData.java", "DefaultTestData.simple"); + PsiElement element = myFixture.getFile().findElementAt(myFixture.getCaretOffset()).getParent(); + assertEquals("http://en.wikipedia.org/", ((SimpleProperty) element.getReferences()[0].resolve()).getValue()); + } +} diff --git a/simple_language/src/test/java/com/intellij/sdk/language/SimpleParsingTest.java b/simple_language/src/test/java/com/intellij/sdk/language/SimpleParsingTest.java new file mode 100644 index 000000000..98a3b9d11 --- /dev/null +++ b/simple_language/src/test/java/com/intellij/sdk/language/SimpleParsingTest.java @@ -0,0 +1,32 @@ +package com.intellij.sdk.language; + +import com.intellij.testFramework.ParsingTestCase; + +public class SimpleParsingTest extends ParsingTestCase { + public SimpleParsingTest() { + super("", "simple", new SimpleParserDefinition()); + } + + public void testParsingTestData() { + doTest(true); + } + + /** + * + * @return path to test data file directory relative to root of this module. + */ + @Override + protected String getTestDataPath() { + return "src/test/testData"; + } + + @Override + protected boolean skipSpaces() { + return false; + } + + @Override + protected boolean includeRanges() { + return true; + } +} diff --git a/simple_language/src/test/testData/AnnotatorTestData.java b/simple_language/src/test/testData/AnnotatorTestData.java new file mode 100644 index 000000000..eae0b79de --- /dev/null +++ b/simple_language/src/test/testData/AnnotatorTestData.java @@ -0,0 +1,7 @@ +public class Test { + public static void main(String[] args) { + System.out.println("simple:website"); + System.out.println("simple:key with spaces"); + System.out.println("simple:websit"); + } +} diff --git a/simple_language/src/test/testData/CompleteTestData.java b/simple_language/src/test/testData/CompleteTestData.java new file mode 100644 index 000000000..7c2c666a1 --- /dev/null +++ b/simple_language/src/test/testData/CompleteTestData.java @@ -0,0 +1,5 @@ +public class Test { + public static void main(String[] args) { + System.out.println("simple:"); + } +} diff --git a/simple_language/src/test/testData/DefaultTestData.simple b/simple_language/src/test/testData/DefaultTestData.simple new file mode 100644 index 000000000..ebe624812 --- /dev/null +++ b/simple_language/src/test/testData/DefaultTestData.simple @@ -0,0 +1,14 @@ +# You are reading the ".properties" entry. +! The exclamation mark can also mark text as comments. +website = http://en.wikipedia.org/ + + +language = English +# The backslash below tells the application to continue reading +# the value onto the next line. +message = Welcome to \ + Wikipedia! +# Add spaces to the key +key\ with\ spaces = This is the value that could be looked up with the key "key with spaces". +# Unicode +tab : \u0009 diff --git a/simple_language/src/test/testData/FindUsagesTestData.java b/simple_language/src/test/testData/FindUsagesTestData.java new file mode 100644 index 000000000..727681239 --- /dev/null +++ b/simple_language/src/test/testData/FindUsagesTestData.java @@ -0,0 +1,5 @@ +public class Test { + public static void main(String[] args) { + System.out.println("simple:key with spaces"); + } +} diff --git a/simple_language/src/test/testData/FindUsagesTestData.simple b/simple_language/src/test/testData/FindUsagesTestData.simple new file mode 100644 index 000000000..2f31ab9e2 --- /dev/null +++ b/simple_language/src/test/testData/FindUsagesTestData.simple @@ -0,0 +1,13 @@ +# You are reading the ".properties" entry. +! The exclamation mark can also mark text as comments. +website = http://en.wikipedia.org/ + +language = English +# The backslash below tells the application to continue reading +# the value onto the next line. +message = Welcome to \ + Wikipedia! +# Add spaces to the key +key\ with\ spaces = This is the value that could be looked up with the key "key with spaces". +# Unicode +tab : \u0009 diff --git a/simple_language/src/test/testData/FoldingTestData.java b/simple_language/src/test/testData/FoldingTestData.java new file mode 100644 index 000000000..1920b5fae --- /dev/null +++ b/simple_language/src/test/testData/FoldingTestData.java @@ -0,0 +1,11 @@ +public class Test { + public static void main(String[] args) { + System.out.println("simple:website"); + } + public static void main1(String[] args) { + System.out.println("simple:key with spaces"); + } + public static void main2(String[] args) { + System.out.println("simple:message"); + } +} diff --git a/simple_language/src/test/testData/FormatterTestData.simple b/simple_language/src/test/testData/FormatterTestData.simple new file mode 100644 index 000000000..44a78fa68 --- /dev/null +++ b/simple_language/src/test/testData/FormatterTestData.simple @@ -0,0 +1,15 @@ +# You are reading the ".properties" entry. +! The exclamation mark can also mark text as comments. +website=http://en.wikipedia.org/ + + + +language= English +# The backslash below tells the application to continue reading +# the value onto the next line. +message = Welcome to \ + Wikipedia! +# Add spaces to the key +key\ with\ spaces = This is the value that could be looked up with the key "key with spaces". +# Unicode +tab :\u0009 diff --git a/simple_language/src/test/testData/ParsingTestData.simple b/simple_language/src/test/testData/ParsingTestData.simple new file mode 100644 index 000000000..e11fdcef3 --- /dev/null +++ b/simple_language/src/test/testData/ParsingTestData.simple @@ -0,0 +1,17 @@ +# You are reading the ".properties" entry. +! The exclamation mark can also mark text as comments. +website = http://en.wikipedia.org/ + +language = English +# The backslash below tells the application to continue reading +# the value onto the next line. +message = Welcome to \ + Wikipedia! +# Add spaces to the key +key\ with\ spaces = This is the value that could be looked up with the key "key with spaces". +# Unicode +tab : \u0009 +# test for illegal key attempt +key\ +with\ +endofline = test diff --git a/simple_language/src/test/testData/ParsingTestData.txt b/simple_language/src/test/testData/ParsingTestData.txt new file mode 100644 index 000000000..012fa0291 --- /dev/null +++ b/simple_language/src/test/testData/ParsingTestData.txt @@ -0,0 +1,66 @@ +Simple File(0,492) + PsiComment(SimpleTokenType.COMMENT)('# You are reading the ".properties" entry.')(0,42) + PsiWhiteSpace('\n')(42,43) + PsiComment(SimpleTokenType.COMMENT)('! The exclamation mark can also mark text as comments.')(43,97) + PsiWhiteSpace('\n')(97,98) + SimplePropertyImpl(PROPERTY)(98,132) + PsiElement(SimpleTokenType.KEY)('website')(98,105) + PsiWhiteSpace(' ')(105,106) + PsiElement(SimpleTokenType.SEPARATOR)('=')(106,107) + PsiWhiteSpace(' ')(107,108) + PsiElement(SimpleTokenType.VALUE)('http://en.wikipedia.org/')(108,132) + PsiWhiteSpace('\n\n')(132,134) + SimplePropertyImpl(PROPERTY)(134,152) + PsiElement(SimpleTokenType.KEY)('language')(134,142) + PsiWhiteSpace(' ')(142,143) + PsiElement(SimpleTokenType.SEPARATOR)('=')(143,144) + PsiWhiteSpace(' ')(144,145) + PsiElement(SimpleTokenType.VALUE)('English')(145,152) + PsiWhiteSpace('\n')(152,153) + PsiComment(SimpleTokenType.COMMENT)('# The backslash below tells the application to continue reading')(153,216) + PsiWhiteSpace('\n')(216,217) + PsiComment(SimpleTokenType.COMMENT)('# the value onto the next line.')(217,248) + PsiWhiteSpace('\n')(248,249) + SimplePropertyImpl(PROPERTY)(249,292) + PsiElement(SimpleTokenType.KEY)('message')(249,256) + PsiWhiteSpace(' ')(256,257) + PsiElement(SimpleTokenType.SEPARATOR)('=')(257,258) + PsiWhiteSpace(' ')(258,259) + PsiElement(SimpleTokenType.VALUE)('Welcome to \\n Wikipedia!')(259,292) + PsiWhiteSpace('\n')(292,293) + PsiComment(SimpleTokenType.COMMENT)('# Add spaces to the key')(293,316) + PsiWhiteSpace('\n')(316,317) + SimplePropertyImpl(PROPERTY)(317,410) + PsiElement(SimpleTokenType.KEY)('key\ with\ spaces')(317,334) + PsiWhiteSpace(' ')(334,335) + PsiElement(SimpleTokenType.SEPARATOR)('=')(335,336) + PsiWhiteSpace(' ')(336,337) + PsiElement(SimpleTokenType.VALUE)('This is the value that could be looked up with the key "key with spaces".')(337,410) + PsiWhiteSpace('\n')(410,411) + PsiComment(SimpleTokenType.COMMENT)('# Unicode')(411,420) + PsiWhiteSpace('\n')(420,421) + SimplePropertyImpl(PROPERTY)(421,433) + PsiElement(SimpleTokenType.KEY)('tab')(421,424) + PsiWhiteSpace(' ')(424,425) + PsiElement(SimpleTokenType.SEPARATOR)(':')(425,426) + PsiWhiteSpace(' ')(426,427) + PsiElement(SimpleTokenType.VALUE)('\u0009')(427,433) + PsiWhiteSpace('\n')(433,434) + PsiComment(SimpleTokenType.COMMENT)('# test for illegal key attempt')(434,464) + PsiWhiteSpace('\n')(464,465) + SimplePropertyImpl(PROPERTY)(465,469) + PsiElement(SimpleTokenType.KEY)('key')(465,468) + PsiErrorElement:SimpleTokenType.SEPARATOR expected, got '\'(468,469) + PsiElement(BAD_CHARACTER)('\')(468,469) + PsiWhiteSpace('\n')(469,470) + SimplePropertyImpl(PROPERTY)(470,475) + PsiElement(SimpleTokenType.KEY)('with')(470,474) + PsiErrorElement:SimpleTokenType.SEPARATOR expected, got '\'(474,475) + PsiElement(BAD_CHARACTER)('\')(474,475) + PsiWhiteSpace('\n')(475,476) + SimplePropertyImpl(PROPERTY)(476,492) + PsiElement(SimpleTokenType.KEY)('endofline')(476,485) + PsiWhiteSpace(' ')(485,486) + PsiElement(SimpleTokenType.SEPARATOR)('=')(486,487) + PsiWhiteSpace(' ')(487,488) + PsiElement(SimpleTokenType.VALUE)('test')(488,492) \ No newline at end of file diff --git a/simple_language/src/test/testData/ReferenceTestData.java b/simple_language/src/test/testData/ReferenceTestData.java new file mode 100644 index 000000000..92c55dfd5 --- /dev/null +++ b/simple_language/src/test/testData/ReferenceTestData.java @@ -0,0 +1,5 @@ +public class Test { + public static void main(String[] args) { + System.out.println("simple:website"); + } +} diff --git a/simple_language/src/test/testData/RenameTestData.java b/simple_language/src/test/testData/RenameTestData.java new file mode 100644 index 000000000..92c55dfd5 --- /dev/null +++ b/simple_language/src/test/testData/RenameTestData.java @@ -0,0 +1,5 @@ +public class Test { + public static void main(String[] args) { + System.out.println("simple:website"); + } +} diff --git a/simple_language/src/test/testData/RenameTestData.simple b/simple_language/src/test/testData/RenameTestData.simple new file mode 100644 index 000000000..31492ca75 --- /dev/null +++ b/simple_language/src/test/testData/RenameTestData.simple @@ -0,0 +1,13 @@ +# You are reading the ".properties" entry. +! The exclamation mark can also mark text as comments. +website = http://en.wikipedia.org/ + +language = English +# The backslash below tells the application to continue reading +# the value onto the next line. +message = Welcome to \ + Wikipedia! +# Add spaces to the key +key\ with\ spaces = This is the value that could be looked up with the key "key with spaces". +# Unicode +tab : \u0009 \ No newline at end of file diff --git a/simple_language/src/test/testData/RenameTestDataAfter.simple b/simple_language/src/test/testData/RenameTestDataAfter.simple new file mode 100644 index 000000000..71bf7bf73 --- /dev/null +++ b/simple_language/src/test/testData/RenameTestDataAfter.simple @@ -0,0 +1,13 @@ +# You are reading the ".properties" entry. +! The exclamation mark can also mark text as comments. +websiteUrl = http://en.wikipedia.org/ + +language = English +# The backslash below tells the application to continue reading +# the value onto the next line. +message = Welcome to \ + Wikipedia! +# Add spaces to the key +key\ with\ spaces = This is the value that could be looked up with the key "key with spaces". +# Unicode +tab : \u0009 \ No newline at end of file diff --git a/simple_language_plugin/src/com/simpleplugin/SimpleFoldingBuilder.java b/simple_language_plugin/src/com/simpleplugin/SimpleFoldingBuilder.java index 70bf45d93..e2ef7cdb6 100644 --- a/simple_language_plugin/src/com/simpleplugin/SimpleFoldingBuilder.java +++ b/simple_language_plugin/src/com/simpleplugin/SimpleFoldingBuilder.java @@ -3,6 +3,7 @@ package com.simpleplugin; import com.intellij.lang.ASTNode; import com.intellij.lang.folding.*; import com.intellij.openapi.editor.*; +import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; @@ -12,7 +13,7 @@ import org.jetbrains.annotations.*; import java.util.*; -public class SimpleFoldingBuilder extends FoldingBuilderEx { +public class SimpleFoldingBuilder extends FoldingBuilderEx implements DumbAware { @NotNull @Override public FoldingDescriptor[] buildFoldRegions(@NotNull PsiElement root, @NotNull Document document, boolean quick) { @@ -52,7 +53,18 @@ public class SimpleFoldingBuilder extends FoldingBuilderEx { @Nullable @Override public String getPlaceholderText(@NotNull ASTNode node) { - return "..."; + String retTxt = "..."; + if ( node.getPsi() instanceof PsiLiteralExpression ) { + PsiLiteralExpression nodeElement = (PsiLiteralExpression) node.getPsi(); + String key = ((String) nodeElement.getValue()).substring("simple:".length()); + final List< SimpleProperty > properties = SimpleUtil.findProperties(nodeElement.getProject(), key); + String place = properties.get(0).getValue(); + // IMPORTANT: keys can come with no values, so a test for null is needed + // IMPORTANT: Convert embedded \n to backslash n, so that the string will look + // like it has LF embedded in it and embedded " to escaped " + return place == null ? retTxt : place.replaceAll("\n", "\\n").replaceAll("\"", "\\\\\""); + } + return retTxt; } @Override diff --git a/simple_language_plugin/src/com/simpleplugin/SimpleParserDefinition.java b/simple_language_plugin/src/com/simpleplugin/SimpleParserDefinition.java index 787b97857..67bd581ea 100644 --- a/simple_language_plugin/src/com/simpleplugin/SimpleParserDefinition.java +++ b/simple_language_plugin/src/com/simpleplugin/SimpleParserDefinition.java @@ -27,19 +27,16 @@ public class SimpleParserDefinition implements ParserDefinition { } @NotNull - @Override public TokenSet getCommentTokens() { return COMMENTS; } @NotNull - @Override public TokenSet getStringLiteralElements() { return TokenSet.EMPTY; } @NotNull - @Override public PsiParser createParser(final Project project) { return new SimpleParser(); } @@ -49,19 +46,16 @@ public class SimpleParserDefinition implements ParserDefinition { return FILE; } - @Override public PsiFile createFile(FileViewProvider viewProvider) { return new SimpleFile(viewProvider); } - @Override public SpaceRequirements spaceExistenceTypeBetweenTokens(ASTNode left, ASTNode right) { return SpaceRequirements.MAY; } @NotNull - @Override public PsiElement createElement(ASTNode node) { return SimpleTypes.Factory.createElement(node); } -} +} \ No newline at end of file diff --git a/simple_language_plugin/testData/AnnotatorTestData.java b/simple_language_plugin/testData/AnnotatorTestData.java index 8bcbf8db3..eae0b79de 100644 --- a/simple_language_plugin/testData/AnnotatorTestData.java +++ b/simple_language_plugin/testData/AnnotatorTestData.java @@ -2,6 +2,6 @@ public class Test { public static void main(String[] args) { System.out.println("simple:website"); System.out.println("simple:key with spaces"); - System.out.println("simple:websit"); + System.out.println("simple:websit"); } } diff --git a/simple_language_plugin/tests/com/simpleplugin/SimpleCodeInsightTest.java b/simple_language_plugin/tests/com/simpleplugin/SimpleCodeInsightTest.java index f8059d075..6ce61b42e 100644 --- a/simple_language_plugin/tests/com/simpleplugin/SimpleCodeInsightTest.java +++ b/simple_language_plugin/tests/com/simpleplugin/SimpleCodeInsightTest.java @@ -6,7 +6,7 @@ import com.intellij.codeInsight.generation.actions.CommentByLineCommentAction; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.psi.PsiElement; import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; +import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase; import com.intellij.usageView.UsageInfo; import com.intellij.util.containers.ContainerUtil; import com.simpleplugin.psi.SimpleProperty; @@ -15,12 +15,13 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; -public class SimpleCodeInsightTest extends LightCodeInsightFixtureTestCase { +public class SimpleCodeInsightTest extends LightJavaCodeInsightFixtureTestCase { @Override protected void setUp() throws Exception { super.setUp(); } + // path to test data file directory relative to working directory in the run configuration for this test. @Override protected String getTestDataPath() { return "testData"; }