+ fix: Undo/Redo handling in case of discarding U/R-Stack

This commit is contained in:
Rainer Kottenhoff 2018-04-19 13:09:38 +02:00
parent a5b86a91da
commit 2d538cf179
5 changed files with 123 additions and 105 deletions

Binary file not shown.

View File

@ -339,6 +339,55 @@ void EditInitWordDelimiter(HWND hwnd)
}
//=============================================================================
//
// _ClearTextBuffer()
//
void __fastcall _ClearTextBuffer(HWND hwnd)
{
SendMessage(hwnd, SCI_CANCEL, 0, 0);
if (SendMessage(hwnd, SCI_GETREADONLY, 0, 0)) { SendMessage(hwnd, SCI_SETREADONLY, false, 0); }
UndoRedoActionMap(-1, NULL);
SciCall_SetUndoCollection(false);
SendMessage(hwnd, SCI_CLEARALL, 0, 0);
SendMessage(hwnd, SCI_MARKERDELETEALL, (WPARAM)MARKER_NP3_BOOKMARK, 0);
EditClearAllOccurrenceMarkers(hwnd, 0, -1);
if (EditToggleView(g_hwndEdit, false)) {
EditToggleView(g_hwndEdit, true);
}
SciCall_SetUndoCollection(true);
SendMessage(hwnd, SCI_SETSCROLLWIDTH, 1, 0);
SendMessage(hwnd, SCI_SETXOFFSET, 0, 0);
}
//=============================================================================
//
// _InitTextBuffer()
//
void __fastcall _InitTextBuffer(HWND hwnd, const char* lpstrText, DocPos textLen, bool bSetSavePoint)
{
SciCall_SetUndoCollection(false);
if (textLen > 0) {
SciCall_AddText(textLen, lpstrText);
}
SciCall_GotoPos(0);
SciCall_ChooseCaretX(0);
SciCall_SetUndoCollection(true);
if (bSetSavePoint) { SendMessage(hwnd, SCI_SETSAVEPOINT, 0, 0); }
}
//=============================================================================
//
@ -347,38 +396,15 @@ void EditInitWordDelimiter(HWND hwnd)
extern bool bFreezeAppTitle;
extern FILEVARS fvCurFile;
void EditSetNewText(HWND hwnd,char* lpstrText,DWORD cbText)
{
bFreezeAppTitle = true;
if (SendMessage(hwnd, SCI_GETREADONLY, 0, 0)) {
SendMessage(hwnd, SCI_SETREADONLY, false, 0);
}
SendMessage(hwnd,SCI_CANCEL,0,0);
SendMessage(hwnd,SCI_SETUNDOCOLLECTION,0,0);
UndoRedoActionMap(-1,NULL);
SendMessage(hwnd,SCI_CLEARALL,0,0);
SendMessage(hwnd,SCI_MARKERDELETEALL,(WPARAM)MARKER_NP3_BOOKMARK,0);
SendMessage(hwnd,SCI_MARKERDELETEALL,(WPARAM)MARKER_NP3_OCCUR_LINE,0);
SendMessage(hwnd,SCI_SETSCROLLWIDTH,GetSystemMetrics(SM_CXSCREEN),0);
SendMessage(hwnd,SCI_SETXOFFSET,0,0);
if (EditToggleView(g_hwndEdit, false)) {
EditToggleView(g_hwndEdit, true);
}
_ClearTextBuffer(hwnd);
FileVars_Apply(hwnd,&fvCurFile);
if (cbText > 0) {
SendMessage(hwnd, SCI_ADDTEXT, cbText, (LPARAM)lpstrText);
}
SendMessage(hwnd,SCI_SETUNDOCOLLECTION,1,0);
//SendMessage(hwnd,EM_EMPTYUNDOBUFFER,0,0); // deprecated
SendMessage(hwnd,SCI_SETSAVEPOINT,0,0);
SendMessage(hwnd, SCI_SETSCROLLWIDTH, 1, 0);
SendMessage(hwnd,SCI_GOTOPOS,0,0);
SendMessage(hwnd,SCI_CHOOSECARETX,0,0);
_InitTextBuffer(hwnd, lpstrText, cbText, true);
bFreezeAppTitle = false;
}
@ -396,22 +422,12 @@ bool EditConvertText(HWND hwnd, int encSource, int encDest, bool bSetSavePoint)
if (!(Encoding_IsValid(encSource) && Encoding_IsValid(encDest)))
return(false);
DocPos length = SciCall_GetTextLength();
DocPos const length = SciCall_GetTextLength();
if (length == 0)
{
SendMessage(hwnd,SCI_CANCEL,0,0);
SendMessage(hwnd,SCI_SETUNDOCOLLECTION,0,0);
UndoRedoActionMap(-1,NULL);
SendMessage(hwnd,SCI_CLEARALL,0,0);
SendMessage(hwnd,SCI_MARKERDELETEALL,(WPARAM)MARKER_NP3_BOOKMARK,0);
SendMessage(hwnd, SCI_MARKERDELETEALL, (WPARAM)MARKER_NP3_OCCUR_LINE, 0);
SendMessage(hwnd,SCI_SETUNDOCOLLECTION,(WPARAM)1,0);
SendMessage(hwnd,SCI_GOTOPOS,0,0);
SendMessage(hwnd,SCI_CHOOSECARETX,0,0);
if (bSetSavePoint)
SendMessage(hwnd,SCI_SETSAVEPOINT,0,0);
_ClearTextBuffer(hwnd);
_InitTextBuffer(hwnd, NULL, length, bSetSavePoint);
}
else {
@ -439,20 +455,12 @@ bool EditConvertText(HWND hwnd, int encSource, int encDest, bool bSetSavePoint)
pchText[cbText] = '\0';
pchText[cbText+1] = '\0';
SendMessage(hwnd,SCI_CANCEL,0,0);
SendMessage(hwnd,SCI_SETUNDOCOLLECTION,0,0);
UndoRedoActionMap(-1,NULL);
SendMessage(hwnd,SCI_CLEARALL,0,0);
SendMessage(hwnd,SCI_MARKERDELETEALL,(WPARAM)MARKER_NP3_BOOKMARK,0);
SendMessage(hwnd, SCI_MARKERDELETEALL, (WPARAM)MARKER_NP3_OCCUR_LINE, 0);
SendMessage(hwnd,SCI_ADDTEXT,cbText,(LPARAM)pchText);
SendMessage(hwnd,SCI_SETUNDOCOLLECTION,(WPARAM)1,0);
SendMessage(hwnd,SCI_GOTOPOS,0,0);
SendMessage(hwnd,SCI_CHOOSECARETX,0,0);
FreeMem(pchText);
FreeMem(pwchText);
_ClearTextBuffer(hwnd);
_InitTextBuffer(hwnd, pchText, cbText, bSetSavePoint);
FreeMem(pchText);
}
return(true);
}
@ -485,6 +493,7 @@ bool EditSetNewEncoding(HWND hwnd,int iNewEncoding,bool bNoUI,bool bSetSavePoint
if (doNewEncoding) {
return EditConvertText(hwnd,iCurrentEncoding,iNewEncoding,bSetSavePoint);
}
}
else {
@ -499,6 +508,7 @@ bool EditSetNewEncoding(HWND hwnd,int iNewEncoding,bool bNoUI,bool bSetSavePoint
return false;
}
//=============================================================================
//
// EditIsRecodingNeeded()
@ -2747,9 +2757,7 @@ void EditIndentBlock(HWND hwnd, int cmd, bool bFormatIndentation)
//
void EditAlignText(HWND hwnd,int nMode)
{
#define BUFSIZE_ALIGN 1024
bool bModified = false;
#define BUFSIZE_ALIGN 2048
const DocPos iSelStart = SciCall_GetSelectionStart();
const DocPos iSelEnd = SciCall_GetSelectionEnd();
@ -2807,15 +2815,9 @@ void EditAlignText(HWND hwnd,int nMode)
DocPos iIndentPos = SciCall_GetLineIndentPosition(iLine);
if ((iIndentPos == iEndPos) && (iEndPos > 0)) {
if (!bModified) {
SendMessage(hwnd, SCI_BEGINUNDOACTION, 0, 0);
bModified = true;
}
SendMessage(hwnd, SCI_SETTARGETRANGE, SciCall_PositionFromLine(iLine), iEndPos);
SendMessage(hwnd, SCI_REPLACETARGET, 0, (LPARAM)"");
}
else {
char tchLineBuf[BUFSIZE_ALIGN*3] = { '\0' };
@ -2827,11 +2829,6 @@ void EditAlignText(HWND hwnd,int nMode)
int iWordsLength = 0;
DocPos cchLine = SciCall_GetLine(iLine, tchLineBuf);
if (!bModified) {
SendMessage(hwnd, SCI_BEGINUNDOACTION, 0, 0);
bModified = true;
}
MultiByteToWideChar(Encoding_SciCP,0,tchLineBuf,(int)cchLine,wchLineBuf,COUNTOF(wchLineBuf));
StrTrim(wchLineBuf,L"\r\n\t ");
@ -2979,10 +2976,6 @@ void EditAlignText(HWND hwnd,int nMode)
else
MsgBox(MBINFO, IDS_BUFFERTOOSMALL);
if (bModified) {
SendMessage(hwnd, SCI_ENDUNDOACTION, 0, 0);
}
if (iCurPos < iAnchorPos) {
iCurPos = SciCall_PositionFromLine(iLineStart);
iAnchorPos = SciCall_PositionFromLine(iLineEnd + 1);

View File

@ -960,13 +960,13 @@ HWND InitInstance(HINSTANCE hInstance,LPSTR pszCmdLine,int nCmdShow)
bool bAutoIndent2 = bAutoIndent;
bAutoIndent = 0;
EditJumpTo(g_hwndEdit, -1, 0);
SendMessage(g_hwndEdit, SCI_BEGINUNDOACTION, 0, 0);
int token = BeginUndoAction();
if (SendMessage(g_hwndEdit, SCI_GETLENGTH, 0, 0) > 0) {
SendMessage(g_hwndEdit, SCI_NEWLINE, 0, 0);
}
SendMessage(g_hwndEdit, SCI_PASTE, 0, 0);
SendMessage(g_hwndEdit, SCI_NEWLINE, 0, 0);
SendMessage(g_hwndEdit, SCI_ENDUNDOACTION, 0, 0);
EndUndoAction(token);
bAutoIndent = bAutoIndent2;
if (flagJumpTo)
EditJumpTo(g_hwndEdit, iInitialLine, iInitialColumn);
@ -5676,16 +5676,16 @@ LRESULT MsgNotify(HWND hwnd,WPARAM wParam,LPARAM lParam)
}
if (pLineBuf)
{
SendMessage(g_hwndEdit, SCI_GETLINE, iCurLine - 1, (LPARAM)pLineBuf);
SciCall_GetLine(iCurLine - 1, pLineBuf);
*(pLineBuf + iPrevLineLength) = '\0';
for (char* pPos = pLineBuf; *pPos; pPos++) {
if (*pPos != ' ' && *pPos != '\t')
*pPos = '\0';
}
if (*pLineBuf) {
SendMessage(g_hwndEdit, SCI_BEGINUNDOACTION, 0, 0);
SendMessage(g_hwndEdit, SCI_ADDTEXT, lstrlenA(pLineBuf), (LPARAM)pLineBuf);
SendMessage(g_hwndEdit, SCI_ENDUNDOACTION, 0, 0);
int token = BeginUndoAction();
SciCall_AddText(lstrlenA(pLineBuf), pLineBuf);
EndUndoAction(token);
}
if (bAllocLnBuf) { FreeMem(pLineBuf); }
}
@ -7480,9 +7480,13 @@ void UpdateUI()
// BeginUndoAction()
//
//
static volatile LONG UndoActionToken = -1L;
int BeginUndoAction()
{
int token = -1;
if (InterlockedExchange(&UndoActionToken, UndoActionToken) >= 0L) { return -1; } // already active
UndoRedoSelection_t sel = INIT_UNDOREDOSEL;
sel.selMode_undo = (int)SendMessage(g_hwndEdit,SCI_GETSELECTIONMODE,0,0);
@ -7505,16 +7509,19 @@ int BeginUndoAction()
sel.curPos_undo = (DocPos)SendMessage(g_hwndEdit, SCI_GETCURRENTPOS, 0, 0);
break;
}
token = UndoRedoActionMap(-1, &sel);
int token = UndoRedoActionMap(-1, &sel);
if (token >= 0) {
SendMessage(g_hwndEdit, SCI_BEGINUNDOACTION, 0, 0);
SendMessage(g_hwndEdit, SCI_ADDUNDOACTION, (WPARAM)token, 0);
SciCall_BeginUndoAction();
SciCall_AddUndoAction(token, 0);
}
InterlockedExchange(&UndoActionToken, (LONG)token);
return token;
}
//=============================================================================
//
// EndUndoAction()
@ -7522,10 +7529,12 @@ int BeginUndoAction()
//
void EndUndoAction(int token)
{
if (token >= 0) {
if ((token >= 0) && (token == (int)InterlockedExchange(&UndoActionToken, UndoActionToken)))
{
UndoRedoSelection_t sel = INIT_UNDOREDOSEL;
if (UndoRedoActionMap(token, &sel) >= 0) {
if (UndoRedoActionMap(token, &sel) >= 0)
{
sel.selMode_redo = (int)SendMessage(g_hwndEdit, SCI_GETSELECTIONMODE, 0, 0);
switch (sel.selMode_redo)
@ -7547,8 +7556,12 @@ void EndUndoAction(int token)
break;
}
}
UndoRedoActionMap(token,&sel); // set with redo action filled
SendMessage(g_hwndEdit, SCI_ENDUNDOACTION, 0, 0);
SciCall_EndUndoAction();
InterlockedExchange(&UndoActionToken, -1L);
}
}
@ -7567,18 +7580,18 @@ void RestoreAction(int token, DoAction doAct)
// we are inside undo/redo transaction, so do delayed PostMessage() instead of SendMessage()
#define ISSUE_MESSAGE PostMessage
const DocPos _anchorPos = (doAct == UNDO ? sel.anchorPos_undo : sel.anchorPos_redo);
const DocPos _curPos = (doAct == UNDO ? sel.curPos_undo : sel.curPos_redo);
DocPos const _anchorPos = (doAct == UNDO ? sel.anchorPos_undo : sel.anchorPos_redo);
DocPos const _curPos = (doAct == UNDO ? sel.curPos_undo : sel.curPos_redo);
// Ensure that the first and last lines of a selection are always unfolded
// This needs to be done _before_ the SCI_SETSEL message
const DocLn anchorPosLine = SciCall_LineFromPosition(_anchorPos);
const DocLn currPosLine = SciCall_LineFromPosition(_curPos);
DocLn const anchorPosLine = SciCall_LineFromPosition(_anchorPos);
DocLn const currPosLine = SciCall_LineFromPosition(_curPos);
ISSUE_MESSAGE(g_hwndEdit, SCI_ENSUREVISIBLE, anchorPosLine, 0);
if (anchorPosLine != currPosLine) { ISSUE_MESSAGE(g_hwndEdit, SCI_ENSUREVISIBLE, currPosLine, 0); }
const int selectionMode = (doAct == UNDO ? sel.selMode_undo : sel.selMode_redo);
int const selectionMode = (doAct == UNDO ? sel.selMode_undo : sel.selMode_redo);
ISSUE_MESSAGE(g_hwndEdit, SCI_SETSELECTIONMODE, (WPARAM)selectionMode, 0);
// independent from selection mode
@ -7594,8 +7607,8 @@ void RestoreAction(int token, DoAction doAct)
case SC_SEL_THIN:
{
const DocPos anchorVS = (doAct == UNDO ? sel.anchorVS_undo : sel.anchorVS_redo);
const DocPos currVS = (doAct == UNDO ? sel.curVS_undo : sel.curVS_redo);
DocPos const anchorVS = (doAct == UNDO ? sel.anchorVS_undo : sel.anchorVS_redo);
DocPos const currVS = (doAct == UNDO ? sel.curVS_undo : sel.curVS_redo);
if ((anchorVS != 0) || (currVS != 0)) {
ISSUE_MESSAGE(g_hwndEdit, SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE, (WPARAM)anchorVS, 0);
ISSUE_MESSAGE(g_hwndEdit, SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE, (WPARAM)currVS, 0);
@ -7625,26 +7638,31 @@ void RestoreAction(int token, DoAction doAct)
//
int UndoRedoActionMap(int token, UndoRedoSelection_t* selection)
{
if (UndoRedoSelectionUTArray == NULL) { return -1; }
if (UndoRedoSelectionUTArray == NULL) { return -1L; }
static unsigned int iTokenCnt = 0;
static unsigned int uiTokenCnt = 0U;
// indexing is unsigned
unsigned int utoken = (token >= 0) ? (unsigned int)token : 0U;
if (selection == NULL) {
// reset / clear
SendMessage(g_hwndEdit, SCI_EMPTYUNDOBUFFER, 0, 0);
int const curToken = InterlockedExchange(&UndoActionToken, UndoActionToken);
if (curToken >= 0) { EndUndoAction(curToken); }
SciCall_SetUndoCollection(false);
SciCall_EmptyUndoBuffer();
utarray_clear(UndoRedoSelectionUTArray);
utarray_init(UndoRedoSelectionUTArray, &UndoRedoSelection_icd);
iTokenCnt = 0U;
uiTokenCnt = 0U;
SciCall_SetUndoCollection(true);
InterlockedExchange(&UndoActionToken, -1L);
return -1;
}
if (!SciCall_GetUndoCollection()) { return -1; }
// get or set map item request ?
if ((token >= 0) && (utoken < iTokenCnt))
if ((token >= 0) && (utoken < uiTokenCnt))
{
if (selection->anchorPos_undo < 0) {
// this is a get request
@ -7658,9 +7676,9 @@ int UndoRedoActionMap(int token, UndoRedoSelection_t* selection)
}
else if (token < 0) {
// set map new item request
utarray_insert(UndoRedoSelectionUTArray, (void*)selection, iTokenCnt);
token = (int)iTokenCnt;
iTokenCnt = (iTokenCnt < INT_MAX) ? (iTokenCnt + 1) : 0U; // round robin next
token = (int)uiTokenCnt;
utarray_insert(UndoRedoSelectionUTArray, (void*)selection, uiTokenCnt);
uiTokenCnt = (uiTokenCnt < (unsigned int)INT_MAX) ? (uiTokenCnt + 1U) : 0U; // round robin next
}
return token;
}
@ -7894,12 +7912,12 @@ bool FileLoad(bool bDontSave, bool bNew, bool bReload, bool bSkipUnicodeDetect,
SendMessage(g_hwndEdit,SCI_GETTEXT,5,(LPARAM)tchLog);
if (StringCchCompareXA(tchLog,".LOG") == 0) {
EditJumpTo(g_hwndEdit,-1,0);
SendMessage(g_hwndEdit,SCI_BEGINUNDOACTION,0,0);
int token = BeginUndoAction();
SendMessage(g_hwndEdit,SCI_NEWLINE,0,0);
SendMessage(g_hwndMain,WM_COMMAND,MAKELONG(IDM_EDIT_INSERT_SHORTDATE,1),0);
EditJumpTo(g_hwndEdit,-1,0);
SendMessage(g_hwndEdit,SCI_NEWLINE,0,0);
SendMessage(g_hwndEdit,SCI_ENDUNDOACTION,0,0);
EndUndoAction(token);
SendMessage(g_hwndEdit, SCI_DOCUMENTEND, 0, 0);
EditEnsureSelectionVisible(g_hwndEdit);
}
@ -8937,13 +8955,13 @@ void CALLBACK PasteBoardTimer(HWND hwnd,UINT uMsg,UINT_PTR idEvent,DWORD dwTime)
bool bAutoIndent2 = bAutoIndent;
bAutoIndent = 0;
EditJumpTo(g_hwndEdit,-1,0);
SendMessage(g_hwndEdit,SCI_BEGINUNDOACTION,0,0);
int token = BeginUndoAction();
if (SendMessage(g_hwndEdit, SCI_GETLENGTH, 0, 0) > 0) {
SendMessage(g_hwndEdit, SCI_NEWLINE, 0, 0);
}
SendMessage(g_hwndEdit,SCI_PASTE,0,0);
SendMessage(g_hwndEdit,SCI_NEWLINE,0,0);
SendMessage(g_hwndEdit,SCI_ENDUNDOACTION,0,0);
EndUndoAction(token);
EditEnsureSelectionVisible(g_hwndEdit);
bAutoIndent = bAutoIndent2;
}

View File

@ -156,10 +156,12 @@ void UpdateUI();
void InvalidateSelections();
int BeginUndoAction();
int BeginUndoAction();
void EndUndoAction(int);
void RestoreAction(int,DoAction);
int UndoRedoActionMap(int,UndoRedoSelection_t*);
int UndoRedoActionMap(int,UndoRedoSelection_t*);
void OpenHotSpotURL(DocPos, bool);
bool IsFindPatternEmpty();

View File

@ -192,7 +192,6 @@ DeclareSciCallV2(SetSel, SETSEL, DocPos, anchorPos, DocPos, currentPos)
DeclareSciCallV0(SelectAll, SELECTALL)
DeclareSciCallR01(GetSelText, GETSELTEXT, DocPos, const char*, text)
DeclareSciCallV01(ReplaceSel, REPLACESEL, const char*, text)
DeclareSciCallR2(GetLine, GETLINE, DocPos, DocLn, line, const char*, text)
DeclareSciCallV2(InsertText, INSERTTEXT, DocPos, position, const char*, text)
@ -226,7 +225,8 @@ DeclareSciCallR2(FindColumn, FINDCOLUMN, DocPos, DocLn, line, DocPos, column)
DeclareSciCallR1(GetLineIndentPosition, GETLINEINDENTPOSITION, DocPos, DocLn, line)
DeclareSciCallR2(GetRangePointer, GETRANGEPOINTER, char* const, DocPos, start, DocPos, length)
DeclareSciCallR0(GetCharacterPointer, GETCHARACTERPOINTER, const char*)
DeclareSciCallR0(GetCharacterPointer, GETCHARACTERPOINTER, char* const)
DeclareSciCallR2(GetLine, GETLINE, DocPos, DocLn, line, const char*, text)
DeclareSciCallV1(SetVirtualSpaceOptions, SETVIRTUALSPACEOPTIONS, int, options)
@ -340,7 +340,12 @@ DeclareSciCallV1(SetCursor, SETCURSOR, int, flags)
//
// Undo/Redo Stack
//
DeclareSciCallV0(EmptyUndoBuffer, EMPTYUNDOBUFFER)
DeclareSciCallV0(BeginUndoAction, BEGINUNDOACTION)
DeclareSciCallV2(AddUndoAction, ADDUNDOACTION, int, token, int, flags)
DeclareSciCallV0(EndUndoAction, ENDUNDOACTION)
DeclareSciCallR0(GetUndoCollection, GETUNDOCOLLECTION, bool)
DeclareSciCallV1(SetUndoCollection, SETUNDOCOLLECTION, bool, bCollectUndo)
//=============================================================================