summaryrefslogtreecommitdiff
path: root/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/EditorPosition.java
blob: 1097f282444525de3528e385c7602831da340297 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/*
 * 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.SoftWrapModelImpl;
import org.jetbrains.annotations.NotNull;

/**
 * Utility class that is assumed to be used for internal purposes only.
 * <p/>
 * 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;

  EditorPosition(@NotNull Editor editor) {
    myEditor = editor;
  }

  EditorPosition(@NotNull LogicalPosition logical,
                 int offset,
                 @NotNull Editor editor)
  {
    this(logical, logical.toVisualPosition(), offset, editor);
  }

  EditorPosition(@NotNull LogicalPosition logical,
                 @NotNull VisualPosition visual,
                 int offset,
                 @NotNull Editor editor)
  {
    myEditor = editor;
    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 <code>'false'</code> 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 = SoftWrapModelImpl.getEditorTextRepresentationHelper(myEditor)
          .toVisualColumnSymbolsNumber(document.getCharsSequence(),
                                       foldRegion.getStartOffset(),
                                       foldRegion.getEndOffset(),
                                       x);
      }
      logicalColumn += collapsedSymbolsWidthInColumns;
      foldingColumnDiff += placeholder.length() - collapsedSymbolsWidthInColumns;
    }
    else {
      // Multi-line fold region.
      if (collapsedSymbolsWidthInColumns < 0) {
        collapsedSymbolsWidthInColumns = SoftWrapModelImpl.getEditorTextRepresentationHelper(myEditor)
          .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);
    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);
  }
}