- enhancement: prohibit move selection up/down under column mode

- enhancement: prohibit move selection up/down when the last line in selection is a folded code blocks
  - enhancement: check validity of selection in column mode when moving caret by keyboard
  - enhancement: check validity of selection in column mode when moving caret by mouse
  - enhancement: only allow insert linebreak at the end of folded code block
  - enhancement: only allow delete whole folded code block
  - refactor of undo system
This commit is contained in:
Roy Qu 2022-07-02 20:19:37 +08:00
parent 39dd7e3abb
commit 348788bbcd
4 changed files with 123 additions and 56 deletions

10
NEWS.md
View File

@ -1,3 +1,13 @@
Red Panda C++ Version 1.1.4
- enhancement: prohibit move selection up/down under column mode
- enhancement: prohibit move selection up/down when the last line in selection is a folded code blocks
- enhancement: check validity of selection in column mode when moving caret by keyboard
- enhancement: check validity of selection in column mode when moving caret by mouse
- enhancement: only allow insert linebreak at the end of folded code block
- enhancement: only allow delete whole folded code block
- refactor of undo system
Red Panda C++ Version 1.1.3 Red Panda C++ Version 1.1.3
- fix: wrong auto indent calculation for comments - fix: wrong auto indent calculation for comments

View File

@ -653,8 +653,13 @@ QStringList splitStrings(const QString &text)
while(i<text.length()) { while(i<text.length()) {
if (text[i]=='\n' || text[i]=='\r') { if (text[i]=='\n' || text[i]=='\r') {
list.append(text.mid(start,i-start)); list.append(text.mid(start,i-start));
i++; if (text[i]=='\r') {
while (i<text.length() && (text[i]=='\n' || text[i]=='\r')) i++; i++;
if (i<text.length() && text[i]=='\n')
i++;
} else {
i++;
}
start=i; start=i;
} else { } else {
i++; i++;

View File

@ -1960,6 +1960,23 @@ void SynEdit::doMouseScroll(bool isDragging)
} }
BufferCoord vCaret = displayToBufferPos(C); BufferCoord vCaret = displayToBufferPos(C);
if ((caretX() != vCaret.Char) || (caretY() != vCaret.Line)) { if ((caretX() != vCaret.Char) || (caretY() != vCaret.Line)) {
if (mActiveSelectionMode == SynSelectionMode::smColumn) {
int startLine=std::min(mBlockBegin.Line,mBlockEnd.Line);
startLine = std::min(startLine,vCaret.Line);
int endLine=std::max(mBlockBegin.Line,mBlockEnd.Line);
endLine = std::max(endLine,vCaret.Line);
int currentCol=displayXY().Column;
for (int i=startLine;i<=endLine;i++) {
QString s = mDocument->getString(i-1);
int cols = stringColumns(s,0);
if (cols+1<currentCol) {
computeScroll(isDragging);
return;
}
}
}
// changes to line / column in one go // changes to line / column in one go
incPaintLock(); incPaintLock();
auto action = finally([this]{ auto action = finally([this]{
@ -2019,7 +2036,7 @@ void SynEdit::doDeleteLastChar()
QStringList helper; QStringList helper;
if (mCaretX > Len + 1) { if (mCaretX > Len + 1) {
// only move caret one column // only move caret one column
internalSetCaretX(mCaretX - 1); return;
} else if (mCaretX == 1) { } else if (mCaretX == 1) {
// join this line with the last line if possible // join this line with the last line if possible
if (mCaretY > 1) { if (mCaretY > 1) {
@ -2104,7 +2121,9 @@ void SynEdit::doDeleteCurrentChar()
updateLastCaretX(); updateLastCaretX();
QString Temp = lineText(); QString Temp = lineText();
int Len = Temp.length(); int Len = Temp.length();
if (mCaretX <= Len) { if (mCaretX>Len+1) {
return;
} else if (mCaretX <= Len) {
QChar ch = Temp[mCaretX-1]; QChar ch = Temp[mCaretX-1];
if (ch==' ' || ch=='\t') if (ch==' ' || ch=='\t')
shouldAddGroupBreak=true; shouldAddGroupBreak=true;
@ -2143,6 +2162,8 @@ void SynEdit::doDeleteWord()
{ {
if (mReadOnly) if (mReadOnly)
return; return;
if (mCaretX>lineText().length()+1)
return;
BufferCoord start = wordStart(); BufferCoord start = wordStart();
BufferCoord end = wordEnd(); BufferCoord end = wordEnd();
@ -2153,6 +2174,9 @@ void SynEdit::doDeleteToEOL()
{ {
if (mReadOnly) if (mReadOnly)
return; return;
if (mCaretX>lineText().length()+1)
return;
deleteFromTo(caretXY(),BufferCoord{lineText().length()+1,mCaretY}); deleteFromTo(caretXY(),BufferCoord{lineText().length()+1,mCaretY});
} }
@ -2160,6 +2184,9 @@ void SynEdit::doDeleteToWordStart()
{ {
if (mReadOnly) if (mReadOnly)
return; return;
if (mCaretX>lineText().length()+1)
return;
BufferCoord start = wordStart(); BufferCoord start = wordStart();
BufferCoord end = caretXY(); BufferCoord end = caretXY();
if (start==end) { if (start==end) {
@ -2172,6 +2199,9 @@ void SynEdit::doDeleteToWordEnd()
{ {
if (mReadOnly) if (mReadOnly)
return; return;
if (mCaretX>lineText().length()+1)
return;
BufferCoord start = caretXY(); BufferCoord start = caretXY();
BufferCoord end = wordEnd(); BufferCoord end = wordEnd();
if (start == end) { if (start == end) {
@ -2184,12 +2214,18 @@ void SynEdit::doDeleteFromBOL()
{ {
if (mReadOnly) if (mReadOnly)
return; return;
if (mCaretX>lineText().length()+1)
return;
deleteFromTo(BufferCoord{1,mCaretY},caretXY()); deleteFromTo(BufferCoord{1,mCaretY},caretXY());
} }
void SynEdit::doDeleteLine() void SynEdit::doDeleteLine()
{ {
if (!mReadOnly && (mDocument->count() > 0)) { if (!mReadOnly && (mDocument->count() > 0)) {
PSynEditFoldRange foldRange=foldStartAtLine(mCaretY);
if (foldRange && foldRange->collapsed)
return;
doOnPaintTransient(SynTransientType::ttBefore); doOnPaintTransient(SynTransientType::ttBefore);
mUndoList->BeginBlock(); mUndoList->BeginBlock();
mUndoList->AddChange(SynChangeReason::crCaret, mUndoList->AddChange(SynChangeReason::crCaret,
@ -2216,7 +2252,6 @@ void SynEdit::doDeleteLine()
QString s = mDocument->getString(mCaretY-2); QString s = mDocument->getString(mCaretY-2);
mDocument->deleteAt(mCaretY - 1); mDocument->deleteAt(mCaretY - 1);
helper.insert(0,""); helper.insert(0,"");
qDebug()<<helper;
mUndoList->AddChange(SynChangeReason::crDelete, mUndoList->AddChange(SynChangeReason::crDelete,
BufferCoord{s.length()+1, mCaretY-1}, BufferCoord{s.length()+1, mCaretY-1},
BufferCoord{helper.length() + 1, mCaretY}, BufferCoord{helper.length() + 1, mCaretY},
@ -2251,6 +2286,9 @@ void SynEdit::doSelecteLine()
void SynEdit::doDuplicateLine() void SynEdit::doDuplicateLine()
{ {
if (!mReadOnly && (mDocument->count() > 0)) { if (!mReadOnly && (mDocument->count() > 0)) {
PSynEditFoldRange foldRange=foldStartAtLine(mCaretY);
if (foldRange && foldRange->collapsed)
return;
QString s = lineText(); QString s = lineText();
doOnPaintTransient(SynTransientType::ttBefore); doOnPaintTransient(SynTransientType::ttBefore);
mDocument->insert(mCaretY, lineText()); mDocument->insert(mCaretY, lineText());
@ -2272,12 +2310,23 @@ void SynEdit::doDuplicateLine()
void SynEdit::doMoveSelUp() void SynEdit::doMoveSelUp()
{ {
if (mActiveSelectionMode == SynSelectionMode::smColumn)
return;
if (!mReadOnly && (mDocument->count() > 0) && (blockBegin().Line > 1)) { if (!mReadOnly && (mDocument->count() > 0) && (blockBegin().Line > 1)) {
BufferCoord origBlockBegin = blockBegin();
BufferCoord origBlockEnd = blockEnd();
PSynEditFoldRange foldRange=foldStartAtLine(origBlockEnd.Line);
if (foldRange && foldRange->collapsed)
return;
// for (int line=origBlockBegin.Line;line<=origBlockEnd.Line;line++) {
// PSynEditFoldRange foldRange=foldStartAtLine(line);
// if (foldRange && foldRange->collapsed)
// return;
// }
doOnPaintTransient(SynTransientType::ttBefore); doOnPaintTransient(SynTransientType::ttBefore);
// Backup caret and selection // Backup caret and selection
BufferCoord origBlockBegin = blockBegin();
BufferCoord origBlockEnd = blockEnd();
if (!mUndoing) { if (!mUndoing) {
mUndoList->BeginBlock(); mUndoList->BeginBlock();
@ -2314,11 +2363,21 @@ void SynEdit::doMoveSelUp()
void SynEdit::doMoveSelDown() void SynEdit::doMoveSelDown()
{ {
if (mActiveSelectionMode == SynSelectionMode::smColumn)
return;
if (!mReadOnly && (mDocument->count() > 0) && (blockEnd().Line < mDocument->count())) { if (!mReadOnly && (mDocument->count() > 0) && (blockEnd().Line < mDocument->count())) {
doOnPaintTransient(SynTransientType::ttBefore);
// Backup caret and selection
BufferCoord origBlockBegin = blockBegin(); BufferCoord origBlockBegin = blockBegin();
BufferCoord origBlockEnd = blockEnd(); BufferCoord origBlockEnd = blockEnd();
PSynEditFoldRange foldRange=foldStartAtLine(origBlockEnd.Line);
if (foldRange && foldRange->collapsed)
return;
// for (int line=origBlockBegin.Line;line<=origBlockEnd.Line;line++) {
// PSynEditFoldRange foldRange=foldStartAtLine(line.Line);
// if (foldRange && foldRange->collapsed)
// return;
// }
doOnPaintTransient(SynTransientType::ttBefore);
// Backup caret and selection
if (!mUndoing) { if (!mUndoing) {
mUndoList->BeginBlock(); mUndoList->BeginBlock();
mUndoList->AddChange(SynChangeReason::crCaret, // backup original caret mUndoList->AddChange(SynChangeReason::crCaret, // backup original caret
@ -2369,9 +2428,11 @@ void SynEdit::insertLine(bool moveCaret)
if (mReadOnly) if (mReadOnly)
return; return;
int nLinesInserted=0; int nLinesInserted=0;
mUndoList->BeginBlock(); if (!mUndoing)
mUndoList->BeginBlock();
auto action = finally([this] { auto action = finally([this] {
mUndoList->EndBlock(); if (!mUndoing)
mUndoList->EndBlock();
}); });
QString helper; QString helper;
if (selAvail()) { if (selAvail()) {
@ -2380,11 +2441,16 @@ void SynEdit::insertLine(bool moveCaret)
} }
QString Temp = lineText(); QString Temp = lineText();
if (mCaretX>lineText().length()+1) { if (mCaretX>lineText().length()+1) {
PSynEditFoldRange foldRange = foldStartAtLine(mCaretY); PSynEditFoldRange foldRange = foldStartAtLine(mCaretY);
if ((foldRange) && foldRange->collapsed) { if ((foldRange) && foldRange->collapsed) {
QString s = Temp+highlighter()->foldString(); QString s = Temp+highlighter()->foldString();
if (mCaretX > s.length()) { if (mCaretX > s.length()) {
if (!mUndoing) {
addCaretToUndo();
addSelectionToUndo();
}
mCaretY=foldRange->toLine; mCaretY=foldRange->toLine;
if (mCaretY>mDocument->count()) { if (mCaretY>mDocument->count()) {
mCaretY=mDocument->count(); mCaretY=mDocument->count();
@ -2394,6 +2460,7 @@ void SynEdit::insertLine(bool moveCaret)
} }
} }
} }
QString Temp2 = Temp; QString Temp2 = Temp;
QString Temp3; QString Temp3;
PSynHighlighterAttribute Attr; PSynHighlighterAttribute Attr;
@ -2430,7 +2497,8 @@ void SynEdit::insertLine(bool moveCaret)
QString indentSpacesForRightLineText = GetLeftSpacing(indentSpaces,true); QString indentSpacesForRightLineText = GetLeftSpacing(indentSpaces,true);
mDocument->insert(mCaretY, indentSpacesForRightLineText+rightLineText); mDocument->insert(mCaretY, indentSpacesForRightLineText+rightLineText);
nLinesInserted++; nLinesInserted++;
mUndoList->AddChange(SynChangeReason::crLineBreak, caretXY(), caretXY(), QStringList(rightLineText), if (!mUndoing)
mUndoList->AddChange(SynChangeReason::crLineBreak, caretXY(), caretXY(), QStringList(rightLineText),
SynSelectionMode::smNormal); SynSelectionMode::smNormal);
if (!mUndoing) { if (!mUndoing) {
@ -4885,7 +4953,7 @@ void SynEdit::moveCaretHorz(int DX, bool isSelection)
int row = lineToRow(ptDst.Line); int row = lineToRow(ptDst.Line);
row++; row++;
int line = rowToLine(row); int line = rowToLine(row);
qDebug()<<line<<ptDst.Line; // qDebug()<<line<<ptDst.Line;
if (line!=ptDst.Line && line<=mDocument->count()) { if (line!=ptDst.Line && line<=mDocument->count()) {
ptDst.Line = line; ptDst.Line = line;
ptDst.Char = 1; ptDst.Char = 1;
@ -5038,43 +5106,6 @@ void SynEdit::setSelTextPrimitiveEx(SynSelectionMode mode, const QStringList &te
bool groupUndo=false; bool groupUndo=false;
BufferCoord startPos = blockBegin(); BufferCoord startPos = blockBegin();
BufferCoord endPos = blockEnd(); BufferCoord endPos = blockEnd();
if (mode==SynSelectionMode::smNormal) {
PSynEditFoldRange foldRange = foldStartAtLine(endPos.Line);
QString s = mDocument->getString(endPos.Line-1);
if ((foldRange) && foldRange->collapsed && endPos.Char>s.length()) {
QString newS=s+highlighter()->foldString();
if (selAvail()) {
if ((startPos.Char<=s.length() || startPos.Line<endPos.Line)
&& endPos.Char>newS.length() ) {
//selection has whole block
endPos.Line = foldRange->toLine;
endPos.Char = mDocument->getString(endPos.Line-1).length()+1;
} else {
uncollapse(foldRange);
endPos.Char = s.length()+1;
if (startPos.Char>s.length())
startPos.Char=s.length()+1;
}
} else {
if (endPos.Char>newS.length()) {
//caret at the end of the block
uncollapse(foldRange);
endPos.Line = foldRange->toLine;
endPos.Char = mDocument->getString(endPos.Line-1).length()+1;
startPos=endPos;
} else {
//caret in the block { }
uncollapse(foldRange);
endPos.Char = mDocument->getString(endPos.Line-1).length()+1;
startPos=endPos;
}
}
mBlockBegin=startPos;
mBlockEnd=endPos;
mCaretX=endPos.Char;
mCaretY=endPos.Line;
}
}
if (selAvail()) { if (selAvail()) {
if (!mUndoing && !text.isEmpty()) { if (!mUndoing && !text.isEmpty()) {
mUndoList->BeginBlock(); mUndoList->BeginBlock();
@ -5351,12 +5382,26 @@ void SynEdit::properSetLine(int ALine, const QString &ALineText, bool notify)
} }
} }
void SynEdit::doDeleteText(const BufferCoord &startPos, const BufferCoord &endPos, SynSelectionMode mode) void SynEdit::doDeleteText(BufferCoord startPos, BufferCoord endPos, SynSelectionMode mode)
{ {
bool UpdateMarks = false; bool UpdateMarks = false;
int MarkOffset = 0; int MarkOffset = 0;
if (mode == SynSelectionMode::smNormal) {
PSynEditFoldRange foldRange = foldStartAtLine(endPos.Line);
QString s = mDocument->getString(endPos.Line-1);
if ((foldRange) && foldRange->collapsed && endPos.Char>s.length()) {
QString newS=s+highlighter()->foldString();
if ((startPos.Char<=s.length() || startPos.Line<endPos.Line)
&& endPos.Char>newS.length() ) {
//selection has whole block
endPos.Line = foldRange->toLine;
endPos.Char = mDocument->getString(endPos.Line-1).length()+1;
} else {
return;
}
}
}
QStringList deleted=getContent(startPos,endPos,mode); QStringList deleted=getContent(startPos,endPos,mode);
switch(mode) { switch(mode) {
case SynSelectionMode::smNormal: case SynSelectionMode::smNormal:
if (mDocument->count() > 0) { if (mDocument->count() > 0) {
@ -5428,12 +5473,20 @@ void SynEdit::doDeleteText(const BufferCoord &startPos, const BufferCoord &endPo
} }
} }
void SynEdit::doInsertText(const BufferCoord& pos, const QStringList& text, SynSelectionMode mode, int startLine, int endLine) { void SynEdit::doInsertText(const BufferCoord& pos,
const QStringList& text,
SynSelectionMode mode, int startLine, int endLine) {
if (text.isEmpty()) if (text.isEmpty())
return; return;
if (startLine>endLine) if (startLine>endLine)
std::swap(startLine,endLine); std::swap(startLine,endLine);
if (mode == SynSelectionMode::smNormal) {
PSynEditFoldRange foldRange = foldStartAtLine(pos.Line);
QString s = mDocument->getString(pos.Line-1);
if ((foldRange) && foldRange->collapsed && pos.Char>s.length()+1)
return;
}
int insertedLines = 0; int insertedLines = 0;
BufferCoord newPos; BufferCoord newPos;
switch(mode){ switch(mode){
@ -5456,7 +5509,6 @@ void SynEdit::doInsertText(const BufferCoord& pos, const QStringList& text, SynS
int SynEdit::doInsertTextByNormalMode(const BufferCoord& pos, const QStringList& text, BufferCoord &newPos) int SynEdit::doInsertTextByNormalMode(const BufferCoord& pos, const QStringList& text, BufferCoord &newPos)
{ {
QString sLeftSide; QString sLeftSide;
QString sRightSide; QString sRightSide;
QString str; QString str;
@ -6225,7 +6277,7 @@ void SynEdit::mousePressEvent(QMouseEvent *event)
}else { }else {
return; return;
} }
} else if (button == Qt::LeftButton && mActiveSelectionMode == SynSelectionMode::smNormal) { } else if (button == Qt::LeftButton) {
if (selAvail()) { if (selAvail()) {
//remember selection state, as it will be cleared later //remember selection state, as it will be cleared later
bWasSel = true; bWasSel = true;

View File

@ -559,7 +559,7 @@ private:
void properSetLine(int ALine, const QString& ALineText, bool notify = true); void properSetLine(int ALine, const QString& ALineText, bool notify = true);
//primitive edit operations //primitive edit operations
void doDeleteText(const BufferCoord& startPos, const BufferCoord& endPos, SynSelectionMode mode); void doDeleteText(BufferCoord startPos, BufferCoord endPos, SynSelectionMode mode);
void doInsertText(const BufferCoord& pos, const QStringList& text, SynSelectionMode mode, int startLine, int endLine); void doInsertText(const BufferCoord& pos, const QStringList& text, SynSelectionMode mode, int startLine, int endLine);
int doInsertTextByNormalMode(const BufferCoord& pos, const QStringList& text, BufferCoord &newPos); int doInsertTextByNormalMode(const BufferCoord& pos, const QStringList& text, BufferCoord &newPos);
int doInsertTextByColumnMode(const BufferCoord& pos, const QStringList& text, BufferCoord &newPos, int startLine, int endLine); int doInsertTextByColumnMode(const BufferCoord& pos, const QStringList& text, BufferCoord &newPos, int startLine, int endLine);