diff --git a/RedPandaIDE/mainwindow.cpp b/RedPandaIDE/mainwindow.cpp index d1a984a8..998f5f5b 100644 --- a/RedPandaIDE/mainwindow.cpp +++ b/RedPandaIDE/mainwindow.cpp @@ -463,7 +463,7 @@ void MainWindow::updateEditorActions() ui->actionConvert_to_UTF_8_BOM->setEnabled(e->encodingOption()!=ENCODING_UTF8_BOM && e->fileEncoding()!=ENCODING_UTF8_BOM); ui->actionCopy->setEnabled(e->selAvail()); - ui->actionCut->setEnabled(e->selAvail()); + ui->actionCut->setEnabled(true); ui->actionFoldAll->setEnabled(e->document()->count()>0); ui->actionIndent->setEnabled(!e->readOnly()); diff --git a/RedPandaIDE/qsynedit/MiscProcs.cpp b/RedPandaIDE/qsynedit/MiscProcs.cpp index 1431d972..9c0aaf59 100644 --- a/RedPandaIDE/qsynedit/MiscProcs.cpp +++ b/RedPandaIDE/qsynedit/MiscProcs.cpp @@ -664,3 +664,8 @@ QStringList splitStrings(const QString &text) list.append(text.mid(start,i)); return list; } + +int calSpanLines(const BufferCoord &startPos, const BufferCoord &endPos) +{ + return std::abs(endPos.Line - startPos.Line+1); +} diff --git a/RedPandaIDE/qsynedit/MiscProcs.h b/RedPandaIDE/qsynedit/MiscProcs.h index cccea624..cbb6a810 100644 --- a/RedPandaIDE/qsynedit/MiscProcs.h +++ b/RedPandaIDE/qsynedit/MiscProcs.h @@ -83,6 +83,8 @@ int CountLines(const QString& Line, int start); QStringList splitStrings(const QString& text); +int calSpanLines(const BufferCoord& startPos, const BufferCoord& endPos); + // Remove all '/' characters from string by changing them into '\.'. // Change all '\' characters into '\\' to allow for unique decoding. QString EncodeString(const QString & s); diff --git a/RedPandaIDE/qsynedit/SynEdit.cpp b/RedPandaIDE/qsynedit/SynEdit.cpp index 91cb686b..9ec30d25 100644 --- a/RedPandaIDE/qsynedit/SynEdit.cpp +++ b/RedPandaIDE/qsynedit/SynEdit.cpp @@ -2012,6 +2012,7 @@ void SynEdit::doDeleteLastChar() setSelectedTextEmpty(); return; } + bool shouldAddGroupBreak=false; QString Temp = lineText(); int Len = Temp.length(); BufferCoord Caret = caretXY(); @@ -2031,6 +2032,7 @@ void SynEdit::doDeleteLastChar() setLineText(lineText() + Temp); helper.append(""); helper.append(""); + shouldAddGroupBreak=true; } } else { // delete text before the caret @@ -2053,14 +2055,19 @@ void SynEdit::doDeleteLastChar() } else { // delete char internalSetCaretX(mCaretX - 1); - helper.append(QString(Temp[mCaretX-1])); + QChar ch=Temp[mCaretX-1]; + if (ch==' ' || ch=='\t') + shouldAddGroupBreak=true; + helper.append(QString(ch)); Temp.remove(mCaretX-1,1); properSetLine(mCaretY - 1, Temp); } } if ((Caret.Char != mCaretX) || (Caret.Line != mCaretY)) { mUndoList->AddChange(SynChangeReason::crDelete, caretXY(), Caret, helper, - SynSelectionMode::smNormal); + mActiveSelectionMode); + if (shouldAddGroupBreak) + mUndoList->AddGroupBreak(); } } @@ -2068,56 +2075,67 @@ void SynEdit::doDeleteCurrentChar() { QStringList helper; BufferCoord Caret; - if (!mReadOnly) { - doOnPaintTransient(SynTransientType::ttBefore); + if (mReadOnly) { + return; + } + doOnPaintTransient(SynTransientType::ttBefore); + auto action = finally([this]{ + ensureCursorPosVisible(); + doOnPaintTransient(SynTransientType::ttAfter); + }); - if (mActiveSelectionMode==SynSelectionMode::smColumn) { - BufferCoord start=blockBegin(); - BufferCoord end=blockEnd(); - if (!selAvail()) { - end.Char++; - setBlockBegin(start); - setBlockEnd(end); - } - setSelectedTextEmpty(); + if (mActiveSelectionMode==SynSelectionMode::smColumn) { + BufferCoord start=blockBegin(); + BufferCoord end=blockEnd(); + if (!selAvail()) { + end.Char++; + setBlockBegin(start); + setBlockEnd(end); + } + setSelectedTextEmpty(); + return; + } + if (selAvail()) + setSelectedTextEmpty(); + else { + bool shouldAddGroupBreak=false; + // Call UpdateLastCaretX. Even though the caret doesn't move, the + // current caret position should "stick" whenever text is modified. + updateLastCaretX(); + QString Temp = lineText(); + int Len = Temp.length(); + if (mCaretX <= Len) { + QChar ch = Temp[mCaretX-1]; + if (ch==' ' || ch=='\t') + shouldAddGroupBreak=true; + // delete char + helper.append(QString(ch)); + Caret.Char = mCaretX + 1; + Caret.Line = mCaretY; + Temp.remove(mCaretX-1, 1); + properSetLine(mCaretY - 1, Temp); } else { - if (selAvail()) - setSelectedTextEmpty(); - else { - // Call UpdateLastCaretX. Even though the caret doesn't move, the - // current caret position should "stick" whenever text is modified. - updateLastCaretX(); - QString Temp = lineText(); - int Len = Temp.length(); - if (mCaretX <= Len) { - // delete char - helper.append(Temp.mid(mCaretX-1, 1)); - Caret.Char = mCaretX + 1; - Caret.Line = mCaretY; - Temp.remove(mCaretX-1, 1); - properSetLine(mCaretY - 1, Temp); - } else { - // join line with the line after - if (mCaretY < mDocument->count()) { - properSetLine(mCaretY - 1, Temp + mDocument->getString(mCaretY)); - Caret.Char = 1; - Caret.Line = mCaretY + 1; - helper.append(""); - helper.append(""); - mDocument->deleteAt(mCaretY); - if (mCaretX==1) - doLinesDeleted(mCaretY, 1); - else - doLinesDeleted(mCaretY + 1, 1); - } - } - if ((Caret.Char != mCaretX) || (Caret.Line != mCaretY)) { - mUndoList->AddChange(SynChangeReason::crDelete, caretXY(), Caret, - helper, SynSelectionMode::smNormal); - } + // join line with the line after + if (mCaretY < mDocument->count()) { + shouldAddGroupBreak=true; + properSetLine(mCaretY - 1, Temp + mDocument->getString(mCaretY)); + Caret.Char = 1; + Caret.Line = mCaretY + 1; + helper.append(""); + helper.append(""); + mDocument->deleteAt(mCaretY); + if (mCaretX==1) + doLinesDeleted(mCaretY, 1); + else + doLinesDeleted(mCaretY + 1, 1); } } - doOnPaintTransient(SynTransientType::ttAfter); + if ((Caret.Char != mCaretX) || (Caret.Line != mCaretY)) { + mUndoList->AddChange(SynChangeReason::crDelete, caretXY(), Caret, + helper, mActiveSelectionMode); + if (shouldAddGroupBreak) + mUndoList->AddGroupBreak(); + } } } @@ -4234,7 +4252,7 @@ void SynEdit::doUndo() return; //Remove Group Break; - if (mUndoList->LastChangeReason() == SynChangeReason::crNothing) { + if (mUndoList->LastChangeReason() == SynChangeReason::crGroupBreak) { int OldBlockNumber = mRedoList->blockChangeNumber(); auto action = finally([&,this]{ mRedoList->setBlockChangeNumber(OldBlockNumber); @@ -4254,8 +4272,8 @@ void SynEdit::doUndo() mRedoList->setBlockChangeNumber(SaveChangeNumber); }); //skip group chain breakers - if (mUndoList->LastChangeReason()==SynChangeReason::crNothing) { - while (!mUndoList->isEmpty() && mUndoList->LastChangeReason()==SynChangeReason::crNothing) { + if (mUndoList->LastChangeReason()==SynChangeReason::crGroupBreak) { + while (!mUndoList->isEmpty() && mUndoList->LastChangeReason()==SynChangeReason::crGroupBreak) { doUndoItem(); } } @@ -4363,10 +4381,12 @@ void SynEdit::doUndoItem() case SynChangeReason::crDelete: { // If there's no selection, we have to set // the Caret's position manualy. - qDebug()<<"undo delete"; - qDebug()<changeText(); - qDebug()<changeStartPos().Line<changeStartPos().Char; - doInsertText(Item->changeStartPos(),Item->changeText(),Item->changeSelMode()); +// qDebug()<<"undo delete"; +// qDebug()<changeText(); +// qDebug()<changeStartPos().Line<changeStartPos().Char; + doInsertText(Item->changeStartPos(),Item->changeText(),Item->changeSelMode(), + Item->changeStartPos().Line, + Item->changeEndPos().Line); internalSetCaretXY(Item->changeEndPos()); mRedoList->AddChange( Item->changeReason(), @@ -4374,50 +4394,6 @@ void SynEdit::doUndoItem() Item->changeEndPos(), Item->changeText(), Item->changeSelMode()); -// BufferCoord TmpPos; -// if (Item->changeSelMode() == SynSelectionMode::smColumn) { -// BufferCoord BB = Item->changeStartPos(); -// BufferCoord BE = Item->changeEndPos(); -// int First = std::min(BB.Line,BE.Line); -// int ColFrom = charToColumn(BB.Line, BB.Char); -// int ColTo = charToColumn(BE.Line, BE.Char); -// if (ColFrom > ColTo) -// ColFrom = ColTo; -// TmpPos.Line = First; -// TmpPos.Char = columnToChar(First,ColFrom); -// } else { -// TmpPos = BufferCoord{ -// minBufferCoord( -// Item->changeStartPos(), -// Item->changeEndPos())}; -// } -// if ( (Item->changeReason() == SynChangeReason::crDeleteAfterCursor -// || Item->changeReason() == SynChangeReason::crSilentDeleteAfterCursor) -// && (TmpPos.Line > mDocument->count())) { -// internalSetCaretXY(BufferCoord{1, mDocument->count()}); -// mDocument->add(""); -// } -// setCaretXY(TmpPos); -// setSelTextPrimitiveEx( -// Item->changeSelMode(), -// Item->changeStr(), -// false); -// if ( (Item->changeReason() == SynChangeReason::crDeleteAfterCursor -// || Item->changeReason() == SynChangeReason::crSilentDeleteAfterCursor)) { -// TmpPos = Item->changeStartPos(); -// internalSetCaretXY(TmpPos); -// } else { -// TmpPos = Item->changeEndPos(); -// setCaretAndSelection(TmpPos, -// Item->changeStartPos(), -// Item->changeEndPos()); -// } - mRedoList->AddChange( - Item->changeReason(), - Item->changeStartPos(), - Item->changeEndPos(), - QStringList(), - Item->changeSelMode()); ensureCursorPosVisible(); break; } @@ -4467,8 +4443,8 @@ void SynEdit::doRedo() mUndoList->setBlockChangeNumber(SaveChangeNumber); }); //skip group chain breakers - if (mRedoList->LastChangeReason()==SynChangeReason::crNothing) { - while (!mRedoList->isEmpty() && mRedoList->LastChangeReason()==SynChangeReason::crNothing) { + if (mRedoList->LastChangeReason()==SynChangeReason::crGroupBreak) { + while (!mRedoList->isEmpty() && mRedoList->LastChangeReason()==SynChangeReason::crGroupBreak) { doRedoItem(); } } @@ -4492,7 +4468,7 @@ void SynEdit::doRedo() } //Remove Group Break - if (mRedoList->LastChangeReason() == SynChangeReason::crNothing) { + if (mRedoList->LastChangeReason() == SynChangeReason::crGroupBreak) { int OldBlockNumber = mUndoList->blockChangeNumber(); Item = mRedoList->PopItem(); { @@ -4584,7 +4560,9 @@ void SynEdit::doRedoItem() Item->changeStartPos(), Item->changeStartPos(), Item->changeStartPos()); - doInsertText(Item->changeStartPos(),Item->changeText(), Item->changeSelMode()); + doInsertText(Item->changeStartPos(),Item->changeText(), Item->changeSelMode(), + Item->changeStartPos().Line, + Item->changeEndPos().Line); internalSetCaretXY(Item->changeEndPos()); mUndoList->AddChange(Item->changeReason(), Item->changeStartPos(), @@ -4889,6 +4867,9 @@ void SynEdit::moveCaretHorz(int DX, bool isSelection) bool bChangeY=true; if (bChangeY && (DX == -1) && (ptO.Char == 1) && (ptO.Line > 1)) { // end of previous line + if (mActiveSelectionMode==SynSelectionMode::smColumn) { + return; + } int row = lineToRow(ptDst.Line); row--; int line = rowToLine(row); @@ -4898,6 +4879,9 @@ void SynEdit::moveCaretHorz(int DX, bool isSelection) } } else if (bChangeY && (DX == 1) && (ptO.Char > nLineLen) && (ptO.Line < mDocument->count())) { // start of next line + if (mActiveSelectionMode==SynSelectionMode::smColumn) { + return; + } int row = lineToRow(ptDst.Line); row++; int line = rowToLine(row); @@ -4930,6 +4914,7 @@ void SynEdit::moveCaretVert(int DY, bool isSelection) DisplayCoord ptO = displayXY(); DisplayCoord ptDst = ptO; + ptDst.Row+=DY; if (DY >= 0) { if (rowToLine(ptDst.Row) > mDocument->count()) @@ -4944,6 +4929,14 @@ void SynEdit::moveCaretVert(int DY, bool isSelection) ptDst.Column = mLastCaretColumn; } BufferCoord vDstLineChar = displayToBufferPos(ptDst); + + if (mActiveSelectionMode==SynSelectionMode::smColumn) { + QString s=mDocument->getString(vDstLineChar.Line-1); + int cols=stringColumns(s,0); + if (cols+1EndBlock(); @@ -5363,8 +5356,6 @@ void SynEdit::doDeleteText(const BufferCoord &startPos, const BufferCoord &endPo bool UpdateMarks = false; int MarkOffset = 0; QStringList deleted=getContent(startPos,endPos,mode); - qDebug()<<"D----"; - qDebug()<endLine) + std::swap(startLine,endLine); int insertedLines = 0; BufferCoord newPos; @@ -5449,8 +5442,8 @@ void SynEdit::doInsertText(const BufferCoord& pos, const QStringList& text, SynS doLinesInserted(pos.Line+1, insertedLines); break; case SynSelectionMode::smColumn: - insertedLines = doInsertTextByColumnMode(pos,text, newPos); - doLinesInserted(pos.Line+text.length()-1-insertedLines,insertedLines); + insertedLines = doInsertTextByColumnMode(pos,text, newPos, startLine,endLine); + doLinesInserted(endLine-insertedLines+1,insertedLines); break; case SynSelectionMode::smLine: insertedLines = doInsertTextByLineMode(pos,text, newPos); @@ -5557,26 +5550,23 @@ int SynEdit::doInsertTextByNormalMode(const BufferCoord& pos, const QStringList& return result; } -int SynEdit::doInsertTextByColumnMode(const BufferCoord& pos, const QStringList& text, BufferCoord &newPos) +int SynEdit::doInsertTextByColumnMode(const BufferCoord& pos, const QStringList& text, BufferCoord &newPos, int startLine, int endLine) { QString str; QString tempString; - int insertCol; int line; int len; BufferCoord lineBreakPos; int result = 0; DisplayCoord insertCoord = bufferToDisplayPos(caretXY()); - int startLine = pos.Line; - // Insert string at begin of the selection - insertCol = insertCoord.Column; + int insertCol = insertCoord.Column; line = startLine; if (!mUndoing) { mUndoList->BeginBlock(); } - for (int i=0;i mDocument->count()) { result++; @@ -5589,7 +5579,7 @@ int SynEdit::doInsertTextByColumnMode(const BufferCoord& pos, const QStringList& mUndoList->AddChange(SynChangeReason::crLineBreak, lineBreakPos, lineBreakPos, - QStringList(), SynSelectionMode::smColumn); + QStringList(), SynSelectionMode::smNormal); } } else { tempString = mDocument->getString(line - 1); @@ -5610,8 +5600,12 @@ int SynEdit::doInsertTextByColumnMode(const BufferCoord& pos, const QStringList& BufferCoord{insertPos, line}, BufferCoord{insertPos+str.length(), line}, QStringList(), - SynSelectionMode::smColumn); + SynSelectionMode::smNormal); } + if (iproposedAction() == Qt::DropAction::CopyAction) { //just copy it - doInsertText(coord,text,mActiveSelectionMode); + doInsertText(coord,text,mActiveSelectionMode,coord.Line,coord.Line+text.length()-1); } else if (event->proposedAction() == Qt::DropAction::MoveAction) { if (coord < mDragSelBeginSave ) { //delete old doDeleteText(mDragSelBeginSave,mDragSelEndSave,mActiveSelectionMode); //paste to new position - doInsertText(coord,text,mActiveSelectionMode); + doInsertText(coord,text,mActiveSelectionMode,coord.Line,coord.Line+text.length()-1); } else { //paste to new position - doInsertText(coord,text,mActiveSelectionMode); + doInsertText(coord,text,mActiveSelectionMode,coord.Line,coord.Line+text.length()-1); //delete old doDeleteText(mDragSelBeginSave,mDragSelEndSave,mActiveSelectionMode); //set caret to right pos @@ -6666,7 +6660,7 @@ void SynEdit::onUndoAdded() // we have to clear the redo information, since adding undo info removes // the necessary context to undo earlier edit actions if (! mUndoList->insideRedo() && - mUndoList->PeekItem() && (mUndoList->PeekItem()->changeReason()!=SynChangeReason::crNothing)) + mUndoList->PeekItem() && (mUndoList->PeekItem()->changeReason()!=SynChangeReason::crGroupBreak)) mRedoList->Clear(); if (mUndoList->blockCount() == 0 ) onChanged(); diff --git a/RedPandaIDE/qsynedit/SynEdit.h b/RedPandaIDE/qsynedit/SynEdit.h index 06dc92e9..69d4e958 100644 --- a/RedPandaIDE/qsynedit/SynEdit.h +++ b/RedPandaIDE/qsynedit/SynEdit.h @@ -560,13 +560,11 @@ private: //primitive edit operations void doDeleteText(const BufferCoord& startPos, const BufferCoord& endPos, SynSelectionMode mode); - void doInsertText(const BufferCoord& pos, const QStringList& text, SynSelectionMode mode); + 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 doInsertTextByColumnMode(const BufferCoord& pos, const QStringList& text, BufferCoord &newPos); + int doInsertTextByColumnMode(const BufferCoord& pos, const QStringList& text, BufferCoord &newPos, int startLine, int endLine); int doInsertTextByLineMode(const BufferCoord& pos, const QStringList& text, BufferCoord &newPos); - - void deleteFromTo(const BufferCoord& start, const BufferCoord& end); void setSelWord(); void setWordBlock(BufferCoord Value); diff --git a/RedPandaIDE/qsynedit/TextBuffer.cpp b/RedPandaIDE/qsynedit/TextBuffer.cpp index c43abfe7..2e8096eb 100644 --- a/RedPandaIDE/qsynedit/TextBuffer.cpp +++ b/RedPandaIDE/qsynedit/TextBuffer.cpp @@ -874,8 +874,8 @@ void SynEditUndoList::AddGroupBreak() { //Add the GroupBreak even if ItemCount = 0. Since items are stored in //reverse order in TCustomSynEdit.fRedoList, a GroupBreak could be lost. - if (LastChangeReason() != SynChangeReason::crNothing) { - AddChange(SynChangeReason::crNothing, {0,0}, {0,0}, QStringList(), SynSelectionMode::smNormal); + if (LastChangeReason() != SynChangeReason::crGroupBreak) { + AddChange(SynChangeReason::crGroupBreak, {0,0}, {0,0}, QStringList(), SynSelectionMode::smNormal); } } @@ -958,7 +958,7 @@ void SynEditUndoList::PushItem(PSynEditUndoItem Item) return; mItems.append(Item); ensureMaxEntries(); - if (Item->changeReason()!= SynChangeReason::crNothing) + if (Item->changeReason()!= SynChangeReason::crGroupBreak) emit addedUndo(); } diff --git a/RedPandaIDE/qsynedit/TextBuffer.h b/RedPandaIDE/qsynedit/TextBuffer.h index 34420929..5d41b180 100644 --- a/RedPandaIDE/qsynedit/TextBuffer.h +++ b/RedPandaIDE/qsynedit/TextBuffer.h @@ -165,24 +165,12 @@ enum class SynChangeReason { crDelete, crCaret, //just restore the Caret, allowing better Undo behavior crSelection, //restore Selection - crNothing, + crGroupBreak, crLeftTop, crLineBreak, crMoveSelectionUp, - crMoveSelectionDown - //several undo entries can be chained together via the ChangeNumber - //see also TCustomSynEdit.[Begin|End]UndoBlock methods -// crDeleteAfterCursor, -// crLineBreak, crIndent, crUnindent, -// crSilentDelete, crSilentDeleteAfterCursor, -// crAutoCompleteBegin, crAutoCompleteEnd, -// crPasteBegin, crPasteEnd, //for pasting, since it might do a lot of operations -// crSpecial1Begin, crSpecial1End, -// crSpecial2Begin, crSpecial2End, - -// crNothing, -// crDeleteAll, - + crMoveSelectionDown, + crNothing }; class SynEditUndoItem { private: diff --git a/docs/qsynedit-redesign.txt b/docs/qsynedit-redesign.txt index 304a23ca..07881c0a 100644 --- a/docs/qsynedit-redesign.txt +++ b/docs/qsynedit-redesign.txt @@ -28,3 +28,5 @@ DELETE/BACKSPACE 鼠标拖拽 列模式 + +4. 列模式移动光标选择时,检查是否可选 \ No newline at end of file