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.
13 enum EncodingFamily
{ efEightBit
, efUnicode
, efDBCS
};
16 * The range class represents a range of text in a document.
17 * The two values are not sorted as one end may be more significant than the other
18 * as is the case for the selection where the end position is the position of the caret.
19 * If either position is invalidPosition then the range is invalid and most operations will fail.
26 explicit Range(Sci::Position pos
=0) :
27 start(pos
), end(pos
) {
29 Range(Sci::Position start_
, Sci::Position end_
) :
30 start(start_
), end(end_
) {
33 bool operator==(const Range
&other
) const {
34 return (start
== other
.start
) && (end
== other
.end
);
38 return (start
!= Sci::invalidPosition
) && (end
!= Sci::invalidPosition
);
41 Sci::Position
First() const {
42 return (start
<= end
) ? start
: end
;
45 Sci::Position
Last() const {
46 return (start
> end
) ? start
: end
;
49 // Is the position within the range?
50 bool Contains(Sci::Position pos
) const {
52 return (pos
>= start
&& pos
<= end
);
54 return (pos
<= start
&& pos
>= end
);
58 // Is the character after pos within the range?
59 bool ContainsCharacter(Sci::Position pos
) const {
61 return (pos
>= start
&& pos
< end
);
63 return (pos
< start
&& pos
>= end
);
67 bool Contains(Range other
) const {
68 return Contains(other
.start
) && Contains(other
.end
);
71 bool Overlaps(Range other
) const {
73 Contains(other
.start
) ||
74 Contains(other
.end
) ||
75 other
.Contains(start
) ||
81 class DocModification
;
85 * Interface class for regular expression searching
87 class RegexSearchBase
{
89 virtual ~RegexSearchBase() {}
91 virtual long FindText(Document
*doc
, Sci::Position minPos
, Sci::Position maxPos
, const char *s
,
92 bool caseSensitive
, bool word
, bool wordStart
, int flags
, Sci::Position
*length
) = 0;
94 ///@return String with the substitutions, must remain valid until the next call or destruction
95 virtual const char *SubstituteByPosition(Document
*doc
, const char *text
, Sci::Position
*length
) = 0;
98 /// Factory function for RegexSearchBase
99 extern RegexSearchBase
*CreateRegexSearch(CharClassify
*charClassTable
);
106 const unsigned char *styles
;
107 StyledText(size_t length_
, const char *text_
, bool multipleStyles_
, int style_
, const unsigned char *styles_
) :
108 length(length_
), text(text_
), multipleStyles(multipleStyles_
), style(style_
), styles(styles_
) {
110 // Return number of bytes from start to before '\n' or end of text.
111 // Return 1 when start is outside text
112 size_t LineLength(size_t start
) const {
114 while ((cur
< length
) && (text
[cur
] != '\n'))
118 size_t StyleAt(size_t i
) const {
119 return multipleStyles
? styles
[i
] : style
;
123 class HighlightDelimiter
{
125 HighlightDelimiter() : isEnabled(false) {
132 firstChangeableLineBefore
= -1;
133 firstChangeableLineAfter
= -1;
136 bool NeedsDrawing(Sci::Line line
) const {
137 return isEnabled
&& (line
<= firstChangeableLineBefore
|| line
>= firstChangeableLineAfter
);
140 bool IsFoldBlockHighlighted(Sci::Line line
) const {
141 return isEnabled
&& beginFoldBlock
!= -1 && beginFoldBlock
<= line
&& line
<= endFoldBlock
;
144 bool IsHeadOfFoldBlock(Sci::Line line
) const {
145 return beginFoldBlock
== line
&& line
< endFoldBlock
;
148 bool IsBodyOfFoldBlock(Sci::Line line
) const {
149 return beginFoldBlock
!= -1 && beginFoldBlock
< line
&& line
< endFoldBlock
;
152 bool IsTailOfFoldBlock(Sci::Line line
) const {
153 return beginFoldBlock
!= -1 && beginFoldBlock
< line
&& line
== endFoldBlock
;
156 Sci::Line beginFoldBlock
; // Begin of current fold block
157 Sci::Line endFoldBlock
; // End of current fold block
158 Sci::Line firstChangeableLineBefore
; // First line that triggers repaint before starting line that determined current fold block
159 Sci::Line firstChangeableLineAfter
; // First line that triggers repaint after starting line that determined current fold block
167 class LineAnnotation
;
169 inline int LevelNumber(int level
) {
170 return level
& SC_FOLDLEVELNUMBERMASK
;
177 bool performingStyle
; ///< Prevent reentrance
179 explicit LexInterface(Document
*pdoc_
) : pdoc(pdoc_
), instance(0), performingStyle(false) {
181 virtual ~LexInterface() {
183 void Colourise(Sci::Position start
, Sci::Position end
);
184 int LineEndTypesSupported();
185 bool UseContainerLexing() const {
186 return instance
== 0;
190 struct RegexError
: public std::runtime_error
{
191 RegexError() : std::runtime_error("regex failure") {}
196 class Document
: PerLine
, public IDocument
, public ILoader
{
199 /** Used to pair watcher pointer with user data. */
200 struct WatcherWithUserData
{
203 WatcherWithUserData(DocWatcher
*watcher_
=0, void *userData_
=0) :
204 watcher(watcher_
), userData(userData_
) {
206 bool operator==(const WatcherWithUserData
&other
) const {
207 return (watcher
== other
.watcher
) && (userData
== other
.userData
);
214 CharClassify charClass
;
215 std::unique_ptr
<CaseFolder
> pcf
;
216 Sci::Position endStyled
;
218 int enteredModification
;
220 int enteredReadOnlyCount
;
223 std::string insertion
;
225 std::vector
<WatcherWithUserData
> watchers
;
227 // ldSize is not real data - it is for dimensions and loops
228 enum lineData
{ ldMarkers
, ldLevels
, ldState
, ldMargin
, ldAnnotation
, ldSize
};
229 std::unique_ptr
<PerLine
> perLineData
[ldSize
];
230 LineMarkers
*Markers() const;
231 LineLevels
*Levels() const;
232 LineState
*States() const;
233 LineAnnotation
*Margins() const;
234 LineAnnotation
*Annotations() const;
237 std::unique_ptr
<RegexSearchBase
> regex
;
238 std::unique_ptr
<LexInterface
> pli
;
242 struct CharacterExtracted
{
243 unsigned int character
;
244 unsigned int widthBytes
;
245 CharacterExtracted(unsigned int character_
, unsigned int widthBytes_
) :
246 character(character_
), widthBytes(widthBytes_
) {
248 // For DBCS characters turn 2 bytes into an int
249 static CharacterExtracted
DBCS(unsigned char lead
, unsigned char trail
) {
250 return CharacterExtracted((lead
<< 8) | trail
, 2);
255 /// Can also be SC_CP_UTF8 to enable UTF-8 mode
260 int actualIndentInChars
;
263 bool backspaceUnindents
;
264 double durationStyleOneLine
;
266 DecorationList decorations
;
268 Document(int options
);
269 // Deleted so Document objects can not be copied.
270 Document(const Document
&) = delete;
271 void operator=(const Document
&) = delete;
275 int SCI_METHOD
Release();
278 int LineEndTypesSupported() const;
279 bool SetDBCSCodePage(int dbcsCodePage_
);
280 int GetLineEndTypesAllowed() const { return cb
.GetLineEndTypes(); }
281 bool SetLineEndTypesAllowed(int lineEndBitSet_
);
282 int GetLineEndTypesActive() const { return cb
.GetLineEndTypes(); }
283 virtual void InsertLine(Sci::Line line
);
284 virtual void RemoveLine(Sci::Line line
);
286 int SCI_METHOD
Version() const {
290 void SCI_METHOD
SetErrorStatus(int status
);
292 Sci_Position SCI_METHOD
LineFromPosition(Sci_Position pos
) const;
293 Sci::Position
ClampPositionIntoDocument(Sci::Position pos
) const;
294 bool ContainsLineEnd(const char *s
, Sci::Position length
) const { return cb
.ContainsLineEnd(s
, length
); }
295 bool IsCrLf(Sci::Position pos
) const;
296 int LenChar(Sci::Position pos
);
297 bool InGoodUTF8(Sci::Position pos
, Sci::Position
&start
, Sci::Position
&end
) const;
298 Sci::Position
MovePositionOutsideChar(Sci::Position pos
, Sci::Position moveDir
, bool checkLineEnd
=true) const;
299 Sci::Position
NextPosition(Sci::Position pos
, int moveDir
) const;
300 bool NextCharacter(Sci::Position
&pos
, int moveDir
) const; // Returns true if pos changed
301 Document::CharacterExtracted
CharacterAfter(Sci::Position position
) const;
302 Document::CharacterExtracted
CharacterBefore(Sci::Position position
) const;
303 Sci_Position SCI_METHOD
GetRelativePosition(Sci_Position positionStart
, Sci_Position characterOffset
) const;
304 Sci::Position
GetRelativePositionUTF16(Sci::Position positionStart
, Sci::Position characterOffset
) const;
305 int SCI_METHOD
GetCharacterAndWidth(Sci_Position position
, Sci_Position
*pWidth
) const;
306 int SCI_METHOD
CodePage() const;
307 bool SCI_METHOD
IsDBCSLeadByte(char ch
) const;
308 int SafeSegment(const char *text
, int length
, int lengthSegment
) const;
309 EncodingFamily
CodePageFamily() const;
311 // Gateways to modifying document
312 void ModifiedAt(Sci::Position pos
);
313 void CheckReadOnly();
314 bool DeleteChars(Sci::Position pos
, Sci::Position len
);
315 Sci::Position
InsertString(Sci::Position position
, const char *s
, Sci::Position insertLength
);
316 void ChangeInsertion(const char *s
, Sci::Position length
);
317 int SCI_METHOD
AddData(const char *data
, Sci_Position length
);
318 void * SCI_METHOD
ConvertToDocument();
319 Sci::Position
Undo();
320 Sci::Position
Redo();
321 bool CanUndo() const { return cb
.CanUndo(); }
322 bool CanRedo() const { return cb
.CanRedo(); }
323 void DeleteUndoHistory() { cb
.DeleteUndoHistory(); }
324 bool SetUndoCollection(bool collectUndo
) {
325 return cb
.SetUndoCollection(collectUndo
);
327 bool IsCollectingUndo() const { return cb
.IsCollectingUndo(); }
328 void BeginUndoAction() { cb
.BeginUndoAction(); }
329 void EndUndoAction() { cb
.EndUndoAction(); }
330 void AddUndoAction(Sci::Position token
, bool mayCoalesce
) { cb
.AddUndoAction(token
, mayCoalesce
); }
332 bool IsSavePoint() const { return cb
.IsSavePoint(); }
334 void TentativeStart() { cb
.TentativeStart(); }
335 void TentativeCommit() { cb
.TentativeCommit(); }
336 void TentativeUndo();
337 bool TentativeActive() const { return cb
.TentativeActive(); }
339 const char * SCI_METHOD
BufferPointer() { return cb
.BufferPointer(); }
340 const char *RangePointer(Sci::Position position
, Sci::Position rangeLength
) { return cb
.RangePointer(position
, rangeLength
); }
341 Sci::Position
GapPosition() const { return cb
.GapPosition(); }
343 int SCI_METHOD
GetLineIndentation(Sci_Position line
);
344 Sci::Position
SetLineIndentation(Sci::Line line
, Sci::Position indent
);
345 Sci::Position
GetLineIndentPosition(Sci::Line line
) const;
346 Sci::Position
GetColumn(Sci::Position pos
);
347 Sci::Position
CountCharacters(Sci::Position startPos
, Sci::Position endPos
) const;
348 Sci::Position
CountUTF16(Sci::Position startPos
, Sci::Position endPos
) const;
349 Sci::Position
FindColumn(Sci::Line line
, Sci::Position column
);
350 void Indent(bool forwards
, Sci::Line lineBottom
, Sci::Line lineTop
);
351 static std::string
TransformLineEnds(const char *s
, size_t len
, int eolModeWanted
);
352 void ConvertLineEnds(int eolModeSet
);
353 void SetReadOnly(bool set
) { cb
.SetReadOnly(set
); }
354 bool IsReadOnly() const { return cb
.IsReadOnly(); }
356 void DelChar(Sci::Position pos
);
357 void DelCharBack(Sci::Position pos
);
359 char CharAt(Sci::Position position
) const { return cb
.CharAt(position
); }
360 void SCI_METHOD
GetCharRange(char *buffer
, Sci_Position position
, Sci_Position lengthRetrieve
) const {
361 cb
.GetCharRange(buffer
, static_cast<Sci::Position
>(position
), static_cast<Sci::Position
>(lengthRetrieve
));
363 char SCI_METHOD
StyleAt(Sci_Position position
) const { return cb
.StyleAt(static_cast<Sci::Position
>(position
)); }
364 int StyleIndexAt(Sci_Position position
) const { return static_cast<unsigned char>(cb
.StyleAt(static_cast<Sci::Position
>(position
))); }
365 void GetStyleRange(unsigned char *buffer
, Sci::Position position
, Sci::Position lengthRetrieve
) const {
366 cb
.GetStyleRange(buffer
, position
, lengthRetrieve
);
368 int GetMark(Sci::Line line
) const;
369 Sci::Line
MarkerNext(Sci::Line lineStart
, int mask
) const;
370 int AddMark(Sci::Line line
, int markerNum
);
371 void AddMarkSet(Sci::Line line
, int valueSet
);
372 void DeleteMark(Sci::Line line
, int markerNum
);
373 void DeleteMarkFromHandle(int markerHandle
);
374 void DeleteAllMarks(int markerNum
);
375 Sci::Line
LineFromHandle(int markerHandle
) const;
376 Sci_Position SCI_METHOD
LineStart(Sci_Position line
) const;
377 bool IsLineStartPosition(Sci::Position position
) const;
378 Sci_Position SCI_METHOD
LineEnd(Sci_Position line
) const;
379 Sci::Position
LineEndPosition(Sci::Position position
) const;
380 bool IsLineEndPosition(Sci::Position position
) const;
381 bool IsPositionInLineEnd(Sci::Position position
) const;
382 Sci::Position
VCHomePosition(Sci::Position position
) const;
384 int SCI_METHOD
SetLevel(Sci_Position line
, int level
);
385 int SCI_METHOD
GetLevel(Sci_Position line
) const;
387 Sci::Line
GetLastChild(Sci::Line lineParent
, int level
=-1, Sci::Line lastLine
=-1);
388 Sci::Line
GetFoldParent(Sci::Line line
) const;
389 void GetHighlightDelimiters(HighlightDelimiter
&highlightDelimiter
, Sci::Line line
, Sci::Line lastLine
);
391 Sci::Position
ExtendWordSelect(Sci::Position pos
, int delta
, bool onlyWordCharacters
=false) const;
392 Sci::Position
NextWordStart(Sci::Position pos
, int delta
) const;
393 Sci::Position
NextWordEnd(Sci::Position pos
, int delta
) const;
394 Sci_Position SCI_METHOD
Length() const { return cb
.Length(); }
395 void Allocate(Sci::Position newSize
) { cb
.Allocate(newSize
); }
397 CharacterExtracted
ExtractCharacter(Sci::Position position
) const;
399 bool IsWordStartAt(Sci::Position pos
) const;
400 bool IsWordEndAt(Sci::Position pos
) const;
401 bool IsWordAt(Sci::Position start
, Sci::Position end
) const;
403 bool MatchesWordOptions(bool word
, bool wordStart
, Sci::Position pos
, Sci::Position length
) const;
404 bool HasCaseFolder() const;
405 void SetCaseFolder(CaseFolder
*pcf_
);
406 long FindText(Sci::Position minPos
, Sci::Position maxPos
, const char *search
, int flags
, Sci::Position
*length
);
407 const char *SubstituteByPosition(const char *text
, Sci::Position
*length
);
408 Sci::Line
LinesTotal() const;
410 void SetDefaultCharClasses(bool includeWordClass
);
411 void SetCharClasses(const unsigned char *chars
, CharClassify::cc newCharClass
);
412 int GetCharsOfClass(CharClassify::cc characterClass
, unsigned char *buffer
) const;
413 void SCI_METHOD
StartStyling(Sci_Position position
);
414 bool SCI_METHOD
SetStyleFor(Sci_Position length
, char style
);
415 bool SCI_METHOD
SetStyles(Sci_Position length
, const char *styles
);
416 Sci::Position
GetEndStyled() const { return endStyled
; }
417 void EnsureStyledTo(Sci::Position pos
);
418 void StyleToAdjustingLineDuration(Sci::Position pos
);
420 int GetStyleClock() const { return styleClock
; }
421 void IncrementStyleClock();
422 void SCI_METHOD
DecorationSetCurrentIndicator(int indicator
);
423 void SCI_METHOD
DecorationFillRange(Sci_Position position
, int value
, Sci_Position fillLength
);
424 LexInterface
*GetLexInterface() const;
425 void SetLexInterface(LexInterface
*pLexInterface
);
427 int SCI_METHOD
SetLineState(Sci_Position line
, int state
);
428 int SCI_METHOD
GetLineState(Sci_Position line
) const;
429 Sci::Line
GetMaxLineState() const;
430 void SCI_METHOD
ChangeLexerState(Sci_Position start
, Sci_Position end
);
432 StyledText
MarginStyledText(Sci::Line line
) const;
433 void MarginSetStyle(Sci::Line line
, int style
);
434 void MarginSetStyles(Sci::Line line
, const unsigned char *styles
);
435 void MarginSetText(Sci::Line line
, const char *text
);
436 void MarginClearAll();
438 StyledText
AnnotationStyledText(Sci::Line line
) const;
439 void AnnotationSetText(Sci::Line line
, const char *text
);
440 void AnnotationSetStyle(Sci::Line line
, int style
);
441 void AnnotationSetStyles(Sci::Line line
, const unsigned char *styles
);
442 int AnnotationLines(Sci::Line line
) const;
443 void AnnotationClearAll();
445 bool AddWatcher(DocWatcher
*watcher
, void *userData
);
446 bool RemoveWatcher(DocWatcher
*watcher
, void *userData
);
448 bool IsASCIIWordByte(unsigned char ch
) const;
449 CharClassify::cc
WordCharacterClass(unsigned int ch
) const;
450 bool IsWordPartSeparator(unsigned int ch
) const;
451 Sci::Position
WordPartLeft(Sci::Position pos
) const;
452 Sci::Position
WordPartRight(Sci::Position pos
) const;
453 Sci::Position
ExtendStyleRange(Sci::Position pos
, int delta
, bool singleLine
= false);
454 bool IsWhiteLine(Sci::Line line
) const;
455 Sci::Position
ParaUp(Sci::Position pos
) const;
456 Sci::Position
ParaDown(Sci::Position pos
) const;
457 int IndentSize() const { return actualIndentInChars
; }
458 Sci::Position
BraceMatch(Sci::Position position
, Sci::Position maxReStyle
);
461 void NotifyModifyAttempt();
462 void NotifySavePoint(bool atSavePoint
);
463 void NotifyModified(DocModification mh
);
470 UndoGroup(Document
*pdoc_
, bool groupNeeded_
=true) :
471 pdoc(pdoc_
), groupNeeded(groupNeeded_
) {
473 pdoc
->BeginUndoAction();
478 pdoc
->EndUndoAction();
481 bool Needed() const {
488 * To optimise processing of document modifications by DocWatchers, a hint is passed indicating the
489 * scope of the change.
490 * If the DocWatcher is a document view then this can be used to optimise screen updating.
492 class DocModification
{
494 int modificationType
;
495 Sci::Position position
;
496 Sci::Position length
;
497 Sci::Line linesAdded
; /**< Negative if lines deleted. */
498 const char *text
; /**< Only valid for changes to text, not for changes to style. */
502 Sci::Line annotationLinesAdded
;
505 DocModification(int modificationType_
, Sci::Position position_
=0, Sci::Position length_
=0,
506 Sci::Line linesAdded_
=0, const char *text_
=0, Sci::Line line_
=0) :
507 modificationType(modificationType_
),
510 linesAdded(linesAdded_
),
515 annotationLinesAdded(0),
518 DocModification(int modificationType_
, const Action
&act
, Sci::Line linesAdded_
=0) :
519 modificationType(modificationType_
),
520 position(act
.position
),
522 linesAdded(linesAdded_
),
523 text(act
.data
.get()),
527 annotationLinesAdded(0),
532 * A class that wants to receive notifications from a Document must be derived from DocWatcher
533 * and implement the notification methods. It can then be added to the watcher list with AddWatcher.
537 virtual ~DocWatcher() {}
539 virtual void NotifyModifyAttempt(Document
*doc
, void *userData
) = 0;
540 virtual void NotifySavePoint(Document
*doc
, void *userData
, bool atSavePoint
) = 0;
541 virtual void NotifyModified(Document
*doc
, DocModification mh
, void *userData
) = 0;
542 virtual void NotifyDeleted(Document
*doc
, void *userData
) = 0;
543 virtual void NotifyStyleNeeded(Document
*doc
, void *userData
, Sci::Position endPos
) = 0;
544 virtual void NotifyLexerChanged(Document
*doc
, void *userData
) = 0;
545 virtual void NotifyErrorOccurred(Document
*doc
, void *userData
, int status
) = 0;