Add "-settingsDir" argument for overriding default settings path

Currently the settings directory could be:

1. Notepad++ installation dir if doLocalConf.xml is present.
2. %APPDATA%\Notepad++ if doLocalConf.xml is absent.
3. The path defined in \cloud\choice in Notepad++ installation or in %APPDATA%\Notepad++, it depends on the existence of doLocalConf.xml.

In this PR "-settingsDir" argument is added for overriding above settings paths:
4. Overrided by command line argument -settingsDir="E:\my NppSettings\" : All the above configurations will be ignored, Notepad++ will load (and write) config.xml and the other configuration xml files from (into) "E:\my NppSettings\". Note that double quotes is not necessary if there's no white space in the given path.

The priorities are: 1. -settingsDir 2. Cloud 3. %APPDATA%\Notepad++ or Notepad++ installation dir.
If the given path "E:\my NppSettings\" is not a valid directory (it doesn't exist or it's a file), this argument is ignored and the settings dir will fall back to Cloud (or to %APPDATA%\Notepad++ or Notepad++ installation dir, if settings on Cloud is not defined).

Close #4696, close #9287
This commit is contained in:
Don HO 2020-12-21 03:40:43 +01:00
parent 8f38707d33
commit b6a66ba2b1
No known key found for this signature in database
GPG Key ID: 6C429F1D8D84F46E
5 changed files with 121 additions and 19 deletions

View File

