// Scintilla source code edit control /** @file Document.h ** Text document that handles notifications, DBCS, styling, words and end of line. **/ // Copyright 1998-2011 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef DOCUMENT_H #define DOCUMENT_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif /** * A Position is a position within a document between two characters or at the beginning or end. * Sometimes used as a character index where it identifies the character after the position. */ typedef int Position; const Position invalidPosition = -1; enum EncodingFamily { efEightBit, efUnicode, efDBCS }; /** * The range class represents a range of text in a document. * The two values are not sorted as one end may be more significant than the other * as is the case for the selection where the end position is the position of the caret. * If either position is invalidPosition then the range is invalid and most operations will fail. */ class Range { public: Position start; Position end; Range(Position pos=0) : start(pos), end(pos) { } Range(Position start_, Position end_) : start(start_), end(end_) { } bool Valid() const { return (start != invalidPosition) && (end != invalidPosition); } // Is the position within the range? bool Contains(Position pos) const { if (start < end) { return (pos >= start && pos <= end); } else { return (pos <= start && pos >= end); } } // Is the character after pos within the range? bool ContainsCharacter(Position pos) const { if (start < end) { return (pos >= start && pos < end); } else { return (pos < start && pos >= end); } } bool Contains(Range other) const { return Contains(other.start) && Contains(other.end); } bool Overlaps(Range other) const { return Contains(other.start) || Contains(other.end) || other.Contains(start) || other.Contains(end); } }; class DocWatcher; class DocModification; class Document; /** * Interface class for regular expression searching */ class RegexSearchBase { public: virtual ~RegexSearchBase() {} virtual long FindText(Document *doc, int minPos, int maxPos, const char *s, bool caseSensitive, bool word, bool wordStart, int flags, int *length) = 0; ///@return String with the substitutions, must remain valid until the next call or destruction virtual const char *SubstituteByPosition(Document *doc, const char *text, int *length) = 0; }; /// Factory function for RegexSearchBase extern RegexSearchBase *CreateRegexSearch(CharClassify *charClassTable); struct StyledText { size_t length; const char *text; bool multipleStyles; size_t style; const unsigned char *styles; StyledText(size_t length_, const char *text_, bool multipleStyles_, int style_, const unsigned char *styles_) : length(length_), text(text_), multipleStyles(multipleStyles_), style(style_), styles(styles_) { } // Return number of bytes from start to before '\n' or end of text. // Return 1 when start is outside text size_t LineLength(size_t start) const { size_t cur = start; while ((cur < length) && (text[cur] != '\n')) cur++; return cur-start; } size_t StyleAt(size_t i) const { return multipleStyles ? styles[i] : style; } }; class HighlightDelimiter { public: HighlightDelimiter() : isEnabled(false) { Clear(); } void Clear() { beginFoldBlock = -1; endFoldBlock = -1; firstChangeableLineBefore = -1; firstChangeableLineAfter = -1; } bool NeedsDrawing(int line) const { return isEnabled && (line <= firstChangeableLineBefore || line >= firstChangeableLineAfter); } bool IsFoldBlockHighlighted(int line) const { return isEnabled && beginFoldBlock != -1 && beginFoldBlock <= line && line <= endFoldBlock; } bool IsHeadOfFoldBlock(int line) const { return beginFoldBlock == line && line < endFoldBlock; } bool IsBodyOfFoldBlock(int line) const { return beginFoldBlock != -1 && beginFoldBlock < line && line < endFoldBlock; } bool IsTailOfFoldBlock(int line) const { return beginFoldBlock != -1 && beginFoldBlock < line && line == endFoldBlock; } int beginFoldBlock; // Begin of current fold block int endFoldBlock; // End of current fold block int firstChangeableLineBefore; // First line that triggers repaint before starting line that determined current fold block int firstChangeableLineAfter; // First line that triggers repaint after starting line that determined current fold block bool isEnabled; }; class Document; class LexInterface { protected: Document *pdoc; ILexer *instance; bool performingStyle; ///< Prevent reentrance public: LexInterface(Document *pdoc_) : pdoc(pdoc_), instance(0), performingStyle(false) { } virtual ~LexInterface() { } void Colourise(int start, int end); int LineEndTypesSupported(); bool UseContainerLexing() const { return instance == 0; } }; /** */ class Document : PerLine, public IDocumentWithLineEnd, public ILoader { public: /** Used to pair watcher pointer with user data. */ struct WatcherWithUserData { DocWatcher *watcher; void *userData; WatcherWithUserData(DocWatcher *watcher_=0, void *userData_=0) : watcher(watcher_), userData(userData_) { } bool operator==(const WatcherWithUserData &other) const { return (watcher == other.watcher) && (userData == other.userData); } }; private: int refCount; CellBuffer cb; CharClassify charClass; CaseFolder *pcf; char stylingMask; int endStyled; int styleClock; int enteredModification; int enteredStyling; int enteredReadOnlyCount; std::vector watchers; // ldSize is not real data - it is for dimensions and loops enum lineData { ldMarkers, ldLevels, ldState, ldMargin, ldAnnotation, ldSize }; PerLine *perLineData[ldSize]; bool matchesValid; RegexSearchBase *regex; public: LexInterface *pli; int stylingBits; int stylingBitsMask; int eolMode; /// Can also be SC_CP_UTF8 to enable UTF-8 mode int dbcsCodePage; int lineEndBitSet; int tabInChars; int indentInChars; int actualIndentInChars; bool useTabs; bool tabIndents; bool backspaceUnindents; DecorationList decorations; Document(); virtual ~Document(); int AddRef(); int SCI_METHOD Release(); virtual void Init(); int LineEndTypesSupported() const; bool SetDBCSCodePage(int dbcsCodePage_); int GetLineEndTypesAllowed() const { return cb.GetLineEndTypes(); } bool SetLineEndTypesAllowed(int lineEndBitSet_); int GetLineEndTypesActive() const { return cb.GetLineEndTypes(); } virtual void InsertLine(int line); virtual void RemoveLine(int line); int SCI_METHOD Version() const { return dvLineEnd; } void SCI_METHOD SetErrorStatus(int status); int SCI_METHOD LineFromPosition(int pos) const; int ClampPositionIntoDocument(int pos) const; bool IsCrLf(int pos) const; int LenChar(int pos); bool InGoodUTF8(int pos, int &start, int &end) const; int MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd=true); int NextPosition(int pos, int moveDir) const; bool NextCharacter(int &pos, int moveDir) const; // Returns true if pos changed int SCI_METHOD GetRelativePosition(int positionStart, int characterOffset) const; int SCI_METHOD GetCharacterAndWidth(int position, int *pWidth) const; int SCI_METHOD CodePage() const; bool SCI_METHOD IsDBCSLeadByte(char ch) const; int SafeSegment(const char *text, int length, int lengthSegment) const; EncodingFamily CodePageFamily() const; // Gateways to modifying document void ModifiedAt(int pos); void CheckReadOnly(); bool DeleteChars(int pos, int len); bool InsertString(int position, const char *s, int insertLength); int SCI_METHOD AddData(char *data, int length); void * SCI_METHOD ConvertToDocument(); int Undo(); int Redo(); bool CanUndo() const { return cb.CanUndo(); } bool CanRedo() const { return cb.CanRedo(); } void DeleteUndoHistory() { cb.DeleteUndoHistory(); } bool SetUndoCollection(bool collectUndo) { return cb.SetUndoCollection(collectUndo); } bool IsCollectingUndo() const { return cb.IsCollectingUndo(); } void BeginUndoAction() { cb.BeginUndoAction(); } void EndUndoAction() { cb.EndHTTP/1.1 200 OK Connection: keep-alive Connection: keep-alive Content-Disposition: inline; filename="Document.h" Content-Disposition: inline; filename="Document.h" Content-Length: 15884 Content-Length: 15884 Content-Security-Policy: default-src 'none' Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Type: text/plain; charset=UTF-8 Date: Tue, 30 Dec 2025 16:43:50 UTC ETag: "d02025cb549fe941340d855e8efb2b9cf35f19b8" ETag: "d02025cb549fe941340d855e8efb2b9cf35f19b8" Expires: Fri, 28 Dec 2035 16:43:50 GMT Expires: Fri, 28 Dec 2035 16:43:51 GMT Last-Modified: Tue, 30 Dec 2025 16:43:50 GMT Last-Modified: Tue, 30 Dec 2025 16:43:51 GMT Server: OpenBSD httpd Server: OpenBSD httpd X-Content-Type-Options: nosniff X-Content-Type-Options: nosniff // Scintilla source code edit control /** @file Document.h ** Text document that handles notifications, DBCS, styling, words and end of line. **/ // Copyright 1998-2011 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef DOCUMENT_H #define DOCUMENT_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif /** * A Position is a position within a document between two characters or at the beginning or end. * Sometimes used as a character index where it identifies the character after the position. */ typedef int Position; const Position invalidPosition = -1; enum EncodingFamily { efEightBit, efUnicode, efDBCS }; /** * The range class represents a range of text in a document. * The two values are not sorted as one end may be more significant than the other * as is the case for the selection where the end position is the position of the caret. * If either position is invalidPosition then the range is invalid and most operations will fail. */ class Range { public: Position start; Position end; Range(Position pos=0) : start(pos), end(pos) { } Range(Position start_, Position end_) : start(start_), end(end_) { } bool Valid() const { return (start != invalidPosition) && (end != invalidPosition); } // Is the position within the range? bool Contains(Position pos) const { if (start < end) { return (pos >= start && pos <= end); } else { return (pos <= start && pos >= end); } } // Is the character after pos within the range? bool ContainsCharacter(Position pos) const { if (start < end) { return (pos >= start && pos < end); } else { return (pos < start && pos >= end); } } bool Contains(Range other) const { return Contains(other.start) && Contains(other.end); } bool Overlaps(Range other) const { return Contains(other.start) || Contains(other.end) || other.Contains(start) || other.Contains(end); } }; class DocWatcher; class DocModification; class Document; /** * Interface class for regular expression searching */ class RegexSearchBase { public: virtual ~RegexSearchBase() {} virtual long FindText(Document *doc, int minPos, int maxPos, const char *s, bool caseSensitive, bool word, bool wordStart, int flags, int *length) = 0; ///@return String with the substitutions, must remain valid until the next call or destruction virtual const char *SubstituteByPosition(Document *doc, const char *text, int *length) = 0; }; /// Factory function for RegexSearchBase extern RegexSearchBase *CreateRegexSearch(CharClassify *charClassTable); struct StyledText { size_t length; const char *text; bool multipleStyles; size_t style; const unsigned char *styles; StyledText(size_t length_, const char *text_, bool multipleStyles_, int style_, const unsigned char *styles_) : length(length_), text(text_), multipleStyles(multipleStyles_), style(style_), styles(styles_) { } // Return number of bytes from start to before '\n' or end of text. // Return 1 when start is outside text size_t LineLength(size_t start) const { size_t cur = start; while ((cur < length) && (text[cur] != '\n')) cur++; return cur-start; } size_t StyleAt(size_t i) const { return multipleStyles ? styles[i] : style; } }; class HighlightDelimiter { public: HighlightDelimiter() : isEnabled(false) { Clear(); } void Clear() { beginFoldBlock = -1; endFoldBlock = -1; firstChangeableLineBefore = -1; firstChangeableLineAfter = -1; } bool NeedsDrawing(int line) const { return isEnabled && (line <= firstChangeableLineBefore || line >= firstChangeableLineAfter); } bool IsFoldBlockHighlighted(int line) const { return isEnabled && beginFoldBlock != -1 && beginFoldBlock <= line && line <= endFoldBlock; } bool IsHeadOfFoldBlock(int line) const { return beginFoldBlock == line && line < endFoldBlock; } bool IsBodyOfFoldBlock(int line) const { return beginFoldBlock != -1 && beginFoldBlock < line && line < endFoldBlock; } bool IsTailOfFoldBlock(int line) const { return beginFoldBlock != -1 && beginFoldBlock < line && line == endFoldBlock; } int beginFoldBlock; // Begin of current fold block int endFoldBlock; // End of current fold block int firstChangeableLineBefore; // First line that triggers repaint before starting line that determined current fold block int firstChangeableLineAfter; // First line that triggers repaint after starting line that determined current fold block bool isEnabled; }; class Document; class LexInterface { protected: Document *pdoc; ILexer *instance; bool performingStyle; ///< Prevent reentrance public: LexInterface(Document *pdoc_) : pdoc(pdoc_), instance(0), performingStyle(false) { } virtual ~LexInterface() { } void Colourise(int start, int end); int LineEndTypesSupported(); bool UseContainerLexing() const { return instance == 0; } }; /** */ class Document : PerLine, public IDocumentWithLineEnd, public ILoader { public: /** Used to pair watcher pointer with user data. */ struct WatcherWithUserData { DocWatcher *watcher; void *userData; WatcherWithUserData(DocWatcher *watcher_=0, void *userData_=0) : watcher(watcher_), userData(userData_) { } bool operator==(const WatcherWithUserData &other) const { return (watcher == other.watcher) && (userData == other.userData); } }; private: int refCount; CellBuffer cb; CharClassify charClass; CaseFolder *pcf; char stylingMask; int endStyled; int styleClock; int enteredModification; int enteredStyling; int enteredReadOnlyCount; std::vector watchers; // ldSize is not real data - it is for dimensions and loops enum lineData { ldMarkers, ldLevels, ldState, ldMargin, ldAnnotation, ldSize }; PerLine *perLineData[ldSize]; bool matchesValid; RegexSearchBase *regex; public: LexInterface *pli; int stylingBits; int stylingBitsMask; int eolMode; /// Can also be SC_CP_UTF8 to enable UTF-8 mode int dbcsCodePage; int lineEndBitSet; int tabInChars; int indentInChars; int actualIndentInChars; bool useTabs; bool tabIndents; bool backspaceUnindents; DecorationList decorations; Document(); virtual ~Document(); int AddRef(); int SCI_METHOD Release(); virtual void Init(); int LineEndTypesSupported() const; bool SetDBCSCodePage(int dbcsCodePage_); int GetLineEndTypesAllowed() const { return cb.GetLineEndTypes(); } bool SetLineEndTypesAllowed(int lineEndBitSet_); int GetLineEndTypesActive() const { return cb.GetLineEndTypes(); } virtual void InsertLine(int line); virtual void RemoveLine(int line); int SCI_METHOD Version() const { return dvLineEnd; } void SCI_METHOD SetErrorStatus(int status); int SCI_METHOD LineFromPosition(int pos) const; int ClampPositionIntoDocument(int pos) const; bool IsCrLf(int pos) const; int LenCh