aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/Document.cxx10
-rw-r--r--src/Document.h1
-rw-r--r--src/Editor.cxx58
-rw-r--r--src/Editor.h2
-rw-r--r--test/simpleTests.py75
5 files changed, 105 insertions, 41 deletions
diff --git a/src/Document.cxx b/src/Document.cxx
index 4f086af4b..9d25f0b08 100644
--- a/src/Document.cxx
+++ b/src/Document.cxx
@@ -1747,6 +1747,16 @@ void Document::ConvertLineEnds(EndOfLine eolModeSet) {
}
+std::string_view Document::EOLString() const noexcept {
+ if (eolMode == EndOfLine::CrLf) {
+ return "\r\n";
+ } else if (eolMode == EndOfLine::Cr) {
+ return "\r";
+ } else {
+ return "\n";
+ }
+}
+
DocumentOption Document::Options() const noexcept {
return (IsLarge() ? DocumentOption::TextLarge : DocumentOption::Default) |
(cb.HasStyles() ? DocumentOption::Default : DocumentOption::StylesNone);
diff --git a/src/Document.h b/src/Document.h
index 8d5643e90..9f4811073 100644
--- a/src/Document.h
+++ b/src/Document.h
@@ -420,6 +420,7 @@ public:
void Indent(bool forwards, Sci::Line lineBottom, Sci::Line lineTop);
static std::string TransformLineEnds(const char *s, size_t len, Scintilla::EndOfLine eolModeWanted);
void ConvertLineEnds(Scintilla::EndOfLine eolModeSet);
+ std::string_view EOLString() const noexcept;
void SetReadOnly(bool set) { cb.SetReadOnly(set); }
bool IsReadOnly() const noexcept { return cb.IsReadOnly(); }
bool IsLarge() const noexcept { return cb.IsLarge(); }
diff --git a/src/Editor.cxx b/src/Editor.cxx
index ed97eed2b..8aab313f3 100644
--- a/src/Editor.cxx
+++ b/src/Editor.cxx
@@ -1067,14 +1067,14 @@ void Editor::MoveSelectedLines(int lineDelta) {
SetSelection(pdoc->MovePositionOutsideChar(selectionStart - 1, -1), selectionEnd);
ClearSelection();
- const char *eol = StringFromEOLMode(pdoc->eolMode);
+ const std::string_view eol = pdoc->EOLString();
if (currentLine + lineDelta >= pdoc->LinesTotal())
- pdoc->InsertString(pdoc->Length(), eol, strlen(eol));
+ pdoc->InsertString(pdoc->Length(), eol);
GoToLine(currentLine + lineDelta);
Sci::Position selectionLength = pdoc->InsertString(CurrentPosition(), selectedText);
if (appendEol) {
- const Sci::Position lengthInserted = pdoc->InsertString(CurrentPosition() + selectionLength, eol, strlen(eol));
+ const Sci::Position lengthInserted = pdoc->InsertString(CurrentPosition() + selectionLength, eol);
selectionLength += lengthInserted;
}
SetSelection(CurrentPosition(), CurrentPosition() + selectionLength);
@@ -1638,16 +1638,6 @@ void Editor::LinesJoin() {
}
}
-const char *Editor::StringFromEOLMode(EndOfLine eolMode) noexcept {
- if (eolMode == EndOfLine::CrLf) {
- return "\r\n";
- } else if (eolMode == EndOfLine::Cr) {
- return "\r";
- } else {
- return "\n";
- }
-}
-
void Editor::LinesSplit(int pixelWidth) {
if (!RangeContainsProtected(targetRange.start.Position(), targetRange.end.Position())) {
if (pixelWidth == 0) {
@@ -1656,7 +1646,7 @@ void Editor::LinesSplit(int pixelWidth) {
}
const Sci::Line lineStart = pdoc->SciLineFromPosition(targetRange.start.Position());
Sci::Line lineEnd = pdoc->SciLineFromPosition(targetRange.end.Position());
- const char *eol = StringFromEOLMode(pdoc->eolMode);
+ const std::string_view eol = pdoc->EOLString();
UndoGroup ug(pdoc);
for (Sci::Line line = lineStart; line <= lineEnd; line++) {
AutoSurface surface(this);
@@ -1667,8 +1657,7 @@ void Editor::LinesSplit(int pixelWidth) {
Sci::Position lengthInsertedTotal = 0;
for (int subLine = 1; subLine < ll->lines; subLine++) {
const Sci::Position lengthInserted = pdoc->InsertString(
- posLineStart + lengthInsertedTotal + ll->LineStart(subLine),
- eol, strlen(eol));
+ posLineStart + lengthInsertedTotal + ll->LineStart(subLine), eol);
targetRange.end.Add(lengthInserted);
lengthInsertedTotal += lengthInserted;
}
@@ -2126,9 +2115,8 @@ void Editor::InsertPasteShape(const char *text, Sci::Position len, PasteShape sh
Sci::Position lengthInserted = pdoc->InsertString(insertPos, text, len);
// add the newline if necessary
if ((len > 0) && (text[len - 1] != '\n' && text[len - 1] != '\r')) {
- const char *endline = StringFromEOLMode(pdoc->eolMode);
- const Sci::Position length = strlen(endline);
- lengthInserted += pdoc->InsertString(insertPos + lengthInserted, endline, length);
+ const std::string_view endline = pdoc->EOLString();
+ lengthInserted += pdoc->InsertString(insertPos + lengthInserted, endline);
}
if (sel.MainCaret() == insertPos) {
SetEmptySelection(sel.MainCaret() + lengthInserted);
@@ -2222,10 +2210,8 @@ void Editor::PasteRectangular(SelectionPosition pos, const char *ptr, Sci::Posit
if ((ptr[i] == '\r') || (!prevCr))
line++;
if (line >= pdoc->LinesTotal()) {
- if (pdoc->eolMode != EndOfLine::Lf)
- pdoc->InsertString(pdoc->Length(), "\r", 1);
- if (pdoc->eolMode != EndOfLine::Cr)
- pdoc->InsertString(pdoc->Length(), "\n", 1);
+ const std::string_view eol = pdoc->EOLString();
+ pdoc->InsertString(pdoc->LengthNoExcept(), eol);
}
// Pad the end of lines with spaces if required
sel.RangeMain().caret.SetPosition(PositionFromLineX(line, xInsert));
@@ -3070,11 +3056,9 @@ void Editor::Duplicate(bool forLine) {
forLine = true;
}
UndoGroup ug(pdoc);
- const char *eol = "";
- Sci::Position eolLen = 0;
+ std::string_view eol;
if (forLine) {
- eol = StringFromEOLMode(pdoc->eolMode);
- eolLen = strlen(eol);
+ eol = pdoc->EOLString();
}
for (size_t r=0; r<sel.Count(); r++) {
SelectionPosition start = sel.Range(r).Start();
@@ -3085,10 +3069,10 @@ void Editor::Duplicate(bool forLine) {
end = SelectionPosition(pdoc->LineEnd(line));
}
std::string text = RangeText(start.Position(), end.Position());
- Sci::Position lengthInserted = eolLen;
+ Sci::Position lengthInserted = 0;
if (forLine)
- lengthInserted = pdoc->InsertString(end.Position(), eol, eolLen);
- pdoc->InsertString(end.Position() + lengthInserted, text.c_str(), text.length());
+ lengthInserted = pdoc->InsertString(end.Position(), eol);
+ pdoc->InsertString(end.Position() + lengthInserted, text);
}
if (sel.Count() && sel.IsRectangular()) {
SelectionPosition last = sel.Last();
@@ -3125,11 +3109,11 @@ void Editor::NewLine() {
// Insert each line end
size_t countInsertions = 0;
+ const std::string_view eol = pdoc->EOLString();
for (size_t r = 0; r < sel.Count(); r++) {
sel.Range(r).ClearVirtualSpace();
- const char *eol = StringFromEOLMode(pdoc->eolMode);
const Sci::Position positionInsert = sel.Range(r).caret.Position();
- const Sci::Position insertLength = pdoc->InsertString(positionInsert, eol, strlen(eol));
+ const Sci::Position insertLength = pdoc->InsertString(positionInsert, eol);
if (insertLength > 0) {
sel.Range(r) = SelectionRange(positionInsert + insertLength);
countInsertions++;
@@ -3139,16 +3123,12 @@ void Editor::NewLine() {
// Perform notifications after all the changes as the application may change the
// selections in response to the characters.
for (size_t i = 0; i < countInsertions; i++) {
- const char *eol = StringFromEOLMode(pdoc->eolMode);
- while (*eol) {
- NotifyChar(*eol, CharacterSource::DirectInput);
+ for (const char ch : eol) {
+ NotifyChar(ch, CharacterSource::DirectInput);
if (recordingMacro) {
- char txt[2];
- txt[0] = *eol;
- txt[1] = '\0';
+ const char txt[2] = { ch, '\0' };
NotifyMacroRecord(Message::ReplaceSel, 0, reinterpret_cast<sptr_t>(txt));
}
- eol++;
}
}
diff --git a/src/Editor.h b/src/Editor.h
index 85d95e21d..d757dd4c4 100644
--- a/src/Editor.h
+++ b/src/Editor.h
@@ -608,8 +608,6 @@ protected: // ScintillaBase subclass needs access to much of Editor
Scintilla::sptr_t StyleGetMessage(Scintilla::Message iMessage, Scintilla::uptr_t wParam, Scintilla::sptr_t lParam);
void SetSelectionNMessage(Scintilla::Message iMessage, Scintilla::uptr_t wParam, Scintilla::sptr_t lParam);
- static const char *StringFromEOLMode(Scintilla::EndOfLine eolMode) noexcept;
-
// Coercion functions for transforming WndProc parameters into pointers
static void *PtrFromSPtr(Scintilla::sptr_t lParam) noexcept {
return reinterpret_cast<void *>(lParam);
diff --git a/test/simpleTests.py b/test/simpleTests.py
index 5383911ee..289359475 100644
--- a/test/simpleTests.py
+++ b/test/simpleTests.py
@@ -191,6 +191,12 @@ class TestSimple(unittest.TestCase):
self.assertEquals(self.ed.Length, 1)
self.assertEquals(data, self.ed.ByteRange(0,1))
+ def testNewLine(self):
+ self.ed.SetContents(b"12")
+ self.ed.SetSel(1, 1)
+ self.ed.NewLine()
+ self.assertEquals(self.ed.Contents(), b"1\r\n2")
+
def testUndoRedo(self):
data = b"xy"
self.assertEquals(self.ed.Modify, 0)
@@ -580,12 +586,81 @@ class TestSimple(unittest.TestCase):
self.ed.SelectionDuplicate()
self.assertEquals(self.ed.Contents(), b"1bb2")
+ def testLineDuplicate(self):
+ self.ed.SetContents(b"1\r\nb\r\n2")
+ self.ed.SetSel(3, 3)
+ # Duplicates the second line containing 'b'
+ self.ed.LineDuplicate()
+ self.assertEquals(self.ed.Contents(), b"1\r\nb\r\nb\r\n2")
+
+ def testLineDuplicateDifferentLineEnd(self):
+ self.ed.SetContents(b"1\nb\n2")
+ self.ed.SetSel(3, 3)
+ # Duplicates the second line containing 'b'
+ self.ed.LineDuplicate()
+ # Same as above but end of duplicated line is \r\n
+ self.assertEquals(self.ed.Contents(), b"1\nb\r\nb\n2")
+
def testTransposeLines(self):
self.ed.AddText(8, b"a1\nb2\nc3")
self.ed.SetSel(3,3)
self.ed.LineTranspose()
self.assertEquals(self.ed.Contents(), b"b2\na1\nc3")
+ def testMoveSelectedLines(self):
+ lineEndType = self.ed.EOLMode
+ self.ed.EOLMode = self.ed.SC_EOL_LF
+
+ self.ed.SetContents(b"a1\nb2\nc3")
+ self.ed.SetSel(3, 6)
+ self.ed.MoveSelectedLinesDown()
+ self.assertEquals(self.ed.Contents(), b"a1\nc3\nb2")
+
+ self.ed.SetContents(b"a1\nb2\nc3")
+ self.ed.SetSel(3, 6)
+ self.ed.MoveSelectedLinesUp()
+ self.assertEquals(self.ed.Contents(), b"b2\na1\nc3")
+
+ # Exercise the 'appendEol' case as the last line has no EOL characters to copy
+ self.ed.SetContents(b"a1\nb2\nc3")
+ self.ed.SetSel(4, 7)
+ self.ed.MoveSelectedLinesUp()
+ self.assertEquals(self.ed.Contents(), b"b2\nc3\na1")
+
+ # Testing extreme lines
+ self.ed.SetContents(b"a1\nb2\nc3")
+ self.ed.SetSel(6, 7)
+ self.ed.MoveSelectedLinesDown()
+ # No change as moving last line down
+ self.assertEquals(self.ed.Contents(), b"a1\nb2\nc3")
+
+ self.ed.SetContents(b"a1\nb2\nc3")
+ self.ed.SetSel(1, 2)
+ self.ed.MoveSelectedLinesUp()
+ # No change as moving first line up
+ self.assertEquals(self.ed.Contents(), b"a1\nb2\nc3")
+
+ # Moving line to end with different line end uses that line end
+ self.ed.EOLMode = self.ed.SC_EOL_CRLF
+ self.ed.SetContents(b"a1\nb2\nc3")
+ self.ed.SetSel(3, 6)
+ self.ed.MoveSelectedLinesDown()
+ self.assertEquals(self.ed.Contents(), b"a1\nc3\r\nb2")
+
+ # Exercise 'appendEol'
+ self.ed.SetContents(b"a1\nb2\nc3")
+ self.ed.SetSel(4, 7)
+ self.ed.MoveSelectedLinesUp()
+ self.assertEquals(self.ed.Contents(), b"b2\nc3\r\na1")
+
+ self.ed.SetContents(b"a1\nb2\nc3")
+ self.ed.SetSel(1, 2)
+ self.ed.MoveSelectedLinesDown()
+ self.assertEquals(self.ed.Contents(), b"b2\na1\nc3")
+
+ # Restore line end
+ self.ed.EOLMode = lineEndType
+
def testGetSet(self):
self.ed.SetContents(b"abc")
self.assertEquals(self.ed.TextLength, 3)