1// @file ScintillaDocument.cpp
2// Wrapper for Scintilla document object so it can be manipulated independently.
3// Copyright (c) 2011 Archaeopteryx Software, Inc. d/b/a Wingware
4
5#include <stdexcept>
6#include <string_view>
7#include <vector>
8#include <map>
9#include <set>
10#include <optional>
11#include <memory>
12
13#include "ScintillaTypes.h"
14#include "ScintillaMessages.h"
15#include "ScintillaStructures.h"
16#include "ScintillaDocument.h"
17
18#include "Debugging.h"
19#include "Geometry.h"
20#include "Platform.h"
21
22#include "ILoader.h"
23#include "ILexer.h"
24#include "Scintilla.h"
25
26#include "CharacterCategoryMap.h"
27#include "Position.h"
28#include "UniqueString.h"
29#include "SplitVector.h"
30#include "Partitioning.h"
31#include "RunStyles.h"
32#include "ContractionState.h"
33#include "CellBuffer.h"
34#include "KeyMap.h"
35#include "Indicator.h"
36#include "LineMarker.h"
37#include "Style.h"
38#include "ViewStyle.h"
39#include "CharClassify.h"
40#include "Decoration.h"
41#include "CaseFolder.h"
42#include "Document.h"
43
44using namespace Scintilla;
45using namespace Scintilla::Internal;
46
47class WatcherHelper : public DocWatcher {
48 ScintillaDocument *owner;
49public:
50 explicit WatcherHelper(ScintillaDocument *owner_);
51
52 void NotifyModifyAttempt(Document *doc, void *userData) override;
53 void NotifySavePoint(Document *doc, void *userData, bool atSavePoint) override;
54 void NotifyModified(Document *doc, DocModification mh, void *userData) override;
55 void NotifyDeleted(Document *doc, void *userData) noexcept override;
56 void NotifyStyleNeeded(Document *doc, void *userData, Sci::Position endPos) override;
57 void NotifyLexerChanged(Document *doc, void *userData) override;
58 void NotifyErrorOccurred(Document *doc, void *userData, Status status) override;
59};
60
61WatcherHelper::WatcherHelper(ScintillaDocument *owner_) : owner(owner_) {
62}
63
64void WatcherHelper::NotifyModifyAttempt(Document *, void *) {
65 emit owner->modify_attempt();
66}
67
68void WatcherHelper::NotifySavePoint(Document *, void *, bool atSavePoint) {
69 emit owner->save_point(atSavePoint);
70}
71
72void WatcherHelper::NotifyModified(Document *, DocModification mh, void *) {
73 int length = mh.length;
74 if (!mh.text)
75 length = 0;
76 QByteArray ba = QByteArray::fromRawData(mh.text, length);
77 emit owner->modified(mh.position, static_cast<int>(mh.modificationType), ba, length,
78 mh.linesAdded, mh.line, static_cast<int>(mh.foldLevelNow), static_cast<int>(mh.foldLevelPrev));
79}
80
81void WatcherHelper::NotifyDeleted(Document *, void *) noexcept {
82}
83
84void WatcherHelper::NotifyStyleNeeded(Document *, void *, Sci::Position endPos) {
85 emit owner->style_needed(endPos);
86}
87
88void WatcherHelper::NotifyLexerChanged(Document *, void *) {
89 emit owner->lexer_changed();
90}
91
92void WatcherHelper::NotifyErrorOccurred(Document *, void *, Status status) {
93 emit owner->error_occurred(static_cast<int>(status));
94}
95
96ScintillaDocument::ScintillaDocument(QObject *parent, void *pdoc_) :
97 QObject(parent), pdoc(pdoc_), docWatcher(nullptr) {
98 if (!pdoc) {
99 pdoc = new Document(DocumentOption::Default);
100 }
101 docWatcher = new WatcherHelper(this);
102 (static_cast<Document *>(pdoc))->AddRef();
103 (static_cast<Document *>(pdoc))->AddWatcher(docWatcher, pdoc);
104}
105
106ScintillaDocument::~ScintillaDocument() {
107 Document *doc = static_cast<Document *>(pdoc);
108 if (doc) {
109 doc->RemoveWatcher(docWatcher, doc);
110 doc->Release();
111 }
112 pdoc = nullptr;
113 delete docWatcher;
114 docWatcher = nullptr;
115}
116
117void *ScintillaDocument::pointer() {
118 return pdoc;
119}
120
121int ScintillaDocument::line_from_position(int pos) {
122 return (static_cast<Document *>(pdoc))->LineFromPosition(pos);
123}
124
125bool ScintillaDocument::is_cr_lf(int pos) {
126 return (static_cast<Document *>(pdoc))->IsCrLf(pos);
127}
128
129bool ScintillaDocument::delete_chars(int pos, int len) {
130 return (static_cast<Document *>(pdoc))->DeleteChars(pos, len);
131}
132
133int ScintillaDocument::undo() {
134 return (static_cast<Document *>(pdoc))->Undo();
135}
136
137int ScintillaDocument::redo() {
138 return (static_cast<Document *>(pdoc))->Redo();
139}
140
141bool ScintillaDocument::can_undo() {
142 return (static_cast<Document *>(pdoc))->CanUndo();
143}
144
145bool ScintillaDocument::can_redo() {
146 return (static_cast<Document *>(pdoc))->CanRedo();
147}
148
149void ScintillaDocument::delete_undo_history() {
150 (static_cast<Document *>(pdoc))->DeleteUndoHistory();
151}
152
153bool ScintillaDocument::set_undo_collection(bool collect_undo) {
154 return (static_cast<Document *>(pdoc))->SetUndoCollection(collect_undo);
155}
156
157bool ScintillaDocument::is_collecting_undo() {
158 return (static_cast<Document *>(pdoc))->IsCollectingUndo();
159}
160
161void ScintillaDocument::begin_undo_action() {
162 (static_cast<Document *>(pdoc))->BeginUndoAction();
163}
164
165void ScintillaDocument::end_undo_action() {
166 (static_cast<Document *>(pdoc))->EndUndoAction();
167}
168
169void ScintillaDocument::set_save_point() {
170 (static_cast<Document *>(pdoc))->SetSavePoint();
171}
172
173bool ScintillaDocument::is_save_point() {
174 return (static_cast<Document *>(pdoc))->IsSavePoint();
175}
176
177void ScintillaDocument::set_read_only(bool read_only) {
178 (static_cast<Document *>(pdoc))->SetReadOnly(read_only);
179}
180
181bool ScintillaDocument::is_read_only() {
182 return (static_cast<Document *>(pdoc))->IsReadOnly();
183}
184
185void ScintillaDocument::insert_string(int position, QByteArray &str) {
186 (static_cast<Document *>(pdoc))->InsertString(position, str.data(), str.size());
187}
188
189QByteArray ScintillaDocument::get_char_range(int position, int length) {
190 Document *doc = static_cast<Document *>(pdoc);
191
192 if (position < 0 || length <= 0 || position + length > doc->Length())
193 return QByteArray();
194
195 QByteArray ba(length, '\0');
196 doc->GetCharRange(ba.data(), position, length);
197 return ba;
198}
199
200char ScintillaDocument::style_at(int position) {
201 return (static_cast<Document *>(pdoc))->StyleAt(position);
202}
203
204int ScintillaDocument::line_start(int lineno) {
205 return (static_cast<Document *>(pdoc))->LineStart(lineno);
206}
207
208int ScintillaDocument::line_end(int lineno) {
209 return (static_cast<Document *>(pdoc))->LineEnd(lineno);
210}
211
212int ScintillaDocument::line_end_position(int pos) {
213 return (static_cast<Document *>(pdoc))->LineEndPosition(pos);
214}
215
216int ScintillaDocument::length() {
217 return (static_cast<Document *>(pdoc))->Length();
218}
219
220int ScintillaDocument::lines_total() {
221 return (static_cast<Document *>(pdoc))->LinesTotal();
222}
223
224void ScintillaDocument::start_styling(int position) {
225 (static_cast<Document *>(pdoc))->StartStyling(position);
226}
227
228bool ScintillaDocument::set_style_for(int length, char style) {
229 return (static_cast<Document *>(pdoc))->SetStyleFor(length, style);
230}
231
232int ScintillaDocument::get_end_styled() {
233 return (static_cast<Document *>(pdoc))->GetEndStyled();
234}
235
236void ScintillaDocument::ensure_styled_to(int position) {
237 (static_cast<Document *>(pdoc))->EnsureStyledTo(position);
238}
239
240void ScintillaDocument::set_current_indicator(int indic) {
241 (static_cast<Document *>(pdoc))->decorations->SetCurrentIndicator(indic);
242}
243
244void ScintillaDocument::decoration_fill_range(int position, int value, int fillLength) {
245 (static_cast<Document *>(pdoc))->DecorationFillRange(position, value, fillLength);
246}
247
248int ScintillaDocument::decorations_value_at(int indic, int position) {
249 return (static_cast<Document *>(pdoc))->decorations->ValueAt(indic, position);
250}
251
252int ScintillaDocument::decorations_start(int indic, int position) {
253 return (static_cast<Document *>(pdoc))->decorations->Start(indic, position);
254}
255
256int ScintillaDocument::decorations_end(int indic, int position) {
257 return (static_cast<Document *>(pdoc))->decorations->End(indic, position);
258}
259
260int ScintillaDocument::get_code_page() {
261 return (static_cast<Document *>(pdoc))->CodePage();
262}
263
264void ScintillaDocument::set_code_page(int code_page) {
265 (static_cast<Document *>(pdoc))->dbcsCodePage = code_page;
266}
267
268int ScintillaDocument::get_eol_mode() {
269 return static_cast<int>((static_cast<Document *>(pdoc))->eolMode);
270}
271
272void ScintillaDocument::set_eol_mode(int eol_mode) {
273 (static_cast<Document *>(pdoc))->eolMode = static_cast<EndOfLine>(eol_mode);
274}
275
276int ScintillaDocument::move_position_outside_char(int pos, int move_dir, bool check_line_end) {
277 return (static_cast<Document *>(pdoc))->MovePositionOutsideChar(pos, move_dir, check_line_end);
278}
279
280int ScintillaDocument::get_character(int pos) {
281 return (static_cast<Document *>(pdoc))->GetCharacterAndWidth(pos, nullptr);
282}
283