Skip to content

Commit 112097c

Browse files
committed
Added transaction callback API for future language server example
1 parent 1151a5b commit 112097c

File tree

3 files changed

+70
-25
lines changed

3 files changed

+70
-25
lines changed

TextEditor.cpp

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -246,16 +246,16 @@ void TextEditor::render(const char* title, const ImVec2& size, bool border) {
246246
}
247247

248248
// handle change tracking if there is a change callback in place
249-
if (changeCallback) {
250-
if (changeDetected) {
251-
if (std::chrono::system_clock::now() > changeReportTime) {
252-
changeCallback();
253-
changeDetected = false;
249+
if (delayedChangeCallback) {
250+
if (delayedChangeDetected) {
251+
if (std::chrono::system_clock::now() > delayedChangeReportTime) {
252+
delayedChangeCallback();
253+
delayedChangeDetected = false;
254254
}
255255

256256
} else if (transactions.getVersion() != transActionVersion) {
257-
changeDetected = true;
258-
changeReportTime = std::chrono::system_clock::now() + changeCallbackDelay;
257+
delayedChangeDetected = true;
258+
delayedChangeReportTime = std::chrono::system_clock::now() + delayedChangeDelay;
259259
}
260260
}
261261

@@ -2109,6 +2109,27 @@ bool TextEditor::endTransaction(std::shared_ptr<Transaction> transaction) {
21092109
cursors.update();
21102110
transaction->setAfterState(cursors);
21112111
transactions.add(transaction);
2112+
std::vector<Change> changes;
2113+
2114+
if (transactionCallback) {
2115+
for (auto& action : *transaction) {
2116+
auto& change = changes.emplace_back();
2117+
change.insert = action.type == Action::Type::insertText;
2118+
2119+
change.startLine = static_cast<int>(action.start.line);
2120+
change.startColumn = static_cast<int>(action.start.column);
2121+
change.startIndex = static_cast<int>(document.getIndex(action.start));
2122+
2123+
change.startLine = static_cast<int>(action.end.line);
2124+
change.startColumn = static_cast<int>(action.end.column);
2125+
change.startIndex = static_cast<int>(document.getIndex(action.end));
2126+
2127+
change.text = action.text;
2128+
}
2129+
2130+
transactionCallback(changes);
2131+
}
2132+
21122133
return true;
21132134

21142135
} else {

TextEditor.h

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -202,17 +202,42 @@ class TextEditor {
202202
inline void ClearMarkers() { clearMarkers(); }
203203
inline bool HasMarkers() const { return markers.size() != 0; }
204204

205-
// change callback (called when changes are made (including undo/redo))
206-
// passed nullptr deactivates the callback
205+
// specify a change callback (called when changes are made (including undo/redo))
207206
// the delay parameter specifies a time in miliseconds that the editor will wait for before calling
208207
// which helps in case you don't need to track every keystroke
208+
// passing nullptr deactivates the callback
209209
inline void SetChangeCallback(std::function<void()> callback, int delay=0) {
210-
changeCallback = callback;
211-
changeCallbackDelay = std::chrono::milliseconds{delay};
210+
delayedChangeCallback = callback;
211+
delayedChangeDelay = std::chrono::milliseconds{delay};
212212
}
213213

214+
// detailed change report passed to callback below
215+
// this callback is different from the one above as is reports every change (not just a summary) and is very detailed
216+
// the insert flag states whether the change was an insert (true) or a delete (false)
217+
// in case of an overwrite, there will be two actions (first a delete and then an insert)
218+
// the start parameters refer to the insert point or the start of the delete
219+
// the end parameters refer to the end of the inserted text or the end of the deleted text
220+
// the text parameter contains the inserted or deleted text
221+
// line, column and index values are zero-based
222+
struct Change {
223+
bool insert;
224+
int startLine;
225+
int startColumn;
226+
int startIndex;
227+
int endLine;
228+
int endColumn;
229+
int endIndex;
230+
std::string text;
231+
};
232+
233+
// specify a transaction callback (live document changes in great detail)
234+
// it provides a list of changes made to the document in a single transaction (in the right order)
235+
// be carefull with this callback as it gets very verbose (called on every keystroke, delete, cut, paste, undo and redo)
236+
// passing nullptr deactivates the callback
237+
inline void SetTransactionCallback(std::function<void(std::vector<Change>&)> callback) { transactionCallback = callback; }
238+
214239
// line-based callbacks (line numbers are zero-based)
215-
// insertor callback is called when for each line inserted and the result is used as line specific user data
240+
// insertor callback is called when for each line inserted and the result is used as the new line specific user data
216241
// deletor callback is called for each line deleted (line specific user data is passed to callback)
217242
// setting either callback to nullptr will deactivate that callback
218243
inline void SetInsertor(std::function<void*(int line)> callback) { document.setInsertor(callback); }
@@ -308,8 +333,8 @@ class TextEditor {
308333

309334
inline void SetPalette(const Palette& newPalette) { paletteBase = newPalette; paletteAlpha = -1.0f; }
310335
inline const Palette& GetPalette() const { return paletteBase; }
311-
inline static void SetDefaultPalette(const Palette& aValue) { defaultPalette = aValue; }
312-
inline static Palette& GetDefaultPalette() { return defaultPalette; }
336+
static inline void SetDefaultPalette(const Palette& aValue) { defaultPalette = aValue; }
337+
static inline Palette& GetDefaultPalette() { return defaultPalette; }
313338

314339
static const Palette& GetDarkPalette();
315340
static const Palette& GetLightPalette();
@@ -460,8 +485,7 @@ class TextEditor {
460485
// optional opaque void* provided by app when autocomplete was setup
461486
void* userData;
462487

463-
// auto complete suggestions te be provided by app callback
464-
// only the first 10 are rendered in the order provided (so app is responsible for sorting)
488+
// auto complete suggestions te be provided by app callback (the app is responsible for sorting)
465489

466490
// the editor does not automatically include language specific keywords or identifiers in the suggestion list
467491
// this is left to the application so it can be context specific in case a language server is used
@@ -516,11 +540,11 @@ class TextEditor {
516540
// configure and activate autocomplete (passing nullptr deactivates it)
517541
inline void SetAutoCompleteConfig(const AutoCompleteConfig* config) { autocomplete.setConfig(config); }
518542

519-
// option to specify autocomplete suggestions later (in case a callback takes to long and lookup is handled in a separate thread)
543+
// provide autocomplete suggestions asynchronously (in case a callback takes to long and lookup is handled in a separate thread/process)
520544
// this call is not threadsafe and must be called from the rendering thread (you must synchronize with your lookup thread yourself)
521545
inline void SetAutoCompleteSuggestions(const std::vector<std::string>& suggestions) { autocomplete.setSuggestions(suggestions); }
522546

523-
// utility class to support autocomplete
547+
// utility class to support some autocomplete implementations
524548
// this is not used by default but can be used in autocomplete callbacks (see example app)
525549
class Trie {
526550
public:
@@ -946,7 +970,7 @@ class TextEditor {
946970
void clearDocument();
947971
} document;
948972

949-
// single action to be performed on text as part of a larger transaction
973+
// single action to be performed on the document as part of a larger transaction
950974
class Action {
951975
public:
952976
// action types
@@ -1314,10 +1338,11 @@ class TextEditor {
13141338
bool scrolling = false;
13151339
ImVec2 scrollStart;
13161340
bool showPanScrollIndicator = true;
1317-
std::function<void()> changeCallback;
1318-
std::chrono::milliseconds changeCallbackDelay;
1319-
std::chrono::system_clock::time_point changeReportTime;
1320-
bool changeDetected = false;
1341+
std::function<void()> delayedChangeCallback;
1342+
std::chrono::milliseconds delayedChangeDelay;
1343+
std::chrono::system_clock::time_point delayedChangeReportTime;
1344+
bool delayedChangeDetected = false;
1345+
std::function<void(std::vector<Change>&)> transactionCallback;
13211346

13221347
// color palette support
13231348
void updatePalette();

docs/autocomplete.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,7 @@ public:
9898
// opaque void* provided by app when autocomplete was setup
9999
void* userData;
100100
101-
// auto complete suggestions te be provided by app callback
102-
// only the first 10 are rendered in the order provided (so app is responsible for sorting)
101+
// auto complete suggestions te be provided by app callback (the app is responsible for sorting)
103102
104103
// the editor does not automatically include language specific keywords or identifiers in the suggestion list
105104
// this is left to the application so it can be context specific in case a language server is used

0 commit comments

Comments
 (0)