From 4040c66fc31c7e537d063c65ed1e734e974250c2 Mon Sep 17 00:00:00 2001 From: Martijn Laan <1092369+martijnlaan@users.noreply.github.com> Date: Thu, 20 Jun 2024 08:23:46 +1000 Subject: Feature [feature-requests:#1518]. Cherry pick SCI_CUTALLOWLINE from isscint. --- call/ScintillaCall.cxx | 4 +++ doc/ScintillaDoc.html | 7 +++++ doc/ScintillaHistory.html | 5 ++++ include/Scintilla.h | 1 + include/Scintilla.iface | 3 ++ include/ScintillaCall.h | 1 + include/ScintillaMessages.h | 1 + src/Editor.cxx | 67 +++++++++++++++++++++++++++++++++------------ src/Editor.h | 3 ++ test/simpleTests.py | 13 +++++++++ win32/ScintillaWin.cxx | 2 +- 11 files changed, 89 insertions(+), 18 deletions(-) diff --git a/call/ScintillaCall.cxx b/call/ScintillaCall.cxx index 78100e774..d6c9ece4d 100644 --- a/call/ScintillaCall.cxx +++ b/call/ScintillaCall.cxx @@ -2711,6 +2711,10 @@ void ScintillaCall::CopyAllowLine() { Call(Message::CopyAllowLine); } +void ScintillaCall::CutAllowLine() { + Call(Message::CutAllowLine); +} + void *ScintillaCall::CharacterPointer() { return reinterpret_cast(Call(Message::GetCharacterPointer)); } diff --git a/doc/ScintillaDoc.html b/doc/ScintillaDoc.html index 5417fa8dd..ed8db883d 100644 --- a/doc/ScintillaDoc.html +++ b/doc/ScintillaDoc.html @@ -1852,6 +1852,7 @@ struct Sci_TextToFindFull { SCI_COPYRANGE(position start, position end)
SCI_COPYTEXT(position length, const char *text)
SCI_COPYALLOWLINE
+ SCI_CUTALLOWLINE
SCI_SETPASTECONVERTENDINGS(bool convert)
SCI_GETPASTECONVERTENDINGS → bool
SCI_REPLACERECTANGULAR(position length, const char *text)
@@ -1863,6 +1864,7 @@ struct Sci_TextToFindFull { SCI_CLEAR
SCI_CANPASTE → bool
SCI_COPYALLOWLINE
+ SCI_CUTALLOWLINE
These commands perform the standard tasks of cutting and copying data to the clipboard, pasting from the clipboard into the document, and clearing the document. SCI_CANPASTE returns non-zero if the document isn't read-only and if the selection @@ -1880,6 +1882,11 @@ struct Sci_TextToFindFull {

SCI_COPYALLOWLINE works the same as SCI_COPY except that if the selection is empty then the current line is copied. On Windows, an extra "MSDEVLineSelect" marker is added to the clipboard which is then used in SCI_PASTE to paste + the whole line before the current line.

+ +

SCI_CUTALLOWLINE works the same as SCI_CUT except that if the + selection is empty then the current line is cut. On Windows, an extra "MSDEVLineSelect" marker + is added to the clipboard which is then used in SCI_PASTE to paste the whole line before the current line.

SCI_COPYRANGE(position start, position end)
diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html index 3bf4c94fb..4b0358ed4 100644 --- a/doc/ScintillaHistory.html +++ b/doc/ScintillaHistory.html @@ -580,6 +580,7 @@ Chengzhi Li Gary James Tsuyoshi Miyake + Martijn Laan

Releases

@@ -591,6 +592,10 @@ Released 23 April 2024.
  • + SCI_CUTALLOWLINE added which is similar to SCI_COPYALLOWLINE but also deletes the copied text. + Feature #1518. +
  • +
  • Increase maximum zoom set interactively to +60 points. Feature #1517.
  • diff --git a/include/Scintilla.h b/include/Scintilla.h index 75583a824..b51c8c2ab 100644 --- a/include/Scintilla.h +++ b/include/Scintilla.h @@ -976,6 +976,7 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP #define SCI_SETLAYOUTTHREADS 2775 #define SCI_GETLAYOUTTHREADS 2776 #define SCI_COPYALLOWLINE 2519 +#define SCI_CUTALLOWLINE 2810 #define SCI_GETCHARACTERPOINTER 2520 #define SCI_GETRANGEPOINTER 2643 #define SCI_GETGAPPOSITION 2644 diff --git a/include/Scintilla.iface b/include/Scintilla.iface index 72d2a7d41..bba11003b 100644 --- a/include/Scintilla.iface +++ b/include/Scintilla.iface @@ -2657,6 +2657,9 @@ get int GetLayoutThreads=2776(,) # Copy the selection, if selection empty copy the line with the caret fun void CopyAllowLine=2519(,) +# Cut the selection, if selection empty cut the line with the caret +fun void CutAllowLine=2810(,) + # Compact the document buffer and return a read-only pointer to the # characters in the document. get pointer GetCharacterPointer=2520(,) diff --git a/include/ScintillaCall.h b/include/ScintillaCall.h index 2f2e4f0cb..5db9c38d7 100644 --- a/include/ScintillaCall.h +++ b/include/ScintillaCall.h @@ -723,6 +723,7 @@ public: void SetLayoutThreads(int threads); int LayoutThreads(); void CopyAllowLine(); + void CutAllowLine(); void *CharacterPointer(); void *RangePointer(Position start, Position lengthRange); Position GapPosition(); diff --git a/include/ScintillaMessages.h b/include/ScintillaMessages.h index a00ed44b4..a2e91c92f 100644 --- a/include/ScintillaMessages.h +++ b/include/ScintillaMessages.h @@ -637,6 +637,7 @@ enum class Message { SetLayoutThreads = 2775, GetLayoutThreads = 2776, CopyAllowLine = 2519, + CutAllowLine = 2810, GetCharacterPointer = 2520, GetRangePointer = 2643, GetGapPosition = 2644, diff --git a/src/Editor.cxx b/src/Editor.cxx index 1bcaca2ef..12150dcda 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -2267,6 +2267,21 @@ void Editor::CopyAllowLine() { CopyToClipboard(selectedText); } +void Editor::CutAllowLine() { + if (sel.Empty()) { + pdoc->CheckReadOnly(); + if (!pdoc->IsReadOnly()) { + SelectionText selectedText; + if (CopyLineRange(&selectedText, false)) { + CopyToClipboard(selectedText); + LineDelete(); + } + } + } else { + Cut(); + } +} + void Editor::Cut() { pdoc->CheckReadOnly(); if (!pdoc->IsReadOnly() && !SelectionContainsProtected()) { @@ -2959,6 +2974,7 @@ void Editor::NotifyMacroRecord(Message iMessage, uptr_t wParam, sptr_t lParam) { case Message::PageDownRectExtend: case Message::SelectionDuplicate: case Message::CopyAllowLine: + case Message::CutAllowLine: case Message::VerticalCentreCaret: case Message::MoveSelectedLinesUp: case Message::MoveSelectedLinesDown: @@ -3081,6 +3097,13 @@ void Editor::ChangeCaseOfSelection(CaseMapping caseMapping) { } } +void Editor::LineDelete() { + const Sci::Line line = pdoc->SciLineFromPosition(sel.MainCaret()); + const Sci::Position start = pdoc->LineStart(line); + const Sci::Position end = pdoc->LineStart(line + 1); + pdoc->DeleteChars(start, end - start); +} + void Editor::LineTranspose() { const Sci::Line line = pdoc->SciLineFromPosition(sel.MainCaret()); if (line > 0) { @@ -3991,12 +4014,8 @@ int Editor::KeyCommand(Message iMessage) { SetLastXChosen(); } break; - case Message::LineDelete: { - const Sci::Line line = pdoc->SciLineFromPosition(sel.MainCaret()); - const Sci::Position start = pdoc->LineStart(line); - const Sci::Position end = pdoc->LineStart(line + 1); - pdoc->DeleteChars(start, end - start); - } + case Message::LineDelete: + LineDelete(); break; case Message::LineTranspose: LineTranspose(); @@ -4316,20 +4335,29 @@ std::string Editor::RangeText(Sci::Position start, Sci::Position end) const { return std::string(); } +bool Editor::CopyLineRange(SelectionText *ss, bool allowProtected) { + const Sci::Line currentLine = pdoc->SciLineFromPosition(sel.MainCaret()); + const Sci::Position start = pdoc->LineStart(currentLine); + const Sci::Position end = pdoc->LineEnd(currentLine); + + if (allowProtected || !RangeContainsProtected(start, end)) { + std::string text = RangeText(start, end); + if (pdoc->eolMode != EndOfLine::Lf) + text.push_back('\r'); + if (pdoc->eolMode != EndOfLine::Cr) + text.push_back('\n'); + ss->Copy(text, pdoc->dbcsCodePage, + vs.styles[StyleDefault].characterSet, false, true); + return true; + } else { + return false; + } +} + void Editor::CopySelectionRange(SelectionText *ss, bool allowLineCopy) { if (sel.Empty()) { if (allowLineCopy) { - const Sci::Line currentLine = pdoc->SciLineFromPosition(sel.MainCaret()); - const Sci::Position start = pdoc->LineStart(currentLine); - const Sci::Position end = pdoc->LineEnd(currentLine); - - std::string text = RangeText(start, end); - if (pdoc->eolMode != EndOfLine::Lf) - text.push_back('\r'); - if (pdoc->eolMode != EndOfLine::Cr) - text.push_back('\n'); - ss->Copy(text, pdoc->dbcsCodePage, - vs.styles[StyleDefault].characterSet, false, true); + CopyLineRange(ss); } } else { std::string text; @@ -6183,6 +6211,11 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) { CopyAllowLine(); break; + case Message::CutAllowLine: + CutAllowLine(); + SetLastXChosen(); + break; + case Message::VerticalCentreCaret: VerticalCentreCaret(); break; diff --git a/src/Editor.h b/src/Editor.h index dfc25d72d..50aa9a660 100644 --- a/src/Editor.h +++ b/src/Editor.h @@ -436,6 +436,7 @@ protected: // ScintillaBase subclass needs access to much of Editor void PasteRectangular(SelectionPosition pos, const char *ptr, Sci::Position len); virtual void Copy() = 0; void CopyAllowLine(); + void CutAllowLine(); virtual bool CanPaste(); virtual void Paste() = 0; void Clear(); @@ -481,6 +482,7 @@ protected: // ScintillaBase subclass needs access to much of Editor enum class CaseMapping { same, upper, lower }; virtual std::string CaseMapString(const std::string &s, CaseMapping caseMapping); void ChangeCaseOfSelection(CaseMapping caseMapping); + void LineDelete(); void LineTranspose(); void LineReverse(); void Duplicate(bool forLine); @@ -515,6 +517,7 @@ protected: // ScintillaBase subclass needs access to much of Editor virtual void CopyToClipboard(const SelectionText &selectedText) = 0; std::string RangeText(Sci::Position start, Sci::Position end) const; + bool CopyLineRange(SelectionText *ss, bool allowProtected=true); void CopySelectionRange(SelectionText *ss, bool allowLineCopy=false); void CopyRangeToClipboard(Sci::Position start, Sci::Position end); void CopyText(size_t length, const char *text); diff --git a/test/simpleTests.py b/test/simpleTests.py index 900f97faf..afd7de328 100644 --- a/test/simpleTests.py +++ b/test/simpleTests.py @@ -581,6 +581,19 @@ class TestSimple(unittest.TestCase): self.ed.EOLMode = lineEndType self.assertEqual(self.ed.Contents(), b"a1\na1\nb2") + def testCutAllowLine(self): + lineEndType = self.ed.EOLMode + self.ed.EOLMode = self.ed.SC_EOL_LF + self.ed.AddText(5, b"a1\nb2") + self.ed.SetSel(1,1) + self.ed.CutAllowLine() + # Clipboard = "a1\n" + self.assertEqual(self.ed.CanPaste(), 1) + self.ed.SetSel(0, 0) + self.ed.Paste() + self.ed.EOLMode = lineEndType + self.assertEqual(self.ed.Contents(), b"a1\nb2") + def testDuplicate(self): self.ed.AddText(3, b"1b2") self.ed.SetSel(1,2) diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx index decf0e8f6..31d1d826f 100644 --- a/win32/ScintillaWin.cxx +++ b/win32/ScintillaWin.cxx @@ -595,7 +595,7 @@ ScintillaWin::ScintillaWin(HWND hwnd) { cfColumnSelect = RegisterClipboardType(L"MSDEVColumnSelect"); cfBorlandIDEBlockType = RegisterClipboardType(L"Borland IDE Block Type"); - // Likewise for line-copy (copies a full line when no text is selected) + // Likewise for line-copy or line-cut (copies or cuts a full line when no text is selected) cfLineSelect = RegisterClipboardType(L"MSDEVLineSelect"); cfVSLineTag = RegisterClipboardType(L"VisualStudioEditorOperationsLineCutCopyClipboardTag"); hrOle = E_FAIL; -- cgit v1.2.3