diff --git a/plugins/gettext/gettext.iml b/plugins/gettext/gettext.iml
new file mode 100644
index 000000000000..53e9f256bae4
--- /dev/null
+++ b/plugins/gettext/gettext.iml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/gettext/src/META-INF/plugin.xml b/plugins/gettext/src/META-INF/plugin.xml
new file mode 100644
index 000000000000..3f91a8f5968a
--- /dev/null
+++ b/plugins/gettext/src/META-INF/plugin.xml
@@ -0,0 +1,32 @@
+
+ GetText
+ com.jetbrains.gettext
+
+ GNU GetText language support
+
+ 1.0
+
+
+ JetBrains
+ com.intellij.modules.lang
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/gettext/src/com/jetbrains/gettext/GetText.flex b/plugins/gettext/src/com/jetbrains/gettext/GetText.flex
new file mode 100644
index 000000000000..d20b2d432ec2
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/GetText.flex
@@ -0,0 +1,161 @@
+package com.jetbrains.gettext;
+
+import com.intellij.lexer.FlexLexer;
+import com.intellij.psi.tree.IElementType;
+import com.jetbrains.gettext.GetTextTokenTypes;
+import com.jetbrains.gettext.GetTextElementType;
+
+%%
+
+%{
+
+ public _GetTextLexer() {
+ this((java.io.Reader)null);
+ }
+
+%}
+
+%class _GetTextLexer
+%implements FlexLexer
+%unicode
+%function advance
+%type IElementType
+%eof{ return;
+%eof}
+%caseless
+%ignorecase
+
+EOL = (\r|\n|\r\n)
+NO_EOL = !(\r|\n|\r\n)
+SPACE = [ \t\f]
+WHITE_SPACE = {EOL} | {SPACE}
+
+STRING_TAIL = [^\r\n]*
+QUOTED_STRING = ("\"")~(\r|\n|\r\n|"\"")
+TMP_QUOTED_STRING = ("\"")~("\"")
+
+DOUBLEQUOTE = \"
+DOUBLEQUOTED_STRING = ([^\"] | \"\" | \\\")+
+
+LBRACE = "["
+RBRACE = "]"
+NUMBER = [0-9]*
+
+COMMENT_SYMBOL = "#"
+
+COMMENT_TYPE_SYMBOLS = ("#."|"#:"|"#,"|"#|")
+COMMENT = (" "|\t|\f)~{EOL}
+EXTRACTED_COMMENT = (".")~{EOL}
+REFERENCE_COMMENT = (":")~{EOL}
+PREVIOUS_COMMENT = ("|")~{EOL}
+FLAG_GROUP = (",")
+
+DOT = "."
+COLON = ":"
+LINE = "|"
+COMMA = ","
+
+MSGCTXT = "msgctxt"
+MSGID = "msgid"
+MSGID_PLURAL = "msgid_plural"
+MSGSTR = "msgstr"
+
+
+FUZZY_FLAG = "fuzzy"
+NO = "no-"
+FORMAT = "-format"
+C = "c"
+OBJC = "objc"
+SH = "sh"
+PYTHON = "python"
+LISP = "lisp"
+ELISP = "elisp"
+LIBREP = "librep"
+SCHEME = "scheme"
+SMALLTALK = "smalltalk"
+JAVA = "java"
+CSHARP = "csharp"
+AWK = "awk"
+YCP = "ycp"
+TCL = "tcl"
+PERL = "perl-brace"
+PHP = "php"
+GCC = "gcc-internal"
+GFC = "gfc-internal"
+QT = "qt"
+KDE = "kde"
+BOOST = "boost"
+OBJECT_PASCAL = "object-pascal"
+QT_PLURAL = "qt-plural"
+
+PASCAL_FORMAT_FLAG = "object-pascal-format"
+NO_PASCAL_FORMAT_FLAG = "no-object-pascal-format"
+QT_FORMAT_FLAG = "qt-plural-format"
+NO_QT_FORMAT_FLAG = "no-qt-plural-format"
+FORMAT_FLAG = (C|OBJC|SH|PYTHON|LISP|EISP|LIBREP|SCHEME|SMALLTALK|JAVA|SCHARP|AWK|OBJECT_PASCAL|YCP|TCL|PERL|PHP|GCC|GFC|QT|QT_PLURAL|KDE|BOOST) {FORMAT}
+NO_FORMAT_FLAG = {NO} {FORMAT_FLAG}
+
+RANGE_FLAG = "range"
+DOTS = ".."
+
+FLAG_DELIVERY=","
+
+%state START_COMMENT
+%state COMMENT
+%state EXTR_COMMENT
+%state REFERENCE_COMMENT
+%state PREVIOUS_COMMENT
+%state FLAG_COMMENT
+%state FLAG_DEL
+
+%ignorecase
+
+%%
+
+ {COMMENT_SYMBOL} { yybegin(START_COMMENT); return GetTextTokenTypes.COMMENT_SYMBOLS;}
+ {SPACE} { yybegin(COMMENT); return GetTextTokenTypes.COMMENT_SYMBOLS;}
+ {DOT} { yybegin(EXTR_COMMENT); return GetTextTokenTypes.COMMENT_SYMBOLS;}
+ {COLON} { yybegin(REFERENCE_COMMENT); return GetTextTokenTypes.COMMENT_SYMBOLS;}
+ {LINE} { yybegin(PREVIOUS_COMMENT); return GetTextTokenTypes.COMMENT_SYMBOLS;}
+ {FLAG_GROUP} { yybegin(FLAG_COMMENT); return GetTextTokenTypes.COMMENT_SYMBOLS;}
+
+ {EOL} { yybegin(YYINITIAL); return GetTextTokenTypes.WHITE_SPACE;}
+ {EOL} { yybegin(YYINITIAL); return GetTextTokenTypes.WHITE_SPACE;}
+ {EOL} { yybegin(YYINITIAL); return GetTextTokenTypes.WHITE_SPACE;}
+ {EOL} { yybegin(YYINITIAL); return GetTextTokenTypes.WHITE_SPACE;}
+ {EOL} { yybegin(YYINITIAL); return GetTextTokenTypes.WHITE_SPACE;}
+ {EOL} { yybegin(YYINITIAL); return GetTextTokenTypes.WHITE_SPACE;}
+ {EOL} { yybegin(YYINITIAL); return GetTextTokenTypes.WHITE_SPACE;}
+
+ {STRING_TAIL} { return GetTextTokenTypes.COMMENT;}
+ {STRING_TAIL} { return GetTextTokenTypes.EXTR_COMMENT;}
+ {STRING_TAIL} { return GetTextTokenTypes.REFERENCE;}
+ {STRING_TAIL} { return GetTextTokenTypes.PREVIOUS_COMMENT;}
+
+ {PASCAL_FORMAT_FLAG} { yybegin(FLAG_DEL); return GetTextTokenTypes.FORMAT_FLAG;}
+ {NO_PASCAL_FORMAT_FLAG} { yybegin(FLAG_DEL); return GetTextTokenTypes.NO_FORMAT_FLAG;}
+ {QT_FORMAT_FLAG} { yybegin(FLAG_DEL); return GetTextTokenTypes.FORMAT_FLAG;}
+ {NO_QT_FORMAT_FLAG} { yybegin(FLAG_DEL); return GetTextTokenTypes.NO_FORMAT_FLAG;}
+ {FORMAT_FLAG} { yybegin(FLAG_DEL); return GetTextTokenTypes.FORMAT_FLAG;}
+ {NO_FORMAT_FLAG} { yybegin(FLAG_DEL); return GetTextTokenTypes.NO_FORMAT_FLAG;}
+ {FUZZY_FLAG} { yybegin(FLAG_DEL); return GetTextTokenTypes.FUZZY_FLAG;}
+ {RANGE_FLAG} { yybegin(FLAG_DEL); return GetTextTokenTypes.RANGE_FLAG;}
+
+ {FLAG_DELIVERY} { yybegin(FLAG_COMMENT); return GetTextTokenTypes.FLAG_DELIVERY;}
+
+{MSGCTXT} { return GetTextTokenTypes.MSGCTXT;}
+{MSGID} { return GetTextTokenTypes.MSGID;}
+{MSGID_PLURAL} { return GetTextTokenTypes.MSGID_PLURAL;}
+{MSGSTR} { return GetTextTokenTypes.MSGSTR;}
+
+ {WHITE_SPACE} { return GetTextTokenTypes.WHITE_SPACE;}
+ {SPACE} { return GetTextTokenTypes.WHITE_SPACE;}
+{NUMBER} { return GetTextTokenTypes.NUMBER;}
+{LBRACE} { return GetTextTokenTypes.LBRACE;}
+{RBRACE} { return GetTextTokenTypes.RBRACE;}
+{COLON} { return GetTextTokenTypes.COLON;}
+{DOTS} { return GetTextTokenTypes.DOTS;}
+
+{QUOTED_STRING} { return GetTextTokenTypes.STRING;}
+
+[^] { return GetTextTokenTypes.BAD_CHARACTER; }
\ No newline at end of file
diff --git a/plugins/gettext/src/com/jetbrains/gettext/GetTextCompositeElement.java b/plugins/gettext/src/com/jetbrains/gettext/GetTextCompositeElement.java
new file mode 100644
index 000000000000..657daac4fbed
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/GetTextCompositeElement.java
@@ -0,0 +1,30 @@
+package com.jetbrains.gettext;
+
+import com.intellij.extapi.psi.ASTWrapperPsiElement;
+import com.intellij.lang.ASTNode;
+import com.intellij.lang.Language;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class GetTextCompositeElement extends ASTWrapperPsiElement {
+ public GetTextCompositeElement(@NotNull ASTNode node) {
+ super(node);
+ }
+
+ @NotNull
+ public Language getLanguage() {
+ return GetTextLanguage.INSTANCE;
+ }
+
+ @NotNull
+ @SuppressWarnings({ "ConstantConditions", "EmptyMethod" })
+ public ASTNode getNode() {
+ return super.getNode();
+ }
+
+ public String toString() {
+ return getNode().getElementType().toString();
+ }
+}
\ No newline at end of file
diff --git a/plugins/gettext/src/com/jetbrains/gettext/GetTextCompositeElementType.java b/plugins/gettext/src/com/jetbrains/gettext/GetTextCompositeElementType.java
new file mode 100644
index 000000000000..210089011018
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/GetTextCompositeElementType.java
@@ -0,0 +1,27 @@
+package com.jetbrains.gettext;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.impl.source.tree.CompositeElement;
+import com.intellij.psi.tree.ICompositeElementType;
+import com.intellij.psi.tree.IElementType;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class GetTextCompositeElementType extends IElementType implements ICompositeElementType {
+ public GetTextCompositeElementType(@NotNull @NonNls final String debugName) {
+ super(debugName, GetTextLanguage.INSTANCE);
+ }
+
+ public static PsiElement createPsiElement(ASTNode node) {
+ return new GetTextCompositeElement(node);
+ }
+
+ @NotNull
+ public ASTNode createCompositeNode() {
+ return new CompositeElement(this);
+ }
+}
\ No newline at end of file
diff --git a/plugins/gettext/src/com/jetbrains/gettext/GetTextCompositeElementTypes.java b/plugins/gettext/src/com/jetbrains/gettext/GetTextCompositeElementTypes.java
new file mode 100644
index 000000000000..b92bf379c32b
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/GetTextCompositeElementTypes.java
@@ -0,0 +1,17 @@
+package com.jetbrains.gettext;
+
+import com.intellij.psi.tree.IElementType;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public interface GetTextCompositeElementTypes {
+ IElementType HEADER = new GetTextCompositeElementType("HEADER");
+
+ IElementType MSG_BLOCK = new GetTextCompositeElementType("MSG_BLOCK");
+ IElementType MSG_CONTENT = new GetTextCompositeElementType("MSG_CONTENT");
+ IElementType MSGID = new GetTextCompositeElementType("MSGID");
+ IElementType MSGSTR = new GetTextCompositeElementType("MSGSTR");
+ IElementType MSGCTXT = new GetTextCompositeElementType("MSGCTXT");
+ IElementType MSGID_PLURAL = new GetTextCompositeElementType("MSGID_PLURAL");
+}
diff --git a/plugins/gettext/src/com/jetbrains/gettext/GetTextElementType.java b/plugins/gettext/src/com/jetbrains/gettext/GetTextElementType.java
new file mode 100644
index 000000000000..8e14a67254a6
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/GetTextElementType.java
@@ -0,0 +1,14 @@
+package com.jetbrains.gettext;
+
+import com.intellij.psi.tree.IElementType;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class GetTextElementType extends IElementType {
+ public GetTextElementType(@NotNull @NonNls String debugName) {
+ super(debugName, GetTextLanguage.INSTANCE);
+ }
+}
diff --git a/plugins/gettext/src/com/jetbrains/gettext/GetTextFile.java b/plugins/gettext/src/com/jetbrains/gettext/GetTextFile.java
new file mode 100644
index 000000000000..b1bfc500f2fa
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/GetTextFile.java
@@ -0,0 +1,26 @@
+package com.jetbrains.gettext;
+
+import com.intellij.extapi.psi.PsiFileBase;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.psi.FileViewProvider;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class GetTextFile extends PsiFileBase {
+ public GetTextFile (FileViewProvider viewProvider) {
+ super(viewProvider, GetTextLanguage.INSTANCE);
+ }
+
+ @NotNull
+ public FileType getFileType() {
+ return GetTextFileType.INSTANCE;
+ }
+
+ @Override
+ public String toString() {
+ return "GNU GetText File";
+ }
+}
+
diff --git a/plugins/gettext/src/com/jetbrains/gettext/GetTextFileType.java b/plugins/gettext/src/com/jetbrains/gettext/GetTextFileType.java
new file mode 100644
index 000000000000..dae16e73914e
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/GetTextFileType.java
@@ -0,0 +1,39 @@
+package com.jetbrains.gettext;
+
+import com.intellij.openapi.fileTypes.LanguageFileType;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class GetTextFileType extends LanguageFileType {
+ public static final GetTextFileType INSTANCE = new GetTextFileType();
+
+ private GetTextFileType() {
+ super(GetTextLanguage.INSTANCE);
+ }
+
+ @NotNull
+ public String getName() {
+ return "GetText";
+ }
+
+ @NotNull
+ public String getDescription() {
+ return "GNU GetText";
+ }
+
+ @NotNull
+ public String getDefaultExtension() {
+ return "po";
+ }
+
+ @Override
+ public Icon getIcon() {
+ return GetTextIcons.FILETYPE_ICON;
+ }
+}
+
+
diff --git a/plugins/gettext/src/com/jetbrains/gettext/GetTextFileTypeFactory.java b/plugins/gettext/src/com/jetbrains/gettext/GetTextFileTypeFactory.java
new file mode 100644
index 000000000000..f39b76ecdf2b
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/GetTextFileTypeFactory.java
@@ -0,0 +1,14 @@
+package com.jetbrains.gettext;
+
+import com.intellij.openapi.fileTypes.FileTypeConsumer;
+import com.intellij.openapi.fileTypes.FileTypeFactory;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class GetTextFileTypeFactory extends FileTypeFactory {
+ public void createFileTypes(@NotNull FileTypeConsumer consumer) {
+ consumer.consume(GetTextFileType.INSTANCE, GetTextFileType.INSTANCE.getDefaultExtension());
+ }
+}
diff --git a/plugins/gettext/src/com/jetbrains/gettext/GetTextFileViewProvider.java b/plugins/gettext/src/com/jetbrains/gettext/GetTextFileViewProvider.java
new file mode 100644
index 000000000000..2b806f7e9875
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/GetTextFileViewProvider.java
@@ -0,0 +1,21 @@
+package com.jetbrains.gettext;
+
+import com.intellij.lang.Language;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiManager;
+import com.intellij.psi.SingleRootFileViewProvider;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class GetTextFileViewProvider extends SingleRootFileViewProvider {
+
+ protected GetTextFileViewProvider(@NotNull PsiManager manager, @NotNull VirtualFile virtualFile, final boolean physical, @NotNull Language language) {
+ super(manager, virtualFile, physical, language);
+ }
+
+ public boolean supportsIncrementalReparse(@NotNull final Language rootLanguage) {
+ return false;
+ }
+}
diff --git a/plugins/gettext/src/com/jetbrains/gettext/GetTextFileViewProviderFactory.java b/plugins/gettext/src/com/jetbrains/gettext/GetTextFileViewProviderFactory.java
new file mode 100644
index 000000000000..07d5914c3166
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/GetTextFileViewProviderFactory.java
@@ -0,0 +1,18 @@
+package com.jetbrains.gettext;
+
+import com.intellij.lang.Language;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.FileViewProvider;
+import com.intellij.psi.FileViewProviderFactory;
+import com.intellij.psi.PsiManager;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class GetTextFileViewProviderFactory implements FileViewProviderFactory {
+
+ public FileViewProvider createFileViewProvider(@NotNull VirtualFile file, Language language, @NotNull PsiManager manager, boolean physical) {
+ return new GetTextFileViewProvider(manager, file, physical, language);
+ }
+}
diff --git a/plugins/gettext/src/com/jetbrains/gettext/GetTextIcons.java b/plugins/gettext/src/com/jetbrains/gettext/GetTextIcons.java
new file mode 100644
index 000000000000..6aa2a3da3660
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/GetTextIcons.java
@@ -0,0 +1,13 @@
+package com.jetbrains.gettext;
+
+import com.intellij.icons.AllIcons;
+
+import javax.swing.*;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class GetTextIcons {
+ //public static Icon FILETYPE_ICON = IconLoader.getIcon("FileIcon.png", GetTextIcons.class);
+ public static Icon FILETYPE_ICON = AllIcons.FileTypes.Text;
+}
diff --git a/plugins/gettext/src/com/jetbrains/gettext/GetTextLanguage.java b/plugins/gettext/src/com/jetbrains/gettext/GetTextLanguage.java
new file mode 100644
index 000000000000..acbf437d373a
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/GetTextLanguage.java
@@ -0,0 +1,15 @@
+package com.jetbrains.gettext;
+
+
+import com.intellij.lang.Language;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class GetTextLanguage extends Language {
+ public static GetTextLanguage INSTANCE = new GetTextLanguage();
+
+ private GetTextLanguage() {
+ super("GetText");
+ }
+}
\ No newline at end of file
diff --git a/plugins/gettext/src/com/jetbrains/gettext/GetTextLexer.java b/plugins/gettext/src/com/jetbrains/gettext/GetTextLexer.java
new file mode 100644
index 000000000000..d99e96f4311a
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/GetTextLexer.java
@@ -0,0 +1,14 @@
+package com.jetbrains.gettext;
+
+import com.intellij.lexer.FlexAdapter;
+
+import java.io.Reader;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class GetTextLexer extends FlexAdapter {
+ public GetTextLexer() {
+ super(new _GetTextLexer((Reader)null));
+ }
+}
\ No newline at end of file
diff --git a/plugins/gettext/src/com/jetbrains/gettext/GetTextTokenTypes.java b/plugins/gettext/src/com/jetbrains/gettext/GetTextTokenTypes.java
new file mode 100644
index 000000000000..fb32c5570c45
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/GetTextTokenTypes.java
@@ -0,0 +1,49 @@
+package com.jetbrains.gettext;
+
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.tree.TokenSet;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public interface GetTextTokenTypes {
+
+ IElementType COMMENT_SYMBOLS = new GetTextElementType("COMMENT_SYMBOLS");
+
+ IElementType BAD_CHARACTER = new GetTextElementType("BAD_CHARACTER");
+ IElementType WHITE_SPACE = new GetTextElementType("WHITE_SPACE");
+
+ IElementType COMMENT = new GetTextElementType("COMMENT"); //#
+ IElementType EXTR_COMMENT = new GetTextElementType("EXTR_COMMENT"); //#.
+ IElementType REFERENCE = new GetTextElementType("REFERENCE"); //#:
+ IElementType FLAG_COMMENT = new GetTextElementType("FLAG_COMMENT"); //#,
+ IElementType PREVIOUS_COMMENT = new GetTextElementType("PREVIOUS_TRANSLATE_COMMENT"); //#|
+
+ IElementType RANGE_FLAG = new GetTextElementType("RANGE_FLAG");
+ IElementType FUZZY_FLAG = new GetTextElementType("FUZZY_FLAG");
+ IElementType FORMAT_FLAG = new GetTextElementType("FORMAT_FLAG");
+ IElementType NO_FORMAT_FLAG = new GetTextElementType("NO_FORMAT_FLAG");
+ IElementType FLAG_DELIVERY = new GetTextElementType("DELIVERY");
+
+ IElementType MSG = new GetTextElementType("MSG_START");
+
+ IElementType MSGCTXT = new GetTextElementType("MSGCTXT");
+ IElementType MSGID = new GetTextElementType("MSGID");
+ IElementType MSGID_PLURAL = new GetTextElementType("MSGID_PLURAL");
+ IElementType MSGSTR = new GetTextElementType("MSGSTR");
+
+ IElementType COLON = new GetTextElementType("COLON");
+ IElementType DOTS = new GetTextElementType("DOTS");
+ IElementType NUMBER = new GetTextElementType("NUMBER");
+ IElementType LBRACE = new GetTextElementType("LBRACE");
+ IElementType RBRACE = new GetTextElementType("RBRACE");
+
+ IElementType STRING = new GetTextElementType("STRING");
+
+ TokenSet SYSTEM_COMMENTS = TokenSet.create(EXTR_COMMENT, REFERENCE, FLAG_COMMENT, PREVIOUS_COMMENT, FLAG_DELIVERY, COMMENT_SYMBOLS);
+ TokenSet COMMENTS = TokenSet.orSet(TokenSet.create(COMMENT), SYSTEM_COMMENTS);
+ TokenSet STRING_LITERALS = TokenSet.create(STRING);
+ TokenSet KEYWORDS = TokenSet.create(MSG, MSGCTXT, MSGID, MSGID_PLURAL, MSGSTR);
+ TokenSet FLAGS = TokenSet.create(FUZZY_FLAG, FORMAT_FLAG, NO_FORMAT_FLAG, RANGE_FLAG);
+ TokenSet BRACES = TokenSet.create(LBRACE, RBRACE);
+}
diff --git a/plugins/gettext/src/com/jetbrains/gettext/_GetTextLexer.java b/plugins/gettext/src/com/jetbrains/gettext/_GetTextLexer.java
new file mode 100644
index 000000000000..9b20ffd1d9cf
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/_GetTextLexer.java
@@ -0,0 +1,703 @@
+/* The following code was generated by JFlex 1.4.3 on 7/10/12 5:05 PM */
+
+package com.jetbrains.gettext;
+
+import com.intellij.lexer.FlexLexer;
+import com.intellij.psi.tree.IElementType;
+
+
+/**
+ * This class is a scanner generated by
+ * JFlex 1.4.3
+ * on 7/10/12 5:05 PM from the specification file
+ * /home/svetlana/git/idea/IDEA/tools/lexer/../../community/plugins/gettext/src/com/jetbrains/gettext/GetText.flex
+ */
+class _GetTextLexer implements FlexLexer {
+ /** initial size of the lookahead buffer */
+ private static final int ZZ_BUFFERSIZE = 16384;
+
+ /** lexical states */
+ public static final int FLAG_DEL = 14;
+ public static final int YYINITIAL = 0;
+ public static final int REFERENCE_COMMENT = 8;
+ public static final int COMMENT = 4;
+ public static final int FLAG_COMMENT = 12;
+ public static final int PREVIOUS_COMMENT = 10;
+ public static final int EXTR_COMMENT = 6;
+ public static final int START_COMMENT = 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, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7
+ };
+
+ /**
+ * Translates characters to character classes
+ */
+ private static final String ZZ_CMAP_PACKED =
+ "\11\0\1\3\1\2\1\0\1\3\1\1\22\0\1\3\1\0\1\4"+
+ "\1\10\10\0\1\13\1\40\1\11\1\0\12\7\1\12\6\0\1\32"+
+ "\1\41\1\20\1\24\1\44\1\33\1\17\1\43\1\23\1\42\1\45"+
+ "\1\27\1\15\1\36\1\37\1\26\1\50\1\31\1\16\1\21\1\30"+
+ "\1\46\1\47\1\22\1\35\1\34\1\5\1\0\1\6\1\0\1\25"+
+ "\1\0\1\32\1\41\1\20\1\24\1\44\1\33\1\17\1\43\1\23"+
+ "\1\42\1\45\1\27\1\15\1\36\1\37\1\26\1\50\1\31\1\16"+
+ "\1\21\1\30\1\46\1\47\1\22\1\35\1\34\1\0\1\14\uff83\0";
+
+ /**
+ * Translates characters to character classes
+ */
+ private static final char [] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED);
+
+ /**
+ * Translates DFA states to action switch labels.
+ */
+ private static final int [] ZZ_ACTION = zzUnpackAction();
+
+ private static final String ZZ_ACTION_PACKED_0 =
+ "\2\1\1\2\1\3\1\4\1\5\2\1\1\6\2\7"+
+ "\1\6\1\10\1\11\1\1\1\12\1\6\1\13\1\6"+
+ "\2\14\1\15\1\16\1\17\1\20\1\21\2\2\2\3"+
+ "\2\4\2\5\21\6\1\22\1\0\2\23\1\24\101\0"+
+ "\1\25\3\0\1\26\1\27\22\0\1\30\20\0\1\31"+
+ "\17\0\1\32\23\0\1\33\1\0\1\34\2\0";
+
+ private static int [] zzUnpackAction() {
+ int [] result = new int[203];
+ 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\51\0\122\0\173\0\244\0\315\0\366\0\u011f"+
+ "\0\u0148\0\u0171\0\u0148\0\u019a\0\u0148\0\u0148\0\u01c3\0\u0148"+
+ "\0\u01ec\0\u0148\0\u0215\0\u023e\0\u0148\0\u0148\0\u01ec\0\u0148"+
+ "\0\u0148\0\u0148\0\u0267\0\u0290\0\u02b9\0\u02e2\0\u030b\0\u0334"+
+ "\0\u035d\0\u0386\0\u03af\0\u03d8\0\u0401\0\u042a\0\u0453\0\u047c"+
+ "\0\u04a5\0\u04ce\0\u04f7\0\u0520\0\u0549\0\u0572\0\u059b\0\u05c4"+
+ "\0\u05ed\0\u0616\0\u063f\0\u0148\0\u019a\0\u0668\0\u0148\0\u0148"+
+ "\0\u0691\0\u06ba\0\u06e3\0\u0401\0\u070c\0\u0735\0\u075e\0\u0787"+
+ "\0\u07b0\0\u07d9\0\u0802\0\u082b\0\u0854\0\u087d\0\u08a6\0\u08cf"+
+ "\0\u08f8\0\u0921\0\u094a\0\u0973\0\u099c\0\u09c5\0\u09ee\0\u0a17"+
+ "\0\u0a40\0\u0a69\0\u0a92\0\u0abb\0\u0ae4\0\u0b0d\0\u0b36\0\u0b5f"+
+ "\0\u0b88\0\u0bb1\0\u0bda\0\u0c03\0\u0c2c\0\u0c55\0\u0c7e\0\u0ca7"+
+ "\0\u0cd0\0\u0cf9\0\u0d22\0\u0d4b\0\u0d74\0\u0d9d\0\u0dc6\0\u0def"+
+ "\0\u0e18\0\u0e41\0\u0e6a\0\u0e93\0\u0ebc\0\u0ee5\0\u0f0e\0\u0f37"+
+ "\0\u0f60\0\u0f89\0\u0fb2\0\u0fdb\0\u1004\0\u102d\0\u1056\0\u107f"+
+ "\0\u10a8\0\u10d1\0\u10fa\0\u1123\0\u114c\0\u0148\0\u0148\0\u1175"+
+ "\0\u119e\0\u11c7\0\u11f0\0\u1219\0\u1242\0\u126b\0\u1294\0\u12bd"+
+ "\0\u12e6\0\u130f\0\u1338\0\u1361\0\u138a\0\u13b3\0\u13dc\0\u1405"+
+ "\0\u142e\0\u0148\0\u1457\0\u1480\0\u14a9\0\u14d2\0\u14fb\0\u1524"+
+ "\0\u154d\0\u1576\0\u159f\0\u15c8\0\u15f1\0\u161a\0\u1643\0\u166c"+
+ "\0\u1695\0\u16be\0\u0148\0\u16e7\0\u1710\0\u1739\0\u1762\0\u178b"+
+ "\0\u17b4\0\u17dd\0\u1806\0\u182f\0\u1858\0\u1881\0\u18aa\0\u18d3"+
+ "\0\u18fc\0\u1925\0\u0148\0\u194e\0\u1977\0\u19a0\0\u19c9\0\u19f2"+
+ "\0\u1a1b\0\u1a44\0\u1a6d\0\u1a96\0\u1abf\0\u1ae8\0\u1b11\0\u1b3a"+
+ "\0\u1b63\0\u1b8c\0\u1bb5\0\u1bde\0\u1c07\0\u1c30\0\u0148\0\u1c59"+
+ "\0\u0148\0\u1c82\0\u1cab";
+
+ private static int [] zzUnpackRowMap() {
+ int [] result = new int[203];
+ 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\11\1\12\2\13\1\14\1\15\1\16\1\17\1\20"+
+ "\1\21\1\22\2\11\1\23\34\11\1\24\1\25\1\26"+
+ "\1\14\1\15\1\16\1\17\1\11\1\27\1\30\1\31"+
+ "\1\32\1\23\33\11\1\33\1\24\1\25\1\33\1\34"+
+ "\44\33\1\35\1\24\1\25\1\35\1\36\44\35\1\37"+
+ "\1\24\1\25\1\37\1\40\44\37\1\41\1\24\1\25"+
+ "\1\41\1\42\44\41\1\11\1\24\1\25\1\13\1\14"+
+ "\1\15\1\16\1\17\1\11\1\21\1\22\2\11\1\23"+
+ "\1\43\1\44\1\45\1\46\4\11\1\47\1\50\1\11"+
+ "\1\51\1\52\1\53\1\11\1\54\1\55\1\56\1\11"+
+ "\1\57\1\60\1\11\1\61\1\62\2\11\1\63\1\11"+
+ "\1\24\1\25\1\13\1\14\1\15\1\16\1\17\1\11"+
+ "\1\21\1\22\1\64\1\11\1\23\33\11\53\0\1\13"+
+ "\46\0\1\65\1\66\1\67\1\65\1\67\44\65\7\0"+
+ "\1\17\52\0\1\70\55\0\1\71\34\0\1\25\46\0"+
+ "\1\33\2\0\46\33\1\34\1\66\1\67\1\34\1\33"+
+ "\44\34\1\35\2\0\46\35\1\36\1\66\1\67\1\36"+
+ "\1\35\44\36\1\37\2\0\46\37\1\40\1\66\1\67"+
+ "\1\40\1\37\44\40\1\41\2\0\46\41\1\42\1\66"+
+ "\1\67\1\42\1\41\44\42\15\0\1\72\2\0\1\73"+
+ "\22\0\1\74\25\0\1\75\12\0\1\75\55\0\1\76"+
+ "\30\0\1\77\65\0\1\100\5\0\1\101\1\102\27\0"+
+ "\1\103\57\0\1\104\65\0\1\105\31\0\1\106\40\0"+
+ "\1\101\67\0\1\107\52\0\1\110\46\0\1\111\43\0"+
+ "\1\112\41\0\1\113\51\0\1\114\45\0\1\115\31\0"+
+ "\1\67\65\0\1\116\63\0\1\117\61\0\1\120\25\0"+
+ "\1\74\63\0\1\121\44\0\1\74\42\0\1\122\55\0"+
+ "\1\74\53\0\1\77\35\0\1\101\22\0\1\123\45\0"+
+ "\1\124\57\0\1\74\37\0\1\125\54\0\1\126\52\0"+
+ "\1\127\45\0\1\130\57\0\1\131\20\0\1\101\76\0"+
+ "\1\74\31\0\1\132\12\0\1\133\26\0\1\134\1\0"+
+ "\1\135\2\0\1\136\54\0\1\137\53\0\1\140\11\0"+
+ "\1\141\43\0\1\142\54\0\1\143\36\0\1\144\36\0"+
+ "\1\145\65\0\1\146\32\0\1\147\1\150\1\151\1\152"+
+ "\4\0\1\153\1\154\2\0\1\155\2\0\1\156\1\0"+
+ "\1\157\1\0\1\160\1\161\1\0\1\162\1\163\2\0"+
+ "\1\164\20\0\1\74\23\0\1\165\22\0\1\166\64\0"+
+ "\1\74\44\0\1\167\50\0\1\167\4\0\1\121\36\0"+
+ "\1\170\50\0\1\171\53\0\1\172\53\0\1\173\52\0"+
+ "\1\101\34\0\1\114\64\0\1\174\56\0\1\175\55\0"+
+ "\1\101\50\0\1\176\41\0\1\177\30\0\1\200\2\0"+
+ "\1\201\22\0\1\151\25\0\1\202\12\0\1\202\55\0"+
+ "\1\203\30\0\1\204\65\0\1\205\5\0\1\206\1\207"+
+ "\27\0\1\210\74\0\1\211\21\0\1\206\71\0\1\212"+
+ "\46\0\1\213\43\0\1\214\41\0\1\215\51\0\1\216"+
+ "\45\0\1\217\47\0\1\220\51\0\1\74\56\0\1\221"+
+ "\52\0\1\222\41\0\1\223\53\0\1\224\44\0\1\225"+
+ "\44\0\1\226\71\0\1\74\44\0\1\227\61\0\1\230"+
+ "\25\0\1\151\63\0\1\231\44\0\1\151\42\0\1\232"+
+ "\55\0\1\151\53\0\1\204\35\0\1\206\22\0\1\233"+
+ "\54\0\1\151\45\0\1\234\45\0\1\235\57\0\1\236"+
+ "\20\0\1\206\76\0\1\151\31\0\1\237\12\0\1\240"+
+ "\31\0\1\241\57\0\1\242\41\0\1\243\55\0\1\244"+
+ "\54\0\1\245\50\0\1\246\45\0\1\247\53\0\1\250"+
+ "\11\0\1\251\43\0\1\252\54\0\1\253\36\0\1\254"+
+ "\37\0\1\151\23\0\1\255\22\0\1\256\64\0\1\151"+
+ "\44\0\1\257\50\0\1\257\4\0\1\231\42\0\1\260"+
+ "\12\0\1\260\41\0\1\261\46\0\1\262\50\0\1\105"+
+ "\42\0\1\263\56\0\1\264\52\0\1\206\34\0\1\216"+
+ "\64\0\1\265\56\0\1\266\55\0\1\206\24\0\1\267"+
+ "\51\0\1\151\56\0\1\270\47\0\1\271\54\0\1\77"+
+ "\46\0\1\272\41\0\1\273\44\0\1\274\71\0\1\151"+
+ "\33\0\1\275\57\0\1\276\52\0\1\277\47\0\1\300"+
+ "\51\0\1\301\50\0\1\302\43\0\1\303\12\0\1\303"+
+ "\41\0\1\304\35\0\1\305\64\0\1\306\45\0\1\211"+
+ "\42\0\1\307\55\0\1\310\54\0\1\204\36\0\1\261"+
+ "\57\0\1\311\53\0\1\312\34\0\1\313\52\0\1\304"+
+ "\30\0";
+
+ private static int [] zzUnpackTrans() {
+ int [] result = new int[7380];
+ int offset = 0;
+ offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result);
+ return result;
+ }
+
+ private static int zzUnpackTrans(String packed, int offset, int [] result) {
+ int i = 0; /* index in packed string */
+ int j = offset; /* index in unpacked array */
+ int l = packed.length();
+ while (i < l) {
+ int count = packed.charAt(i++);
+ int value = packed.charAt(i++);
+ value--;
+ do result[j++] = value; while (--count > 0);
+ }
+ return j;
+ }
+
+
+ /* error codes */
+ private static final int ZZ_UNKNOWN_ERROR = 0;
+ private static final int ZZ_NO_MATCH = 1;
+ private static final int ZZ_PUSHBACK_2BIG = 2;
+ private static final char[] EMPTY_BUFFER = new char[0];
+ private static final int YYEOF = -1;
+ private static java.io.Reader zzReader = null; // Fake
+
+ /* error messages for the codes above */
+ private static final String ZZ_ERROR_MSG[] = {
+ "Unkown internal scanner error",
+ "Error: could not match input",
+ "Error: pushback value was too large"
+ };
+
+ /**
+ * ZZ_ATTRIBUTE[aState] contains the attributes of state aState
+ */
+ private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute();
+
+ private static final String ZZ_ATTRIBUTE_PACKED_0 =
+ "\10\1\1\11\1\1\1\11\1\1\2\11\1\1\1\11"+
+ "\1\1\1\11\2\1\2\11\1\1\3\11\31\1\1\11"+
+ "\1\0\1\1\2\11\101\0\1\1\3\0\2\11\22\0"+
+ "\1\11\20\0\1\11\17\0\1\11\23\0\1\11\1\0"+
+ "\1\11\2\0";
+
+ private static int [] zzUnpackAttribute() {
+ int [] result = new int[203];
+ int offset = 0;
+ offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result);
+ return result;
+ }
+
+ private static int zzUnpackAttribute(String packed, int offset, int [] result) {
+ int i = 0; /* index in packed string */
+ int j = offset; /* index in unpacked array */
+ int l = packed.length();
+ while (i < l) {
+ int count = packed.charAt(i++);
+ int value = packed.charAt(i++);
+ do result[j++] = value; while (--count > 0);
+ }
+ return j;
+ }
+
+ /** the current state of the DFA */
+ private int zzState;
+
+ /** the current lexical state */
+ private int zzLexicalState = YYINITIAL;
+
+ /** this buffer contains the current text to be matched and is
+ the source of the yytext() string */
+ private CharSequence zzBuffer = "";
+
+ /** this buffer may contains the current text array to be matched when it is cheap to acquire it */
+ private char[] zzBufferArray;
+
+ /** the textposition at the last accepting state */
+ private int zzMarkedPos;
+
+ /** the textposition at the last state to be included in yytext */
+ private int zzPushbackPos;
+
+ /** the current text position in the buffer */
+ private int zzCurrentPos;
+
+ /** startRead marks the beginning of the yytext() string in the buffer */
+ private int zzStartRead;
+
+ /** endRead marks the last character in the buffer, that has been read
+ from input */
+ private int zzEndRead;
+
+ /**
+ * zzAtBOL == true <=> the scanner is currently at the beginning of a line
+ */
+ private boolean zzAtBOL = true;
+
+ /** zzAtEOF == true <=> the scanner is at the EOF */
+ private boolean zzAtEOF;
+
+ /** denotes if the user-EOF-code has already been executed */
+ private boolean zzEOFDone;
+
+ /* user code: */
+
+ public _GetTextLexer() {
+ this((java.io.Reader)null);
+ }
+
+
+
+ _GetTextLexer(java.io.Reader in) {
+ this.zzReader = in;
+ }
+
+ /**
+ * Creates a new scanner.
+ * There is also java.io.Reader version of this constructor.
+ *
+ * @param in the java.io.Inputstream to read input from.
+ */
+ _GetTextLexer(java.io.InputStream in) {
+ this(new java.io.InputStreamReader(in));
+ }
+
+ /**
+ * Unpacks the compressed character translation table.
+ *
+ * @param packed the packed character translation table
+ * @return the unpacked character translation table
+ */
+ private static char [] zzUnpackCMap(String packed) {
+ char [] map = new char[0x10000];
+ int i = 0; /* index in packed string */
+ int j = 0; /* index in unpacked array */
+ while (i < 160) {
+ int count = packed.charAt(i++);
+ char value = packed.charAt(i++);
+ do map[j++] = value; while (--count > 0);
+ }
+ return map;
+ }
+
+ public final int getTokenStart(){
+ return zzStartRead;
+ }
+
+ public final int getTokenEnd(){
+ return getTokenStart() + yylength();
+ }
+
+ public void reset(CharSequence buffer, int start, int end,int initialState){
+ zzBuffer = buffer;
+ zzBufferArray = com.intellij.util.text.CharArrayUtil.fromSequenceWithoutCopying(buffer);
+ zzCurrentPos = zzMarkedPos = zzStartRead = start;
+ zzPushbackPos = 0;
+ zzAtEOF = false;
+ zzAtBOL = true;
+ zzEndRead = end;
+ yybegin(initialState);
+ }
+
+ /**
+ * Refills the input buffer.
+ *
+ * @return 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 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 zzBufferArray != null ? zzBufferArray[zzStartRead+pos]:zzBuffer.charAt(zzStartRead+pos);
+ }
+
+
+ /**
+ * Returns the length of the matched text region.
+ */
+ public final int yylength() {
+ return zzMarkedPos-zzStartRead;
+ }
+
+
+ /**
+ * Reports an error that occured while scanning.
+ *
+ * In a wellformed scanner (no or only correct usage of
+ * yypushback(int) and a match-all fallback rule) this method
+ * will only be called with things that "Can't Possibly Happen".
+ * If this method is called, something is seriously wrong
+ * (e.g. a JFlex bug producing a faulty scanner etc.).
+ *
+ * Usual syntax/scanner level error handling should be done
+ * in error fallback rules.
+ *
+ * @param errorCode the code of the errormessage to display
+ */
+ private void zzScanError(int errorCode) {
+ String message;
+ try {
+ message = ZZ_ERROR_MSG[errorCode];
+ }
+ catch (ArrayIndexOutOfBoundsException e) {
+ message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR];
+ }
+
+ throw new Error(message);
+ }
+
+
+ /**
+ * Pushes the specified amount of characters back into the input stream.
+ *
+ * They will be read again by then next call of the scanning method
+ *
+ * @param number the number of characters to be read again.
+ * This number must not be greater than yylength()!
+ */
+ public void yypushback(int number) {
+ if ( number > yylength() )
+ zzScanError(ZZ_PUSHBACK_2BIG);
+
+ zzMarkedPos -= number;
+ }
+
+
+ /**
+ * 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;
+ char[] zzBufferArrayL = zzBufferArray;
+ char [] zzCMapL = ZZ_CMAP;
+
+ int [] zzTransL = ZZ_TRANS;
+ int [] zzRowMapL = ZZ_ROWMAP;
+ int [] zzAttrL = ZZ_ATTRIBUTE;
+
+ while (true) {
+ zzMarkedPosL = zzMarkedPos;
+
+ zzAction = -1;
+
+ zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL;
+
+ zzState = ZZ_LEXSTATE[zzLexicalState];
+
+
+ zzForAction: {
+ while (true) {
+
+ if (zzCurrentPosL < zzEndReadL)
+ zzInput = zzBufferArrayL != null ? zzBufferArrayL[zzCurrentPosL++]:zzBufferL.charAt(zzCurrentPosL++);
+ else if (zzAtEOF) {
+ zzInput = YYEOF;
+ break zzForAction;
+ }
+ else {
+ // store back cached positions
+ zzCurrentPos = zzCurrentPosL;
+ zzMarkedPos = zzMarkedPosL;
+ boolean eof = zzRefill();
+ // get translated positions and possibly new buffer
+ zzCurrentPosL = zzCurrentPos;
+ zzMarkedPosL = zzMarkedPos;
+ zzBufferL = zzBuffer;
+ zzEndReadL = zzEndRead;
+ if (eof) {
+ zzInput = YYEOF;
+ break zzForAction;
+ }
+ else {
+ zzInput = zzBufferArrayL != null ? zzBufferArrayL[zzCurrentPosL++]:zzBufferL.charAt(zzCurrentPosL++);
+ }
+ }
+ int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMapL[zzInput] ];
+ if (zzNext == -1) break zzForAction;
+ zzState = zzNext;
+
+ int zzAttributes = zzAttrL[zzState];
+ if ( (zzAttributes & 1) == 1 ) {
+ zzAction = zzState;
+ zzMarkedPosL = zzCurrentPosL;
+ if ( (zzAttributes & 8) == 8 ) break zzForAction;
+ }
+
+ }
+ }
+
+ // store back cached position
+ zzMarkedPos = zzMarkedPosL;
+
+ switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) {
+ case 2:
+ { return GetTextTokenTypes.COMMENT;
+ }
+ case 29: break;
+ case 27:
+ { yybegin(FLAG_DEL); return GetTextTokenTypes.NO_FORMAT_FLAG;
+ }
+ case 30: break;
+ case 25:
+ { return GetTextTokenTypes.MSGCTXT;
+ }
+ case 31: break;
+ case 14:
+ { yybegin(EXTR_COMMENT); return GetTextTokenTypes.COMMENT_SYMBOLS;
+ }
+ case 32: break;
+ case 7:
+ { return GetTextTokenTypes.WHITE_SPACE;
+ }
+ case 33: break;
+ case 8:
+ { return GetTextTokenTypes.LBRACE;
+ }
+ case 34: break;
+ case 10:
+ { yybegin(START_COMMENT); return GetTextTokenTypes.COMMENT_SYMBOLS;
+ }
+ case 35: break;
+ case 26:
+ { yybegin(FLAG_DEL); return GetTextTokenTypes.FORMAT_FLAG;
+ }
+ case 36: break;
+ case 6:
+ { return GetTextTokenTypes.BAD_CHARACTER;
+ }
+ case 37: break;
+ case 9:
+ { return GetTextTokenTypes.RBRACE;
+ }
+ case 38: break;
+ case 12:
+ { yybegin(YYINITIAL); return GetTextTokenTypes.WHITE_SPACE;
+ }
+ case 39: break;
+ case 16:
+ { yybegin(FLAG_COMMENT); return GetTextTokenTypes.COMMENT_SYMBOLS;
+ }
+ case 40: break;
+ case 17:
+ { yybegin(PREVIOUS_COMMENT); return GetTextTokenTypes.COMMENT_SYMBOLS;
+ }
+ case 41: break;
+ case 20:
+ { return GetTextTokenTypes.DOTS;
+ }
+ case 42: break;
+ case 4:
+ { return GetTextTokenTypes.REFERENCE;
+ }
+ case 43: break;
+ case 24:
+ { return GetTextTokenTypes.MSGSTR;
+ }
+ case 44: break;
+ case 19:
+ { return GetTextTokenTypes.STRING;
+ }
+ case 45: break;
+ case 15:
+ { yybegin(REFERENCE_COMMENT); return GetTextTokenTypes.COMMENT_SYMBOLS;
+ }
+ case 46: break;
+ case 22:
+ { yybegin(FLAG_DEL); return GetTextTokenTypes.RANGE_FLAG;
+ }
+ case 47: break;
+ case 11:
+ { return GetTextTokenTypes.COLON;
+ }
+ case 48: break;
+ case 1:
+ { return GetTextTokenTypes.NUMBER;
+ }
+ case 49: break;
+ case 18:
+ { yybegin(FLAG_COMMENT); return GetTextTokenTypes.FLAG_DELIVERY;
+ }
+ case 50: break;
+ case 3:
+ { return GetTextTokenTypes.EXTR_COMMENT;
+ }
+ case 51: break;
+ case 21:
+ { return GetTextTokenTypes.MSGID;
+ }
+ case 52: break;
+ case 5:
+ { return GetTextTokenTypes.PREVIOUS_COMMENT;
+ }
+ case 53: break;
+ case 28:
+ { return GetTextTokenTypes.MSGID_PLURAL;
+ }
+ case 54: break;
+ case 23:
+ { yybegin(FLAG_DEL); return GetTextTokenTypes.FUZZY_FLAG;
+ }
+ case 55: break;
+ case 13:
+ { yybegin(COMMENT); return GetTextTokenTypes.COMMENT_SYMBOLS;
+ }
+ case 56: break;
+ default:
+ if (zzInput == YYEOF && zzStartRead == zzCurrentPos) {
+ zzAtEOF = true;
+ zzDoEOF();
+ return null;
+ }
+ else {
+ zzScanError(ZZ_NO_MATCH);
+ }
+ }
+ }
+ }
+
+
+}
diff --git a/plugins/gettext/src/com/jetbrains/gettext/completion/GetTextCompletitionContributor.java b/plugins/gettext/src/com/jetbrains/gettext/completion/GetTextCompletitionContributor.java
new file mode 100644
index 000000000000..de526dcbcb9b
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/completion/GetTextCompletitionContributor.java
@@ -0,0 +1,89 @@
+package com.jetbrains.gettext.completion;
+
+import com.intellij.codeInsight.completion.*;
+import com.intellij.codeInsight.lookup.LookupElementBuilder;
+import com.intellij.psi.PsiElement;
+import com.intellij.util.ProcessingContext;
+import com.jetbrains.gettext.GetTextLanguage;
+import com.jetbrains.gettext.GetTextTokenTypes;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.intellij.patterns.PlatformPatterns.psiElement;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class GetTextCompletitionContributor extends CompletionContributor {
+
+ private final static String[] KEYWORDS = {
+ "msgid",
+ "msgstr",
+ "msgctxt",
+ "msgid_plural",
+ "fuzzy",
+ "c-format"
+ };
+
+ //private final static String[] BUILT_IN_FILTERS = {
+ // "date",
+ // "format",
+ // "replace",
+ // "url_encode",
+ // "json_encode",
+ // "title",
+ // "capitalize",
+ // "upper",
+ // "lower",
+ // "striptags",
+ // "join",
+ // "reverse",
+ // "length",
+ // "sort",
+ // "default",
+ // "keys",
+ // "escape",
+ // "raw",
+ // "merge"
+ //};
+
+ private final static List KEYWORD_LOOKUPS = new ArrayList();
+ //private final static List BUILT_IN_FILTER_LOOKUPS = new ArrayList();
+
+ static {
+ for (String keyword : KEYWORDS) {
+ KEYWORD_LOOKUPS.add(LookupElementBuilder.create(keyword));
+ }
+ //for (String filter : BUILT_IN_FILTERS) {
+ // BUILT_IN_FILTER_LOOKUPS.add(LookupElementBuilder.create(filter));
+ //}
+ }
+
+ public GetTextCompletitionContributor() {
+ extend(CompletionType.BASIC, psiElement().withParent(psiElement().withLanguage(GetTextLanguage.INSTANCE)),
+ new GetTextKeywordCompletionContributor());
+ }
+
+ private static class GetTextKeywordCompletionContributor extends CompletionProvider {
+
+ @Override
+ protected void addCompletions(@NotNull CompletionParameters parameters,
+ ProcessingContext context,
+ @NotNull CompletionResultSet result) {
+ final PsiElement currElement = parameters.getPosition().getOriginalElement();
+ if (currElement.getNode().getElementType() == GetTextTokenTypes.BAD_CHARACTER) {
+ for (LookupElementBuilder builder : KEYWORD_LOOKUPS) result.addElement(builder);
+ result.stopHere();
+ //return;
+ }
+ //PsiElement prevElement = currElement.getPrevSibling();
+ //if (prevElement != null && prevElement instanceof PsiWhiteSpace) prevElement = prevElement.getPrevSibling();
+ //if (prevElement != null && prevElement.getNode().getElementType() == TwigTokenTypes.FILTER) {
+ // for (LookupElementBuilder builder : BUILT_IN_FILTER_LOOKUPS) result.addElement(builder);
+ // result.stopHere();
+ //}
+ }
+ }
+}
diff --git a/plugins/gettext/src/com/jetbrains/gettext/highlighter/GetTextHighlighterData.java b/plugins/gettext/src/com/jetbrains/gettext/highlighter/GetTextHighlighterData.java
new file mode 100644
index 000000000000..1147e110535b
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/highlighter/GetTextHighlighterData.java
@@ -0,0 +1,42 @@
+package com.jetbrains.gettext.highlighter;
+
+import com.intellij.openapi.editor.HighlighterColors;
+import com.intellij.openapi.editor.SyntaxHighlighterColors;
+import com.intellij.openapi.editor.colors.TextAttributesKey;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class GetTextHighlighterData {
+
+ public static final String COMMENT_ID = "GET_TEXT_COMMENT";
+ public static final TextAttributesKey COMMENT =
+ TextAttributesKey.createTextAttributesKey(COMMENT_ID, SyntaxHighlighterColors.LINE_COMMENT.getDefaultAttributes().clone());
+
+ public static final String KEYWORD_ID = "GET_TEXT_KEYWORD";
+ public static final TextAttributesKey KEYWORD =
+ TextAttributesKey.createTextAttributesKey(KEYWORD_ID, SyntaxHighlighterColors.KEYWORD.getDefaultAttributes().clone());
+
+ public static final String STRING_ID = "GET_TEXT_STRING";
+ public static final TextAttributesKey STRING =
+ TextAttributesKey.createTextAttributesKey(STRING_ID, SyntaxHighlighterColors.STRING.getDefaultAttributes().clone());
+
+ public static final String FLAG_ID = "GET_TEXT_FLAG";
+ public static final TextAttributesKey FLAG =
+ TextAttributesKey.createTextAttributesKey(FLAG_ID, SyntaxHighlighterColors.DOC_COMMENT_TAG.getDefaultAttributes().clone());
+
+ public static final String TRANSLATED_NUMBER_ID = "GET_TEXT_TRANSLATED_NUMBER";
+ public static final TextAttributesKey TRANSLATED_NUMBER =
+ TextAttributesKey.createTextAttributesKey(TRANSLATED_NUMBER_ID, SyntaxHighlighterColors.NUMBER.getDefaultAttributes().clone());
+
+ public static final String BRACES_ID = "GET_TEXT_BRACES";
+ public static final TextAttributesKey BRACES =
+ TextAttributesKey.createTextAttributesKey(BRACES_ID, SyntaxHighlighterColors.BRACES.getDefaultAttributes().clone());
+
+ public static final String DOTS_ID = "GET_TEXT_DOTS";
+ public static final TextAttributesKey DOTS =
+ TextAttributesKey.createTextAttributesKey(DOTS_ID, SyntaxHighlighterColors.DOT.getDefaultAttributes().clone());
+
+ public static final TextAttributesKey BAD_CHARACTER =
+ TextAttributesKey.createTextAttributesKey("TS_BAD_CHARACTER", HighlighterColors.BAD_CHARACTER.getDefaultAttributes());
+}
diff --git a/plugins/gettext/src/com/jetbrains/gettext/highlighter/GetTextSyntaxHighlighter.java b/plugins/gettext/src/com/jetbrains/gettext/highlighter/GetTextSyntaxHighlighter.java
new file mode 100644
index 000000000000..7719be7df13b
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/highlighter/GetTextSyntaxHighlighter.java
@@ -0,0 +1,47 @@
+package com.jetbrains.gettext.highlighter;
+
+import com.intellij.lexer.Lexer;
+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.jetbrains.gettext.GetTextLexer;
+import com.jetbrains.gettext.GetTextTokenTypes;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class GetTextSyntaxHighlighter extends SyntaxHighlighterBase {
+ private static final Map keys1;
+
+ public GetTextSyntaxHighlighter() {
+ }
+
+ @NotNull
+ public Lexer getHighlightingLexer() {
+ return new GetTextLexer();
+ }
+
+ static {
+ keys1 = new HashMap();
+
+ fillMap(keys1, GetTextTokenTypes.FLAGS, GetTextHighlighterData.FLAG);
+ fillMap(keys1, GetTextTokenTypes.COMMENTS, GetTextHighlighterData.COMMENT);
+ fillMap(keys1, GetTextTokenTypes.KEYWORDS, GetTextHighlighterData.KEYWORD);
+ fillMap(keys1, GetTextTokenTypes.STRING_LITERALS, GetTextHighlighterData.STRING);
+ fillMap(keys1, GetTextTokenTypes.BRACES, GetTextHighlighterData.BRACES);
+ keys1.put(GetTextTokenTypes.NUMBER, GetTextHighlighterData.TRANSLATED_NUMBER);
+ keys1.put(GetTextTokenTypes.DOTS, GetTextHighlighterData.DOTS);
+ keys1.put(TokenType.BAD_CHARACTER, GetTextHighlighterData.BAD_CHARACTER);
+
+ }
+
+ @NotNull
+ public TextAttributesKey[] getTokenHighlights(IElementType tokenType) {
+ return pack(keys1.get(tokenType));
+ }
+}
\ No newline at end of file
diff --git a/plugins/gettext/src/com/jetbrains/gettext/lang/CommandFormatException.java b/plugins/gettext/src/com/jetbrains/gettext/lang/CommandFormatException.java
new file mode 100644
index 000000000000..212465d09c2e
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/lang/CommandFormatException.java
@@ -0,0 +1,11 @@
+package com.jetbrains.gettext.lang;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class CommandFormatException extends Exception {
+
+ public CommandFormatException(String message) {
+ super(message);
+ }
+}
diff --git a/plugins/gettext/src/com/jetbrains/gettext/lang/MsgCommand.java b/plugins/gettext/src/com/jetbrains/gettext/lang/MsgCommand.java
new file mode 100644
index 000000000000..b85fd9d6dcec
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/lang/MsgCommand.java
@@ -0,0 +1,68 @@
+package com.jetbrains.gettext.lang;
+
+import com.intellij.lang.PsiBuilder;
+import com.intellij.psi.tree.IElementType;
+import com.jetbrains.gettext.GetTextTokenTypes;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public abstract class MsgCommand {
+
+ protected boolean exists = false;
+
+ public abstract IElementType getCompositeElement();
+
+ public void parse(PsiBuilder builder) throws CommandFormatException {
+ builder.advanceLexer();
+ int count = 0;
+ while (builder.getTokenType() == GetTextTokenTypes.STRING) {
+ checkString(builder);
+ count++;
+ }
+ if (count == 0) {
+ throw new CommandFormatException("String for " + getName() + " is not specified");
+ }
+ }
+
+ private static void checkString(PsiBuilder builder) {
+ String text = builder.getTokenText();
+ if (text != null && text.length() > 0 &&
+ (text.charAt(0) != '\"' || text.charAt(text.length() - 1) != '\"')) {
+ PsiBuilder.Marker marker = builder.mark();
+ builder.advanceLexer();
+ marker.error("Unbounded string");
+ } else {
+ builder.advanceLexer();
+ }
+ }
+
+ public boolean isNecessary() {
+ return false;
+ }
+
+ public boolean isMultiple() {
+ return false;
+ }
+
+ public boolean exists() {
+ return exists;
+ }
+
+ public boolean register() {
+ if (!exists) {
+ exists = true;
+ return true;
+ }
+ else if (isMultiple()) {
+ return true;
+ }
+ return false;
+ }
+
+ public abstract String getName();
+
+ public int getCount() {
+ return exists ? 1 : 0;
+ }
+}
diff --git a/plugins/gettext/src/com/jetbrains/gettext/lang/MsgCommandContainer.java b/plugins/gettext/src/com/jetbrains/gettext/lang/MsgCommandContainer.java
new file mode 100644
index 000000000000..8305aa91bd90
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/lang/MsgCommandContainer.java
@@ -0,0 +1,68 @@
+package com.jetbrains.gettext.lang;
+
+import com.intellij.lang.PsiBuilder;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.util.containers.hash.HashMap;
+import com.jetbrains.gettext.GetTextTokenTypes;
+
+import java.util.Map;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class MsgCommandContainer {
+
+ private Map commands;
+
+ public MsgCommandContainer() {
+ this.commands = new HashMap();
+ commands.put(GetTextTokenTypes.MSGID, new MsgidCommand());
+ commands.put(GetTextTokenTypes.MSGSTR, new MsgstrCommand());
+ commands.put(GetTextTokenTypes.MSGCTXT, new MsgctxtCommand());
+ commands.put(GetTextTokenTypes.MSGID_PLURAL, new MsgidPluralCommand());
+ }
+
+
+ public boolean isFull() {
+ for (MsgCommand command : commands.values()) {
+ boolean full = !command.isNecessary() || command.exists();
+ if (!full) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private MsgCommand getCommand(IElementType token) throws UnknownCommandException {
+ MsgCommand command = commands.get(token);
+ if (command == null) {
+ throw new UnknownCommandException("Unexpected token");
+ }
+ return command;
+ }
+
+ public boolean parse(PsiBuilder builder) {
+ PsiBuilder.Marker marker = builder.mark();
+ try {
+ MsgCommand command = getCommand(builder.getTokenType());
+ command.parse(builder);
+ //if (result) {
+ marker.done(command.getCompositeElement());
+ //}
+ //else {
+ // marker.error("String for " + command.getName() + " is not specified");
+ //}
+ //return result;
+ return true;
+ }
+ catch (Exception e) {
+ marker.error(e.getMessage());
+ builder.advanceLexer();
+ return false;
+ }
+ }
+
+ public boolean addCommand(IElementType token) throws UnknownCommandException {
+ return getCommand(token).register();
+ }
+}
diff --git a/plugins/gettext/src/com/jetbrains/gettext/lang/MsgctxtCommand.java b/plugins/gettext/src/com/jetbrains/gettext/lang/MsgctxtCommand.java
new file mode 100644
index 000000000000..3da7994ee968
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/lang/MsgctxtCommand.java
@@ -0,0 +1,22 @@
+package com.jetbrains.gettext.lang;
+
+import com.intellij.psi.tree.IElementType;
+import com.jetbrains.gettext.GetTextCompositeElementTypes;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class MsgctxtCommand extends MsgCommand {
+ public MsgctxtCommand() {
+ }
+
+ @Override
+ public IElementType getCompositeElement() {
+ return GetTextCompositeElementTypes.MSGCTXT;
+ }
+
+ @Override
+ public String getName() {
+ return "msgctxt";
+ }
+}
diff --git a/plugins/gettext/src/com/jetbrains/gettext/lang/MsgidCommand.java b/plugins/gettext/src/com/jetbrains/gettext/lang/MsgidCommand.java
new file mode 100644
index 000000000000..f4780d09f9e4
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/lang/MsgidCommand.java
@@ -0,0 +1,28 @@
+package com.jetbrains.gettext.lang;
+
+import com.intellij.psi.tree.IElementType;
+import com.jetbrains.gettext.GetTextCompositeElementTypes;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class MsgidCommand extends MsgCommand {
+
+ public MsgidCommand() {
+ }
+
+ @Override
+ public IElementType getCompositeElement() {
+ return GetTextCompositeElementTypes.MSGID;
+ }
+
+ @Override
+ public boolean isNecessary() {
+ return true;
+ }
+
+ @Override
+ public String getName() {
+ return "msgid";
+ }
+}
diff --git a/plugins/gettext/src/com/jetbrains/gettext/lang/MsgidPluralCommand.java b/plugins/gettext/src/com/jetbrains/gettext/lang/MsgidPluralCommand.java
new file mode 100644
index 000000000000..12c8664bdd52
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/lang/MsgidPluralCommand.java
@@ -0,0 +1,21 @@
+package com.jetbrains.gettext.lang;
+
+import com.intellij.psi.tree.IElementType;
+import com.jetbrains.gettext.GetTextCompositeElementTypes;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class MsgidPluralCommand extends MsgCommand {
+ public MsgidPluralCommand() {
+ }
+ @Override
+ public IElementType getCompositeElement() {
+ return GetTextCompositeElementTypes.MSGID_PLURAL;
+ }
+
+ @Override
+ public String getName() {
+ return "msgid_plural";
+ }
+}
diff --git a/plugins/gettext/src/com/jetbrains/gettext/lang/MsgstrCommand.java b/plugins/gettext/src/com/jetbrains/gettext/lang/MsgstrCommand.java
new file mode 100644
index 000000000000..15afdcb08002
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/lang/MsgstrCommand.java
@@ -0,0 +1,76 @@
+package com.jetbrains.gettext.lang;
+
+import com.intellij.lang.PsiBuilder;
+import com.intellij.psi.tree.IElementType;
+import com.jetbrains.gettext.GetTextCompositeElementTypes;
+import com.jetbrains.gettext.GetTextTokenTypes;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class MsgstrCommand extends MsgCommand {
+
+ private int count;
+
+ public MsgstrCommand() {
+ count = 0;
+ }
+
+ @Override
+ public IElementType getCompositeElement() {
+ return GetTextCompositeElementTypes.MSGSTR;
+ }
+
+ @Override
+ public void parse(PsiBuilder builder) throws CommandFormatException {
+ try {
+ super.parse(builder);
+ }
+ catch (CommandFormatException e) {
+ parseBraces(builder);
+ }
+ //return super.parse(builder) || parseBraces(builder);
+ }
+
+ private boolean parseBraces(PsiBuilder builder) throws CommandFormatException {
+ if (builder.getTokenType() == GetTextTokenTypes.LBRACE) {
+ builder.advanceLexer();
+ if (builder.getTokenType() == GetTextTokenTypes.NUMBER) {
+ builder.advanceLexer();
+ if (builder.getTokenType() == GetTextTokenTypes.RBRACE) {
+ super.parse(builder);
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isNecessary() {
+ return true;
+ }
+
+ @Override
+ public boolean isMultiple() {
+ return true;
+ }
+
+ @Override
+ public String getName() {
+ return "msgstr";
+ }
+
+ @Override
+ public int getCount() {
+ return count;
+ }
+
+ @Override
+ public boolean register() {
+ boolean result = super.register();
+ if (result) {
+ count++;
+ }
+ return result;
+ }
+}
diff --git a/plugins/gettext/src/com/jetbrains/gettext/lang/UnknownCommandException.java b/plugins/gettext/src/com/jetbrains/gettext/lang/UnknownCommandException.java
new file mode 100644
index 000000000000..60d70f9b4e75
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/lang/UnknownCommandException.java
@@ -0,0 +1,11 @@
+package com.jetbrains.gettext.lang;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class UnknownCommandException extends Exception {
+
+ public UnknownCommandException(String message) {
+ super(message);
+ }
+}
diff --git a/plugins/gettext/src/com/jetbrains/gettext/parser/GetTextParser.java b/plugins/gettext/src/com/jetbrains/gettext/parser/GetTextParser.java
new file mode 100644
index 000000000000..c0b9a0242118
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/parser/GetTextParser.java
@@ -0,0 +1,75 @@
+package com.jetbrains.gettext.parser;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.lang.PsiBuilder;
+import com.intellij.lang.PsiParser;
+import com.intellij.psi.tree.IElementType;
+import com.jetbrains.gettext.GetTextCompositeElementTypes;
+import com.jetbrains.gettext.GetTextTokenTypes;
+import com.jetbrains.gettext.lang.MsgCommandContainer;
+import com.jetbrains.gettext.lang.UnknownCommandException;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class GetTextParser implements PsiParser {
+ @NotNull
+ @Override
+ public ASTNode parse(IElementType root, PsiBuilder builder) {
+ builder.setDebugMode(true);
+ final PsiBuilder.Marker marker = builder.mark();
+ while (!builder.eof()) {
+ parseMsgBock(builder);
+ }
+ marker.done(root);
+ return builder.getTreeBuilt();
+ }
+
+ private static void parseMsgBock(PsiBuilder builder) {
+ PsiBuilder.Marker msgidMarker = builder.mark();
+ parseCommentHeader(builder);
+ parseMsgContent(builder);
+ msgidMarker.done(GetTextCompositeElementTypes.MSG_BLOCK);
+ }
+
+ private static void parseCommentHeader(PsiBuilder builder) {
+ PsiBuilder.Marker marker = builder.mark();
+ while (GetTextTokenTypes.COMMENTS.contains(builder.getTokenType()) ||
+ GetTextTokenTypes.FLAGS.contains(builder.getTokenType())) {
+ builder.advanceLexer();
+ }
+ marker.done(GetTextCompositeElementTypes.HEADER);
+ }
+
+ private static boolean parseMsgContent(PsiBuilder builder) {
+ PsiBuilder.Marker marker = builder.mark();
+ MsgCommandContainer container = new MsgCommandContainer();
+ while (!canTerminate(builder, container)) {
+ try {
+ IElementType token = builder.getTokenType();
+ if (container.parse(builder)) {
+ container.addCommand(token);
+ }
+ }
+ catch (UnknownCommandException e) {
+ //marker.precede().error(e.getMessage());
+ //builder.advanceLexer();
+ }
+ }
+ if (!container.isFull()) {
+ marker.error("Not enough commands");
+ return false;
+ }
+ else {
+ marker.done(GetTextCompositeElementTypes.MSG_CONTENT);
+ return true;
+ }
+ }
+
+ private static boolean canTerminate(PsiBuilder builder, MsgCommandContainer container) {
+ return builder.eof() ||
+ GetTextTokenTypes.SYSTEM_COMMENTS.contains(builder.getTokenType()) ||
+ builder.getTokenType() == GetTextTokenTypes.MSGID && container.isFull();
+ }
+}
diff --git a/plugins/gettext/src/com/jetbrains/gettext/parser/GetTextParserDefinition.java b/plugins/gettext/src/com/jetbrains/gettext/parser/GetTextParserDefinition.java
new file mode 100644
index 000000000000..193a5ecc46f7
--- /dev/null
+++ b/plugins/gettext/src/com/jetbrains/gettext/parser/GetTextParserDefinition.java
@@ -0,0 +1,75 @@
+package com.jetbrains.gettext.parser;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.lang.ParserDefinition;
+import com.intellij.lang.PsiParser;
+import com.intellij.lexer.Lexer;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.FileViewProvider;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.tree.IFileElementType;
+import com.intellij.psi.tree.IStubFileElementType;
+import com.intellij.psi.tree.TokenSet;
+import com.jetbrains.gettext.*;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class GetTextParserDefinition implements ParserDefinition {
+ private static final TokenSet WHITE_SPACE = TokenSet.create(GetTextTokenTypes.WHITE_SPACE);
+ private static final TokenSet COMMENT = TokenSet.create(GetTextTokenTypes.COMMENT, GetTextTokenTypes.COMMENT_SYMBOLS);
+
+ @NotNull
+ public Lexer createLexer(Project project) {
+ return new GetTextLexer();
+ }
+
+ public PsiParser createParser(Project project) {
+ return new GetTextParser();
+ }
+
+ public IFileElementType getFileNodeType() {
+ return new IStubFileElementType(GetTextLanguage.INSTANCE);
+ }
+
+ @NotNull
+ public TokenSet getWhitespaceTokens() {
+ return WHITE_SPACE;
+ }
+
+ @NotNull
+ public TokenSet getCommentTokens() {
+ return COMMENT;
+ }
+
+ @NotNull
+ public TokenSet getStringLiteralElements() {
+ return GetTextTokenTypes.STRING_LITERALS;
+ }
+
+ @NotNull
+ public PsiElement createElement(ASTNode node) {
+ final IElementType type = node.getElementType();
+ if (type instanceof GetTextCompositeElementType) {
+ return GetTextCompositeElementType.createPsiElement(node);
+ }
+ throw new AssertionError("Unknown type: " + type);
+ }
+
+ public PsiFile createFile(FileViewProvider viewProvider) {
+ return new GetTextFile(viewProvider);
+ }
+
+ public SpaceRequirements spaceExistanceTypeBetweenTokens(ASTNode left, ASTNode right) {
+ return SpaceRequirements.MAY;
+ }
+
+ @Override
+ public String toString() {
+ return "GetTextParserDefinition";
+ }
+}
+
diff --git a/plugins/gettext/test/com/jetbrains/gettext/GetTextLexerTest.java b/plugins/gettext/test/com/jetbrains/gettext/GetTextLexerTest.java
new file mode 100644
index 000000000000..666bbcd73d34
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/GetTextLexerTest.java
@@ -0,0 +1,66 @@
+package com.jetbrains.gettext;
+
+import com.intellij.lexer.Lexer;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.testFramework.UsefulTestCase;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class GetTextLexerTest extends UsefulTestCase {
+
+ private static void doFileLexerTest(Lexer lexer, String testText, String expected) {
+ lexer.start(testText);
+ String result = "";
+ while (true) {
+ IElementType tokenType = lexer.getTokenType();
+ if (tokenType == null) {
+ break;
+ }
+ String tokenText = getTokenText(lexer);
+ String tokenTypeName = tokenType.toString();
+ String line = tokenTypeName + " ('" + tokenText + "')\n";
+ result += line;
+ lexer.advance();
+ }
+ assertSameLinesWithFile(expected, result);
+ }
+
+ private static String getTokenText(Lexer lexer) {
+ return lexer.getBufferSequence().subSequence(lexer.getTokenStart(), lexer.getTokenEnd()).toString();
+ }
+
+ private static void doTest(String fileName) throws IOException {
+ final String fullPath = GetTextUtils.getFullPath(fileName);
+ final Lexer lexer = new GetTextLexer();
+ final String testText = getFileText(fullPath + ".po");
+ final String expected = fullPath + ".txt";
+ doFileLexerTest(lexer, testText, expected);
+ }
+
+ public static String getFileText(final String filePath) {
+ try {
+ return FileUtil.loadFile(new File(filePath));
+ }
+ catch (IOException e) {
+ System.out.println(filePath);
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void testLexer() throws Throwable {
+ doTest("string");
+ }
+
+ public void testAllFiles() throws Throwable {
+ for (final String file : GetTextUtils.getAllTestedFiles()) {
+ doTest(file);
+ }
+ }
+}
+
+
diff --git a/plugins/gettext/test/com/jetbrains/gettext/GetTextParserTest.java b/plugins/gettext/test/com/jetbrains/gettext/GetTextParserTest.java
new file mode 100644
index 000000000000..6e574abfe2d7
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/GetTextParserTest.java
@@ -0,0 +1,47 @@
+package com.jetbrains.gettext;
+
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.impl.DebugUtil;
+import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
+import org.jetbrains.annotations.NonNls;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class GetTextParserTest extends LightCodeInsightFixtureTestCase {
+
+ private void doTest(String fileName) throws IOException {
+ final String filePath = GetTextUtils.getFullPath(fileName) + ".po";
+
+ try {
+ final String fileText = FileUtil.loadFile(new File(filePath));
+ doTest(StringUtil.convertLineSeparators(fileText), fileName);
+ }
+ catch (IOException e) {
+ fail("Can't load file: " + filePath);
+ }
+ }
+
+ private void doTest(@NonNls final String code, final String fileName) {
+ final PsiFile psiFile = createLightFile(fileName, GetTextLanguage.INSTANCE, code);
+ final String tree = DebugUtil.psiTreeToString(psiFile, false);
+ final String path = GetTextUtils.getFullParserResultPath(fileName);
+ assertSameLinesWithFile(path, tree);
+ }
+
+ public void testSimple() throws IOException {
+ doTest("string");
+ }
+
+ public void testAllFiles() throws Throwable {
+ for(final String file : GetTextUtils.getAllTestedFiles()) {
+ System.out.println("Start: " + file);
+ doTest(file);
+ }
+ }
+}
diff --git a/plugins/gettext/test/com/jetbrains/gettext/GetTextUtils.java b/plugins/gettext/test/com/jetbrains/gettext/GetTextUtils.java
new file mode 100644
index 000000000000..d0099f4d0837
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/GetTextUtils.java
@@ -0,0 +1,32 @@
+package com.jetbrains.gettext;
+
+import com.intellij.openapi.application.PathManager;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public class GetTextUtils {
+
+ public static String[] getAllTestedFiles() {
+ return new String[]{
+ "simple",
+ "without_comments",
+ "flags",
+ "complex_flags",
+ "msg_plural",
+ "range_flag",
+ "string"};
+ }
+
+ protected static String getDataSubpath() {
+ return "community/plugins/gettext/test/com/jetbrains/gettext/lexer";
+ }
+
+ public static String getFullPath(final String fileName) {
+ return PathManager.getHomePath() + "/" + getDataSubpath() + "/" + fileName;
+ }
+
+ public static String getFullParserResultPath(final String fileName) {
+ return getFullPath(fileName) + "_parser.txt";
+ }
+}
\ No newline at end of file
diff --git a/plugins/gettext/test/com/jetbrains/gettext/lexer/complex_flags.po b/plugins/gettext/test/com/jetbrains/gettext/lexer/complex_flags.po
new file mode 100644
index 000000000000..cc96fa6374dd
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/lexer/complex_flags.po
@@ -0,0 +1,6 @@
+# test
+#. another
+#: ref
+#, fuzzy, c-format, no-objc-format
+msgid "new string to translate"
+msgstr "translated string"
\ No newline at end of file
diff --git a/plugins/gettext/test/com/jetbrains/gettext/lexer/complex_flags.txt b/plugins/gettext/test/com/jetbrains/gettext/lexer/complex_flags.txt
new file mode 100644
index 000000000000..6cb191ceaf80
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/lexer/complex_flags.txt
@@ -0,0 +1,35 @@
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS (' ')
+COMMENT ('test')
+WHITE_SPACE ('
+')
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS ('.')
+EXTR_COMMENT (' another')
+WHITE_SPACE ('
+')
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS (':')
+REFERENCE (' ref')
+WHITE_SPACE ('
+')
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS (',')
+WHITE_SPACE (' ')
+FUZZY_FLAG ('fuzzy')
+DELIVERY (',')
+WHITE_SPACE (' ')
+FORMAT_FLAG ('c-format')
+DELIVERY (',')
+WHITE_SPACE (' ')
+NO_FORMAT_FLAG ('no-objc-format')
+WHITE_SPACE ('
+')
+MSGID ('msgid')
+WHITE_SPACE (' ')
+STRING ('"new string to translate"')
+WHITE_SPACE ('
+')
+MSGSTR ('msgstr')
+WHITE_SPACE (' ')
+STRING ('"translated string"')
\ No newline at end of file
diff --git a/plugins/gettext/test/com/jetbrains/gettext/lexer/complex_flags_parser.txt b/plugins/gettext/test/com/jetbrains/gettext/lexer/complex_flags_parser.txt
new file mode 100644
index 000000000000..84ee7f7463e1
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/lexer/complex_flags_parser.txt
@@ -0,0 +1,36 @@
+GNU GetText File
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)(' ')
+ PsiComment(COMMENT)('test')
+ PsiWhiteSpace('\n')
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)('.')
+ MSG_BLOCK
+ HEADER
+ PsiElement(EXTR_COMMENT)(' another')
+ PsiWhiteSpace('\n')
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)(':')
+ PsiElement(REFERENCE)(' ref')
+ PsiWhiteSpace('\n')
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)(',')
+ PsiWhiteSpace(' ')
+ PsiElement(FUZZY_FLAG)('fuzzy')
+ PsiElement(DELIVERY)(',')
+ PsiWhiteSpace(' ')
+ PsiElement(FORMAT_FLAG)('c-format')
+ PsiElement(DELIVERY)(',')
+ PsiWhiteSpace(' ')
+ PsiElement(NO_FORMAT_FLAG)('no-objc-format')
+ PsiWhiteSpace('\n')
+ MSG_CONTENT
+ MSGID
+ PsiElement(MSGID)('msgid')
+ PsiWhiteSpace(' ')
+ PsiElement(STRING)('"new string to translate"')
+ PsiWhiteSpace('\n')
+ MSGSTR
+ PsiElement(MSGSTR)('msgstr')
+ PsiWhiteSpace(' ')
+ PsiElement(STRING)('"translated string"')
\ No newline at end of file
diff --git a/plugins/gettext/test/com/jetbrains/gettext/lexer/flags.po b/plugins/gettext/test/com/jetbrains/gettext/lexer/flags.po
new file mode 100644
index 000000000000..1c0785015626
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/lexer/flags.po
@@ -0,0 +1,6 @@
+# test
+#. another
+#: ref
+#, fuzzy,
+msgid "new string to translate"
+msgstr "translated string"
\ No newline at end of file
diff --git a/plugins/gettext/test/com/jetbrains/gettext/lexer/flags.txt b/plugins/gettext/test/com/jetbrains/gettext/lexer/flags.txt
new file mode 100644
index 000000000000..33db8a1dae30
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/lexer/flags.txt
@@ -0,0 +1,30 @@
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS (' ')
+COMMENT ('test')
+WHITE_SPACE ('
+')
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS ('.')
+EXTR_COMMENT (' another')
+WHITE_SPACE ('
+')
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS (':')
+REFERENCE (' ref')
+WHITE_SPACE ('
+')
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS (',')
+WHITE_SPACE (' ')
+FUZZY_FLAG ('fuzzy')
+DELIVERY (',')
+WHITE_SPACE ('
+')
+MSGID ('msgid')
+WHITE_SPACE (' ')
+STRING ('"new string to translate"')
+WHITE_SPACE ('
+')
+MSGSTR ('msgstr')
+WHITE_SPACE (' ')
+STRING ('"translated string"')
\ No newline at end of file
diff --git a/plugins/gettext/test/com/jetbrains/gettext/lexer/flags_parser.txt b/plugins/gettext/test/com/jetbrains/gettext/lexer/flags_parser.txt
new file mode 100644
index 000000000000..039070d56e50
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/lexer/flags_parser.txt
@@ -0,0 +1,31 @@
+GNU GetText File
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)(' ')
+ PsiComment(COMMENT)('test')
+ PsiWhiteSpace('\n')
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)('.')
+ MSG_BLOCK
+ HEADER
+ PsiElement(EXTR_COMMENT)(' another')
+ PsiWhiteSpace('\n')
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)(':')
+ PsiElement(REFERENCE)(' ref')
+ PsiWhiteSpace('\n')
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)(',')
+ PsiWhiteSpace(' ')
+ PsiElement(FUZZY_FLAG)('fuzzy')
+ PsiElement(DELIVERY)(',')
+ PsiWhiteSpace('\n')
+ MSG_CONTENT
+ MSGID
+ PsiElement(MSGID)('msgid')
+ PsiWhiteSpace(' ')
+ PsiElement(STRING)('"new string to translate"')
+ PsiWhiteSpace('\n')
+ MSGSTR
+ PsiElement(MSGSTR)('msgstr')
+ PsiWhiteSpace(' ')
+ PsiElement(STRING)('"translated string"')
\ No newline at end of file
diff --git a/plugins/gettext/test/com/jetbrains/gettext/lexer/msg_plural.po b/plugins/gettext/test/com/jetbrains/gettext/lexer/msg_plural.po
new file mode 100644
index 000000000000..c198b49cfa84
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/lexer/msg_plural.po
@@ -0,0 +1,8 @@
+# test
+#. another
+#: ref
+#| msgid test
+msgid_plural ""
+msgid "new string to translate"
+msgstr[0] "translated string"
+msgstr[01] "translated string"
\ No newline at end of file
diff --git a/plugins/gettext/test/com/jetbrains/gettext/lexer/msg_plural.txt b/plugins/gettext/test/com/jetbrains/gettext/lexer/msg_plural.txt
new file mode 100644
index 000000000000..4cc17e19bbd6
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/lexer/msg_plural.txt
@@ -0,0 +1,44 @@
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS (' ')
+COMMENT ('test')
+WHITE_SPACE ('
+')
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS ('.')
+EXTR_COMMENT (' another')
+WHITE_SPACE ('
+')
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS (':')
+REFERENCE (' ref')
+WHITE_SPACE ('
+')
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS ('|')
+PREVIOUS_TRANSLATE_COMMENT (' msgid test')
+WHITE_SPACE ('
+')
+MSGID_PLURAL ('msgid_plural')
+WHITE_SPACE (' ')
+STRING ('""')
+WHITE_SPACE ('
+')
+MSGID ('msgid')
+WHITE_SPACE (' ')
+STRING ('"new string to translate"')
+WHITE_SPACE ('
+')
+MSGSTR ('msgstr')
+LBRACE ('[')
+NUMBER ('0')
+RBRACE (']')
+WHITE_SPACE (' ')
+STRING ('"translated string"')
+WHITE_SPACE ('
+')
+MSGSTR ('msgstr')
+LBRACE ('[')
+NUMBER ('01')
+RBRACE (']')
+WHITE_SPACE (' ')
+STRING ('"translated string"')
\ No newline at end of file
diff --git a/plugins/gettext/test/com/jetbrains/gettext/lexer/msg_plural_parser.txt b/plugins/gettext/test/com/jetbrains/gettext/lexer/msg_plural_parser.txt
new file mode 100644
index 000000000000..d9707ff13dc7
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/lexer/msg_plural_parser.txt
@@ -0,0 +1,45 @@
+GNU GetText File
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)(' ')
+ PsiComment(COMMENT)('test')
+ PsiWhiteSpace('\n')
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)('.')
+ MSG_BLOCK
+ HEADER
+ PsiElement(EXTR_COMMENT)(' another')
+ PsiWhiteSpace('\n')
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)(':')
+ PsiElement(REFERENCE)(' ref')
+ PsiWhiteSpace('\n')
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)('|')
+ PsiElement(PREVIOUS_TRANSLATE_COMMENT)(' msgid test')
+ PsiWhiteSpace('\n')
+ MSG_CONTENT
+ MSGID_PLURAL
+ PsiElement(MSGID_PLURAL)('msgid_plural')
+ PsiWhiteSpace(' ')
+ PsiElement(STRING)('""')
+ PsiWhiteSpace('\n')
+ MSGID
+ PsiElement(MSGID)('msgid')
+ PsiWhiteSpace(' ')
+ PsiElement(STRING)('"new string to translate"')
+ PsiWhiteSpace('\n')
+ MSGSTR
+ PsiElement(MSGSTR)('msgstr')
+ PsiElement(LBRACE)('[')
+ PsiElement(NUMBER)('0')
+ PsiElement(RBRACE)(']')
+ PsiWhiteSpace(' ')
+ PsiElement(STRING)('"translated string"')
+ PsiWhiteSpace('\n')
+ MSGSTR
+ PsiElement(MSGSTR)('msgstr')
+ PsiElement(LBRACE)('[')
+ PsiElement(NUMBER)('01')
+ PsiElement(RBRACE)(']')
+ PsiWhiteSpace(' ')
+ PsiElement(STRING)('"translated string"')
\ No newline at end of file
diff --git a/plugins/gettext/test/com/jetbrains/gettext/lexer/parser.po b/plugins/gettext/test/com/jetbrains/gettext/lexer/parser.po
new file mode 100644
index 000000000000..8fb1fac63830
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/lexer/parser.po
@@ -0,0 +1,2 @@
+msgid "string"
+msgstr "translated"
\ No newline at end of file
diff --git a/plugins/gettext/test/com/jetbrains/gettext/lexer/parser_parser.txt b/plugins/gettext/test/com/jetbrains/gettext/lexer/parser_parser.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/plugins/gettext/test/com/jetbrains/gettext/lexer/range_flag.po b/plugins/gettext/test/com/jetbrains/gettext/lexer/range_flag.po
new file mode 100644
index 000000000000..80f9327d1fcd
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/lexer/range_flag.po
@@ -0,0 +1,6 @@
+# test
+#. another
+#: ref
+#, fuzzy, range: 0..10
+msgid "new string to translate"
+msgstr "translated string"
\ No newline at end of file
diff --git a/plugins/gettext/test/com/jetbrains/gettext/lexer/range_flag.txt b/plugins/gettext/test/com/jetbrains/gettext/lexer/range_flag.txt
new file mode 100644
index 000000000000..60d2ec2e176a
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/lexer/range_flag.txt
@@ -0,0 +1,37 @@
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS (' ')
+COMMENT ('test')
+WHITE_SPACE ('
+')
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS ('.')
+EXTR_COMMENT (' another')
+WHITE_SPACE ('
+')
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS (':')
+REFERENCE (' ref')
+WHITE_SPACE ('
+')
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS (',')
+WHITE_SPACE (' ')
+FUZZY_FLAG ('fuzzy')
+DELIVERY (',')
+WHITE_SPACE (' ')
+RANGE_FLAG ('range')
+COLON (':')
+WHITE_SPACE (' ')
+NUMBER ('0')
+DOTS ('..')
+NUMBER ('10')
+WHITE_SPACE ('
+')
+MSGID ('msgid')
+WHITE_SPACE (' ')
+STRING ('"new string to translate"')
+WHITE_SPACE ('
+')
+MSGSTR ('msgstr')
+WHITE_SPACE (' ')
+STRING ('"translated string"')
\ No newline at end of file
diff --git a/plugins/gettext/test/com/jetbrains/gettext/lexer/range_flag_parser.txt b/plugins/gettext/test/com/jetbrains/gettext/lexer/range_flag_parser.txt
new file mode 100644
index 000000000000..46048336c942
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/lexer/range_flag_parser.txt
@@ -0,0 +1,46 @@
+GNU GetText File
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)(' ')
+ PsiComment(COMMENT)('test')
+ PsiWhiteSpace('\n')
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)('.')
+ MSG_BLOCK
+ HEADER
+ PsiElement(EXTR_COMMENT)(' another')
+ PsiWhiteSpace('\n')
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)(':')
+ PsiElement(REFERENCE)(' ref')
+ PsiWhiteSpace('\n')
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)(',')
+ PsiWhiteSpace(' ')
+ PsiElement(FUZZY_FLAG)('fuzzy')
+ PsiElement(DELIVERY)(',')
+ PsiWhiteSpace(' ')
+ PsiElement(RANGE_FLAG)('range')
+ MSG_CONTENT
+ PsiErrorElement:Unexpected token
+
+ PsiElement(COLON)(':')
+ PsiErrorElement:Unexpected token
+
+ PsiWhiteSpace(' ')
+ PsiElement(NUMBER)('0')
+ PsiErrorElement:Unexpected token
+
+ PsiElement(DOTS)('..')
+ PsiErrorElement:Unexpected token
+
+ PsiElement(NUMBER)('10')
+ PsiWhiteSpace('\n')
+ MSGID
+ PsiElement(MSGID)('msgid')
+ PsiWhiteSpace(' ')
+ PsiElement(STRING)('"new string to translate"')
+ PsiWhiteSpace('\n')
+ MSGSTR
+ PsiElement(MSGSTR)('msgstr')
+ PsiWhiteSpace(' ')
+ PsiElement(STRING)('"translated string"')
\ No newline at end of file
diff --git a/plugins/gettext/test/com/jetbrains/gettext/lexer/simple.po b/plugins/gettext/test/com/jetbrains/gettext/lexer/simple.po
new file mode 100644
index 000000000000..327fa0c9a109
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/lexer/simple.po
@@ -0,0 +1,13 @@
+# test
+#. another
+#: ref
+#| msgid test
+msgid "new string to translate"
+msgstr "translated string"
+
+# t
+#. another
+#: ref
+#| msgid test
+msgid "new string to translate"
+msgstr "translated string"
diff --git a/plugins/gettext/test/com/jetbrains/gettext/lexer/simple.txt b/plugins/gettext/test/com/jetbrains/gettext/lexer/simple.txt
new file mode 100644
index 000000000000..ba45c1662815
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/lexer/simple.txt
@@ -0,0 +1,62 @@
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS (' ')
+COMMENT ('test')
+WHITE_SPACE ('
+')
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS ('.')
+EXTR_COMMENT (' another')
+WHITE_SPACE ('
+')
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS (':')
+REFERENCE (' ref')
+WHITE_SPACE ('
+')
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS ('|')
+PREVIOUS_TRANSLATE_COMMENT (' msgid test')
+WHITE_SPACE ('
+')
+MSGID ('msgid')
+WHITE_SPACE (' ')
+STRING ('"new string to translate"')
+WHITE_SPACE ('
+')
+MSGSTR ('msgstr')
+WHITE_SPACE (' ')
+STRING ('"translated string"')
+WHITE_SPACE ('
+')
+WHITE_SPACE ('
+')
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS (' ')
+COMMENT ('t')
+WHITE_SPACE ('
+')
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS ('.')
+EXTR_COMMENT (' another')
+WHITE_SPACE ('
+')
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS (':')
+REFERENCE (' ref')
+WHITE_SPACE ('
+')
+COMMENT_SYMBOLS ('#')
+COMMENT_SYMBOLS ('|')
+PREVIOUS_TRANSLATE_COMMENT (' msgid test')
+WHITE_SPACE ('
+')
+MSGID ('msgid')
+WHITE_SPACE (' ')
+STRING ('"new string to translate"')
+WHITE_SPACE ('
+')
+MSGSTR ('msgstr')
+WHITE_SPACE (' ')
+STRING ('"translated string"')
+WHITE_SPACE ('
+')
\ No newline at end of file
diff --git a/plugins/gettext/test/com/jetbrains/gettext/lexer/simple_parser.txt b/plugins/gettext/test/com/jetbrains/gettext/lexer/simple_parser.txt
new file mode 100644
index 000000000000..5250fbc94eb3
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/lexer/simple_parser.txt
@@ -0,0 +1,60 @@
+GNU GetText File
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)(' ')
+ PsiComment(COMMENT)('test')
+ PsiWhiteSpace('\n')
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)('.')
+ MSG_BLOCK
+ HEADER
+ PsiElement(EXTR_COMMENT)(' another')
+ PsiWhiteSpace('\n')
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)(':')
+ PsiElement(REFERENCE)(' ref')
+ PsiWhiteSpace('\n')
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)('|')
+ PsiElement(PREVIOUS_TRANSLATE_COMMENT)(' msgid test')
+ PsiWhiteSpace('\n')
+ MSG_CONTENT
+ MSGID
+ PsiElement(MSGID)('msgid')
+ PsiWhiteSpace(' ')
+ PsiElement(STRING)('"new string to translate"')
+ PsiWhiteSpace('\n')
+ MSGSTR
+ PsiElement(MSGSTR)('msgstr')
+ PsiWhiteSpace(' ')
+ PsiElement(STRING)('"translated string"')
+ PsiWhiteSpace('\n')
+ PsiWhiteSpace('\n')
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)(' ')
+ PsiComment(COMMENT)('t')
+ PsiWhiteSpace('\n')
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)('.')
+ MSG_BLOCK
+ HEADER
+ PsiElement(EXTR_COMMENT)(' another')
+ PsiWhiteSpace('\n')
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)(':')
+ PsiElement(REFERENCE)(' ref')
+ PsiWhiteSpace('\n')
+ PsiComment(COMMENT_SYMBOLS)('#')
+ PsiComment(COMMENT_SYMBOLS)('|')
+ PsiElement(PREVIOUS_TRANSLATE_COMMENT)(' msgid test')
+ PsiWhiteSpace('\n')
+ MSG_CONTENT
+ MSGID
+ PsiElement(MSGID)('msgid')
+ PsiWhiteSpace(' ')
+ PsiElement(STRING)('"new string to translate"')
+ PsiWhiteSpace('\n')
+ MSGSTR
+ PsiElement(MSGSTR)('msgstr')
+ PsiWhiteSpace(' ')
+ PsiElement(STRING)('"translated string"')
+ PsiWhiteSpace('\n')
\ No newline at end of file
diff --git a/plugins/gettext/test/com/jetbrains/gettext/lexer/string.po b/plugins/gettext/test/com/jetbrains/gettext/lexer/string.po
new file mode 100644
index 000000000000..3ef390f8e671
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/lexer/string.po
@@ -0,0 +1,4 @@
+msgid "
+""
+"
+"\n"
\ No newline at end of file
diff --git a/plugins/gettext/test/com/jetbrains/gettext/lexer/string.txt b/plugins/gettext/test/com/jetbrains/gettext/lexer/string.txt
new file mode 100644
index 000000000000..928ffa32eb1f
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/lexer/string.txt
@@ -0,0 +1,10 @@
+MSGID ('msgid')
+WHITE_SPACE (' ')
+STRING ('"
+')
+STRING ('""')
+WHITE_SPACE ('
+')
+STRING ('"
+')
+STRING ('"\n"')
\ No newline at end of file
diff --git a/plugins/gettext/test/com/jetbrains/gettext/lexer/string_parser.txt b/plugins/gettext/test/com/jetbrains/gettext/lexer/string_parser.txt
new file mode 100644
index 000000000000..7bab51b67de5
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/lexer/string_parser.txt
@@ -0,0 +1,15 @@
+GNU GetText File
+ MSG_BLOCK
+ HEADER
+
+ PsiErrorElement:Not enough commands
+ MSGID
+ PsiElement(MSGID)('msgid')
+ PsiWhiteSpace(' ')
+ PsiErrorElement:Unbounded string
+ PsiElement(STRING)('"\n')
+ PsiElement(STRING)('""')
+ PsiWhiteSpace('\n')
+ PsiErrorElement:Unbounded string
+ PsiElement(STRING)('"\n')
+ PsiElement(STRING)('"\n"')
\ No newline at end of file
diff --git a/plugins/gettext/test/com/jetbrains/gettext/lexer/without_comments.po b/plugins/gettext/test/com/jetbrains/gettext/lexer/without_comments.po
new file mode 100644
index 000000000000..57013dc8ca86
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/lexer/without_comments.po
@@ -0,0 +1,4 @@
+msgid "str-to-translate"
+msgstr "translated str"
+msgid "one more"
+msgstr "one more translated str"
diff --git a/plugins/gettext/test/com/jetbrains/gettext/lexer/without_comments.txt b/plugins/gettext/test/com/jetbrains/gettext/lexer/without_comments.txt
new file mode 100644
index 000000000000..1a7772639825
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/lexer/without_comments.txt
@@ -0,0 +1,20 @@
+MSGID ('msgid')
+WHITE_SPACE (' ')
+STRING ('"str-to-translate"')
+WHITE_SPACE ('
+')
+MSGSTR ('msgstr')
+WHITE_SPACE (' ')
+STRING ('"translated str"')
+WHITE_SPACE ('
+')
+MSGID ('msgid')
+WHITE_SPACE (' ')
+STRING ('"one more"')
+WHITE_SPACE ('
+')
+MSGSTR ('msgstr')
+WHITE_SPACE (' ')
+STRING ('"one more translated str"')
+WHITE_SPACE ('
+')
\ No newline at end of file
diff --git a/plugins/gettext/test/com/jetbrains/gettext/lexer/without_comments_parser.txt b/plugins/gettext/test/com/jetbrains/gettext/lexer/without_comments_parser.txt
new file mode 100644
index 000000000000..36393b9f709c
--- /dev/null
+++ b/plugins/gettext/test/com/jetbrains/gettext/lexer/without_comments_parser.txt
@@ -0,0 +1,29 @@
+GNU GetText File
+ MSG_BLOCK
+ HEADER
+
+ MSG_CONTENT
+ MSGID
+ PsiElement(MSGID)('msgid')
+ PsiWhiteSpace(' ')
+ PsiElement(STRING)('"str-to-translate"')
+ PsiWhiteSpace('\n')
+ MSGSTR
+ PsiElement(MSGSTR)('msgstr')
+ PsiWhiteSpace(' ')
+ PsiElement(STRING)('"translated str"')
+ PsiWhiteSpace('\n')
+ MSG_BLOCK
+ HEADER
+
+ MSG_CONTENT
+ MSGID
+ PsiElement(MSGID)('msgid')
+ PsiWhiteSpace(' ')
+ PsiElement(STRING)('"one more"')
+ PsiWhiteSpace('\n')
+ MSGSTR
+ PsiElement(MSGSTR)('msgstr')
+ PsiWhiteSpace(' ')
+ PsiElement(STRING)('"one more translated str"')
+ PsiWhiteSpace('\n')
\ No newline at end of file