Search in sources :

Example 36 with LogicalPosition

use of com.intellij.openapi.editor.LogicalPosition in project Perl5-IDEA by Camelcade.

the class PerlEnterHeredocClosingHandler method postProcessEnter.

@Override
public Result postProcessEnter(@NotNull PsiFile file, @NotNull Editor editor, @NotNull DataContext dataContext) {
    if (!file.getLanguage().is(PerlLanguage.INSTANCE)) {
        return Result.Continue;
    }
    final CaretModel caretModel = editor.getCaretModel();
    int offset = caretModel.getOffset();
    PsiElement currentElement = file.findElementAt(offset);
    if (currentElement != null && (!(currentElement.getParent() instanceof PerlHeredocElementImpl) || !Perl5CodeInsightSettings.getInstance().HEREDOC_AUTO_INSERTION)) {
        return Result.Continue;
    }
    LogicalPosition currentPosition = caretModel.getLogicalPosition();
    final int enterLine = currentPosition.line - 1;
    final int currentOffset = caretModel.getOffset();
    if (enterLine <= -1 || currentOffset <= 0) {
        return Result.Continue;
    }
    final Document document = editor.getDocument();
    final PsiDocumentManager manager = PsiDocumentManager.getInstance(file.getProject());
    manager.commitDocument(document);
    final int lineStartOffset = document.getLineStartOffset(enterLine);
    PsiElement firstLineElement = file.findElementAt(lineStartOffset);
    if (firstLineElement == null) {
        return Result.Continue;
    }
    HeredocCollector collector = new HeredocCollector(currentOffset - 1);
    PerlPsiUtil.iteratePsiElementsRight(firstLineElement, collector);
    SmartPsiElementPointer<PerlHeredocOpener> lastOpenerPointer = null;
    for (SmartPsiElementPointer<PerlHeredocOpener> currentOpenerPointer : collector.getResult()) {
        PerlHeredocOpener currentOpener = currentOpenerPointer.getElement();
        if (currentOpener == null) {
            // System.err.println("Opener invalidated on reparse");
            return Result.Continue;
        }
        String openerName = currentOpener.getName();
        boolean emptyOpener = StringUtil.isEmpty(openerName);
        PsiReference inboundReference = ReferencesSearch.search(currentOpener).findFirst();
        if (inboundReference != null) {
            boolean falseAlarm = false;
            PsiElement run = inboundReference.getElement().getPrevSibling();
            while (run instanceof PsiWhiteSpace) {
                run = run.getPrevSibling();
            }
            if (run instanceof PerlHeredocElementImpl) {
                Pattern openerPattern = EMPTY_OPENER_PATTERN;
                if (!emptyOpener) {
                    openerPattern = Pattern.compile("<<~?(\\s*)(?:" + "\"" + openerName + "\"" + "|" + "`" + openerName + "`" + "|" + "'" + openerName + "'" + "|" + "\\\\" + openerName + "|" + openerName + ")");
                }
                falseAlarm = openerPattern.matcher(run.getNode().getChars()).find();
            }
            if (// looks like overlapping heredocs
            falseAlarm) {
                inboundReference = null;
            } else {
                lastOpenerPointer = currentOpenerPointer;
            }
        }
        if (// disclosed marker
        inboundReference == null) {
            int addOffset;
            String closeMarker = "\n" + openerName + "\n";
            if (// first one
            lastOpenerPointer == null) {
                addOffset = currentOffset;
            } else // sequentional
            {
                PerlHeredocOpener lastOpener = lastOpenerPointer.getElement();
                if (lastOpener == null) {
                    return Result.Continue;
                }
                PsiReference lastOpenerReference = ReferencesSearch.search(lastOpener).findFirst();
                if (lastOpenerReference != null) {
                    PsiElement element = lastOpenerReference.getElement();
                    addOffset = element.getTextRange().getEndOffset();
                    if (!emptyOpener) {
                        closeMarker = "\n" + closeMarker;
                    }
                } else {
                    return Result.Continue;
                }
            }
            document.insertString(addOffset, closeMarker);
            manager.commitDocument(document);
            CodeStyleManager.getInstance(file.getProject()).reformatRange(file, addOffset, addOffset + closeMarker.length());
            currentOpener = currentOpenerPointer.getElement();
            if (currentOpener == null) {
                return Result.Continue;
            }
            inboundReference = ReferencesSearch.search(currentOpener).findFirst();
            if (inboundReference != null) {
                lastOpenerPointer = currentOpenerPointer;
            } else {
                return Result.Continue;
            }
        }
    }
    return Result.Continue;
}
Also used : LogicalPosition(com.intellij.openapi.editor.LogicalPosition) Pattern(java.util.regex.Pattern) CaretModel(com.intellij.openapi.editor.CaretModel) PerlHeredocOpener(com.perl5.lang.perl.psi.PerlHeredocOpener) Document(com.intellij.openapi.editor.Document) PerlHeredocElementImpl(com.perl5.lang.perl.psi.impl.PerlHeredocElementImpl)

