Add Notepad++ compatible versions in plugin list

Implement: https://github.com/notepad-plus-plus/nppPluginList/issues/416

While PluginAdmin loading nppPluginList.dll, it will check an attribute "npp-compatible-versions" (optional),
in order to determinate if plugin is compatible to the current version of Notepad++. If plugin is not compatible,
then this plugin will be ignored, therefore it won't be shown on the PluginAdmin's plugin list.
Note that it's only about pluginsAdmin's plugin list:
it prevent from Notepad++ install/update a plugin non-compatible to current version of Notepad++,
but it still allows Notepad++ load this plugin in question, if it's already installed.

Here is the attribite "npp-compatible-versions" looks like in plugin list json file:
```
{
	"name": "npp-pluginList",
	"version": "1.4.7",
	"arch": "32",
	"npp-plugins": [
		{
			"folder-name": "demoPluginA",
			"display-name": "Demo Plugin A",
			"version": "1.8.7",
			"npp-compatible-versions": "[4.2,6.6.6]",
			"id": "9c566a9083ef66a0ce93a3ce5f55977faea559b5b0993e37a1461b87f4aeb6f0",
			...
		},
		{
			"folder-name": "demoPluginB",
			"display-name": "Demo Plugin B",
			"version": "1.1.8.7",
			"id": "8a6b9dadbf2ec37d5c60a12a5445f0eec2ef00e6eaa80452925789fd73950193",
			...
		},
		...
	}
}
```
It's optional. In the case of its absence, it's considered compatible to all versions of Notepad++.
The format of value for "npp-compatible-versions" is following (no white space is allowed):

"6.9"          : exact version 6.9
"[4.2,6.6.6]"  : from version 4.2 to 6.6.6 inclusive
"[8.3,]"       : any version from 8.3 to the latest one
"[,8.2.1]"     : 8.2.1 and any previous version

Fix #11338, close #11334
pull/11352/head
Don Ho 3 years ago
parent 0affe35bc6
commit a06b404708

@ -7214,6 +7214,10 @@ static const QuoteParams quotes[] =
{TEXT("Anonymous #181"), QuoteParams::rapid, false, SC_CP_UTF8, L_TEXT, TEXT("I met a magical Genie. He gave me one wish.\nI said: \"I wish I could be you.\"\nThe Genue saud: \"Weurd wush but U wull grant ut.\"\n") }, {TEXT("Anonymous #181"), QuoteParams::rapid, false, SC_CP_UTF8, L_TEXT, TEXT("I met a magical Genie. He gave me one wish.\nI said: \"I wish I could be you.\"\nThe Genue saud: \"Weurd wush but U wull grant ut.\"\n") },
{TEXT("Anonymous #182"), QuoteParams::slow, false, SC_CP_UTF8, L_CPP, TEXT("printf(\"%s%s\", \"\\\\o/\\n| |\\n| |8=\", \"=D\\n/ \\\\\\n\");\n") }, {TEXT("Anonymous #182"), QuoteParams::slow, false, SC_CP_UTF8, L_CPP, TEXT("printf(\"%s%s\", \"\\\\o/\\n| |\\n| |8=\", \"=D\\n/ \\\\\\n\");\n") },
{TEXT("Anonymous #183"), QuoteParams::rapid, false, SC_CP_UTF8, L_TEXT, TEXT("Dear Optimist, Pessimist and Realist,\n\nWhile you guys were busy arguing about\nthe glass of water, I drank it!\n\n\n Sincerely,\n The Opportunist\n") }, {TEXT("Anonymous #183"), QuoteParams::rapid, false, SC_CP_UTF8, L_TEXT, TEXT("Dear Optimist, Pessimist and Realist,\n\nWhile you guys were busy arguing about\nthe glass of water, I drank it!\n\n\n Sincerely,\n The Opportunist\n") },
{TEXT("Anonymous #184"), QuoteParams::slow, false, SC_CP_UTF8, L_TEXT, TEXT("Dance like nobody's watching.\nEncrypt like everyone is.\n") },
{TEXT("Anonymous #185"), QuoteParams::rapid, false, SC_CP_UTF8, L_TEXT, TEXT("Me: \"I'm 45 years old but I've got a 19 year-old young man's body\"\nHer: \"Show me\"\nI opened the freezer to show her the body.\nShe screamed.\nMe too.\n") },
{TEXT("Anonymous #186"), QuoteParams::slow, false, SC_CP_UTF8, L_TEXT, TEXT("Everyone complains about the weather,\nbut no one wants to sacrifice a virgin to change it.\n") },
{TEXT("Anonymous #187"), QuoteParams::rapid, false, SC_CP_UTF8, L_TEXT, TEXT("If you are alone at home and feel lonely:\nTurn off the lights, turn on the TV and watch a horror movie.\nThen you will have feeling that there are someone hidden in the kitchen, in the toilet\nand even under your bed.\n") },
{TEXT("xkcd"), QuoteParams::rapid, false, SC_CP_UTF8, L_TEXT, TEXT("Never have I felt so close to another soul\nAnd yet so helplessly alone\nAs when I Google an error\nAnd there's one result\nA thread by someone with the same problem\nAnd no answer\nLast posted to in 2003\n\n\"Who were you, DenverCoder9?\"\n\"What did you see?!\"\n\n(ref: https://xkcd.com/979/)") }, {TEXT("xkcd"), QuoteParams::rapid, false, SC_CP_UTF8, L_TEXT, TEXT("Never have I felt so close to another soul\nAnd yet so helplessly alone\nAs when I Google an error\nAnd there's one result\nA thread by someone with the same problem\nAnd no answer\nLast posted to in 2003\n\n\"Who were you, DenverCoder9?\"\n\"What did you see?!\"\n\n(ref: https://xkcd.com/979/)") },
{TEXT("A developer"), QuoteParams::slow, false, SC_CP_UTF8, L_TEXT, TEXT("No hugs & kisses.\nOnly bugs & fixes.") }, {TEXT("A developer"), QuoteParams::slow, false, SC_CP_UTF8, L_TEXT, TEXT("No hugs & kisses.\nOnly bugs & fixes.") },
{TEXT("Elon Musk"), QuoteParams::rapid, false, SC_CP_UTF8, L_TEXT, TEXT("Don't set your password as your child's name.\nName your child after your password.") }, {TEXT("Elon Musk"), QuoteParams::rapid, false, SC_CP_UTF8, L_TEXT, TEXT("Don't set your password as your child's name.\nName your child after your password.") },

