/* * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intellij.openapi.editor.impl.softwrap.mapping; import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.impl.EditorTextRepresentationHelper; import org.jetbrains.annotations.NotNull; /** * Utility class that is assumed to be used for internal purposes only. *

* Allows to hold complete information about particular position of document exposed via IJ editor and provides utility * methods for working with it. * * @author Denis Zhdanov * @since Sep 1, 2010 12:16:38 PM */ class EditorPosition implements Cloneable { public int logicalLine; public int logicalColumn; public int visualLine; public int visualColumn; public int offset; public int softWrapLinesBefore; public int softWrapLinesCurrent; public int softWrapColumnDiff; public int foldedLines; public int foldingColumnDiff; public int x; public char symbol; public int symbolWidthInColumns; public int symbolWidthInPixels; private final Editor myEditor; private final EditorTextRepresentationHelper myRepresentationHelper; EditorPosition(@NotNull Editor editor, @NotNull EditorTextRepresentationHelper representationHelper) { myEditor = editor; myRepresentationHelper = representationHelper; } EditorPosition(@NotNull LogicalPosition logical, int offset, @NotNull Editor editor, @NotNull EditorTextRepresentationHelper representationHelper) { this(logical, logical.toVisualPosition(), offset, editor, representationHelper); } EditorPosition(@NotNull LogicalPosition logical, @NotNull VisualPosition visual, int offset, @NotNull Editor editor, @NotNull EditorTextRepresentationHelper representationHelper) { myEditor = editor; myRepresentationHelper = representationHelper; logicalLine = logical.line; logicalColumn = logical.column; softWrapLinesBefore = logical.softWrapLinesBeforeCurrentLogicalLine; softWrapLinesCurrent = logical.softWrapLinesOnCurrentLogicalLine; softWrapColumnDiff = logical.softWrapColumnDiff; foldedLines = logical.foldedLines; foldingColumnDiff = logical.foldingColumnDiff; visualLine = visual.line; visualColumn = visual.column; this.offset = offset; } @NotNull public LogicalPosition buildLogicalPosition() { return new LogicalPosition( logicalLine, logicalColumn, softWrapLinesBefore, softWrapLinesCurrent, softWrapColumnDiff, foldedLines, foldingColumnDiff ); } @NotNull public VisualPosition buildVisualPosition() { return new VisualPosition(visualLine, visualColumn); } /** * Asks current position to change its state assuming that it should point to the start of the next visual line. * * @param softWrapAware flag that indicates if state update should check if current visual line ends with soft wrap */ public void onNewLine(boolean softWrapAware) { if (!softWrapAware || myEditor.getSoftWrapModel().getSoftWrap(offset) == null) { onNewLine(); return; } softWrapLinesCurrent++; softWrapColumnDiff = -logicalColumn - foldingColumnDiff; visualLine++; visualColumn = 0; x = 0; } /** * Similar as {@link #onNewLine(boolean)} with 'false' argument. */ public void onNewLine() { softWrapLinesBefore += softWrapLinesCurrent; softWrapLinesCurrent = 0; softWrapColumnDiff = 0; foldingColumnDiff = 0; visualLine++; visualColumn = 0; logicalLine++; logicalColumn = 0; x = 0; offset++; } /** * Updates state of the current processing position in order to point it to the end offset of the given fold region. * * @param foldRegion fold region which end offset should be pointed by the current position * @param collapsedSymbolsWidthInColumns identifies collapsed text width in columns, i.e. width of the last collapsed logical line * in columns, negative value, if it's unknown and needs to be calculated */ public void advance(@NotNull FoldRegion foldRegion, int collapsedSymbolsWidthInColumns) { // We assume that fold region placeholder contains only 'simple' symbols, i.e. symbols that occupy single visual column. String placeholder = foldRegion.getPlaceholderText(); visualColumn += placeholder.length(); offset = foldRegion.getEndOffset(); Document document = myEditor.getDocument(); int endOffsetLogicalLine = document.getLineNumber(foldRegion.getEndOffset()); if (logicalLine == endOffsetLogicalLine) { // Single-line fold region. if (collapsedSymbolsWidthInColumns < 0) { collapsedSymbolsWidthInColumns = myRepresentationHelper.toVisualColumnSymbolsNumber(document.getCharsSequence(), foldRegion.getStartOffset(), foldRegion.getEndOffset(), x); } logicalColumn += collapsedSymbolsWidthInColumns; foldingColumnDiff += placeholder.length() - collapsedSymbolsWidthInColumns; } else { // Multi-line fold region. if (collapsedSymbolsWidthInColumns < 0) { collapsedSymbolsWidthInColumns = myRepresentationHelper.toVisualColumnSymbolsNumber(document.getCharsSequence(), foldRegion.getStartOffset(), foldRegion.getEndOffset(), 0); } int linesDiff = endOffsetLogicalLine - logicalLine; logicalLine += linesDiff; foldedLines += linesDiff; logicalColumn = collapsedSymbolsWidthInColumns; foldingColumnDiff = visualColumn - logicalColumn - softWrapColumnDiff; } } public void from(@NotNull EditorPosition position) { logicalLine = position.logicalLine; logicalColumn = position.logicalColumn; visualLine = position.visualLine; visualColumn = position.visualColumn; offset = position.offset; softWrapLinesBefore = position.softWrapLinesBefore; softWrapLinesCurrent = position.softWrapLinesCurrent; softWrapColumnDiff = position.softWrapColumnDiff; foldedLines = position.foldedLines; foldingColumnDiff = position.foldingColumnDiff; x = position.x; symbol = position.symbol; symbolWidthInColumns = position.symbolWidthInColumns; symbolWidthInPixels = position.symbolWidthInPixels; } @Override protected EditorPosition clone() { EditorPosition result = new EditorPosition(myEditor, myRepresentationHelper); result.logicalLine = logicalLine; result.logicalColumn = logicalColumn; result.visualLine = visualLine; result.visualColumn = visualColumn; result.offset = offset; result.softWrapLinesBefore = softWrapLinesBefore; result.softWrapLinesCurrent = softWrapLinesCurrent; result.softWrapColumnDiff = softWrapColumnDiff; result.foldedLines = foldedLines; result.foldingColumnDiff = foldingColumnDiff; result.x = x; result.symbol = symbol; result.symbolWidthInColumns = symbolWidthInColumns; result.symbolWidthInPixels = symbolWidthInPixels; return result; } @Override public String toString() { return String.format( "visual position: (%d; %d); logical position: (%d; %d); offset: %d; soft wraps: before=%d, current=%d, column diff=%d; " + "fold regions: lines=%d, column diff=%d", visualLine, visualColumn, logicalLine, logicalColumn, offset, softWrapLinesBefore, softWrapLinesCurrent, softWrapColumnDiff, foldedLines, foldingColumnDiff); } }