From a6ff703c1430aadf5e1ebd676a7f03ebf2dbb4da Mon Sep 17 00:00:00 2001 From: "METANEOCORTEX\\Kotti" Date: Tue, 2 May 2023 15:55:06 +0200 Subject: [PATCH] +fix: cut (Ctrl+X) and delete (Ctrl+D) last line (EOF -> EOL) --- src/Edit.c | 295 ++++++++++++++++++++++++++----------------------- src/Edit.h | 1 + src/Notepad3.c | 4 + src/SciCall.h | 16 ++- 4 files changed, 173 insertions(+), 143 deletions(-) diff --git a/src/Edit.c b/src/Edit.c index 46ca346cc..98e850574 100644 --- a/src/Edit.c +++ b/src/Edit.c @@ -799,17 +799,22 @@ void EditGetClipboardW(LPWSTR pwchBuffer, size_t wchLength) // bool EditSetClipboardText(HWND hwnd, const char* pszText, size_t cchText) { + if (!pszText || cchText == 0) { + EditClearClipboard(hwnd); + return true; + } + if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) { SciCall_CopyText((DocPos)cchText, pszText); return true; } - WCHAR* pszTextW = NULL; - ptrdiff_t const cchTextW = MultiByteToWideCharEx(Encoding_SciCP, 0, pszText, cchText, NULL, 0); - if (cchTextW > 1) { + WCHAR* pszTextW = NULL; + ptrdiff_t const cchTextW = MultiByteToWideChar(Encoding_SciCP, 0, pszText, (int)cchText, NULL, 0); + if (cchTextW > 0) { pszTextW = AllocMem((cchTextW + 1) * sizeof(WCHAR), HEAP_ZERO_MEMORY); if (pszTextW) { - MultiByteToWideCharEx(Encoding_SciCP, 0, pszText, cchText, pszTextW, cchTextW + 1); + MultiByteToWideChar(Encoding_SciCP, 0, pszText, (int)cchText, pszTextW, (int)(cchTextW + 1)); pszTextW[cchTextW] = L'\0'; } } @@ -817,13 +822,67 @@ bool EditSetClipboardText(HWND hwnd, const char* pszText, size_t cchText) if (pszTextW) { SetClipboardText(GetParent(hwnd), pszTextW, cchTextW); FreeMem(pszTextW); - pszTextW = NULL; return true; } return false; } +//============================================================================= +// +// EditAppendToClipboard() - (append current linebreak too - even if empty) +// +bool EditAppendToClipboard(HWND hwnd, const char* pszText, size_t cchText) +{ + bool res = false; + ptrdiff_t const cchTextW = MultiByteToWideChar(Encoding_SciCP, 0, pszText, (int)cchText, NULL, 0); + WCHAR* pszTextW = AllocMem((cchTextW + 1) * sizeof(WCHAR), HEAP_ZERO_MEMORY); + if (pszTextW) { + MultiByteToWideChar(Encoding_SciCP, 0, pszText, (int)cchText, pszTextW, (int)(cchTextW + 1)); + pszTextW[cchTextW] = L'\0'; + } + if (!pszTextW) { + return res; + } + + HWND const hwndParent = GetParent(hwnd); + if (!OpenClipboard(hwndParent)) { + FreeMem(pszTextW); + pszTextW = NULL; + return res; + } + + HANDLE const hOld = GetClipboardData(CF_UNICODETEXT); + const WCHAR* pszOld = GlobalLock(hOld); + + WCHAR pszSep[3] = { L'\0' }; + Sci_GetCurrentEOL_W(pszSep); + + size_t const cchNewText = cchTextW + StringCchLen(pszOld, 0) + StringCchLen(pszSep, 0); + + // Copy Clip & add line break + WCHAR* const pszNewTextW = AllocMem((cchNewText + 1) * sizeof(WCHAR), HEAP_ZERO_MEMORY); + if (pszNewTextW) { + if (pszOld) { StringCchCopy(pszNewTextW, (cchNewText + 1), pszOld); } + StringCchCat(pszNewTextW, (cchNewText + 1), pszSep); + } + GlobalUnlock(hOld); + CloseClipboard(); + + // Add New + if (pszNewTextW) { + if (pszTextW) { StringCchCat(pszNewTextW, (cchNewText + 1), pszTextW); } + res = SetClipboardText(hwndParent, pszNewTextW, cchNewText); + } + + FreeMem(pszNewTextW); + FreeMem(pszTextW); + + return res; +} + + + //============================================================================= // // EditClearClipboard() @@ -891,6 +950,7 @@ bool EditSwapClipboard(HWND hwnd, bool bSkipUnicodeCheck) } + //============================================================================= // // EditCopyRangeAppend() @@ -901,75 +961,19 @@ bool EditCopyRangeAppend(HWND hwnd, DocPos posBegin, DocPos posEnd, bool bAppend swapos(&posBegin, &posEnd); } DocPos const length = (posEnd - posBegin); - if (length == 0) { + if (!length) { return true; } const char* const pszText = SciCall_GetRangePointer(posBegin, length); - WCHAR* pszTextW = NULL; - ptrdiff_t cchTextW = 0; - if (pszText && *pszText) { - cchTextW = MultiByteToWideChar(Encoding_SciCP, 0, pszText, (int)length, NULL, 0); - if (cchTextW > 0) { - pszTextW = AllocMem((cchTextW + 1) * sizeof(WCHAR), HEAP_ZERO_MEMORY); - if (pszTextW) { - MultiByteToWideChar(Encoding_SciCP, 0, pszText, (int)length, pszTextW, (int)(cchTextW + 1)); - pszTextW[cchTextW] = L'\0'; - } - } - else { - return false; - } - } - bool res = false; - HWND const hwndParent = GetParent(hwnd); - - if (!bAppend) { - res = SetClipboardText(hwndParent, pszTextW, cchTextW); - FreeMem(pszTextW); - pszTextW = NULL; - return res; + if (bAppend) { + res = EditAppendToClipboard(hwnd, pszText, length); } - - // --- Append to Clipboard --- - - if (!OpenClipboard(hwndParent)) { - FreeMem(pszTextW); - pszTextW = NULL; - return res; + else { + res = EditSetClipboardText(hwnd, pszText, length); } - - HANDLE const hOld = GetClipboardData(CF_UNICODETEXT); - const WCHAR* pszOld = GlobalLock(hOld); - - WCHAR pszSep[3] = { L'\0' }; - Sci_GetCurrentEOL_W(pszSep); - - size_t cchNewText = cchTextW; - if (pszOld && *pszOld) { - cchNewText += (StringCchLen(pszOld, 0) + StringCchLen(pszSep, 0)); - } - - // Copy Clip & add line break - WCHAR* const pszNewTextW = AllocMem((cchNewText + 1) * sizeof(WCHAR), HEAP_ZERO_MEMORY); - if (pszOld && *pszOld && pszNewTextW) { - StringCchCopy(pszNewTextW, cchNewText + 1, pszOld); - StringCchCat(pszNewTextW, cchNewText + 1, pszSep); - } - GlobalUnlock(hOld); - CloseClipboard(); - - // Add New - if (pszTextW && *pszTextW && pszNewTextW) { - StringCchCat(pszNewTextW, cchNewText + 1, pszTextW); - res = SetClipboardText(hwndParent, pszNewTextW, cchNewText); - } - - FreeMem(pszTextW); - pszTextW = NULL; - FreeMem(pszNewTextW); return res; } @@ -2941,95 +2945,106 @@ static int utsort_ln(const void *a, const void *b) { return (_a < _b) ? -1 : ((_a > _b) ? 1 : 0); } -void EditCutLines(HWND hwnd) { - - if (!Sci_IsMultiOrRectangleSelection()) { - +void EditCutLines(HWND hwnd) +{ + if (!Sci_IsMultiOrRectangleSelection()) + { + bool const bInLastLine = Sci_InLastLine(); + bool const bClearCB = bInLastLine ? (Sci_GetNetLineLength(Sci_GetCurrentLineNumber()) == 0) : false; UndoTransActionBegin(); SciCall_LineCut(); + if (bInLastLine) { + SciCall_DeleteBack(); + SciCall_Home(); + } EndUndoTransAction(); - - } else { + if (bInLastLine) { + if (bClearCB) { + EditClearClipboard(hwnd); + } + EditAppendToClipboard(hwnd, "", 0); // adds EOL instead of EOF + } + return; + } - DocPos const iRestorePos = Sci_GetLineStartPosition(SciCall_GetSelectionStart()); - bool const bSelRectangle = SciCall_IsSelectionRectangle(); + DocPos const iRestorePos = Sci_GetLineStartPosition(SciCall_GetSelectionStart()); + bool const bSelRectangle = SciCall_IsSelectionRectangle(); - UT_icd docln_icd = { sizeof(DocLn), NULL, NULL, NULL }; - UT_array *lines; - utarray_new(lines, &docln_icd); - - DocLn const ln_init = -1; - utarray_push_back(lines, &ln_init); // first elem to compare + UT_icd docln_icd = { sizeof(DocLn), NULL, NULL, NULL }; + UT_array* lines; + utarray_new(lines, &docln_icd); - DocPosU const selCount = SciCall_GetSelections(); + DocLn const ln_init = -1; + utarray_push_back(lines, &ln_init); // first elem to compare - if (bSelRectangle) { + DocPosU const selCount = SciCall_GetSelections(); - DocLn const seln_beg = SciCall_LineFromPosition(SciCall_GetSelectionStart()); - DocLn const seln_end = SciCall_LineFromPosition(SciCall_GetSelectionEnd()); + if (bSelRectangle) { - EditCopyRangeAppend(hwnd, SciCall_PositionFromLine(seln_beg), SciCall_PositionFromLine(seln_end + 1), false); + DocLn const seln_beg = SciCall_LineFromPosition(SciCall_GetSelectionStart()); + DocLn const seln_end = SciCall_LineFromPosition(SciCall_GetSelectionEnd()); + EditCopyRangeAppend(hwnd, SciCall_PositionFromLine(seln_beg), SciCall_PositionFromLine(seln_end + 1), false); + + // add all lines in between + for (DocLn l = seln_beg; l <= seln_end; ++l) { + utarray_push_back(lines, &l); + } + } + else { + + for (DocPosU s = 0; s < selCount; ++s) { + + DocLn const seln_beg = SciCall_LineFromPosition(SciCall_GetSelectionNStart(s)); + DocLn const seln_end = SciCall_LineFromPosition(SciCall_GetSelectionNEnd(s)); + DocLn const last_ln = (DocLn)utarray_back(lines); + if (seln_beg != last_ln) { + utarray_push_back(lines, &seln_beg); + } // add all lines in between - for (DocLn l = seln_beg; l <= seln_end; ++l) { + for (DocLn l = seln_beg + 1; l <= seln_end; ++l) { utarray_push_back(lines, &l); } - - } else { - - for (DocPosU s = 0; s < selCount; ++s) { - - DocLn const seln_beg = SciCall_LineFromPosition(SciCall_GetSelectionNStart(s)); - DocLn const seln_end = SciCall_LineFromPosition(SciCall_GetSelectionNEnd(s)); - DocLn const last_ln = (DocLn)utarray_back(lines); - if (seln_beg != last_ln) { - utarray_push_back(lines, &seln_beg); - } - // add all lines in between - for (DocLn l = seln_beg + 1; l <= seln_end; ++l) { - utarray_push_back(lines, &l); - } - } - utarray_sort(lines, utsort_ln); - } - - // prepare appending - if ((utarray_len(lines) > 1) && !bSelRectangle) { - EditClearClipboard(hwnd); - } - - DocLn* pLn = NULL; - pLn = (DocLn*)utarray_next(lines, pLn); // initial item - DocLn prevLn = pLn ? *pLn : -1; - DocLn delCnt = 0; - - UndoTransActionBegin(); - - while ((pLn = (DocLn *)utarray_next(lines, pLn)) != NULL) { - if (prevLn != *pLn) { - DocLn const del_ln = *pLn - delCnt; - DocPos const posLn = SciCall_PositionFromLine(del_ln); - if (!bSelRectangle) { - EditCopyRangeAppend(hwnd, posLn, SciCall_GetLineEndPosition(del_ln), true); - } - SciCall_SetAnchor(posLn); - SciCall_SetCurrentPos(posLn); - SciCall_LineDelete(); - ++delCnt; - prevLn = *pLn; - } - } - - EndUndoTransAction(); - - utarray_free(lines); - - Sci_GotoPosChooseCaret(iRestorePos); + utarray_sort(lines, utsort_ln); } + + // prepare appending + if ((utarray_len(lines) > 1) && !bSelRectangle) { + EditClearClipboard(hwnd); + } + + DocLn* pLn = NULL; + pLn = (DocLn*)utarray_next(lines, pLn); // initial item + DocLn prevLn = pLn ? *pLn : -1; + DocLn delCnt = 0; + + UndoTransActionBegin(); + + while ((pLn = (DocLn*)utarray_next(lines, pLn)) != NULL) { + if (prevLn != *pLn) { + DocLn const del_ln = *pLn - delCnt; + DocPos const posLn = SciCall_PositionFromLine(del_ln); + if (!bSelRectangle) { + EditCopyRangeAppend(hwnd, posLn, SciCall_GetLineEndPosition(del_ln), true); + } + SciCall_SetAnchor(posLn); + SciCall_SetCurrentPos(posLn); + SciCall_LineDelete(); + ++delCnt; + prevLn = *pLn; + } + } + + EndUndoTransAction(); + + utarray_free(lines); + + Sci_GotoPosChooseCaret(iRestorePos); } + //============================================================================= // // EditCopyMultiSelection() @@ -8068,7 +8083,7 @@ static void _UpdateIndicators(const int indicator, const int indicator2nd, swapos(&startPos, &endPos); } if (startPos < 0) { // current line only - DocLn const lineNo = SciCall_LineFromPosition(SciCall_GetCurrentPos()); + DocLn const lineNo = Sci_GetCurrentLineNumber(); startPos = SciCall_PositionFromLine(lineNo); endPos = SciCall_GetLineEndPosition(lineNo); } else if (endPos == startPos) { @@ -8326,7 +8341,7 @@ static INT_PTR CALLBACK EditLinenumDlgProc(HWND hwnd,UINT umsg,WPARAM wParam,LPA } #endif - DocLn const iCurLine = SciCall_LineFromPosition(SciCall_GetCurrentPos())+1; + DocLn const iCurLine = Sci_GetCurrentLineNumber() + 1; DocLn const iMaxLnNum = SciCall_GetLineCount(); DocPos const iCurColumn = SciCall_GetColumn(SciCall_GetCurrentPos()) + 1; DocPos const iLineEndPos = Sci_GetNetLineLength(iCurLine); @@ -9740,7 +9755,7 @@ void EditFoldClick(DocLn ln, int mode) void EditFoldCmdKey(FOLD_MOVE move, FOLD_ACTION action) { if (FocusedView.CodeFoldingAvailable && FocusedView.ShowCodeFolding) { - DocLn ln = SciCall_LineFromPosition(SciCall_GetCurrentPos()); + DocLn ln = Sci_GetCurrentLineNumber(); // Jump to the next visible fold point if (move == DOWN) { diff --git a/src/Edit.h b/src/Edit.h index 1f37df618..8a4cd9385 100644 --- a/src/Edit.h +++ b/src/Edit.h @@ -35,6 +35,7 @@ size_t EditGetSelectedText(LPWSTR pwchBuffer, size_t wchCount); char* EditGetClipboardText(HWND hwnd,bool,int* pLineCount,int* pLenLastLn); void EditGetClipboardW(LPWSTR pwchBuffer, size_t wchLength); bool EditSetClipboardText(HWND hwnd, const char* pszText, size_t cchText); +bool EditAppendToClipboard(HWND hwnd, const char* pszText, size_t cchText); bool EditClearClipboard(HWND hwnd); bool EditSwapClipboard(HWND hwnd,bool); bool EditCopyRangeAppend(HWND hwnd, DocPos posBegin, DocPos posEnd, bool bAppend); diff --git a/src/Notepad3.c b/src/Notepad3.c index 5134160ff..431070df3 100644 --- a/src/Notepad3.c +++ b/src/Notepad3.c @@ -5174,6 +5174,10 @@ LRESULT MsgCommand(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) case IDM_EDIT_DELETELINE: { UserMarkerDeleteAll(Sci_GetCurrentLineNumber()); SciCall_LineDelete(); + if (Sci_InLastLine()) { + SciCall_DeleteBack(); + SciCall_Home(); + } } break; diff --git a/src/SciCall.h b/src/SciCall.h index 8d9afcf76..20a26175d 100644 --- a/src/SciCall.h +++ b/src/SciCall.h @@ -313,10 +313,14 @@ DeclareSciCallV0(ZoomIn, ZOOMIN); DeclareSciCallV0(ZoomOut, ZOOMOUT); // Keyboard Commands +// The SCI_HOME* commands move the caret to the start of the line, +// while the SCI_VCHOME* commands move the caret to the first non-blank character of the line +// (ie. just after the indentation) unless it is already there; in this case, it acts as SCI_HOME*. +DeclareSciCallV0(Home, HOME); +DeclareSciCallV0(VCHome, VCHOME); DeclareSciCallV0(NewLine, NEWLINE); DeclareSciCallV0(Tab, TAB); DeclareSciCallV0(BackTab, BACKTAB); -DeclareSciCallV0(VCHome, VCHOME); DeclareSciCallV0(LineUp, LINEUP); DeclareSciCallV0(LineDown, LINEDOWN); DeclareSciCallV0(LineUpExtend, LINEUPEXTEND); @@ -772,10 +776,11 @@ DeclareSciCallR0(IsSelectionRectangle, SELECTIONISRECTANGLE, bool); #define Sci_HaveUndoRedoHistory() (SciCall_CanUndo() || SciCall_CanRedo()) +#define Sci_GetCurrentLineNumber() SciCall_LineFromPosition(SciCall_GetCurrentPos()) #define Sci_GetCurrentColumnNumber() SciCall_GetColumn(SciCall_GetCurrentPos()) #define Sci_GetAnchorLineNumber() SciCall_LineFromPosition(SciCall_GetAnchor()) -#define Sci_GetCurrentLineNumber() SciCall_LineFromPosition(SciCall_GetCurrentPos()) #define Sci_GetLastDocLineNumber() (SciCall_GetLineCount() - 1) +#define Sci_InLastLine() (SciCall_GetLineCount() == (Sci_GetCurrentLineNumber() + 1)) #define Sci_GetLineStartPosition(position) SciCall_PositionFromLine(SciCall_LineFromPosition(position)) #define Sci_GetLineEndPosition(position) SciCall_GetLineEndPosition(SciCall_LineFromPosition(position)) @@ -812,11 +817,13 @@ inline void Sci_GotoPosChooseCaret(const DocPos pos) SciCall_GotoPos(pos); SciCall_ChooseCaretX(); } + inline void Sci_ScrollChooseCaret() { SciCall_ScrollCaret(); SciCall_ChooseCaretX(); } + inline void Sci_ScrollToLine(const DocLn line) { if (!SciCall_GetLineVisible(line)) { @@ -824,14 +831,16 @@ inline void Sci_ScrollToLine(const DocLn line) } SciCall_ScrollRange(SciCall_GetLineEndPosition(line), SciCall_PositionFromLine(line)); } + inline void Sci_ScrollToCurrentLine() { Sci_ScrollToLine(Sci_GetCurrentLineNumber()); } + inline void Sci_EnsureVisibleSelection() { + DocLn const iCurrentLn = Sci_GetCurrentLineNumber(); DocLn const iAnchorLn = SciCall_LineFromPosition(SciCall_GetAnchor()); - DocLn const iCurrentLn = SciCall_LineFromPosition(SciCall_GetCurrentPos()); if (!SciCall_GetLineVisible(iAnchorLn)) { if (iAnchorLn == iCurrentLn) { SciCall_EnsureVisibleEnforcePolicy(iAnchorLn); @@ -843,6 +852,7 @@ inline void Sci_EnsureVisibleSelection() SciCall_EnsureVisibleEnforcePolicy(iCurrentLn); } } + inline void Sci_ScrollSelectionToView() { Sci_EnsureVisibleSelection();