@ -177,7 +177,7 @@ void Notepad_plus_Window::init(HINSTANCE hInst, HWND parent, const TCHAR *cmdLin
{ {
::ShowWindow(_hSelf, SW_HIDE); ::ShowWindow(_hSelf, SW_HIDE);
} }
else if (not cmdLineParams->_isPreLaunch) else if (!cmdLineParams->_isPreLaunch)
{ {
if (cmdLineParams->isPointValid()) if (cmdLineParams->isPointValid())
::ShowWindow(_hSelf, SW_SHOW); ::ShowWindow(_hSelf, SW_SHOW);

View File

@ -31,7 +31,7 @@
const TCHAR COMMAND_ARG_HELP[] = TEXT("Usage :\r\ const TCHAR COMMAND_ARG_HELP[] = TEXT("Usage :\r\
\r\ \r\
notepad++ [--help] [-multiInst] [-noPlugin] [-lLanguage] [-LlangCode] [-nLineNumber] [-cColumnNumber] [-pPosition] [-xLeftPos] [-yTopPos] [-nosession] [-notabbar] [-ro] [-systemtray] [-loadingTime] [-alwaysOnTop] [-openSession] [-r] [-qnEasterEggName | -qtText | -qfCntentFileName] [-qSpeed1|2|3] [-quickPrint] [-openFoldersAsWorkspace] [filePath]\r\ notepad++ [--help] [-multiInst] [-noPlugin] [-lLanguage] [-LlangCode] [-nLineNumber] [-cColumnNumber] [-pPosition] [-xLeftPos] [-yTopPos] [-nosession] [-notabbar] [-ro] [-systemtray] [-loadingTime] [-alwaysOnTop] [-openSession] [-r] [-qnEasterEggName | -qtText | -qfCntentFileName] [-qSpeed1|2|3] [-quickPrint] [-settingsDir=\"d:\\your settings dir\\\"] [-openFoldersAsWorkspace] [filePath]\r\
\r\ \r\
--help : This help message\r\ --help : This help message\r\
-multiInst : Launch another Notepad++ instance\r\ -multiInst : Launch another Notepad++ instance\r\
@ -57,6 +57,7 @@ notepad++ [--help] [-multiInst] [-noPlugin] [-lLanguage] [-LlangCode] [-nLineNum
-qf : Launch ghost typing to display a file content via the file path\r\ -qf : Launch ghost typing to display a file content via the file path\r\
-qSpeed : Ghost typing speed. Value from 1 to 3 for slow, fast and fastest\r\ -qSpeed : Ghost typing speed. Value from 1 to 3 for slow, fast and fastest\r\
-quickPrint : Print the file given as argument then quit Notepad++\r\ -quickPrint : Print the file given as argument then quit Notepad++\r\
-settingsDir=\"d:\\your settings dir\\\": Override the default settings dir\r\
-openFoldersAsWorkspace: open filePath of folder(s) as workspace\r\ -openFoldersAsWorkspace: open filePath of folder(s) as workspace\r\
filePath : file or folder name to open (absolute or relative path name)\r\ filePath : file or folder name to open (absolute or relative path name)\r\
"); ");

View File

@ -1005,8 +1005,6 @@ bool NppParameters::load()
{ {
L_END = L_EXTERNAL; L_END = L_EXTERNAL;
bool isAllLaoded = true; bool isAllLaoded = true;
for (int i = 0 ; i < NB_LANG ; _langList[i] = NULL, ++i)
{}
_isx64 = sizeof(void *) == 8; _isx64 = sizeof(void *) == 8;
@ -1037,6 +1035,9 @@ bool NppParameters::load()
_pluginRootDir = _nppPath; _pluginRootDir = _nppPath;
PathAppend(_pluginRootDir, TEXT("plugins")); PathAppend(_pluginRootDir, TEXT("plugins"));
//
// the 3rd priority: general default configuration
//
generic_string nppPluginRootParent; generic_string nppPluginRootParent;
if (_isLocal) if (_isLocal)
{ {
@ -1078,7 +1079,9 @@ bool NppParameters::load()
generic_string cloudChoicePath{_userPath}; generic_string cloudChoicePath{_userPath};
cloudChoicePath += TEXT("\\cloud\\choice"); cloudChoicePath += TEXT("\\cloud\\choice");
// cloudChoicePath doesn't exist, just quit //
// the 2nd priority: cloud Choice Path
//
if (::PathFileExists(cloudChoicePath.c_str())) if (::PathFileExists(cloudChoicePath.c_str()))
{ {
// Read cloud choice // Read cloud choice
@ -1086,7 +1089,7 @@ bool NppParameters::load()
WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance(); WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance();
std::wstring cloudChoiceStrW = wmc.char2wchar(cloudChoiceStr.c_str(), SC_CP_UTF8); std::wstring cloudChoiceStrW = wmc.char2wchar(cloudChoiceStr.c_str(), SC_CP_UTF8);
if (not cloudChoiceStrW.empty() and ::PathFileExists(cloudChoiceStrW.c_str())) if (!cloudChoiceStrW.empty() && ::PathFileExists(cloudChoiceStrW.c_str()))
{ {
_userPath = cloudChoiceStrW; _userPath = cloudChoiceStrW;
_nppGUI._cloudPath = cloudChoiceStrW; _nppGUI._cloudPath = cloudChoiceStrW;
@ -1094,6 +1097,26 @@ bool NppParameters::load()
} }
} }
//
// the 1st priority: custom settings dir via command line argument
//
if (!_cmdSettingsDir.empty())
{
if (!::PathIsDirectory(_cmdSettingsDir.c_str()))
{
// The following text is not translatable.
// _pNativeLangSpeaker is initialized AFTER _userPath being dterminated because nativeLang.xml is from from _userPath.
generic_string errMsg = TEXT("The given path\r");
errMsg += _cmdSettingsDir;
errMsg += TEXT("\nvia command line \"-settingsDir=\" is not a valid directory.\rThis argument will be ignored.");
::MessageBox(NULL, errMsg.c_str(), TEXT("Invalid directory"), MB_OK);
}
else
{
_userPath = _cmdSettingsDir;
_sessionPath = _userPath; // reset session path
}
}
//-------------------------------------// //-------------------------------------//
// Transparent function for w2k and xp // // Transparent function for w2k and xp //

View File

@ -231,6 +231,7 @@ struct CmdLineParams
LangType _langType = L_EXTERNAL; LangType _langType = L_EXTERNAL;
generic_string _localizationPath; generic_string _localizationPath;
generic_string _easterEggName; generic_string _easterEggName;
unsigned char _quoteType = '\0'; unsigned char _quoteType = '\0';
int _ghostTypingSpeed = -1; // -1: initial value 1: slow 2: fast 3: speed of light int _ghostTypingSpeed = -1; // -1: initial value 1: slow 2: fast 3: speed of light
@ -1678,6 +1679,11 @@ public:
void setUseNewStyleSaveDlg(bool v) { void setUseNewStyleSaveDlg(bool v) {
_nppGUI._useNewStyleSaveDlg = v; _nppGUI._useNewStyleSaveDlg = v;
} }
void setCmdSettingsDir(const generic_string& settingsDir) {
_cmdSettingsDir = settingsDir;
};
DPIManager _dpiManager; DPIManager _dpiManager;
generic_string static getSpecialFolderLocation(int folderKind); generic_string static getSpecialFolderLocation(int folderKind);
@ -1716,7 +1722,7 @@ private:
NppGUI _nppGUI; NppGUI _nppGUI;
ScintillaViewParams _svp; ScintillaViewParams _svp;
Lang *_langList[NB_LANG]; Lang *_langList[NB_LANG] = {};
int _nbLang = 0; int _nbLang = 0;
// Recent File History // Recent File History
@ -1756,6 +1762,8 @@ private:
bool _isLocal; bool _isLocal;
bool _isx64 = false; // by default 32-bit bool _isx64 = false; // by default 32-bit
generic_string _cmdSettingsDir;
public: public:
void setShortcutDirty() { _isAnyShortcutModified = true; }; void setShortcutDirty() { _isAnyShortcutModified = true; };
void setAdminMode(bool isAdmin) { _isAdminMode = isAdmin; } void setAdminMode(bool isAdmin) { _isAdminMode = isAdmin; }

View File

@ -77,21 +77,76 @@ void allowWmCopydataMessages(Notepad_plus_Window& notepad_plus_plus, const NppPa
} }
} }
//commandLine should contain path to n++ executable running // parseCommandLine() takes command line arguments part string, cuts arguments by using white space as separater.
ParamVector parseCommandLine(const TCHAR* commandLine) // Only white space in double quotes will be kept, such as file path argument or "-settingsDir=" argument (ex.: -settingsDir="c:\my settings\my folder\")
void parseCommandLine(const TCHAR* commandLine, ParamVector& paramVector)
{ {
ParamVector result; if (!commandLine)
if ( commandLine[0] != '\0' ) return;
TCHAR* cmdLine = new TCHAR[lstrlen(commandLine) + 1];
lstrcpy(cmdLine, commandLine);
TCHAR* cmdLinePtr = cmdLine;
bool isInFile = false;
bool isStringInArg = false;
bool isInWhiteSpace = true;
size_t commandLength = lstrlen(cmdLinePtr);
std::vector<TCHAR *> args;
for (size_t i = 0; i < commandLength; ++i)
{ {
int numArgs; switch (cmdLinePtr[i])
LPWSTR* tokenizedCmdLine = CommandLineToArgvW( commandLine, &numArgs );
if ( tokenizedCmdLine != nullptr )
{ {
result.assign( tokenizedCmdLine, tokenizedCmdLine+numArgs ); case '\"': //quoted filename, ignore any following whitespace
LocalFree( tokenizedCmdLine ); {
if (!isStringInArg && i > 0 && cmdLinePtr[i - 1] == '=')
{
isStringInArg = true;
}
else if (isStringInArg)
{
isStringInArg = false;
//cmdLinePtr[i] = 0;
}
else if (!isInFile) //" will always be treated as start or end of param, in case the user forgot to add an space
{
args.push_back(cmdLinePtr + i + 1); //add next param(since zero terminated original, no overflow of +1)
isInFile = true;
cmdLinePtr[i] = 0;
}
else if (isInFile)
{
isInFile = false;
//because we dont want to leave in any quotes in the filename, remove them now (with zero terminator)
cmdLinePtr[i] = 0;
}
isInWhiteSpace = false;
}
break;
case '\t': //also treat tab as whitespace
case ' ':
{
isInWhiteSpace = true;
if (!isInFile && !isStringInArg)
cmdLinePtr[i] = 0; //zap spaces into zero terminators, unless its part of a filename
}
break;
default: //default TCHAR, if beginning of word, add it
{
if (!isInFile && !isStringInArg && isInWhiteSpace)
{
args.push_back(cmdLinePtr + i); //add next param
isInWhiteSpace = false;
} }
} }
return result; }
}
paramVector.assign(args.begin(), args.end());
delete[] cmdLine;
} }
// 1. Converts /p to -quickPrint if it exists as the first parameter // 1. Converts /p to -quickPrint if it exists as the first parameter
@ -265,6 +320,7 @@ const TCHAR FLAG_FUNCLSTEXPORT[] = TEXT("-export=functionList");
const TCHAR FLAG_PRINTANDQUIT[] = TEXT("-quickPrint"); const TCHAR FLAG_PRINTANDQUIT[] = TEXT("-quickPrint");
const TCHAR FLAG_NOTEPAD_COMPATIBILITY[] = TEXT("-notepadStyleCmdline"); const TCHAR FLAG_NOTEPAD_COMPATIBILITY[] = TEXT("-notepadStyleCmdline");
const TCHAR FLAG_OPEN_FOLDERS_AS_WORKSPACE[] = TEXT("-openFoldersAsWorkspace"); const TCHAR FLAG_OPEN_FOLDERS_AS_WORKSPACE[] = TEXT("-openFoldersAsWorkspace");
const TCHAR FLAG_SETTINGS_DIR[] = TEXT("-settingsDir=");
void doException(Notepad_plus_Window & notepad_plus_plus) void doException(Notepad_plus_Window & notepad_plus_plus)
{ {
@ -360,7 +416,8 @@ PWSTR stripIgnoredParams(ParamVector & params, PWSTR pCmdLine)
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int) int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int)
{ {
ParamVector params = parseCommandLine(pCmdLine); ParamVector params;
parseCommandLine(pCmdLine, params);
PWSTR pCmdLineWithoutIgnores = stripIgnoredParams(params, pCmdLine); PWSTR pCmdLineWithoutIgnores = stripIgnoredParams(params, pCmdLine);
MiniDumper mdump; //for debugging purposes. MiniDumper mdump; //for debugging purposes.
@ -394,6 +451,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int)
cmdLineParams._isSessionFile = isInList(FLAG_OPENSESSIONFILE, params); cmdLineParams._isSessionFile = isInList(FLAG_OPENSESSIONFILE, params);
cmdLineParams._isRecursive = isInList(FLAG_RECURSIVE, params); cmdLineParams._isRecursive = isInList(FLAG_RECURSIVE, params);
cmdLineParams._openFoldersAsWorkspace = isInList(FLAG_OPEN_FOLDERS_AS_WORKSPACE, params); cmdLineParams._openFoldersAsWorkspace = isInList(FLAG_OPEN_FOLDERS_AS_WORKSPACE, params);
cmdLineParams._langType = getLangTypeFromParam(params); cmdLineParams._langType = getLangTypeFromParam(params);
cmdLineParams._localizationPath = getLocalizationPathFromParam(params); cmdLineParams._localizationPath = getLocalizationPathFromParam(params);
cmdLineParams._easterEggName = getEasterEggNameFromParam(params, cmdLineParams._quoteType); cmdLineParams._easterEggName = getEasterEggNameFromParam(params, cmdLineParams._quoteType);
@ -406,11 +464,23 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int)
cmdLineParams._point.x = getNumberFromParam('x', params, cmdLineParams._isPointXValid); cmdLineParams._point.x = getNumberFromParam('x', params, cmdLineParams._isPointXValid);
cmdLineParams._point.y = getNumberFromParam('y', params, cmdLineParams._isPointYValid); cmdLineParams._point.y = getNumberFromParam('y', params, cmdLineParams._isPointYValid);
NppParameters& nppParameters = NppParameters::getInstance();
generic_string path;
if (getParamValFromString(FLAG_SETTINGS_DIR, params, path))
{
// path could contain double quotes if path contains white space
if (path.c_str()[0] == '"' && path.c_str()[path.length() - 1] == '"')
{
path = path.substr(1, path.length() - 2);
}
nppParameters.setCmdSettingsDir(path);
}
if (showHelp) if (showHelp)
::MessageBox(NULL, COMMAND_ARG_HELP, TEXT("Notepad++ Command Argument Help"), MB_OK); ::MessageBox(NULL, COMMAND_ARG_HELP, TEXT("Notepad++ Command Argument Help"), MB_OK);
NppParameters& nppParameters = NppParameters::getInstance();
if (cmdLineParams._localizationPath != TEXT("")) if (cmdLineParams._localizationPath != TEXT(""))
{ {