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.
15 enum EncodingFamily
{ efEightBit
, efUnicode
, efDBCS
};
18 * The range class represents a range of text in a document.
19 * The two values are not sorted as one end may be more significant than the other
20 * as is the case for the selection where the end position is the position of the caret.
21 * If either position is invalidPosition then the range is invalid and most operations will fail.
28 explicit Range(Sci::Position pos
=0) :
29 start(pos
), end(pos
) {
31 Range(Sci::Position start_
, Sci::Position end_
) :
32 start(start_
), end(end_
) {
35 bool operator==(const Range
&other
) const {
36 return (start
== other
.start
) && (end
== other
.end
);
40 return (start
!= Sci::invalidPosition
) && (end
!= Sci::invalidPosition
);
43 Sci::Position
First() const {
44 return (start
<= end
) ? start
: end
;
47 Sci::Position
Last() const {
48 return (start
> end
) ? start
: end
;
51 // Is the position within the range?
52 bool Contains(Sci::Position pos
) const {
54 return (pos
>= start
&& pos
<= end
);
56 return (pos
<= start
&& pos
>= end
);
60 // Is the character after pos within the range?
61 bool ContainsCharacter(Sci::Position pos
) const {
63 return (pos
>= start
&& pos
< end
);
65 return (pos
< start
&& pos
>= end
);
69 bool Contains(Range other
) const {
70 return Contains(other
.start
) && Contains(other
.end
);
73 bool Overlaps(Range other
) const {
75 Contains(other
.start
) ||
76 Contains(other
.end
) ||
77 other
.Contains(start
) ||
83 class DocModification
;
87 * Interface class for regular expression searching
89 class RegexSearchBase
{
91 virtual ~RegexSearchBase() {}
93 virtual long FindText(Document
*doc
, Sci::Position minPos
, Sci::Position maxPos
, const char *s
,
94 bool caseSensitive
, bool word
, bool wordStart
, int flags
, Sci::Position
*length
) = 0;
96 ///@return String with the substitutions, must remain valid until the next call or destruction
97 virtual const char *SubstituteByPosition(Document
*doc
, const char *text
, Sci::Position
*length
) = 0;
100 /// Factory function for RegexSearchBase
101 extern RegexSearchBase
*CreateRegexSearch(CharClassify
*charClassTable
);
108 const unsigned char *styles
;
109 StyledText(size_t length_
, const char *text_
, bool multipleStyles_
, int style_
, const unsigned char *styles_
) :
110 length(length_
), text(text_
), multipleStyles(multipleStyles_
), style(style_
), styles(styles_
) {
112 // Return number of bytes from start to before '\n' or end of text.
113 // Return 1 when start is outside text
114 size_t LineLength(size_t start
) const {
116 while ((cur
< length
) && (text
[cur
] != '\n'))
120 size_t StyleAt(size_t i
) const {
121 return multipleStyles
? styles
[i
] : style
;
125 class HighlightDelimiter
{
127 HighlightDelimiter() : isEnabled(false) {
134 firstChangeableLineBefore
= -1;
135 firstChangeableLineAfter
= -1;
138 bool NeedsDrawing(Sci::Line line
) const {
139 return isEnabled
&& (line
<= firstChangeableLineBefore
|| line
>= firstChangeableLineAfter
);
142 bool IsFoldBlockHighlighted(Sci::Line line
) const {
143 return isEnabled
&& beginFoldBlock
!= -1 && beginFoldBlock
<= line
&& line
<= endFoldBlock
;
146 bool IsHeadOfFoldBlock(Sci::Line line
) const {
147 return beginFoldBlock
== line
&& line
< endFoldBlock
;
150 bool IsBodyOfFoldBlock(Sci::Line line
) const {
151 return beginFoldBlock
!= -1 && beginFoldBlock
< line
&& line
< endFoldBlock
;
154 bool IsTailOfFoldBlock(Sci::Line line
) const {
155 return beginFoldBlock
!= -1 && beginFoldBlock
< line
&& line
== endFoldBlock
;
158 Sci::Line beginFoldBlock
; // Begin of current fold block
159 Sci::Line endFoldBlock
; // End of current fold block
160 Sci::Line firstChangeableLineBefore
; // First line that triggers repaint before starting line that determined current fold block
161 Sci::Line firstChangeableLineAfter
; // First line that triggers repaint after starting line that determined current fold block
169 class LineAnnotation
;
171 inline int LevelNumber(int level
) {
172 return level
& SC_FOLDLEVELNUMBERMASK
;
179 bool performingStyle
; ///< Prevent reentrance
181 explicit LexInterface(Document
*pdoc_
) : pdoc(pdoc_
), instance(0), performingStyle(false) {
183 virtual ~LexInterface() {
185 void Colourise(Sci::Position start
, Sci::Position end
);
186 int LineEndTypesSupported();
187 bool UseContainerLexing() const {
188 return instance
== 0;
192 struct RegexError
: public std::runtime_error
{
193 RegexError() : std::runtime_error("regex failure") {}
198 class Document
: PerLine
, public IDocumentWithLineEnd
, public ILoader
{
201 /** Used to pair watcher pointer with user data. */
202 struct WatcherWithUserData
{
205 WatcherWithUserData(DocWatcher
*watcher_
=0, void *userData_
=0) :
206 watcher(watcher_
), userData(userData_
) {
208 bool operator==(const WatcherWithUserData
&other
) const {
209 return (watcher
== other
.watcher
) && (userData
== other
.userData
);
216 CharClassify charClass
;
217 std::unique_ptr
<CaseFolder
> pcf
;
218 Sci::Position endStyled
;
220 int enteredModification
;
222 int enteredReadOnlyCount
;
225 std::string insertion
;
227 std::vector
<WatcherWithUserData
> watchers
;
229 // ldSize is not real data - it is for dimensions and loops
230 enum lineData
{ ldMarkers
, ldLevels
, ldState
, ldMargin
, ldAnnotation
, ldSize
};
231 std::unique_ptr
<PerLine
> perLineData
[ldSize
];
232 LineMarkers
*Markers() const;
233 LineLevels
*Levels() const;
234 LineState
*States() const;
235 LineAnnotation
*Margins() const;
236 LineAnnotation
*Annotations() const;
239 std::unique_ptr
<RegexSearchBase
> regex
;
240 std::unique_ptr
<LexInterface
> pli
;
244 struct CharacterExtracted
{
245 unsigned int character
;
246 unsigned int widthBytes
;
247 CharacterExtracted(unsigned int character_
, unsigned int widthBytes_
) :
248 character(character_
), widthBytes(widthBytes_
) {
250 // For DBCS characters turn 2 bytes into an int
251 static CharacterExtracted
DBCS(unsigned char lead
, unsigned char trail
) {
252 return CharacterExtracted((lead
<< 8) | trail
, 2);
257 /// Can also be SC_CP_UTF8 to enable UTF-8 mode
262 int actualIndentInChars
;
265 bool backspaceUnindents
;
266 double durationStyleOneLine
;
268 DecorationList decorations
;
271 // Deleted so Document objects can not be copied.
272 Document(const Document
&) = delete;
273 void operator=(const Document
&) = delete;
277 int SCI_METHOD
Release();
280 int LineEndTypesSupported() const;
281 bool SetDBCSCodePage(int dbcsCodePage_
);
282 int GetLineEndTypesAllowed() const { return cb
.GetLineEndTypes(); }
283 bool SetLineEndTypesAllowed(int lineEndBitSet_
);
284 int GetLineEndTypesActive() const { return cb
.GetLineEndTypes(); }
285 virtual void InsertLine(Sci::Line line
);
286 virtual void RemoveLine(Sci::Line line
);
288 int SCI_METHOD
Version() const {
292 void SCI_METHOD
SetErrorStatus(int status
);
294 Sci_Position SCI_METHOD
LineFromPosition(Sci_Position pos
) const;
295 Sci::Position
ClampPositionIntoDocument(Sci::Position pos
) const;
296 bool ContainsLineEnd(const char *s
, Sci::Position length
) const { return cb
.ContainsLineEnd(s
, length
); }
297 bool IsCrLf(Sci::Position pos
) const;
298 int LenChar(Sci::Position pos
);
299 bool InGoodUTF8(Sci::Position pos
, Sci::Position
&start
, Sci::Position
&end
) const;
300 Sci::Position
MovePositionOutsideChar(Sci::Position pos
, Sci::Position moveDir
, bool checkLineEnd
=true) const;
301 Sci::Position
NextPosition(Sci::Position pos
, int moveDir
) const;
302 bool NextCharacter(Sci::Position
&pos
, int moveDir
) const; // Returns true if pos changed
303 Document::CharacterExtracted
CharacterAfter(Sci::Position position
) const;
304 Document::CharacterExtracted
CharacterBefore(Sci::Position position
) const;
305 Sci_Position SCI_METHOD
GetRelativePosition(Sci_Position positionStart
, Sci_Position characterOffset
) const;
306 Sci::Position
GetRelativePositionUTF16(Sci::Position positionStart
, Sci::Position characterOffset
) const;
307 int SCI_METHOD
GetCharacterAndWidth(Sci_Position position
, Sci_Position
*pWidth
) const;
308 int SCI_METHOD
CodePage() const;
309 bool SCI_METHOD
IsDBCSLeadByte(char ch
) const;
310 int SafeSegment(const char *text
, int length
, int lengthSegment
) const;
311 EncodingFamily
CodePageFamily() const;
313 // Gateways to modifying document
314 void ModifiedAt(Sci::Position pos
);
315 void CheckReadOnly();
316 bool DeleteChars(Sci::Position pos
, Sci::Position len
);
317 Sci::Position
InsertString(Sci::Position position
, const char *s
, Sci::Position insertLength
);
318 void ChangeInsertion(const char *s
, Sci::Position length
);
319 int SCI_METHOD
AddData(char *data
, Sci_Position length
);
320 void * SCI_METHOD
ConvertToDocument();
321 Sci::Position
Undo();
322 Sci::Position
Redo();
323 bool CanUndo() const { return cb
.CanUndo(); }
324 bool CanRedo() const { return cb
.CanRedo(); }
325 void DeleteUndoHistory() { cb
.DeleteUndoHistory(); }
326 bool SetUndoCollection(bool collectUndo
) {
327 return cb
.SetUndoCollection(collectUndo
);
329 bool IsCollectingUndo() const { return cb
.IsCollectingUndo(); }
330 void BeginUndoAction() { cb
.BeginUndoAction(); }
331 void EndUndoAction() { cb
.EndUndoAction(); }
332 void AddUndoAction(Sci::Position token
, bool mayCoalesce
) { cb
.AddUndoAction(token
, mayCoalesce
); }
334 bool IsSavePoint() const { return cb
.IsSavePoint(); }
336 void TentativeStart() { cb
.TentativeStart(); }
337 void TentativeCommit() { cb
.TentativeCommit(); }
338 void TentativeUndo();
339 bool TentativeActive() const { return cb
.TentativeActive(); }
341 const char * SCI_METHOD
BufferPointer() { return cb
.BufferPointer(); }
342 const char *RangePointer(Sci::Position position
, Sci::Position rangeLength
) { return cb
.RangePointer(position
, rangeLength
); }
343 Sci::Position
GapPosition() const { return cb
.GapPosition(); }
345 int SCI_METHOD
GetLineIndentation(Sci_Position line
);
346 Sci::Position
SetLineIndentation(Sci::Line line
, Sci::Position indent
);
347 Sci::Position
GetLineIndentPosition(Sci::Line line
) const;
348 Sci::Position
GetColumn(Sci::Position pos
);
349 Sci::Position
CountCharacters(Sci::Position startPos
, Sci::Position endPos
) const;
350 Sci::Position
CountUTF16(Sci::Position startPos
, Sci::Position endPos
) const;
351 Sci::Position
FindColumn(Sci::Line line
, Sci::Position column
);
352 void Indent(bool forwards
, Sci::Line lineBottom
, Sci::Line lineTop
);
353 static std::string
TransformLineEnds(const char *s
, size_t len
, int eolModeWanted
);
354 void ConvertLineEnds(int eolModeSet
);
355 void SetReadOnly(bool set
) { cb
.SetReadOnly(set
); }
356 bool IsReadOnly() const { return cb
.IsReadOnly(); }
358 void DelChar(Sci::Position pos
);
359 void DelCharBack(Sci::Position pos
);
361 char CharAt(Sci::Position position
) const { return cb
.CharAt(position
); }
362 void SCI_METHOD
GetCharRange(char *buffer
, Sci_Position position
, Sci_Position lengthRetrieve
) const {
363 cb
.GetCharRange(buffer
, position
, lengthRetrieve
);
365 char SCI_METHOD
StyleAt(Sci_Position position
) const { return cb
.StyleAt(position
); }
366 int StyleIndexAt(Sci_Position position
) const { return static_cast<unsigned char>(cb
.StyleAt(position
)); }
367 void GetStyleRange(unsigned char *buffer
, Sci::Position position
, Sci::Position lengthRetrieve
) const {
368 cb
.GetStyleRange(buffer
, position
, lengthRetrieve
);
370 int GetMark(Sci::Line line
) const;
371 Sci::Line
MarkerNext(Sci::Line lineStart
, int mask
) const;
372 int AddMark(Sci::Line line
, int markerNum
);
373 void AddMarkSet(Sci::Line line
, int valueSet
);
374 void DeleteMark(Sci::Line line
, int markerNum
);
375 void DeleteMarkFromHandle(int markerHandle
);
376 void DeleteAllMarks(int markerNum
);
377 Sci::Line
LineFromHandle(int markerHandle
) const;
378 Sci_Position SCI_METHOD
LineStart(Sci_Position line
) const;
379 bool IsLineStartPosition(Sci::Position position
) const;
380 Sci_Position SCI_METHOD
LineEnd(Sci_Position line
) const;
381 Sci::Position
LineEndPosition(Sci::Position position
) const;
382 bool IsLineEndPosition(Sci::Position position
) const;
383 bool IsPositionInLineEnd(Sci::Position position
) const;
384 Sci::Position
VCHomePosition(Sci::Position position
) const;
386 int SCI_METHOD
SetLevel(Sci_Position line
, int level
);
387 int SCI_METHOD
GetLevel(Sci_Position line
) const;
389 Sci::Line
GetLastChild(Sci::Line lineParent
, int level
=-1, Sci::Line lastLine
=-1);
390 Sci::Line
GetFoldParent(Sci::Line line
) const;
391 void GetHighlightDelimiters(HighlightDelimiter
&highlightDelimiter
, Sci::Line line
, Sci::Line lastLine
);
393 Sci::Position
ExtendWordSelect(Sci::Position pos
, int delta
, bool onlyWordCharacters
=false) const;
394 Sci::Position
NextWordStart(Sci::Position pos
, int delta
) const;
395 Sci::Position
NextWordEnd(Sci::Position pos
, int delta
) const;
396 Sci_Position SCI_METHOD
Length() const { return cb
.Length(); }
397 void Allocate(Sci::Position newSize
) { cb
.Allocate(newSize
); }
399 CharacterExtracted
ExtractCharacter(Sci::Position position
) const;
401 bool IsWordStartAt(Sci::Position pos
) const;
402 bool IsWordEndAt(Sci::Position pos
) const;
403 bool IsWordAt(Sci::Position start
, Sci::Position end
) const;
405 bool MatchesWordOptions(bool word
, bool wordStart
, Sci::Position pos
, Sci::Position length
) const;
406 bool HasCaseFolder() const;
407 void SetCaseFolder(CaseFolder
*pcf_
);
408 long FindText(Sci::Position minPos
, Sci::Position maxPos
, const char *search
, int flags
, Sci::Position
*length
);
409 const char *SubstituteByPosition(const char *text
, Sci::Position
*length
);
410 Sci::Line
LinesTotal() const;
412 void SetDefaultCharClasses(bool includeWordClass
);
413 void SetCharClasses(const unsigned char *chars
, CharClassify::cc newCharClass
);
414 int GetCharsOfClass(CharClassify::cc characterClass
, unsigned char *buffer
) const;
415 void SCI_METHOD
StartStyling(Sci_Position position
, char mask
);
416 bool SCI_METHOD
SetStyleFor(Sci_Position length
, char style
);
417 bool SCI_METHOD
SetStyles(Sci_Position length
, const char *styles
);
418 Sci::Position
GetEndStyled() const { return endStyled
; }
419 void EnsureStyledTo(Sci::Position pos
);
420 void StyleToAdjustingLineDuration(Sci::Position pos
);
422 int GetStyleClock() const { return styleClock
; }
423 void IncrementStyleClock();
424 void SCI_METHOD
DecorationSetCurrentIndicator(int indicator
);
425 void SCI_METHOD
DecorationFillRange(Sci_Position position
, int value
, Sci_Position fillLength
);
426 LexInterface
*GetLexInterface() const;
427 void SetLexInterface(LexInterface
*pLexInterface
);
429 int SCI_METHOD
SetLineState(Sci_Position line
, int state
);
430 int SCI_METHOD
GetLineState(Sci_Position line
) const;
431 Sci::Line
GetMaxLineState() const;
432 void SCI_METHOD
ChangeLexerState(Sci_Position start
, Sci_Position end
);
434 StyledText
MarginStyledText(Sci::Line line
) const;
435 void MarginSetStyle(Sci::Line line
, int style
);
436 void MarginSetStyles(Sci::Line line
, const unsigned char *styles
);
437 void MarginSetText(Sci::Line line
, const char *text
);
438 void MarginClearAll();
440 StyledText
AnnotationStyledText(Sci::Line line
) const;
441 void AnnotationSetText(Sci::Line line
, const char *text
);
442 void AnnotationSetStyle(Sci::Line line
, int style
);
443 void AnnotationSetStyles(Sci::Line line
, const unsigned char *styles
);
444 int AnnotationLines(Sci::Line line
) const;
445 void AnnotationClearAll();
447 bool AddWatcher(DocWatcher
*watcher
, void *userData
);
448 bool RemoveWatcher(DocWatcher
*watcher
, void *userData
);
450 bool IsASCIIWordByte(unsigned char ch
) const;
451 CharClassify::cc
WordCharacterClass(unsigned int ch
) const;
452 bool IsWordPartSeparator(unsigned int ch
) const;
453 Sci::Position
WordPartLeft(Sci::Position pos
) const;
454 Sci::Position
WordPartRight(Sci::Position pos
) const;
455 Sci::Position
ExtendStyleRange(Sci::Position pos
, int delta
, bool singleLine
= false);
456 bool IsWhiteLine(Sci::Line line
) const;
457 Sci::Position
ParaUp(Sci::Position pos
) const;
458 Sci::Position
ParaDown(Sci::Position pos
) const;
459 int IndentSize() const { return actualIndentInChars
; }
460 Sci::Position
BraceMatch(Sci::Position position
, Sci::Position maxReStyle
);
463 void NotifyModifyAttempt();
464 void NotifySavePoint(bool atSavePoint
);
465 void NotifyModified(DocModification mh
);
472 UndoGroup(Document
*pdoc_
, bool groupNeeded_
=true) :
473 pdoc(pdoc_
), groupNeeded(groupNeeded_
) {
475 pdoc
->BeginUndoAction();
480 pdoc
->EndUndoAction();
483 bool Needed() const {
490 * To optimise processing of document modifications by DocWatchers, a hint is passed indicating the
491 * scope of the change.
492 * If the DocWatcher is a document view then this can be used to optimise screen updating.
494 class DocModification
{
496 int modificationType
;
497 Sci::Position position
;
498 Sci::Position length
;
499 Sci::Line linesAdded
; /**< Negative if lines deleted. */
500 const char *text
; /**< Only valid for changes to text, not for changes to style. */
504 Sci::Line annotationLinesAdded
;
507 DocModification(int modificationType_
, Sci::Position position_
=0, Sci::Position length_
=0,
508 Sci::Line linesAdded_
=0, const char *text_
=0, Sci::Line line_
=0) :
509 modificationType(modificationType_
),
512 linesAdded(linesAdded_
),
517 annotationLinesAdded(0),
520 DocModification(int modificationType_
, const Action
&act
, Sci::Line linesAdded_
=0) :
521 modificationType(modificationType_
),
522 position(act
.position
),
524 linesAdded(linesAdded_
),
525 text(act
.data
.get()),
529 annotationLinesAdded(0),
534 * A class that wants to receive notifications from a Document must be derived from DocWatcher
535 * and implement the notification methods. It can then be added to the watcher list with AddWatcher.
539 virtual ~DocWatcher() {}
541 virtual void NotifyModifyAttempt(Document
*doc
, void *userData
) = 0;
542 virtual void NotifySavePoint(Document
*doc
, void *userData
, bool atSavePoint
) = 0;
543 virtual void NotifyModified(Document
*doc
, DocModification mh
, void *userData
) = 0;
544 virtual void NotifyDeleted(Document
*doc
, void *userData
) = 0;
545 virtual void NotifyStyleNeeded(Document
*doc
, void *userData
, Sci::Position endPos
) = 0;
546 virtual void NotifyLexerChanged(Document
*doc
, void *userData
) = 0;
547 virtual void NotifyErrorOccurred(Document
*doc
, void *userData
, int status
) = 0;