Search code examples
intellij-ideaintellij-plugin

Get context at caret


I'm developing a IntelliJ IDEA plugin to get context at current caret. More specific, I need to get a list of variables' types and names that can be used at caret. For example:

public static void main(String[] args) throws IOException {
    Workbook wb = new HSSFWorkbook();
    // caret 1
    Sheet sheet = wb.createSheet("new sheet");
    Row row = sheet.createRow((short) 1);
    for(int i = 0; i < 5; i++) {
        // caret 2
        row.createCell(i).setCellValue("X");
    }
    // caret 3
}

I need to get wb: Workbook at caret 1, wb: Workbook, sheet: Sheet, row: Row, i: int at caret 2 and wb: Workbook, sheet: Sheet, row: Row at caret 3 because i: int is no longer in the scope.

This link seems related, it suggests file.findElementAt(editor.getCaretModel().getOffset()). This expression returns a PsiElement object. However, when I get context of this object and traverse the context using PsiRecursiveElementVisitor, it will visit elements defined after caret, which doesn't meet my requirement above.

My code:

public class ContextView extends AnAction {

    public void actionPerformed(AnActionEvent event) {
        final Editor editor = event.getRequiredData(CommonDataKeys.EDITOR);
        final Project project = event.getRequiredData(CommonDataKeys.PROJECT);
        //Access document, caret, and selection
        final Document document = editor.getDocument();
        PsiJavaFile javaFile = (PsiJavaFile) PsiDocumentManager.getInstance(project).getPsiFile(document);

        PsiElement currentEle = javaFile.findElementAt(editor.getCaretModel().getOffset());
        PsiElement cxt = currentEle.getContext();

        cxt.accept(new PsiRecursiveElementVisitor() {
            @Override
            public void visitElement(PsiElement element) {
                System.out.println(element.toString());
                super.visitElement(element);
            }
        });
    }
}

So how to solve the problem?


Solution

  • This link seems related, it suggests file.findElementAt(editor.getCaretModel().getOffset()). This expression returns a PsiElement object. However, when I get context of this object and traverse the context using PsiRecursiveElementVisitor, it will visit elements defined after caret, which doesn't meet my requirement above.

    Have you tried com.intellij.psi.util.PsiTreeUtil#getParentOfType(com.intellij.psi.PsiElement, java.lang.Class<T>)? You may fill the first argument with the result of findElementAt, and the second argument with PsiDeclarationStatement.class, which is the Psi class for variable declarations.

    By this you can get the local variable declaration. You can test by sout(parent.getText())