1 // Scintilla source code edit control
3 ** Text document that handles notifications, DBCS, styling, words and end of line.
5 // Copyright 1998-2011 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
16 * A Position is a position within a document between two characters or at the beginning or end.
17 * Sometimes used as a character index where it identifies the character after the position.
20 const Position invalidPosition
= -1;
22 enum EncodingFamily
{ efEightBit
, efUnicode
, efDBCS
};
25 * The range class represents a range of text in a document.
26 * The two values are not sorted as one end may be more significant than the other
27 * as is the case for the selection where the end position is the position of the caret.
28 * If either position is invalidPosition then the range is invalid and most operations will fail.
35 explicit Range(Position pos
=0) :
36 start(pos
), end(pos
) {
38 Range(Position start_
, Position end_
) :
39 start(start_
), end(end_
) {
42 bool operator==(const Range
&other
) const {
43 return (start
== other
.start
) && (end
== other
.end
);
47 return (start
!= invalidPosition
) && (end
!= invalidPosition
);
50 Position
First() const {
51 return (start
<= end
) ? start
: end
;
54 Position
Last() const {
55 return (start
> end
) ? start
: end
;
58 // Is the position within the range?
59 bool Contains(Position pos
) const {
61 return (pos
>= start
&& pos
<= end
);
63 return (pos
<= start
&& pos
>= end
);
67 // Is the character after pos within the range?
68 bool ContainsCharacter(Position pos
) const {
70 return (pos
>= start
&& pos
< end
);
72 return (pos
< start
&& pos
>= end
);
76 bool Contains(Range other
) const {
77 return Contains(other
.start
) && Contains(other
.end
);
80 bool Overlaps(Range other
) const {
82 Contains(other
.start
) ||
83 Contains(other
.end
) ||
84 other
.Contains(start
) ||
90 class DocModification
;
94 * Interface class for regular expression searching
96 class RegexSearchBase
{
98 virtual ~RegexSearchBase() {}
100 virtual long FindText(Document
*doc
, int minPos
, int maxPos
, const char *s
,
101 bool caseSensitive
, bool word
, bool wordStart
, int flags
, int *length
) = 0;
103 ///@return String with the substitutions, must remain valid until the next call or destruction
104 virtual const char *SubstituteByPosition(Document
*doc
, const char *text
, int *length
) = 0;
107 /// Factory function for RegexSearchBase
108 extern RegexSearchBase
*CreateRegexSearch(CharClassify
*charClassTable
);
115 const unsigned char *styles
;
116 StyledText(size_t length_
, const char *text_
, bool multipleStyles_
, int style_
, const unsigned char *styles_
) :
117 length(length_
), text(text_
), multipleStyles(multipleStyles_
), style(style_
), styles(styles_
) {
119 // Return number of bytes from start to before '\n' or end of text.
120 // Return 1 when start is outside text
121 size_t LineLength(size_t start
) const {
123 while ((cur
< length
) && (text
[cur
] != '\n'))
127 size_t StyleAt(size_t i
) const {
128 return multipleStyles
? styles
[i
] : style
;
132 class HighlightDelimiter
{
134 HighlightDelimiter() : isEnabled(false) {
141 firstChangeableLineBefore
= -1;
142 firstChangeableLineAfter
= -1;
145 bool NeedsDrawing(int line
) const {
146 return isEnabled
&& (line
<= firstChangeableLineBefore
|| line
>= firstChangeableLineAfter
);
149 bool IsFoldBlockHighlighted(int line
) const {
150 return isEnabled
&& beginFoldBlock
!= -1 && beginFoldBlock
<= line
&& line
<= endFoldBlock
;
153 bool IsHeadOfFoldBlock(int line
) const {
154 return beginFoldBlock
== line
&& line
< endFoldBlock
;
157 bool IsBodyOfFoldBlock(int line
) const {
158 return beginFoldBlock
!= -1 && beginFoldBlock
< line
&& line
< endFoldBlock
;
161 bool IsTailOfFoldBlock(int line
) const {
162 return beginFoldBlock
!= -1 && beginFoldBlock
< line
&& line
== endFoldBlock
;
165 int beginFoldBlock
; // Begin of current fold block
166 int endFoldBlock
; // End of current fold block
167 int firstChangeableLineBefore
; // First line that triggers repaint before starting line that determined current fold block
168 int firstChangeableLineAfter
; // First line that triggers repaint after starting line that determined current fold block
178 bool performingStyle
; ///< Prevent reentrance
180 explicit LexInterface(Document
*pdoc_
) : pdoc(pdoc_
), instance(0), performingStyle(false) {
182 virtual ~LexInterface() {
184 void Colourise(int start
, int end
);
185 int LineEndTypesSupported();
186 bool UseContainerLexing() const {
187 return instance
== 0;
191 struct RegexError
: public std::runtime_error
{
192 RegexError() : std::runtime_error("regex failure") {}
197 class Document
: PerLine
, public IDocumentWithLineEnd
, public ILoader
{
200 /** Used to pair watcher pointer with user data. */
201 struct WatcherWithUserData
{
204 WatcherWithUserData(DocWatcher
*watcher_
=0, void *userData_
=0) :
205 watcher(watcher_
), userData(userData_
) {
207 bool operator==(const WatcherWithUserData
&other
) const {
208 return (watcher
== other
.watcher
) && (userData
== other
.userData
);
215 CharClassify charClass
;
219 int enteredModification
;
221 int enteredReadOnlyCount
;
224 std::string insertion
;
226 std::vector
<WatcherWithUserData
> watchers
;
228 // ldSize is not real data - it is for dimensions and loops
229 enum lineData
{ ldMarkers
, ldLevels
, ldState
, ldMargin
, ldAnnotation
, ldSize
};
230 PerLine
*perLineData
[ldSize
];
233 RegexSearchBase
*regex
;
240 /// Can also be SC_CP_UTF8 to enable UTF-8 mode
245 int actualIndentInChars
;
248 bool backspaceUnindents
;
249 double durationStyleOneLine
;
251 DecorationList decorations
;
257 int SCI_METHOD
Release();
260 int LineEndTypesSupported() const;
261 bool SetDBCSCodePage(int dbcsCodePage_
);
262 int GetLineEndTypesAllowed() const { return cb
.GetLineEndTypes(); }
263 bool SetLineEndTypesAllowed(int lineEndBitSet_
);
264 int GetLineEndTypesActive() const { return cb
.GetLineEndTypes(); }
265 virtual void InsertLine(int line
);
266 virtual void RemoveLine(int line
);
268 int SCI_METHOD
Version() const {
272 void SCI_METHOD
SetErrorStatus(int status
);
274 Sci_Position SCI_METHOD
LineFromPosition(Sci_Position pos
) const;
275 int ClampPositionIntoDocument(int pos
) const;
276 bool ContainsLineEnd(const char *s
, int length
) const { return cb
.ContainsLineEnd(s
, length
); }
277 bool IsCrLf(int pos
) const;
278 int LenChar(int pos
);
279 bool InGoodUTF8(int pos
, int &start
, int &end
) const;
280 int MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
=true) const;
281 int NextPosition(int pos
, int moveDir
) const;
282 bool NextCharacter(int &pos
, int moveDir
) const; // Returns true if pos changed
283 Sci_Position SCI_METHOD
GetRelativePosition(Sci_Position positionStart
, Sci_Position characterOffset
) const;
284 int GetRelativePositionUTF16(int positionStart
, int characterOffset
) const;
285 int SCI_METHOD
GetCharacterAndWidth(Sci_Position position
, Sci_Position
*pWidth
) const;
286 int SCI_METHOD
CodePage() const;
287 bool SCI_METHOD
IsDBCSLeadByte(char ch
) const;
288 int SafeSegment(const char *text
, int length
, int lengthSegment
) const;
289 EncodingFamily
CodePageFamily() const;
291 // Gateways to modifying document
292 void ModifiedAt(int pos
);
293 void CheckReadOnly();
294 bool DeleteChars(int pos
, int len
);
295 int InsertString(int position
, const char *s
, int insertLength
);
296 void ChangeInsertion(const char *s
, int length
);
297 int SCI_METHOD
AddData(char *data
, Sci_Position length
);
298 void * SCI_METHOD
ConvertToDocument();
301 bool CanUndo() const { return cb
.CanUndo(); }
302 bool CanRedo() const { return cb
.CanRedo(); }
303 void DeleteUndoHistory() { cb
.DeleteUndoHistory(); }
304 bool SetUndoCollection(bool collectUndo
) {
305 return cb
.SetUndoCollection(collectUndo
);
307 bool IsCollectingUndo() const { return cb
.IsCollectingUndo(); }
308 void BeginUndoAction() { cb
.BeginUndoAction(); }
309 void EndUndoAction() { cb
.EndUndoAction(); }
310 void AddUndoAction(int token
, bool mayCoalesce
) { cb
.AddUndoAction(token
, mayCoalesce
); }
312 bool IsSavePoint() const { return cb
.IsSavePoint(); }
314 void TentativeStart() { cb
.TentativeStart(); }
315 void TentativeCommit() { cb
.TentativeCommit(); }
316 void TentativeUndo();
317 bool TentativeActive() const { return cb
.TentativeActive(); }
319 const char * SCI_METHOD
BufferPointer() { return cb
.BufferPointer(); }
320 const char *RangePointer(int position
, int rangeLength
) { return cb
.RangePointer(position
, rangeLength
); }
321 int GapPosition() const { return cb
.GapPosition(); }
323 int SCI_METHOD
GetLineIndentation(Sci_Position line
);
324 int SetLineIndentation(int line
, int indent
);
325 int GetLineIndentPosition(int line
) const;
326 int GetColumn(int position
);
327 int CountCharacters(int startPos
, int endPos
) const;
328 int CountUTF16(int startPos
, int endPos
) const;
329 int FindColumn(int line
, int column
);
330 void Indent(bool forwards
, int lineBottom
, int lineTop
);
331 static std::string
TransformLineEnds(const char *s
, size_t len
, int eolModeWanted
);
332 void ConvertLineEnds(int eolModeSet
);
333 void SetReadOnly(bool set
) { cb
.SetReadOnly(set
); }
334 bool IsReadOnly() const { return cb
.IsReadOnly(); }
336 void DelChar(int pos
);
337 void DelCharBack(int pos
);
339 char CharAt(int position
) const { return cb
.CharAt(position
); }
340 void SCI_METHOD
GetCharRange(char *buffer
, Sci_Position position
, Sci_Position lengthRetrieve
) const {
341 cb
.GetCharRange(buffer
, position
, lengthRetrieve
);
343 char SCI_METHOD
StyleAt(Sci_Position position
) const { return cb
.StyleAt(position
); }
344 int StyleIndexAt(Sci_Position position
) const { return static_cast<unsigned char>(cb
.StyleAt(position
)); }
345 void GetStyleRange(unsigned char *buffer
, int position
, int lengthRetrieve
) const {
346 cb
.GetStyleRange(buffer
, position
, lengthRetrieve
);
348 int GetMark(int line
);
349 int MarkerNext(int lineStart
, int mask
) const;
350 int AddMark(int line
, int markerNum
);
351 void AddMarkSet(int line
, int valueSet
);
352 void DeleteMark(int line
, int markerNum
);
353 void DeleteMarkFromHandle(int markerHandle
);
354 void DeleteAllMarks(int markerNum
);
355 int LineFromHandle(int markerHandle
);
356 Sci_Position SCI_METHOD
LineStart(Sci_Position line
) const;
357 bool IsLineStartPosition(int position
) const;
358 Sci_Position SCI_METHOD
LineEnd(Sci_Position line
) const;
359 int LineEndPosition(int position
) const;
360 bool IsLineEndPosition(int position
) const;
361 bool IsPositionInLineEnd(int position
) const;
362 int VCHomePosition(int position
) const;
364 int SCI_METHOD
SetLevel(Sci_Position line
, int level
);
365 int SCI_METHOD
GetLevel(Sci_Position line
) const;
367 int GetLastChild(int lineParent
, int level
=-1, int lastLine
=-1);
368 int GetFoldParent(int line
) const;
369 void GetHighlightDelimiters(HighlightDelimiter
&hDelimiter
, int line
, int lastLine
);
371 void Indent(bool forwards
);
372 int ExtendWordSelect(int pos
, int delta
, bool onlyWordCharacters
=false);
373 int NextWordStart(int pos
, int delta
);
374 int NextWordEnd(int pos
, int delta
);
375 Sci_Position SCI_METHOD
Length() const { return cb
.Length(); }
376 void Allocate(int newSize
) { cb
.Allocate(newSize
); }
378 struct CharacterExtracted
{
379 unsigned int character
;
380 unsigned int widthBytes
;
381 CharacterExtracted(unsigned int character_
, unsigned int widthBytes_
) :
382 character(character_
), widthBytes(widthBytes_
) {
385 CharacterExtracted
ExtractCharacter(int position
) const;
387 bool IsWordStartAt(int pos
) const;
388 bool IsWordEndAt(int pos
) const;
389 bool IsWordAt(int start
, int end
) const;
391 bool MatchesWordOptions(bool word
, bool wordStart
, int pos
, int length
) const;
392 bool HasCaseFolder(void) const;
393 void SetCaseFolder(CaseFolder
*pcf_
);
394 long FindText(int minPos
, int maxPos
, const char *search
, int flags
, int *length
);
395 const char *SubstituteByPosition(const char *text
, int *length
);
396 int LinesTotal() const;
398 void SetDefaultCharClasses(bool includeWordClass
);
399 void SetCharClasses(const unsigned char *chars
, CharClassify::cc newCharClass
);
400 int GetCharsOfClass(CharClassify::cc characterClass
, unsigned char *buffer
);
401 void SCI_METHOD
StartStyling(Sci_Position position
, char mask
);
402 bool SCI_METHOD
SetStyleFor(Sci_Position length
, char style
);
403 bool SCI_METHOD
SetStyles(Sci_Position length
, const char *styles
);
404 int GetEndStyled() const { return endStyled
; }
405 void EnsureStyledTo(int pos
);
406 void StyleToAdjustingLineDuration(int pos
);
408 int GetStyleClock() const { return styleClock
; }
409 void IncrementStyleClock();
410 void SCI_METHOD
DecorationSetCurrentIndicator(int indicator
) {
411 decorations
.SetCurrentIndicator(indicator
);
413 void SCI_METHOD
DecorationFillRange(Sci_Position position
, int value
, Sci_Position fillLength
);
415 int SCI_METHOD
SetLineState(Sci_Position line
, int state
);
416 int SCI_METHOD
GetLineState(Sci_Position line
) const;
417 int GetMaxLineState();
418 void SCI_METHOD
ChangeLexerState(Sci_Position start
, Sci_Position end
);
420 StyledText
MarginStyledText(int line
) const;
421 void MarginSetStyle(int line
, int style
);
422 void MarginSetStyles(int line
, const unsigned char *styles
);
423 void MarginSetText(int line
, const char *text
);
424 void MarginClearAll();
426 StyledText
AnnotationStyledText(int line
) const;
427 void AnnotationSetText(int line
, const char *text
);
428 void AnnotationSetStyle(int line
, int style
);
429 void AnnotationSetStyles(int line
, const unsigned char *styles
);
430 int AnnotationLines(int line
) const;
431 void AnnotationClearAll();
433 bool AddWatcher(DocWatcher
*watcher
, void *userData
);
434 bool RemoveWatcher(DocWatcher
*watcher
, void *userData
);
436 CharClassify::cc
WordCharClass(unsigned char ch
) const;
437 bool IsWordPartSeparator(char ch
) const;
438 int WordPartLeft(int pos
);
439 int WordPartRight(int pos
);
440 int ExtendStyleRange(int pos
, int delta
, bool singleLine
= false);
441 bool IsWhiteLine(int line
) const;
442 int ParaUp(int pos
) const;
443 int ParaDown(int pos
) const;
444 int IndentSize() const { return actualIndentInChars
; }
445 int BraceMatch(int position
, int maxReStyle
);
448 void NotifyModifyAttempt();
449 void NotifySavePoint(bool atSavePoint
);
450 void NotifyModified(DocModification mh
);
457 UndoGroup(Document
*pdoc_
, bool groupNeeded_
=true) :
458 pdoc(pdoc_
), groupNeeded(groupNeeded_
) {
460 pdoc
->BeginUndoAction();
465 pdoc
->EndUndoAction();
468 bool Needed() const {
475 * To optimise processing of document modifications by DocWatchers, a hint is passed indicating the
476 * scope of the change.
477 * If the DocWatcher is a document view then this can be used to optimise screen updating.
479 class DocModification
{
481 int modificationType
;
484 int linesAdded
; /**< Negative if lines deleted. */
485 const char *text
; /**< Only valid for changes to text, not for changes to style. */
489 int annotationLinesAdded
;
492 DocModification(int modificationType_
, int position_
=0, int length_
=0,
493 int linesAdded_
=0, const char *text_
=0, int line_
=0) :
494 modificationType(modificationType_
),
497 linesAdded(linesAdded_
),
502 annotationLinesAdded(0),
505 DocModification(int modificationType_
, const Action
&act
, int linesAdded_
=0) :
506 modificationType(modificationType_
),
507 position(act
.position
),
509 linesAdded(linesAdded_
),
514 annotationLinesAdded(0),
519 * A class that wants to receive notifications from a Document must be derived from DocWatcher
520 * and implement the notification methods. It can then be added to the watcher list with AddWatcher.
524 virtual ~DocWatcher() {}
526 virtual void NotifyModifyAttempt(Document
*doc
, void *userData
) = 0;
527 virtual void NotifySavePoint(Document
*doc
, void *userData
, bool atSavePoint
) = 0;
528 virtual void NotifyModified(Document
*doc
, DocModification mh
, void *userData
) = 0;
529 virtual void NotifyDeleted(Document
*doc
, void *userData
) = 0;
530 virtual void NotifyStyleNeeded(Document
*doc
, void *userData
, int endPos
) = 0;
531 virtual void NotifyLexerChanged(Document
*doc
, void *userData
) = 0;
532 virtual void NotifyErrorOccurred(Document
*doc
, void *userData
, int status
) = 0;