mirror of
https://github.com/notepad-plus-plus/notepad-plus-plus.git
synced 2025-07-23 13:54:54 +02:00
Fix case sensitivity bug in Calltips
Single existing file on commandline will not be interpreted but opened directly git-svn-id: svn://svn.tuxfamily.org/svnroot/notepadplus/repository@253 f5eea248-9336-0410-98b8-ebc06183d4e3
This commit is contained in:
parent
4c138a5518
commit
ec66a22890
@ -249,13 +249,16 @@ bool AutoCompletion::setLanguage(LangType language) {
|
|||||||
_funcCalltip._stop = ')';
|
_funcCalltip._stop = ')';
|
||||||
_funcCalltip._param = ',';
|
_funcCalltip._param = ',';
|
||||||
_funcCalltip._terminal = ';';
|
_funcCalltip._terminal = ';';
|
||||||
|
_funcCalltip._ignoreCase = true;
|
||||||
|
|
||||||
TiXmlElement * pElem = pAutoNode->FirstChildElement("Environment");
|
TiXmlElement * pElem = pAutoNode->FirstChildElement("Environment");
|
||||||
if (pElem) {
|
if (pElem) {
|
||||||
const char * val = 0;
|
const char * val = 0;
|
||||||
val = pElem->Attribute("ignoreCase");
|
val = pElem->Attribute("ignoreCase");
|
||||||
if (val && !strcmp(val, "no"))
|
if (val && !strcmp(val, "no")) {
|
||||||
_ignoreCase = false;
|
_ignoreCase = false;
|
||||||
|
_funcCalltip._ignoreCase = false;
|
||||||
|
}
|
||||||
val = pElem->Attribute("startFunc");
|
val = pElem->Attribute("startFunc");
|
||||||
if (val && val[0])
|
if (val && val[0])
|
||||||
_funcCalltip._start = val[0];
|
_funcCalltip._start = val[0];
|
||||||
|
@ -33,15 +33,38 @@ struct FunctionValues {
|
|||||||
FunctionValues() : lastIdentifier(-1), lastFunctionIdentifier(-1), param(0), scopeLevel(-1) {};
|
FunctionValues() : lastIdentifier(-1), lastFunctionIdentifier(-1), param(0), scopeLevel(-1) {};
|
||||||
};
|
};
|
||||||
|
|
||||||
bool stringEqualN(const char * first, const char * second, int n) {
|
inline bool lower(char c) {
|
||||||
int i = 0;
|
return (c >= 'a' && c <= 'z');
|
||||||
while(i < n) { //no checks for 0 as n has to take that into account (if one string is shorter, no overflow as 0 doesnt equal anything
|
}
|
||||||
if (first[i] != second[i])
|
|
||||||
|
inline bool match(char c1, char c2) {
|
||||||
|
if (c1 == c2) return true;
|
||||||
|
if (lower(c1))
|
||||||
|
return ((c1-32) == c2);
|
||||||
|
if (lower(c2))
|
||||||
|
return ((c2-32) == c1);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//test string case insensitive ala Scintilla
|
||||||
|
//0 if equal, <0 of before, >0 if after (name1 that is)
|
||||||
|
int testNameNoCase(const char * name1, const char * name2, int len = -1) {
|
||||||
|
if (len == -1) {
|
||||||
|
len = 1024; //magic value, but it probably fails way before it reaches this
|
||||||
|
}
|
||||||
|
int i = 0;
|
||||||
|
while(match(name1[i], name2[i])) {
|
||||||
|
if (name1[i] == 0 || i == len) {
|
||||||
|
return 0; //equal
|
||||||
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
};
|
int subs1 = lower(name1[i])?32:0;
|
||||||
|
int subs2 = lower(name2[i])?32:0;
|
||||||
|
|
||||||
|
return ( (name1[i]-subs1) - (name2[i]-subs2) );
|
||||||
|
}
|
||||||
|
|
||||||
void FunctionCallTip::setLanguageXML(TiXmlElement * pXmlKeyword) {
|
void FunctionCallTip::setLanguageXML(TiXmlElement * pXmlKeyword) {
|
||||||
if (isVisible())
|
if (isVisible())
|
||||||
@ -186,17 +209,22 @@ bool FunctionCallTip::getCursorFunction() {
|
|||||||
funcToken.token[funcToken.length] = 0;
|
funcToken.token[funcToken.length] = 0;
|
||||||
_currentParam = curValue.param;
|
_currentParam = curValue.param;
|
||||||
|
|
||||||
if (!_funcName || !stringEqualN(_funcName, funcToken.token, strlen(_funcName))) { //check if we need to reload data
|
bool same = false;
|
||||||
res = loadFunction(funcToken.token);
|
if (_funcName) {
|
||||||
} else {
|
if(_ignoreCase)
|
||||||
res = true;
|
same = testNameNoCase(_funcName, funcToken.token, strlen(_funcName)) == 0;
|
||||||
|
else
|
||||||
|
same = strncmp(_funcName, funcToken.token, strlen(_funcName)) == 0;
|
||||||
}
|
}
|
||||||
}
|
if (!same) { //check if we need to reload data
|
||||||
if (!res) {
|
|
||||||
reset();
|
|
||||||
if (_funcName) {
|
if (_funcName) {
|
||||||
delete [] _funcName;
|
delete [] _funcName;
|
||||||
_funcName = 0;
|
}
|
||||||
|
_funcName = new char[funcToken.length+1];
|
||||||
|
strcpy(_funcName, funcToken.token);
|
||||||
|
res = loadFunction();
|
||||||
|
} else {
|
||||||
|
res = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete [] lineData;
|
delete [] lineData;
|
||||||
@ -206,8 +234,8 @@ bool FunctionCallTip::getCursorFunction() {
|
|||||||
/*
|
/*
|
||||||
Find function in XML structure and parse it
|
Find function in XML structure and parse it
|
||||||
*/
|
*/
|
||||||
|
bool FunctionCallTip::loadFunction() {
|
||||||
bool FunctionCallTip::loadFunction(const char * nameToFind) {
|
reset(); //set everything back to 0
|
||||||
//The functions should be ordered, but linear search because we cant access like array
|
//The functions should be ordered, but linear search because we cant access like array
|
||||||
_curFunction = NULL;
|
_curFunction = NULL;
|
||||||
//Iterate through all keywords and find the correct function keyword
|
//Iterate through all keywords and find the correct function keyword
|
||||||
@ -217,7 +245,11 @@ bool FunctionCallTip::loadFunction(const char * nameToFind) {
|
|||||||
name = funcNode->Attribute("name");
|
name = funcNode->Attribute("name");
|
||||||
if (!name) //malformed node
|
if (!name) //malformed node
|
||||||
continue;
|
continue;
|
||||||
int compVal = strcmp(name, nameToFind);
|
int compVal = 0;
|
||||||
|
if (_ignoreCase)
|
||||||
|
compVal = testNameNoCase(name, _funcName); //strcmpi doesnt work in this case
|
||||||
|
else
|
||||||
|
compVal = strcmp(name, _funcName);
|
||||||
if (!compVal) { //found it?
|
if (!compVal) { //found it?
|
||||||
const char * val = funcNode->Attribute("func");
|
const char * val = funcNode->Attribute("func");
|
||||||
if (val)
|
if (val)
|
||||||
@ -240,12 +272,6 @@ bool FunctionCallTip::loadFunction(const char * nameToFind) {
|
|||||||
if (!_curFunction)
|
if (!_curFunction)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_funcName = name;
|
|
||||||
if (!_funcName) //this should not happen
|
|
||||||
return false;
|
|
||||||
|
|
||||||
_retVals.clear();
|
|
||||||
_overloads.clear();
|
|
||||||
stringVec paramVec;
|
stringVec paramVec;
|
||||||
|
|
||||||
TiXmlElement *overloadNode = _curFunction->FirstChildElement("Overload");
|
TiXmlElement *overloadNode = _curFunction->FirstChildElement("Overload");
|
||||||
@ -255,6 +281,13 @@ bool FunctionCallTip::loadFunction(const char * nameToFind) {
|
|||||||
if (!retVal)
|
if (!retVal)
|
||||||
continue; //malformed node
|
continue; //malformed node
|
||||||
_retVals.push_back(retVal);
|
_retVals.push_back(retVal);
|
||||||
|
|
||||||
|
const char * description = overloadNode->Attribute("descr");
|
||||||
|
if (description)
|
||||||
|
_descriptions.push_back(description);
|
||||||
|
else
|
||||||
|
_descriptions.push_back(""); //"no description available"
|
||||||
|
|
||||||
paramNode = overloadNode->FirstChildElement("Param");
|
paramNode = overloadNode->FirstChildElement("Param");
|
||||||
for (; paramNode ; paramNode = paramNode->NextSiblingElement("Param") ) {
|
for (; paramNode ; paramNode = paramNode->NextSiblingElement("Param") ) {
|
||||||
const char * param = paramNode->Attribute("name");
|
const char * param = paramNode->Attribute("name");
|
||||||
@ -296,8 +329,15 @@ void FunctionCallTip::showCalltip() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const char * curRetValText = _retVals.at(_currentOverload);
|
const char * curRetValText = _retVals.at(_currentOverload);
|
||||||
|
const char * curDescriptionText = _descriptions.at(_currentOverload);
|
||||||
|
bool hasDescr = true;
|
||||||
|
if (!curDescriptionText[0])
|
||||||
|
hasDescr = false;
|
||||||
|
|
||||||
int bytesNeeded = strlen(curRetValText) + strlen(_funcName) + 5;//'retval funcName (params)\0'
|
int bytesNeeded = strlen(curRetValText) + strlen(_funcName) + 5;//'retval funcName (params)\0'
|
||||||
|
if (hasDescr)
|
||||||
|
bytesNeeded += strlen(curDescriptionText);
|
||||||
|
|
||||||
size_t nrParams = params.size();
|
size_t nrParams = params.size();
|
||||||
for(size_t i = 0; i < nrParams; i++) {
|
for(size_t i = 0; i < nrParams; i++) {
|
||||||
bytesNeeded += strlen(params.at(i)) + 2; //'param, '
|
bytesNeeded += strlen(params.at(i)) + 2; //'param, '
|
||||||
@ -332,6 +372,10 @@ void FunctionCallTip::showCalltip() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
strcat(textBuffer, ")");
|
strcat(textBuffer, ")");
|
||||||
|
if (hasDescr) {
|
||||||
|
strcat(textBuffer, "\n");
|
||||||
|
strcat(textBuffer, curDescriptionText);
|
||||||
|
}
|
||||||
|
|
||||||
if (isVisible())
|
if (isVisible())
|
||||||
_pEditView->execute(SCI_CALLTIPCANCEL);
|
_pEditView->execute(SCI_CALLTIPCANCEL);
|
||||||
@ -351,13 +395,16 @@ void FunctionCallTip::reset() {
|
|||||||
_currentParam = 0;
|
_currentParam = 0;
|
||||||
_curPos = 0;
|
_curPos = 0;
|
||||||
_startPos = 0;
|
_startPos = 0;
|
||||||
|
_overloads.clear();
|
||||||
|
_currentNrOverloads = 0;
|
||||||
|
_retVals.clear();
|
||||||
|
_descriptions.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FunctionCallTip::cleanup() {
|
void FunctionCallTip::cleanup() {
|
||||||
reset();
|
reset();
|
||||||
_overloads.clear();
|
if (_funcName)
|
||||||
_currentNrOverloads = 0;
|
delete [] _funcName;
|
||||||
_retVals.clear();
|
|
||||||
_funcName = 0;
|
_funcName = 0;
|
||||||
_pEditView = NULL;
|
_pEditView = NULL;
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ public:
|
|||||||
FunctionCallTip(ScintillaEditView * pEditView) : _pEditView(pEditView), _pXmlKeyword(NULL), _curPos(0), _startPos(0),
|
FunctionCallTip(ScintillaEditView * pEditView) : _pEditView(pEditView), _pXmlKeyword(NULL), _curPos(0), _startPos(0),
|
||||||
_curFunction(NULL), _currentNrOverloads(0), _currentOverload(0),
|
_curFunction(NULL), _currentNrOverloads(0), _currentOverload(0),
|
||||||
_currentParam(0), _funcName(NULL),
|
_currentParam(0), _funcName(NULL),
|
||||||
_start('('), _stop(')'), _param(','), _terminal(';')
|
_start('('), _stop(')'), _param(','), _terminal(';'), _ignoreCase(true)
|
||||||
{};
|
{};
|
||||||
~FunctionCallTip() {/* cleanup(); */};
|
~FunctionCallTip() {/* cleanup(); */};
|
||||||
void setLanguageXML(TiXmlElement * pXmlKeyword); //set calltip keyword node
|
void setLanguageXML(TiXmlElement * pXmlKeyword); //set calltip keyword node
|
||||||
@ -47,9 +47,10 @@ private:
|
|||||||
|
|
||||||
TiXmlElement * _curFunction; //current function element
|
TiXmlElement * _curFunction; //current function element
|
||||||
//cache some XML values n stuff
|
//cache some XML values n stuff
|
||||||
const char * _funcName; //name of function
|
char * _funcName; //name of function
|
||||||
stringVec _retVals; //vector of overload return values/types
|
stringVec _retVals; //vector of overload return values/types
|
||||||
vector<stringVec> _overloads; //vector of overload params (=vector)
|
vector<stringVec> _overloads; //vector of overload params (=vector)
|
||||||
|
stringVec _descriptions; //vecotr of function descriptions
|
||||||
int _currentNrOverloads; //current amount of overloads
|
int _currentNrOverloads; //current amount of overloads
|
||||||
int _currentOverload; //current chosen overload
|
int _currentOverload; //current chosen overload
|
||||||
int _currentParam; //current highlighted param
|
int _currentParam; //current highlighted param
|
||||||
@ -58,9 +59,10 @@ private:
|
|||||||
char _stop;
|
char _stop;
|
||||||
char _param;
|
char _param;
|
||||||
char _terminal;
|
char _terminal;
|
||||||
|
bool _ignoreCase;
|
||||||
|
|
||||||
bool getCursorFunction(); //retrieve data about function at cursor. Returns true if a function was found. Calls loaddata if needed
|
bool getCursorFunction(); //retrieve data about function at cursor. Returns true if a function was found. Calls loaddata if needed
|
||||||
bool loadFunction(const char * nameToFind); //returns true if the function can be found
|
bool loadFunction(); //returns true if the function can be found
|
||||||
void showCalltip(); //display calltip based on current variables
|
void showCalltip(); //display calltip based on current variables
|
||||||
void reset(); //reset all vars in case function is invalidated
|
void reset(); //reset all vars in case function is invalidated
|
||||||
void cleanup(); //delete any leftovers
|
void cleanup(); //delete any leftovers
|
||||||
|
@ -19,11 +19,27 @@
|
|||||||
#include "SysMsg.h"
|
#include "SysMsg.h"
|
||||||
#include "Process.h"
|
#include "Process.h"
|
||||||
|
|
||||||
#include <exception> //default C++ esception
|
#include <exception> //default C++ exception
|
||||||
#include "Win32Exception.h" //Win32 exception
|
#include "Win32Exception.h" //Win32 exception
|
||||||
|
|
||||||
typedef std::vector<const char*> ParamVector;
|
typedef std::vector<const char*> ParamVector;
|
||||||
|
|
||||||
|
bool checkSingleFile(const char * commandLine) {
|
||||||
|
char fullpath[MAX_PATH];
|
||||||
|
::GetFullPathName(commandLine, MAX_PATH, fullpath, NULL);
|
||||||
|
if (::PathFileExists(fullpath)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void parseCommandLine(char * commandLine, ParamVector & paramVector) {
|
void parseCommandLine(char * commandLine, ParamVector & paramVector) {
|
||||||
|
bool isFile = checkSingleFile(commandLine); //if the commandline specifies only a file, open it as such
|
||||||
|
if (isFile) {
|
||||||
|
paramVector.push_back(commandLine);
|
||||||
|
return;
|
||||||
|
}
|
||||||
bool isInFile = false;
|
bool isInFile = false;
|
||||||
bool isInWhiteSpace = true;
|
bool isInWhiteSpace = true;
|
||||||
paramVector.clear();
|
paramVector.clear();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user