@ -705,6 +705,31 @@ void cutString(const TCHAR* str2cut, vector<generic_string>& patternVect)
patternVect.emplace_back(pBegin, pEnd); patternVect.emplace_back(pBegin, pEnd);
} }
void cutStringBy(const TCHAR* str2cut, vector<generic_string>& patternVect, char byChar, bool allowEmptyStr)
{
if (str2cut == nullptr) return;
const TCHAR* pBegin = str2cut;
const TCHAR* pEnd = pBegin;
while (*pEnd != '\0')
{
if (*pEnd == byChar)
{
if (allowEmptyStr)
patternVect.emplace_back(pBegin, pEnd);
else if (pBegin != pEnd)
patternVect.emplace_back(pBegin, pEnd);
pBegin = pEnd + 1;
}
++pEnd;
}
if (allowEmptyStr)
patternVect.emplace_back(pBegin, pEnd);
else if (pBegin != pEnd)
patternVect.emplace_back(pBegin, pEnd);
}
std::wstring LocalizationSwitcher::getLangFromXmlFileName(const wchar_t *fn) const std::wstring LocalizationSwitcher::getLangFromXmlFileName(const wchar_t *fn) const
{ {

@ -139,6 +139,7 @@ const TCHAR nppLogNetworkDriveIssue[] = TEXT("nppLogNetworkDriveIssue");
const TCHAR nppLogNulContentCorruptionIssue[] = TEXT("nppLogNulContentCorruptionIssue"); const TCHAR nppLogNulContentCorruptionIssue[] = TEXT("nppLogNulContentCorruptionIssue");
void cutString(const TCHAR *str2cut, std::vector<generic_string> & patternVect); void cutString(const TCHAR *str2cut, std::vector<generic_string> & patternVect);
void cutStringBy(const TCHAR *str2cut, std::vector<generic_string> & patternVect, char byChar, bool allowEmptyStr);
struct Position struct Position

@ -1553,7 +1553,7 @@ bool FileManager::loadFileData(Document doc, int64_t fileSize, const TCHAR * fil
switch (sciStatus) switch (sciStatus)
{ {
case SC_STATUS_OK: case SC_STATUS_OK:
// either the Scintilla not catched this exception or the error is in the N++ code, report the exception anyway // either the Scintilla doesn't catch this exception or the error is in the Notepad++ code, report the exception anyway
#if defined(__GNUC__) #if defined(__GNUC__)
// there is the std::current_exception() possibility, but getting the real exception code from there requires an ugly hack, // there is the std::current_exception() possibility, but getting the real exception code from there requires an ugly hack,
// because of the std::exception_ptr has its members _Data1 (GetExceptionCode) and _Data2 (GetExceptionInformation) private // because of the std::exception_ptr has its members _Data1 (GetExceptionCode) and _Data2 (GetExceptionInformation) private

@ -41,7 +41,7 @@ Version::Version(const generic_string& versionStr)
auto ss = tokenizeString(versionStr, '.'); auto ss = tokenizeString(versionStr, '.');
if (ss.size() > 4) if (ss.size() > 4)
throw generic_string(TEXT("The string to parse is not a valid version format. Let's make it default value in catch block.")); throw wstring(TEXT("Version parts are more than 4. The string to parse is not a valid version format. Let's make it default value in catch block."));
int i = 0; int i = 0;
vector<unsigned long*> v = {&_major, &_minor, &_patch, &_build}; vector<unsigned long*> v = {&_major, &_minor, &_patch, &_build};
@ -49,19 +49,33 @@ Version::Version(const generic_string& versionStr)
{ {
if (!isNumber(s)) if (!isNumber(s))
{ {
throw generic_string(TEXT("The string to parse is not a valid version format. Let's make it default value in catch block.")); throw wstring(TEXT("One of version character is not number. The string to parse is not a valid version format. Let's make it default value in catch block."));
} }
*(v[i]) = std::stoi(s); *(v[i]) = std::stoi(s);
++i; ++i;
} }
} }
#ifdef DEBUG
catch (const wstring& s)
{
_major = 0;
_minor = 0;
_patch = 0;
_build = 0;
throw s;
}
#endif
catch (...) catch (...)
{ {
_major = 0; _major = 0;
_minor = 0; _minor = 0;
_patch = 0; _patch = 0;
_build = 0; _build = 0;
#ifdef DEBUG
throw wstring(TEXT("Unknown exception from \"Version::Version(const generic_string& versionStr)\""));
#endif
} }
} }
@ -636,6 +650,56 @@ void PluginViewList::pushBack(PluginUpdateInfo* pi)
_ui.addLine(values2Add, reinterpret_cast<LPARAM>(pi), static_cast<int>(i)); _ui.addLine(values2Add, reinterpret_cast<LPARAM>(pi), static_cast<int>(i));
} }
// intervalVerStr format:
//
// "6.9" : exact version 6.9
// "[4.2,6.6.6]" : from version 4.2 to 6.6.6 inclusive
// "[8.3,]" : any version from 8.3 to the latest one
// "[,8.2.1]" : 8.2.1 and any previous version
//
std::pair<Version, Version> getIntervalVersions(generic_string intervalVerStr)
{
std::pair<Version, Version> result;
if (intervalVerStr.empty())
return result;
const size_t indexEnd = intervalVerStr.length() - 1;
if (intervalVerStr[0] == '[' && intervalVerStr[indexEnd] == ']') // interval versions format
{
generic_string cleanIntervalVerStr = intervalVerStr.substr(1, indexEnd - 1);
vector<generic_string> versionVect;
cutStringBy(cleanIntervalVerStr.c_str(), versionVect, ',', true);
if (versionVect.size() == 2)
{
if (!versionVect[0].empty() && !versionVect[1].empty()) // "[4.2,6.6.6]" : from version 4.2 to 6.6.6 inclusive
{
result.first = Version(versionVect[0]);
result.second = Version(versionVect[1]);
}
else if (!versionVect[0].empty() && versionVect[1].empty()) // "[8.3,]" : any version from 8.3 to the latest one
{
result.first = Version(versionVect[0]);
}
else if (versionVect[0].empty() && !versionVect[1].empty()) // "[,8.2.1]" : 8.2.1 and any previous version
{
result.second = Version(versionVect[1]);
}
}
}
else if (intervalVerStr[0] != '[' && intervalVerStr[indexEnd] != ']') // one version format -> "6.9" : exact version 6.9
{
result.first = Version(intervalVerStr);
result.second = Version(intervalVerStr);
}
else // invalid format
{
// do nothing
}
return result;
}
bool loadFromJson(PluginViewList & pl, const json& j) bool loadFromJson(PluginViewList & pl, const json& j)
{ {
if (j.empty()) if (j.empty())
@ -650,7 +714,65 @@ bool loadFromJson(PluginViewList & pl, const json& j)
for (const auto& i : jArray) for (const auto& i : jArray)
{ {
try { try {
//std::unique_ptr<PluginUpdateInfo*> pi = make_unique<PluginUpdateInfo*>();
// Optional
std::pair<Version, Version> _nppCompatibleVersions; // compatible to Notepad++ interval versions: <from, to> example:
// <0.0.0.0, 0.0.0.0>: plugin is compatible to all Notepad++ versions (due to invalid format set)
// <6.9, 6.9>: plugin is compatible to only v6.9
// <4.2, 6.6.6>: from v4.2 (included) to v6.6.6 (included)
// <0.0.0.0, 8.2.1> all until v8.2.1 (included)
// <8.3, 0.0.0.0> from v8.3 (included) to all
if (i.contains("npp-compatible-versions"))
{
json jNppCompatibleVer = i["npp-compatible-versions"];
string versionsStr = jNppCompatibleVer.get<std::string>();
generic_string nppCompatibleVersionStr(versionsStr.begin(), versionsStr.end());
std::pair<Version, Version> nppCompatibleVersions = getIntervalVersions(nppCompatibleVersionStr);
// nppCompatibleVersions contains compatibilty to Notepad++ versions <from, to> example:
// <0.0.0.0, 0.0.0.0>: plugin is compatible to all Notepad++ versions
// <6.9, 6.9>: plugin is compatible to only v6.9
// <4.2, 6.6.6>: from v4.2 (included) to v6.6.6 (included)
// <0.0.0.0, 8.2.1>: all version until v8.2.1 (included)
// <8.3, 0.0.0.0>: from v8.3 (included) to the latest verrsion
if (nppCompatibleVersions.first == nppCompatibleVersions.second && nppCompatibleVersions.first.empty()) // compatible versions not set
// 1 case is processed:
// <0.0.0.0, 0.0.0.0>: plugin is compatible to all Notepad++ versions
{
// OK - do nothing
}
else
{
TCHAR nppFullPathName[MAX_PATH];
GetModuleFileName(NULL, nppFullPathName, MAX_PATH);
Version nppVer;
nppVer.setVersionFrom(nppFullPathName);
if (nppCompatibleVersions.first <= nppVer && nppCompatibleVersions.second >= nppVer) // from <= npp <= to
// 3 cases are processed:
// <6.9, 6.9>: plugin is compatible to only v6.9
// <4.2, 6.6.6>: from v4.2 (included) to v6.6.6 (included)
// <0.0.0.0, 8.2.1>: all versions until v8.2.1 (included)
{
// OK - do nothing
}
else if (nppCompatibleVersions.first <= nppVer && nppCompatibleVersions.second.empty()) // from <= npp <= to
// 1 case is processed:
// <8.3, 0.0.0.0>: from v8.3 (included) to the latest version
{
// OK - do nothing
}
else // Not compatible to Notepad++ current version
{
// Not OK - skip this plugin
continue;
}
}
}
PluginUpdateInfo* pi = new PluginUpdateInfo(); PluginUpdateInfo* pi = new PluginUpdateInfo();
string valStr = i.at("folder-name").get<std::string>(); string valStr = i.at("folder-name").get<std::string>();
@ -681,8 +803,24 @@ bool loadFromJson(PluginViewList & pl, const json& j)
pl.pushBack(pi); pl.pushBack(pi);
} }
catch (...) // Every field is mandatory. If one of property is missing, an exception is thrown then this plugin will be ignored #ifdef DEBUG
catch (const wstring& s)
{
::MessageBox(NULL, s.c_str(), TEXT("Exception caught in: PluginsAdmin loadFromJson()"), MB_ICONERROR);
continue;
}
catch (std::exception& e)
{ {
::MessageBoxA(NULL, e.what(), "Exception caught in: PluginsAdmin loadFromJson()", MB_ICONERROR);
continue;
}
#endif
catch (...) // If one of mandatory properties is missing or with the incorrect format, an exception is thrown then this plugin will be ignored
{
#ifdef DEBUG
::MessageBoxA(NULL, "An unknown exception is just caught", "Unknown Exception", MB_OK);
#endif
continue; continue;
} }
} }

@ -49,10 +49,20 @@ struct Version
return compareTo(v2c) == -1; return compareTo(v2c) == -1;
}; };
bool operator <= (const Version& v2c) const {
int r = compareTo(v2c);
return r == -1 || r == 0;
};
bool operator > (const Version& v2c) const { bool operator > (const Version& v2c) const {
return compareTo(v2c) == 1; return compareTo(v2c) == 1;
}; };
bool operator >= (const Version& v2c) const {
int r = compareTo(v2c);
return r == 1 || r == 0;
};
bool operator == (const Version& v2c) const { bool operator == (const Version& v2c) const {
return compareTo(v2c) == 0; return compareTo(v2c) == 0;
}; };
@ -60,6 +70,10 @@ struct Version
bool operator != (const Version& v2c) const { bool operator != (const Version& v2c) const {
return compareTo(v2c) != 0; return compareTo(v2c) != 0;
}; };
bool empty() const {
return _major == 0 && _minor == 0 && _patch == 0 && _build == 0;
}
}; };
struct PluginUpdateInfo struct PluginUpdateInfo

Loading…
Cancel
Save