Example 37 with LogicalPosition

use of com.intellij.openapi.editor.LogicalPosition in project intellij by bazelbuild.

the class BuildEnterHandler method preprocessEnter.

@Override
public Result preprocessEnter(PsiFile file, Editor editor, Ref<Integer> caretOffset, Ref<Integer> caretAdvance, DataContext dataContext, EditorActionHandler originalHandler) {
    int offset = caretOffset.get();
    if (editor instanceof EditorWindow) {
        file = InjectedLanguageManager.getInstance(file.getProject()).getTopLevelFile(file);
        editor = InjectedLanguageUtil.getTopLevelEditor(editor);
        offset = editor.getCaretModel().getOffset();
    }
    if (!isApplicable(file, dataContext)) {
        return Result.Continue;
    }
    // Previous enter handler's (e.g. EnterBetweenBracesHandler) can introduce a mismatch
    // between the editor's caret model and the offset we've been provided with.
    editor.getCaretModel().moveToOffset(offset);
    Document doc = editor.getDocument();
    PsiDocumentManager.getInstance(file.getProject()).commitDocument(doc);
    CodeStyleSettings currentSettings = CodeStyleSettingsManager.getSettings(file.getProject());
    IndentOptions indentOptions = currentSettings.getIndentOptions(file.getFileType());
    Integer indent = determineIndent(file, editor, offset, indentOptions);
    if (indent == null) {
        return Result.Continue;
    }
    removeTrailingWhitespace(doc, file, offset);
    originalHandler.execute(editor, editor.getCaretModel().getCurrentCaret(), dataContext);
    LogicalPosition position = editor.getCaretModel().getLogicalPosition();
    if (position.column == indent) {
        return Result.Stop;
    }
    if (position.column > indent) {
        // default enter handler has added too many spaces -- remove them
        int excess = position.column - indent;
        doc.deleteString(editor.getCaretModel().getOffset() - excess, editor.getCaretModel().getOffset());
    } else if (position.column < indent) {
        String spaces = StringUtil.repeatSymbol(' ', indent - position.column);
        doc.insertString(editor.getCaretModel().getOffset(), spaces);
    }
    editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(position.line, indent));
    return Result.Stop;
}
Also used : LogicalPosition(com.intellij.openapi.editor.LogicalPosition) CodeStyleSettings(com.intellij.psi.codeStyle.CodeStyleSettings) IndentOptions(com.intellij.psi.codeStyle.CommonCodeStyleSettings.IndentOptions) Document(com.intellij.openapi.editor.Document) EditorWindow(com.intellij.injected.editor.EditorWindow)

Example 38 with LogicalPosition

use of com.intellij.openapi.editor.LogicalPosition in project intellij by bazelbuild.

the class EditorTestHelper method assertCaretPosition.

public void assertCaretPosition(Editor editor, int lineNumber, int columnNumber) {
    CaretInfo info = new CaretInfo(new LogicalPosition(lineNumber, columnNumber), null);
    EditorTestUtil.verifyCaretAndSelectionState(editor, new CaretAndSelectionState(ImmutableList.of(info), null));
}
Also used : CaretInfo(com.intellij.testFramework.EditorTestUtil.CaretInfo) LogicalPosition(com.intellij.openapi.editor.LogicalPosition) CaretAndSelectionState(com.intellij.testFramework.EditorTestUtil.CaretAndSelectionState)

Example 39 with LogicalPosition

use of com.intellij.openapi.editor.LogicalPosition in project intellij-code-outline by sitano.

the class CodeOutlineImage method updateImg.

/**
 * Updates the code outline image to reflect the given document change.
 *
 * @param e a document change event
 * @param oldend the logical position of the end of the "old" changed region
 *        before the change was actually made
 */
