/* * The MIT License (MIT) * * Copyright (c) 2017 hsz Jakub Chrzanowski <jakub@hsz.mobi> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package mobi.hsz.idea.gitignore.lang; import com.intellij.lang.ASTNode; import com.intellij.lang.Language; import com.intellij.lang.ParserDefinition; import com.intellij.lang.PsiParser; import com.intellij.lexer.Lexer; import com.intellij.openapi.project.Project; import com.intellij.psi.FileViewProvider; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.TokenType; import com.intellij.psi.tree.IFileElementType; import com.intellij.psi.tree.TokenSet; import mobi.hsz.idea.gitignore.file.type.IgnoreFileType; import mobi.hsz.idea.gitignore.lexer.IgnoreLexerAdapter; import mobi.hsz.idea.gitignore.parser.IgnoreParser; import mobi.hsz.idea.gitignore.psi.IgnoreFile; import mobi.hsz.idea.gitignore.psi.IgnoreTypes; import org.jetbrains.annotations.NotNull; /** * Defines the implementation of a parser for a custom language. * * @author Jakub Chrzanowski <jakub@hsz.mobi> * @since 0.1 */ public class IgnoreParserDefinition implements ParserDefinition { /** Whitespaces. */ public static final TokenSet WHITE_SPACES = TokenSet.create(TokenType.WHITE_SPACE); /** Regular comment started with # */ public static final TokenSet COMMENTS = TokenSet.create(IgnoreTypes.COMMENT); /** Section comment started with ## */ public static final TokenSet SECTIONS = TokenSet.create(IgnoreTypes.SECTION); /** Header comment started with ### */ public static final TokenSet HEADERS = TokenSet.create(IgnoreTypes.HEADER); /** Negation element - ! in the beginning of the entry */ public static final TokenSet NEGATIONS = TokenSet.create(IgnoreTypes.NEGATION); /** Brackets [] */ public static final TokenSet BRACKETS = TokenSet.create(IgnoreTypes.BRACKET_LEFT, IgnoreTypes.BRACKET_RIGHT); /** Slashes / */ public static final TokenSet SLASHES = TokenSet.create(IgnoreTypes.SLASH); /** Syntax syntax: */ public static final TokenSet SYNTAXES = TokenSet.create(IgnoreTypes.SYNTAX_KEY); /** All values - parts of paths */ public static final TokenSet VALUES = TokenSet.create(IgnoreTypes.VALUE); /** Element type of the node describing a file in the specified language. */ public static final IFileElementType FILE = new IFileElementType(Language.findInstance(IgnoreLanguage.class)); /** * Returns the lexer for lexing files in the specified project. This lexer does not need to support incremental * relexing - it is always called for the entire file. * * @param project the project to which the lexer is connected. * @return the lexer instance. */ @NotNull @Override public Lexer createLexer(Project project) { return new IgnoreLexerAdapter(project); } /** * Returns the parser for parsing files in the specified project. * * @param project the project to which the parser is connected. * @return the parser instance. */ @Override public PsiParser createParser(Project project) { return new IgnoreParser(); } /** * Returns the element type of the node describing a file in the specified language. * * @return the file node element type. */ @Override public IFileElementType getFileNodeType() { return FILE; } /** * Returns the set of token types which are treated as whitespace by the PSI builder. Tokens of those types are * automatically skipped by PsiBuilder. Whitespace elements on the bounds of nodes built by PsiBuilder are * automatically excluded from the text range of the nodes. <p><strong>It is strongly advised you return TokenSet * that only contains {@link com.intellij.psi.TokenType#WHITE_SPACE}, which is suitable for all the languages unless * you really need to use special whitespace token</strong> * * @return the set of whitespace token types. */ @NotNull @Override public TokenSet getWhitespaceTokens() { return WHITE_SPACES; } /** * Returns the set of token types which are treated as comments by the PSI builder. * Tokens of those types are automatically skipped by PsiBuilder. Also, To Do patterns * are searched in the text of tokens of those types. * * @return the set of comment token types. */ @NotNull @Override public TokenSet getCommentTokens() { return COMMENTS; } /** * Returns the set of element types which are treated as string literals. "Search in strings" * option in refactorings is applied to the contents of such tokens. * * @return the set of string literal element types. */ @NotNull @Override public TokenSet getStringLiteralElements() { return TokenSet.EMPTY; } /** * Creates a PSI element for the specified AST node. The AST tree is a simple, semantic-free * tree of AST nodes which is built during the PsiBuilder parsing pass. The PSI tree is built * over the AST tree and includes elements of different types for different language constructs. * * @param node the node for which the PSI element should be returned. * @return the PSI element matching the element type of the AST node. */ @NotNull @Override public PsiElement createElement(ASTNode node) { return IgnoreTypes.Factory.createElement(node); } /** * Creates a PSI element for the specified virtual file. * * @param viewProvider virtual file. * @return the PSI file element. */ @Override public PsiFile createFile(FileViewProvider viewProvider) { if (viewProvider.getBaseLanguage() instanceof IgnoreLanguage) { return ((IgnoreLanguage) viewProvider.getBaseLanguage()).createFile(viewProvider); } return new IgnoreFile(viewProvider, IgnoreFileType.INSTANCE); } /** * Checks if the specified two token types need to be separated by a space according to the language grammar. For * example, in Java two keywords are always separated by a space; a keyword and an opening parenthesis may be * separated or not separated. This is used for automatic whitespace insertion during AST modification operations. * * @param left the first token to check. * @param right the second token to check. * @return the spacing requirements. * * @since 6.0 */ @Override public SpaceRequirements spaceExistanceTypeBetweenTokens(ASTNode left, ASTNode right) { return SpaceRequirements.MAY; } }