1 // Scintilla source code edit control
2 /** @file Document.h
3 ** Text document that handles notifications, DBCS, styling, words and end of line.
4 **/
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.
7
8 #ifndef DOCUMENT_H
9 #define DOCUMENT_H
10
11 #ifdef SCI_NAMESPACE
12 namespace Scintilla {
13 #endif
14
15 /**
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.
18 */
19 typedef int Position;
20 const Position invalidPosition = -1;
21
22 enum EncodingFamily { efEightBit, efUnicode, efDBCS };
23
24 /**
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.
29 */
30 class Range {
31 public:
32 Position start;
33 Position end;
34
35 explicit Range(Position pos=0) :
start(pos)36 start(pos), end(pos) {
37 }
Range(Position start_,Position end_)38 Range(Position start_, Position end_) :
39 start(start_), end(end_) {
40 }
41
42 bool operator==(const Range &other) const {
43 return (start == other.start) && (end == other.end);
44 }
45
Valid()46 bool Valid() const {
47 return (start != invalidPosition) && (end != invalidPosition);
48 }
49
First()50 Position First() const {
51 return (start <= end) ? start : end;
52 }
53
Last()54 Position Last() const {
55 return (start > end) ? start : end;
56 }
57
58 // Is the position within the range?
Contains(Position pos)59 bool Contains(Position pos) const {
60 if (start < end) {
61 return (pos >= start && pos <= end);
62 } else {
63 return (pos <= start && pos >= end);
64 }
65 }
66
67 // Is the character after pos within the range?
ContainsCharacter(Position pos)68 bool ContainsCharacter(Position pos) const {
69 if (start < end) {
70 return (pos >= start && pos < end);
71 } else {
72 return (pos < start && pos >= end);
73 }
74 }
75
Contains(Range other)76 bool Contains(Range other) const {
77 return Contains(other.start) && Contains(other.end);
78 }
79
Overlaps(Range other)80 bool Overlaps(Range other) const {
81 return
82 Contains(other.start) ||
83 Contains(other.end) ||
84 other.Contains(start) ||
85 other.Contains(end);
86 }
87 };
88
89 class DocWatcher;
90 class DocModification;
91 class Document;
92
93 /**
94 * Interface class for regular expression searching
95 */
96 class RegexSearchBase {
97 public:
~RegexSearchBase()98 virtual ~RegexSearchBase() {}
99
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;
102
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;
105 };
106
107 /// Factory function for RegexSearchBase
108 extern RegexSearchBase *CreateRegexSearch(CharClassify *charClassTable);
109
110 struct StyledText {
111 size_t length;
112 const char *text;
113 bool multipleStyles;
114 size_t style;
115 const unsigned char *styles;
StyledTextStyledText116 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_) {
118 }
119 // Return number of bytes from start to before '\n' or end of text.
120 // Return 1 when start is outside text
LineLengthStyledText121 size_t LineLength(size_t start) const {
122 size_t cur = start;
123 while ((cur < length) && (text[cur] != '\n'))
124 cur++;
125 return cur-start;
126 }
StyleAtStyledText127 size_t StyleAt(size_t i) const {
128 return multipleStyles ? styles[i] : style;
129 }
130 };
131
132 class HighlightDelimiter {
133 public:
HighlightDelimiter()134 HighlightDelimiter() : isEnabled(false) {
135 Clear();
136 }
137
Clear()138 void Clear() {
139 beginFoldBlock = -1;
140 endFoldBlock = -1;
141 firstChangeableLineBefore = -1;
142 firstChangeableLineAfter = -1;
143 }
144
NeedsDrawing(int line)145 bool NeedsDrawing(int line) const {
146 return isEnabled && (line <= firstChangeableLineBefore || line >= firstChangeableLineAfter);
147 }
148
IsFoldBlockHighlighted(int line)149 bool IsFoldBlockHighlighted(int line) const {
150 return isEnabled && beginFoldBlock != -1 && beginFoldBlock <= line && line <= endFoldBlock;
151 }
152
IsHeadOfFoldBlock(int line)153 bool IsHeadOfFoldBlock(int line) const {
154 return beginFoldBlock == line && line < endFoldBlock;
155 }
156
IsBodyOfFoldBlock(int line)157 bool IsBodyOfFoldBlock(int line) const {
158 return beginFoldBlock != -1 && beginFoldBlock < line && line < endFoldBlock;
159 }
160
IsTailOfFoldBlock(int line)161 bool IsTailOfFoldBlock(int line) const {
162 return beginFoldBlock != -1 && beginFoldBlock < line && line == endFoldBlock;
163 }
164
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
169 bool isEnabled;
170 };
171
172 class Document;
173
LevelNumber(int level)174 inline int LevelNumber(int level) {
175 return level & SC_FOLDLEVELNUMBERMASK;
176 }
177
178 class LexInterface {
179 protected:
180 Document *pdoc;
181 ILexer *instance;
182 bool performingStyle; ///< Prevent reentrance
183 public:
LexInterface(Document * pdoc_)184 explicit LexInterface(Document *pdoc_) : pdoc(pdoc_), instance(0), performingStyle(false) {
185 }
~LexInterface()186 virtual ~LexInterface() {
187 }
188 void Colourise(int start, int end);
189 int LineEndTypesSupported();
UseContainerLexing()190 bool UseContainerLexing() const {
191 return instance == 0;
192 }
193 };
194
195 struct RegexError : public std::runtime_error {
RegexErrorRegexError196 RegexError() : std::runtime_error("regex failure") {}
197 };
198
199 /**
200 */
201 class Document : PerLine, public IDocumentWithLineEnd, public ILoader {
202
203 public:
204 /** Used to pair watcher pointer with user data. */
205 struct WatcherWithUserData {
206 DocWatcher *watcher;
207 void *userData;
208 WatcherWithUserData(DocWatcher *watcher_=0, void *userData_=0) :
watcherWatcherWithUserData209 watcher(watcher_), userData(userData_) {
210 }
211 bool operator==(const WatcherWithUserData &other) const {
212 return (watcher == other.watcher) && (userData == other.userData);
213 }
214 bool operator!=(const WatcherWithUserData &other) const {
215 return !((watcher == other.watcher) && (userData == other.userData));
216 }
217 };
218
219 private:
220 int refCount;
221 CellBuffer cb;
222 CharClassify charClass;
223 CaseFolder *pcf;
224 int endStyled;
225 int styleClock;
226 int enteredModification;
227 int enteredStyling;
228 int enteredReadOnlyCount;
229
230 bool insertionSet;
231 std::string insertion;
232
233 std::vector<WatcherWithUserData> watchers;
234
235 // ldSize is not real data - it is for dimensions and loops
236 enum lineData { ldMarkers, ldLevels, ldState, ldMargin, ldAnnotation, ldSize };
237 PerLine *perLineData[ldSize];
238
239 bool matchesValid;
240 RegexSearchBase *regex;
241
242 public:
243
244 struct CharacterExtracted {
245 unsigned int character;
246 unsigned int widthBytes;
CharacterExtractedCharacterExtracted247 CharacterExtracted(unsigned int character_, unsigned int widthBytes_) :
248 character(character_), widthBytes(widthBytes_) {
249 }
250 // For DBCS characters turn 2 bytes into an int
DBCSCharacterExtracted251 static CharacterExtracted DBCS(unsigned char lead, unsigned char trail) {
252 return CharacterExtracted((lead << 8) | trail, 2);
253 }
254 };
255
256 LexInterface *pli;
257
258 int eolMode;
259 /// Can also be SC_CP_UTF8 to enable UTF-8 mode
260 int dbcsCodePage;
261 int lineEndBitSet;
262 int tabInChars;
263 int indentInChars;
264 int actualIndentInChars;
265 bool useTabs;
266 bool tabIndents;
267 bool backspaceUnindents;
268 double durationStyleOneLine;
269
270 DecorationList decorations;
271
272 Document();
273 virtual ~Document();
274
275 int AddRef();
276 int SCI_METHOD Release();
277
278 virtual void Init();
279 int LineEndTypesSupported() const;
280 bool SetDBCSCodePage(int dbcsCodePage_);
GetLineEndTypesAllowed()281 int GetLineEndTypesAllowed() const { return cb.GetLineEndTypes(); }
282 bool SetLineEndTypesAllowed(int lineEndBitSet_);
GetLineEndTypesActive()283 int GetLineEndTypesActive() const { return cb.GetLineEndTypes(); }
284 virtual void InsertLine(int line);
285 virtual void RemoveLine(int line);
286
Version()287 int SCI_METHOD Version() const {
288 return dvLineEnd;
289 }
290
291 void SCI_METHOD SetErrorStatus(int status);
292
293 Sci_Position SCI_METHOD LineFromPosition(Sci_Position pos) const;
294 int ClampPositionIntoDocument(int pos) const;
ContainsLineEnd(const char * s,int length)295 bool ContainsLineEnd(const char *s, int length) const { return cb.ContainsLineEnd(s, length); }
296 bool IsCrLf(int pos) const;
297 int LenChar(int pos);
298 bool InGoodUTF8(int pos, int &start, int &end) const;
299 int MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd=true) const;
300 int NextPosition(int pos, int moveDir) const;
301 bool NextCharacter(int &pos, int moveDir) const; // Returns true if pos changed
302 Document::CharacterExtracted CharacterAfter(int position) const;
303 Document::CharacterExtracted CharacterBefore(int position) const;
304 Sci_Position SCI_METHOD GetRelativePosition(Sci_Position positionStart, Sci_Position characterOffset) const;
305 int GetRelativePositionUTF16(int positionStart, int characterOffset) const;
306 int SCI_METHOD GetCharacterAndWidth(Sci_Position position, Sci_Position *pWidth) const;
307 int SCI_METHOD CodePage() const;
308 bool SCI_METHOD IsDBCSLeadByte(char ch) const;
309 int SafeSegment(const char *text, int length, int lengthSegment) const;
310 EncodingFamily CodePageFamily() const;
311
312 // Gateways to modifying document
313 void ModifiedAt(int pos);
314 void CheckReadOnly();
315 bool DeleteChars(int pos, int len);
316 int InsertString(int position, const char *s, int insertLength);
317 void ChangeInsertion(const char *s, int length);
318 int SCI_METHOD AddData(char *data, Sci_Position length);
319 void * SCI_METHOD ConvertToDocument();
320 int Undo();
321 int Redo();
CanUndo()322 bool CanUndo() const { return cb.CanUndo(); }
CanRedo()323 bool CanRedo() const { return cb.CanRedo(); }
DeleteUndoHistory()324 void DeleteUndoHistory() { cb.DeleteUndoHistory(); }
SetUndoCollection(bool collectUndo)325 bool SetUndoCollection(bool collectUndo) {
326 return cb.SetUndoCollection(collectUndo);
327 }
IsCollectingUndo()328 bool IsCollectingUndo() const { return cb.IsCollectingUndo(); }
BeginUndoAction()329 void BeginUndoAction() { cb.BeginUndoAction(); }
EndUndoAction()330 void EndUndoAction() { cb.EndUndoAction(); }
AddUndoAction(int token,bool mayCoalesce)331 void AddUndoAction(int token, bool mayCoalesce) { cb.AddUndoAction(token, mayCoalesce); }
332 void SetSavePoint();
IsSavePoint()333 bool IsSavePoint() const { return cb.IsSavePoint(); }
334
TentativeStart()335 void TentativeStart() { cb.TentativeStart(); }
TentativeCommit()336 void TentativeCommit() { cb.TentativeCommit(); }
337 void TentativeUndo();
TentativeActive()338 bool TentativeActive() const { return cb.TentativeActive(); }
339
BufferPointer()340 const char * SCI_METHOD BufferPointer() { return cb.BufferPointer(); }
RangePointer(int position,int rangeLength)341 const char *RangePointer(int position, int rangeLength) { return cb.RangePointer(position, rangeLength); }
GapPosition()342 int GapPosition() const { return cb.GapPosition(); }
343
344 int SCI_METHOD GetLineIndentation(Sci_Position line);
345 int SetLineIndentation(int line, int indent);
346 int GetLineIndentPosition(int line) const;
347 int GetColumn(int position);
348 int CountCharacters(int startPos, int endPos) const;
349 int CountUTF16(int startPos, int endPos) const;
350 int FindColumn(int line, int column);
351 void Indent(bool forwards, int lineBottom, int lineTop);
352 static std::string TransformLineEnds(const char *s, size_t len, int eolModeWanted);
353 void ConvertLineEnds(int eolModeSet);
SetReadOnly(bool set)354 void SetReadOnly(bool set) { cb.SetReadOnly(set); }
IsReadOnly()355 bool IsReadOnly() const { return cb.IsReadOnly(); }
356
357 void DelChar(int pos);
358 void DelCharBack(int pos);
359
CharAt(int position)360 char CharAt(int position) const { return cb.CharAt(position); }
GetCharRange(char * buffer,Sci_Position position,Sci_Position lengthRetrieve)361 void SCI_METHOD GetCharRange(char *buffer, Sci_Position position, Sci_Position lengthRetrieve) const {
362 cb.GetCharRange(buffer, position, lengthRetrieve);
363 }
StyleAt(Sci_Position position)364 char SCI_METHOD StyleAt(Sci_Position position) const { return cb.StyleAt(position); }
StyleIndexAt(Sci_Position position)365 int StyleIndexAt(Sci_Position position) const { return static_cast<unsigned char>(cb.StyleAt(position)); }
GetStyleRange(unsigned char * buffer,int position,int lengthRetrieve)366 void GetStyleRange(unsigned char *buffer, int position, int lengthRetrieve) const {
367 cb.GetStyleRange(buffer, position, lengthRetrieve);
368 }
369 int GetMark(int line);
370 int MarkerNext(int lineStart, int mask) const;
371 int AddMark(int line, int markerNum);
372 void AddMarkSet(int line, int valueSet);
373 void DeleteMark(int line, int markerNum);
374 void DeleteMarkFromHandle(int markerHandle);
375 void DeleteAllMarks(int markerNum);
376 int LineFromHandle(int markerHandle);
377 Sci_Position SCI_METHOD LineStart(Sci_Position line) const;
378 bool IsLineStartPosition(int position) const;
379 Sci_Position SCI_METHOD LineEnd(Sci_Position line) const;
380 int LineEndPosition(int position) const;
381 bool IsLineEndPosition(int position) const;
382 bool IsPositionInLineEnd(int position) const;
383 int VCHomePosition(int position) const;
384
385 int SCI_METHOD SetLevel(Sci_Position line, int level);
386 int SCI_METHOD GetLevel(Sci_Position line) const;
387 void ClearLevels();
388 int GetLastChild(int lineParent, int level=-1, int lastLine=-1);
389 int GetFoldParent(int line) const;
390 void GetHighlightDelimiters(HighlightDelimiter &hDelimiter, int line, int lastLine);
391
392 void Indent(bool forwards);
393 int ExtendWordSelect(int pos, int delta, bool onlyWordCharacters=false) const;
394 int NextWordStart(int pos, int delta) const;
395 int NextWordEnd(int pos, int delta) const;
Length()396 Sci_Position SCI_METHOD Length() const { return cb.Length(); }
Allocate(int newSize)397 void Allocate(int newSize) { cb.Allocate(newSize); }
398
399 CharacterExtracted ExtractCharacter(int position) const;
400
401 bool IsWordStartAt(int pos) const;
402 bool IsWordEndAt(int pos) const;
403 bool IsWordAt(int start, int end) const;
404
405 bool MatchesWordOptions(bool word, bool wordStart, int pos, int length) const;
406 bool HasCaseFolder(void) const;
407 void SetCaseFolder(CaseFolder *pcf_);
408 long FindText(int minPos, int maxPos, const char *search, int flags, int *length);
409 const char *SubstituteByPosition(const char *text, int *length);
410 int LinesTotal() const;
411
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);
GetEndStyled()418 int GetEndStyled() const { return endStyled; }
419 void EnsureStyledTo(int pos);
420 void StyleToAdjustingLineDuration(int pos);
421 void LexerChanged();
GetStyleClock()422 int GetStyleClock() const { return styleClock; }
423 void IncrementStyleClock();
DecorationSetCurrentIndicator(int indicator)424 void SCI_METHOD DecorationSetCurrentIndicator(int indicator) {
425 decorations.SetCurrentIndicator(indicator);
426 }
427 void SCI_METHOD DecorationFillRange(Sci_Position position, int value, Sci_Position fillLength);
428
429 int SCI_METHOD SetLineState(Sci_Position line, int state);
430 int SCI_METHOD GetLineState(Sci_Position line) const;
431 int GetMaxLineState();
432 void SCI_METHOD ChangeLexerState(Sci_Position start, Sci_Position end);
433
434 StyledText MarginStyledText(int line) const;
435 void MarginSetStyle(int line, int style);
436 void MarginSetStyles(int line, const unsigned char *styles);
437 void MarginSetText(int line, const char *text);
438 void MarginClearAll();
439
440 StyledText AnnotationStyledText(int line) const;
441 void AnnotationSetText(int line, const char *text);
442 void AnnotationSetStyle(int line, int style);
443 void AnnotationSetStyles(int line, const unsigned char *styles);
444 int AnnotationLines(int line) const;
445 void AnnotationClearAll();
446
447 bool AddWatcher(DocWatcher *watcher, void *userData);
448 bool RemoveWatcher(DocWatcher *watcher, void *userData);
449
450 bool IsASCIIWordByte(unsigned char ch) const;
451 CharClassify::cc WordCharacterClass(unsigned int ch) const;
452 bool IsWordPartSeparator(unsigned int ch) const;
453 int WordPartLeft(int pos) const;
454 int WordPartRight(int pos) const;
455 int ExtendStyleRange(int pos, int delta, bool singleLine = false);
456 bool IsWhiteLine(int line) const;
457 int ParaUp(int pos) const;
458 int ParaDown(int pos) const;
IndentSize()459 int IndentSize() const { return actualIndentInChars; }
460 int BraceMatch(int position, int maxReStyle);
461
462 private:
463 void NotifyModifyAttempt();
464 void NotifySavePoint(bool atSavePoint);
465 void NotifyModified(DocModification mh);
466 };
467
468 class UndoGroup {
469 Document *pdoc;
470 bool groupNeeded;
471 public:
472 UndoGroup(Document *pdoc_, bool groupNeeded_=true) :
pdoc(pdoc_)473 pdoc(pdoc_), groupNeeded(groupNeeded_) {
474 if (groupNeeded) {
475 pdoc->BeginUndoAction();
476 }
477 }
~UndoGroup()478 ~UndoGroup() {
479 if (groupNeeded) {
480 pdoc->EndUndoAction();
481 }
482 }
Needed()483 bool Needed() const {
484 return groupNeeded;
485 }
486 };
487
488
489 /**
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.
493 */
494 class DocModification {
495 public:
496 int modificationType;
497 int position;
498 int length;
499 int linesAdded; /**< Negative if lines deleted. */
500 const char *text; /**< Only valid for changes to text, not for changes to style. */
501 int line;
502 int foldLevelNow;
503 int foldLevelPrev;
504 int annotationLinesAdded;
505 int token;
506
507 DocModification(int modificationType_, int position_=0, int length_=0,
508 int linesAdded_=0, const char *text_=0, int line_=0) :
modificationType(modificationType_)509 modificationType(modificationType_),
510 position(position_),
511 length(length_),
512 linesAdded(linesAdded_),
513 text(text_),
514 line(line_),
515 foldLevelNow(0),
516 foldLevelPrev(0),
517 annotationLinesAdded(0),
518 token(0) {}
519
520 DocModification(int modificationType_, const Action &act, int linesAdded_=0) :
modificationType(modificationType_)521 modificationType(modificationType_),
522 position(act.position),
523 length(act.lenData),
524 linesAdded(linesAdded_),
525 text(act.data),
526 line(0),
527 foldLevelNow(0),
528 foldLevelPrev(0),
529 annotationLinesAdded(0),
530 token(0) {}
531 };
532
533 /**
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.
536 */
537 class DocWatcher {
538 public:
~DocWatcher()539 virtual ~DocWatcher() {}
540
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, int endPos) = 0;
546 virtual void NotifyLexerChanged(Document *doc, void *userData) = 0;
547 virtual void NotifyErrorOccurred(Document *doc, void *userData, int status) = 0;
548 };
549
550 #ifdef SCI_NAMESPACE
551 }
552 #endif
553
554 #endif
555