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