Search code examples
javapycharmintellij-plugin

Writing a PyCharm extension to display text beside source code


I wrote an Eclipse PyDev plugin, and I'm trying to port it to PyCharm, but I can't find an easy way to display a text view next to the Python source code. Is there any way easier than copying the PsiAwareTextEditorImpl class and all its helpers?

I got the splitter control working so I can display something next to the Python source code. In this prototype branch, I displayed a text editor next to the Python editor. Then I created a text file for each Python file to hold the display text, but that displays the text file's name, and it would be a pain to manage a bunch of temporary files.

I stepped through the standard editor class, PsiAwareTextEditorImpl, and found that it has a ton of helper classes, and eventually calls EditorPainter.paintTextWithEffects(). Here are some of the things it does to paint text:

private void paintTextWithEffects(Graphics2D g, Rectangle clip, int startVisualLine, int endVisualLine) {
    final CharSequence text = myDocument.getImmutableCharSequence();
    // ...
    VisualLinesIterator visLinesIterator = new VisualLinesIterator(myEditor, startVisualLine);
    while (!visLinesIterator.atEnd()) {
        int visualLine = visLinesIterator.getVisualLine();
        if (visualLine > endVisualLine || visualLine >= lineCount) break;

        int y = visLinesIterator.getY();
        final boolean paintSoftWraps = paintAllSoftWraps ||
                myEditor.getCaretModel().getLogicalPosition().line == visLinesIterator.getStartLogicalLine();
        final int[] currentLogicalLine = new int[] {-1};

        paintLineFragments(g, clip, visLinesIterator, y + myView.getAscent(), new LineFragmentPainter() {
            @Override
            public void paintBeforeLineStart(Graphics2D g, TextAttributes attributes, int columnEnd, float xEnd, int y) {
                // ...
            }

            @Override
            public void paint(Graphics2D g, VisualLineFragmentsIterator.Fragment fragment, int start, int end,
                              TextAttributes attributes, float xStart, float xEnd, int y) {
                // ...
            }

            @Override
            public void paintAfterLineEnd(Graphics2D g, Rectangle clip, IterationState iterationState, int columnStart, float x, int y) {
                // ...
            }
        });
        visLinesIterator.advance();
    }
    ComplexTextFragment.flushDrawingCache(g);
}

That seems like a ton of work if I have to reproduce that, so is there some existing component that I can use to display a block of text that isn't coming from a file? Should I be creating my own instance of DocumentImpl and somehow wiring that to an editor?

Here's what the Eclipse plugin looks like with the Python code on the left, and the text display on the right.

Screenshot of Live Coding in Python


Solution

  • You can create instance of LightVirtualFile, fill with any content and display in editor as file of existing type or your custom type.