Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial plugin setup, including naive lexer.

  • Loading branch information...
commit 5cab3cb41b49a8ab2cabe1d41005e2f9e58a8436 0 parents
Daniel Marcotte authored
30 .gitignore
@@ -0,0 +1,30 @@
+# Numerous always-ignore extensions
+*.diff
+*.err
+*.orig
+*.log
+*.rej
+*.swo
+*.swp
+*.vi
+*~
+*.sass-cache
+*.iml
+
+# OS or Editor folders
+.DS_Store
+.cache
+.project
+.settings
+.tmproj
+nbproject
+Thumbs.db
+
+# Folders to ignore
+.hg
+.svn
+.CVS
+intermediate
+publish
+target
+.idea
24 META-INF/plugin.xml
@@ -0,0 +1,24 @@
+<idea-plugin version="2">
+ <name>Google Closure Templates (Soy) for Idea</name>
+ <description>Google Closure Templates (Soy) Plug-in</description>
+ <version>0.1</version>
+ <vendor>https://github.com/dmarcotte</vendor>
+ <idea-version since-build="8000"/>
+
+ <application-components>
+ <!-- Add your application components here -->
+ </application-components>
+
+ <project-components>
+ <!-- Add your project components here -->
+ </project-components>
+
+ <actions>
+ <!-- Add your actions here -->
+ </actions>
+
+ <extensions defaultExtensionNs="com.intellij">
+ <fileTypeFactory implementation="com.dmarcotte.handlebars.HbFileTypeFactory" />
+ <lang.parserDefinition language="Handlebars" implementationClass="com.dmarcotte.handlebars.parsing.HbParseDefinition" />
+ </extensions>
+</idea-plugin>
4 readme.md
@@ -0,0 +1,4 @@
+
+
+Special thanks to the https://github.com/juzna/intellij-latte project (for having a clean code-base to learn from,
+and taking the time to make posts like this gem: http://devnet.jetbrains.net/message/5450284?tstart=0)
BIN  resources/icons/closure_logo.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1  resources/messages/HbBundle.properties
@@ -0,0 +1 @@
+hb.files.file.type.description=Handlebars Templates
33 src/com/dmarcotte/handlebars/HbBundle.java
@@ -0,0 +1,33 @@
+package com.dmarcotte.handlebars;
+
+import com.intellij.CommonBundle;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.PropertyKey;
+
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
+import java.util.ResourceBundle;
+
+public class HbBundle {
+ private static Reference<ResourceBundle> ourBundle;
+
+ @NonNls
+ protected static final String PATH_TO_BUNDLE = "messages.HbBundle";
+
+ private HbBundle() {
+ }
+
+ public static String message(@PropertyKey (resourceBundle = PATH_TO_BUNDLE)String key, Object... params) {
+ return CommonBundle.message(getBundle(), key, params);
+ }
+
+ private static ResourceBundle getBundle() {
+ ResourceBundle bundle = null;
+ if (ourBundle != null) bundle = ourBundle.get();
+ if (bundle == null) {
+ bundle = ResourceBundle.getBundle(PATH_TO_BUNDLE);
+ ourBundle = new SoftReference<ResourceBundle>(bundle);
+ }
+ return bundle;
+ }
+}
49 src/com/dmarcotte/handlebars/HbFileType.java
@@ -0,0 +1,49 @@
+package com.dmarcotte.handlebars;
+
+import com.intellij.openapi.fileTypes.LanguageFileType;
+import com.intellij.openapi.util.IconLoader;
+import com.intellij.openapi.vfs.CharsetToolkit;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.encoding.EncodingManager;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.Icon;
+import java.nio.charset.Charset;
+
+public class HbFileType extends LanguageFileType {
+ public static final Icon FILE_ICON = IconLoader.getIcon("/fileTypes/properties.png");
+ public static final LanguageFileType INSTANCE = new HbFileType();
+ @NonNls
+ public static final String DEFAULT_EXTENSION = "handlebars";
+ @NonNls public static final String DOT_DEFAULT_EXTENSION = "."+DEFAULT_EXTENSION;
+
+ private HbFileType() {
+ super(HbLanguage.INSTANCE);
+ }
+
+ @NotNull
+ public String getName() {
+ return "Handlebars";
+ }
+
+ @NotNull
+ public String getDescription() {
+ return HbBundle.message("hb.files.file.type.description");
+ }
+
+ @NotNull
+ public String getDefaultExtension() {
+ return DEFAULT_EXTENSION;
+ }
+
+ public Icon getIcon() {
+ return FILE_ICON;
+ }
+
+ public String getCharset(@NotNull VirtualFile file, final byte[] content) {
+ Charset charset = EncodingManager.getInstance().getDefaultCharsetForPropertiesFiles(file);
+ String defaultCharsetName = charset == null ? CharsetToolkit.getDefaultSystemCharset().name() : charset.name();
+ return defaultCharsetName;
+ }
+}
12 src/com/dmarcotte/handlebars/HbFileTypeFactory.java
@@ -0,0 +1,12 @@
+package com.dmarcotte.handlebars;
+
+import com.intellij.openapi.fileTypes.FileTypeConsumer;
+import com.intellij.openapi.fileTypes.FileTypeFactory;
+import org.jetbrains.annotations.NotNull;
+
+public class HbFileTypeFactory extends FileTypeFactory {
+ @Override
+ public void createFileTypes(@NotNull FileTypeConsumer consumer) {
+ consumer.consume(HbFileType.INSTANCE, HbFileType.DEFAULT_EXTENSION);
+ }
+}
12 src/com/dmarcotte/handlebars/HbLanguage.java
@@ -0,0 +1,12 @@
+package com.dmarcotte.handlebars;
+
+import com.intellij.lang.Language;
+
+public class HbLanguage extends Language {
+ public static final HbLanguage INSTANCE = new HbLanguage();
+
+ public HbLanguage() {
+ super("Handlebars", "text/x-handlebars-template");
+ // dm todo addd SyntaxHighlighterFactory like PropertiesLanguage?
+ }
+}
11 src/com/dmarcotte/handlebars/pages/HbColorsPage.java
@@ -0,0 +1,11 @@
+package com.dmarcotte.handlebars.pages;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: daniel.marcotte
+ * Date: 2/11/12
+ * Time: 10:45 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class HbColorsPage {
+}
17 src/com/dmarcotte/handlebars/parsing/HbElementType.java
@@ -0,0 +1,17 @@
+package com.dmarcotte.handlebars.parsing;
+
+import com.dmarcotte.handlebars.HbLanguage;
+import com.intellij.psi.tree.IElementType;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+public class HbElementType extends IElementType {
+ public HbElementType(@NotNull @NonNls String debugName) {
+ super(debugName, HbLanguage.INSTANCE);
+ }
+
+ @Override
+ public String toString() {
+ return "[Hb] " + super.toString();
+ }
+}
16 src/com/dmarcotte/handlebars/parsing/HbLexer.java
@@ -0,0 +1,16 @@
+package com.dmarcotte.handlebars.parsing;
+
+import com.intellij.lexer.FlexAdapter;
+import java.io.Reader;
+
+public class HbLexer extends FlexAdapter {
+
+ // -------------------------------------------------------
+ // - LOGIC -
+ // -------------------------------------------------------
+
+ public HbLexer() {
+ super(new _HbLexer((Reader) null));
+ }
+
+}
62 src/com/dmarcotte/handlebars/parsing/HbParseDefinition.java
@@ -0,0 +1,62 @@
+package com.dmarcotte.handlebars.parsing;
+
+import com.dmarcotte.handlebars.psi.HbPsiElement;
+import com.dmarcotte.handlebars.psi.HbPsiFile;
+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.TokenSet;
+import org.jetbrains.annotations.NotNull;
+
+public class HbParseDefinition implements ParserDefinition {
+ @NotNull
+ public Lexer createLexer(Project project) {
+ return new HbLexer();
+ }
+
+ public PsiParser createParser(Project project) {
+ return new HbParser();
+ }
+
+ public IFileElementType getFileNodeType() {
+ return HbTokenTypes.FILE;
+ }
+
+ @NotNull
+ public TokenSet getWhitespaceTokens() {
+ return HbTokenTypes.WHITESPACES;
+ }
+
+ @NotNull
+ public TokenSet getCommentTokens() {
+ return HbTokenTypes.COMMENTS;
+ }
+
+ @NotNull
+ public TokenSet getStringLiteralElements() {
+ return HbTokenTypes.STRING_LITERALS;
+ }
+
+ @NotNull
+ public PsiElement createElement(ASTNode node) {
+ IElementType type = node.getElementType();
+
+ // dm todo there may be more work to be done there... check out what latte is up to
+ return new HbPsiElement(node);
+ }
+
+ public PsiFile createFile(FileViewProvider viewProvider) {
+ return new HbPsiFile(viewProvider);
+ }
+
+ public SpaceRequirements spaceExistanceTypeBetweenTokens(ASTNode left, ASTNode right) {
+ return SpaceRequirements.MAY;
+ }
+}
22 src/com/dmarcotte/handlebars/parsing/HbParser.java
@@ -0,0 +1,22 @@
+package com.dmarcotte.handlebars.parsing;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.lang.PsiBuilder;
+import com.intellij.lang.PsiParser;
+import com.intellij.psi.tree.IElementType;
+import org.jetbrains.annotations.NotNull;
+
+public class HbParser implements PsiParser {
+ @NotNull
+ public ASTNode parse(IElementType root, PsiBuilder builder) {
+ final PsiBuilder.Marker rootMarker = builder.mark();
+
+ while (!builder.eof()) {
+ builder.advanceLexer();
+ }
+
+ rootMarker.done(root);
+
+ return builder.getTreeBuilt();
+ }
+}
38 src/com/dmarcotte/handlebars/parsing/HbTokenTypes.java
@@ -0,0 +1,38 @@
+package com.dmarcotte.handlebars.parsing;
+
+import com.dmarcotte.handlebars.HbLanguage;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.tree.IFileElementType;
+import com.intellij.psi.tree.TokenSet;
+
+public class HbTokenTypes {
+
+ /**
+ * private constructor since this is a constants class
+ */
+ private HbTokenTypes() {}
+
+ public static final IElementType WHITE_SPACE = new HbElementType("WHITE_SPACE");
+ public static final IElementType COMMENT = new HbElementType("COMMENT");
+ public static final IElementType CONTENT = new HbElementType("CONTENT");
+ public static final IElementType OPEN_PARTIAL = new HbElementType("OPEN_PARTIAL");
+ public static final IElementType OPEN_BLOCK = new HbElementType("OPEN_BLOCK");
+ public static final IElementType OPEN_ENDBLOCK = new HbElementType("OPEN_ENDBLOCK");
+ public static final IElementType OPEN_INVERSE = new HbElementType("OPEN_INVERSE");
+ public static final IElementType OPEN_UNESCAPED = new HbElementType("OPEN_UNESCAPED");
+ public static final IElementType OPEN = new HbElementType("OPEN");
+ public static final IElementType EQUALS = new HbElementType("EQUALS");
+ public static final IElementType ID = new HbElementType("ID");
+ public static final IElementType SEP = new HbElementType("SEP");
+ public static final IElementType CLOSE = new HbElementType("CLOSE");
+ public static final IElementType BOOLEAN = new HbElementType("BOOLEAN");
+ public static final IElementType INTEGER = new HbElementType("INTEGER");
+ public static final IElementType INVALID = new HbElementType("INVALID");
+ public static final IElementType REG_TAG_EXPRESSION = new HbElementType("REG_TAG_EXPRESSION");
+
+ public static final IFileElementType FILE = new IFileElementType("FILE", HbLanguage.INSTANCE);
+
+ public static final TokenSet WHITESPACES = TokenSet.create(WHITE_SPACE);
+ public static final TokenSet COMMENTS = TokenSet.create(COMMENT);
+ public static final TokenSet STRING_LITERALS = TokenSet.create();
+}
87 src/com/dmarcotte/handlebars/parsing/handlebars.flex
@@ -0,0 +1,87 @@
+//[^\x00]*?/("{{") {
+// if(yytext.slice(-1) !== "\\") this.begin("mu");
+// if(yytext.slice(-1) === "\\") yytext = yytext.substr(0,yyleng-1), this.begin("emu");
+// if(yytext) return 'CONTENT';
+// }
+//
+//[^\x00]+ { return 'CONTENT'; }
+//
+//<emu>[^\x00]{2,}?/("{{") { this.popState(); return 'CONTENT'; }
+//
+//<mu>"{{>" { return 'OPEN_PARTIAL'; }
+//<mu>"{{#" { return 'OPEN_BLOCK'; }
+//<mu>"{{/" { return 'OPEN_ENDBLOCK'; }
+//<mu>"{{^" { return 'OPEN_INVERSE'; }
+//<mu>"{{"\s*"else" { return 'OPEN_INVERSE'; }
+//<mu>"{{{" { return 'OPEN_UNESCAPED'; }
+//<mu>"{{&" { return 'OPEN_UNESCAPED'; }
+//<mu>"{{!"[\s\S]*?"}}" { yytext = yytext.substr(3,yyleng-5); this.popState(); return 'COMMENT'; }
+//<mu>"{{" { return 'OPEN'; }
+//
+//<mu>"=" { return 'EQUALS'; }
+//<mu>"."/[} ] { return 'ID'; }
+//<mu>".." { return 'ID'; }
+//<mu>[\/.] { return 'SEP'; }
+//<mu>\s+ { /*ignore whitespace*/ }
+//<mu>"}}}" { this.popState(); return 'CLOSE'; }
+//<mu>"}}" { this.popState(); return 'CLOSE'; }
+//<mu>'"'("\\"["]|[^"])*'"' { yytext = yytext.substr(1,yyleng-2).replace(/\\"/g,'"'); return 'STRING'; }
+//<mu>"true"/[}\s] { return 'BOOLEAN'; }
+//<mu>"false"/[}\s] { return 'BOOLEAN'; }
+//<mu>[0-9]+/[}\s] { return 'INTEGER'; }
+//<mu>[a-zA-Z0-9_$-]+/[=}\s\/.] { return 'ID'; }
+//<mu>'['[^\]]*']' { yytext = yytext.substr(1, yyleng-2); return 'ID'; }
+//<mu>. { return 'INVALID'; }
+//
+//<INITIAL,mu><<EOF>> { return 'EOF'; }
+
+package com.dmarcotte.handlebars.parsing;
+
+import com.intellij.lexer.FlexLexer;
+import com.intellij.psi.tree.IElementType;
+import com.dmarcotte.handlebars.parsing.HbTokenTypes;
+
+%%
+
+%class _HbLexer
+%implements FlexLexer
+%final
+%unicode
+%function advance
+%type IElementType
+%eof{ return;
+%eof}
+
+LineTerminator = \r|\n|\r\n
+WhiteSpace = {LineTerminator} | [ \t\f]
+
+%state CONTENT
+%state HB_TAG_START
+%state HB_REG_TAG_CONTENTS
+%state HB_BLOCK_TAG_CONTENTS
+//%state HB_BLOCK_END
+
+%%
+
+<YYINITIAL, CONTENT> {
+
+ "[^({{)]*" { yypushback(2); yybegin(HB_TAG_START); return HbTokenTypes.CONTENT; }
+
+}
+
+<HB_TAG_START> {
+
+ "{{^[#]" { yybegin(HB_REG_TAG_CONTENTS); return HbTokenTypes.OPEN; }
+ "{{#" { yybegin(HB_BLOCK_TAG_CONTENTS); }
+
+}
+
+<HB_REG_TAG_CONTENTS> {
+
+ ".*}}" { yypushback(2); return HbTokenTypes.REG_TAG_EXPRESSION; }
+ "}}" { yybegin(CONTENT); return HbTokenTypes.CLOSE; }
+
+}
+
+{WhiteSpace}+ { return HbTokenTypes.WHITE_SPACE; }
+. { return HbTokenTypes.INVALID; }
8 src/com/dmarcotte/handlebars/parsing/jflex_generate.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# dm todo probably move this file
+
+# thanks to http://code.google.com/p/google-closure-soy/source/browse/trunk/src/net/intellij/plugins/soy/lexer/build-lexer.cmd
+# for help with the command line switches
+/home/dmarcotte/workspace/code/intellij-community-11.x/tools/lexer/jflex-1.4/bin/jflex --charat --nobak --skel \
+ /home/dmarcotte/workspace/code/intellij-community-11.x/tools/lexer/idea-flex.skeleton -d . --verbose handlebars.flex
16 src/com/dmarcotte/handlebars/psi/HbPsiElement.java
@@ -0,0 +1,16 @@
+package com.dmarcotte.handlebars.psi;
+
+import com.intellij.extapi.psi.ASTWrapperPsiElement;
+import com.intellij.lang.ASTNode;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Base of all PsiElements
+ */
+public class HbPsiElement extends ASTWrapperPsiElement {
+ public HbPsiElement(@NotNull ASTNode astNode) {
+ super(astNode);
+ }
+
+ // some common logic should come here
+}
21 src/com/dmarcotte/handlebars/psi/HbPsiFile.java
@@ -0,0 +1,21 @@
+package com.dmarcotte.handlebars.psi;
+
+import com.dmarcotte.handlebars.HbFileType;
+import com.dmarcotte.handlebars.HbLanguage;
+import com.intellij.extapi.psi.PsiFileBase;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.psi.FileViewProvider;
+import com.intellij.psi.impl.PsiFileEx;
+import org.jetbrains.annotations.NotNull;
+
+public class HbPsiFile extends PsiFileBase implements PsiFileEx {
+
+ public HbPsiFile(@NotNull FileViewProvider viewProvider) {
+ super(viewProvider, HbLanguage.INSTANCE);
+ }
+
+ @NotNull
+ public FileType getFileType() {
+ return HbFileType.INSTANCE;
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.