Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Writing A Plugin for Android Studio

Writing A Plugin for Android Studio

Do you wish you could click autocomplete an exotic language or drill down into framework String parameters? But sadly there's no IDE plugin for that, what a shame.. But do not fear, we have a solution! Let's explore how we could make our own plugin for our favourite tool. We will start with capability overview of plugin API, get into parsers and lexers, syntax highlight, adding buttons to toolbars, etc. As well as briefly cover best practices, build system configurations and deployment to get your plugin into the wilds into the plugin store!

Alexey Buzdin

November 04, 2017
Tweet

More Decks by Alexey Buzdin

Other Decks in Programming

Transcript

  1. RECAP: PLUGIN PROJECT IS A JAVA PROJECT WITH PLUGIN.XML AND

    TARGET SDK - INTELLIJ PRODUCT http://www.jetbrains.org/intellij/sdk/docs/tutorials/customlanguagesupport_tutorial.html
  2. WHAT DID WE ACHIEVE? 1. We’ve written an Action 2.

    Created our own Language 3. Registered a new File Type 4. Added an Icon ☺
  3. MORE ON ACTION: GROUPING ACTIONS <actions> <group id="SimpleGroup" text="Custom Action

    Group" popup="true"> <add-to-group group-id="EditorPopupMenu" anchor="first"/> <action class="org.jetbrains.tutorials.actions.GroupedAction" id="org.jetbrains.tutorials.actions.GroupedAction" text="Grouped Action" description="Grouped Action Demo"> </action> </group> </actions>
  4. MORE ON ACTION: DEFAULTACTIONGROUP public class CustomDefaultActionGroup extends DefaultActionGroup {

    @Override public void update(AnActionEvent event) { Editor editor = event.getData(CommonDataKeys.EDITOR); event.getPresentation().setVisible(true); event.getPresentation().setEnabled(editor != null); event.getPresentation().setIcon(AllIcons.General.Error); } }
  5. LET’S FIX THIS! <hikr.Page ux:Class="EditHikePage"> <Router ux:Dependency="router" /> <JavaScript File="EditHikePage.js"

    /> <DockPanel> <Grid ColumnCount="2" Dock="Bottom"> <hikr.Button Text="Cancel" Clicked="{cancel}" /> <hikr.Button Text="Save" Clicked="{save}" /> </Grid> <ScrollView> <StackPanel ItemSpacing="10" Padding="10"> <hikr.Text ux:Class="TitleText" Opacity=".6" Margin="0,0,0,5" /> <StackPanel> <TitleText>Name:</TitleText> <hikr.TextBox Value="{name}" /> </StackPanel> <StackPanel> <TitleText>Comments:</TitleText> <hikr.TextView Value="{comments}" TextWrapping="Wrap" /> </StackPanel> </StackPanel> </ScrollView> </DockPanel> </hikr.Page>
  6. LET’S FIX THIS! <hikr.Page ux:Class="EditHikePage"> <Router ux:Dependency="router" /> <JavaScript File="EditHikePage.js"

    /> <DockPanel> <Grid ColumnCount="2" Dock="Bottom"> <hikr.Button Text="Cancel" Clicked="{cancel}" /> <hikr.Button Text="Save" Clicked="{save}" /> </Grid> <ScrollView> <StackPanel ItemSpacing="10" Padding="10"> <hikr.Text ux:Class="TitleText" Opacity=".6" Margin="0,0,0,5" /> <StackPanel> <TitleText>Name:</TitleText> <hikr.TextBox Value="{name}" /> </StackPanel> <StackPanel> <TitleText>Comments:</TitleText> <hikr.TextView Value="{comments}" TextWrapping="Wrap" /> </StackPanel> </StackPanel> </ScrollView> </DockPanel> </hikr.Page>
  7. BACKUS–NAUR FORM FOR CSV <file> ::= <line>* <line> ::= <value>?

    | <value>(“,”<value>)+ “,”? <value> ::= [^,]+
  8. Grammar-Kit root_rule ::= rule_A rule_B rule_C rule_D // a sequence

    rule_A ::= token | 'or_text' | "another_one" // a choice rule_B ::= [ optional_token ] and_another_one? // optional parts rule_C ::= &required !forbidden // predicates rule_D ::= { can_use_braces + (and_parens) * } // grouping and repetition // Grammar-Kit extensions: private left rule_with_modifier ::= '+' // rule modifiers left rule_with_attributes ::= '?' {elementType=rule_D} // left rule and attributes private meta list_macro ::= <<p>> (',' <<p>>) * // meta rule private list_usage ::= <<list_macro rule_D>> // external expression https://github.com/JetBrains/Grammar-Kit
  9. package com.simpleplugin; import com.intellij.lexer.FlexLexer; import com.intellij.psi.tree.IElementType; import com.simpleplugin.psi.SimpleTypes; import com.intellij.psi.TokenType;

    %% %class SimpleLexer %implements FlexLexer %unicode %function advance %type IElementType %eof{ return; %eof} CRLF=\R WHITE_SPACE=[\ \n\t\f] FIRST_VALUE_CHARACTER=[^ \n\f\\] | "\\"{CRLF} | "\\". VALUE_CHARACTER=[^\n\f\\] | "\\"{CRLF} | "\\". END_OF_LINE_COMMENT=("#"|"!")[^\r\n]* SEPARATOR=[:=] KEY_CHARACTER=[^:=\ \n\t\f\\] | "\\ "
  10. PROPERTY: KEY = VALUE %state WAITING_VALUE %% <YYINITIAL> {END_OF_LINE_COMMENT} {

    yybegin(YYINITIAL); return SimpleTypes.COMMENT; } <YYINITIAL> {KEY_CHARACTER}+ { yybegin(YYINITIAL); return SimpleTypes.KEY; } <YYINITIAL> {SEPARATOR} { yybegin(WAITING_VALUE); return SimpleTypes.SEPARATOR; } <WAITING_VALUE> {CRLF}({CRLF}|{WHITE_SPACE})+ { yybegin(YYINITIAL); return TokenType.WHITE_SPACE; } <WAITING_VALUE> {WHITE_SPACE}+ { yybegin(WAITING_VALUE); return TokenType.WHITE_SPACE; } <WAITING_VALUE> {FIRST_VALUE_CHARACTER}{VALUE_CHARACTER}* { yybegin(YYINITIAL); return SimpleTypes.VALUE; } ({CRLF}|{WHITE_SPACE})+ { yybegin(YYINITIAL); return TokenType.WHITE_SPACE; } . { return TokenType.BAD_CHARACTER; }
  11. WHAT DID WE ACHIEVE? 1. We’ve described a Parser 2.

    Implemented a Lexer 3. Added some ! NEXT STEPS?
  12. WHAT CAN YOU DO WITH PSIELEMENT 1. References and GoTo

    2. Find Usage 3. Code Completion 4. Annotators 5. Line Marker 6. More