Scintilla 4.0.3
[TortoiseGit.git] / ext / scintilla / src / Document.h
blob7b1776de2e223761316040678837b796a0f73036
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.
8 #ifndef DOCUMENT_H
9 #define DOCUMENT_H
11 namespace Scintilla {
13 enum EncodingFamily { efEightBit, efUnicode, efDBCS };
15 /**
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.
21 class Range {
22 public:
23 Sci::Position start;
24 Sci::Position end;
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);
37 bool Valid() const {
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 {
51 if (start < end) {
52 return (pos >= start && pos <= end);
53 } else {
54 return (pos <= start && pos >= end);
58 // Is the character after pos within the range?
59 bool ContainsCharacter(Sci::Position pos) const {
60 if (start < end) {
61 return (pos >= start && pos < end);
62 } else {
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 {
72 return
73 Contains(other.start) ||
74 Contains(other.end) ||
75 other.Contains(start) ||
76 other.Contains(end);
80 class DocWatcher;
81 class DocModification;
82 class Document;
84 /**
85 * Interface class for regular expression searching
87 class RegexSearchBase {
88 public:
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);
101 struct StyledText {
102 size_t length;
103 const char *text;
104 bool multipleStyles;
105 size_t style;
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 {
113 size_t cur = start;
114 while ((cur < length) && (text[cur] != '\n'))
115 cur++;
116 return cur-start;
118 size_t StyleAt(size_t i) const {
119 return multipleStyles ? styles[i] : style;
123 class HighlightDelimiter {
124 public:
125 HighlightDelimiter() : isEnabled(false) {
126 Clear();
129 void Clear() {
130 beginFoldBlock = -1;
131 endFoldBlock = -1;
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
160 bool isEnabled;
163 class Document;
164 class LineMarkers;
165 class LineLevels;
166 class LineState;
167 class LineAnnotation;
169 inline int LevelNumber(int level) {
170 return level & SC_FOLDLEVELNUMBERMASK;
173 class LexInterface {
174 protected:
175 Document *pdoc;
176 ILexer4 *instance;
177 bool performingStyle; ///< Prevent reentrance
178 public:
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 {
198 public:
199 /** Used to pair watcher pointer with user data. */
200 struct WatcherWithUserData {
201 DocWatcher *watcher;
202 void *userData;
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);
211 private:
212 int refCount;
213 CellBuffer cb;
214 CharClassify charClass;
215 std::unique_ptr<CaseFolder> pcf;
216 Sci::Position endStyled;
217 int styleClock;
218 int enteredModification;
219 int enteredStyling;
220 int enteredReadOnlyCount;
222 bool insertionSet;
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;
236 bool matchesValid;
237 std::unique_ptr<RegexSearchBase> regex;
238 std::unique_ptr<LexInterface> pli;
240 public:
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);
254 int eolMode;
255 /// Can also be SC_CP_UTF8 to enable UTF-8 mode
256 int dbcsCodePage;
257 int lineEndBitSet;
258 int tabInChars;
259 int indentInChars;
260 int actualIndentInChars;
261 bool useTabs;
262 bool tabIndents;
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;
272 virtual ~Document();
274 int AddRef();
275 int SCI_METHOD Release();
277 virtual void Init();
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 {
287 return dvRelease4;
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); }
331 void SetSavePoint();
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;
386 void ClearLevels();
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);
419 void LexerChanged();
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);
460 private:
461 void NotifyModifyAttempt();
462 void NotifySavePoint(bool atSavePoint);
463 void NotifyModified(DocModification mh);
466 class UndoGroup {
467 Document *pdoc;
468 bool groupNeeded;
469 public:
470 UndoGroup(Document *pdoc_, bool groupNeeded_=true) :
471 pdoc(pdoc_), groupNeeded(groupNeeded_) {
472 if (groupNeeded) {
473 pdoc->BeginUndoAction();
476 ~UndoGroup() {
477 if (groupNeeded) {
478 pdoc->EndUndoAction();
481 bool Needed() const {
482 return groupNeeded;
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 {
493 public:
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. */
499 Sci::Line line;
500 int foldLevelNow;
501 int foldLevelPrev;
502 Sci::Line annotationLinesAdded;
503 Sci::Position token;
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_),
508 position(position_),
509 length(length_),
510 linesAdded(linesAdded_),
511 text(text_),
512 line(line_),
513 foldLevelNow(0),
514 foldLevelPrev(0),
515 annotationLinesAdded(0),
516 token(0) {}
518 DocModification(int modificationType_, const Action &act, Sci::Line linesAdded_=0) :
519 modificationType(modificationType_),
520 position(act.position),
521 length(act.lenData),
522 linesAdded(linesAdded_),
523 text(act.data.get()),
524 line(0),
525 foldLevelNow(0),
526 foldLevelPrev(0),
527 annotationLinesAdded(0),
528 token(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.
535 class DocWatcher {
536 public:
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;
550 #endif