mirror of
https://github.com/rizonesoft/Notepad3.git
synced 2026-06-11 21:03:05 +08:00
+upd: Scintilla v5.5.4
This commit is contained in:
parent
5744dd52f6
commit
4c1add22c0
@ -678,8 +678,8 @@ BEGIN
|
||||
CONTROL "&Diese Nachricht nicht nochmals anzeigen", IDC_INFOBOXCHECK,
|
||||
"Button", BS_AUTOCHECKBOX | WS_TABSTOP,7,66,122,10
|
||||
DEFPUSHBUTTON "&Neu Laden", IDRETRY, 186, 82, 50, 14
|
||||
PUSHBUTTON "&Ignore", IDCANCEL, 130, 82, 50, 14
|
||||
PUSHBUTTON "&Monitor", IDCONTINUE, 242, 82, 50, 14
|
||||
PUSHBUTTON "&Ignorieren", IDCANCEL, 130, 82, 50, 14
|
||||
PUSHBUTTON "&Monitoring", IDCONTINUE, 242, 82, 50, 14
|
||||
END
|
||||
|
||||
IDD_MUI_SORT DIALOGEX 0, 0, 185, 188
|
||||
|
||||
@ -179,7 +179,7 @@ BEGIN
|
||||
IDS_MUI_ASK_CLEAR_UNDO "Diese Operation wird die Undo-History löschen. Weiter machen?"
|
||||
IDS_MUI_READONLY_SAVE """%s"" ist schreibgeschützt. Dokument unter einem anderen Dateipfad speichern?"
|
||||
IDS_MUI_FILECHANGENOTIFY
|
||||
"Die geladene Datei wurde durch ein anderes Programm auf dem Datenträger verändert. Bitte wähle:\n\nIgnore - \t\tIgnoriere alle Änderungen\nNeu Laden - \tDatei neu laden\nMonitor - \t\tWechsle zum Logfile Monitoring"
|
||||
"Die geladene Datei wurde durch ein anderes Programm auf dem Datenträger verändert. Bitte wähle:\n\nIgnorieren:\tIgnoriere weitere Änderungen\nNeu Laden:\tDatei neu laden\nMonitoring:\tWechsle zum Logfile Monitoring"
|
||||
IDS_MUI_FILECHANGENOTIFY2 "Die geladene Datei wurde auf dem Datenträger gelöscht. Nochmals speichern?"
|
||||
IDS_MUI_FILELOCK_ERROR "Es konnte keine exklusive Dateisperre auf ""%s"" gesetzt werden!"
|
||||
IDS_MUI_STICKYWINPOS "Eingefrorene Fensterpositionierung is eingeschaltet worden. Jede neue Notepad3 Instanz wird nun diese Fensterpositionierung initial verwenden"
|
||||
|
||||
@ -1275,6 +1275,14 @@ ChangeHistoryOption ScintillaCall::ChangeHistory() {
|
||||
return static_cast<Scintilla::ChangeHistoryOption>(Call(Message::GetChangeHistory));
|
||||
}
|
||||
|
||||
void ScintillaCall::SetUndoSelectionHistory(Scintilla::UndoSelectionHistoryOption undoSelectionHistory) {
|
||||
Call(Message::SetUndoSelectionHistory, static_cast<uintptr_t>(undoSelectionHistory));
|
||||
}
|
||||
|
||||
UndoSelectionHistoryOption ScintillaCall::UndoSelectionHistory() {
|
||||
return static_cast<Scintilla::UndoSelectionHistoryOption>(Call(Message::GetUndoSelectionHistory));
|
||||
}
|
||||
|
||||
Line ScintillaCall::FirstVisibleLine() {
|
||||
return Call(Message::GetFirstVisibleLine);
|
||||
}
|
||||
|
||||
@ -1121,7 +1121,7 @@ struct Sci_TextRangeFull {
|
||||
If the text argument is NULL(0) then the length that should be allocated
|
||||
to store the entire current line is returned.</p>
|
||||
|
||||
<p>See also: <code
|
||||
<p>See also: <code>
|
||||
<a class="seealso" href="#SCI_GETSELTEXT">SCI_GETSELTEXT</a>,
|
||||
<a class="seealso" href="#SCI_GETLINE">SCI_GETLINE</a>,
|
||||
<a class="seealso" href="#SCI_GETTEXT">SCI_GETTEXT</a>,
|
||||
@ -1938,6 +1938,8 @@ struct Sci_TextToFindFull {
|
||||
<a class="message" href="#SCI_ENDUNDOACTION">SCI_ENDUNDOACTION</a><br />
|
||||
<a class="message" href="#SCI_GETUNDOSEQUENCE">SCI_GETUNDOSEQUENCE → int</a><br />
|
||||
<a class="message" href="#SCI_ADDUNDOACTION">SCI_ADDUNDOACTION(int token, int flags)</a><br />
|
||||
<a class="message" href="#SCI_SETUNDOSELECTIONHISTORY">SCI_SETUNDOSELECTIONHISTORY(int undoSelectionHistory)</a><br />
|
||||
<a class="message" href="#SCI_GETUNDOSELECTIONHISTORY">SCI_GETUNDOSELECTIONHISTORY → int</a><br />
|
||||
</code>
|
||||
|
||||
<p><b id="SCI_UNDO">SCI_UNDO</b><br />
|
||||
@ -2016,6 +2018,35 @@ struct Sci_TextToFindFull {
|
||||
look like typing or deletions that look like multiple uses of the Backspace or Delete keys.
|
||||
</p>
|
||||
|
||||
<p><b id="SCI_SETUNDOSELECTIONHISTORY">SCI_SETUNDOSELECTIONHISTORY(int undoSelectionHistory)</b><br />
|
||||
<b id="SCI_GETUNDOSELECTIONHISTORY">SCI_GETUNDOSELECTIONHISTORY → int</b><br />
|
||||
The selection for each action can be saved and then restored when undo or redo is performed.
|
||||
<code>SCI_SETUNDOSELECTIONHISTORY</code> controls this.
|
||||
There is a memory cost for this feature with a minimum of 150 bytes for each of undo and redo for each recorded action.
|
||||
Recording may be turned on at any time.</p>
|
||||
|
||||
<p>The <code class="parameter">undoSelectionHistory</code> argument can be:</p>
|
||||
<table class="standard" summary="Undo selection history state">
|
||||
<tbody valign="top">
|
||||
<tr>
|
||||
<th align="left"><code>SC_UNDO_SELECTION_HISTORY_DISABLED</code></th>
|
||||
|
||||
<td>0</td>
|
||||
|
||||
<td>The default: undo selection history turned off.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th align="left"><code>SC_UNDO_SELECTION_HISTORY_ENABLED</code></th>
|
||||
|
||||
<td>1</td>
|
||||
|
||||
<td>Restore selection for each undo and redo.</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="UndoSaveRestore">Undo Save and Restore</h2>
|
||||
|
||||
<p>This feature is unfinished and has limitations.
|
||||
@ -5216,7 +5247,7 @@ struct Sci_TextToFindFull {
|
||||
<td><code>SC_SUPPORTS_LINE_DRAWS_FINAL</code></td>
|
||||
<td>0</td>
|
||||
<td>Whether drawing a line draws its final position.<br />
|
||||
Only false on Win32 GDI.</div></td>
|
||||
Only false on Win32 GDI.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
@ -7523,7 +7554,7 @@ sptr_t CallScintilla(unsigned int iMessage, uptr_t wParam, sptr_t lParam){
|
||||
<p>For many applications lexing documents larger than 4GB will be too sluggish so
|
||||
<code>SC_DOCUMENTOPTION_STYLES_NONE</code>
|
||||
and the null lexer <code>"null"</code> can be used. Another approach is to turn on idle styling with
|
||||
<code><a class="seealso" href="#SCI_SETIDLESTYLING">SCI_SETIDLESTYLING</code></a>.
|
||||
<a class="seealso" href="#SCI_SETIDLESTYLING"><code>SCI_SETIDLESTYLING</code></a>.
|
||||
</p>
|
||||
|
||||
<table class="standard" summary="Document options">
|
||||
|
||||
@ -26,9 +26,9 @@
|
||||
<table bgcolor="#CCCCCC" width="100%" cellspacing="0" cellpadding="8" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
<font size="4"> <a href="https://www.scintilla.org/scintilla553.zip">
|
||||
<font size="4"> <a href="https://www.scintilla.org/scintilla554.zip">
|
||||
Windows</a>
|
||||
<a href="https://www.scintilla.org/scintilla553.tgz">
|
||||
<a href="https://www.scintilla.org/scintilla554.tgz">
|
||||
GTK/Linux</a>
|
||||
</font>
|
||||
</td>
|
||||
@ -42,7 +42,7 @@
|
||||
containing very few restrictions.
|
||||
</p>
|
||||
<h3>
|
||||
Release 5.5.3
|
||||
Release 5.5.4
|
||||
</h3>
|
||||
<h4>
|
||||
Source Code
|
||||
@ -50,8 +50,8 @@
|
||||
The source code package contains all of the source code for Scintilla but no binary
|
||||
executable code and is available in
|
||||
<ul>
|
||||
<li><a href="https://www.scintilla.org/scintilla553.zip">zip format</a> (1.8M) commonly used on Windows</li>
|
||||
<li><a href="https://www.scintilla.org/scintilla553.tgz">tgz format</a> (1.7M) commonly used on Linux and compatible operating systems</li>
|
||||
<li><a href="https://www.scintilla.org/scintilla554.zip">zip format</a> (1.8M) commonly used on Windows</li>
|
||||
<li><a href="https://www.scintilla.org/scintilla554.tgz">tgz format</a> (1.7M) commonly used on Linux and compatible operating systems</li>
|
||||
</ul>
|
||||
Instructions for building on both Windows and Linux are included in the readme file.
|
||||
<h4>
|
||||
|
||||
@ -587,12 +587,29 @@
|
||||
</tr>
|
||||
</table>
|
||||
<h2>Releases</h2>
|
||||
<h3>
|
||||
<a href="https://www.scintilla.org/scintilla555.zip">Release 5.5.5</a>
|
||||
</h3>
|
||||
<ul>
|
||||
<li>
|
||||
Released 18 December 2024.
|
||||
</li>
|
||||
<li>
|
||||
Remember selection with undo and redo. Controlled with SCI_SETUNDOSELECTIONHISTORY.
|
||||
<a href="https://sourceforge.net/p/scintilla/feature-requests/1273/">Feature #1273</a>,
|
||||
<a href="https://sourceforge.net/p/scintilla/bugs/1479/">Bug #1479</a>,
|
||||
<a href="https://sourceforge.net/p/scintilla/bugs/1224/">Bug #1224</a>.
|
||||
</li>
|
||||
<li>
|
||||
Fix bug on Qt where double-click stopped working when Scintilla instance had been running for weeks.
|
||||
</li>
|
||||
</ul>
|
||||
<h3>
|
||||
<a href="https://www.scintilla.org/scintilla554.zip">Release 5.5.4</a>
|
||||
</h3>
|
||||
<ul>
|
||||
<li>
|
||||
Released 19 October 2024.
|
||||
Released 18 December 2024.
|
||||
</li>
|
||||
<li>
|
||||
Update to Unicode 15.1.
|
||||
@ -603,10 +620,18 @@
|
||||
<a href="https://sourceforge.net/p/scintilla/feature-requests/1533/">Feature #1533</a>.
|
||||
</li>
|
||||
<li>
|
||||
Improve performance of DBCS text.
|
||||
<a href="https://sourceforge.net/p/scintilla/feature-requests/1535/">Feature #1535</a>.
|
||||
</li>
|
||||
<li>
|
||||
Fix wrapping removed lines.
|
||||
<a href="https://sourceforge.net/p/scintilla/bugs/2456/">Bug #2456</a>.
|
||||
</li>
|
||||
<li>
|
||||
Fix moving line down to empty final line and moving empty final line up.
|
||||
<a href="https://sourceforge.net/p/scintilla/bugs/2457/">Bug #2457</a>.
|
||||
</li>
|
||||
<li>
|
||||
On GTK, allow middle click to insert multiple times within a document.
|
||||
<a href="https://github.com/geany/geany/issues/2629">Geany Issue #2629</a>.
|
||||
</li>
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
<meta name="keywords" content="Scintilla, SciTE, Editing Component, Text Editor" />
|
||||
<meta name="Description"
|
||||
content="www.scintilla.org is the home of the Scintilla editing component and SciTE text editor application." />
|
||||
<meta name="Date.Modified" content="20241019" />
|
||||
<meta name="Date.Modified" content="20241218" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<style type="text/css">
|
||||
.logo {
|
||||
@ -61,8 +61,8 @@
|
||||
GTK, and macOS</font>
|
||||
</td>
|
||||
<td width="40%" align="right">
|
||||
<font color="#FFCC99" size="3"> Release version 5.5.3<br />
|
||||
Site last modified October 19 2024</font>
|
||||
<font color="#FFCC99" size="3"> Release version 5.5.4<br />
|
||||
Site last modified December 18 2024</font>
|
||||
</td>
|
||||
<td width="20%">
|
||||
|
||||
@ -77,11 +77,11 @@
|
||||
</tr>
|
||||
</table>
|
||||
<ul id="versionlist">
|
||||
<li>Version 5.5.4 fixes wrapping of removed lines and edge cases for moving lines. On GTK, middle click can be repeated with one value.</li>
|
||||
<li>Version 5.5.3 fixes horizontal scrolling with a touchpad on Win32.</li>
|
||||
<li>Version 5.5.2 adds multiple selection copy with separator, a font stretch setting, and access to whether an undo sequence is active.</li>
|
||||
<li>Version 5.5.1 adds SCI_CUTALLOWLINE and fixes a Win32 bug that caused the cursor to flicker.</li>
|
||||
<li>Version 5.5.0 adds elements for inactive additional selections.</li>
|
||||
<li>Version 5.4.3 fixes a redo bug.</li>
|
||||
</ul>
|
||||
<ul id="menu">
|
||||
<li id="remote1"><a href="https://www.scintilla.org/SciTEImage.html">Screenshot</a></li>
|
||||
|
||||
@ -550,6 +550,10 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP
|
||||
#define SC_CHANGE_HISTORY_INDICATORS 4
|
||||
#define SCI_SETCHANGEHISTORY 2780
|
||||
#define SCI_GETCHANGEHISTORY 2781
|
||||
#define SC_UNDO_SELECTION_HISTORY_DISABLED 0
|
||||
#define SC_UNDO_SELECTION_HISTORY_ENABLED 1
|
||||
#define SCI_SETUNDOSELECTIONHISTORY 2782
|
||||
#define SCI_GETUNDOSELECTIONHISTORY 2783
|
||||
#define SCI_GETFIRSTVISIBLELINE 2152
|
||||
#define SCI_GETLINE 2153
|
||||
#define SCI_GETLINECOUNT 2154
|
||||
|
||||
@ -1355,6 +1355,16 @@ set void SetChangeHistory=2780(ChangeHistoryOption changeHistory,)
|
||||
# Report change history status.
|
||||
get ChangeHistoryOption GetChangeHistory=2781(,)
|
||||
|
||||
enu UndoSelectionHistoryOption=SC_UNDO_SELECTION_HISTORY_
|
||||
val SC_UNDO_SELECTION_HISTORY_DISABLED=0
|
||||
val SC_UNDO_SELECTION_HISTORY_ENABLED=1
|
||||
|
||||
# Enable or disable undo selection history.
|
||||
set void SetUndoSelectionHistory=2782(UndoSelectionHistoryOption undoSelectionHistory,)
|
||||
|
||||
# Report undo selection history status.
|
||||
get UndoSelectionHistoryOption GetUndoSelectionHistory=2783(,)
|
||||
|
||||
# Retrieve the display line at the top of the display.
|
||||
get line GetFirstVisibleLine=2152(,)
|
||||
|
||||
|
||||
@ -364,6 +364,8 @@ public:
|
||||
Position FormatRangeFull(bool draw, RangeToFormatFull *fr);
|
||||
void SetChangeHistory(Scintilla::ChangeHistoryOption changeHistory);
|
||||
Scintilla::ChangeHistoryOption ChangeHistory();
|
||||
void SetUndoSelectionHistory(Scintilla::UndoSelectionHistoryOption undoSelectionHistory);
|
||||
Scintilla::UndoSelectionHistoryOption UndoSelectionHistory();
|
||||
Line FirstVisibleLine();
|
||||
Position GetLine(Line line, char *text);
|
||||
std::string GetLine(Line line);
|
||||
|
||||
@ -289,6 +289,8 @@ enum class Message {
|
||||
FormatRangeFull = 2777,
|
||||
SetChangeHistory = 2780,
|
||||
GetChangeHistory = 2781,
|
||||
SetUndoSelectionHistory = 2782,
|
||||
GetUndoSelectionHistory = 2783,
|
||||
GetFirstVisibleLine = 2152,
|
||||
GetLine = 2153,
|
||||
GetLineCount = 2154,
|
||||
|
||||
@ -300,6 +300,11 @@ enum class ChangeHistoryOption {
|
||||
Indicators = 4,
|
||||
};
|
||||
|
||||
enum class UndoSelectionHistoryOption {
|
||||
Disabled = 0,
|
||||
Enabled = 1,
|
||||
};
|
||||
|
||||
enum class FoldLevel {
|
||||
None = 0x0,
|
||||
Base = 0x400,
|
||||
|
||||
@ -93,7 +93,7 @@ bool AutoComplete::IsFillUpChar(char ch) const noexcept {
|
||||
return ch && (fillUpChars.find(ch) != std::string::npos);
|
||||
}
|
||||
|
||||
void AutoComplete::SetSeparator(char separator_) {
|
||||
void AutoComplete::SetSeparator(char separator_) noexcept {
|
||||
separator = separator_;
|
||||
}
|
||||
|
||||
@ -101,7 +101,7 @@ char AutoComplete::GetSeparator() const noexcept {
|
||||
return separator;
|
||||
}
|
||||
|
||||
void AutoComplete::SetTypesep(char separator_) {
|
||||
void AutoComplete::SetTypesep(char separator_) noexcept {
|
||||
typesep = separator_;
|
||||
}
|
||||
|
||||
@ -109,28 +109,32 @@ char AutoComplete::GetTypesep() const noexcept {
|
||||
return typesep;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct Sorter {
|
||||
AutoComplete *ac;
|
||||
const bool ignoreCase;
|
||||
const char *list;
|
||||
std::vector<int> indices;
|
||||
|
||||
Sorter(AutoComplete *ac_, const char *list_) : ac(ac_), list(list_) {
|
||||
Sorter(const AutoComplete *ac, const char *list_) : ignoreCase(ac->ignoreCase), list(list_) {
|
||||
int i = 0;
|
||||
if (!list[i]) {
|
||||
// Empty list has a single empty member
|
||||
indices.push_back(i); // word start
|
||||
indices.push_back(i); // word end
|
||||
}
|
||||
const char separator = ac->GetSeparator();
|
||||
const char typesep = ac->GetTypesep();
|
||||
while (list[i]) {
|
||||
indices.push_back(i); // word start
|
||||
while (list[i] != ac->GetTypesep() && list[i] != ac->GetSeparator() && list[i])
|
||||
while (list[i] != typesep && list[i] != separator && list[i])
|
||||
++i;
|
||||
indices.push_back(i); // word end
|
||||
if (list[i] == ac->GetTypesep()) {
|
||||
while (list[i] != ac->GetSeparator() && list[i])
|
||||
if (list[i] == typesep) {
|
||||
while (list[i] != separator && list[i])
|
||||
++i;
|
||||
}
|
||||
if (list[i] == ac->GetSeparator()) {
|
||||
if (list[i] == separator) {
|
||||
++i;
|
||||
// preserve trailing separator as blank entry
|
||||
if (!list[i]) {
|
||||
@ -142,34 +146,41 @@ struct Sorter {
|
||||
indices.push_back(i); // index of last position
|
||||
}
|
||||
|
||||
bool operator()(int a, int b) noexcept {
|
||||
const int lenA = indices[a * 2 + 1] - indices[a * 2];
|
||||
const int lenB = indices[b * 2 + 1] - indices[b * 2];
|
||||
bool operator()(int a, int b) const noexcept {
|
||||
const unsigned indexA = a * 2;
|
||||
const unsigned indexB = b * 2;
|
||||
const int lenA = indices[indexA + 1] - indices[indexA];
|
||||
const int lenB = indices[indexB + 1] - indices[indexB];
|
||||
const int len = std::min(lenA, lenB);
|
||||
int cmp;
|
||||
if (ac->ignoreCase)
|
||||
cmp = CompareNCaseInsensitive(list + indices[a * 2], list + indices[b * 2], len);
|
||||
if (ignoreCase)
|
||||
cmp = CompareNCaseInsensitive(list + indices[indexA], list + indices[indexB], len);
|
||||
else
|
||||
cmp = strncmp(list + indices[a * 2], list + indices[b * 2], len);
|
||||
cmp = strncmp(list + indices[indexA], list + indices[indexB], len);
|
||||
if (cmp == 0)
|
||||
cmp = lenA - lenB;
|
||||
return cmp < 0;
|
||||
}
|
||||
};
|
||||
|
||||
void FillSortMatrix(std::vector<int> &sortMatrix, int itemCount) {
|
||||
sortMatrix.clear();
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
sortMatrix.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AutoComplete::SetList(const char *list) {
|
||||
if (autoSort == Ordering::PreSorted) {
|
||||
lb->SetList(list, separator, typesep);
|
||||
sortMatrix.clear();
|
||||
for (int i = 0; i < lb->Length(); ++i)
|
||||
sortMatrix.push_back(i);
|
||||
FillSortMatrix(sortMatrix, lb->Length());
|
||||
return;
|
||||
}
|
||||
|
||||
Sorter IndexSort(this, list);
|
||||
sortMatrix.clear();
|
||||
for (int i = 0; i < static_cast<int>(IndexSort.indices.size()) / 2; ++i)
|
||||
sortMatrix.push_back(i);
|
||||
const Sorter IndexSort(this, list);
|
||||
FillSortMatrix(sortMatrix, static_cast<int>(IndexSort.indices.size() / 2));
|
||||
std::sort(sortMatrix.begin(), sortMatrix.end(), IndexSort);
|
||||
if (autoSort == Ordering::Custom || sortMatrix.size() < 2) {
|
||||
lb->SetList(list, separator, typesep);
|
||||
@ -178,28 +189,25 @@ void AutoComplete::SetList(const char *list) {
|
||||
}
|
||||
|
||||
std::string sortedList;
|
||||
char item[maxItemLen];
|
||||
for (size_t i = 0; i < sortMatrix.size(); ++i) {
|
||||
int wordLen = IndexSort.indices[sortMatrix[i] * 2 + 2] - IndexSort.indices[sortMatrix[i] * 2];
|
||||
if (wordLen > maxItemLen-2)
|
||||
wordLen = maxItemLen - 2;
|
||||
memcpy(item, list + IndexSort.indices[sortMatrix[i] * 2], wordLen);
|
||||
if ((i+1) == sortMatrix.size()) {
|
||||
const unsigned index = sortMatrix[i] * 2;
|
||||
sortMatrix[i] = static_cast<int>(i);
|
||||
// word length include trailing typesep and separator
|
||||
const int wordLen = IndexSort.indices[index + 2] - IndexSort.indices[index];
|
||||
const std::string_view item(list + IndexSort.indices[index], wordLen);
|
||||
sortedList += item;
|
||||
if ((i + 1) == sortMatrix.size()) {
|
||||
// Last item so remove separator if present
|
||||
if ((wordLen > 0) && (item[wordLen-1] == separator))
|
||||
wordLen--;
|
||||
if (!item.empty() && item.back() == separator) {
|
||||
sortedList.pop_back();
|
||||
}
|
||||
} else {
|
||||
// Item before last needs a separator
|
||||
if ((wordLen == 0) || (item[wordLen-1] != separator)) {
|
||||
item[wordLen] = separator;
|
||||
wordLen++;
|
||||
if (item.empty() || item.back() != separator) {
|
||||
sortedList += separator;
|
||||
}
|
||||
}
|
||||
item[wordLen] = '\0';
|
||||
sortedList += item;
|
||||
}
|
||||
for (int i = 0; i < static_cast<int>(sortMatrix.size()); ++i)
|
||||
sortMatrix[i] = i;
|
||||
lb->SetList(sortedList.c_str(), separator, typesep);
|
||||
}
|
||||
|
||||
@ -293,7 +301,7 @@ void AutoComplete::Select(const char *word) {
|
||||
if (autoSort == Ordering::Custom) {
|
||||
// Check for a logically earlier match
|
||||
for (int i = location + 1; i <= end; ++i) {
|
||||
std::string item = lb->GetValue(sortMatrix[i]);
|
||||
const std::string item = lb->GetValue(sortMatrix[i]);
|
||||
if (CompareNCaseInsensitive(word, item.c_str(), lenWord))
|
||||
break;
|
||||
if (sortMatrix[i] < sortMatrix[location] && !strncmp(word, item.c_str(), lenWord))
|
||||
|
||||
@ -18,7 +18,6 @@ class AutoComplete {
|
||||
std::string fillUpChars;
|
||||
char separator;
|
||||
char typesep; // Type separator
|
||||
enum { maxItemLen=1000 };
|
||||
std::vector<int> sortMatrix;
|
||||
|
||||
public:
|
||||
@ -67,11 +66,11 @@ public:
|
||||
bool IsFillUpChar(char ch) const noexcept;
|
||||
|
||||
/// The separator character is used when interpreting the list in SetList
|
||||
void SetSeparator(char separator_);
|
||||
void SetSeparator(char separator_) noexcept;
|
||||
char GetSeparator() const noexcept;
|
||||
|
||||
/// The typesep character is used for separating the word from the type
|
||||
void SetTypesep(char separator_);
|
||||
void SetTypesep(char separator_) noexcept;
|
||||
char GetTypesep() const noexcept;
|
||||
|
||||
/// The list string contains a sequence of words separated by the separator character
|
||||
|
||||
@ -1076,6 +1076,10 @@ int CellBuffer::UndoSequenceDepth() const noexcept {
|
||||
return uh->UndoSequenceDepth();
|
||||
}
|
||||
|
||||
bool CellBuffer::AfterUndoSequenceStart() const noexcept {
|
||||
return uh->AfterUndoSequenceStart();
|
||||
}
|
||||
|
||||
void CellBuffer::AddUndoAction(Sci::Position token, bool mayCoalesce) {
|
||||
bool startSequence = false;
|
||||
uh->AppendAction(ActionType::container, token, nullptr, 0, startSequence, mayCoalesce);
|
||||
|
||||
@ -171,6 +171,7 @@ public:
|
||||
void BeginUndoAction(bool mayCoalesce=false) noexcept;
|
||||
void EndUndoAction() noexcept;
|
||||
int UndoSequenceDepth() const noexcept;
|
||||
bool AfterUndoSequenceStart() const noexcept;
|
||||
void AddUndoAction(Sci::Position token, bool mayCoalesce);
|
||||
void DeleteUndoHistory() noexcept;
|
||||
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <forward_list>
|
||||
#include <optional>
|
||||
#include <algorithm>
|
||||
@ -833,15 +834,9 @@ Sci::Position Document::MovePositionOutsideChar(Sci::Position pos, Sci::Position
|
||||
// Else invalid UTF-8 so return position of isolated trail byte
|
||||
}
|
||||
} else {
|
||||
// Anchor DBCS calculations at start of line because start of line can
|
||||
// not be a DBCS trail byte.
|
||||
const Sci::Position posStartLine = LineStartPosition(pos);
|
||||
if (pos == posStartLine)
|
||||
return pos;
|
||||
|
||||
// Step back until a non-lead-byte is found.
|
||||
Sci::Position posCheck = pos;
|
||||
while ((posCheck > posStartLine) && IsDBCSLeadByteNoExcept(cb.CharAt(posCheck-1)))
|
||||
while ((posCheck > 0) && IsDBCSLeadByteNoExcept(cb.CharAt(posCheck-1)))
|
||||
posCheck--;
|
||||
|
||||
// Check from known start of character.
|
||||
@ -916,14 +911,11 @@ Sci::Position Document::NextPosition(Sci::Position pos, int moveDir) const noexc
|
||||
if (pos > cb.Length())
|
||||
pos = cb.Length();
|
||||
} else {
|
||||
// Anchor DBCS calculations at start of line because start of line can
|
||||
// not be a DBCS trail byte.
|
||||
const Sci::Position posStartLine = LineStartPosition(pos);
|
||||
// See http://msdn.microsoft.com/en-us/library/cc194792%28v=MSDN.10%29.aspx
|
||||
// http://msdn.microsoft.com/en-us/library/cc194790.aspx
|
||||
if ((pos - 1) <= posStartLine) {
|
||||
return pos - 1;
|
||||
} else if (IsDBCSLeadByteNoExcept(cb.CharAt(pos - 1))) {
|
||||
// How to Go Backward in a DBCS String
|
||||
// https://msdn.microsoft.com/en-us/library/cc194792.aspx
|
||||
// DBCS-Enabled Programs vs. Non-DBCS-Enabled Programs
|
||||
// https://msdn.microsoft.com/en-us/library/cc194790.aspx
|
||||
if (IsDBCSLeadByteNoExcept(cb.CharAt(pos - 1))) {
|
||||
// Should actually be trail byte
|
||||
if (IsDBCSDualByteAt(pos - 2)) {
|
||||
return pos - 2;
|
||||
@ -934,7 +926,7 @@ Sci::Position Document::NextPosition(Sci::Position pos, int moveDir) const noexc
|
||||
} else {
|
||||
// Otherwise, step back until a non-lead-byte is found.
|
||||
Sci::Position posTemp = pos - 1;
|
||||
while (posStartLine <= --posTemp && IsDBCSLeadByteNoExcept(cb.CharAt(posTemp)))
|
||||
while (--posTemp >= 0 && IsDBCSLeadByteNoExcept(cb.CharAt(posTemp)))
|
||||
;
|
||||
// Now posTemp+1 must point to the beginning of a character,
|
||||
// so figure out whether we went back an even or an odd
|
||||
@ -1329,6 +1321,10 @@ bool Document::DeleteChars(Sci::Position pos, Sci::Position len) {
|
||||
} else {
|
||||
enteredModification++;
|
||||
if (!cb.IsReadOnly()) {
|
||||
if (cb.IsCollectingUndo() && cb.CanRedo()) {
|
||||
// Abandoning some undo actions so truncate any later selections
|
||||
TruncateUndoComments(cb.UndoCurrent());
|
||||
}
|
||||
NotifyModified(
|
||||
DocModification(
|
||||
ModificationFlags::BeforeDelete | ModificationFlags::User,
|
||||
@ -1382,6 +1378,10 @@ Sci::Position Document::InsertString(Sci::Position position, const char *s, Sci:
|
||||
s = insertion.c_str();
|
||||
insertLength = insertion.length();
|
||||
}
|
||||
if (cb.IsCollectingUndo() && cb.CanRedo()) {
|
||||
// Abandoning some undo actions so truncate any later selections
|
||||
TruncateUndoComments(cb.UndoCurrent());
|
||||
}
|
||||
NotifyModified(
|
||||
DocModification(
|
||||
ModificationFlags::BeforeInsert | ModificationFlags::User,
|
||||
@ -1565,6 +1565,20 @@ Sci::Position Document::Redo() {
|
||||
return newPos;
|
||||
}
|
||||
|
||||
void Document::EndUndoAction() noexcept {
|
||||
cb.EndUndoAction();
|
||||
if (UndoSequenceDepth() == 0) {
|
||||
// Broadcast notification to views to allow end of group processing.
|
||||
// NotifyGroupCompleted may throw (for memory exhaustion) but this method
|
||||
// may not as it is called in UndoGroup destructor so ignore exception.
|
||||
try {
|
||||
NotifyGroupCompleted();
|
||||
} catch (...) {
|
||||
// Ignore any exception
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Document::UndoSequenceDepth() const noexcept {
|
||||
return cb.UndoSequenceDepth();
|
||||
}
|
||||
@ -2513,6 +2527,25 @@ void Document::SetLexInterface(std::unique_ptr<LexInterface> pLexInterface) noex
|
||||
pli = std::move(pLexInterface);
|
||||
}
|
||||
|
||||
void Document::SetViewState(void *view, ViewStateShared pVSS) {
|
||||
viewData[view] = pVSS;
|
||||
}
|
||||
|
||||
ViewStateShared Document::GetViewState(void *view) const noexcept {
|
||||
const std::map<void *, ViewStateShared>::const_iterator it = viewData.find(view);
|
||||
|
||||
if (it != viewData.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void Document::TruncateUndoComments(int action) {
|
||||
for (auto &[key, value] : viewData) {
|
||||
value->TruncateUndo(action);
|
||||
}
|
||||
}
|
||||
|
||||
int SCI_METHOD Document::SetLineState(Sci_Position line, int state) {
|
||||
const int statePrevious = States()->SetLineState(line, state, LinesTotal());
|
||||
if (state != statePrevious) {
|
||||
@ -2709,6 +2742,12 @@ void Document::NotifySavePoint(bool atSavePoint) {
|
||||
}
|
||||
}
|
||||
|
||||
void Document::NotifyGroupCompleted() noexcept {
|
||||
for (const WatcherWithUserData &watcher : watchers) {
|
||||
watcher.watcher->NotifyGroupCompleted(this, watcher.userData);
|
||||
}
|
||||
}
|
||||
|
||||
void Document::NotifyModified(DocModification mh) {
|
||||
if (FlagSet(mh.modificationType, ModificationFlags::InsertText)) {
|
||||
decorations->InsertSpace(mh.position, mh.length);
|
||||
@ -2855,39 +2894,33 @@ Sci::Position Document::BraceMatch(Sci::Position position, Sci::Position /*maxRe
|
||||
const unsigned char chBrace = CharAt(position);
|
||||
const unsigned char chSeek = BraceOpposite(chBrace);
|
||||
if (chSeek == '\0')
|
||||
return - 1;
|
||||
return -1;
|
||||
const int styBrace = StyleIndexAt(position);
|
||||
int direction = -1;
|
||||
if (chBrace == '(' || chBrace == '[' || chBrace == '{' || chBrace == '<')
|
||||
direction = 1;
|
||||
int depth = 1;
|
||||
position = useStartPos ? startPos : NextPosition(position, direction);
|
||||
position = useStartPos ? startPos : position + direction;
|
||||
|
||||
// Avoid complex NextPosition call for bytes that may not cause incorrect match
|
||||
// Avoid using MovePositionOutsideChar to check DBCS trail byte
|
||||
unsigned char maxSafeChar = 0xff;
|
||||
if (dbcsCodePage != 0 && dbcsCodePage != CpUtf8) {
|
||||
maxSafeChar = (direction >= 0) ? 0x80 : DBCSMinTrailByte() - 1;
|
||||
maxSafeChar = DBCSMinTrailByte() - 1;
|
||||
}
|
||||
|
||||
while ((position >= 0) && (position < LengthNoExcept())) {
|
||||
const unsigned char chAtPos = CharAt(position);
|
||||
if (chAtPos == chBrace || chAtPos == chSeek) {
|
||||
if ((position > GetEndStyled()) || (StyleIndexAt(position) == styBrace)) {
|
||||
if (((position > GetEndStyled()) || (StyleIndexAt(position) == styBrace)) &&
|
||||
(chAtPos <= maxSafeChar || position == MovePositionOutsideChar(position, direction, false))) {
|
||||
depth += (chAtPos == chBrace) ? 1 : -1;
|
||||
if (depth == 0)
|
||||
return position;
|
||||
}
|
||||
}
|
||||
if (chAtPos <= maxSafeChar) {
|
||||
position += direction;
|
||||
} else {
|
||||
const Sci::Position positionBeforeMove = position;
|
||||
position = NextPosition(position, direction);
|
||||
if (position == positionBeforeMove)
|
||||
break;
|
||||
}
|
||||
position += direction;
|
||||
}
|
||||
return - 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2915,14 +2948,13 @@ namespace {
|
||||
*/
|
||||
class RESearchRange {
|
||||
public:
|
||||
const Document *doc;
|
||||
int increment;
|
||||
Sci::Position startPos;
|
||||
Sci::Position endPos;
|
||||
Sci::Line lineRangeStart;
|
||||
Sci::Line lineRangeEnd;
|
||||
Sci::Line lineRangeBreak;
|
||||
RESearchRange(const Document *doc_, Sci::Position minPos, Sci::Position maxPos) noexcept : doc(doc_) {
|
||||
RESearchRange(const Document *doc, Sci::Position minPos, Sci::Position maxPos) noexcept {
|
||||
increment = (minPos <= maxPos) ? 1 : -1;
|
||||
|
||||
// Range endpoints should not be inside DBCS characters or between a CR and LF,
|
||||
|
||||
@ -9,6 +9,10 @@
|
||||
#define DOCUMENT_H
|
||||
|
||||
// >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>>
|
||||
#if defined(__cplusplus)
|
||||
#include <map>
|
||||
#else
|
||||
#endif
|
||||
#include "ILoader.h"
|
||||
// <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<<
|
||||
|
||||
@ -176,6 +180,22 @@ public:
|
||||
bool isEnabled;
|
||||
};
|
||||
|
||||
// Base class for view state that can be held and transferred without understanding the contents.
|
||||
// Declared here but real implementation subclass declared in EditModel
|
||||
struct ViewState {
|
||||
ViewState() noexcept = default;
|
||||
// Deleted so ViewState objects can not be copied
|
||||
ViewState(const ViewState &) = delete;
|
||||
ViewState(ViewState &&) = delete;
|
||||
ViewState &operator=(const ViewState &) = delete;
|
||||
ViewState &operator=(ViewState &&) = delete;
|
||||
virtual ~ViewState() noexcept = default;
|
||||
|
||||
virtual void TruncateUndo(int index)=0;
|
||||
};
|
||||
|
||||
using ViewStateShared = std::shared_ptr<ViewState>;
|
||||
|
||||
struct LexerReleaser {
|
||||
// Called by unique_ptr to destroy/free the Resource
|
||||
void operator()(Scintilla::ILexer5 *pLexer) noexcept {
|
||||
@ -308,6 +328,8 @@ private:
|
||||
std::unique_ptr<RegexSearchBase> regex;
|
||||
std::unique_ptr<LexInterface> pli;
|
||||
|
||||
std::map<void *, ViewStateShared>viewData;
|
||||
|
||||
public:
|
||||
|
||||
Scintilla::EndOfLine eolMode;
|
||||
@ -400,8 +422,9 @@ public:
|
||||
}
|
||||
bool IsCollectingUndo() const noexcept { return cb.IsCollectingUndo(); }
|
||||
void BeginUndoAction(bool coalesceWithPrior=false) noexcept { cb.BeginUndoAction(coalesceWithPrior); }
|
||||
void EndUndoAction() noexcept { cb.EndUndoAction(); }
|
||||
void EndUndoAction() noexcept;
|
||||
int UndoSequenceDepth() const noexcept;
|
||||
bool AfterUndoSequenceStart() const noexcept { return cb.AfterUndoSequenceStart(); }
|
||||
void AddUndoAction(Sci::Position token, bool mayCoalesce) { cb.AddUndoAction(token, mayCoalesce); }
|
||||
void SetSavePoint();
|
||||
bool IsSavePoint() const noexcept { return cb.IsSavePoint(); }
|
||||
@ -538,6 +561,10 @@ public:
|
||||
LexInterface *GetLexInterface() const noexcept;
|
||||
void SetLexInterface(std::unique_ptr<LexInterface> pLexInterface) noexcept;
|
||||
|
||||
void SetViewState(void *view, ViewStateShared pVSS);
|
||||
ViewStateShared GetViewState(void *view) const noexcept;
|
||||
void TruncateUndoComments(int action);
|
||||
|
||||
int SCI_METHOD SetLineState(Sci_Position line, int state) override;
|
||||
int SCI_METHOD GetLineState(Sci_Position line) const noexcept override;
|
||||
Sci::Line GetMaxLineState() const noexcept;
|
||||
@ -578,6 +605,7 @@ public:
|
||||
private:
|
||||
void NotifyModifyAttempt();
|
||||
void NotifySavePoint(bool atSavePoint);
|
||||
void NotifyGroupCompleted() noexcept;
|
||||
void NotifyModified(DocModification mh);
|
||||
};
|
||||
|
||||
@ -668,6 +696,7 @@ public:
|
||||
virtual void NotifyDeleted(Document *doc, void *userData) noexcept = 0;
|
||||
virtual void NotifyStyleNeeded(Document *doc, void *userData, Sci::Position endPos) = 0;
|
||||
virtual void NotifyErrorOccurred(Document *doc, void *userData, Scintilla::Status status) = 0;
|
||||
virtual void NotifyGroupCompleted(Document *doc, void *userData) noexcept = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -58,6 +58,54 @@ using namespace Scintilla::Internal;
|
||||
Caret::Caret() noexcept :
|
||||
active(false), on(false), period(500) {}
|
||||
|
||||
SelectionSimple::SelectionSimple(const Selection &sel) {
|
||||
selType = sel.selType;
|
||||
if (sel.IsRectangular()) {
|
||||
// rectangular or thin
|
||||
// Could be large so don't remember each range, just the rectangular bounds then reconstitute when undone
|
||||
rangeRectangular = sel.RectangularCopy();
|
||||
} else {
|
||||
ranges = sel.RangesCopy();
|
||||
}
|
||||
mainRange = sel.Main();
|
||||
}
|
||||
|
||||
void ModelState::RememberSelectionForUndo(int index, const Selection &sel) {
|
||||
historyForUndo.indexCurrent = index;
|
||||
historyForUndo.ssCurrent = SelectionSimple(sel);
|
||||
}
|
||||
|
||||
void ModelState::ForgetSelectionForUndo() noexcept {
|
||||
historyForUndo.indexCurrent = -1;
|
||||
}
|
||||
|
||||
void ModelState::RememberSelectionOntoStack(int index) {
|
||||
if ((historyForUndo.indexCurrent >= 0) && (index == historyForUndo.indexCurrent + 1)) {
|
||||
// Don't overwrite initial selection save if most recent action was coalesced
|
||||
historyForUndo.stack[index] = historyForUndo.ssCurrent;
|
||||
}
|
||||
}
|
||||
|
||||
void ModelState::RememberSelectionForRedoOntoStack(int index, const Selection &sel) {
|
||||
historyForRedo.stack[index] = SelectionSimple(sel);
|
||||
}
|
||||
|
||||
const SelectionSimple *ModelState::SelectionFromStack(int index, UndoRedo history) const {
|
||||
const SelectionHistory &sh = history == UndoRedo::undo ? historyForUndo : historyForRedo;
|
||||
std::map<int, SelectionSimple>::const_iterator it = sh.stack.find(index);
|
||||
if (it != sh.stack.end()) {
|
||||
return &it->second;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void ModelState::TruncateUndo(int index) {
|
||||
std::map<int, SelectionSimple>::iterator itUndo = historyForUndo.stack.find(index);
|
||||
historyForUndo.stack.erase(itUndo, historyForUndo.stack.end());
|
||||
std::map<int, SelectionSimple>::iterator itRedo = historyForRedo.stack.find(index);
|
||||
historyForRedo.stack.erase(itRedo, historyForRedo.stack.end());
|
||||
}
|
||||
|
||||
EditModel::EditModel() : braces{} {
|
||||
inOverstrike = false;
|
||||
xOffset = 0;
|
||||
@ -135,3 +183,14 @@ InSelection EditModel::LineEndInSelection(Sci::Line lineDoc) const {
|
||||
int EditModel::GetMark(Sci::Line line) const {
|
||||
return pdoc->GetMark(line, FlagSet(changeHistoryOption, ChangeHistoryOption::Markers));
|
||||
}
|
||||
|
||||
void EditModel::EnsureModelState() {
|
||||
if (!modelState && (undoSelectionHistoryOption == UndoSelectionHistoryOption::Enabled)) {
|
||||
if (ViewStateShared vss = pdoc->GetViewState(this)) {
|
||||
modelState = std::dynamic_pointer_cast<ModelState>(vss);
|
||||
} else {
|
||||
modelState = std::make_shared<ModelState>();
|
||||
pdoc->SetViewState(this, std::static_pointer_cast<ViewState>(modelState));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,6 +21,41 @@ public:
|
||||
Caret() noexcept;
|
||||
};
|
||||
|
||||
// Simplified version of selection which won't contain rectangular selection realized
|
||||
// into ranges as too much data.
|
||||
// Just a type and single range for now.
|
||||
|
||||
struct SelectionSimple {
|
||||
std::vector<SelectionRange> ranges;
|
||||
SelectionRange rangeRectangular;
|
||||
size_t mainRange = 0;
|
||||
Selection::SelTypes selType = Selection::SelTypes::stream;
|
||||
|
||||
SelectionSimple() = default;
|
||||
explicit SelectionSimple(const Selection &sel);
|
||||
};
|
||||
|
||||
enum class UndoRedo { undo, redo };
|
||||
|
||||
struct SelectionHistory {
|
||||
int indexCurrent = 0;
|
||||
SelectionSimple ssCurrent;
|
||||
std::map<int, SelectionSimple> stack;
|
||||
};
|
||||
|
||||
struct ModelState : ViewState {
|
||||
SelectionHistory historyForUndo;
|
||||
SelectionHistory historyForRedo;
|
||||
void RememberSelectionForUndo(int index, const Selection &sel);
|
||||
void ForgetSelectionForUndo() noexcept;
|
||||
void RememberSelectionOntoStack(int index);
|
||||
void RememberSelectionForRedoOntoStack(int index, const Selection &sel);
|
||||
const SelectionSimple *SelectionFromStack(int index, UndoRedo history) const;
|
||||
virtual void TruncateUndo(int index) final;
|
||||
};
|
||||
|
||||
using ModelStateShared = std::shared_ptr<ModelState>;
|
||||
|
||||
class EditModel {
|
||||
public:
|
||||
bool inOverstrike;
|
||||
@ -61,6 +96,10 @@ public:
|
||||
|
||||
Document *pdoc;
|
||||
|
||||
Scintilla::UndoSelectionHistoryOption undoSelectionHistoryOption = UndoSelectionHistoryOption::Disabled;
|
||||
bool needRedoRemembered = false;
|
||||
ModelStateShared modelState;
|
||||
|
||||
EditModel();
|
||||
// Deleted so EditModel objects can not be copied.
|
||||
EditModel(const EditModel &) = delete;
|
||||
@ -79,6 +118,8 @@ public:
|
||||
const char *GetFoldDisplayText(Sci::Line lineDoc) const noexcept;
|
||||
InSelection LineEndInSelection(Sci::Line lineDoc) const;
|
||||
[[nodiscard]] int GetMark(Sci::Line line) const;
|
||||
|
||||
void EnsureModelState();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -2541,19 +2541,13 @@ void EditView::PaintText(Surface *surfaceWindow, const EditModel &model, const V
|
||||
|
||||
Sci::Line lineDocPrevious = -1; // Used to avoid laying out one document line multiple times
|
||||
std::shared_ptr<LineLayout> ll;
|
||||
std::vector<DrawPhase> phases;
|
||||
DrawPhase phase = DrawPhase::all;
|
||||
if ((phasesDraw == PhasesDraw::Multiple) && !bufferedDraw) {
|
||||
for (DrawPhase phase = DrawPhase::back; phase <= DrawPhase::carets; phase = static_cast<DrawPhase>(static_cast<int>(phase) * 2)) {
|
||||
phases.push_back(phase);
|
||||
}
|
||||
} else {
|
||||
phases.push_back(DrawPhase::all);
|
||||
phase = DrawPhase::back;
|
||||
}
|
||||
for (const DrawPhase &phase : phases) {
|
||||
int ypos = 0;
|
||||
if (!bufferedDraw)
|
||||
ypos += screenLinePaintFirst * vsDraw.lineHeight;
|
||||
for (;;) {
|
||||
int yposScreen = screenLinePaintFirst * vsDraw.lineHeight;
|
||||
int ypos = bufferedDraw ? 0 : yposScreen;
|
||||
Sci::Line visibleLine = model.TopLineOfMain() + screenLinePaintFirst;
|
||||
while (visibleLine < model.pcs->LinesDisplayed() && yposScreen < rcArea.bottom) {
|
||||
|
||||
@ -2572,6 +2566,10 @@ void EditView::PaintText(Surface *surfaceWindow, const EditModel &model, const V
|
||||
ll = RetrieveLineLayout(lineDoc, model);
|
||||
LayoutLine(model, surface, vsDraw, ll.get(), model.wrapWidth);
|
||||
lineDocPrevious = lineDoc;
|
||||
if (ll && model.BidirectionalEnabled()) {
|
||||
// Fill the line bidi data
|
||||
UpdateBidiData(model, vsDraw, ll.get());
|
||||
}
|
||||
}
|
||||
#if defined(TIME_PAINTING)
|
||||
durLayout += ep.Duration(true);
|
||||
@ -2599,11 +2597,6 @@ void EditView::PaintText(Surface *surfaceWindow, const EditModel &model, const V
|
||||
surface->FillRectangleAligned(rcSpacer, Fill(vsDraw.styles[StyleDefault].back));
|
||||
}
|
||||
|
||||
if (model.BidirectionalEnabled()) {
|
||||
// Fill the line bidi data
|
||||
UpdateBidiData(model, vsDraw, ll.get());
|
||||
}
|
||||
|
||||
DrawLine(surface, model, vsDraw, ll.get(), lineDoc, visibleLine, xStart, rcLine, subLine, phase);
|
||||
#if defined(TIME_PAINTING)
|
||||
durPaint += ep.Duration(true);
|
||||
@ -2642,6 +2635,11 @@ void EditView::PaintText(Surface *surfaceWindow, const EditModel &model, const V
|
||||
yposScreen += vsDraw.lineHeight;
|
||||
visibleLine++;
|
||||
}
|
||||
|
||||
if (phase >= DrawPhase::carets) {
|
||||
break;
|
||||
}
|
||||
phase = static_cast<DrawPhase>(static_cast<int>(phase) * 2);
|
||||
}
|
||||
ll.reset();
|
||||
#if defined(TIME_PAINTING)
|
||||
|
||||
@ -517,10 +517,14 @@ void Editor::RedrawSelMargin(Sci::Line line, bool allAfter) {
|
||||
}
|
||||
|
||||
PRectangle Editor::RectangleFromRange(Range r, int overlap) {
|
||||
const Sci::Line minLine = pcs->DisplayFromDoc(
|
||||
pdoc->SciLineFromPosition(r.First()));
|
||||
const Sci::Line maxLine = pcs->DisplayLastFromDoc(
|
||||
pdoc->SciLineFromPosition(r.Last()));
|
||||
const Sci::Line docLineFirst = pdoc->SciLineFromPosition(r.First());
|
||||
const Sci::Line minLine = pcs->DisplayFromDoc(docLineFirst);
|
||||
Sci::Line docLineLast = docLineFirst; // Common case where range is wholly in one document line
|
||||
if (r.Last() >= pdoc->LineStart(docLineFirst + 1)) {
|
||||
// Range covers multiple lines so need last line
|
||||
docLineLast = pdoc->SciLineFromPosition(r.Last());
|
||||
}
|
||||
const Sci::Line maxLine = pcs->DisplayLastFromDoc(docLineLast);
|
||||
const PRectangle rcClientDrawing = GetClientDrawingRectangle();
|
||||
PRectangle rc;
|
||||
const int leftTextOverlap = ((xOffset == 0) && (vs.leftMarginWidth > 0)) ? 1 : 0;
|
||||
@ -923,6 +927,37 @@ void Editor::SetLastXChosen() {
|
||||
lastXChosen = static_cast<int>(pt.x) + xOffset;
|
||||
}
|
||||
|
||||
void Editor::RememberSelectionForUndo(int index) {
|
||||
EnsureModelState();
|
||||
if (modelState) {
|
||||
modelState->RememberSelectionForUndo(index, sel);
|
||||
needRedoRemembered = true;
|
||||
// Remember selection at end of processing current message
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::RememberSelectionOntoStack(int index) {
|
||||
EnsureModelState();
|
||||
if (modelState) {
|
||||
// Is undo currently inside a group?
|
||||
if (!pdoc->AfterUndoSequenceStart()) {
|
||||
// Don't remember selections inside a grouped sequence as can only
|
||||
// unto or redo to the start and end of the group.
|
||||
modelState->RememberSelectionOntoStack(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::RememberCurrentSelectionForRedoOntoStack() {
|
||||
if (needRedoRemembered && (pdoc->UndoSequenceDepth() == 0)) {
|
||||
EnsureModelState();
|
||||
if (modelState) {
|
||||
modelState->RememberSelectionForRedoOntoStack(pdoc->UndoCurrent(), sel);
|
||||
needRedoRemembered = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::ScrollTo(Sci::Line line, bool moveThumb) {
|
||||
const Sci::Line topLineNew = std::clamp<Sci::Line>(line, 0, MaxScrollPos());
|
||||
if (topLineNew != topLine) {
|
||||
@ -1000,21 +1035,25 @@ void Editor::MoveSelectedLines(int lineDelta) {
|
||||
// if selection doesn't end at the beginning of a line greater than that of the start,
|
||||
// then set it at the beginning of the next one
|
||||
Sci::Position selectionEnd = SelectionEnd().Position();
|
||||
const Sci::Line endLine = pdoc->SciLineFromPosition(selectionEnd);
|
||||
Sci::Line endLine = pdoc->SciLineFromPosition(selectionEnd);
|
||||
const Sci::Position beginningOfEndLine = pdoc->LineStart(endLine);
|
||||
bool appendEol = false;
|
||||
if (selectionEnd > beginningOfEndLine
|
||||
|| selectionStart == selectionEnd) {
|
||||
selectionEnd = pdoc->LineStart(endLine + 1);
|
||||
appendEol = (selectionEnd == pdoc->Length() && pdoc->SciLineFromPosition(selectionEnd) == endLine);
|
||||
endLine = pdoc->SciLineFromPosition(selectionEnd);
|
||||
}
|
||||
|
||||
// if there's nowhere for the selection to move
|
||||
// (i.e. at the beginning going up or at the end going down),
|
||||
// stop it right there!
|
||||
const bool docEndLineEmpty = pdoc->LineStart(endLine) == pdoc->Length();
|
||||
if ((selectionStart == 0 && lineDelta < 0)
|
||||
|| (selectionEnd == pdoc->Length() && lineDelta > 0)
|
||||
|| selectionStart == selectionEnd) {
|
||||
|| (selectionEnd == pdoc->Length() && lineDelta > 0
|
||||
&& !docEndLineEmpty) // allow moving when end line of document is empty
|
||||
|| ((selectionStart == selectionEnd)
|
||||
&& !(lineDelta < 0 && docEndLineEmpty && selectionEnd == pdoc->Length()))) { // allow moving-up last empty line
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2080,13 +2119,13 @@ void Editor::InsertCharacter(std::string_view sv, CharacterSource charSource) {
|
||||
}
|
||||
}
|
||||
}
|
||||
ThinRectangularRange();
|
||||
}
|
||||
if (wrapOccurred) {
|
||||
SetScrollBars();
|
||||
SetVerticalScrollPos();
|
||||
Redraw();
|
||||
}
|
||||
ThinRectangularRange();
|
||||
// If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
|
||||
EnsureCaretVisible();
|
||||
// Avoid blinking during rapid typing:
|
||||
@ -2362,22 +2401,44 @@ void Editor::SelectAll() {
|
||||
Redraw();
|
||||
}
|
||||
|
||||
void Editor::RestoreSelection(Sci::Position newPos, UndoRedo history) {
|
||||
EnsureModelState();
|
||||
if ((undoSelectionHistoryOption == UndoSelectionHistoryOption::Enabled) && modelState) {
|
||||
// Undo wants the element after the current as it just undid it
|
||||
const int index = pdoc->UndoCurrent() + (history == UndoRedo::undo ? 1 : 0);
|
||||
const SelectionSimple *pss = modelState->SelectionFromStack(index, history);
|
||||
if (pss) {
|
||||
sel.selType = pss->selType;
|
||||
if (sel.IsRectangular()) {
|
||||
sel.Rectangular() = pss->rangeRectangular;
|
||||
// Reconstitute ranges from rectangular range
|
||||
SetRectangularRange();
|
||||
} else {
|
||||
sel.SetRanges(pss->ranges);
|
||||
}
|
||||
// Unsure if this is safe with SetMain potentially failing if document doesn't appear the same.
|
||||
// Maybe this can occur if the user changes font or wrap mode?
|
||||
sel.SetMain(pss->mainRange);
|
||||
newPos = -1; // Used selection from stack so don't use position returned from undo/redo.
|
||||
}
|
||||
}
|
||||
if (newPos >= 0)
|
||||
SetEmptySelection(newPos);
|
||||
EnsureCaretVisible();
|
||||
}
|
||||
|
||||
void Editor::Undo() {
|
||||
if (pdoc->CanUndo()) {
|
||||
InvalidateCaret();
|
||||
const Sci::Position newPos = pdoc->Undo();
|
||||
if (newPos >= 0)
|
||||
SetEmptySelection(newPos);
|
||||
EnsureCaretVisible();
|
||||
RestoreSelection(newPos, UndoRedo::undo);
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::Redo() {
|
||||
if (pdoc->CanRedo()) {
|
||||
const Sci::Position newPos = pdoc->Redo();
|
||||
if (newPos >= 0)
|
||||
SetEmptySelection(newPos);
|
||||
EnsureCaretVisible();
|
||||
RestoreSelection(newPos, UndoRedo::redo);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2453,6 +2514,17 @@ void Editor::NotifyErrorOccurred(Document *, void *, Status status) {
|
||||
errorStatus = status;
|
||||
}
|
||||
|
||||
void Editor::NotifyGroupCompleted(Document *, void *) noexcept {
|
||||
// RememberCurrentSelectionForRedoOntoStack may throw (for memory exhaustion)
|
||||
// but this method may not as it is called in UndoGroup destructor so ignore
|
||||
// exception.
|
||||
try {
|
||||
RememberCurrentSelectionForRedoOntoStack();
|
||||
} catch (...) {
|
||||
// Ignore any exception
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::NotifyChar(int ch, CharacterSource charSource) {
|
||||
NotificationData scn = {};
|
||||
scn.nmhdr.code = Notification::CharAdded;
|
||||
@ -2721,6 +2793,15 @@ void Editor::NotifyModified(Document *, DocModification mh, void *) {
|
||||
view.llc.Invalidate(LineLayout::ValidLevel::checkTextAndStyle);
|
||||
}
|
||||
} else {
|
||||
if ((undoSelectionHistoryOption == UndoSelectionHistoryOption::Enabled) &&
|
||||
FlagSet(mh.modificationType, ModificationFlags::User)) {
|
||||
if (FlagSet(mh.modificationType, ModificationFlags::BeforeInsert | ModificationFlags::BeforeDelete)) {
|
||||
RememberSelectionForUndo(pdoc->UndoCurrent());
|
||||
}
|
||||
if (FlagSet(mh.modificationType, ModificationFlags::InsertText | ModificationFlags::DeleteText)) {
|
||||
RememberSelectionOntoStack(pdoc->UndoCurrent());
|
||||
}
|
||||
}
|
||||
// Move selection and brace highlights
|
||||
if (FlagSet(mh.modificationType, ModificationFlags::InsertText)) {
|
||||
sel.MovePositions(true, mh.position, mh.length);
|
||||
@ -5473,6 +5554,7 @@ void Editor::SetDocPointer(Document *document) {
|
||||
pdoc = document;
|
||||
}
|
||||
pdoc->AddRef();
|
||||
modelState.reset();
|
||||
pcs = ContractionStateCreate(pdoc->IsLarge());
|
||||
|
||||
// Ensure all positions within document
|
||||
@ -8661,6 +8743,13 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) {
|
||||
case Message::GetChangeHistory:
|
||||
return static_cast<sptr_t>(changeHistoryOption);
|
||||
|
||||
case Message::SetUndoSelectionHistory:
|
||||
undoSelectionHistoryOption = static_cast<UndoSelectionHistoryOption>(wParam);
|
||||
break;
|
||||
|
||||
case Message::GetUndoSelectionHistory:
|
||||
return static_cast<sptr_t>(undoSelectionHistoryOption);
|
||||
|
||||
case Message::SetExtraAscent:
|
||||
vs.extraAscent = static_cast<int>(wParam);
|
||||
InvalidateStyleRedraw();
|
||||
@ -9070,6 +9159,11 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) {
|
||||
default:
|
||||
return DefWndProc(iMessage, wParam, lParam);
|
||||
}
|
||||
|
||||
// If there was a change that needs its selection saved and it wasn't explicity saved
|
||||
// then do that here.
|
||||
RememberCurrentSelectionForRedoOntoStack();
|
||||
|
||||
//Platform::DebugPrintf("end wnd proc\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -182,6 +182,8 @@ constexpr XYScrollOptions operator|(XYScrollOptions a, XYScrollOptions b) noexce
|
||||
return static_cast<XYScrollOptions>(static_cast<int>(a) | static_cast<int>(b));
|
||||
}
|
||||
|
||||
struct SelectionStack;
|
||||
|
||||
/**
|
||||
*/
|
||||
class Editor : public EditModel, public DocWatcher {
|
||||
@ -371,6 +373,9 @@ protected: // ScintillaBase subclass needs access to much of Editor
|
||||
SelectionPosition MovePositionSoVisible(Sci::Position pos, int moveDir);
|
||||
Point PointMainCaret();
|
||||
void SetLastXChosen();
|
||||
void RememberSelectionForUndo(int index);
|
||||
void RememberSelectionOntoStack(int index);
|
||||
void RememberCurrentSelectionForRedoOntoStack();
|
||||
|
||||
void ScrollTo(Sci::Line line, bool moveThumb=true);
|
||||
virtual void ScrollText(Sci::Line linesToMove);
|
||||
@ -447,6 +452,7 @@ protected: // ScintillaBase subclass needs access to much of Editor
|
||||
virtual void Paste() = 0;
|
||||
void Clear();
|
||||
virtual void SelectAll();
|
||||
void RestoreSelection(Sci::Position newPos, UndoRedo history);
|
||||
virtual void Undo();
|
||||
virtual void Redo();
|
||||
void DelCharBack(bool allowLineStartDeletion);
|
||||
@ -483,6 +489,7 @@ protected: // ScintillaBase subclass needs access to much of Editor
|
||||
void NotifyDeleted(Document *document, void *userData) noexcept override;
|
||||
void NotifyStyleNeeded(Document *doc, void *userData, Sci::Position endStyleNeeded) override;
|
||||
void NotifyErrorOccurred(Document *doc, void *userData, Scintilla::Status status) override;
|
||||
void NotifyGroupCompleted(Document *, void *) noexcept override;
|
||||
void NotifyMacroRecord(Scintilla::Message iMessage, Scintilla::uptr_t wParam, Scintilla::sptr_t lParam);
|
||||
|
||||
void ContainerNeedsUpdate(Scintilla::Update flags) noexcept;
|
||||
|
||||
@ -185,7 +185,7 @@ public:
|
||||
T upper = Partitions();
|
||||
do {
|
||||
const T middle = (upper + lower + 1) / 2; // Round high
|
||||
T posMiddle = body.ValueAt(middle);
|
||||
T posMiddle = body[middle];
|
||||
if (middle > stepPartition)
|
||||
posMiddle += stepLength;
|
||||
if (pos < posMiddle) {
|
||||
|
||||
@ -80,8 +80,6 @@ void RunStyles<DISTANCE, STYLE>::RemoveRunIfSameAsPrevious(DISTANCE run) {
|
||||
|
||||
template <typename DISTANCE, typename STYLE>
|
||||
RunStyles<DISTANCE, STYLE>::RunStyles() {
|
||||
starts = Partitioning<DISTANCE>(8);
|
||||
styles = SplitVector<STYLE>();
|
||||
styles.InsertValue(0, 2, 0);
|
||||
}
|
||||
|
||||
@ -136,7 +134,8 @@ FillResult<DISTANCE> RunStyles<DISTANCE, STYLE>::FillRange(DISTANCE position, ST
|
||||
return resultNoChange;
|
||||
}
|
||||
DISTANCE runEnd = RunFromPosition(end);
|
||||
if (styles.ValueAt(runEnd) == value) {
|
||||
const STYLE valueCurrent = styles.ValueAt(runEnd);
|
||||
if (valueCurrent == value) {
|
||||
// End already has value so trim range.
|
||||
end = starts.PositionFromPartition(runEnd);
|
||||
if (position >= end) {
|
||||
@ -145,6 +144,22 @@ FillResult<DISTANCE> RunStyles<DISTANCE, STYLE>::FillRange(DISTANCE position, ST
|
||||
}
|
||||
fillLength = end - position;
|
||||
} else {
|
||||
const DISTANCE startRun = starts.PositionFromPartition(runEnd);
|
||||
if (position > startRun) {
|
||||
const DISTANCE runNext = runEnd + 1;
|
||||
const DISTANCE endRun = starts.PositionFromPartition(runNext);
|
||||
if (end < endRun) {
|
||||
// New piece is completely inside a run with a different value so its a simple
|
||||
// insertion of two points [ (position, value), (end, valueCurrent) ]
|
||||
const DISTANCE range[] { position, end};
|
||||
starts.InsertPartitions(runEnd + 1, range, 2);
|
||||
// Temporary runEndIndex silences non-useful arithmetic overflow warnings
|
||||
const ptrdiff_t runEndIndex = runEnd;
|
||||
styles.Insert(runEndIndex + 1, value);
|
||||
styles.Insert(runEndIndex + 2, valueCurrent);
|
||||
return { true, position, fillLength };
|
||||
}
|
||||
}
|
||||
runEnd = SplitRun(end);
|
||||
}
|
||||
DISTANCE runStart = RunFromPosition(position);
|
||||
@ -172,9 +187,8 @@ FillResult<DISTANCE> RunStyles<DISTANCE, STYLE>::FillRange(DISTANCE position, ST
|
||||
runEnd = RunFromPosition(end);
|
||||
RemoveRunIfEmpty(runEnd);
|
||||
return result;
|
||||
} else {
|
||||
return resultNoChange;
|
||||
}
|
||||
return resultNoChange;
|
||||
}
|
||||
|
||||
template <typename DISTANCE, typename STYLE>
|
||||
@ -213,7 +227,7 @@ void RunStyles<DISTANCE, STYLE>::InsertSpace(DISTANCE position, DISTANCE insertL
|
||||
|
||||
template <typename DISTANCE, typename STYLE>
|
||||
void RunStyles<DISTANCE, STYLE>::DeleteAll() {
|
||||
starts = Partitioning<DISTANCE>(8);
|
||||
starts = Partitioning<DISTANCE>();
|
||||
styles = SplitVector<STYLE>();
|
||||
styles.InsertValue(0, 2, 0);
|
||||
}
|
||||
|
||||
@ -52,13 +52,6 @@ void SelectionPosition::MoveForInsertDelete(bool insertion, Sci::Position startC
|
||||
}
|
||||
}
|
||||
|
||||
bool SelectionPosition::operator <(const SelectionPosition &other) const noexcept {
|
||||
if (position == other.position)
|
||||
return virtualSpace < other.virtualSpace;
|
||||
else
|
||||
return position < other.position;
|
||||
}
|
||||
|
||||
bool SelectionPosition::operator >(const SelectionPosition &other) const noexcept {
|
||||
if (position == other.position)
|
||||
return virtualSpace > other.virtualSpace;
|
||||
@ -217,6 +210,10 @@ SelectionRange &Selection::Rectangular() noexcept {
|
||||
return rangeRectangular;
|
||||
}
|
||||
|
||||
SelectionRange Selection::RectangularCopy() const noexcept {
|
||||
return rangeRectangular;
|
||||
}
|
||||
|
||||
SelectionSegment Selection::Limits() const noexcept {
|
||||
PLATFORM_ASSERT(!ranges.empty());
|
||||
SelectionSegment sr(ranges[0].anchor, ranges[0].caret);
|
||||
@ -428,11 +425,13 @@ void Selection::Clear() noexcept {
|
||||
if (ranges.size() > 1) {
|
||||
ranges.erase(ranges.begin() + 1, ranges.end());
|
||||
}
|
||||
mainRange = 0;
|
||||
selType = SelTypes::stream;
|
||||
moveExtends = false;
|
||||
ranges[mainRange].Reset();
|
||||
ranges[0].Reset();
|
||||
rangesSaved.clear();
|
||||
rangeRectangular.Reset();
|
||||
mainRange = 0;
|
||||
moveExtends = false;
|
||||
tentativeMain = false;
|
||||
selType = SelTypes::stream;
|
||||
}
|
||||
|
||||
void Selection::RemoveDuplicates() noexcept {
|
||||
@ -456,3 +455,6 @@ void Selection::RotateMain() noexcept {
|
||||
mainRange = (mainRange + 1) % ranges.size();
|
||||
}
|
||||
|
||||
void Selection::SetRanges(const Ranges &rangesToSet) {
|
||||
ranges = rangesToSet;
|
||||
}
|
||||
|
||||
@ -11,10 +11,11 @@
|
||||
namespace Scintilla::Internal {
|
||||
|
||||
class SelectionPosition {
|
||||
Sci::Position position;
|
||||
Sci::Position virtualSpace;
|
||||
Sci::Position position = Sci::invalidPosition;
|
||||
Sci::Position virtualSpace = 0;
|
||||
public:
|
||||
explicit SelectionPosition(Sci::Position position_= Sci::invalidPosition, Sci::Position virtualSpace_=0) noexcept : position(position_), virtualSpace(virtualSpace_) {
|
||||
constexpr SelectionPosition() noexcept = default;
|
||||
constexpr explicit SelectionPosition(Sci::Position position_, Sci::Position virtualSpace_=0) noexcept : position(position_), virtualSpace(virtualSpace_) {
|
||||
PLATFORM_ASSERT(virtualSpace < 800000000);
|
||||
if (virtualSpace < 0)
|
||||
virtualSpace = 0;
|
||||
@ -24,13 +25,20 @@ public:
|
||||
virtualSpace = 0;
|
||||
}
|
||||
void MoveForInsertDelete(bool insertion, Sci::Position startChange, Sci::Position length, bool moveForEqual) noexcept;
|
||||
bool operator ==(const SelectionPosition &other) const noexcept {
|
||||
return position == other.position && virtualSpace == other.virtualSpace;
|
||||
[[nodiscard]] constexpr bool operator ==(const SelectionPosition &other) const noexcept {
|
||||
return (position == other.position) && (virtualSpace == other.virtualSpace);
|
||||
}
|
||||
bool operator <(const SelectionPosition &other) const noexcept;
|
||||
bool operator >(const SelectionPosition &other) const noexcept;
|
||||
bool operator <=(const SelectionPosition &other) const noexcept;
|
||||
bool operator >=(const SelectionPosition &other) const noexcept;
|
||||
[[nodiscard]] constexpr bool operator !=(const SelectionPosition &other) const noexcept {
|
||||
return (position != other.position) || (virtualSpace != other.virtualSpace);
|
||||
}
|
||||
[[nodiscard]] constexpr bool operator <(const SelectionPosition &other) const noexcept {
|
||||
if (position == other.position)
|
||||
return virtualSpace < other.virtualSpace;
|
||||
return position < other.position;
|
||||
}
|
||||
[[nodiscard]] bool operator >(const SelectionPosition &other) const noexcept;
|
||||
[[nodiscard]] bool operator <=(const SelectionPosition &other) const noexcept;
|
||||
[[nodiscard]] bool operator >=(const SelectionPosition &other) const noexcept;
|
||||
Sci::Position Position() const noexcept {
|
||||
return position;
|
||||
}
|
||||
@ -61,9 +69,8 @@ public:
|
||||
struct SelectionSegment {
|
||||
SelectionPosition start;
|
||||
SelectionPosition end;
|
||||
SelectionSegment() noexcept : start(), end() {
|
||||
}
|
||||
SelectionSegment(SelectionPosition a, SelectionPosition b) noexcept {
|
||||
constexpr SelectionSegment() noexcept = default;
|
||||
constexpr SelectionSegment(SelectionPosition a, SelectionPosition b) noexcept {
|
||||
if (a < b) {
|
||||
start = a;
|
||||
end = b;
|
||||
@ -96,15 +103,14 @@ struct SelectionRange {
|
||||
SelectionPosition caret;
|
||||
SelectionPosition anchor;
|
||||
|
||||
SelectionRange() noexcept : caret(), anchor() {
|
||||
constexpr SelectionRange() noexcept = default;
|
||||
constexpr explicit SelectionRange(SelectionPosition single) noexcept : caret(single), anchor(single) {
|
||||
}
|
||||
explicit SelectionRange(SelectionPosition single) noexcept : caret(single), anchor(single) {
|
||||
constexpr explicit SelectionRange(Sci::Position single) noexcept : caret(single), anchor(single) {
|
||||
}
|
||||
explicit SelectionRange(Sci::Position single) noexcept : caret(single), anchor(single) {
|
||||
constexpr SelectionRange(SelectionPosition caret_, SelectionPosition anchor_) noexcept : caret(caret_), anchor(anchor_) {
|
||||
}
|
||||
SelectionRange(SelectionPosition caret_, SelectionPosition anchor_) noexcept : caret(caret_), anchor(anchor_) {
|
||||
}
|
||||
SelectionRange(Sci::Position caret_, Sci::Position anchor_) noexcept : caret(caret_), anchor(anchor_) {
|
||||
constexpr SelectionRange(Sci::Position caret_, Sci::Position anchor_) noexcept : caret(caret_), anchor(anchor_) {
|
||||
}
|
||||
bool Empty() const noexcept {
|
||||
return anchor == caret;
|
||||
@ -147,8 +153,9 @@ struct SelectionRange {
|
||||
enum InSelection { inNone, inMain, inAdditional };
|
||||
|
||||
class Selection {
|
||||
std::vector<SelectionRange> ranges;
|
||||
std::vector<SelectionRange> rangesSaved;
|
||||
using Ranges = std::vector<SelectionRange>;
|
||||
Ranges ranges;
|
||||
Ranges rangesSaved;
|
||||
SelectionRange rangeRectangular;
|
||||
size_t mainRange;
|
||||
bool moveExtends;
|
||||
@ -157,11 +164,12 @@ public:
|
||||
enum class SelTypes { none, stream, rectangle, lines, thin };
|
||||
SelTypes selType;
|
||||
|
||||
Selection();
|
||||
Selection(); // Allocates so may throw.
|
||||
bool IsRectangular() const noexcept;
|
||||
Sci::Position MainCaret() const noexcept;
|
||||
Sci::Position MainAnchor() const noexcept;
|
||||
SelectionRange &Rectangular() noexcept;
|
||||
SelectionRange RectangularCopy() const noexcept;
|
||||
SelectionSegment Limits() const noexcept;
|
||||
// This is for when you want to move the caret in response to a
|
||||
// user direction command - for rectangular selections, use the range
|
||||
@ -198,9 +206,10 @@ public:
|
||||
void RemoveDuplicates() noexcept;
|
||||
void RotateMain() noexcept;
|
||||
bool Tentative() const noexcept { return tentativeMain; }
|
||||
std::vector<SelectionRange> RangesCopy() const {
|
||||
Ranges RangesCopy() const {
|
||||
return ranges;
|
||||
}
|
||||
void SetRanges(const Ranges &rangesToSet);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -27,8 +27,6 @@ private:
|
||||
}
|
||||
public:
|
||||
SparseVector() : empty() {
|
||||
starts = Partitioning<Sci::Position>(8);
|
||||
values = SplitVector<T>();
|
||||
values.InsertEmpty(0, 2);
|
||||
}
|
||||
Sci::Position Length() const noexcept {
|
||||
@ -158,7 +156,7 @@ public:
|
||||
Check();
|
||||
}
|
||||
void DeleteAll() {
|
||||
starts = Partitioning<Sci::Position>(8);
|
||||
starts = Partitioning<Sci::Position>();
|
||||
values = SplitVector<T>();
|
||||
values.InsertEmpty(0, 2);
|
||||
}
|
||||
|
||||
@ -195,7 +195,7 @@ public:
|
||||
}
|
||||
RoomFor(insertLength);
|
||||
GapTo(position);
|
||||
std::fill(body.data() + part1Length, body.data() + part1Length + insertLength, v);
|
||||
std::fill_n(body.data() + part1Length, insertLength, v);
|
||||
lengthBody += insertLength;
|
||||
part1Length += insertLength;
|
||||
gapLength -= insertLength;
|
||||
@ -214,10 +214,8 @@ public:
|
||||
}
|
||||
RoomFor(insertLength);
|
||||
GapTo(position);
|
||||
for (ptrdiff_t elem = part1Length; elem < part1Length + insertLength; elem++) {
|
||||
T emptyOne = {};
|
||||
body[elem] = std::move(emptyOne);
|
||||
}
|
||||
T *ptr = body.data() + part1Length;
|
||||
std::uninitialized_value_construct_n(ptr, insertLength);
|
||||
lengthBody += insertLength;
|
||||
part1Length += insertLength;
|
||||
gapLength -= insertLength;
|
||||
@ -242,7 +240,7 @@ public:
|
||||
}
|
||||
RoomFor(insertLength);
|
||||
GapTo(positionToInsert);
|
||||
std::copy(s + positionFrom, s + positionFrom + insertLength, body.data() + part1Length);
|
||||
std::copy_n(s + positionFrom, insertLength, body.data() + part1Length);
|
||||
lengthBody += insertLength;
|
||||
part1Length += insertLength;
|
||||
gapLength -= insertLength;
|
||||
@ -288,11 +286,11 @@ public:
|
||||
if (range1Length > part1AfterPosition)
|
||||
range1Length = part1AfterPosition;
|
||||
}
|
||||
std::copy(body.data() + position, body.data() + position + range1Length, buffer);
|
||||
std::copy_n(body.data() + position, range1Length, buffer);
|
||||
buffer += range1Length;
|
||||
position = position + range1Length + gapLength;
|
||||
const ptrdiff_t range2Length = retrieveLength - range1Length;
|
||||
std::copy(body.data() + position, body.data() + position + range2Length, buffer);
|
||||
std::copy_n(body.data() + position, range2Length, buffer);
|
||||
}
|
||||
|
||||
/// Compact the buffer and return a pointer to the first element.
|
||||
|
||||
@ -354,6 +354,14 @@ int UndoHistory::UndoSequenceDepth() const noexcept {
|
||||
return undoSequenceDepth;
|
||||
}
|
||||
|
||||
bool UndoHistory::AfterUndoSequenceStart() const noexcept {
|
||||
if (currentAction == 0) {
|
||||
return false;
|
||||
}
|
||||
// Count back to last sequence start?
|
||||
return !actions.AtStart(currentAction-1);
|
||||
}
|
||||
|
||||
void UndoHistory::DropUndoSequence() noexcept {
|
||||
undoSequenceDepth = 0;
|
||||
}
|
||||
|
||||
@ -102,6 +102,7 @@ public:
|
||||
void BeginUndoAction(bool mayCoalesce=false) noexcept;
|
||||
void EndUndoAction() noexcept;
|
||||
int UndoSequenceDepth() const noexcept;
|
||||
bool AfterUndoSequenceStart() const noexcept;
|
||||
void DropUndoSequence() noexcept;
|
||||
void DeleteUndoHistory() noexcept;
|
||||
|
||||
|
||||
@ -1 +1 @@
|
||||
553
|
||||
554
|
||||
|
||||
@ -6,8 +6,8 @@
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#define VERSION_SCINTILLA "5.5.3"
|
||||
#define VERSION_WORDS 5, 5, 3, 0
|
||||
#define VERSION_SCINTILLA "5.5.4"
|
||||
#define VERSION_WORDS 5, 5, 4, 0
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION VERSION_WORDS
|
||||
|
||||
@ -272,7 +272,7 @@ public:
|
||||
return ImmGetCompositionStringW(hIMC, GCS_CURSORPOS, nullptr, 0);
|
||||
}
|
||||
|
||||
std::vector<BYTE> GetImeAttributes() {
|
||||
std::vector<BYTE> GetImeAttributes() const {
|
||||
const int attrLen = ::ImmGetCompositionStringW(hIMC, GCS_COMPATTR, nullptr, 0);
|
||||
std::vector<BYTE> attr(attrLen, 0);
|
||||
::ImmGetCompositionStringW(hIMC, GCS_COMPATTR, &attr[0], static_cast<DWORD>(attr.size()));
|
||||
@ -284,7 +284,7 @@ public:
|
||||
return byteLen / sizeof(wchar_t);
|
||||
}
|
||||
|
||||
std::wstring GetCompositionString(DWORD dwIndex) {
|
||||
std::wstring GetCompositionString(DWORD dwIndex) const {
|
||||
const LONG byteLen = ::ImmGetCompositionStringW(hIMC, dwIndex, nullptr, 0);
|
||||
std::wstring wcs(byteLen / 2, 0);
|
||||
::ImmGetCompositionStringW(hIMC, dwIndex, &wcs[0], byteLen);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user