Skip to content

Commit

Permalink
Fix clickable links break syntax highlighting issue
Browse files Browse the repository at this point in the history
By using indicators instead of stylers to make code shorter and cleaner.

Fix #999, close #8263
  • Loading branch information
Uhf7 authored and donho committed May 15, 2020
1 parent 9f29015 commit 4738c96
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 157 deletions.
131 changes: 23 additions & 108 deletions PowerEditor/src/Notepad_plus.cpp
Expand Up @@ -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<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
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<int32_t>(_pEditView->execute(SCI_SEARCHINTARGET, strlen(URL_REG_EXPR), reinterpret_cast<LPARAM>(URL_REG_EXPR)));
pView->execute(SCI_SETSEARCHFLAGS, SCFIND_REGEXP|SCFIND_POSIX);
pView->execute(SCI_SETTARGETRANGE, startPos, endPos);
int posFound = static_cast<int32_t>(pView->execute(SCI_SEARCHINTARGET, strlen(URL_REG_EXPR), reinterpret_cast<LPARAM>(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<unsigned char>(_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<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)));
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<int32_t>(pView->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)
Expand Down
3 changes: 2 additions & 1 deletion PowerEditor/src/Notepad_plus.h
Expand Up @@ -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,
Expand Down Expand Up @@ -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
{
Expand Down
6 changes: 6 additions & 0 deletions PowerEditor/src/NppBigSwitch.cpp
Expand Up @@ -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)
Expand Down
65 changes: 19 additions & 46 deletions PowerEditor/src/NppNotification.cpp
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}

Expand All @@ -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
Expand Down Expand Up @@ -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;
}

Expand All @@ -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<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:
{
break;
Expand Down
4 changes: 4 additions & 0 deletions PowerEditor/src/WinControls/Preference/preferenceDlg.cpp
Expand Up @@ -1004,13 +1004,17 @@ 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;

case IDC_CHECK_CLICKABLELINK_NOUNDERLINE:
{
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;

Expand Down
4 changes: 2 additions & 2 deletions PowerEditor/src/resource.h
Expand Up @@ -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)

Expand Down

0 comments on commit 4738c96

Please sign in to comment.