private synchronized void updateImg(DocumentEvent e, LogicalPosition oldend) {
    // if there's no image we don't need to do anything
    if (img == null)
        return;
    final int offset = e.getOffset();
    final int newLength = e.getNewLength();
    final int oldLength = e.getOldLength();
    final int width = visibleImgWidth;
    final int height = visibleImgHeight;
    final double scale = this.scale;
    // compute the logical positions of the old and new offsets
    final LogicalPosition start = editor.offsetToLogicalPosition(offset);
    final LogicalPosition newend = editor.offsetToLogicalPosition(offset + newLength);
    // to do
    if (getScaledLine(start.line, scale) >= height)
        return;
    // the number of affected lines
    int affected = Math.abs(newend.line - oldend.line) + 1;
    // to do
    if (affected == 1 && start.column >= width)
        return;
    // the number of lines added (a negative value means lines were removed)
    int addedLines = newend.line - oldend.line;
    /*
         * If lines count changed, then redraw all the stuff if there are:
         * 1. deleted lines
         * 2. scale factor changed (scaling)
         */
    if (addedLines != 0) {
        if (addedLines < 0 || scale < 1.0 || getScaleFactor(height, document.getLineCount()) < 1.0) {
            refreshImage();
            // TODO: Delayed redraw for last timed out change
            listener.shouldRepaint(this, new Rectangle(0, 0, width, height));
            return;
        }
    }
    /*

        This method does the following things:
        1. Copy the (unmodified) rest of the line at the end of the modified
           region
        2. Move all unmodified lines, below the changed region, up or down, if
           lines were added or removed
        3. Clear data at end of line on first line of changed region
        4. Clear middle lines, if any, in the changed region
        5. Clear data at beginning of line on last line of changed region
        6. Paste the data copied in #1 at the new end of region
        7. Re-render any data which was not copied in #6 because of insufficient
           window width
        8. Render the new data in the changed region

        */
    // how much of the end of the last line needs to be cleared
    int needsFilling = Math.max(0, width - newend.column);
    // how much of the end of the old last line needs to be copied to the
    // new end of the last line (this takes into account how much is there,
    // and how much space there is at the end of the new line, so no unused
    // data is copied)
    int charsToCopy = Math.min(needsFilling, Math.max(0, width - oldend.column));
    // copy the (unmodified) rest of the line at the end of the modified
    // region
    WritableRaster raster = img.getRaster();
    Object endOfLine = null;
    int oldEndLine = getScaledLine(oldend.line, scale);
    int newEndLine = getScaledLine(newend.line, scale);
    if (oldEndLine < height && newEndLine < height && charsToCopy > 0) {
        endOfLine = raster.getDataElements(oldend.column, oldEndLine, charsToCopy, 1, null);
    }
    // this never modifies any of the lines containing the modified text.
    if (addedLines != 0) {
        int ol = getScaledLine(oldend.line + 1, scale);
        int nl = getScaledLine(newend.line + 1, scale);
        int fh = height - ol;
        int th = height - nl;
        if (fh > 0 && th > 0) {
            BufferedImage from = img.getSubimage(0, ol, width, fh);
            BufferedImage to = img.getSubimage(0, nl, width, th);
            if (addedLines > 0)
                moveDataDown(from, to);
            else
                moveDataUp(from, to);
        }
    }
    // 1. clear first line chars at end of line
    // 2. clear middle lines
    // 3. clear last line chars at beginning of line
    // 4. copy line data at old end to new end
    // 5. re-render any data which was not copied because of insufficient
    // window width
    // 1.
    int toFill = 0;
    if (affected > 1) {
        toFill = width - Math.min(width, start.column);
    } else if (start.column < newend.column) {
        toFill = Math.min(width - start.column, newend.column - start.column);
    }
    if (toFill > 0) {
        img.setRGB(start.column, getScaledLine(start.line, scale), toFill, 1, emptyLine, 0, toFill);
    }
    if (newend.line != start.line) {
        // 2.
        int last = getScaledLine(Math.min(newend.line, height - 1) - 1, scale);
        for (int i = getScaledLine(start.line + 1, scale); i <= last; i++) {
            img.setRGB(0, i, width, 1, emptyLine, 0, width);
        }
        // 3.
        if (newEndLine < height) {
            int toFillEnd = Math.min(width, newend.column);
            img.setRGB(0, newEndLine, toFillEnd, 1, emptyLine, 0, toFillEnd);
        }
    }
    // 4.
    if (endOfLine != null) {
        // copy old end of line data to new end of line
        raster.setDataElements(newend.column, newEndLine, charsToCopy, 1, endOfLine);
        // clear the rest of the line, if necessary
        int diff = needsFilling - charsToCopy;
        if (diff > 0) {
            img.setRGB(newend.column + charsToCopy, newEndLine, diff, 1, emptyLine, 0, diff);
        }
    }
    // 5.
    int minCharsToCopy = Math.max(0, charsToCopy);
    int missing = needsFilling - minCharsToCopy;
    if (missing > 0) {
        int toClear = newend.column + minCharsToCopy;
        raster.setDataElements(toClear, newEndLine, width - toClear, 1, emptyLine);
        // re-render the last line, since we don't know what the data on
        // that line was, since it was past our right margin
        int renderWidth = renderRestOfLineToImg(offset + newLength + minCharsToCopy);
        int clearx = newend.column + minCharsToCopy + renderWidth;
        if (clearx < width) {
            raster.setDataElements(clearx, newEndLine, width - clearx, 1, emptyLine);
        }
    }
    // render the new text
    final CharSequence nc = e.getNewFragment();
    renderToImg(nc, 0, nc.length(), start);
    // repaint the changed region
    final Rectangle toRepaint = getImgRepaintRect(offset, Math.max(newLength, oldLength));
    if (affected > 1) {
        toRepaint.height = visibleImgHeight - toRepaint.y;
    }
    listener.shouldRepaint(this, toRepaint);
}
Also used : LogicalPosition(com.intellij.openapi.editor.LogicalPosition) WritableRaster(java.awt.image.WritableRaster) BufferedImage(java.awt.image.BufferedImage)

