mirror of
https://github.com/notepad-plus-plus/notepad-plus-plus.git
synced 2025-07-26 07:15:21 +02:00
Fix clickable links break syntax highlighting issue
By using indicators instead of stylers to make code shorter and cleaner. Fix #999, close #8263
This commit is contained in:
parent
9f29015a71
commit
4738c96318
@ -2453,123 +2453,38 @@ void Notepad_plus::setUniModeText()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Notepad_plus::addHotSpot()
|
void Notepad_plus::addHotSpot(ScintillaEditView* view)
|
||||||
{
|
{
|
||||||
|
ScintillaEditView* pView = view ? view : _pEditView;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
int startPos = 0;
|
int startPos = 0;
|
||||||
int endPos = -1;
|
int endPos = -1;
|
||||||
auto endStyle = _pEditView->execute(SCI_GETENDSTYLED);
|
pView->getVisibleStartAndEndPosition(&startPos, &endPos);
|
||||||
|
if (startPos >= endPos) return;
|
||||||
|
pView->execute(SCI_SETINDICATORCURRENT, URL_INDIC);
|
||||||
|
pView->execute(SCI_INDICATORCLEARRANGE, startPos, endPos - startPos);
|
||||||
|
if (!urlAction) return;
|
||||||
|
|
||||||
_pEditView->getVisibleStartAndEndPosition(&startPos, &endPos);
|
pView->execute(SCI_SETSEARCHFLAGS, SCFIND_REGEXP|SCFIND_POSIX);
|
||||||
|
pView->execute(SCI_SETTARGETRANGE, startPos, endPos);
|
||||||
_pEditView->execute(SCI_SETSEARCHFLAGS, SCFIND_REGEXP|SCFIND_POSIX);
|
int posFound = static_cast<int32_t>(pView->execute(SCI_SEARCHINTARGET, strlen(URL_REG_EXPR), reinterpret_cast<LPARAM>(URL_REG_EXPR)));
|
||||||
|
|
||||||
_pEditView->execute(SCI_SETTARGETRANGE, startPos, endPos);
|
|
||||||
|
|
||||||
std::vector<unsigned char> 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
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
|
|
||||||
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 posFound = static_cast<int32_t>(_pEditView->execute(SCI_SEARCHINTARGET, strlen(URL_REG_EXPR), reinterpret_cast<LPARAM>(URL_REG_EXPR)));
|
|
||||||
|
|
||||||
while (posFound != -1 && posFound != -2)
|
while (posFound != -1 && posFound != -2)
|
||||||
{
|
{
|
||||||
int start = int(_pEditView->execute(SCI_GETTARGETSTART));
|
int start = int(pView->execute(SCI_GETTARGETSTART));
|
||||||
int end = int(_pEditView->execute(SCI_GETTARGETEND));
|
int end = int(pView->execute(SCI_GETTARGETEND));
|
||||||
int foundTextLen = end - start;
|
int foundTextLen = end - start;
|
||||||
unsigned char idStyle = static_cast<unsigned char>(_pEditView->execute(SCI_GETSTYLEAT, posFound));
|
pView->execute(SCI_SETINDICATORCURRENT, URL_INDIC);
|
||||||
|
pView->execute(SCI_SETINDICATORVALUE, 0);
|
||||||
// Search the style
|
pView->execute(SCI_INDICATORFILLRANGE, start, foundTextLen);
|
||||||
int fs = -1;
|
pView->execute(SCI_SETTARGETRANGE, posFound + foundTextLen, endPos);
|
||||||
for (size_t i = 0, len = hotspotPairs.size(); i < len ; ++i)
|
posFound = static_cast<int32_t>(pView->execute(SCI_SEARCHINTARGET, strlen(URL_REG_EXPR), reinterpret_cast<LPARAM>(URL_REG_EXPR)));
|
||||||
{
|
|
||||||
// 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<int>(style_hotspot);
|
|
||||||
_pEditView->execute(SCI_STYLEGETFONT, idStyleMSBunset, reinterpret_cast<LPARAM>(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<COLORREF>(_pEditView->execute(SCI_STYLEGETFORE, idStyleMSBunset));
|
|
||||||
hotspotStyle._bgColor = static_cast<COLORREF>(_pEditView->execute(SCI_STYLEGETBACK, idStyleMSBunset));
|
|
||||||
hotspotStyle._fontSize = static_cast<int32_t>(_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<int32_t>(_pEditView->execute(SCI_SEARCHINTARGET, strlen(URL_REG_EXPR), reinterpret_cast<LPARAM>(URL_REG_EXPR)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_pEditView->execute(SCI_STARTSTYLING, endStyle, 0xFF);
|
|
||||||
_pEditView->execute(SCI_SETSTYLING, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Notepad_plus::isConditionExprLine(int lineNumber)
|
bool Notepad_plus::isConditionExprLine(int lineNumber)
|
||||||
|
@ -62,6 +62,7 @@
|
|||||||
#define TOOLBAR 0x02
|
#define TOOLBAR 0x02
|
||||||
|
|
||||||
#define URL_REG_EXPR "[A-Za-z]+://[A-Za-z0-9_\\-\\+~.:?&@=/%#,;\\{\\}\\(\\)\\[\\]\\|\\*\\!\\\\]+"
|
#define URL_REG_EXPR "[A-Za-z]+://[A-Za-z0-9_\\-\\+~.:?&@=/%#,;\\{\\}\\(\\)\\[\\]\\|\\*\\!\\\\]+"
|
||||||
|
#define URL_INDIC 8
|
||||||
|
|
||||||
enum FileTransferMode {
|
enum FileTransferMode {
|
||||||
TransferClone = 0x01,
|
TransferClone = 0x01,
|
||||||
@ -496,7 +497,7 @@ private:
|
|||||||
int findMachedBracePos(size_t startPos, size_t endPos, char targetSymbol, char matchedSymbol);
|
int findMachedBracePos(size_t startPos, size_t endPos, char targetSymbol, char matchedSymbol);
|
||||||
void maintainIndentation(TCHAR ch);
|
void maintainIndentation(TCHAR ch);
|
||||||
|
|
||||||
void addHotSpot();
|
void addHotSpot(ScintillaEditView* view = NULL);
|
||||||
|
|
||||||
void bookmarkAdd(int lineno) const
|
void bookmarkAdd(int lineno) const
|
||||||
{
|
{
|
||||||
|
@ -2448,6 +2448,12 @@ LRESULT Notepad_plus::process(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case NPPM_INTERNAL_UPDATECLICKABLELINKS:
|
||||||
|
{
|
||||||
|
addHotSpot(_pEditView);
|
||||||
|
addHotSpot(_pNonEditView);
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
if (message == WDN_NOTIFY)
|
if (message == WDN_NOTIFY)
|
||||||
|
@ -611,9 +611,7 @@ BOOL Notepad_plus::notify(SCNotification *notification)
|
|||||||
|
|
||||||
if (!_isFolding)
|
if (!_isFolding)
|
||||||
{
|
{
|
||||||
int urlAction = (NppParameters::getInstance()).getNppGUI()._styleURL;
|
addHotSpot();
|
||||||
if ((urlAction == 1) || (urlAction == 2))
|
|
||||||
addHotSpot();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_pDocMap)
|
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<size_t>(startPos), static_cast<size_t>(endPos));
|
||||||
|
::ShellExecute(_pPublicInterface->getHSelf(), TEXT("open"), url.c_str(), NULL, NULL, SW_SHOW);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -804,9 +817,7 @@ BOOL Notepad_plus::notify(SCNotification *notification)
|
|||||||
// replacement for obsolete custom SCN_SCROLLED
|
// replacement for obsolete custom SCN_SCROLLED
|
||||||
if (notification->updated & SC_UPDATE_V_SCROLL)
|
if (notification->updated & SC_UPDATE_V_SCROLL)
|
||||||
{
|
{
|
||||||
int urlAction = (NppParameters::getInstance()).getNppGUI()._styleURL;
|
addHotSpot();
|
||||||
if ((urlAction == 1) || (urlAction == 2))
|
|
||||||
addHotSpot();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if it's searching/replacing, then do nothing
|
// 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 it's searching/replacing, then do nothing
|
||||||
if ((_linkTriggered && !nppParam._isFindReplacing) || notification->wParam == LINKTRIGGERED)
|
if ((_linkTriggered && !nppParam._isFindReplacing) || notification->wParam == LINKTRIGGERED)
|
||||||
{
|
{
|
||||||
int urlAction = (NppParameters::getInstance()).getNppGUI()._styleURL;
|
addHotSpot();
|
||||||
if ((urlAction == 1) || (urlAction == 2))
|
|
||||||
addHotSpot();
|
|
||||||
_linkTriggered = false;
|
_linkTriggered = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -987,42 +996,6 @@ BOOL Notepad_plus::notify(SCNotification *notification)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SCN_HOTSPOTDOUBLECLICK:
|
|
||||||
{
|
|
||||||
if (not notifyView)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
// Get the style and make sure it is a hotspot
|
|
||||||
uint8_t style = static_cast<uint8_t>(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<uint8_t>(notifyView->execute(SCI_GETSTYLEAT, static_cast<WPARAM>(startPos - 1))) == style)
|
|
||||||
startPos--;
|
|
||||||
while (endPos < docLen && static_cast<uint8_t>(notifyView->execute(SCI_GETSTYLEAT, static_cast<WPARAM>(endPos))) == style)
|
|
||||||
endPos++;
|
|
||||||
|
|
||||||
// Select the entire link
|
|
||||||
notifyView->execute(SCI_SETANCHOR, static_cast<WPARAM>(startPos));
|
|
||||||
notifyView->execute(SCI_SETCURRENTPOS, static_cast<WPARAM>(endPos));
|
|
||||||
|
|
||||||
generic_string url = notifyView->getGenericTextAsString(static_cast<size_t>(startPos), static_cast<size_t>(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:
|
case SCN_NEEDSHOWN:
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
|
@ -1004,6 +1004,8 @@ INT_PTR CALLBACK SettingsDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM)
|
|||||||
::EnableWindow(::GetDlgItem(_hSelf, IDC_CHECK_CLICKABLELINK_NOUNDERLINE), isChecked);
|
::EnableWindow(::GetDlgItem(_hSelf, IDC_CHECK_CLICKABLELINK_NOUNDERLINE), isChecked);
|
||||||
|
|
||||||
nppGUI._styleURL = isChecked?2:0;
|
nppGUI._styleURL = isChecked?2:0;
|
||||||
|
HWND grandParent = ::GetParent(_hParent);
|
||||||
|
::SendMessage(grandParent, NPPM_INTERNAL_UPDATECLICKABLELINKS, 0, 0);
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
@ -1011,6 +1013,8 @@ INT_PTR CALLBACK SettingsDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM)
|
|||||||
{
|
{
|
||||||
bool isChecked = isCheckedOrNot(IDC_CHECK_CLICKABLELINK_NOUNDERLINE);
|
bool isChecked = isCheckedOrNot(IDC_CHECK_CLICKABLELINK_NOUNDERLINE);
|
||||||
nppGUI._styleURL = isChecked?1:2;
|
nppGUI._styleURL = isChecked?1:2;
|
||||||
|
HWND grandParent = ::GetParent(_hParent);
|
||||||
|
::SendMessage(grandParent, NPPM_INTERNAL_UPDATECLICKABLELINKS, 0, 0);
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
@ -443,8 +443,8 @@
|
|||||||
#define NPPM_INTERNAL_STOPMONITORING (NOTEPADPLUS_USER_INTERNAL + 49) // Used by Monitoring feature
|
#define NPPM_INTERNAL_STOPMONITORING (NOTEPADPLUS_USER_INTERNAL + 49) // Used by Monitoring feature
|
||||||
#define NPPM_INTERNAL_EDGEBACKGROUND (NOTEPADPLUS_USER_INTERNAL + 50)
|
#define NPPM_INTERNAL_EDGEBACKGROUND (NOTEPADPLUS_USER_INTERNAL + 50)
|
||||||
#define NPPM_INTERNAL_EDGEMULTISETSIZE (NOTEPADPLUS_USER_INTERNAL + 51)
|
#define NPPM_INTERNAL_EDGEMULTISETSIZE (NOTEPADPLUS_USER_INTERNAL + 51)
|
||||||
//wParam: 0
|
#define NPPM_INTERNAL_UPDATECLICKABLELINKS (NOTEPADPLUS_USER_INTERNAL + 52)
|
||||||
//lParam: document new index
|
|
||||||
// See Notepad_plus_msgs.h
|
// See Notepad_plus_msgs.h
|
||||||
//#define NOTEPADPLUS_USER (WM_USER + 1000)
|
//#define NOTEPADPLUS_USER (WM_USER + 1000)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user