55269b764eefb9c08a5aa55517ebea5e3c6c50d7
[idea/community.git] / platform / editor-ui-api / src / com / intellij / openapi / editor / CaretModel.java
1 /*
2  * Copyright 2000-2017 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.openapi.editor;
17
18 import com.intellij.openapi.editor.event.CaretListener;
19 import com.intellij.openapi.editor.markup.TextAttributes;
20 import org.jetbrains.annotations.NotNull;
21 import org.jetbrains.annotations.Nullable;
22
23 import java.util.List;
24
25 /**
26  * Provides services for moving the caret and retrieving information about caret position.
27  *
28  * May support several carets existing simultaneously in a document. {@link #supportsMultipleCarets()} method can be used to find out
29  * whether particular instance of CaretModel does it. If it does, query and update methods for caret position operate on a certain 'primary'
30  * caret. There exists a way to perform the same operation(s) on each caret - see
31  * {@link #runForEachCaret(CaretAction)} method. Within its context, query and update methods operate on the
32  * current caret in that iteration. This behaviour can change in future though, so using caret and selection query and update methods in
33  * actions that need to operate on multiple carets is discouraged - methods on {@link Caret} instances obtained
34  * via {@link #getAllCarets()} or {@link #runForEachCaret(CaretAction)} should be used instead.
35  * <p>
36  * How 'primary' caret is determined by the model is not defined (currently it's the most recently added caret, but that can change).
37  * <p>
38  * At all times at least one caret will exist in a document.
39  * <p>
40  * Update methods, {@link #runBatchCaretOperation(Runnable)} and {@link #runForEachCaret(CaretAction)} methods
41  * should only be run from EDT. Query methods can be run from any thread, when called not from EDT, those methods are 'not aware' of
42  * 'runForEachCaret' scope - they will always return information about primary caret.
43  *
44  * @see Editor#getCaretModel()
45  */
46 public interface CaretModel {
47   /**
48    * Moves the caret by the specified number of lines and/or columns.
49    *
50    * @param columnShift    the number of columns to move the caret by.
51    * @param lineShift      the number of lines to move the caret by.
52    * @param withSelection  if true, the caret move should extend the selection range in the document.
53    * @param blockSelection This parameter is currently ignored.
54    * @param scrollToCaret  if true, the document should be scrolled so that the caret is visible after the move.
55    */
56   void moveCaretRelatively(int columnShift,
57                            int lineShift,
58                            boolean withSelection,
59                            boolean blockSelection,
60                            boolean scrollToCaret);
61
62   /**
63    * Moves the caret to the specified logical position.
64    * If corresponding position is in the folded region currently, the region will be expanded.
65    *
66    * @param pos the position to move to.
67    */
68   void moveToLogicalPosition(@NotNull LogicalPosition pos);
69
70   /**
71    * Moves the caret to the specified visual position.
72    *
73    * @param pos the position to move to.
74    */
75   void moveToVisualPosition(@NotNull VisualPosition pos);
76
77   /**
78    * Short hand for calling {@link #moveToOffset(int, boolean)} with <code>'false'</code> as a second argument.
79    *
80    * @param offset      the offset to move to
81    */
82   void moveToOffset(int offset);
83
84   /**
85    * Moves the caret to the specified offset in the document.
86    * If corresponding position is in the folded region currently, the region will be expanded.
87    *
88    * @param offset                  the offset to move to.
89    * @param locateBeforeSoftWrap    there is a possible case that there is a soft wrap at the given offset, hence, the same offset
90    *                                corresponds to two different visual positions - just before soft wrap and just after soft wrap.
91    *                                We may want to clearly indicate where to put the caret then. Given parameter allows to do that.
92    *                                <b>Note:</b> it's ignored if there is no soft wrap at the given offset
93    */
94   void moveToOffset(int offset, boolean locateBeforeSoftWrap);
95
96   /**
97    * Caret position may be updated on document change (e.g. consider that user updates from VCS that causes addition of text
98    * before caret. Caret offset, visual and logical positions should be updated then). So, there is a possible case
99    * that caret model in in the process of caret position update now.
100    * <p/>
101    * Current method allows to check that.
102    *
103    * @return    <code>true</code> if caret position is up-to-date for now; <code>false</code> otherwise
104    */
105   boolean isUpToDate();
106
107   /**
108    * Returns the logical position of the caret.
109    *
110    * @return the caret position.
111    */
112   @NotNull
113   LogicalPosition getLogicalPosition();
114
115   /**
116    * Returns the visual position of the caret.
117    *
118    * @return the caret position.
119    */
120   @NotNull
121   VisualPosition getVisualPosition();
122
123   /**
124    * Returns the offset of the caret in the document.
125    *
126    * @return the caret offset.
127    */
128   int getOffset();
129
130   /**
131    * Adds a listener for receiving notifications about caret movement and caret addition/removal
132    *
133    * @param listener the listener instance.
134    */
135   void addCaretListener(@NotNull CaretListener listener);
136
137   /**
138    * Removes a listener for receiving notifications about caret movement and caret addition/removal
139    *
140    * @param listener the listener instance.
141    */
142   void removeCaretListener(@NotNull CaretListener listener);
143
144   /**
145    * @return    document offset for the start of the logical line where caret is located
146    */
147   int getVisualLineStart();
148
149   /**
150    * @return    document offset that points to the first symbol shown at the next visual line after the one with caret on it
151    */
152   int getVisualLineEnd();
153
154   /**
155    * Returns visual representation of caret (e.g. background color).
156    *
157    * @return Caret attributes.
158    */
159   TextAttributes getTextAttributes();
160
161   /**
162    * Tells whether multiple coexisting carets are supported by this CaretModel instance. Multiple carets
163    * are not supported when the corresponding Editor instance is a facade over a Swing JTextArea component.
164    */
165   boolean supportsMultipleCarets();
166
167   /**
168    * Returns current caret - the one, query and update methods in the model operate at the moment. In the current implementation this is
169    * either an iteration-current caret within the context of {@link #runForEachCaret(CaretAction)} method, or the 'primary' caret without that
170    * context. Users {@link #runForEachCaret(CaretAction)} method should use caret parameter passed to
171    * {@link CaretAction#perform(Caret)} method instead of this method, as the definition of current caret (as
172    * well as caret instance operated on by model methods) can potentially change.
173    */
174   @NotNull
175   Caret getCurrentCaret();
176
177   /**
178    * Returns the 'primary' caret.
179    */
180   @NotNull
181   Caret getPrimaryCaret();
182
183   /**
184    * Returns number of carets currently existing in the document
185    */
186   int getCaretCount();
187
188   /**
189    * Returns all carets currently existing in the document, ordered by their position in the document.
190    */
191   @NotNull
192   List<Caret> getAllCarets();
193
194   /**
195    * Returns a caret at the given position in the document, or <code>null</code>, if there's no caret there.
196    */
197   @Nullable
198   Caret getCaretAt(@NotNull VisualPosition pos);
199
200   /**
201    * Same as {@link #addCaret(VisualPosition, boolean)} with <code>true</code> as a <code>makePrimary</code> boolean parameter value.
202    */
203   @Nullable
204   Caret addCaret(@NotNull VisualPosition pos);
205
206   /**
207    * Adds a new caret at the given position, and returns corresponding {@link Caret} instance. Locations outside of possible values
208    * for the given document are trimmed automatically.
209    * Newly added caret will become a primary caret if and only if <code>makePrimary</code> value is <code>true</code>.
210    * Does nothing if multiple carets are not supported, a caret already exists at specified location or selection of existing caret
211    * includes the specified location, <code>null</code> is returned in this case.
212    */
213   @Nullable
214   Caret addCaret(@NotNull VisualPosition pos, boolean makePrimary);
215
216   /**
217    * Removes a given caret if it's recognized by the model and is not the only existing caret in the document, returning <code>true</code>.
218    * <code>false</code> is returned if any of the above condition doesn't hold, and the removal cannot happen.
219    */
220   boolean removeCaret(@NotNull Caret caret);
221
222   /**
223    * Removes all carets except the 'primary' one from the document.
224    */
225   void removeSecondaryCarets();
226
227   /**
228    * Sets the number of carets, their positions and selection ranges according to the provided data. Null values for caret position or
229    * selection boundaries will mean that corresponding caret's position and/or selection won't be changed.
230    * <p>
231    * System selection will be updated, if such feature is supported by current editor.
232    *
233    * @throws IllegalArgumentException if {@code caretStates} list is empty, or if it contains more than one element and editor doesn't
234    * support multiple carets
235    *
236    * @see #supportsMultipleCarets()
237    * @see #getCaretsAndSelections()
238    * @see #setCaretsAndSelections(List, boolean)
239    */
240   void setCaretsAndSelections(@NotNull List<CaretState> caretStates);
241
242   /**
243    * Sets the number of carets, their positions and selection ranges according to the provided data. Null values for caret position or
244    * selection boundaries will mean that corresponding caret's position and/or selection won't be changed.
245    * <p>
246    * System selection will be updated, if such feature is supported by current editor
247    * and corresponding invocation parameter is set to <code>true</code>.
248    *
249    * @throws IllegalArgumentException if {@code caretStates} list is empty, or if it contains more than one element and editor doesn't
250    * support multiple carets
251    *
252    * @see #supportsMultipleCarets()
253    * @see #getCaretsAndSelections()
254    */
255   void setCaretsAndSelections(@NotNull List<CaretState> caretStates, boolean updateSystemSelection);
256
257   /**
258    * Returns the current positions of all carets and their selections. The order of entries in the returned list does not necessarily
259    * correspond to the order of {@link #getAllCarets()} method results. Passing the result of this method to
260    * {@link #setCaretsAndSelections(List)} will restore the state of carets, including the internal caret order, in particular,
261    * the caret, that was primary when this method was called, will be the primary one after corresponding
262    * {@link #setCaretsAndSelections(List)} invocation.
263    *
264    * @see #setCaretsAndSelections(List)
265    */
266   @NotNull
267   List<CaretState> getCaretsAndSelections();
268
269   /**
270    * Same as {@link #runForEachCaret(CaretAction, boolean)} with <code>reverseOrder</code> set to <code>false</code>
271    */
272   void runForEachCaret(@NotNull CaretAction action);
273
274   /**
275    * Executes the given task for each existing caret. Set of carets to iterate over is
276    * determined in the beginning and is not affected by the potential carets addition or removal by the task being executed.
277    * At the end, merging of carets and selections is performed, so that no two carets will occur at the same logical position and
278    * no two selection will overlap after this method is finished.
279    * <p>
280    * Carets are iterated in position order (top-to-bottom) if <code>reverseOrder</code> is <code>false</code>, and in reverse order
281    * if it's <code>true</code>.
282    */
283   void runForEachCaret(@NotNull CaretAction action, boolean reverseOrder);
284
285   /**
286    * Executes the given task, performing caret merging afterwards. Caret merging will not happen until the operation is finished.
287    */
288   void runBatchCaretOperation(@NotNull Runnable runnable);
289 }