Example 40 with LogicalPosition

use of com.intellij.openapi.editor.LogicalPosition in project intellij-code-outline by sitano.

the class CodeOutlineImage method renderRestOfLineToImg.

/**
 * Renders the characters at the given document offset to the code outline
 * image until the first newline character is reached or until the right
 * edge of the image is reached and no more characters can be rendered.
 *
 * @param startOff the offset into the document at which to start rendering
 * @return how many characters were rendered, not including the newline
 */
protected int renderRestOfLineToImg(int startOff) {
    final CharSequence chars = document.getCharsSequence();
    final int endOff = document.getTextLength();
    if (startOff >= endOff)
        return 0;
    final LogicalPosition startPos = editor.offsetToLogicalPosition(startOff);
    final int line = startPos.line;
    int col = startPos.column;
    int painted = 0;
    for (int i = startOff; i < endOff; i++) {
        final char ch = chars.charAt(i);
        if (ch == '\n' || col >= visibleImgWidth)
            break;
        drawChar(ch, col, line, editor.getColorsScheme().getDefaultForeground());
        painted++;
        col++;
    }
    return painted;
}
Also used : LogicalPosition(com.intellij.openapi.editor.LogicalPosition)

Aggregations

LogicalPosition (com.intellij.openapi.editor.LogicalPosition)106 Document (com.intellij.openapi.editor.Document)16 PsiElement (com.intellij.psi.PsiElement)14 Editor (com.intellij.openapi.editor.Editor)12 TextRange (com.intellij.openapi.util.TextRange)11 VirtualFile (com.intellij.openapi.vfs.VirtualFile)10 EditorEx (com.intellij.openapi.editor.ex.EditorEx)7 CaretModel (com.intellij.openapi.editor.CaretModel)6 NotNull (org.jetbrains.annotations.NotNull)6 RelativePoint (com.intellij.ui.awt.RelativePoint)5 JSFile (com.intellij.lang.javascript.psi.JSFile)4 EditorColorsManager (com.intellij.openapi.editor.colors.EditorColorsManager)4 TextAttributes (com.intellij.openapi.editor.markup.TextAttributes)4 Project (com.intellij.openapi.project.Project)4 PsiFile (com.intellij.psi.PsiFile)4 PsiReference (com.intellij.psi.PsiReference)4 PsiMultiReference (com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference)4 Mark (com.maddyhome.idea.vim.common.Mark)4 HighlightManager (com.intellij.codeInsight.highlighting.HighlightManager)3 EditorWindow (com.intellij.injected.editor.EditorWindow)3