From 4738c96318418c7e338aa3c80ea2edfed81fa61c Mon Sep 17 00:00:00 2001 From: Udo Hoffmann Date: Wed, 13 May 2020 19:00:44 +0200 Subject: [PATCH] Fix clickable links break syntax highlighting issue By using indicators instead of stylers to make code shorter and cleaner. Fix #999, close #8263 --- PowerEditor/src/Notepad_plus.cpp | 131 +++--------------- PowerEditor/src/Notepad_plus.h | 3 +- PowerEditor/src/NppBigSwitch.cpp | 6 + PowerEditor/src/NppNotification.cpp | 65 +++------ .../WinControls/Preference/preferenceDlg.cpp | 4 + PowerEditor/src/resource.h | 4 +- 6 files changed, 56 insertions(+), 157 deletions(-) diff --git a/PowerEditor/src/Notepad_plus.cpp b/PowerEditor/src/Notepad_plus.cpp index 56be831a6ea..27188f58714 100644 --- a/PowerEditor/src/Notepad_plus.cpp +++ b/PowerEditor/src/Notepad_plus.cpp @@ -2453,123 +2453,38 @@ void Notepad_plus::setUniModeText() } -void Notepad_plus::addHotSpot() +void Notepad_plus::addHotSpot(ScintillaEditView* view) { - int startPos = 0; - int endPos = -1; - auto endStyle = _pEditView->execute(SCI_GETENDSTYLED); - - _pEditView->getVisibleStartAndEndPosition(&startPos, &endPos); - - _pEditView->execute(SCI_SETSEARCHFLAGS, SCFIND_REGEXP|SCFIND_POSIX); - - _pEditView->execute(SCI_SETTARGETRANGE, startPos, endPos); - - std::vector hotspotPairs; //= _pEditView->GetHotspotPairs(); - - unsigned char style_hotspot = 0; - unsigned char mask = 0x40; // INDIC1_MASK; - // INDIC2_MASK == 255 and it represents MSB bit - // only LEX_HTML and LEX_POSTSCRIPT use use INDIC2_MASK bit internally - // LEX_HTML is using INDIC2_MASK bit even though it has only 127 states, so it is safe to overwrite 8th bit - // INDIC2_MASK will be used for LEX_HTML - - // LEX_POSTSCRIPT is using INDIC2_MASK bit for "tokenization", and is using mask=31 in lexer, - // therefore hotspot in LEX_POSTSCRIPT will be saved to 5th bit - // there are only 15 states in LEX_POSTSCRIPT, so it is safe to overwrite 5th bit + ScintillaEditView* pView = view ? view : _pEditView; - // rule of the thumb is, any lexet that calls: styler.StartAt(startPos, 255); - // must have special processing here, all other lexers are fine with INDIC1_MASK (7th bit) + int urlAction = (NppParameters::getInstance()).getNppGUI()._styleURL; + LPARAM Style = (urlAction == 2) ? INDIC_PLAIN : INDIC_HIDDEN; + pView->execute(SCI_INDICSETSTYLE, URL_INDIC, Style); + pView->execute(SCI_INDICSETHOVERSTYLE, URL_INDIC, INDIC_FULLBOX); - LangType type = _pEditView->getCurrentBuffer()->getLangType(); - - if (type == L_HTML || type == L_PHP || type == L_ASP || type == L_JSP) - mask = 0x80; // INDIC2_MASK; - else if (type == L_PS) - mask = 16; + int startPos = 0; + int endPos = -1; + pView->getVisibleStartAndEndPosition(&startPos, &endPos); + if (startPos >= endPos) return; + pView->execute(SCI_SETINDICATORCURRENT, URL_INDIC); + pView->execute(SCI_INDICATORCLEARRANGE, startPos, endPos - startPos); + if (!urlAction) return; - int posFound = static_cast(_pEditView->execute(SCI_SEARCHINTARGET, strlen(URL_REG_EXPR), reinterpret_cast(URL_REG_EXPR))); + pView->execute(SCI_SETSEARCHFLAGS, SCFIND_REGEXP|SCFIND_POSIX); + pView->execute(SCI_SETTARGETRANGE, startPos, endPos); + int posFound = static_cast(pView->execute(SCI_SEARCHINTARGET, strlen(URL_REG_EXPR), reinterpret_cast(URL_REG_EXPR))); while (posFound != -1 && posFound != -2) { - int start = int(_pEditView->execute(SCI_GETTARGETSTART)); - int end = int(_pEditView->execute(SCI_GETTARGETEND)); + int start = int(pView->execute(SCI_GETTARGETSTART)); + int end = int(pView->execute(SCI_GETTARGETEND)); int foundTextLen = end - start; - unsigned char idStyle = static_cast(_pEditView->execute(SCI_GETSTYLEAT, posFound)); - - // Search the style - int fs = -1; - for (size_t i = 0, len = hotspotPairs.size(); i < len ; ++i) - { - // make sure to ignore "hotspot bit" when comparing document style with archived hotspot style - if ((hotspotPairs[i] & ~mask) == (idStyle & ~mask)) - { - fs = hotspotPairs[i]; - _pEditView->execute(SCI_STYLEGETFORE, fs); - break; - } - } - - // if we found it then use it to colourize - if (fs != -1) - { - _pEditView->execute(SCI_STARTSTYLING, start, 0xFF); - _pEditView->execute(SCI_SETSTYLING, foundTextLen, fs); - } - else // generalize a new style and add it into a array - { - style_hotspot = idStyle | mask; // set "hotspot bit" - hotspotPairs.push_back(style_hotspot); - unsigned char idStyleMSBunset = idStyle & ~mask; - char fontNameA[128]; - - Style hotspotStyle; - - hotspotStyle._styleID = static_cast(style_hotspot); - _pEditView->execute(SCI_STYLEGETFONT, idStyleMSBunset, reinterpret_cast(fontNameA)); - const size_t generic_fontnameLen = 128; - TCHAR *generic_fontname = new TCHAR[generic_fontnameLen]; - - WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance(); - const wchar_t * fontNameW = wmc.char2wchar(fontNameA, _nativeLangSpeaker.getLangEncoding()); - wcscpy_s(generic_fontname, generic_fontnameLen, fontNameW); - hotspotStyle._fontName = generic_fontname; - - hotspotStyle._fgColor = static_cast(_pEditView->execute(SCI_STYLEGETFORE, idStyleMSBunset)); - hotspotStyle._bgColor = static_cast(_pEditView->execute(SCI_STYLEGETBACK, idStyleMSBunset)); - hotspotStyle._fontSize = static_cast(_pEditView->execute(SCI_STYLEGETSIZE, idStyleMSBunset)); - - auto isBold = _pEditView->execute(SCI_STYLEGETBOLD, idStyleMSBunset); - auto isItalic = _pEditView->execute(SCI_STYLEGETITALIC, idStyleMSBunset); - auto isUnderline = _pEditView->execute(SCI_STYLEGETUNDERLINE, idStyleMSBunset); - hotspotStyle._fontStyle = (isBold?FONTSTYLE_BOLD:0) | (isItalic?FONTSTYLE_ITALIC:0) | (isUnderline?FONTSTYLE_UNDERLINE:0); - - int urlAction = (NppParameters::getInstance()).getNppGUI()._styleURL; - if (urlAction == 2) - hotspotStyle._fontStyle |= FONTSTYLE_UNDERLINE; - - _pEditView->setHotspotStyle(hotspotStyle); - - _pEditView->execute(SCI_STYLESETHOTSPOT, style_hotspot, TRUE); - int activeFG = 0xFF0000; - Style *urlHovered = getStyleFromName(TEXT("URL hovered")); - if (urlHovered) - activeFG = urlHovered->_fgColor; - _pEditView->execute(SCI_SETHOTSPOTACTIVEFORE, TRUE, activeFG); - _pEditView->execute(SCI_SETHOTSPOTSINGLELINE, style_hotspot, 0); - - // colourize it! - _pEditView->execute(SCI_STARTSTYLING, start, 0xFF); - _pEditView->execute(SCI_SETSTYLING, foundTextLen, style_hotspot); - } - - _pEditView->execute(SCI_SETTARGETRANGE, posFound + foundTextLen, endPos); - - posFound = static_cast(_pEditView->execute(SCI_SEARCHINTARGET, strlen(URL_REG_EXPR), reinterpret_cast(URL_REG_EXPR))); + pView->execute(SCI_SETINDICATORCURRENT, URL_INDIC); + pView->execute(SCI_SETINDICATORVALUE, 0); + pView->execute(SCI_INDICATORFILLRANGE, start, foundTextLen); + pView->execute(SCI_SETTARGETRANGE, posFound + foundTextLen, endPos); + posFound = static_cast(pView->execute(SCI_SEARCHINTARGET, strlen(URL_REG_EXPR), reinterpret_cast(URL_REG_EXPR))); } - - _pEditView->execute(SCI_STARTSTYLING, endStyle, 0xFF); - _pEditView->execute(SCI_SETSTYLING, 0, 0); } bool Notepad_plus::isConditionExprLine(int lineNumber) diff --git a/PowerEditor/src/Notepad_plus.h b/PowerEditor/src/Notepad_plus.h index 9172fb9ff77..8f6cb05e52a 100644 --- a/PowerEditor/src/Notepad_plus.h +++ b/PowerEditor/src/Notepad_plus.h @@ -62,6 +62,7 @@ #define TOOLBAR 0x02 #define URL_REG_EXPR "[A-Za-z]+://[A-Za-z0-9_\\-\\+~.:?&@=/%#,;\\{\\}\\(\\)\\[\\]\\|\\*\\!\\\\]+" +#define URL_INDIC 8 enum FileTransferMode { TransferClone = 0x01, @@ -496,7 +497,7 @@ friend class FileManager; int findMachedBracePos(size_t startPos, size_t endPos, char targetSymbol, char matchedSymbol); void maintainIndentation(TCHAR ch); - void addHotSpot(); + void addHotSpot(ScintillaEditView* view = NULL); void bookmarkAdd(int lineno) const { diff --git a/PowerEditor/src/NppBigSwitch.cpp b/PowerEditor/src/NppBigSwitch.cpp index 919935ebf59..63f7d2838b6 100644 --- a/PowerEditor/src/NppBigSwitch.cpp +++ b/PowerEditor/src/NppBigSwitch.cpp @@ -2448,6 +2448,12 @@ LRESULT Notepad_plus::process(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa return TRUE; } + case NPPM_INTERNAL_UPDATECLICKABLELINKS: + { + addHotSpot(_pEditView); + addHotSpot(_pNonEditView); + } + default: { if (message == WDN_NOTIFY) diff --git a/PowerEditor/src/NppNotification.cpp b/PowerEditor/src/NppNotification.cpp index f7fce42cc96..9a06986c90c 100644 --- a/PowerEditor/src/NppNotification.cpp +++ b/PowerEditor/src/NppNotification.cpp @@ -611,9 +611,7 @@ BOOL Notepad_plus::notify(SCNotification *notification) if (!_isFolding) { - int urlAction = (NppParameters::getInstance()).getNppGUI()._styleURL; - if ((urlAction == 1) || (urlAction == 2)) - addHotSpot(); + addHotSpot(); } if (_pDocMap) @@ -789,7 +787,22 @@ BOOL Notepad_plus::notify(SCNotification *notification) } } } - + else + { // Double click with no modifiers + // Check wether cursor is within URL + auto indicMsk = notifyView->execute(SCI_INDICATORALLONFOR, notification->position); + if (!(indicMsk & (1 << URL_INDIC))) break; + + // Revert selection of current word. Best to this early, otherwise the + // selected word is visible all the time while the browser is starting + notifyView->execute(SCI_SETSEL, notification->position, notification->position); + + // Open URL + auto startPos = notifyView->execute(SCI_INDICATORSTART, URL_INDIC, notification->position); + auto endPos = notifyView->execute(SCI_INDICATOREND, URL_INDIC, notification->position); + generic_string url = notifyView->getGenericTextAsString(static_cast(startPos), static_cast(endPos)); + ::ShellExecute(_pPublicInterface->getHSelf(), TEXT("open"), url.c_str(), NULL, NULL, SW_SHOW); + } break; } @@ -804,9 +817,7 @@ BOOL Notepad_plus::notify(SCNotification *notification) // replacement for obsolete custom SCN_SCROLLED if (notification->updated & SC_UPDATE_V_SCROLL) { - int urlAction = (NppParameters::getInstance()).getNppGUI()._styleURL; - if ((urlAction == 1) || (urlAction == 2)) - addHotSpot(); + addHotSpot(); } // if it's searching/replacing, then do nothing @@ -973,9 +984,7 @@ BOOL Notepad_plus::notify(SCNotification *notification) // if it's searching/replacing, then do nothing if ((_linkTriggered && !nppParam._isFindReplacing) || notification->wParam == LINKTRIGGERED) { - int urlAction = (NppParameters::getInstance()).getNppGUI()._styleURL; - if ((urlAction == 1) || (urlAction == 2)) - addHotSpot(); + addHotSpot(); _linkTriggered = false; } @@ -987,42 +996,6 @@ BOOL Notepad_plus::notify(SCNotification *notification) break; } - case SCN_HOTSPOTDOUBLECLICK: - { - if (not notifyView) - return FALSE; - - // Get the style and make sure it is a hotspot - uint8_t style = static_cast(notifyView->execute(SCI_GETSTYLEAT, notification->position)); - if (not notifyView->execute(SCI_STYLEGETHOTSPOT, style)) - break; - - long long startPos, endPos, docLen; - startPos = endPos = notification->position; - docLen = notifyView->getCurrentDocLen(); - - // Walk backwards/forwards to get the contiguous text in the same style - while (startPos > 0 && static_cast(notifyView->execute(SCI_GETSTYLEAT, static_cast(startPos - 1))) == style) - startPos--; - while (endPos < docLen && static_cast(notifyView->execute(SCI_GETSTYLEAT, static_cast(endPos))) == style) - endPos++; - - // Select the entire link - notifyView->execute(SCI_SETANCHOR, static_cast(startPos)); - notifyView->execute(SCI_SETCURRENTPOS, static_cast(endPos)); - - generic_string url = notifyView->getGenericTextAsString(static_cast(startPos), static_cast(endPos)); - - // remove the flickering: it seems a mouse left button up is missing after SCN_HOTSPOTDOUBLECLICK - ::PostMessage(notifyView->getHSelf(), WM_LBUTTONUP, 0, 0); - auto curPos = notifyView->execute(SCI_GETCURRENTPOS); - notifyView->execute(SCI_SETSEL, curPos, curPos); - - ::ShellExecute(_pPublicInterface->getHSelf(), TEXT("open"), url.c_str(), NULL, NULL, SW_SHOW); - - break; - } - case SCN_NEEDSHOWN: { break; diff --git a/PowerEditor/src/WinControls/Preference/preferenceDlg.cpp b/PowerEditor/src/WinControls/Preference/preferenceDlg.cpp index 33eea15b296..e6727204f68 100644 --- a/PowerEditor/src/WinControls/Preference/preferenceDlg.cpp +++ b/PowerEditor/src/WinControls/Preference/preferenceDlg.cpp @@ -1004,6 +1004,8 @@ INT_PTR CALLBACK SettingsDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM) ::EnableWindow(::GetDlgItem(_hSelf, IDC_CHECK_CLICKABLELINK_NOUNDERLINE), isChecked); nppGUI._styleURL = isChecked?2:0; + HWND grandParent = ::GetParent(_hParent); + ::SendMessage(grandParent, NPPM_INTERNAL_UPDATECLICKABLELINKS, 0, 0); } return TRUE; @@ -1011,6 +1013,8 @@ INT_PTR CALLBACK SettingsDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM) { bool isChecked = isCheckedOrNot(IDC_CHECK_CLICKABLELINK_NOUNDERLINE); nppGUI._styleURL = isChecked?1:2; + HWND grandParent = ::GetParent(_hParent); + ::SendMessage(grandParent, NPPM_INTERNAL_UPDATECLICKABLELINKS, 0, 0); } return TRUE; diff --git a/PowerEditor/src/resource.h b/PowerEditor/src/resource.h index b43b8b1fa59..c9f19e7ddb5 100644 --- a/PowerEditor/src/resource.h +++ b/PowerEditor/src/resource.h @@ -443,8 +443,8 @@ #define NPPM_INTERNAL_STOPMONITORING (NOTEPADPLUS_USER_INTERNAL + 49) // Used by Monitoring feature #define NPPM_INTERNAL_EDGEBACKGROUND (NOTEPADPLUS_USER_INTERNAL + 50) #define NPPM_INTERNAL_EDGEMULTISETSIZE (NOTEPADPLUS_USER_INTERNAL + 51) - //wParam: 0 - //lParam: document new index + #define NPPM_INTERNAL_UPDATECLICKABLELINKS (NOTEPADPLUS_USER_INTERNAL + 52) + // See Notepad_plus_msgs.h //#define NOTEPADPLUS_USER (WM_USER + 1000)