├── Makefile ├── README ├── doc ├── SessionMgr.css └── SessionMgr.html ├── license.txt ├── setenv.cmd ├── src ├── ContextMenu.cpp ├── ContextMenu.h ├── DlgDelete.cpp ├── DlgDelete.h ├── DlgNew.cpp ├── DlgNew.h ├── DlgRename.cpp ├── DlgRename.h ├── DlgSessions.cpp ├── DlgSessions.h ├── DlgSettings.cpp ├── DlgSettings.h ├── DllMain.cpp ├── Menu.cpp ├── Menu.h ├── Properties.cpp ├── Properties.h ├── SessionMgr.cpp ├── SessionMgr.h ├── SessionMgrApi.h ├── Settings.cpp ├── Settings.h ├── System.cpp ├── System.h ├── Util.cpp ├── Util.h ├── npp │ ├── Notepad_plus_msgs.h │ ├── PluginInterface.h │ ├── Scintilla.h │ └── menuCmdID.h ├── res │ ├── resource.h │ ├── resource.rc │ ├── version.h │ └── version.rc2 ├── utf8 │ ├── checked.h │ ├── core.h │ └── unchecked.h └── xml │ ├── tinyxml.h │ ├── tinyxml2.cpp │ └── tinyxml2.h └── x.cmd /Makefile: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | # SessionMgr nmake file 3 | 4 | # 1. Check that you have environment variables PATH, INCLUDE and LIB defined. 5 | # 2. Modify "setenv.cmd" with your toolchain paths. 6 | # 3. Open a DOS box in the directory containing this makefile. 7 | # 4. Run setenv, then run nmake. 8 | 9 | PRJ=SessionMgr 10 | 11 | O=obj 12 | S=src 13 | R=src\res 14 | N=src\npp 15 | X=src\xml 16 | 17 | # http://msdn.microsoft.com/en-us/library/fwkeyyhe.aspx 18 | CXX=cl 19 | CXXFLAGS=/O2 /EHs /GR- /MT /nologo /W3 /WX- /Gd /Gm- /Fo$O\ /fp:fast /wd4995 \ 20 | /errorReport:none /Zc:wchar_t /DWIN32 /DNDEBUG /D_WINDOWS /D_USRDLL \ 21 | /D_WINDLL /DUNICODE /D_UNICODE /c 22 | 23 | # http://msdn.microsoft.com/en-us/library/y0zzbyt4.aspx 24 | LD=link 25 | LIBS=user32.lib shell32.lib 26 | LDFLAGS=/DLL /nologo /OUT:$O\$(PRJ).dll /INCREMENTAL:NO /MANIFEST:NO \ 27 | /MACHINE:X86 /ERRORREPORT:NONE 28 | 29 | RC=rc 30 | RCFLAGS=/nologo /fo$O\$(PRJ).res 31 | RESDEPS=$R\resource.rc $R\resource.h $R\version.rc2 $R\version.h 32 | NPPDEPS=$N\PluginInterface.h $N\Scintilla.h $N\Notepad_plus_msgs.h $N\menuCmdID.h 33 | 34 | #------------------------------------------------------------------------------- 35 | # Targets 36 | 37 | default: init $(PRJ) 38 | 39 | init: 40 | if not exist $O\ mkdir $O 41 | 42 | clean: 43 | if exist $O\ del $O\*.obj & del $O\$(PRJ).* 44 | 45 | #------------------------------------------------------------------------------- 46 | # Link obj files to make dll 47 | 48 | $(PRJ): $O\$(PRJ).obj $O\Settings.obj $O\DlgDelete.obj $O\DlgNew.obj $O\DlgRename.obj \ 49 | $O\DlgSessions.obj $O\DlgSettings.obj $O\DllMain.obj $O\Menu.obj $O\Properties.obj \ 50 | $O\ContextMenu.obj $O\System.obj $O\Util.obj $O\tinyxml2.obj $O\$(PRJ).res 51 | $(LD) $(LDFLAGS) $(LIBS) $? 52 | 53 | #------------------------------------------------------------------------------- 54 | # Compile cpp files 55 | 56 | $O\$(PRJ).obj: $S\$(@B).cpp $S\$(@B).h $(NPPDEPS) 57 | $(CXX) $(CXXFLAGS) %s 58 | 59 | $O\Settings.obj: $S\$(@B).cpp $S\$(@B).h 60 | $(CXX) $(CXXFLAGS) %s 61 | 62 | $O\DlgDelete.obj: $S\$(@B).cpp $S\$(@B).h 63 | $(CXX) $(CXXFLAGS) %s 64 | 65 | $O\DlgNew.obj: $S\$(@B).cpp $S\$(@B).h 66 | $(CXX) $(CXXFLAGS) %s 67 | 68 | $O\DlgRename.obj: $S\$(@B).cpp $S\$(@B).h 69 | $(CXX) $(CXXFLAGS) %s 70 | 71 | $O\DlgSessions.obj: $S\$(@B).cpp $S\$(@B).h 72 | $(CXX) $(CXXFLAGS) %s 73 | 74 | $O\DlgSettings.obj: $S\$(@B).cpp $S\$(@B).h 75 | $(CXX) $(CXXFLAGS) %s 76 | 77 | $O\DllMain.obj: $S\$(@B).cpp 78 | $(CXX) $(CXXFLAGS) %s 79 | 80 | $O\Menu.obj: $S\$(@B).cpp $S\$(@B).h $(NPPDEPS) $(RESDEPS) 81 | $(CXX) $(CXXFLAGS) %s 82 | 83 | $O\Properties.obj: $S\$(@B).cpp $S\$(@B).h 84 | $(CXX) $(CXXFLAGS) %s 85 | 86 | $O\ContextMenu.obj: $S\$(@B).cpp $S\$(@B).h 87 | $(CXX) $(CXXFLAGS) %s 88 | 89 | $O\System.obj: $S\$(@B).cpp $S\$(@B).h $(NPPDEPS) 90 | $(CXX) $(CXXFLAGS) %s 91 | 92 | $O\Util.obj: $S\$(@B).cpp $S\$(@B).h 93 | $(CXX) $(CXXFLAGS) %s 94 | 95 | $O\tinyxml2.obj: $X\$(@B).cpp $X\$(@B).h 96 | $(CXX) $(CXXFLAGS) %s 97 | 98 | #------------------------------------------------------------------------------- 99 | # Compile resource files 100 | 101 | $O\$(PRJ).res: $(RESDEPS) 102 | $(RC) $(RCFLAGS) %s 103 | 104 | #------------------------------------------------------------------------------- 105 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Session Manager 2 | A Plugin for Notepad++ 3 | -------------------------------------------------------------------------------- 4 | 5 | Project home: http://mfoster.com/npp/ 6 | Project source: https://github.com/mike-foster/npp-session-manager 7 | User documentation: http://mfoster.com/npp/SessionMgr.html 8 | Build instructions: See "Makefile" 9 | License: See "license.txt" 10 | Discussion, feedback, bug reports: 11 | https://sourceforge.net/p/notepad-plus/discussion/482781/ 12 | 13 | -------------------------------------------------------------------------------- /doc/SessionMgr.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin:0; 3 | padding:0; 4 | } 5 | html, body { 6 | color: #333; 7 | background-color: #a7a09a; 8 | font-size: small; 9 | font-family: verdana,arial,helvetica,sans-serif; 10 | } 11 | body { 12 | min-width: 950px; 13 | text-align: center; /* to center layout-container in IE6 */ 14 | } 15 | p { 16 | margin: 1em 0; 17 | line-height: 1.3em; 18 | } 19 | b { 20 | color:#666; 21 | font-weight: bold; 22 | } 23 | tt { 24 | font-size: small; 25 | font-family: 'courier new',monospace; 26 | } 27 | a { 28 | color:#333; 29 | } 30 | a:link, a:active { 31 | color:#366; 32 | } 33 | a:visited { 34 | color:#333; 35 | } 36 | a:hover { 37 | color: #fff; 38 | background-color: #a7a09a; 39 | text-decoration:none; 40 | } 41 | h1 { 42 | color: #555; 43 | font-size: xx-large; 44 | margin: .5em 0 .2em 0; 45 | } 46 | h2, h3, h4 { 47 | color: #555; 48 | margin: 1.2em 0 .5em 0; 49 | } 50 | h2 { 51 | font-size: x-large; 52 | } 53 | h3 { 54 | font-size: large; 55 | /* text-decoration: underline; */ 56 | } 57 | h4 { 58 | font-size: medium; 59 | } 60 | pre { 61 | font-family: 'courier new',monospace; 62 | color: #666; 63 | background: transparent; 64 | border: 1px dotted #a7a09a; 65 | margin: .3em .12em .6em 0; 66 | padding: .6em; 67 | overflow: auto; 68 | font-size: small; 69 | max-height: 32em; 70 | } 71 | ul#contents li { 72 | /* font-size: smaller; */ 73 | margin-top: 1px; 74 | margin-bottom: 1px; 75 | } 76 | 77 | .smaller { 78 | font-size: smaller; 79 | } 80 | 81 | #layout-container { 82 | position: relative; 83 | background-color: #eee; 84 | margin: 10px auto; 85 | width: 950px; 86 | text-align: left; 87 | overflow: hidden; 88 | } 89 | #layout-header { 90 | position: relative; 91 | background-color: #eee; 92 | padding: 5px 10px 5px 20px; 93 | } 94 | #layout-header p { 95 | /* font-style: italic; */ 96 | font-weight: bold; 97 | /* font-size: smaller; */ 98 | } 99 | #layout-hmenu { 100 | /* font-size: smaller; */ 101 | position: relative; 102 | left: 1px; 103 | width: 918px; 104 | background-color: #c99; 105 | padding: 5px 10px 5px 20px; 106 | text-align: right; 107 | } 108 | #layout-main-col { 109 | padding: 10px 20px 20px 20px; 110 | background-color: #eee; 111 | overflow: hidden; 112 | } 113 | #layout-main-col ul { 114 | margin-left: 20px; 115 | } 116 | #layout-main-col ul ul { 117 | margin-top: 7px; 118 | } 119 | #layout-main-col ol { 120 | margin-left: 28px; 121 | } 122 | #layout-main-col li { 123 | line-height: 1.3em; 124 | margin-bottom: 7px; 125 | } 126 | #layout-footer { 127 | clear: both; 128 | position: relative; 129 | padding: 5px 20px 5px 20px; 130 | /* font-size: smaller; */ 131 | background-color: #eee; 132 | border-top: 1px solid #fff; 133 | text-align: right; 134 | } 135 | 136 | #layout-container, 137 | #layout-header, 138 | #layout-hmenu, 139 | #layout-main-col, 140 | #layout-footer { 141 | -moz-border-radius: 5px; 142 | -webkit-border-radius: 5px; 143 | -khtml-border-radius: 5px; 144 | } 145 | -------------------------------------------------------------------------------- /setenv.cmd: -------------------------------------------------------------------------------- 1 | :: Set paths for the "include" and "lib" directories of the toolchain and the 2 | :: Windows SDK. Note that "link" has a dependency on "common7\ide\mspdb*.dll". 3 | 4 | set PATH=c:\bin\msvs\vc\bin;c:\program files\microsoft sdks\windows\v7.1\bin;c:\bin\msvs\common7\ide;%PATH% 5 | set INCLUDE=c:\bin\msvs\vc\include;c:\program files\microsoft sdks\windows\v7.1\include;%INCLUDE% 6 | set LIB=c:\bin\msvs\vc\lib;c:\program files\microsoft sdks\windows\v7.1\lib;%LIB% 7 | -------------------------------------------------------------------------------- /src/ContextMenu.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file ContextMenu.cpp 13 | @copyright Copyright 2014,2015 Michael Foster 14 | 15 | Session Manager creates a submenu in the context (right-click) menu if the 16 | useContextMenu setting is enabled. The submenu is only created or updated 17 | when a change is made to favorite sessions. Notepad++ must be restarted for 18 | the changes to appear in the menus. The menu labels used in the context 19 | submenu are the same as those used in the Plugins menu and favorite sessions 20 | are listed after the About item. 21 | */ 22 | 23 | #include "System.h" 24 | #include "ContextMenu.h" 25 | #include "Menu.h" 26 | #include "Util.h" 27 | 28 | //------------------------------------------------------------------------------ 29 | 30 | namespace NppPlugin { 31 | 32 | //------------------------------------------------------------------------------ 33 | 34 | namespace { 35 | 36 | /// XML nodes 37 | #define XN_NOTEPADPLUS "NotepadPlus" ///< root node 38 | #define XN_SCINTILLACONTEXTMENU "ScintillaContextMenu" 39 | #define XN_ITEM "Item" 40 | 41 | /// XML attributes 42 | #define XA_FOLDERNAME "FolderName" 43 | #define XA_PLUGINENTRYNAME "PluginEntryName" 44 | #define XA_PLUGINCOMMANDITEMNAME "PluginCommandItemName" 45 | #define XA_ITEMNAMEAS "ItemNameAs" 46 | #define XA_ID "id" 47 | 48 | tXmlDocP _pCtxXmlDoc = NULL; 49 | tXmlEleP _pCtxLastFav = NULL; 50 | 51 | tXmlEleP getFavSeparator(); 52 | tXmlEleP createContextMenu(tXmlEleP sciCtxMnuEle); 53 | tXmlEleP newItemElement(LPCWSTR itemName = NULL); 54 | 55 | } // end namespace 56 | 57 | //------------------------------------------------------------------------------ 58 | 59 | namespace api { 60 | 61 | void ctx_onUnload() 62 | { 63 | ctx::unload(); 64 | } 65 | 66 | } // end namespace NppPlugin::api 67 | 68 | //------------------------------------------------------------------------------ 69 | 70 | namespace ctx { 71 | 72 | /** Deletes all favorite Item elements. Does not save the file after deleting. 73 | @return a pointer to the separator element preceeding the favorite elements */ 74 | void deleteFavorites() 75 | { 76 | tXmlEleP ele, sepEle, favEle, sciCtxMnuEle; 77 | 78 | if (cfg::getBool(kUseContextMenu)) { 79 | LPSTR mbMain = str::utf16ToUtf8(mnu_getMenuLabel()); 80 | if (mbMain) { 81 | sepEle = getFavSeparator(); 82 | if (sepEle) { 83 | sciCtxMnuEle = sepEle->Parent()->ToElement(); 84 | favEle = sepEle->NextSiblingElement(XN_ITEM); 85 | while (favEle && favEle->Attribute(XA_FOLDERNAME, mbMain)) { 86 | ele = favEle; 87 | favEle = favEle->NextSiblingElement(XN_ITEM); 88 | sciCtxMnuEle->DeleteChild(ele); 89 | } 90 | } 91 | sys_free(mbMain); 92 | } 93 | _pCtxLastFav = NULL; 94 | } 95 | } 96 | 97 | /** Adds a new favorite element in NPP's contextMenu.xml file. Does not save the file. */ 98 | void addFavorite(LPCWSTR favName) 99 | { 100 | tXmlEleP sepEle, favEle, sciCtxMnuEle; 101 | 102 | if (cfg::getBool(kUseContextMenu)) { 103 | if (!_pCtxLastFav) { 104 | sepEle = getFavSeparator(); 105 | if (sepEle) { 106 | favEle = newItemElement(favName); 107 | sciCtxMnuEle = sepEle->Parent()->ToElement(); 108 | sciCtxMnuEle->InsertAfterChild(sepEle, favEle); 109 | _pCtxLastFav = favEle; 110 | } 111 | } 112 | else { 113 | favEle = newItemElement(favName); 114 | sciCtxMnuEle = _pCtxLastFav->Parent()->ToElement(); 115 | sciCtxMnuEle->InsertAfterChild(_pCtxLastFav, favEle); 116 | _pCtxLastFav = favEle; 117 | } 118 | } 119 | } 120 | 121 | void saveContextMenu() 122 | { 123 | DWORD lastErr; 124 | tXmlError xmlErr; 125 | 126 | if (cfg::getBool(kUseContextMenu)) { 127 | if (_pCtxXmlDoc) { 128 | xmlErr = _pCtxXmlDoc->SaveFile(sys_getNppCtxMnuFile()); 129 | if (xmlErr != kXmlSuccess) { 130 | lastErr = ::GetLastError(); 131 | msg::error(lastErr, L"%s: Error %u saving the context menu file.", _W(__FUNCTION__), xmlErr); 132 | } 133 | } 134 | } 135 | } 136 | 137 | void unload() 138 | { 139 | if (_pCtxXmlDoc) { 140 | delete _pCtxXmlDoc; 141 | _pCtxXmlDoc = NULL; 142 | } 143 | } 144 | 145 | } // end namespace NppPlugin::ctx 146 | 147 | //------------------------------------------------------------------------------ 148 | 149 | namespace { 150 | 151 | /** Creates the entire context menu if it is not found. Saves the file if any 152 | changes are made. 153 | @return a pointer to the separator element preceeding the favorite elements */ 154 | tXmlEleP getFavSeparator() 155 | { 156 | DWORD lastErr; 157 | tXmlError xmlErr; 158 | bool changed = false; 159 | tXmlEleP sepEle = NULL; 160 | LPSTR mbMain, mbAbout; 161 | 162 | // Load the contextMenu file if not already loaded 163 | if (!_pCtxXmlDoc) { 164 | _pCtxXmlDoc = new tinyxml2::XMLDocument(); 165 | xmlErr = _pCtxXmlDoc->LoadFile(sys_getNppCtxMnuFile()); 166 | if (xmlErr != kXmlSuccess) { 167 | lastErr = ::GetLastError(); 168 | msg::error(lastErr, L"%s: Error %u loading the context menu file.", _W(__FUNCTION__), xmlErr); 169 | return NULL; 170 | } 171 | } 172 | tXmlEleP sciCtxMnuEle, itemEle; 173 | tXmlHnd ctxDocHnd(_pCtxXmlDoc); 174 | sciCtxMnuEle = ctxDocHnd.FirstChildElement(XN_NOTEPADPLUS).FirstChildElement(XN_SCINTILLACONTEXTMENU).ToElement(); 175 | 176 | // the main menu item label 177 | mbMain = str::utf16ToUtf8(mnu_getMenuLabel()); 178 | // the About item label 179 | mbAbout = str::utf16ToUtf8(mnu_getMenuLabel(MNU_BASE_MAX_ITEMS - 1)); 180 | if (mbMain && mbAbout) { 181 | // Iterate over the Item elements looking for our About item 182 | itemEle = sciCtxMnuEle->FirstChildElement(XN_ITEM); 183 | while (itemEle) { 184 | if (itemEle->Attribute(XA_FOLDERNAME, mbMain) && itemEle->Attribute(XA_ITEMNAMEAS, mbAbout)) { 185 | break; // found it 186 | } 187 | itemEle = itemEle->NextSiblingElement(XN_ITEM); 188 | } 189 | if (!itemEle) { // not found so need to create our entire context menu 190 | sepEle = createContextMenu(sciCtxMnuEle); 191 | changed = true; 192 | } 193 | else { // found it so check if a separator follows it, if not then add it 194 | sepEle = itemEle->NextSiblingElement(XN_ITEM); 195 | if (!sepEle->Attribute(XA_FOLDERNAME, mbMain) || !sepEle->Attribute(XA_ID, "0")) { 196 | sepEle = newItemElement(); 197 | sciCtxMnuEle->InsertAfterChild(itemEle, sepEle); 198 | changed = true; 199 | } 200 | } 201 | if (changed) { 202 | ctx::saveContextMenu(); 203 | } 204 | sys_free(mbMain); 205 | sys_free(mbAbout); 206 | } 207 | 208 | return sepEle; 209 | } 210 | 211 | /** Creates our context menu. Does not save the file. 212 | @return a pointer to the separator element preceeding the favorite elements */ 213 | tXmlEleP createContextMenu(tXmlEleP sciCtxMnuEle) 214 | { 215 | tXmlEleP ele; 216 | 217 | for (INT mnuIdx = 0; mnuIdx < MNU_BASE_MAX_ITEMS; ++mnuIdx) { 218 | ele = newItemElement(mnuIdx == 4 ? NULL : mnu_getMenuLabel(mnuIdx)); 219 | sciCtxMnuEle->InsertEndChild(ele); 220 | } 221 | // the separator preceeding the favorites 222 | ele = newItemElement(); 223 | sciCtxMnuEle->InsertEndChild(ele); 224 | 225 | return ele; 226 | } 227 | 228 | /** @return a new Item element */ 229 | tXmlEleP newItemElement(LPCWSTR itemName) 230 | { 231 | tXmlEleP ele = NULL; 232 | 233 | LPSTR mbMain = str::utf16ToUtf8(mnu_getMenuLabel()); 234 | if (mbMain) { 235 | ele = _pCtxXmlDoc->NewElement(XN_ITEM); 236 | ele->SetAttribute(XA_FOLDERNAME, mbMain); 237 | if (!itemName) { // separator 238 | ele->SetAttribute(XA_ID, "0"); 239 | } 240 | else { 241 | CHAR mbMainNoAmp[MNU_MAX_NAME_LEN], mbBufNoAmp[MNU_MAX_NAME_LEN]; 242 | LPSTR mbBuf = str::utf16ToUtf8(itemName); 243 | if (mbBuf) { 244 | str::removeAmp(mbMain, mbMainNoAmp); 245 | str::removeAmp(mbBuf, mbBufNoAmp); 246 | ele->SetAttribute(XA_PLUGINENTRYNAME, mbMainNoAmp); 247 | ele->SetAttribute(XA_ITEMNAMEAS, mbBuf); 248 | ele->SetAttribute(XA_PLUGINCOMMANDITEMNAME, mbBufNoAmp); 249 | sys_free(mbBuf); 250 | } 251 | } 252 | sys_free(mbMain); 253 | } 254 | 255 | return ele; 256 | } 257 | 258 | } // end namespace 259 | 260 | } // end namespace NppPlugin 261 | -------------------------------------------------------------------------------- /src/ContextMenu.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file ContextMenu.h 13 | @copyright Copyright 2014,2015 Michael Foster 14 | */ 15 | 16 | #ifndef NPP_PLUGIN_CONTEXTMENU_H 17 | #define NPP_PLUGIN_CONTEXTMENU_H 18 | 19 | //------------------------------------------------------------------------------ 20 | 21 | namespace NppPlugin { 22 | 23 | //------------------------------------------------------------------------------ 24 | /// @namespace NppPlugin::api Contains functions called only from DllMain. 25 | 26 | namespace api { 27 | 28 | void ctx_onUnload(); 29 | 30 | } // end namespace NppPlugin::api 31 | 32 | //------------------------------------------------------------------------------ 33 | /** @namespace NppPlugin::ctx Contains functions for creating the context menu 34 | items and managing the favorites there. */ 35 | 36 | namespace ctx { 37 | 38 | void deleteFavorites(); 39 | void addFavorite(LPCWSTR favName); 40 | void saveContextMenu(); 41 | void unload(); 42 | 43 | } // end namespace NppPlugin::ctx 44 | 45 | } // end namespace NppPlugin 46 | 47 | #endif // NPP_PLUGIN_CONTEXTMENU_H 48 | -------------------------------------------------------------------------------- /src/DlgDelete.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file DlgDelete.cpp 13 | @copyright Copyright 2011,2013-2015 Michael Foster 14 | 15 | The "Delete Session" dialog. 16 | */ 17 | 18 | #include "System.h" 19 | #include "SessionMgr.h" 20 | #include "DlgSessions.h" 21 | #include "DlgDelete.h" 22 | #include "Util.h" 23 | #include "res\resource.h" 24 | #include 25 | 26 | //------------------------------------------------------------------------------ 27 | 28 | namespace NppPlugin { 29 | 30 | //------------------------------------------------------------------------------ 31 | 32 | namespace { 33 | 34 | ChildDialogData *_dialogData; 35 | 36 | void onInit(HWND hDlg); 37 | bool onOk(HWND hDlg); 38 | 39 | } // end namespace 40 | 41 | //------------------------------------------------------------------------------ 42 | 43 | INT_PTR CALLBACK dlgDel_msgProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam) 44 | { 45 | INT_PTR status = FALSE; 46 | 47 | if (uMessage == WM_COMMAND) { 48 | switch (LOWORD(wParam)) { 49 | 50 | case IDOK: 51 | if (onOk(hDlg)) { 52 | ::EndDialog(hDlg, 1); 53 | status = TRUE; 54 | } 55 | break; 56 | 57 | case IDCANCEL: 58 | ::EndDialog(hDlg, 0); 59 | status = TRUE; 60 | break; 61 | } 62 | } 63 | else if (uMessage == WM_INITDIALOG) { 64 | _dialogData = (ChildDialogData*)lParam; 65 | onInit(hDlg); 66 | } 67 | 68 | return status; 69 | } 70 | 71 | //------------------------------------------------------------------------------ 72 | 73 | namespace { 74 | 75 | void onInit(HWND hDlg) 76 | { 77 | dlg::focus(hDlg, IDOK); 78 | dlg::centerWnd(hDlg, NULL, 150, -5); 79 | ::ShowWindow(hDlg, SW_SHOW); 80 | } 81 | 82 | bool onOk(HWND hDlg) 83 | { 84 | WCHAR sesPth[MAX_PATH]; 85 | if (app_isValidSessionIndex(_dialogData->selectedSessionIndex)) { 86 | app_getSessionFile(_dialogData->selectedSessionIndex, sesPth); 87 | if (::DeleteFileW(sesPth)) { 88 | return true; 89 | } 90 | else { 91 | DWORD le = ::GetLastError(); 92 | msg::error(le, L"%s: Error deleting \"%s\".", _W(__FUNCTION__), sesPth); 93 | } 94 | } 95 | return false; 96 | } 97 | 98 | } // end namespace 99 | 100 | } // end namespace NppPlugin 101 | -------------------------------------------------------------------------------- /src/DlgDelete.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file DlgDelete.h 13 | @copyright Copyright 2011,2014,2015 Michael Foster 14 | */ 15 | 16 | #ifndef NPP_PLUGIN_DLGDELETE_H 17 | #define NPP_PLUGIN_DLGDELETE_H 18 | 19 | //------------------------------------------------------------------------------ 20 | 21 | namespace NppPlugin { 22 | 23 | INT_PTR CALLBACK dlgDel_msgProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam); 24 | 25 | } // end namespace NppPlugin 26 | 27 | #endif // NPP_PLUGIN_DLGDELETE_H 28 | -------------------------------------------------------------------------------- /src/DlgNew.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file DlgNew.cpp 13 | @copyright Copyright 2011-2015 Michael Foster 14 | 15 | The "New Session" dialog. 16 | */ 17 | 18 | #include "System.h" 19 | #include "SessionMgr.h" 20 | #include "DlgSessions.h" 21 | #include "DlgNew.h" 22 | #include "Util.h" 23 | #include "res\resource.h" 24 | #include 25 | 26 | //------------------------------------------------------------------------------ 27 | 28 | namespace NppPlugin { 29 | 30 | //------------------------------------------------------------------------------ 31 | 32 | namespace { 33 | 34 | ChildDialogData *_dialogData; 35 | 36 | void onInit(HWND hDlg); 37 | bool onOk(HWND hDlg); 38 | bool newAsEmpty(LPWSTR dstPathname); 39 | bool newFromOpen(LPWSTR dstPathname); 40 | bool newByCopy(LPWSTR dstPathname); 41 | 42 | } // end namespace 43 | 44 | //------------------------------------------------------------------------------ 45 | 46 | INT_PTR CALLBACK dlgNew_msgProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam) 47 | { 48 | INT_PTR status = FALSE; 49 | 50 | if (uMessage == WM_COMMAND) { 51 | switch (LOWORD(wParam)) { 52 | 53 | case IDOK: 54 | if (onOk(hDlg)) { 55 | ::EndDialog(hDlg, 1); 56 | status = TRUE; 57 | } 58 | break; 59 | 60 | case IDCANCEL: 61 | ::EndDialog(hDlg, 0); 62 | status = TRUE; 63 | break; 64 | 65 | case IDC_NEW_RAD_EMPTY: 66 | case IDC_NEW_RAD_OPEN: 67 | case IDC_NEW_RAD_COPY: 68 | if (HIWORD(wParam) == BN_CLICKED) { 69 | WCHAR buf[SES_NAME_BUF_LEN]; 70 | buf[0] = 0; 71 | dlg::getText(hDlg, IDC_NEW_ETX_NAME, buf, SES_NAME_BUF_LEN); 72 | if (buf[0] == 0) { 73 | dlg::setText(hDlg, IDC_NEW_ETX_NAME, app_getSessionName(_dialogData->selectedSessionIndex)); 74 | } 75 | dlg::focus(hDlg, IDC_NEW_ETX_NAME, false); 76 | status = TRUE; 77 | } 78 | break; 79 | } 80 | } 81 | else if (uMessage == WM_INITDIALOG) { 82 | _dialogData = (ChildDialogData*)lParam; 83 | onInit(hDlg); 84 | } 85 | 86 | return status; 87 | } 88 | 89 | //------------------------------------------------------------------------------ 90 | 91 | namespace { 92 | 93 | void onInit(HWND hDlg) 94 | { 95 | dlg::setCheck(hDlg, IDC_NEW_RAD_EMPTY, true); 96 | dlg::focus(hDlg, IDC_NEW_ETX_NAME); 97 | dlg::centerWnd(hDlg, NULL, 150, -40); 98 | ::ShowWindow(hDlg, SW_SHOW); 99 | } 100 | 101 | bool onOk(HWND hDlg) 102 | { 103 | bool succ; 104 | WCHAR newName[SES_NAME_BUF_LEN]; 105 | WCHAR dstPathname[MAX_PATH]; 106 | 107 | // Set the destination file pathname. 108 | newName[0] = 0; 109 | dlg::getText(hDlg, IDC_NEW_ETX_NAME, newName, SES_NAME_BUF_LEN); 110 | if (newName[0] == 0) { 111 | msg::show(L"Missing file name.", M_WARN); 112 | return false; 113 | } 114 | ::StringCchCopyW(dstPathname, MAX_PATH, cfg::getStr(kSessionDirectory)); 115 | ::StringCchCatW(dstPathname, MAX_PATH, newName); 116 | ::StringCchCatW(dstPathname, MAX_PATH, cfg::getStr(kSessionExtension)); 117 | 118 | if (dlg::getCheck(hDlg, IDC_NEW_RAD_EMPTY)) { 119 | succ = newAsEmpty(dstPathname); 120 | } 121 | else if (dlg::getCheck(hDlg, IDC_NEW_RAD_OPEN)) { 122 | succ = newFromOpen(dstPathname); 123 | } 124 | else { 125 | succ = newByCopy(dstPathname); 126 | } 127 | if (succ) { 128 | ::StringCchCopyW(_dialogData->newSessionName, SES_NAME_BUF_LEN, newName); 129 | } 130 | return succ; 131 | } 132 | 133 | /** Creates a new, empty session. */ 134 | bool newAsEmpty(LPWSTR dstPathname) 135 | { 136 | pth::createFileIfMissing(dstPathname, SES_DEFAULT_CONTENTS); 137 | return true; 138 | } 139 | 140 | /** Creates a new session containing the currently open files. */ 141 | bool newFromOpen(LPWSTR dstPathname) 142 | { 143 | ::SendMessage(sys_getNppHandle(), NPPM_SAVECURRENTSESSION, 0, (LPARAM)dstPathname); 144 | return true; 145 | } 146 | 147 | /** Creates a new session by copying the selected session. */ 148 | bool newByCopy(LPWSTR dstPathname) 149 | { 150 | bool status = false; 151 | WCHAR srcPathname[MAX_PATH]; 152 | 153 | // Set the source file pathname. 154 | app_getSessionFile(_dialogData->selectedSessionIndex, srcPathname); 155 | // Copy the file. 156 | _dialogData->newSessionName[0] = 0; 157 | if (::CopyFileW(srcPathname, dstPathname, TRUE)) { 158 | status = true; 159 | } 160 | else { 161 | DWORD le = ::GetLastError(); 162 | msg::error(le, L"%s: Error copying from \"%s\" to \"%s\".", _W(__FUNCTION__), srcPathname, dstPathname); 163 | } 164 | return status; 165 | } 166 | 167 | } // end namespace 168 | 169 | } // end namespace NppPlugin 170 | -------------------------------------------------------------------------------- /src/DlgNew.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file DlgNew.h 13 | @copyright Copyright 2011,2014,2015 Michael Foster 14 | */ 15 | 16 | #ifndef NPP_PLUGIN_DLGNEW_H 17 | #define NPP_PLUGIN_DLGNEW_H 18 | 19 | //------------------------------------------------------------------------------ 20 | 21 | namespace NppPlugin { 22 | 23 | INT_PTR CALLBACK dlgNew_msgProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam); 24 | 25 | } // end namespace NppPlugin 26 | 27 | #endif // NPP_PLUGIN_DLGNEW_H 28 | -------------------------------------------------------------------------------- /src/DlgRename.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file DlgRename.cpp 13 | @copyright Copyright 2011-2015 Michael Foster 14 | 15 | The "Rename Session" dialog. 16 | */ 17 | 18 | #include "System.h" 19 | #include "SessionMgr.h" 20 | #include "DlgSessions.h" 21 | #include "DlgRename.h" 22 | #include "Util.h" 23 | #include "res\resource.h" 24 | #include 25 | 26 | //------------------------------------------------------------------------------ 27 | 28 | namespace NppPlugin { 29 | 30 | //------------------------------------------------------------------------------ 31 | 32 | namespace { 33 | 34 | ChildDialogData *_dialogData; 35 | 36 | void onInit(HWND hDlg); 37 | bool onOk(HWND hDlg); 38 | 39 | } // end namespace 40 | 41 | //------------------------------------------------------------------------------ 42 | 43 | INT_PTR CALLBACK dlgRen_msgProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam) 44 | { 45 | INT_PTR status = FALSE; 46 | 47 | if (uMessage == WM_COMMAND) { 48 | switch (LOWORD(wParam)) { 49 | 50 | case IDOK: 51 | if (onOk(hDlg)) { 52 | ::EndDialog(hDlg, 1); 53 | status = TRUE; 54 | } 55 | break; 56 | 57 | case IDCANCEL: 58 | ::EndDialog(hDlg, 0); 59 | status = TRUE; 60 | break; 61 | } 62 | } 63 | else if (uMessage == WM_INITDIALOG) { 64 | _dialogData = (ChildDialogData*)lParam; 65 | onInit(hDlg); 66 | } 67 | 68 | return status; 69 | } 70 | 71 | //------------------------------------------------------------------------------ 72 | 73 | namespace { 74 | 75 | void onInit(HWND hDlg) 76 | { 77 | dlg::setText(hDlg, IDC_REN_ETX_NAME, app_getSessionName(_dialogData->selectedSessionIndex)); 78 | dlg::focus(hDlg, IDC_REN_ETX_NAME); 79 | dlg::centerWnd(hDlg, NULL, 150, -35); 80 | ::ShowWindow(hDlg, SW_SHOW); 81 | } 82 | 83 | bool onOk(HWND hDlg) 84 | { 85 | bool status = false; 86 | WCHAR srcPathname[MAX_PATH]; 87 | WCHAR dstPathname[MAX_PATH]; 88 | WCHAR newName[SES_NAME_BUF_LEN]; 89 | 90 | // Set the destination file pathname. 91 | newName[0] = 0; 92 | dlg::getText(hDlg, IDC_REN_ETX_NAME, newName, SES_NAME_BUF_LEN); 93 | if (newName[0] == 0) { 94 | msg::show(L"Missing file name.", M_WARN); 95 | return false; 96 | } 97 | ::StringCchCopyW(dstPathname, MAX_PATH, cfg::getStr(kSessionDirectory)); 98 | ::StringCchCatW(dstPathname, MAX_PATH, newName); 99 | ::StringCchCatW(dstPathname, MAX_PATH, cfg::getStr(kSessionExtension)); 100 | 101 | // Set the source file that will be renamed. 102 | app_getSessionFile(_dialogData->selectedSessionIndex, srcPathname); 103 | 104 | // Rename the file. 105 | _dialogData->newSessionName[0] = 0; 106 | if (::MoveFileExW(srcPathname, dstPathname, 0)) { 107 | ::StringCchCopyW(_dialogData->newSessionName, SES_NAME_BUF_LEN, newName); 108 | status = true; 109 | } 110 | else { 111 | DWORD le = ::GetLastError(); 112 | msg::error(le, L"%s: Error renaming from \"%s\" to \"%s\".", _W(__FUNCTION__), srcPathname, dstPathname); 113 | } 114 | 115 | return status; 116 | } 117 | 118 | } // end namespace 119 | 120 | } // end namespace NppPlugin 121 | -------------------------------------------------------------------------------- /src/DlgRename.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file DlgRename.h 13 | @copyright Copyright 2011,2014,2015 Michael Foster 14 | */ 15 | 16 | #ifndef NPP_PLUGIN_DLGRENAME_H 17 | #define NPP_PLUGIN_DLGRENAME_H 18 | 19 | //------------------------------------------------------------------------------ 20 | 21 | namespace NppPlugin { 22 | 23 | INT_PTR CALLBACK dlgRen_msgProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam); 24 | 25 | } // end namespace NppPlugin 26 | 27 | #endif // NPP_PLUGIN_DLGRENAME_H 28 | -------------------------------------------------------------------------------- /src/DlgSessions.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file DlgSessions.h 13 | @copyright Copyright 2011,2014,2015 Michael Foster 14 | */ 15 | 16 | #ifndef NPP_PLUGIN_DLGSESSIONS_H 17 | #define NPP_PLUGIN_DLGSESSIONS_H 18 | 19 | //------------------------------------------------------------------------------ 20 | 21 | namespace NppPlugin { 22 | 23 | typedef struct ChildDialogData_tag { 24 | INT selectedSessionIndex; ///< passed to child 25 | WCHAR newSessionName[SES_NAME_BUF_LEN]; ///< returned from child 26 | } ChildDialogData; 27 | 28 | INT_PTR CALLBACK dlgSes_msgProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam); 29 | 30 | } // end namespace NppPlugin 31 | 32 | #endif // NPP_PLUGIN_DLGSESSIONS_H 33 | -------------------------------------------------------------------------------- /src/DlgSettings.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file DlgSettings.cpp 13 | @copyright Copyright 2011-2015 Michael Foster 14 | 15 | The "Settings" dialog. 16 | */ 17 | 18 | #include "System.h" 19 | #include "SessionMgr.h" 20 | #include "DlgSettings.h" 21 | #include "Util.h" 22 | #include "ContextMenu.h" 23 | #include "res\resource.h" 24 | #include 25 | #include 26 | 27 | //------------------------------------------------------------------------------ 28 | 29 | namespace NppPlugin { 30 | 31 | //------------------------------------------------------------------------------ 32 | 33 | namespace { 34 | 35 | INT _minWidth = 0, _minHeight = 0; 36 | bool _inInit, _opChanged, _dirChanged; 37 | 38 | void onInit(HWND hDlg); 39 | void closeDialog(HWND hDlg, INT_PTR nResult); 40 | INT onOk(HWND hDlg); 41 | void onResize(HWND hDlg, INT w = 0, INT h = 0); 42 | void onGetMinSize(HWND hDlg, LPMINMAXINFO p); 43 | bool getFolderName(HWND parent, LPWSTR buf); 44 | 45 | } // end namespace 46 | 47 | //------------------------------------------------------------------------------ 48 | 49 | INT_PTR CALLBACK dlgCfg_msgProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam) 50 | { 51 | INT okStatus; 52 | INT_PTR status = FALSE; 53 | 54 | if (uMessage == WM_COMMAND) { 55 | WORD ctrl = LOWORD(wParam); 56 | WORD ntfy = HIWORD(wParam); 57 | switch (ctrl) { 58 | case IDOK: 59 | okStatus = onOk(hDlg); 60 | if (okStatus == 2) { 61 | msg::show(L"An error occurred while creating the new session directory.\nThis setting was not changed.", M_WARN); 62 | } 63 | closeDialog(hDlg, 1); 64 | status = TRUE; 65 | break; 66 | case IDCANCEL: 67 | closeDialog(hDlg, 0); 68 | status = TRUE; 69 | break; 70 | case IDC_CFG_CHK_ASV: 71 | case IDC_CFG_CHK_ALD: 72 | case IDC_CFG_CHK_LIC: 73 | case IDC_CFG_CHK_LWC: 74 | case IDC_CFG_CHK_SITB: 75 | case IDC_CFG_CHK_SISB: 76 | case IDC_CFG_CHK_GBKM: 77 | if (!_inInit && ntfy == BN_CLICKED) { 78 | _opChanged = true; 79 | } 80 | status = TRUE; 81 | break; 82 | case IDC_CFG_CHK_CTXM: 83 | if (!_inInit && ntfy == BN_CLICKED) { 84 | _opChanged = true; 85 | if (cfg::getBool(kUseContextMenu) && !dlg::getCheck(hDlg, IDC_CFG_CHK_CTXM)) { 86 | ctx::unload(); 87 | } 88 | } 89 | status = TRUE; 90 | break; 91 | case IDC_CFG_ETX_DIR: 92 | case IDC_CFG_ETX_EXT: 93 | if (!_inInit && ntfy == EN_CHANGE) { 94 | _dirChanged = true; 95 | } 96 | status = TRUE; 97 | break; 98 | case IDC_CFG_BTN_BRW: 99 | if (!_inInit && ntfy == BN_CLICKED) { 100 | WCHAR pthBuf[MAX_PATH]; 101 | if (getFolderName(hDlg, pthBuf)) { 102 | _dirChanged = true; 103 | dlg::setText(hDlg, IDC_CFG_ETX_DIR, pthBuf); 104 | } 105 | } 106 | status = TRUE; 107 | break; 108 | } // end switch 109 | } 110 | else if (uMessage == WM_WINDOWPOSCHANGED) { 111 | LPWINDOWPOS wp = (LPWINDOWPOS)lParam; 112 | if (!(wp->flags & SWP_NOSIZE)) { 113 | onResize(hDlg); 114 | } 115 | } 116 | else if (uMessage == WM_GETMINMAXINFO) { 117 | onGetMinSize(hDlg, (LPMINMAXINFO)lParam); 118 | } 119 | else if (uMessage == WM_INITDIALOG) { 120 | onInit(hDlg); 121 | } 122 | 123 | return status; 124 | } 125 | 126 | //------------------------------------------------------------------------------ 127 | 128 | namespace { 129 | 130 | /** Determines minimum dialog size. Populates controls with current values from 131 | settings. Resizes, centers and displays the dialog window. */ 132 | void onInit(HWND hDlg) 133 | { 134 | RECT r; 135 | 136 | LOG("Opening settings dialog."); 137 | _inInit = true; 138 | _opChanged = false; 139 | _dirChanged = false; 140 | if (_minWidth == 0) { 141 | ::GetWindowRect(hDlg, &r); 142 | _minWidth = r.right - r.left; 143 | _minHeight = r.bottom - r.top; 144 | } 145 | // init control values 146 | dlg::setCheck(hDlg, IDC_CFG_CHK_ASV, cfg::getBool(kAutomaticSave)); 147 | dlg::setCheck(hDlg, IDC_CFG_CHK_ALD, cfg::getBool(kAutomaticLoad)); 148 | dlg::setCheck(hDlg, IDC_CFG_CHK_LIC, cfg::getBool(kLoadIntoCurrent)); 149 | dlg::setCheck(hDlg, IDC_CFG_CHK_LWC, cfg::getBool(kLoadWithoutClosing)); 150 | dlg::setCheck(hDlg, IDC_CFG_CHK_SITB, cfg::getBool(kShowInTitlebar)); 151 | dlg::setCheck(hDlg, IDC_CFG_CHK_SISB, cfg::getBool(kShowInStatusbar)); 152 | dlg::setCheck(hDlg, IDC_CFG_CHK_GBKM, cfg::getBool(kUseGlobalProperties)); 153 | dlg::setCheck(hDlg, IDC_CFG_CHK_CTXM, cfg::getBool(kUseContextMenu)); 154 | dlg::setText(hDlg, IDC_CFG_ETX_DIR, cfg::getStr(kSessionDirectory)); 155 | dlg::setText(hDlg, IDC_CFG_ETX_EXT, cfg::getStr(kSessionExtension)); 156 | // focus the first edit control 157 | dlg::focus(hDlg, IDC_CFG_ETX_DIR); 158 | // resize, center and show the window 159 | INT w = cfg::getInt(kSettingsDialogWidth), h = cfg::getInt(kSettingsDialogHeight); 160 | if (w <= 0 || h <= 0) { 161 | w = 0; 162 | h = 0; 163 | } 164 | dlg::centerWnd(hDlg, sys_getNppHandle(), 0, 0, w, h, true); 165 | onResize(hDlg); 166 | ::ShowWindow(hDlg, SW_SHOW); 167 | _inInit = false; 168 | } 169 | 170 | void closeDialog(HWND hDlg, INT_PTR nResult) 171 | { 172 | LOG("Closing settings dialog with %u.", nResult); 173 | ::EndDialog(hDlg, nResult); 174 | } 175 | 176 | /** Gets values, if changed, from dialog box controls. Updates the global 177 | config object and save them to the ini file. */ 178 | INT onOk(HWND hDlg) 179 | { 180 | INT stat = 0; 181 | bool change = false; 182 | WCHAR buf[MAX_PATH]; 183 | 184 | if (_opChanged) { 185 | change = true; 186 | cfg::putBool(kAutomaticSave, dlg::getCheck(hDlg, IDC_CFG_CHK_ASV)); 187 | cfg::putBool(kAutomaticLoad, dlg::getCheck(hDlg, IDC_CFG_CHK_ALD)); 188 | cfg::putBool(kLoadIntoCurrent, dlg::getCheck(hDlg, IDC_CFG_CHK_LIC)); 189 | cfg::putBool(kLoadWithoutClosing, dlg::getCheck(hDlg, IDC_CFG_CHK_LWC)); 190 | cfg::putBool(kShowInTitlebar, dlg::getCheck(hDlg, IDC_CFG_CHK_SITB)); 191 | cfg::putBool(kShowInStatusbar, dlg::getCheck(hDlg, IDC_CFG_CHK_SISB)); 192 | cfg::putBool(kUseGlobalProperties, dlg::getCheck(hDlg, IDC_CFG_CHK_GBKM)); 193 | cfg::putBool(kUseContextMenu, dlg::getCheck(hDlg, IDC_CFG_CHK_CTXM)); 194 | } 195 | if (_dirChanged) { 196 | change = true; 197 | dlg::getText(hDlg, IDC_CFG_ETX_DIR, buf, MAX_PATH); 198 | if (!cfg::setSessionDirectory(buf)) { 199 | stat = 2; // error creating ses dir 200 | } 201 | dlg::getText(hDlg, IDC_CFG_ETX_EXT, buf, MAX_PATH); 202 | cfg::setSessionExtension(buf); 203 | } 204 | 205 | if (change) { 206 | cfg::saveSettings(); 207 | if (_dirChanged) { 208 | app_readSessionDirectory(); 209 | } 210 | } 211 | else { 212 | stat = 1; // no changes 213 | } 214 | 215 | return stat; 216 | } 217 | 218 | /** Resizes and repositions dialog controls. */ 219 | void onResize(HWND hDlg, INT dlgW, INT dlgH) 220 | { 221 | RECT r; 222 | 223 | if (dlgW == 0) { 224 | ::GetClientRect(hDlg, &r); 225 | dlgW = r.right; 226 | dlgH = r.bottom; 227 | } 228 | // Resize the Directory and Extension edit boxes 229 | dlg::adjToEdge(hDlg, IDC_CFG_ETX_DIR, dlgW, dlgH, 4, IDC_CFG_ETX_WRO, 0); 230 | dlg::adjToEdge(hDlg, IDC_CFG_ETX_EXT, dlgW, dlgH, 4, IDC_CFG_ETX_WRO, 0); 231 | // Move the OK and Cancel buttons 232 | dlg::adjToEdge(hDlg, IDOK, dlgW, dlgH, 1|2, IDC_CFG_BTN_OK_XRO, IDC_CFG_BTN_YBO); 233 | dlg::adjToEdge(hDlg, IDCANCEL, dlgW, dlgH, 1|2, IDC_CFG_BTN_CAN_XRO, IDC_CFG_BTN_YBO, true); 234 | // Save new dialog size 235 | ::GetWindowRect(hDlg, &r); 236 | cfg::putInt(kSettingsDialogWidth, r.right - r.left); 237 | cfg::putInt(kSettingsDialogHeight, r.bottom - r.top); 238 | } 239 | 240 | /** Sets the minimum size the user can resize to. */ 241 | void onGetMinSize(HWND hDlg, LPMINMAXINFO p) 242 | { 243 | p->ptMinTrackSize.x = _minWidth; 244 | p->ptMinTrackSize.y = _minHeight; 245 | } 246 | 247 | /** Copied and slightly modifed from: npp.6.2.3.src\PowerEditor\src\MISC\Common\Common.cpp */ 248 | bool getFolderName(HWND parent, LPWSTR buf) 249 | { 250 | bool ok = false; 251 | LPMALLOC pShellMalloc = 0; 252 | 253 | if (::SHGetMalloc(&pShellMalloc) == NO_ERROR) { 254 | BROWSEINFOW info; 255 | ::memset(&info, 0, sizeof(info)); 256 | info.hwndOwner = parent; 257 | info.pidlRoot = NULL; 258 | WCHAR displayName[MAX_PATH]; 259 | info.pszDisplayName = displayName; 260 | info.lpszTitle = L"Select a sessions folder"; 261 | info.ulFlags = BIF_NEWDIALOGSTYLE; 262 | LPITEMIDLIST pidl = ::SHBrowseForFolderW(&info); 263 | // pidl will be null if they cancel the browse dialog, else not null if they select a folder. 264 | if (pidl) { 265 | if (::SHGetPathFromIDListW(pidl, buf)) { 266 | ok = true; 267 | } 268 | pShellMalloc->Free(pidl); 269 | } 270 | pShellMalloc->Release(); 271 | } 272 | return ok; 273 | } 274 | 275 | } // end namespace 276 | 277 | } // end namespace NppPlugin 278 | -------------------------------------------------------------------------------- /src/DlgSettings.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file DlgSettings.h 13 | @copyright Copyright 2011,2014,2015 Michael Foster 14 | */ 15 | 16 | #ifndef NPP_PLUGIN_DLGSETTINGS_H 17 | #define NPP_PLUGIN_DLGSETTINGS_H 18 | 19 | //------------------------------------------------------------------------------ 20 | 21 | namespace NppPlugin { 22 | 23 | INT_PTR CALLBACK dlgCfg_msgProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam); 24 | 25 | } // end namespace NppPlugin 26 | 27 | #endif // NPP_PLUGIN_DLGSETTINGS_H 28 | -------------------------------------------------------------------------------- /src/DllMain.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file DllMain.cpp 13 | @copyright Copyright 2011,2014,2015 Michael Foster 14 | 15 | The DLL entry point. 16 | */ 17 | 18 | #include "System.h" 19 | #include "SessionMgr.h" 20 | #include "Menu.h" 21 | #include "Settings.h" 22 | #include "Properties.h" 23 | #include "ContextMenu.h" 24 | 25 | using namespace NppPlugin::api; 26 | 27 | //------------------------------------------------------------------------------ 28 | 29 | namespace { 30 | 31 | INT _dllCount = 0; 32 | 33 | } // end namespace 34 | 35 | //------------------------------------------------------------------------------ 36 | 37 | BOOL APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) 38 | { 39 | switch (dwReason) { 40 | case DLL_PROCESS_ATTACH: 41 | if (++_dllCount == 1) { 42 | sys_onLoad(hInstance); 43 | app_onLoad(); 44 | mnu_onLoad(); 45 | } 46 | break; 47 | case DLL_PROCESS_DETACH: 48 | if (--_dllCount == 0) { 49 | ctx_onUnload(); 50 | mnu_onUnload(); 51 | app_onUnload(); 52 | cfg_onUnload(); 53 | sys_onUnload(); 54 | } 55 | break; 56 | } 57 | 58 | return TRUE; 59 | } 60 | 61 | extern "C" __declspec(dllexport) void setInfo(NppData nppd) 62 | { 63 | sys_init(nppd); 64 | app_init(); 65 | mnu_init(); 66 | prp_init(); 67 | } 68 | 69 | extern "C" __declspec(dllexport) LPCWSTR getName() 70 | { 71 | return app_getName(); 72 | } 73 | 74 | extern "C" __declspec(dllexport) FuncItem* getFuncsArray(INT *pnbFuncItems) 75 | { 76 | return mnu_getItems(pnbFuncItems); 77 | } 78 | 79 | extern "C" __declspec(dllexport) void beNotified(SCNotification *pscn) 80 | { 81 | app_onNotify(pscn); 82 | } 83 | 84 | extern "C" __declspec(dllexport) LRESULT messageProc(UINT Message, WPARAM wParam, LPARAM lParam) 85 | { 86 | return app_msgProc(Message, wParam, lParam); 87 | } 88 | 89 | extern "C" __declspec(dllexport) BOOL isUnicode() 90 | { 91 | return TRUE; 92 | } 93 | -------------------------------------------------------------------------------- /src/Menu.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file Menu.cpp 13 | @copyright Copyright 2011,2013-2015 Michael Foster 14 | 15 | Session Manager creates a submenu in the Notepad++ Plugins menu. Those items 16 | can be customized via settings. Favorite sessions are listed after the About 17 | item. 18 | */ 19 | 20 | #include "System.h" 21 | #include "SessionMgr.h" 22 | #include "DlgSessions.h" 23 | #include "DlgSettings.h" 24 | #include "Menu.h" 25 | #include "Util.h" 26 | #include "res\resource.h" 27 | #include 28 | 29 | //------------------------------------------------------------------------------ 30 | 31 | namespace NppPlugin { 32 | 33 | //------------------------------------------------------------------------------ 34 | 35 | namespace { 36 | 37 | #define PLUGIN_ABOUT PLUGIN_FULL_NAME SPACE_STR PLUGIN_VERSION L"\nA plugin for Notepad++\nhttp://mfoster.com/npp/" 38 | #define HELP_FILE_SUFFIX L"doc\\" PLUGIN_DLL_NAME L".html" 39 | 40 | /// Menu callback functions 41 | extern "C" { 42 | void cbSessions(); 43 | void cbSettings(); 44 | void cbSaveCurrent(); 45 | void cbLoadPrevious(); 46 | void cbHelp(); 47 | void cbAbout(); 48 | void cbFav1(); 49 | void cbFav2(); 50 | void cbFav3(); 51 | void cbFav4(); 52 | void cbFav5(); 53 | void cbFav6(); 54 | void cbFav7(); 55 | void cbFav8(); 56 | void cbFav9(); 57 | void cbFav10(); 58 | void cbFav11(); 59 | void cbFav12(); 60 | void cbFav13(); 61 | void cbFav14(); 62 | void cbFav15(); 63 | void cbFav16(); 64 | void cbFav17(); 65 | void cbFav18(); 66 | void cbFav19(); 67 | void cbFav20(); 68 | }; 69 | 70 | /// Menu config 71 | INT _menuItemsCount = MNU_BASE_MAX_ITEMS; 72 | WCHAR _menuMainLabel[MNU_MAX_NAME_LEN + 1]; 73 | FuncItem _menuItems[] = { 74 | { EMPTY_STR, cbSessions, 0, false, NULL }, 75 | { EMPTY_STR, cbSettings, 0, false, NULL }, 76 | { EMPTY_STR, cbSaveCurrent, 0, false, NULL }, 77 | { EMPTY_STR, cbLoadPrevious, 0, false, NULL }, 78 | { EMPTY_STR, NULL, 0, false, NULL }, 79 | { EMPTY_STR, cbHelp, 0, false, NULL }, 80 | { EMPTY_STR, cbAbout, 0, false, NULL }, 81 | { EMPTY_STR, NULL, 0, false, NULL }, 82 | { EMPTY_STR, cbFav1, 0, false, NULL }, 83 | { EMPTY_STR, cbFav2, 0, false, NULL }, 84 | { EMPTY_STR, cbFav3, 0, false, NULL }, 85 | { EMPTY_STR, cbFav4, 0, false, NULL }, 86 | { EMPTY_STR, cbFav5, 0, false, NULL }, 87 | { EMPTY_STR, cbFav6, 0, false, NULL }, 88 | { EMPTY_STR, cbFav7, 0, false, NULL }, 89 | { EMPTY_STR, cbFav8, 0, false, NULL }, 90 | { EMPTY_STR, cbFav9, 0, false, NULL }, 91 | { EMPTY_STR, cbFav10, 0, false, NULL }, 92 | { EMPTY_STR, cbFav11, 0, false, NULL }, 93 | { EMPTY_STR, cbFav12, 0, false, NULL }, 94 | { EMPTY_STR, cbFav13, 0, false, NULL }, 95 | { EMPTY_STR, cbFav14, 0, false, NULL }, 96 | { EMPTY_STR, cbFav15, 0, false, NULL }, 97 | { EMPTY_STR, cbFav16, 0, false, NULL }, 98 | { EMPTY_STR, cbFav17, 0, false, NULL }, 99 | { EMPTY_STR, cbFav18, 0, false, NULL }, 100 | { EMPTY_STR, cbFav19, 0, false, NULL }, 101 | { EMPTY_STR, cbFav20, 0, false, NULL } 102 | }; 103 | 104 | } // end namespace 105 | 106 | //------------------------------------------------------------------------------ 107 | 108 | namespace api { 109 | 110 | void mnu_onLoad() 111 | { 112 | } 113 | 114 | void mnu_onUnload() 115 | { 116 | } 117 | 118 | void mnu_init() 119 | { 120 | INT mnuIdx, cfgIdx = 0; 121 | 122 | // plugin menu 123 | cfg::getStr(kMenuLabelMain, _menuMainLabel, MNU_MAX_NAME_LEN); 124 | cfg::getStr(kMenuLabelSub1, _menuItems[0]._itemName, MNU_MAX_NAME_LEN); 125 | cfg::getStr(kMenuLabelSub2, _menuItems[1]._itemName, MNU_MAX_NAME_LEN); 126 | cfg::getStr(kMenuLabelSub3, _menuItems[2]._itemName, MNU_MAX_NAME_LEN); 127 | cfg::getStr(kMenuLabelSub4, _menuItems[3]._itemName, MNU_MAX_NAME_LEN); 128 | cfg::getStr(kMenuLabelSub5, _menuItems[5]._itemName, MNU_MAX_NAME_LEN); 129 | cfg::getStr(kMenuLabelSub6, _menuItems[6]._itemName, MNU_MAX_NAME_LEN); 130 | // favorites 131 | cfgIdx = 0; 132 | for (mnuIdx = MNU_FIRST_FAV_IDX; mnuIdx <= MNU_LAST_FAV_IDX; ++mnuIdx) { 133 | if (!cfg::getStr(kFavorites, cfgIdx++, _menuItems[mnuIdx]._itemName, MNU_MAX_NAME_LEN)) { 134 | break; 135 | } 136 | ++_menuItemsCount; 137 | } 138 | if (cfgIdx > 0) { 139 | ++_menuItemsCount; // for the 2nd separator if any fav was added 140 | } 141 | } 142 | 143 | FuncItem* mnu_getItems(INT *pNum) 144 | { 145 | *pNum = _menuItemsCount; 146 | return _menuItems; 147 | } 148 | 149 | } // end namespace NppPlugin::api 150 | 151 | //------------------------------------------------------------------------------ 152 | 153 | /** @return a pointer to the main or the 0-based mnuIdx'th sub label. */ 154 | LPCWSTR mnu_getMenuLabel(INT mnuIdx) 155 | { 156 | LPCWSTR lbl = NULL; 157 | 158 | if (mnuIdx == -1) { 159 | lbl = _menuMainLabel; 160 | } 161 | else if (mnuIdx >= 0 && mnuIdx < MNU_BASE_MAX_ITEMS) { 162 | lbl = _menuItems[mnuIdx]._itemName; 163 | } 164 | return lbl; 165 | } 166 | 167 | //------------------------------------------------------------------------------ 168 | 169 | namespace { 170 | 171 | extern "C" void cbSessions() 172 | { 173 | app_readSessionDirectory(); 174 | ::DialogBox(sys_getDllHandle(), MAKEINTRESOURCE(IDD_SES_DLG), sys_getNppHandle(), dlgSes_msgProc); 175 | } 176 | 177 | extern "C" void cbSettings() 178 | { 179 | ::DialogBox(sys_getDllHandle(), MAKEINTRESOURCE(IDD_CFG_DLG), sys_getNppHandle(), dlgCfg_msgProc); 180 | } 181 | 182 | extern "C" void cbSaveCurrent() 183 | { 184 | app_saveSession(SI_CURRENT); 185 | } 186 | 187 | extern "C" void cbLoadPrevious() 188 | { 189 | app_loadSession(SI_PREVIOUS); 190 | } 191 | 192 | extern "C" void cbHelp() 193 | { 194 | WCHAR helpFile[MAX_PATH]; 195 | 196 | ::GetModuleFileNameW((HMODULE)sys_getDllHandle(), helpFile, MAX_PATH); 197 | pth::removeName(helpFile, MAX_PATH); 198 | ::StringCchCatW(helpFile, MAX_PATH, HELP_FILE_SUFFIX); 199 | 200 | HINSTANCE h = ::ShellExecuteW(NULL, L"open", helpFile, NULL, NULL, SW_SHOW); 201 | if ((int)h <= 32) { 202 | DWORD le = ::GetLastError(); 203 | msg::error(le, L"%s: Error shelling to default browser.", _W(__FUNCTION__)); 204 | } 205 | } 206 | 207 | extern "C" void cbAbout() 208 | { 209 | const size_t s = 450; 210 | WCHAR m[s]; 211 | 212 | ::StringCchCopyW(m, s, PLUGIN_ABOUT); 213 | ::StringCchCatW(m, s, L"\n\nSpecial thanks to....\n\n- Don Ho and team, for Notepad++\n- You! for using Session Manager\n- Dave Brotherstone, for PluginManager\n- Jack Handy, for wildcardMatch\n- Jens Lorenz and Thell Fowler, for example code\n- Julien Audo, for ResEdit\n- Lee Thomason, for TinyXML2\n- Nemanja Trifunovic, for UTF8-CPP\n- Users at the plugin forum, for testing and feedback"); 214 | msg::show(m, L"About Session Manager", MB_ICONINFORMATION); 215 | //LOG("strlen = %u", ::wcslen(m)); 216 | } 217 | 218 | void loadFavorite(INT mnuOfs) 219 | { 220 | app_loadSession(app_getSessionIndex(_menuItems[mnuOfs + MNU_BASE_MAX_ITEMS]._itemName)); 221 | } 222 | 223 | extern "C" void cbFav1() { loadFavorite(1); } 224 | extern "C" void cbFav2() { loadFavorite(2); } 225 | extern "C" void cbFav3() { loadFavorite(3); } 226 | extern "C" void cbFav4() { loadFavorite(4); } 227 | extern "C" void cbFav5() { loadFavorite(5); } 228 | extern "C" void cbFav6() { loadFavorite(6); } 229 | extern "C" void cbFav7() { loadFavorite(7); } 230 | extern "C" void cbFav8() { loadFavorite(8); } 231 | extern "C" void cbFav9() { loadFavorite(9); } 232 | extern "C" void cbFav10() { loadFavorite(10); } 233 | extern "C" void cbFav11() { loadFavorite(11); } 234 | extern "C" void cbFav12() { loadFavorite(12); } 235 | extern "C" void cbFav13() { loadFavorite(13); } 236 | extern "C" void cbFav14() { loadFavorite(14); } 237 | extern "C" void cbFav15() { loadFavorite(15); } 238 | extern "C" void cbFav16() { loadFavorite(16); } 239 | extern "C" void cbFav17() { loadFavorite(17); } 240 | extern "C" void cbFav18() { loadFavorite(18); } 241 | extern "C" void cbFav19() { loadFavorite(19); } 242 | extern "C" void cbFav20() { loadFavorite(20); } 243 | 244 | } // end namespace 245 | 246 | } // end namespace NppPlugin 247 | -------------------------------------------------------------------------------- /src/Menu.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file Menu.h 13 | @copyright Copyright 2011,2013-2015 Michael Foster 14 | */ 15 | 16 | #ifndef NPP_PLUGIN_MENU_H 17 | #define NPP_PLUGIN_MENU_H 18 | 19 | //------------------------------------------------------------------------------ 20 | 21 | namespace NppPlugin { 22 | 23 | const int MNU_BASE_MAX_ITEMS = 7; ///< see _menuItemsCount 24 | const int MNU_MAX_FAVS = 20; 25 | const int MNU_FIRST_FAV_IDX = MNU_BASE_MAX_ITEMS + 1; 26 | const int MNU_LAST_FAV_IDX = MNU_BASE_MAX_ITEMS + MNU_MAX_FAVS; 27 | const int MNU_MAX_NAME_LEN = 63; ///< see nbChar in npp\PluginInterface.h 28 | 29 | //------------------------------------------------------------------------------ 30 | /// @namespace NppPlugin::api Contains functions called only from DllMain. 31 | 32 | namespace api { 33 | 34 | void mnu_onLoad(); 35 | void mnu_onUnload(); 36 | void mnu_init(); 37 | FuncItem* mnu_getItems(INT *pNum); 38 | 39 | } // end namespace NppPlugin::api 40 | 41 | //------------------------------------------------------------------------------ 42 | 43 | LPCWSTR mnu_getMenuLabel(INT mnuIdx = -1); 44 | 45 | } // end namespace NppPlugin 46 | 47 | #endif // NPP_PLUGIN_MENU_H 48 | -------------------------------------------------------------------------------- /src/Properties.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file Properties.cpp 13 | @copyright Copyright 2014,2015 Michael Foster 14 | 15 | Notepad++ saves a file's bookmarks (and other properties) in the session 16 | file, so the same file in different sessions will not have the same 17 | bookmarks. Session Manager can keep files' bookmarks (and a little more) 18 | synchronized across different sessions. These are referred to as "global 19 | properties". The file "global.xml", in the Session Manager configuration 20 | directory, stores bookmarks, firstVisibleLine and language for each unique 21 | pathname in all sessions. 22 | */ 23 | 24 | #include "System.h" 25 | #include "Properties.h" 26 | #include "Util.h" 27 | 28 | //------------------------------------------------------------------------------ 29 | 30 | namespace NppPlugin { 31 | 32 | //------------------------------------------------------------------------------ 33 | 34 | namespace { 35 | 36 | /// XML nodes 37 | #define XN_NOTEPADPLUS "NotepadPlus" ///< root node 38 | #define XN_SESSION "Session" 39 | #define XN_MAINVIEW "mainView" 40 | #define XN_SUBVIEW "subView" 41 | #define XN_FILE "File" 42 | #define XN_MARK "Mark" 43 | #define XN_FOLD "Fold" 44 | #define XN_FILEPROPERTIES "FileProperties" 45 | 46 | /// XML attributes 47 | #define XA_FILENAME "filename" 48 | #define XA_LANG "lang" 49 | #define XA_FIRSTVISIBLELINE "firstVisibleLine" 50 | #define XA_LINE "line" 51 | 52 | void removeMissingFilesFromGlobal(); 53 | void deleteChildren(tXmlEleP parent, LPCSTR eleName); 54 | 55 | } // end namespace 56 | 57 | //------------------------------------------------------------------------------ 58 | 59 | namespace api { 60 | 61 | void prp_init() 62 | { 63 | if (cfg::getBool(kCleanGlobalProperties)) { 64 | removeMissingFilesFromGlobal(); 65 | } 66 | } 67 | 68 | } // end namespace NppPlugin::api 69 | 70 | //------------------------------------------------------------------------------ 71 | 72 | namespace prp { 73 | 74 | /** Updates global file properties from local (session) file properties. 75 | After a session is saved, the global bookmarks, firstVisibleLine and 76 | language are updated from the session properties. */ 77 | void updateGlobalFromSession(LPWSTR sesFile) 78 | { 79 | DWORD lastErr; 80 | tXmlError xmlErr; 81 | LPCSTR target; 82 | 83 | LOGF("%S", sesFile); 84 | 85 | // Load the properties file (global file properties) 86 | tXmlDoc globalDoc; 87 | xmlErr = globalDoc.LoadFile(sys_getGlobalFile()); 88 | if (xmlErr != kXmlSuccess) { 89 | lastErr = ::GetLastError(); 90 | msg::error(lastErr, L"%s: Error %u loading the global properties file.", _W(__FUNCTION__), xmlErr); 91 | return; 92 | } 93 | tXmlEleP globalPropsEle, globalFileEle, globalMarkEle, globalFoldEle; 94 | tXmlHnd globalDocHnd(&globalDoc); 95 | globalPropsEle = globalDocHnd.FirstChildElement(XN_NOTEPADPLUS).FirstChildElement(XN_FILEPROPERTIES).ToElement(); 96 | 97 | // Load the session file (file properties local to a session) 98 | tXmlDoc localDoc; 99 | xmlErr = localDoc.LoadFile(sesFile); 100 | if (xmlErr != kXmlSuccess) { 101 | lastErr = ::GetLastError(); 102 | msg::error(lastErr, L"%s: Error %u loading session file \"%s\".", _W(__FUNCTION__), xmlErr, sesFile); 103 | return; 104 | } 105 | tXmlEleP localViewEle, localFileEle, localMarkEle, localFoldEle; 106 | tXmlHnd localDocHnd(&localDoc); 107 | 108 | // Iterate over the local View elements 109 | localViewEle = localDocHnd.FirstChildElement(XN_NOTEPADPLUS).FirstChildElement(XN_SESSION).FirstChildElement(XN_MAINVIEW).ToElement(); 110 | while (localViewEle) { 111 | // Iterate over the local File elements 112 | localFileEle = localViewEle->FirstChildElement(XN_FILE); 113 | while (localFileEle) { 114 | // Find the global File element corresponding to the current local File element 115 | target = localFileEle->Attribute(XA_FILENAME); 116 | LOGG(21, "File = %s", target); 117 | globalFileEle = globalPropsEle->FirstChildElement(XN_FILE); 118 | while (globalFileEle) { 119 | if (globalFileEle->Attribute(XA_FILENAME, target)) { 120 | break; // found it 121 | } 122 | globalFileEle = globalFileEle->NextSiblingElement(XN_FILE); 123 | } 124 | if (!globalFileEle) { // not found so create one 125 | globalFileEle = globalDoc.NewElement(XN_FILE); 126 | globalFileEle->SetAttribute(XA_FILENAME, target); 127 | } 128 | globalPropsEle->InsertFirstChild(globalFileEle); // an existing element will get moved to the top 129 | // Update global File attributes with values from the current local File attributes 130 | globalFileEle->SetAttribute(XA_LANG, localFileEle->Attribute(XA_LANG)); 131 | globalFileEle->SetAttribute(XA_FIRSTVISIBLELINE, localFileEle->Attribute(XA_FIRSTVISIBLELINE)); 132 | LOGG(21, "lang = '%s', firstVisibleLine = %s", localFileEle->Attribute(XA_LANG), localFileEle->Attribute(XA_FIRSTVISIBLELINE)); 133 | // Iterate over the local Mark elements for the current local File element 134 | deleteChildren(globalFileEle, XN_MARK); 135 | localMarkEle = localFileEle->FirstChildElement(XN_MARK); 136 | while (localMarkEle) { 137 | globalMarkEle = globalDoc.NewElement(XN_MARK); 138 | globalFileEle->InsertEndChild(globalMarkEle); 139 | // Update global Mark attributes with values from the current local Mark attributes 140 | globalMarkEle->SetAttribute(XA_LINE, localMarkEle->Attribute(XA_LINE)); 141 | LOGG(21, "Mark = %s", localMarkEle->Attribute(XA_LINE)); 142 | localMarkEle = localMarkEle->NextSiblingElement(XN_MARK); 143 | } 144 | // Iterate over the local Fold elements for the current local File element 145 | deleteChildren(globalFileEle, XN_FOLD); 146 | localFoldEle = localFileEle->FirstChildElement(XN_FOLD); 147 | while (localFoldEle) { 148 | globalFoldEle = globalDoc.NewElement(XN_FOLD); 149 | globalFileEle->InsertEndChild(globalFoldEle); 150 | // Update global Fold attributes with values from the current local Fold attributes 151 | globalFoldEle->SetAttribute(XA_LINE, localFoldEle->Attribute(XA_LINE)); 152 | LOGG(21, "Fold = %s", localFoldEle->Attribute(XA_LINE)); 153 | localFoldEle = localFoldEle->NextSiblingElement(XN_FOLD); 154 | } 155 | // Next local File element 156 | localFileEle = localFileEle->NextSiblingElement(XN_FILE); 157 | } 158 | localViewEle = localViewEle->NextSiblingElement(XN_SUBVIEW); 159 | } 160 | 161 | // Add XML declaration if missing 162 | if (memcmp(globalDoc.FirstChild()->Value(), "xml", 3) != 0) { 163 | globalDoc.InsertFirstChild(globalDoc.NewDeclaration()); 164 | } 165 | // Save changes to the properties file 166 | xmlErr = globalDoc.SaveFile(sys_getGlobalFile()); 167 | if (xmlErr != kXmlSuccess) { 168 | lastErr = ::GetLastError(); 169 | msg::error(lastErr, L"%s: Error %u saving the global properties file.", _W(__FUNCTION__), xmlErr); 170 | } 171 | } 172 | 173 | /** Updates local (session) file properties from global file properties. 174 | When a session is about to be loaded, the session bookmarks and language 175 | are updated from the global properties, then the session is loaded. */ 176 | void updateSessionFromGlobal(LPWSTR sesFile) 177 | { 178 | LPSTR buf; 179 | DWORD lastErr; 180 | tXmlError xmlErr; 181 | bool save = false; 182 | LPCSTR target; 183 | 184 | LOGF("%S", sesFile); 185 | 186 | // Load the properties file (global file properties) 187 | tXmlDoc globalDoc; 188 | xmlErr = globalDoc.LoadFile(sys_getGlobalFile()); 189 | if (xmlErr != kXmlSuccess) { 190 | lastErr = ::GetLastError(); 191 | msg::error(lastErr, L"%s: Error %u loading the global properties file.", _W(__FUNCTION__), xmlErr); 192 | return; 193 | } 194 | tXmlEleP globalPropsEle, globalFileEle, globalMarkEle, globalFoldEle; 195 | tXmlHnd globalDocHnd(&globalDoc); 196 | globalPropsEle = globalDocHnd.FirstChildElement(XN_NOTEPADPLUS).FirstChildElement(XN_FILEPROPERTIES).ToElement(); 197 | 198 | // Load the session file (file properties local to a session) 199 | tXmlDoc localDoc; 200 | xmlErr = localDoc.LoadFile(sesFile); 201 | if (xmlErr != kXmlSuccess) { 202 | lastErr = ::GetLastError(); 203 | msg::error(lastErr, L"%s: Error %u loading session file \"%s\".", _W(__FUNCTION__), xmlErr, sesFile); 204 | return; 205 | } 206 | tXmlEleP localViewEle, localFileEle, localMarkEle, localFoldEle; 207 | tXmlHnd localDocHnd(&localDoc); 208 | 209 | // Iterate over the local View elements 210 | localViewEle = localDocHnd.FirstChildElement(XN_NOTEPADPLUS).FirstChildElement(XN_SESSION).FirstChildElement(XN_MAINVIEW).ToElement(); 211 | while (localViewEle) { 212 | // Iterate over the local File elements 213 | localFileEle = localViewEle->FirstChildElement(XN_FILE); 214 | while (localFileEle) { 215 | // Find the global File element corresponding to the current local File element 216 | target = localFileEle->Attribute(XA_FILENAME); 217 | LOGG(22, "File = %s", target); 218 | globalFileEle = globalPropsEle->FirstChildElement(XN_FILE); 219 | while (globalFileEle) { 220 | if (globalFileEle->Attribute(XA_FILENAME, target)) { 221 | break; // found it 222 | } 223 | globalFileEle = globalFileEle->NextSiblingElement(XN_FILE); 224 | } 225 | if (globalFileEle) { 226 | save = true; 227 | // Update current local File attributes with values from the global File attributes 228 | buf = (LPSTR)sys_alloc(str::utf8ToAscii(target) * sizeof CHAR); 229 | if (buf == NULL) { 230 | return; 231 | } 232 | str::utf8ToAscii(target, buf); // NPP expects the pathname to be encoded like this 233 | localFileEle->SetAttribute(XA_FILENAME, buf); 234 | sys_free(buf); 235 | localFileEle->SetAttribute(XA_LANG, globalFileEle->Attribute(XA_LANG)); 236 | LOGG(22, "lang = '%s'", globalFileEle->Attribute(XA_LANG)); 237 | // Iterate over the global Mark elements for the current global File element 238 | deleteChildren(localFileEle, XN_MARK); 239 | globalMarkEle = globalFileEle->FirstChildElement(XN_MARK); 240 | while (globalMarkEle) { 241 | localMarkEle = localDoc.NewElement(XN_MARK); 242 | localFileEle->InsertEndChild(localMarkEle); 243 | // Update local Mark attributes with values from the current global Mark attributes 244 | localMarkEle->SetAttribute(XA_LINE, globalMarkEle->Attribute(XA_LINE)); 245 | LOGG(22, "Mark = %s", globalMarkEle->Attribute(XA_LINE)); 246 | globalMarkEle = globalMarkEle->NextSiblingElement(XN_MARK); 247 | } 248 | // Iterate over the global Fold elements for the current global File element 249 | deleteChildren(localFileEle, XN_FOLD); 250 | globalFoldEle = globalFileEle->FirstChildElement(XN_FOLD); 251 | while (globalFoldEle) { 252 | localFoldEle = localDoc.NewElement(XN_FOLD); 253 | localFileEle->InsertEndChild(localFoldEle); 254 | // Update local Fold attributes with values from the current global Fold attributes 255 | localFoldEle->SetAttribute(XA_LINE, globalFoldEle->Attribute(XA_LINE)); 256 | LOGG(22, "Fold = %s", globalFoldEle->Attribute(XA_LINE)); 257 | globalFoldEle = globalFoldEle->NextSiblingElement(XN_FOLD); 258 | } 259 | } 260 | //else { 261 | // TODO: not found 262 | // This indicates global needs to be updated from this session, 263 | // but we can't call updateGlobalFromSession here. 264 | //} 265 | localFileEle = localFileEle->NextSiblingElement(XN_FILE); 266 | } 267 | localViewEle = localViewEle->NextSiblingElement(XN_SUBVIEW); 268 | } 269 | 270 | if (save) { 271 | // Add XML declaration if missing 272 | if (memcmp(localDoc.FirstChild()->Value(), "xml", 3) != 0) { 273 | localDoc.InsertFirstChild(localDoc.NewDeclaration()); 274 | } 275 | // Save changes to the session file 276 | xmlErr = localDoc.SaveFile(sesFile); 277 | if (xmlErr != kXmlSuccess) { 278 | lastErr = ::GetLastError(); 279 | msg::error(lastErr, L"%s: Error %u saving session file \"%s\".", _W(__FUNCTION__), xmlErr, sesFile); 280 | } 281 | } 282 | } 283 | 284 | /** Updates document properties from global file properties. 285 | When an existing document is added to a session, its bookmarks and 286 | firstVisibleLine are updated from the global properties. */ 287 | void updateDocumentFromGlobal(INT bufferId) 288 | { 289 | LPSTR mbPathname; 290 | WCHAR pathname[MAX_PATH]; 291 | INT line, pos, view; 292 | HWND hNpp = sys_getNppHandle(); 293 | 294 | LOGF("%i", bufferId); 295 | 296 | // Get pathname for bufferId 297 | ::SendMessage(hNpp, NPPM_GETFULLPATHFROMBUFFERID, bufferId, (LPARAM)pathname); 298 | mbPathname = str::utf16ToUtf8(pathname); 299 | if (mbPathname == NULL) { 300 | return; 301 | } 302 | LOGG(20, "File = %s", mbPathname); 303 | // Load the properties file (global file properties) 304 | tXmlDoc globalDoc; 305 | tXmlError xmlErr = globalDoc.LoadFile(sys_getGlobalFile()); 306 | if (xmlErr != kXmlSuccess) { 307 | DWORD lastErr = ::GetLastError(); 308 | msg::error(lastErr, L"%s: Error %u loading the global properties file.", _W(__FUNCTION__), xmlErr); 309 | sys_free(mbPathname); 310 | return; 311 | } 312 | tXmlEleP globalFileEle, globalMarkEle, globalFoldEle; 313 | tXmlHnd globalDocHnd(&globalDoc); 314 | globalFileEle = globalDocHnd.FirstChildElement(XN_NOTEPADPLUS).FirstChildElement(XN_FILEPROPERTIES).FirstChildElement(XN_FILE).ToElement(); 315 | 316 | // Find the global File element corresponding to mbPathname 317 | while (globalFileEle) { 318 | if (globalFileEle->Attribute(XA_FILENAME, mbPathname)) { 319 | break; // found it 320 | } 321 | globalFileEle = globalFileEle->NextSiblingElement(XN_FILE); 322 | } 323 | sys_free(mbPathname); 324 | if (!globalFileEle) { // not found 325 | return; 326 | } 327 | 328 | // TODO: Need to set lang here 329 | 330 | // Determine containing view and tab for bufferId 331 | pos = ::SendMessage(hNpp, NPPM_GETPOSFROMBUFFERID, bufferId, 0); 332 | LOGG(20, "Pos = 0x%X", pos); 333 | view = (pos & (1 << 30)) == 0 ? 1 : 2; 334 | 335 | // Iterate over the global Mark elements and set them in the active document 336 | globalMarkEle = globalFileEle->FirstChildElement(XN_MARK); 337 | while (globalMarkEle) { 338 | line = globalMarkEle->IntAttribute(XA_LINE); 339 | // Go to line and set mark 340 | ::SendMessage(sys_getSciHandle(view), SCI_GOTOLINE, line, 0); 341 | ::SendMessage(hNpp, NPPM_MENUCOMMAND, 0, IDM_SEARCH_TOGGLE_BOOKMARK); 342 | LOGG(20, "Mark = %i", line); 343 | globalMarkEle = globalMarkEle->NextSiblingElement(XN_MARK); 344 | } 345 | 346 | // Iterate over the global Fold elements and set them in the active document 347 | globalFoldEle = globalFileEle->FirstChildElement(XN_FOLD); 348 | while (globalFoldEle) { 349 | line = globalFoldEle->IntAttribute(XA_LINE); 350 | // Go to line and set fold 351 | ::SendMessage(sys_getSciHandle(view), SCI_GOTOLINE, line, 0); 352 | ::SendMessage(hNpp, NPPM_MENUCOMMAND, 0, IDM_VIEW_FOLD_CURRENT); 353 | LOGG(20, "Fold = %i", line); 354 | globalFoldEle = globalFoldEle->NextSiblingElement(XN_FOLD); 355 | } 356 | 357 | // Move cursor to the last known firstVisibleLine 358 | line = globalFileEle->IntAttribute(XA_FIRSTVISIBLELINE); 359 | ::SendMessage(sys_getSciHandle(view), SCI_GOTOLINE, line, 0); 360 | LOGG(20, "firstVisibleLine = %i", line); 361 | } 362 | 363 | } // end namespace NppPlugin::prp 364 | 365 | //------------------------------------------------------------------------------ 366 | 367 | namespace { 368 | 369 | /** Removes global File elements whose files do not exist on disk. */ 370 | void removeMissingFilesFromGlobal() 371 | { 372 | DWORD lastErr; 373 | tXmlError xmlErr; 374 | bool save = false; 375 | LPWSTR wPathname; 376 | LPCSTR mbPathname; 377 | tXmlEleP propsEle, fileEle, currentFileEle; 378 | 379 | LOGF(""); 380 | 381 | // Load the properties file (global file properties) 382 | tXmlDoc globalDoc; 383 | xmlErr = globalDoc.LoadFile(sys_getGlobalFile()); 384 | if (xmlErr != kXmlSuccess) { 385 | lastErr = ::GetLastError(); 386 | msg::error(lastErr, L"%s: Error %u loading the global properties file.", _W(__FUNCTION__), xmlErr); 387 | return; 388 | } 389 | tXmlHnd globalDocHnd(&globalDoc); 390 | propsEle = globalDocHnd.FirstChildElement(XN_NOTEPADPLUS).FirstChildElement(XN_FILEPROPERTIES).ToElement(); 391 | fileEle = propsEle->FirstChildElement(XN_FILE); 392 | 393 | // Iterate over the File elements and remove those whose files do not exist 394 | while (fileEle) { 395 | mbPathname = fileEle->Attribute(XA_FILENAME); 396 | wPathname = str::utf8ToUtf16(mbPathname); 397 | if (wPathname == NULL) { 398 | continue; // XXX was: return; 399 | } 400 | currentFileEle = fileEle; 401 | fileEle = fileEle->NextSiblingElement(XN_FILE); 402 | if (!pth::fileExists(wPathname)) { 403 | save = true; 404 | propsEle->DeleteChild(currentFileEle); 405 | LOGG(20, "File = %s", mbPathname); 406 | } 407 | sys_free(wPathname); 408 | } 409 | 410 | if (save) { 411 | // Add XML declaration if missing 412 | if (memcmp(globalDoc.FirstChild()->Value(), "xml", 3) != 0) { 413 | globalDoc.InsertFirstChild(globalDoc.NewDeclaration()); 414 | } 415 | // Save changes to the properties file 416 | xmlErr = globalDoc.SaveFile(sys_getGlobalFile()); 417 | if (xmlErr != kXmlSuccess) { 418 | lastErr = ::GetLastError(); 419 | msg::error(lastErr, L"%s: Error %u saving the global properties file.", _W(__FUNCTION__), xmlErr); 420 | } 421 | } 422 | } 423 | 424 | /** Deletes parent's child elements having the given element name. */ 425 | void deleteChildren(tXmlEleP parent, LPCSTR eleName) 426 | { 427 | tXmlEleP ele, tmp; 428 | 429 | ele = parent->FirstChildElement(eleName); 430 | while (ele) { 431 | tmp = ele; 432 | ele = ele->NextSiblingElement(eleName); 433 | parent->DeleteChild(tmp); 434 | } 435 | } 436 | 437 | } // end namespace 438 | 439 | } // end namespace NppPlugin 440 | -------------------------------------------------------------------------------- /src/Properties.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file Properties.h 13 | @copyright Copyright 2014,2015 Michael Foster 14 | */ 15 | 16 | #ifndef NPP_PLUGIN_PROPERTIES_H 17 | #define NPP_PLUGIN_PROPERTIES_H 18 | 19 | //------------------------------------------------------------------------------ 20 | 21 | namespace NppPlugin { 22 | 23 | //------------------------------------------------------------------------------ 24 | /// @namespace NppPlugin::api Contains functions called only from DllMain. 25 | 26 | namespace api { 27 | 28 | void prp_init(); 29 | 30 | } // end namespace NppPlugin::api 31 | 32 | //------------------------------------------------------------------------------ 33 | /// @namespace NppPlugin::prp Implements global file properties. 34 | 35 | namespace prp { 36 | 37 | void updateGlobalFromSession(LPWSTR sesFile); 38 | void updateSessionFromGlobal(LPWSTR sesFile); 39 | void updateDocumentFromGlobal(INT bufferId); 40 | 41 | } // end namespace NppPlugin::prp 42 | 43 | } // end namespace NppPlugin 44 | 45 | #endif // NPP_PLUGIN_PROPERTIES_H 46 | -------------------------------------------------------------------------------- /src/SessionMgr.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file SessionMgr.h 13 | @copyright Copyright 2011,2013-2015 Michael Foster 14 | */ 15 | 16 | #ifndef NPP_PLUGIN_APPLICATION_H 17 | #define NPP_PLUGIN_APPLICATION_H 18 | 19 | #include "res\version.h" 20 | 21 | //------------------------------------------------------------------------------ 22 | 23 | namespace NppPlugin { 24 | 25 | #define PLUGIN_DLL_NAME L"SessionMgr" 26 | #define PLUGIN_FULL_NAME L"Session Manager" 27 | #define SES_NAME_NONE L"None" 28 | #define SES_NAME_DEFAULT L"Default" 29 | #define SES_NAME_BUF_LEN 100 30 | /// Used as virtual session indexes 31 | #define SI_NONE -1 32 | #define SI_CURRENT -2 33 | #define SI_PREVIOUS -3 34 | #define SI_DEFAULT -4 35 | 36 | /// @class Session 37 | class Session 38 | { 39 | public: 40 | INT index; 41 | bool isVisible; 42 | bool isFavorite; 43 | FILETIME modified; 44 | WCHAR name[SES_NAME_BUF_LEN]; 45 | Session(LPCWSTR sesName, FILETIME modTime); 46 | }; 47 | 48 | //------------------------------------------------------------------------------ 49 | /// @namespace NppPlugin::api Contains functions called only from DllMain. 50 | 51 | namespace api { 52 | 53 | void app_onLoad(); 54 | void app_onUnload(); 55 | void app_init(); 56 | LPCWSTR app_getName(); 57 | void app_onNotify(SCNotification *pscn); 58 | LRESULT app_msgProc(UINT Message, WPARAM wParam, LPARAM lParam); 59 | 60 | } // end namespace NppPlugin::api 61 | 62 | //------------------------------------------------------------------------------ 63 | 64 | void app_readSessionDirectory(bool firstLoad = false); 65 | void app_loadSession(INT si); 66 | void app_loadSession(INT si, bool lic, bool lwc, bool firstLoad = false); 67 | void app_saveSession(INT si = SI_CURRENT); 68 | bool app_isValidSessionIndex(INT si); 69 | INT app_getSessionCount(); 70 | INT app_getSessionIndex(LPCWSTR name); 71 | INT app_getCurrentIndex(); 72 | INT app_getPreviousIndex(); 73 | INT app_getDefaultIndex(); 74 | void app_resetPreviousIndex(); 75 | void app_renameSession(INT si, LPWSTR newName); 76 | LPCWSTR app_getSessionName(INT si = SI_CURRENT); 77 | void app_getSessionFile(INT si, LPWSTR buf); 78 | Session* app_getSessionObject(INT si); 79 | void app_confirmDefaultSession(); 80 | void app_updateNppBars(); 81 | void app_updateFavorites(bool clearAll = false); 82 | INT app_getLbIdxStartingWith(WCHAR targetChar); 83 | 84 | } // end namespace NppPlugin 85 | 86 | #endif // NPP_PLUGIN_APPLICATION_H 87 | -------------------------------------------------------------------------------- /src/SessionMgrApi.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file SessionMgrApi.h 13 | @copyright Copyright 2014,2015 Michael Foster 14 | 15 | Session Manager P2P API 16 | 17 | Clients should send NPPM_MSGTOPLUGIN to NPP with wParam pointing to 18 | L"SessionMgr.dll" and lParam pointing to a SessionMgrApiData object. 19 | */ 20 | 21 | #ifndef NPP_PLUGIN_SESSIONMGRAPI_H 22 | #define NPP_PLUGIN_SESSIONMGRAPI_H 23 | 24 | #define SM_NULL 0 25 | #define SM_OK -1 26 | #define SM_BUSY -2 27 | #define SM_ERROR -3 28 | #define SM_INVMSG -4 29 | #define SM_INVARG -5 30 | 31 | /** This is compatible with casting to NPP's CommunicationInfo struct. 32 | @see npp\Notepad_plus_msgs.h */ 33 | struct SessionMgrApiData { 34 | long message; ///< one of the SMM_ message codes 35 | LPCWSTR caller; ///< for NPP but not used as of v6.6.9 36 | INT iData; ///< input and output API usage 37 | WCHAR wData[MAX_PATH]; ///< input or output API usage 38 | }; 39 | 40 | enum SettingId { 41 | kAutomaticSave = 0, 42 | kAutomaticLoad, 43 | kLoadIntoCurrent, 44 | kLoadWithoutClosing, 45 | kShowInTitlebar, 46 | kShowInStatusbar, 47 | kUseGlobalProperties, 48 | kCleanGlobalProperties, 49 | kUseContextMenu, 50 | kBackupOnStartup, 51 | kSessionSaveDelay, 52 | kSettingsSavePoll, 53 | kSessionDirectory, 54 | kSessionExtension, 55 | kCurrentMark, 56 | kCurrentFavMark, 57 | kPreviousMark, 58 | kPreviousFavMark, 59 | kDefaultMark, 60 | kDefaultFavMark, 61 | kFavoriteMark, 62 | kUseFilterWildcards, 63 | kSessionSortOrder, 64 | kCurrentSession, 65 | kPreviousSession, 66 | kDefaultSession, 67 | kMenuLabelMain, 68 | kMenuLabelSub1, 69 | kMenuLabelSub2, 70 | kMenuLabelSub3, 71 | kMenuLabelSub4, 72 | kMenuLabelSub5, 73 | kMenuLabelSub6, 74 | kSessionsDialogWidth, 75 | kSessionsDialogHeight, 76 | kSettingsDialogWidth, 77 | kSettingsDialogHeight, 78 | kDebugLogLevel, 79 | kDebugLogFile, 80 | kSettingsCount 81 | }; 82 | 83 | //------------------------------------------------------------------------------ 84 | 85 | /** Loads a session from the current sessions list. 86 | @pre wData = session name, no path or extension 87 | @pre iData = SM_NULL 88 | @post iData = SM_OK else SM_BUSY or SM_INVARG */ 89 | #define SMM_SES_LOAD (WM_APP + 1) 90 | 91 | /** Loads the previous session. 92 | @pre iData = SM_NULL 93 | @post iData = SM_OK else SM_BUSY */ 94 | #define SMM_SES_LOAD_PRV (WM_APP + 2) 95 | 96 | /** Loads the default session. 97 | @pre iData = SM_NULL 98 | @post iData = SM_OK else SM_BUSY */ 99 | #define SMM_SES_LOAD_DEF (WM_APP + 3) 100 | 101 | /** Saves the current session. 102 | @pre iData = SM_NULL 103 | @post iData = SM_OK else SM_BUSY */ 104 | #define SMM_SES_SAVE (WM_APP + 4) 105 | 106 | /** Gets the current session name, no path or extension. 107 | @pre iData = SM_NULL 108 | @post iData = SM_OK else SM_BUSY 109 | @post wData = name */ 110 | #define SMM_SES_GET_NAME (WM_APP + 5) 111 | 112 | /** Gets the fully qualified name of the current session file. 113 | @pre iData = SM_NULL 114 | @post iData = SM_OK else SM_BUSY 115 | @post wData = fqn */ 116 | #define SMM_SES_GET_FQN (WM_APP + 6) 117 | 118 | /** Gets the integer value of a setting. 119 | @pre iData = SettingId 120 | @post iData = SM_OK else SM_BUSY or SM_INVARG 121 | @post wData[0] = value of setting */ 122 | #define SMM_CFG_GET_INT (WM_APP + 7) 123 | 124 | /** Sets the integer value of a setting. 125 | @pre iData = SettingId 126 | @pre wData[0] = value to set 127 | @post iData = SM_OK else SM_BUSY or SM_INVARG */ 128 | #define SMM_CFG_PUT_INT (WM_APP + 8) 129 | 130 | /** Gets the string value of a setting. 131 | @pre iData = SettingId 132 | @post iData = SM_OK else SM_BUSY or SM_INVARG 133 | @post wData = value of setting */ 134 | #define SMM_CFG_GET_STR (WM_APP + 9) 135 | 136 | /** Sets the string value of a setting. 137 | @pre iData = SettingId 138 | @pre wData = value to set 139 | @post iData = SM_OK else SM_BUSY, SM_INVARG or SM_ERROR */ 140 | #define SMM_CFG_PUT_STR (WM_APP + 10) 141 | 142 | /** Removes all favorites. 143 | @pre iData = SM_NULL 144 | @post iData = SM_OK else SM_BUSY */ 145 | #define SMM_FAV_CLR (WM_APP + 11) 146 | 147 | /** Adds or removes a session as a favorite. 148 | @pre wData = session name, no path or extension 149 | @pre iData = 0: remove, 1: add 150 | @post iData = SM_OK else SM_BUSY, SM_INVARG or SM_ERROR */ 151 | #define SMM_FAV_SET (WM_APP + 12) 152 | 153 | /** Removes all filters. 154 | @pre iData = SM_NULL 155 | @post iData = SM_OK else SM_BUSY */ 156 | #define SMM_FIL_CLR (WM_APP + 13) 157 | 158 | /** Adds a filter. It is moved to the top if it is already in the list. 159 | @pre wData = filter 160 | @pre iData = SM_NULL 161 | @post iData = SM_OK else SM_BUSY */ 162 | #define SMM_FIL_ADD (WM_APP + 14) 163 | 164 | /** Gets NPP's configuration directory. 165 | @pre iData = SM_NULL 166 | @post iData = SM_OK else SM_BUSY or SM_ERROR 167 | @post wData = path */ 168 | #define SMM_NPP_CFG_DIR (WM_APP + 15) 169 | 170 | 171 | #endif // NPP_PLUGIN_SESSIONMGRAPI_H 172 | -------------------------------------------------------------------------------- /src/Settings.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file Settings.cpp 13 | @copyright Copyright 2014,2015 Michael Foster 14 | 15 | Implements management of configuration settings. 16 | */ 17 | 18 | #include "System.h" 19 | #include "SessionMgr.h" 20 | #include "Menu.h" 21 | #include "Util.h" 22 | #include 23 | #include 24 | 25 | //------------------------------------------------------------------------------ 26 | 27 | namespace NppPlugin { 28 | 29 | INT gDbgLvl = 0; 30 | 31 | //------------------------------------------------------------------------------ 32 | 33 | namespace { 34 | 35 | /// Initial contents of a new settings.xml file 36 | #define INITIAL_CONTENTS "\n\n" 37 | /// XML node and attribute names 38 | #define XN_ROOT "SessionMgr" 39 | #define XN_ITEM "item" 40 | #define XA_VALUE "value" 41 | /// Defaults 42 | #define DEFAULT_SES_DIR L"sessions\\" 43 | #define DEFAULT_SES_EXT L".npp-session" 44 | 45 | tXmlDocP _xmlDocument = NULL; 46 | WCHAR _tmpBuffer[MAX_PATH]; 47 | bool _isDirty = false; 48 | 49 | /** These must be in the same order as the ContainerId enums. */ 50 | LPCSTR _containerNames[] = { 51 | "Settings", 52 | "Favorites", 53 | "Filters" 54 | }; 55 | 56 | tXmlEleP _containerElements[kContainersCount]; 57 | 58 | typedef struct Setting_tag { 59 | LPSTR cName; 60 | LPSTR cDefault; 61 | bool isInt; 62 | INT iCache; 63 | LPWSTR wCache; 64 | tXmlEleP element; 65 | INT wCacheSize; // character size of the wCache buffer, 0 if isInt 66 | } Setting; 67 | 68 | /** These must be in the same order as the SettingId enums. */ 69 | Setting _settings[] = { 70 | { "automaticSave", "1", true, 0, 0, 0, 0 }, 71 | { "automaticLoad", "0", true, 0, 0, 0, 0 }, 72 | { "loadIntoCurrent", "0", true, 0, 0, 0, 0 }, 73 | { "loadWithoutClosing", "0", true, 0, 0, 0, 0 }, 74 | { "showInTitlebar", "0", true, 0, 0, 0, 0 }, 75 | { "showInStatusbar", "0", true, 0, 0, 0, 0 }, 76 | { "useGlobalProperties", "1", true, 0, 0, 0, 0 }, 77 | { "cleanGlobalProperties","0", true, 0, 0, 0, 0 }, 78 | { "useContextMenu", "1", true, 0, 0, 0, 0 }, 79 | { "backupOnStartup", "1", true, 0, 0, 0, 0 }, 80 | { "sessionSaveDelay", "3", true, 0, 0, 0, 0 }, 81 | { "settingsSavePoll", "2", true, 0, 0, 0, 0 }, 82 | { "sessionDirectory", "", false, 0, 0, 0, MAX_PATH }, 83 | { "sessionExtension", ".npp-session", false, 0, 0, 0, MAX_PATH }, // 25 }, 84 | { "currentMark", "9674", true, 0, 0, 0, 0 }, 85 | { "currentFavMark", "9830", true, 0, 0, 0, 0 }, 86 | { "previousMark", "9702", true, 0, 0, 0, 0 }, 87 | { "previousFavMark", "8226", true, 0, 0, 0, 0 }, 88 | { "defaultMark", "9653", true, 0, 0, 0, 0 }, 89 | { "defaultFavMark", "9652", true, 0, 0, 0, 0 }, 90 | { "favoriteMark", "183", true, 0, 0, 0, 0 }, 91 | { "useFilterWildcards", "0", true, 0, 0, 0, 0 }, 92 | { "sessionSortOrder", "1", true, 0, 0, 0, 0 }, 93 | { "currentSession", "Default", false, 0, 0, 0, MAX_PATH }, // SES_NAME_BUF_LEN }, 94 | { "previousSession", "Default", false, 0, 0, 0, MAX_PATH }, // SES_NAME_BUF_LEN }, 95 | { "defaultSession", "Default", false, 0, 0, 0, MAX_PATH }, // SES_NAME_BUF_LEN }, 96 | { "menuLabelMain", "&Session Manager", false, 0, 0, 0, MAX_PATH }, // MNU_MAX_NAME_LEN + 1 }, 97 | { "menuLabelSub1", "&Sessions...", false, 0, 0, 0, MAX_PATH }, // MNU_MAX_NAME_LEN + 1 }, 98 | { "menuLabelSub2", "Se&ttings...", false, 0, 0, 0, MAX_PATH }, // MNU_MAX_NAME_LEN + 1 }, 99 | { "menuLabelSub3", "Sa&ve current", false, 0, 0, 0, MAX_PATH }, // MNU_MAX_NAME_LEN + 1 }, 100 | { "menuLabelSub4", "Load &previous", false, 0, 0, 0, MAX_PATH }, // MNU_MAX_NAME_LEN + 1 }, 101 | { "menuLabelSub5", "&Help", false, 0, 0, 0, MAX_PATH }, // MNU_MAX_NAME_LEN + 1 }, 102 | { "menuLabelSub6", "&About...", false, 0, 0, 0, MAX_PATH }, // MNU_MAX_NAME_LEN + 1 }, 103 | { "sessionsDialogWidth", "0", true, 0, 0, 0, 0 }, 104 | { "sessionsDialogHeight", "0", true, 0, 0, 0, 0 }, 105 | { "settingsDialogWidth", "0", true, 0, 0, 0, 0 }, 106 | { "settingsDialogHeight", "0", true, 0, 0, 0, 0 }, 107 | { "debugLogLevel", "0", true, 0, 0, 0, 0 }, 108 | { "debugLogFile", "", false, 0, 0, 0, MAX_PATH } 109 | }; 110 | 111 | bool readSettingsFile(); 112 | void initContainers(); 113 | void initSettings(); 114 | void updateCache(Setting *setting); 115 | void afterLoad(); 116 | void upgradeIniToXml(); 117 | 118 | } // end namespace 119 | 120 | //------------------------------------------------------------------------------ 121 | 122 | namespace api { 123 | 124 | void cfg_onUnload() 125 | { 126 | INT i; 127 | 128 | if (_isDirty) { 129 | cfg::saveSettings(); 130 | } 131 | for (i = 0; i < kSettingsCount; ++i) { 132 | if (!_settings[i].isInt && _settings[i].wCache) { 133 | sys_free(_settings[i].wCache); 134 | } 135 | } 136 | for (i = 0; i < kContainersCount; ++i) { 137 | _containerElements[i] = NULL; 138 | } 139 | if (_xmlDocument) { 140 | delete _xmlDocument; 141 | _xmlDocument = NULL; 142 | } 143 | } 144 | 145 | } // end namespace NppPlugin::api 146 | 147 | //------------------------------------------------------------------------------ 148 | 149 | namespace cfg { 150 | 151 | void loadSettings() 152 | { 153 | if (readSettingsFile()) { 154 | initContainers(); 155 | initSettings(); 156 | afterLoad(); 157 | if (_isDirty) { 158 | saveSettings(); 159 | } 160 | } 161 | } 162 | 163 | void saveSettings() 164 | { 165 | DWORD lastErr; 166 | tXmlError xmlErr; 167 | 168 | if (_xmlDocument) { 169 | xmlErr = _xmlDocument->SaveFile(sys_getSettingsFile()); 170 | if (xmlErr != kXmlSuccess) { 171 | lastErr = ::GetLastError(); 172 | msg::error(lastErr, L"%s: Error %u saving the settings file.", _W(__FUNCTION__), xmlErr); 173 | } 174 | else { 175 | _isDirty = false; 176 | LOG("Settings saved."); 177 | } 178 | } 179 | } 180 | 181 | bool isDirty() 182 | { 183 | return _isDirty; 184 | } 185 | 186 | //------------------------------------------------------------------------------ 187 | // Functions that read or write child elements of the Settings container. 188 | 189 | /** @return a pointer to the value of the cfgId element of the Settings container. */ 190 | LPCWSTR getStr(SettingId cfgId) 191 | { 192 | return _settings[cfgId].wCache; 193 | } 194 | 195 | /** Copies to buf the value of the cfgId element of the Settings container. */ 196 | void getStr(SettingId cfgId, LPWSTR buf, INT bufLen) 197 | { 198 | ::StringCchCopyW(buf, bufLen, _settings[cfgId].wCache); 199 | } 200 | 201 | /** @return the boolean value of the cfgId element of the Settings container. */ 202 | bool getBool(SettingId cfgId) 203 | { 204 | return _settings[cfgId].iCache != 0; 205 | } 206 | 207 | /** @return the integer value of the cfgId element of the Settings container. */ 208 | INT getInt(SettingId cfgId) 209 | { 210 | return _settings[cfgId].iCache; 211 | } 212 | 213 | /** Copies value to the cfgId element of the Settings container. */ 214 | void putStr(SettingId cfgId, LPCSTR value) 215 | { 216 | if (value && *value) { 217 | _settings[cfgId].element->SetAttribute(XA_VALUE, value); 218 | updateCache(&_settings[cfgId]); 219 | _isDirty = true; 220 | } 221 | } 222 | 223 | /** Copies value to the cfgId element of the Settings container. */ 224 | void putStr(SettingId cfgId, LPCWSTR value) 225 | { 226 | LPSTR mbValue = str::utf16ToUtf8(value); 227 | if (mbValue) { 228 | putStr(cfgId, mbValue); 229 | sys_free(mbValue); 230 | } 231 | } 232 | 233 | /** Writes the boolean value to the cfgId element of the Settings container. */ 234 | void putBool(SettingId cfgId, bool value) 235 | { 236 | putStr(cfgId, value ? "1" : "0"); 237 | } 238 | 239 | /** Writes the integer value to the cfgId element of the Settings container. */ 240 | void putInt(SettingId cfgId, INT value) 241 | { 242 | CHAR buf[MAX_PATH]; 243 | ::_itoa_s(value, buf, MAX_PATH, 10); 244 | putStr(cfgId, buf); 245 | } 246 | 247 | //------------------------------------------------------------------------------ 248 | // Functions that read or write child elements of any container. 249 | 250 | /** @return a pointer to the value of the 0-based childIndex'th element of the 251 | conId container, or NULL if the element doesn't exist. */ 252 | LPCSTR getCStr(ContainerId conId, INT childIndex) 253 | { 254 | tXmlEleP childEle; 255 | childEle = _containerElements[conId]->FirstChildElement(); 256 | while (childEle && childIndex-- > 0) { 257 | childEle = childEle->NextSiblingElement(); 258 | } 259 | if (childEle) { 260 | return childEle->Attribute(XA_VALUE); 261 | } 262 | return NULL; 263 | } 264 | 265 | /** @return a pointer to the value of the 0-based childIndex'th element of the 266 | conId container, or NULL if the element doesn't exist. It points to a 267 | temporary buffer which will be overwritten the next time this function 268 | is called. */ 269 | LPCWSTR getStr(ContainerId conId, INT childIndex) 270 | { 271 | LPCSTR mbStr = getCStr(conId, childIndex); 272 | if (!mbStr) { 273 | return NULL; 274 | } 275 | return str::utf8ToUtf16(mbStr, _tmpBuffer, MAX_PATH); 276 | } 277 | 278 | /** Copies to buf the value of the 0-based childIndex'th element of the conId container. 279 | @return true if the element exists else false */ 280 | bool getStr(ContainerId conId, INT childIndex, LPWSTR buf, INT bufLen) 281 | { 282 | LPCSTR mbStr = getCStr(conId, childIndex); 283 | if (!mbStr) { 284 | return false; 285 | } 286 | return str::utf8ToUtf16(mbStr, buf, bufLen) != NULL; 287 | } 288 | 289 | /** @return a pointer to the first child of conId with value, else NULL */ 290 | tXmlEleP getChild(ContainerId conId, LPCSTR value) 291 | { 292 | if (value && *value) { 293 | tXmlEleP childEle = _containerElements[conId]->FirstChildElement(); 294 | while (childEle) { 295 | if (childEle->Attribute(XA_VALUE, value)) { 296 | return childEle; 297 | } 298 | childEle = childEle->NextSiblingElement(); 299 | } 300 | } 301 | return NULL; 302 | } 303 | 304 | /** Adds a new element to the conId container and copies value to it. Appends 305 | if append is true else prepends. Does nothing if conId is kSettings, or 306 | value is null or empty, or a child with value already exists. */ 307 | void addChild(ContainerId conId, LPCWSTR value, bool append) 308 | { 309 | if (conId != kSettings && value && *value) { 310 | LPSTR mbValue = str::utf16ToUtf8(value); 311 | if (mbValue && !getChild(conId, mbValue)) { 312 | tXmlEleP cfgEle = _xmlDocument->NewElement(XN_ITEM); 313 | cfgEle->SetAttribute(XA_VALUE, mbValue); 314 | if (append) { 315 | _containerElements[conId]->InsertEndChild(cfgEle); 316 | } 317 | else { 318 | _containerElements[conId]->InsertFirstChild(cfgEle); 319 | } 320 | sys_free(mbValue); 321 | _isDirty = true; 322 | } 323 | } 324 | } 325 | 326 | /** If a child of conId with value exists, moves it to the top, else adds a new 327 | element at the top and copies value to it. If it already exists at the top, 328 | does nothing. Does nothing if conId is kSettings or value is null or empty. 329 | @return true if any change was made, else false */ 330 | bool moveToTop(ContainerId conId, LPCWSTR value) 331 | { 332 | if (conId != kSettings && value && *value) { 333 | LPSTR mbValue = str::utf16ToUtf8(value); 334 | if (mbValue) { 335 | tXmlEleP childEle = getChild(conId, mbValue); 336 | sys_free(mbValue); 337 | if (!childEle) { // not found so add it at the top 338 | addChild(conId, value, false); 339 | return true; 340 | } 341 | if (childEle->PreviousSiblingElement()) { // found and not at top so move it to the top 342 | _containerElements[conId]->InsertFirstChild(childEle); 343 | _isDirty = true; 344 | return true; 345 | } 346 | } 347 | } 348 | return false; 349 | } 350 | 351 | /** Deletes all child elements of the conId container. Does nothing if conId 352 | is kSettings. */ 353 | void deleteChildren(ContainerId conId) 354 | { 355 | if (conId != kSettings) { 356 | _containerElements[conId]->DeleteChildren(); 357 | _isDirty = true; 358 | } 359 | } 360 | 361 | //------------------------------------------------------------------------------ 362 | // Application-specific functions built on top of the generic cfg functions. 363 | 364 | bool setSessionDirectory(LPCWSTR sesDir, bool confirmDefSes) 365 | { 366 | WCHAR buf[MAX_PATH]; 367 | 368 | if (!sesDir || !*sesDir) { 369 | ::StringCchCopyW(buf, MAX_PATH, sys_getCfgDir()); 370 | ::StringCchCatW(buf, MAX_PATH, DEFAULT_SES_DIR); 371 | } 372 | else { 373 | ::StringCchCopyW(buf, MAX_PATH, sesDir); 374 | pth::appendSlash(buf, MAX_PATH); 375 | if (!pth::dirExists(buf)) { 376 | if (::SHCreateDirectoryExW(NULL, buf, NULL) != ERROR_SUCCESS ) { 377 | DWORD le = ::GetLastError(); 378 | msg::error(le, L"%s: Error creating session directory \"%s\".", _W(__FUNCTION__), buf); 379 | return false; // ses dir not changed 380 | } 381 | } 382 | } 383 | putStr(kSessionDirectory, buf); 384 | /* TODO: What if both kSessionDirectory and kSessionExtension are changing? 385 | Then app_confirmDefaultSession doesn't need to be called until after both have changed. */ 386 | if (confirmDefSes) { 387 | app_confirmDefaultSession(); 388 | } 389 | return true; 390 | } 391 | 392 | void setSessionExtension(LPCWSTR sesExt, bool confirmDefSes) 393 | { 394 | WCHAR buf[MAX_PATH]; 395 | 396 | if (!sesExt || !*sesExt) { 397 | ::StringCchCopyW(buf, MAX_PATH, DEFAULT_SES_EXT); 398 | } 399 | else { 400 | buf[0] = L'\0'; 401 | if (*sesExt != L'.') { 402 | buf[0] = L'.'; 403 | buf[1] = L'\0'; 404 | } 405 | ::StringCchCatW(buf, MAX_PATH, sesExt); 406 | } 407 | putStr(kSessionExtension, buf); 408 | if (confirmDefSes) { 409 | app_confirmDefaultSession(); 410 | } 411 | } 412 | 413 | void setShowInTitlebar(bool enable) 414 | { 415 | putBool(kShowInTitlebar, enable); 416 | if (enable) { 417 | app_updateNppBars(); 418 | } 419 | } 420 | 421 | void setShowInStatusbar(bool enable) 422 | { 423 | putBool(kShowInStatusbar, enable); 424 | if (enable) { 425 | app_updateNppBars(); 426 | } 427 | } 428 | 429 | void getMarkStr(SettingId cfgId, LPWSTR buf) 430 | { 431 | buf[0] = getInt(cfgId); 432 | buf[1] = L'\t'; 433 | buf[2] = 0; 434 | } 435 | 436 | bool isSortAlpha() 437 | { 438 | return getInt(kSessionSortOrder) == SORT_ORDER_ALPHA; 439 | } 440 | 441 | bool isFavorite(LPCWSTR fav) 442 | { 443 | bool isFav = false; 444 | LPSTR mbFav = str::utf16ToUtf8(fav); 445 | if (mbFav) { 446 | isFav = getChild(kFavorites, mbFav) != NULL; 447 | sys_free(mbFav); 448 | } 449 | return isFav; 450 | } 451 | 452 | } // end namespace NppPlugin::cfg 453 | 454 | //------------------------------------------------------------------------------ 455 | 456 | namespace { 457 | 458 | /** Loads the settings.xml file if it has not already been loaded. Creates it if 459 | it doesn't exist. */ 460 | bool readSettingsFile() 461 | { 462 | DWORD lastErr; 463 | tXmlError xmlErr; 464 | LPCWSTR settingsFile; 465 | 466 | if (!_xmlDocument) { 467 | settingsFile = sys_getSettingsFile(); 468 | if (!pth::fileExists(settingsFile)) { 469 | pth::createFileIfMissing(settingsFile, INITIAL_CONTENTS); 470 | _isDirty = true; 471 | } 472 | _xmlDocument = new tinyxml2::XMLDocument(); 473 | xmlErr = _xmlDocument->LoadFile(settingsFile); 474 | if (xmlErr != kXmlSuccess) { 475 | lastErr = ::GetLastError(); 476 | msg::error(lastErr, L"%s: Error %u loading the settings file.", _W(__FUNCTION__), xmlErr); 477 | return false; 478 | } 479 | } 480 | 481 | return true; 482 | } 483 | 484 | /** Initializes the _containerElements array with pointers to the ContainerId 485 | elements. Creates missing elements. */ 486 | void initContainers() 487 | { 488 | INT conId; 489 | tXmlEleP conEle, rootEle; 490 | 491 | rootEle = _xmlDocument->FirstChildElement(XN_ROOT); 492 | for (conId = 0; conId < kContainersCount; ++conId) { 493 | conEle = rootEle->FirstChildElement(_containerNames[conId]); 494 | if (!conEle) { 495 | conEle = _xmlDocument->NewElement(_containerNames[conId]); 496 | rootEle->InsertEndChild(conEle); 497 | _isDirty = true; 498 | } 499 | _containerElements[conId] = conEle; 500 | } 501 | } 502 | 503 | /** Initializes the _settings array. Creates missing elements. */ 504 | void initSettings() 505 | { 506 | INT cfgId; 507 | tXmlEleP settingsEle, cfgEle, prvCfgEle = NULL; 508 | 509 | settingsEle = _containerElements[kSettings]; 510 | for (cfgId = 0; cfgId < kSettingsCount; ++cfgId) { 511 | cfgEle = settingsEle->FirstChildElement(_settings[cfgId].cName); 512 | if (!cfgEle) { 513 | cfgEle = _xmlDocument->NewElement(_settings[cfgId].cName); 514 | cfgEle->SetAttribute(XA_VALUE, _settings[cfgId].cDefault); 515 | if (prvCfgEle) { 516 | settingsEle->InsertAfterChild(prvCfgEle, cfgEle); 517 | } 518 | else { 519 | settingsEle->InsertEndChild(cfgEle); 520 | } 521 | _isDirty = true; 522 | } 523 | if (!_settings[cfgId].isInt) { 524 | _settings[cfgId].wCache = (LPWSTR)sys_alloc(_settings[cfgId].wCacheSize * sizeof WCHAR); 525 | _settings[cfgId].wCache[0] = 0; 526 | } 527 | prvCfgEle = cfgEle; 528 | _settings[cfgId].element = cfgEle; 529 | updateCache(&_settings[cfgId]); 530 | } 531 | } 532 | 533 | /** Refreshes the cached value of the given setting. */ 534 | void updateCache(Setting *setting) 535 | { 536 | LPCSTR value = setting->element->Attribute(XA_VALUE); 537 | if (!value || !*value) { 538 | value = setting->cDefault; 539 | } 540 | if (setting->isInt) { 541 | setting->iCache = ::atoi(value); 542 | } 543 | else { 544 | str::utf8ToUtf16(value, setting->wCache, setting->wCacheSize); 545 | } 546 | } 547 | 548 | /** Things that may need to be done after the configuration is loaded and initialized. */ 549 | void afterLoad() 550 | { 551 | if (!*cfg::getStr(kSessionDirectory)) { // If needed, set default session directory. 552 | cfg::setSessionDirectory(NULL, false); 553 | } 554 | cfg::addChild(kFilters, L"*"); // Add "*" filter if it doesn't already exist. 555 | gDbgLvl = cfg::getInt(kDebugLogLevel); // Use a global for fastest access. 556 | } 557 | 558 | } // end namespace 559 | 560 | } // end namespace NppPlugin 561 | -------------------------------------------------------------------------------- /src/Settings.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file Settings.h 13 | @copyright Copyright 2014,2015 Michael Foster 14 | */ 15 | 16 | #ifndef NPP_PLUGIN_SETTINGS_H 17 | #define NPP_PLUGIN_SETTINGS_H 18 | 19 | #include "SessionMgrApi.h" 20 | #include "xml\tinyxml.h" 21 | 22 | //------------------------------------------------------------------------------ 23 | 24 | namespace NppPlugin { 25 | 26 | extern INT gDbgLvl; 27 | 28 | enum ContainerId { 29 | kSettings = 0, 30 | kFavorites, 31 | kFilters, 32 | kContainersCount 33 | }; 34 | 35 | // See SessionMgrApi.h for enum SettingId 36 | 37 | #define SORT_ORDER_ALPHA 1 38 | #define SORT_ORDER_DATE 2 39 | #define FILTER_BUF_LEN 50 40 | #define FILTERS_MAX 100 41 | 42 | //------------------------------------------------------------------------------ 43 | /// @namespace NppPlugin::api Contains functions called only from DllMain. 44 | 45 | namespace api { 46 | 47 | void cfg_onUnload(); 48 | 49 | } // end namespace NppPlugin::api 50 | 51 | //------------------------------------------------------------------------------ 52 | /// @namespace NppPlugin::cfg Implements management of configuration settings. 53 | 54 | namespace cfg { 55 | 56 | void loadSettings(); 57 | void saveSettings(); 58 | bool isDirty(); 59 | 60 | // Functions that read or write child elements of the Settings container. 61 | LPCWSTR getStr(SettingId cfgId); 62 | void getStr(SettingId cfgId, LPWSTR buf, INT bufLen); 63 | bool getBool(SettingId cfgId); 64 | INT getInt(SettingId cfgId); 65 | void putStr(SettingId cfgId, LPCSTR value); 66 | void putStr(SettingId cfgId, LPCWSTR value); 67 | void putBool(SettingId cfgId, bool value); 68 | void putInt(SettingId cfgId, INT value); 69 | 70 | // Functions that read or write child elements of any container. 71 | LPCSTR getCStr(ContainerId conId, INT childIndex); 72 | LPCWSTR getStr(ContainerId conId, INT childIndex); 73 | bool getStr(ContainerId conId, INT childIndex, LPWSTR buf, INT bufLen); 74 | tXmlEleP getChild(ContainerId conId, LPCSTR value); 75 | void addChild(ContainerId conId, LPCWSTR value, bool append = true); 76 | bool moveToTop(ContainerId conId, LPCWSTR value); 77 | void deleteChildren(ContainerId conId); 78 | 79 | // Application-specific functions built on top of the generic cfg functions. 80 | bool setSessionDirectory(LPCWSTR sesDir, bool confirmDefSes = true); 81 | void setSessionExtension(LPCWSTR sesExt, bool confirmDefSes = true); 82 | void setShowInTitlebar(bool enable); 83 | void setShowInStatusbar(bool enable); 84 | void getMarkStr(SettingId cfgId, LPWSTR buf); 85 | bool isSortAlpha(); 86 | bool isFavorite(LPCWSTR fav); 87 | 88 | } // end namespace NppPlugin::cfg 89 | 90 | } // end namespace NppPlugin 91 | 92 | #endif // NPP_PLUGIN_SETTINGS_H 93 | -------------------------------------------------------------------------------- /src/System.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file System.cpp 13 | @copyright Copyright 2011,2014,2015 Michael Foster 14 | */ 15 | 16 | #include "System.h" 17 | #include "SessionMgr.h" 18 | #include "Util.h" 19 | #include 20 | //#include // for findNppCtxMnuFile 21 | 22 | //------------------------------------------------------------------------------ 23 | 24 | namespace NppPlugin { 25 | 26 | //------------------------------------------------------------------------------ 27 | 28 | namespace { 29 | 30 | #define INI_FILE_NAME L"settings.ini" 31 | #define CFG_FILE_NAME L"settings.xml" 32 | #define CTX_FILE_NAME L"contextMenu.xml" 33 | #define GLB_FILE_NAME L"global.xml" 34 | #define GLB_DEFAULT_CONTENT "\n\n" 35 | #define BAK_DIR_NAME L"backup" 36 | #define BAK_SES_DIR_NAME L"sessions" 37 | 38 | HWND _hNpp; 39 | HWND _hSci1; 40 | HWND _hSci2; 41 | HANDLE _hHeap; 42 | HINSTANCE _hDll; 43 | UINT _nppVersion; 44 | UINT _winVersion; 45 | LPWSTR _cfgDir; ///< SessionMgr's config directory, includes trailing slash 46 | LPWSTR _cfgFile; ///< pathname of settings.xml 47 | LPWSTR _glbFile; ///< pathname of global.xml 48 | LPWSTR _ctxFile; ///< pathname of NPP's contextMenu.xml file 49 | 50 | //void findNppCtxMnuFile(); 51 | void backupFiles(); 52 | void backupConfigFiles(LPCWSTR backupDir); 53 | void backupSessionFiles(LPCWSTR backupDir); 54 | 55 | } // end namespace 56 | 57 | //------------------------------------------------------------------------------ 58 | 59 | namespace api { 60 | 61 | void sys_onLoad(HINSTANCE hDLLInstance) 62 | { 63 | _hDll = hDLLInstance; 64 | } 65 | 66 | void sys_onUnload() 67 | { 68 | sys_free(_ctxFile); 69 | sys_free(_glbFile); 70 | sys_free(_cfgFile); 71 | sys_free(_cfgDir); 72 | } 73 | 74 | void sys_init(NppData nppd) 75 | { 76 | // Save NPP handles 77 | _hNpp = nppd._nppHandle; 78 | _hSci1 = nppd._scintillaMainHandle; 79 | _hSci2 = nppd._scintillaSecondHandle; 80 | _hHeap = ::GetProcessHeap(); 81 | 82 | // Allocate buffers 83 | _cfgDir = (LPWSTR)sys_alloc(MAX_PATH * sizeof WCHAR); 84 | _cfgFile = (LPWSTR)sys_alloc(MAX_PATH * sizeof WCHAR); 85 | _glbFile = (LPWSTR)sys_alloc(MAX_PATH * sizeof WCHAR); 86 | _ctxFile = (LPWSTR)sys_alloc(MAX_PATH * sizeof WCHAR); 87 | 88 | _nppVersion = ::SendMessage(_hNpp, NPPM_GETNPPVERSION, 0, 0); 89 | _winVersion = ::SendMessage(_hNpp, NPPM_GETWINDOWSVERSION, 0, 0); 90 | 91 | // Get NPP's "plugins\Config" directory. 92 | ::SendMessage(_hNpp, NPPM_GETPLUGINSCONFIGDIR, MAX_PATH, (LPARAM)_ctxFile); 93 | 94 | // Get SessionMgr config directory and create it if missing. 95 | ::StringCchCopyW(_cfgDir, MAX_PATH, _ctxFile); 96 | pth::appendSlash(_cfgDir, MAX_PATH); 97 | ::StringCchCatW(_cfgDir, MAX_PATH, PLUGIN_DLL_NAME); 98 | ::StringCchCatW(_cfgDir, MAX_PATH, L"\\"); 99 | ::CreateDirectoryW(_cfgDir, NULL); 100 | 101 | // Get the global.xml file pathname and create it if missing. 102 | ::StringCchCopyW(_glbFile, MAX_PATH, _cfgDir); 103 | ::StringCchCatW(_glbFile, MAX_PATH, GLB_FILE_NAME); 104 | pth::createFileIfMissing(_glbFile, GLB_DEFAULT_CONTENT); 105 | 106 | // Get the settings.xml file pathname and load the configuration. 107 | ::StringCchCopyW(_cfgFile, MAX_PATH, _cfgDir); 108 | ::StringCchCatW(_cfgFile, MAX_PATH, CFG_FILE_NAME); 109 | cfg::loadSettings(); 110 | // Create sessions directory if missing. 111 | ::CreateDirectoryW(cfg::getStr(kSessionDirectory), NULL); 112 | // Create default session file if missing. 113 | app_confirmDefaultSession(); 114 | 115 | // Get NPP's contextMenu.xml pathname (two directories up from "plugins\Config"). 116 | LPWSTR p = ::wcsstr(_ctxFile, L"plugins\\Config"); 117 | ::StringCchCopyW(p, MAX_PATH, CTX_FILE_NAME); 118 | 119 | // Backup existing config and session files. 120 | if (cfg::getBool(kBackupOnStartup)) { 121 | backupFiles(); 122 | } 123 | } 124 | 125 | } // end namespace NppPlugin::api 126 | 127 | //------------------------------------------------------------------------------ 128 | 129 | LPWSTR sys_getCfgDir() 130 | { 131 | return _cfgDir; 132 | } 133 | 134 | LPWSTR sys_getSettingsFile() 135 | { 136 | return _cfgFile; 137 | } 138 | 139 | LPWSTR sys_getGlobalFile() 140 | { 141 | return _glbFile; 142 | } 143 | 144 | LPCWSTR sys_getNppCtxMnuFile() 145 | { 146 | return _ctxFile; 147 | } 148 | 149 | HINSTANCE sys_getDllHandle() 150 | { 151 | return _hDll; 152 | } 153 | 154 | HWND sys_getNppHandle() 155 | { 156 | return _hNpp; 157 | } 158 | 159 | HWND sys_getSciHandle(INT v) 160 | { 161 | if (v == 1) return _hSci1; 162 | else if (v == 2) return _hSci2; 163 | else return NULL; 164 | } 165 | 166 | /** @return NPP version with major in hiword and minor in loword */ 167 | DWORD sys_getNppVer() 168 | { 169 | return _nppVersion; 170 | } 171 | 172 | /** @return a winVer enum 173 | @see npp/Notepad_plus_msgs.h */ 174 | UINT sys_getWinVer() 175 | { 176 | return _winVersion; 177 | } 178 | 179 | LPVOID sys_alloc(INT bytes) 180 | { 181 | LPVOID p = ::HeapAlloc(_hHeap, HEAP_ZERO_MEMORY, bytes); 182 | if (p == NULL) { 183 | LOG("Error allocating %u bytes.", bytes); 184 | msg::show(L"Memory allocation failed.", M_ERR); 185 | } 186 | return p; 187 | } 188 | 189 | void sys_free(LPVOID p) 190 | { 191 | if (p) ::HeapFree(_hHeap, 0, p); 192 | } 193 | 194 | //------------------------------------------------------------------------------ 195 | 196 | namespace { 197 | 198 | /* Gets the pathname of NPP's contextMenu.xml. Now not used. Just assume the 199 | file is two directories up from "plugins\Config". 200 | void findNppCtxMnuFile() 201 | { 202 | ITEMIDLIST *pidl; 203 | bool isLocal = false; 204 | WCHAR tmp[MAX_PATH], nppDir[MAX_PATH]; 205 | 206 | ::SendMessage(_hNpp, NPPM_GETNPPDIRECTORY, MAX_PATH, (LPARAM)nppDir); 207 | pth::appendSlash(nppDir, MAX_PATH); 208 | ::StringCchCopyW(tmp, MAX_PATH, nppDir); 209 | ::StringCchCatW(tmp, MAX_PATH, L"doLocalConf.xml"); 210 | if (pth::fileExists(tmp)) { 211 | isLocal = true; 212 | LOGG(12, "Found doLocalConf.xml"); 213 | } 214 | 215 | // See NppParameters::load in NPP's Parameters.cpp... 216 | if (isLocal && _winVersion >= WV_VISTA) { 217 | if (::SHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidl) == S_OK) { 218 | if (::SHGetPathFromIDList(pidl, tmp)) { 219 | LOGG(12, "prg=\"%S\", npp=\"%S\"", tmp, nppDir); 220 | if (::_wcsnicmp(tmp, nppDir, wcslen(tmp)) == 0) { 221 | isLocal = false; 222 | } 223 | } 224 | else LOGG(12, "SHGetPathFromIDList failed for CSIDL_PROGRAM_FILES"); 225 | //::CoTaskMemFree(pidl); 226 | } 227 | else LOGG(12, "SHGetSpecialFolderLocation failed for CSIDL_PROGRAM_FILES"); 228 | } 229 | ::StringCchCopyW(_ctxFile, MAX_PATH, nppDir); 230 | if (!isLocal) { 231 | if (::SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, &pidl) == S_OK) { 232 | if (::SHGetPathFromIDList(pidl, tmp)) { 233 | pth::appendSlash(tmp, MAX_PATH); 234 | ::StringCchCatW(tmp, MAX_PATH, L"Notepad++"); 235 | if (pth::dirExists(tmp)) { 236 | LOGG(12, "Found \"%S\"", tmp); 237 | ::StringCchCopyW(_ctxFile, MAX_PATH, tmp); 238 | } 239 | else LOGG(12, "Could not find \"%S\"", tmp); 240 | } 241 | else LOGG(12, "SHGetPathFromIDList failed for CSIDL_APPDATA"); 242 | //::CoTaskMemFree(pidl); 243 | } 244 | else LOGG(12, "SHGetSpecialFolderLocation failed for CSIDL_APPDATA"); 245 | } 246 | 247 | pth::appendSlash(_ctxFile, MAX_PATH); 248 | ::StringCchCatW(_ctxFile, MAX_PATH, CTX_FILE_NAME); 249 | LOGG(12, "Will use \"%S\"", _ctxFile); 250 | } 251 | */ 252 | 253 | void backupFiles() 254 | { 255 | WCHAR backupDir[MAX_PATH]; 256 | 257 | // Create main backup directory if missing and copy config files. 258 | ::StringCchCopyW(backupDir, MAX_PATH, _cfgDir); 259 | ::StringCchCatW(backupDir, MAX_PATH, BAK_DIR_NAME); 260 | if (!pth::dirExists(backupDir)) { 261 | ::CreateDirectoryW(backupDir, NULL); 262 | } 263 | if (pth::dirExists(backupDir)) { 264 | ::StringCchCatW(backupDir, MAX_PATH, L"\\"); 265 | backupConfigFiles(backupDir); 266 | // Create backup directory for session files if missing and copy session files. 267 | ::StringCchCatW(backupDir, MAX_PATH, BAK_SES_DIR_NAME); 268 | if (!pth::dirExists(backupDir)) { 269 | ::CreateDirectoryW(backupDir, NULL); 270 | } 271 | if (pth::dirExists(backupDir)) { 272 | ::StringCchCatW(backupDir, MAX_PATH, L"\\"); 273 | backupSessionFiles(backupDir); 274 | } 275 | } 276 | } 277 | 278 | void backupConfigFiles(LPCWSTR backupDir) 279 | { 280 | WCHAR dstFile[MAX_PATH]; 281 | 282 | // Copy settings.xml 283 | if (pth::fileExists(_cfgFile)) { 284 | ::StringCchCopyW(dstFile, MAX_PATH, backupDir); 285 | ::StringCchCatW(dstFile, MAX_PATH, CFG_FILE_NAME); 286 | ::CopyFileW(_cfgFile, dstFile, FALSE); 287 | } 288 | // Copy global.xml 289 | if (pth::fileExists(_glbFile)) { 290 | ::StringCchCopyW(dstFile, MAX_PATH, backupDir); 291 | ::StringCchCatW(dstFile, MAX_PATH, GLB_FILE_NAME); 292 | ::CopyFileW(_glbFile, dstFile, FALSE); 293 | } 294 | // Copy NPP's contextMenu.xml 295 | if (pth::fileExists(_ctxFile)) { 296 | ::StringCchCopyW(dstFile, MAX_PATH, backupDir); 297 | ::StringCchCatW(dstFile, MAX_PATH, CTX_FILE_NAME); 298 | ::CopyFileW(_ctxFile, dstFile, FALSE); 299 | } 300 | } 301 | 302 | void backupSessionFiles(LPCWSTR backupDir) 303 | { 304 | HANDLE hFind; 305 | WIN32_FIND_DATAW ffd; 306 | WCHAR fileSpec[MAX_PATH]; 307 | WCHAR srcFile[MAX_PATH]; 308 | WCHAR dstFile[MAX_PATH]; 309 | 310 | // Create the file spec. 311 | ::StringCchCopyW(fileSpec, MAX_PATH, cfg::getStr(kSessionDirectory)); 312 | ::StringCchCatW(fileSpec, MAX_PATH, L"*.*"); 313 | // Loop over files in the session directory and copy them to the backup directory. 314 | hFind = ::FindFirstFileW(fileSpec, &ffd); 315 | if (hFind == INVALID_HANDLE_VALUE) { 316 | return; 317 | } 318 | do { 319 | ::StringCchCopyW(srcFile, MAX_PATH, cfg::getStr(kSessionDirectory)); 320 | ::StringCchCatW(srcFile, MAX_PATH, ffd.cFileName); 321 | ::StringCchCopyW(dstFile, MAX_PATH, backupDir); 322 | ::StringCchCatW(dstFile, MAX_PATH, ffd.cFileName); 323 | ::CopyFileW(srcFile, dstFile, FALSE); 324 | } 325 | while (::FindNextFileW(hFind, &ffd) != 0); 326 | ::FindClose(hFind); 327 | } 328 | 329 | } // end namespace 330 | 331 | } // end namespace NppPlugin 332 | 333 | -------------------------------------------------------------------------------- /src/System.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file System.h 13 | @copyright Copyright 2011,2014,2015 Michael Foster 14 | */ 15 | 16 | #ifndef NPP_PLUGIN_SYSTEM_H 17 | #define NPP_PLUGIN_SYSTEM_H 18 | 19 | #define SES_DEFAULT_CONTENTS "\n\n" 20 | 21 | #include 22 | #include "npp\PluginInterface.h" 23 | 24 | //------------------------------------------------------------------------------ 25 | 26 | namespace NppPlugin { 27 | 28 | //------------------------------------------------------------------------------ 29 | /// @namespace NppPlugin::api Contains functions called only from DllMain. 30 | 31 | namespace api { 32 | 33 | void sys_onLoad(HINSTANCE hDLLInstance); 34 | void sys_onUnload(); 35 | void sys_init(NppData nppd); 36 | 37 | } // end namespace NppPlugin::api 38 | 39 | //------------------------------------------------------------------------------ 40 | 41 | LPWSTR sys_getCfgDir(); 42 | LPWSTR sys_getSettingsFile(); 43 | LPWSTR sys_getGlobalFile(); 44 | LPCWSTR sys_getNppCtxMnuFile(); 45 | HINSTANCE sys_getDllHandle(); 46 | HWND sys_getNppHandle(); 47 | HWND sys_getSciHandle(INT v); 48 | DWORD sys_getNppVer(); 49 | UINT sys_getWinVer(); 50 | LPVOID sys_alloc(INT bytes); 51 | void sys_free(LPVOID p); 52 | 53 | } // end namespace NppPlugin 54 | 55 | #endif // NPP_PLUGIN_SYSTEM_H 56 | -------------------------------------------------------------------------------- /src/Util.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file Util.cpp 13 | @copyright Copyright 2011-2015 Michael Foster 14 | */ 15 | 16 | #include "System.h" 17 | #include "SessionMgr.h" 18 | #include "Util.h" 19 | #include "utf8\unchecked.h" 20 | #include 21 | 22 | //------------------------------------------------------------------------------ 23 | 24 | namespace NppPlugin { 25 | 26 | //------------------------------------------------------------------------------ 27 | 28 | namespace msg { 29 | 30 | /** Displays a simple message box. For title/options see the M_* constants. */ 31 | INT show(LPCWSTR msg, LPWSTR title, UINT options) 32 | { 33 | return ::MessageBoxW(sys_getNppHandle(), msg, title != NULL ? title : PLUGIN_FULL_NAME, options); 34 | } 35 | 36 | /** Displays an error message and logs it. lastError is expected to be from GetLastError. */ 37 | void error(DWORD lastError, LPCWSTR format, ...) 38 | { 39 | INT len; 40 | va_list argptr; 41 | LPWSTR buf, buf1, buf2 = NULL, lem, lastErrorMsg = NULL; 42 | 43 | va_start(argptr, format); 44 | len = ::_vscwprintf(format, argptr); 45 | buf1 = (LPWSTR)sys_alloc((len + 2) * sizeof(WCHAR)); 46 | if (buf1 == NULL) { 47 | log("Error allocating %u bytes for: \"%S\".", (len + 2) * sizeof(WCHAR), format); 48 | return; 49 | } 50 | ::vswprintf_s(buf1, len + 1, format, argptr); 51 | va_end(argptr); 52 | buf = buf1; 53 | 54 | if (lastError) { 55 | FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 56 | NULL, lastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), lastErrorMsg, 0, NULL); 57 | lem = lastErrorMsg == NULL ? EMPTY_STR : lastErrorMsg; 58 | LPCWSTR fmt = L"%s\nError %lu: %s"; 59 | len = ::_scwprintf(fmt, buf1, lastError, lem); 60 | buf2 = (LPWSTR)sys_alloc((len + 2) * sizeof(WCHAR)); 61 | if (buf2) { 62 | ::swprintf_s(buf2, len + 1, fmt, buf1, lastError, lem); 63 | buf = buf2; 64 | } 65 | } 66 | 67 | show(buf, M_ERR); 68 | log("%S", buf); 69 | sys_free(buf1); 70 | sys_free(buf2); 71 | if (lastErrorMsg) { 72 | LocalFree((HLOCAL)lastErrorMsg); 73 | } 74 | } 75 | 76 | /** Writes a formatted UTF-8 string to the debug log file. In format, use "%s" 77 | for ASCII strings and "%S" for wide strings. */ 78 | void log(LPCSTR format, ...) 79 | { 80 | if (gDbgLvl) { 81 | LPCWSTR logFile = cfg::getStr(kDebugLogFile); 82 | if (logFile && *logFile) { 83 | FILE *fp; 84 | ::_wfopen_s(&fp, logFile, L"a+"); 85 | if (fp) { 86 | va_list argptr; 87 | va_start(argptr, format); 88 | ::vfprintf(fp, format, argptr); // Expects 'format' to be UTF-8, vfwprintf would write UTF-16 89 | va_end(argptr); 90 | ::fputwc(L'\n', fp); 91 | ::fflush(fp); 92 | ::fclose(fp); 93 | } 94 | } 95 | } 96 | } 97 | 98 | } // end namespace NppPlugin::msg 99 | 100 | //------------------------------------------------------------------------------ 101 | 102 | namespace pth { 103 | 104 | /** Removes the file name extension. 105 | @return non-zero on error */ 106 | errno_t removeExt(LPWSTR buf, size_t bufLen) 107 | { 108 | errno_t err; 109 | WCHAR drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME]; 110 | err = ::_wsplitpath_s(buf, drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME, NULL, 0); 111 | if (err == 0) { 112 | err = ::_wmakepath_s(buf, bufLen, drive, dir, fname, NULL); 113 | } 114 | return err; 115 | } 116 | 117 | /** Removes the file name, leaving only the path and trailing slash. 118 | @return non-zero on error */ 119 | errno_t removeName(LPWSTR buf, size_t bufLen) 120 | { 121 | errno_t err; 122 | WCHAR drive[_MAX_DRIVE], dir[_MAX_DIR]; 123 | err = ::_wsplitpath_s(buf, drive, _MAX_DRIVE, dir, _MAX_DIR, NULL, 0, NULL, 0); 124 | if (err == 0) { 125 | err = ::_wmakepath_s(buf, bufLen, drive, dir, NULL, NULL); 126 | } 127 | return err; 128 | } 129 | 130 | /** Removes the path, leaving only the file name. 131 | @return non-zero on error */ 132 | errno_t removePath(LPWSTR buf, size_t bufLen) 133 | { 134 | errno_t err; 135 | WCHAR fname[_MAX_FNAME], ext[_MAX_EXT]; 136 | err = ::_wsplitpath_s(buf, NULL, 0, NULL, 0, fname, _MAX_FNAME, ext, _MAX_EXT); 137 | if (err == 0) { 138 | err = ::_wmakepath_s(buf, bufLen, NULL, NULL, fname, ext); 139 | } 140 | return err; 141 | } 142 | 143 | /** Appends a backslash if a trailing backslash or foreslash is not already present. */ 144 | void appendSlash(LPWSTR buf, size_t bufLen) 145 | { 146 | LPWSTR p; 147 | if (buf != NULL) { 148 | p = ::wcsrchr(buf, L'\0'); 149 | if (p != NULL) { 150 | p = ::CharPrevW(buf, p); 151 | if (p != NULL && *p != L'\\' && *p != L'/') { 152 | ::StringCchCatW(buf, bufLen, L"\\"); 153 | } 154 | } 155 | } 156 | } 157 | 158 | /** @return true if path is an existing directory */ 159 | bool dirExists(LPCWSTR path) 160 | { 161 | DWORD a = ::GetFileAttributesW(path); 162 | return (bool)(a != INVALID_FILE_ATTRIBUTES && (a & FILE_ATTRIBUTE_DIRECTORY)); 163 | } 164 | 165 | /** @return true if pathname is an existing file */ 166 | bool fileExists(LPCWSTR pathname) 167 | { 168 | DWORD a = ::GetFileAttributesW(pathname); 169 | return (bool)(a != INVALID_FILE_ATTRIBUTES && !(a & FILE_ATTRIBUTE_DIRECTORY)); 170 | } 171 | 172 | /** Creates a new file with initial contents, if the file doesn't already exist. */ 173 | void createFileIfMissing(LPCWSTR pathname, LPCSTR contents) 174 | { 175 | BOOL suc; 176 | HANDLE hFile; 177 | DWORD len, bytes; 178 | 179 | hFile = ::CreateFileW(pathname, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); 180 | if (hFile != INVALID_HANDLE_VALUE) { 181 | len = ::strlen(contents); 182 | suc = ::WriteFile(hFile, contents, len, &bytes, NULL); 183 | if (!suc || bytes != len) { 184 | WCHAR msg[MAX_PATH]; 185 | ::StringCchCopyW(msg, MAX_PATH, L"Failed creating file: "); 186 | ::StringCchCatW(msg, MAX_PATH, pathname); 187 | msg::show(msg, M_ERR); 188 | } 189 | ::CloseHandle(hFile); 190 | } 191 | } 192 | 193 | } // end namespace NppPlugin::pth 194 | 195 | //------------------------------------------------------------------------------ 196 | 197 | namespace str { 198 | 199 | /** Writes src to dst with ampersands removed. */ 200 | void removeAmp(LPCWSTR src, LPWSTR dst) 201 | { 202 | while (*src != 0) { 203 | if (*src != L'&') { 204 | *dst++ = *src; 205 | } 206 | ++src; 207 | } 208 | *dst = 0; 209 | } 210 | 211 | /** Writes src to dst with ampersands removed. */ 212 | void removeAmp(LPCSTR src, LPSTR dst) 213 | { 214 | while (*src != 0) { 215 | if (*src != '&') { 216 | *dst++ = *src; 217 | } 218 | ++src; 219 | } 220 | *dst = 0; 221 | } 222 | 223 | /** Case-insensitive wildcard match. */ 224 | bool wildcardMatchI(LPCWSTR wild, LPCWSTR str) 225 | { 226 | WCHAR lcWild[MAX_PATH], lcStr[MAX_PATH]; 227 | 228 | ::StringCchCopyW(lcWild, MAX_PATH, wild); 229 | ::StringCchCopyW(lcStr, MAX_PATH, str); 230 | ::CharLower(lcWild); 231 | ::CharLower(lcStr); 232 | return wildcardMatch(lcWild, lcStr); 233 | } 234 | 235 | /** Originally written by Jack Handy and slightly modified by Mike Foster. 236 | @see http://www.codeproject.com/Articles/1088/Wildcard-string-compare-globbing */ 237 | bool wildcardMatch(LPCWSTR wild, LPCWSTR str) 238 | { 239 | LPCWSTR cp = NULL, mp = NULL; 240 | 241 | while (*str && *wild != L'*') { 242 | if (*wild != *str && *wild != L'?') { 243 | return false; 244 | } 245 | wild++; 246 | str++; 247 | } 248 | 249 | while (*str) { 250 | if (*wild == L'*') { 251 | if (!*++wild) { 252 | return true; 253 | } 254 | mp = wild; 255 | cp = str + 1; 256 | } 257 | else if (*wild == *str || *wild == L'?') { 258 | wild++; 259 | str++; 260 | } 261 | else { 262 | wild = mp; 263 | str = cp++; 264 | } 265 | } 266 | 267 | while (*wild == L'*') { 268 | wild++; 269 | } 270 | 271 | return !*wild; 272 | } 273 | 274 | /** Converts a UTF-8 string to a string where all chars < 32 or > 126 are 275 | converted to entities. Pass NULL for buf to get the size needed for buf. 276 | @return the number of bytes in the converted string including the terminator */ 277 | INT utf8ToAscii(LPCSTR str, LPSTR buf) 278 | { 279 | INT bytes = 0; 280 | LPSTR b = buf; 281 | LPCSTR s = str; 282 | utf8::uint32_t cp; 283 | while (*s) { 284 | cp = utf8::unchecked::next(s); 285 | if (cp < 32 || cp > 126) { 286 | if (buf) { 287 | ::sprintf_s(b, 9, "&#x%04X;", cp); 288 | b += 8; 289 | } 290 | bytes += 8; 291 | } 292 | else { 293 | if (buf) { 294 | *b++ = (unsigned char)cp; 295 | } 296 | ++bytes; 297 | } 298 | } 299 | if (buf) { 300 | *b = 0; 301 | } 302 | return bytes + 1; 303 | } 304 | 305 | /** cStr must be zero-terminated. 306 | @return a pointer to an allocated buffer which caller must free, else NULL 307 | on error */ 308 | LPWSTR utf8ToUtf16(LPCSTR cStr) 309 | { 310 | return utf8ToUtf16(cStr, NULL, 0); 311 | } 312 | 313 | /** cStr must be zero-terminated. 314 | @return if buf is NULL, a pointer to an allocated buffer which caller must 315 | free, else buf, or NULL on error */ 316 | LPWSTR utf8ToUtf16(LPCSTR cStr, LPWSTR buf, size_t bufLen) 317 | { 318 | size_t wLen; 319 | DWORD lastError; 320 | LPWSTR wBuf = NULL; 321 | 322 | wLen = ::MultiByteToWideChar(CP_UTF8, 0, cStr, -1, NULL, 0); 323 | if (wLen > 0) { 324 | if (buf) { 325 | if (bufLen >= wLen) { 326 | if (::MultiByteToWideChar(CP_UTF8, 0, cStr, -1, buf, bufLen)) { 327 | wBuf = buf; 328 | } 329 | else { 330 | lastError = ::GetLastError(); 331 | LOG("Error %lu for \"%s\".", lastError, cStr); 332 | } 333 | } 334 | else { 335 | LOG("Error. Provided buffer size (%i) is smaller than required (%i) for \"%s\".", bufLen, wLen, cStr); 336 | } 337 | } 338 | else { 339 | wBuf = (LPWSTR)sys_alloc(wLen * sizeof(WCHAR)); 340 | if (wBuf) { 341 | if (!::MultiByteToWideChar(CP_UTF8, 0, cStr, -1, wBuf, wLen)) { 342 | lastError = ::GetLastError(); 343 | LOG("Error %lu for \"%s\".", lastError, cStr); 344 | sys_free(wBuf); 345 | wBuf = NULL; 346 | } 347 | } 348 | else { 349 | LOG("Error allocating %u bytes for \"%s\".", wLen * sizeof(WCHAR), cStr); 350 | } 351 | } 352 | } 353 | else { 354 | lastError = ::GetLastError(); 355 | LOG("Error %lu. Invalid characters in \"%s\".", lastError, cStr); 356 | } 357 | 358 | return wBuf; 359 | } 360 | 361 | /** wStr must be zero-terminated. 362 | @return a pointer to an allocated buffer which caller must free, else NULL 363 | on error */ 364 | LPSTR utf16ToUtf8(LPCWSTR wStr) 365 | { 366 | return utf16ToUtf8(wStr, NULL, 0); 367 | } 368 | 369 | /** wStr must be zero-terminated. 370 | @return if buf is NULL, a pointer to an allocated buffer which caller must 371 | free, else buf, or NULL on error */ 372 | LPSTR utf16ToUtf8(LPCWSTR wStr, LPSTR buf, size_t bufLen) 373 | { 374 | size_t cLen; 375 | DWORD lastError; 376 | LPSTR cBuf = NULL; 377 | 378 | cLen = ::WideCharToMultiByte(CP_UTF8, 0, wStr, -1, NULL, 0, NULL, NULL); 379 | if (cLen > 0) { 380 | if (buf) { 381 | if (bufLen >= cLen) { 382 | if (::WideCharToMultiByte(CP_UTF8, 0, wStr, -1, buf, bufLen, NULL, NULL)) { 383 | cBuf = buf; 384 | } 385 | else { 386 | lastError = ::GetLastError(); 387 | LOG("Error %lu for \"%S\".", lastError, wStr); 388 | } 389 | } 390 | else { 391 | LOG("Error. Provided buffer size (%i) is smaller than required (%i) for \"%S\".", bufLen, cLen, wStr); 392 | } 393 | } 394 | else { 395 | cBuf = (LPSTR)sys_alloc(cLen * sizeof(CHAR)); 396 | if (cBuf) { 397 | if (!::WideCharToMultiByte(CP_UTF8, 0, wStr, -1, cBuf, cLen, NULL, NULL)) { 398 | lastError = ::GetLastError(); 399 | LOG("Error %lu for \"%S\".", lastError, wStr); 400 | sys_free(cBuf); 401 | cBuf = NULL; 402 | } 403 | } 404 | else { 405 | LOG("Error allocating %u bytes for \"%S\".", cLen * sizeof(WCHAR), wStr); 406 | } 407 | } 408 | } 409 | else { 410 | lastError = ::GetLastError(); 411 | LOG("Error %lu. Invalid characters in \"%S\".", lastError, wStr); 412 | } 413 | 414 | return cBuf; 415 | } 416 | 417 | } // end namespace NppPlugin::str 418 | 419 | //------------------------------------------------------------------------------ 420 | 421 | namespace dlg { 422 | 423 | void setText(HWND hDlg, UINT idCtrl, LPCWSTR text) 424 | { 425 | HWND hCtrl = ::GetDlgItem(hDlg, idCtrl); 426 | if (hCtrl) { 427 | ::SetWindowTextW(hCtrl, text); 428 | redrawControl(hDlg, hCtrl); 429 | } 430 | } 431 | 432 | void getText(HWND hDlg, UINT idCtrl, LPWSTR buf, size_t bufLen) 433 | { 434 | HWND hCtrl = ::GetDlgItem(hDlg, idCtrl); 435 | if (hCtrl) { 436 | buf[0] = 0; 437 | ::GetWindowTextW(hCtrl, buf, bufLen); 438 | //::SendMessage(hCtrl, WM_GETTEXT, bufLen, (LPARAM)buf); 439 | } 440 | } 441 | 442 | bool edtModified(HWND hDlg, UINT idCtrl) 443 | { 444 | bool modified = false; 445 | HWND hCtrl = ::GetDlgItem(hDlg, idCtrl); 446 | if (hCtrl) { 447 | if (::SendMessage(hCtrl, EM_GETMODIFY, 0, 0)) { 448 | modified = true; 449 | } 450 | } 451 | return modified; 452 | } 453 | 454 | void setCheck(HWND hDlg, UINT idCtrl, bool bChecked) 455 | { 456 | HWND hCtrl = ::GetDlgItem(hDlg, idCtrl); 457 | if (hCtrl) { 458 | ::SendMessage(hCtrl, BM_SETCHECK, (WPARAM) (bChecked ? BST_CHECKED : BST_UNCHECKED), 0); 459 | } 460 | } 461 | 462 | bool getCheck(HWND hDlg, UINT idCtrl) 463 | { 464 | HWND hCtrl = ::GetDlgItem(hDlg, idCtrl); 465 | if (hCtrl) { 466 | return (::SendMessage(hCtrl, BM_GETCHECK, 0, 0) == BST_CHECKED) ? true : false; 467 | } 468 | return false; 469 | } 470 | 471 | void focus(HWND hDlg, UINT idCtrl, bool inInit) 472 | { 473 | HWND hCtrl = ::GetDlgItem(hDlg, idCtrl); 474 | if (hCtrl) { 475 | if (inInit) { 476 | ::SetFocus(hCtrl); 477 | } 478 | else { 479 | ::SendMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)hCtrl, TRUE); 480 | } 481 | } 482 | } 483 | 484 | void lbReplaceSelItem(HWND hDlg, UINT idCtrl, LPCWSTR text, LPARAM data) 485 | { 486 | HWND hCtrl = ::GetDlgItem(hDlg, idCtrl); 487 | if (hCtrl) { 488 | ::SendMessage(hCtrl, WM_SETREDRAW, FALSE, 0); 489 | WPARAM lbItemIdx = ::SendMessage(hCtrl, LB_GETCURSEL, 0, 0); 490 | if (::SendMessage(hCtrl, LB_DELETESTRING, lbItemIdx, 0) != LB_ERR) { 491 | if (::SendMessage(hCtrl, LB_INSERTSTRING, lbItemIdx, (LPARAM)text) != LB_ERR) { 492 | ::SendMessage(hCtrl, LB_SETITEMDATA, lbItemIdx, (LPARAM)data); 493 | ::SendMessage(hCtrl, WM_SETREDRAW, TRUE, 0); 494 | ::SendMessage(hCtrl, LB_SETCURSEL, lbItemIdx, 0); 495 | } 496 | } 497 | } 498 | } 499 | 500 | LRESULT getLbSelData(HWND hDlg, UINT idCtrl) 501 | { 502 | HWND hCtrl = ::GetDlgItem(hDlg, idCtrl); 503 | if (hCtrl) { 504 | WPARAM i = ::SendMessage(hCtrl, LB_GETCURSEL, 0, 0); 505 | return ::SendMessage(hCtrl, LB_GETITEMDATA, i, 0); 506 | } 507 | return NULL; 508 | } 509 | 510 | void getCbSelText(HWND hDlg, UINT idCtrl, LPWSTR buf) 511 | { 512 | HWND hCtrl = ::GetDlgItem(hDlg, idCtrl); 513 | if (hCtrl) { 514 | WPARAM i = ::SendMessage(hCtrl, CB_GETCURSEL, 0, 0); 515 | ::SendMessage(hCtrl, CB_GETLBTEXT, i, (LPARAM)buf); 516 | } 517 | } 518 | 519 | /** @see http://stackoverflow.com/questions/1823883/updating-text-in-a-c-win32-api-static-control-drawn-with-ws-ex-transparent */ 520 | void redrawControl(HWND hDlg, HWND hCtrl) 521 | { 522 | RECT r; 523 | ::GetClientRect(hCtrl, &r); 524 | ::InvalidateRect(hCtrl, &r, TRUE); 525 | ::MapWindowPoints(hCtrl, hDlg, (POINT *)&r, 2); 526 | ::RedrawWindow(hDlg, &r, NULL, RDW_ERASE | RDW_INVALIDATE); 527 | } 528 | 529 | /** Centers window hWnd relative to window hParentWnd with the given sizes and offsets. */ 530 | void centerWnd(HWND hWnd, HWND hParentWnd, INT xOffset, INT yOffset, INT width, INT height, bool bRepaint) 531 | { 532 | RECT rect, rectParent; 533 | INT x, y; 534 | if (hParentWnd == NULL) { 535 | hParentWnd = ::GetParent(hWnd); 536 | } 537 | ::GetWindowRect(hParentWnd, &rectParent); 538 | ::GetWindowRect(hWnd, &rect); 539 | width = width > 0 ? width : rect.right - rect.left; 540 | height = height > 0 ? height : rect.bottom - rect.top; 541 | x = ((rectParent.right - rectParent.left) - width) / 2; 542 | x += rectParent.left + xOffset; 543 | y = ((rectParent.bottom - rectParent.top) - height) / 2; 544 | y += rectParent.top + yOffset; 545 | ::MoveWindow(hWnd, x, y, width, height, bRepaint); 546 | } 547 | 548 | /** Sets the control's position and/or size relative to the right and bottom 549 | edges of the dialog. 550 | @param toChange X=1, Y=2, W=4, H=8 551 | @param duoRight offset from dialog right edge in dialog units 552 | @param duoBottom offset from dialog bottom edge in dialog units 553 | @param redraw if true, the control will be redrawn, sometimes needed for 554 | the last row of controls on a dialog 555 | */ 556 | void adjToEdge(HWND hDlg, INT idCtrl, INT dlgW, INT dlgH, INT toChange, INT duoRight, INT duoBottom, bool redraw) 557 | { 558 | HWND hCtrl = ::GetDlgItem(hDlg, idCtrl); 559 | if (hCtrl) { 560 | RECT ro = {0, 0, duoRight, duoBottom}; 561 | ::MapDialogRect(hDlg, &ro); 562 | RECT rc; 563 | POINT p; 564 | ::GetWindowRect(hCtrl, &rc); 565 | 566 | p.x = rc.left; 567 | p.y = rc.top; 568 | ::ScreenToClient(hDlg, &p); 569 | rc.left = p.x; 570 | rc.top = p.y; 571 | 572 | p.x = rc.right; 573 | p.y = rc.bottom; 574 | ::ScreenToClient(hDlg, &p); 575 | rc.right = p.x; 576 | rc.bottom = p.y; 577 | 578 | INT x = rc.left; 579 | INT y = rc.top; 580 | INT w = rc.right - rc.left; 581 | INT h = rc.bottom - rc.top; 582 | 583 | // change x with offset from client right 584 | if (toChange & 1) { 585 | if (duoRight) { 586 | x = dlgW - ro.right; 587 | } 588 | } 589 | // or change width with offset from client right 590 | else if (toChange & 4) { 591 | if (duoRight) { 592 | w = dlgW - ro.right - x; 593 | } 594 | } 595 | // change y with offset from client bottom 596 | if (toChange & 2) { 597 | if (duoBottom) { 598 | y = dlgH - ro.bottom; 599 | } 600 | } 601 | // or change height with offset from client bottom 602 | else if (toChange & 8) { 603 | if (duoBottom) { 604 | h = dlgH - ro.bottom - y; 605 | } 606 | } 607 | 608 | ::MoveWindow(hCtrl, x, y, w, h, true); 609 | if (redraw) { 610 | redrawControl(hDlg, hCtrl); 611 | } 612 | } 613 | } 614 | 615 | } // end namespace NppPlugin::dlg 616 | 617 | } // end namespace NppPlugin 618 | 619 | -------------------------------------------------------------------------------- /src/Util.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file Util.h 13 | @copyright Copyright 2011-2015 Michael Foster 14 | */ 15 | 16 | #ifndef NPP_PLUGIN_UTIL_H 17 | #define NPP_PLUGIN_UTIL_H 18 | 19 | #include "Settings.h" 20 | 21 | //------------------------------------------------------------------------------ 22 | 23 | namespace NppPlugin { 24 | 25 | #define LOG(fmt, ...) msg::log(__FUNCTION__ ": " fmt, __VA_ARGS__) 26 | #define LOGF(fmt, ...) msg::log(__FUNCTION__ "(" fmt ")", __VA_ARGS__) 27 | #define LOGG(lvl, fmt, ...) if (gDbgLvl >= lvl) { LOG(fmt, __VA_ARGS__); } 28 | #define LOGE(lvl, fmt, ...) if (gDbgLvl == lvl) { LOG(fmt, __VA_ARGS__); } 29 | #define LOGR(l1, l2, fmt, ...) if (gDbgLvl >= l1 && gDbgLvl <= l2) { LOG(fmt, __VA_ARGS__); } 30 | #define LOGNN(ntf) LOG("%-20s\t%8u\t%u", ntf, bufferId, _bidBufferActivated) 31 | #define LOGSN(ntf) LOG("%-20s\t%8s\t%u", ntf, "", _bidBufferActivated) 32 | #define __W(x) L ## x 33 | #define _W(x) __W(x) 34 | #define EMPTY_STR L"" 35 | #define SPACE_STR L" " 36 | // msg::show title and options 37 | #define M_DBG PLUGIN_FULL_NAME SPACE_STR L"Debug", (MB_OK | MB_ICONWARNING) 38 | #define M_ERR PLUGIN_FULL_NAME SPACE_STR L"Error", (MB_OK | MB_ICONERROR) 39 | #define M_WARN PLUGIN_FULL_NAME SPACE_STR L"Warning", (MB_OK | MB_ICONWARNING) 40 | #define M_INFO PLUGIN_FULL_NAME, (MB_OK | MB_ICONINFORMATION) 41 | 42 | inline LPCWSTR boolToStr(const bool b) { return b ? L"true" : L"false"; } 43 | inline const bool uintToBool(UINT n) { return n == 0 ? false : true; } 44 | 45 | //------------------------------------------------------------------------------ 46 | /** @namespace NppPlugin::msg Contains functions for displaying error and 47 | informational messages to the user and for logging to the debug log file. */ 48 | 49 | namespace msg { 50 | 51 | INT show(LPCWSTR msg, LPWSTR title = NULL, UINT options = MB_OK); 52 | void error(DWORD lastError, LPCWSTR format, ...); 53 | void log(LPCSTR format, ...); 54 | 55 | } // end namespace NppPlugin::msg 56 | 57 | //------------------------------------------------------------------------------ 58 | /** @namespace NppPlugin::pth Contains functions for manipulating file paths, 59 | checking the existence of directories and files, and creating new files. */ 60 | 61 | namespace pth { 62 | 63 | errno_t removeExt(LPWSTR buf, size_t bufLen); 64 | errno_t removeName(LPWSTR buf, size_t bufLen); 65 | errno_t removePath(LPWSTR buf, size_t bufLen); 66 | void appendSlash(LPWSTR buf, size_t bufLen); 67 | bool dirExists(LPCWSTR path); 68 | bool fileExists(LPCWSTR pathname); 69 | void createFileIfMissing(LPCWSTR pathname, LPCSTR contents); 70 | 71 | } // end namespace NppPlugin::pth 72 | 73 | //------------------------------------------------------------------------------ 74 | /// @namespace NppPlugin::str Contains string utility functions. 75 | 76 | namespace str { 77 | 78 | void removeAmp(LPCWSTR src, LPWSTR dst); 79 | void removeAmp(LPCSTR src, LPSTR dst); 80 | bool wildcardMatchI(LPCWSTR wild, LPCWSTR str); 81 | bool wildcardMatch(LPCWSTR wild, LPCWSTR str); 82 | INT utf8ToAscii(LPCSTR str, LPSTR buf = NULL); 83 | LPWSTR utf8ToUtf16(LPCSTR cStr); 84 | LPWSTR utf8ToUtf16(LPCSTR cStr, LPWSTR buf, size_t bufLen); 85 | LPSTR utf16ToUtf8(LPCWSTR wStr); 86 | LPSTR utf16ToUtf8(LPCWSTR wStr, LPSTR buf, size_t bufLen); 87 | 88 | } // end namespace NppPlugin::str 89 | 90 | //------------------------------------------------------------------------------ 91 | /// @namespace NppPlugin::dlg Contains functions for managing dialog controls. 92 | 93 | namespace dlg { 94 | 95 | void setText(HWND hDlg, UINT idCtrl, LPCWSTR text); 96 | void getText(HWND hDlg, UINT idCtrl, LPWSTR buf, size_t bufLen); 97 | bool edtModified(HWND hDlg, UINT idCtrl); 98 | void setCheck(HWND hDlg, UINT idCtrl, bool bChecked); 99 | bool getCheck(HWND hDlg, UINT idCtrl); 100 | void focus(HWND hDlg, UINT idCtrl, bool inInit = true); 101 | void lbReplaceSelItem(HWND hDlg, UINT idCtrl, LPCWSTR text, LPARAM data); 102 | LRESULT getLbSelData(HWND hDlg, UINT idCtrl); 103 | void getCbSelText(HWND hDlg, UINT idCtrl, LPWSTR buf); 104 | void redrawControl(HWND hDlg, HWND hCtrl); 105 | void centerWnd(HWND hWnd, HWND hParentWnd, INT xOffset = 0, INT yOffset = 0, INT width = 0, INT height = 0, bool bRepaint = FALSE); 106 | void adjToEdge(HWND hDlg, INT idCtrl, INT dlgW, INT dlgH, INT toChange, INT duoRight, INT duoBottom, bool redraw = false); 107 | 108 | } // end namespace NppPlugin::dlg 109 | 110 | } // end namespace NppPlugin 111 | 112 | #endif // NPP_PLUGIN_UTIL_H 113 | -------------------------------------------------------------------------------- /src/npp/PluginInterface.h: -------------------------------------------------------------------------------- 1 | // This file is part of Notepad++ project 2 | // Copyright (C)2003 Don HO 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either 7 | // version 2 of the License, or (at your option) any later version. 8 | // 9 | // Note that the GPL places important restrictions on "derived works", yet 10 | // it does not provide a detailed definition of that term. To avoid 11 | // misunderstandings, we consider an application to constitute a 12 | // "derivative work" for the purpose of this license if it does any of the 13 | // following: 14 | // 1. Integrates source code from Notepad++. 15 | // 2. Integrates/includes/aggregates Notepad++ into a proprietary executable 16 | // installer, such as those produced by InstallShield. 17 | // 3. Links to a library or executes a program that does any of the above. 18 | // 19 | // This program is distributed in the hope that it will be useful, 20 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | // GNU General Public License for more details. 23 | // 24 | // You should have received a copy of the GNU General Public License 25 | // along with this program; if not, write to the Free Software 26 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 27 | 28 | 29 | #ifndef PLUGININTERFACE_H 30 | #define PLUGININTERFACE_H 31 | 32 | #ifndef SCINTILLA_H 33 | #include "Scintilla.h" 34 | #endif //SCINTILLA_H 35 | 36 | #ifndef NOTEPAD_PLUS_MSGS_H 37 | #include "Notepad_plus_msgs.h" 38 | #endif //NOTEPAD_PLUS_MSGS_H 39 | 40 | #ifndef MENUCMDID_H 41 | #include "menuCmdID.h" 42 | #endif //MENUCMDID_H 43 | 44 | const int nbChar = 64; 45 | 46 | typedef const TCHAR * (__cdecl * PFUNCGETNAME)(); 47 | 48 | struct NppData { 49 | HWND _nppHandle; 50 | HWND _scintillaMainHandle; 51 | HWND _scintillaSecondHandle; 52 | }; 53 | 54 | typedef void (__cdecl * PFUNCSETINFO)(NppData); 55 | typedef void (__cdecl * PFUNCPLUGINCMD)(); 56 | typedef void (__cdecl * PBENOTIFIED)(SCNotification *); 57 | typedef LRESULT (__cdecl * PMESSAGEPROC)(UINT Message, WPARAM wParam, LPARAM lParam); 58 | 59 | 60 | struct ShortcutKey { 61 | bool _isCtrl; 62 | bool _isAlt; 63 | bool _isShift; 64 | UCHAR _key; 65 | }; 66 | 67 | struct FuncItem { 68 | TCHAR _itemName[nbChar]; 69 | PFUNCPLUGINCMD _pFunc; 70 | int _cmdID; 71 | bool _init2Check; 72 | ShortcutKey *_pShKey; 73 | }; 74 | 75 | typedef FuncItem * (__cdecl * PFUNCGETFUNCSARRAY)(int *); 76 | 77 | // You should implement (or define an empty function body) those functions which are called by Notepad++ plugin manager 78 | extern "C" __declspec(dllexport) void setInfo(NppData); 79 | extern "C" __declspec(dllexport) const TCHAR * getName(); 80 | extern "C" __declspec(dllexport) FuncItem * getFuncsArray(int *); 81 | extern "C" __declspec(dllexport) void beNotified(SCNotification *); 82 | extern "C" __declspec(dllexport) LRESULT messageProc(UINT Message, WPARAM wParam, LPARAM lParam); 83 | 84 | #ifdef UNICODE 85 | extern "C" __declspec(dllexport) BOOL isUnicode(); 86 | #endif //UNICODE 87 | 88 | #endif //PLUGININTERFACE_H 89 | -------------------------------------------------------------------------------- /src/res/resource.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file resource.h 13 | @copyright Copyright 2011-2014 Michael Foster 14 | */ 15 | 16 | #ifndef IDC_STATIC 17 | #define IDC_STATIC (-1) 18 | #endif 19 | 20 | // Dialog IDs 21 | #define IDD_SES_DLG 100 22 | #define IDD_NEW_DLG 110 23 | #define IDD_REN_DLG 120 24 | #define IDD_DEL_DLG 130 25 | #define IDD_CFG_DLG 140 26 | 27 | // Control IDs 28 | #define IDC_SES_LST_SES 1000 29 | #define IDC_SES_CMB_FIL 1001 30 | #define IDC_SES_CHK_WILD 1002 31 | #define IDC_SES_BTN_LOAD 1003 32 | #define IDC_SES_BTN_PRV 1004 33 | #define IDC_SES_BTN_SAVE 1005 34 | #define IDC_SES_BTN_NEW 1006 35 | #define IDC_SES_BTN_REN 1007 36 | #define IDC_SES_BTN_DEL 1008 37 | #define IDC_SES_BTN_FAV 1009 38 | #define IDC_SES_BTN_CANCEL 1010 39 | #define IDC_SES_RAD_ALPHA 1011 40 | #define IDC_SES_RAD_DATE 1012 41 | #define IDC_SES_CHK_LIC 1013 42 | #define IDC_SES_CHK_LWC 1014 43 | #define IDC_NEW_ETX_NAME 1100 44 | #define IDC_NEW_RAD_EMPTY 1101 45 | #define IDC_NEW_RAD_COPY 1102 46 | #define IDC_NEW_RAD_OPEN 1103 47 | #define IDC_REN_ETX_NAME 1200 48 | #define IDC_CFG_CHK_ASV 1400 49 | #define IDC_CFG_CHK_ALD 1401 50 | #define IDC_CFG_CHK_LIC 1402 51 | #define IDC_CFG_CHK_LWC 1403 52 | #define IDC_CFG_CHK_SITB 1404 53 | #define IDC_CFG_CHK_SISB 1405 54 | #define IDC_CFG_CHK_GBKM 1406 55 | #define IDC_CFG_CHK_CTXM 1407 56 | #define IDC_CFG_BTN_BRW 1408 57 | #define IDC_CFG_ETX_DIR 1409 58 | #define IDC_CFG_ETX_EXT 1410 59 | 60 | // Common sizes 61 | #define IDC_MAR_1 6 62 | #define IDC_MAR_2 2 63 | #define IDC_MAR_3 3 64 | #define IDC_BTN_W 34 65 | #define IDC_BTN_H 13 66 | #define IDC_ETX_H 13 67 | #define IDC_LTX_H 8 68 | #define IDC_CHK_H 8 69 | 70 | /* 71 | The Sessions dialog 72 | */ 73 | 74 | #define IDD_SES_W 187 75 | #define IDD_SES_H 230 76 | 77 | // Right and bottom offsets (for moving/resizing) 78 | #define IDC_SES_CMB_WRO (IDC_MAR_1 + IDC_BTN_W + IDC_MAR_1) 79 | #define IDC_SES_LST_WRO IDC_SES_CMB_WRO 80 | #define IDC_SES_LST_HBO (IDC_MAR_1 + IDC_CHK_H + IDC_MAR_2 + IDC_CHK_H + IDC_MAR_1) 81 | #define IDC_SES_BTN_XRO (IDC_MAR_1 + IDC_BTN_W) 82 | #define IDC_SES_OPT_R1_YBO (IDC_MAR_1 + IDC_CHK_H + IDC_MAR_3 + IDC_CHK_H) 83 | #define IDC_SES_OPT_R2_YBO (IDC_MAR_1 + IDC_CHK_H) 84 | 85 | #define IDC_SES_CMB_FIL_X IDC_MAR_1 86 | #define IDC_SES_CMB_FIL_Y IDC_MAR_1 87 | #define IDC_SES_CMB_FIL_W (IDD_SES_W - IDC_SES_CMB_FIL_X - IDC_SES_CMB_WRO) 88 | #define IDC_SES_CMB_FIL_H IDC_ETX_H 89 | 90 | #define IDC_SES_LST_SES_X IDC_MAR_1 91 | #define IDC_SES_LST_SES_Y (IDC_SES_CMB_FIL_Y + IDC_SES_CMB_FIL_H + IDC_MAR_3) 92 | #define IDC_SES_LST_SES_W (IDD_SES_W - IDC_SES_LST_SES_X - IDC_SES_LST_WRO) 93 | #define IDC_SES_LST_SES_H (IDD_SES_H - IDC_SES_LST_SES_Y - IDC_SES_LST_HBO) 94 | 95 | #define IDC_SES_OPT_R1_Y (IDD_SES_H - IDC_SES_OPT_R1_YBO) 96 | #define IDC_SES_OPT_R2_Y (IDD_SES_H - IDC_SES_OPT_R2_YBO) 97 | 98 | #define IDC_SES_CHK_WILD_Y (IDC_MAR_1 + 2) 99 | 100 | #define IDC_SES_BTN_X (IDD_SES_W - IDC_SES_BTN_XRO) 101 | #define IDC_SES_BTN_LOAD_Y IDC_SES_LST_SES_Y 102 | #define IDC_SES_BTN_PRV_Y (IDC_SES_BTN_LOAD_Y + IDC_MAR_1 + IDC_BTN_H) 103 | #define IDC_SES_BTN_SAVE_Y (IDC_SES_BTN_PRV_Y + IDC_MAR_1 + IDC_BTN_H) 104 | #define IDC_SES_BTN_NEW_Y (IDC_SES_BTN_SAVE_Y + IDC_MAR_1 + IDC_BTN_H) 105 | #define IDC_SES_BTN_REN_Y (IDC_SES_BTN_NEW_Y + IDC_MAR_1 + IDC_BTN_H) 106 | #define IDC_SES_BTN_DEL_Y (IDC_SES_BTN_REN_Y + IDC_MAR_1 + IDC_BTN_H) 107 | #define IDC_SES_BTN_FAV_Y (IDC_SES_BTN_DEL_Y + IDC_MAR_1 + IDC_BTN_H) 108 | #define IDC_SES_BTN_CANCEL_Y (IDC_SES_BTN_FAV_Y + IDC_MAR_1 + IDC_BTN_H) 109 | 110 | // Child dialogs of the Sessions dialog 111 | #define IDD_CDLG_W 164 112 | #define IDC_CDLG_TXT_W 150 113 | #define IDC_CDLG_RAD_W 120 114 | 115 | /* 116 | The Settings dialog 117 | */ 118 | 119 | #define IDD_CFG_W 315 120 | #define IDD_CFG_H 120 121 | 122 | // Right and bottom offsets (for moving/resizing) 123 | #define IDC_CFG_ETX_WRO IDC_MAR_1 124 | #define IDC_CFG_BTN_YBO (IDC_MAR_1 + IDC_BTN_H) 125 | #define IDC_CFG_BTN_OK_XRO (IDC_MAR_1 + IDC_BTN_W + IDC_MAR_1 + IDC_BTN_W) 126 | #define IDC_CFG_BTN_CAN_XRO (IDC_MAR_1 + IDC_BTN_W) 127 | 128 | #define IDC_CFG_ETX_DIR_X 25 129 | #define IDC_CFG_ETX_DIR_Y 50 130 | #define IDC_CFG_ETX_DIR_W (IDD_CFG_W - IDC_CFG_ETX_DIR_X - IDC_CFG_ETX_WRO) 131 | #define IDC_CFG_ETX_DIR_H IDC_ETX_H 132 | 133 | #define IDC_CFG_ETX_EXT_X IDC_MAR_1 134 | #define IDC_CFG_ETX_EXT_Y 78 135 | #define IDC_CFG_ETX_EXT_W (IDD_CFG_W - IDC_CFG_ETX_EXT_X - IDC_CFG_ETX_WRO) 136 | #define IDC_CFG_ETX_EXT_H IDC_ETX_H 137 | 138 | #define IDC_CFG_BTN_OK_X (IDD_CFG_W - IDC_CFG_BTN_OK_XRO) 139 | #define IDC_CFG_BTN_OK_Y (IDD_CFG_H - IDC_CFG_BTN_YBO) 140 | #define IDC_CFG_BTN_CAN_X (IDD_CFG_W - IDC_CFG_BTN_CAN_XRO) 141 | #define IDC_CFG_BTN_CAN_Y IDC_CFG_BTN_OK_Y 142 | 143 | 144 | -------------------------------------------------------------------------------- /src/res/resource.rc: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file resource.rc 13 | @copyright Copyright 2011-2014 Michael Foster 14 | */ 15 | 16 | #include 17 | #include 18 | #include "resource.h" 19 | #include "version.rc2" 20 | 21 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 22 | IDD_SES_DLG DIALOGEX 0, 0, IDD_SES_W, IDD_SES_H 23 | STYLE WS_SIZEBOX | DS_SHELLFONT | WS_CAPTION | WS_POPUP 24 | EXSTYLE WS_EX_TOOLWINDOW 25 | CAPTION " Session Manager" 26 | FONT 8, "MS Shell Dlg", 400, 0, 0 27 | { 28 | COMBOBOX IDC_SES_CMB_FIL, IDC_SES_CMB_FIL_X, IDC_SES_CMB_FIL_Y, IDC_SES_CMB_FIL_W, IDC_SES_CMB_FIL_H, WS_TABSTOP | CBS_DROPDOWN | CBS_HASSTRINGS | CBS_AUTOHSCROLL, WS_EX_LEFT 29 | LISTBOX IDC_SES_LST_SES, IDC_SES_LST_SES_X, IDC_SES_LST_SES_Y, IDC_SES_LST_SES_W, IDC_SES_LST_SES_H, WS_TABSTOP | WS_VSCROLL | LBS_NOINTEGRALHEIGHT | LBS_NOTIFY | LBS_USETABSTOPS | LBS_WANTKEYBOARDINPUT 30 | AUTOCHECKBOX "* ?", IDC_SES_CHK_WILD, IDC_SES_BTN_X, IDC_SES_CHK_WILD_Y, IDC_BTN_W, IDC_CHK_H, BS_VCENTER, WS_EX_LEFT 31 | DEFPUSHBUTTON "&Load", IDC_SES_BTN_LOAD, IDC_SES_BTN_X, IDC_SES_BTN_LOAD_Y, IDC_BTN_W, IDC_BTN_H, BS_CENTER 32 | PUSHBUTTON "&Previous", IDC_SES_BTN_PRV, IDC_SES_BTN_X, IDC_SES_BTN_PRV_Y, IDC_BTN_W, IDC_BTN_H, BS_CENTER 33 | PUSHBUTTON "&Save", IDC_SES_BTN_SAVE, IDC_SES_BTN_X, IDC_SES_BTN_SAVE_Y, IDC_BTN_W, IDC_BTN_H, BS_CENTER 34 | PUSHBUTTON "New", IDC_SES_BTN_NEW, IDC_SES_BTN_X, IDC_SES_BTN_NEW_Y, IDC_BTN_W, IDC_BTN_H, BS_CENTER 35 | PUSHBUTTON "Rename", IDC_SES_BTN_REN, IDC_SES_BTN_X, IDC_SES_BTN_REN_Y, IDC_BTN_W, IDC_BTN_H, BS_CENTER 36 | PUSHBUTTON "Delete", IDC_SES_BTN_DEL, IDC_SES_BTN_X, IDC_SES_BTN_DEL_Y, IDC_BTN_W, IDC_BTN_H, BS_CENTER 37 | PUSHBUTTON "&Favorite", IDC_SES_BTN_FAV, IDC_SES_BTN_X, IDC_SES_BTN_FAV_Y, IDC_BTN_W, IDC_BTN_H, BS_CENTER 38 | PUSHBUTTON "Close", IDC_SES_BTN_CANCEL, IDC_SES_BTN_X, IDC_SES_BTN_CANCEL_Y, IDC_BTN_W, IDC_BTN_H, BS_CENTER 39 | AUTOCHECKBOX "Load &into current", IDC_SES_CHK_LIC, IDC_MAR_1, IDC_SES_OPT_R1_Y, 69, IDC_CHK_H, BS_VCENTER, WS_EX_LEFT 40 | AUTOCHECKBOX "Load &without closing", IDC_SES_CHK_LWC, IDC_MAR_1, IDC_SES_OPT_R2_Y, 81, IDC_CHK_H, BS_VCENTER, WS_EX_LEFT 41 | AUTORADIOBUTTON "Sort by &alpha", IDC_SES_RAD_ALPHA, 89, IDC_SES_OPT_R1_Y, 57, IDC_CHK_H, 0, WS_EX_LEFT 42 | AUTORADIOBUTTON "Sort by &date", IDC_SES_RAD_DATE, 89, IDC_SES_OPT_R2_Y, 54, IDC_CHK_H, 0, WS_EX_LEFT 43 | } 44 | 45 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 46 | IDD_NEW_DLG DIALOGEX 0, 0, IDD_CDLG_W, 98 47 | STYLE DS_MODALFRAME | DS_SHELLFONT | WS_POPUP 48 | FONT 8, "MS Shell Dlg", 400, 0, 1 49 | { 50 | LTEXT "Create New Session", IDC_STATIC, IDC_MAR_1, IDC_MAR_1, IDC_CDLG_TXT_W, IDC_LTX_H, SS_LEFT 51 | EDITTEXT IDC_NEW_ETX_NAME, IDC_MAR_1, 19, 154, IDC_ETX_H, ES_AUTOHSCROLL 52 | AUTORADIOBUTTON "As an empty session", IDC_NEW_RAD_EMPTY, IDC_MAR_1, 36, IDC_CDLG_RAD_W, IDC_CHK_H, WS_GROUP | WS_TABSTOP 53 | AUTORADIOBUTTON "As a copy of the current session", IDC_NEW_RAD_OPEN, IDC_MAR_1, 49, IDC_CDLG_RAD_W, IDC_CHK_H, WS_TABSTOP 54 | AUTORADIOBUTTON "As a copy of the selected session", IDC_NEW_RAD_COPY, IDC_MAR_1, 62, IDC_CDLG_RAD_W, IDC_CHK_H, WS_TABSTOP 55 | DEFPUSHBUTTON "OK", IDOK, 83, 77, IDC_BTN_W, IDC_BTN_H, BS_CENTER 56 | PUSHBUTTON "Cancel", IDCANCEL, 124, 77, IDC_BTN_W, IDC_BTN_H, BS_CENTER 57 | } 58 | 59 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 60 | IDD_REN_DLG DIALOGEX 0, 0, IDD_CDLG_W, 62 61 | STYLE DS_MODALFRAME | DS_SHELLFONT | WS_POPUP | WS_SYSMENU 62 | FONT 8, "MS Shell Dlg", 400, 0, 1 63 | { 64 | LTEXT "Rename Selected Session", IDC_STATIC, IDC_MAR_1, IDC_MAR_1, IDC_CDLG_TXT_W, IDC_LTX_H, SS_LEFT 65 | EDITTEXT IDC_REN_ETX_NAME, IDC_MAR_1, 19, IDC_CDLG_TXT_W, IDC_ETX_H, ES_AUTOHSCROLL 66 | DEFPUSHBUTTON "OK", IDOK, 83, 41, IDC_BTN_W, IDC_BTN_H, BS_CENTER 67 | PUSHBUTTON "Cancel", IDCANCEL, 123, 41, IDC_BTN_W, IDC_BTN_H, BS_CENTER 68 | } 69 | 70 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 71 | IDD_DEL_DLG DIALOGEX 0, 0, IDD_CDLG_W, 44 72 | STYLE DS_MODALFRAME | DS_SHELLFONT | WS_POPUP | WS_SYSMENU 73 | FONT 8, "MS Shell Dlg", 400, 0, 1 74 | { 75 | LTEXT "Delete Selected Session", IDC_STATIC, IDC_MAR_1, IDC_MAR_1, IDC_CDLG_TXT_W, IDC_LTX_H, SS_LEFT 76 | DEFPUSHBUTTON "OK", IDOK, 82, 23, IDC_BTN_W, IDC_BTN_H, BS_CENTER 77 | PUSHBUTTON "Cancel", IDCANCEL, 123, 23, IDC_BTN_W, IDC_BTN_H, BS_CENTER 78 | } 79 | 80 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 81 | IDD_CFG_DLG DIALOGEX 0, 0, IDD_CFG_W, IDD_CFG_H 82 | STYLE WS_SIZEBOX | DS_SHELLFONT | WS_CAPTION | WS_POPUP 83 | EXSTYLE WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_STATICEDGE 84 | CAPTION " Session Manager Settings" 85 | FONT 8, "MS Shell Dlg", 400, 0, 1 86 | { 87 | AUTOCHECKBOX "Auto save", IDC_CFG_CHK_ASV, IDC_MAR_1, IDC_MAR_1, 45, IDC_CHK_H, 0, WS_EX_LEFT 88 | AUTOCHECKBOX "Auto load", IDC_CFG_CHK_ALD, IDC_MAR_1, 23, 45, IDC_CHK_H, 0, WS_EX_LEFT 89 | AUTOCHECKBOX "Load into current", IDC_CFG_CHK_LIC, 63, IDC_MAR_1, 65, IDC_CHK_H, 0, WS_EX_LEFT 90 | AUTOCHECKBOX "Load without closing", IDC_CFG_CHK_LWC, 63, 23, 75, IDC_CHK_H, 0, WS_EX_LEFT 91 | AUTOCHECKBOX "Show in title bar", IDC_CFG_CHK_SITB, 154, IDC_MAR_1, 65, IDC_CHK_H, 0, WS_EX_LEFT 92 | AUTOCHECKBOX "Show in status bar", IDC_CFG_CHK_SISB, 154, 23, 75, IDC_CHK_H, 0, WS_EX_LEFT 93 | AUTOCHECKBOX "Global properties", IDC_CFG_CHK_GBKM, 238, IDC_MAR_1, 65, IDC_CHK_H, 0, WS_EX_LEFT 94 | AUTOCHECKBOX "Use context menu", IDC_CFG_CHK_CTXM, 238, 23, 70, IDC_CHK_H, 0, WS_EX_LEFT 95 | LTEXT "Session files folder", IDC_STATIC, IDC_MAR_1, 40, 60, IDC_LTX_H, SS_LEFT 96 | PUSHBUTTON "...", IDC_CFG_BTN_BRW, IDC_MAR_1, 50, 13, IDC_BTN_H - 1, BS_CENTER 97 | EDITTEXT IDC_CFG_ETX_DIR, IDC_CFG_ETX_DIR_X, IDC_CFG_ETX_DIR_Y, IDC_CFG_ETX_DIR_W, IDC_CFG_ETX_DIR_H, ES_AUTOHSCROLL 98 | LTEXT "Session file extension", IDC_STATIC, IDC_MAR_1, 68, 80, IDC_LTX_H, SS_LEFT 99 | EDITTEXT IDC_CFG_ETX_EXT, IDC_CFG_ETX_EXT_X, IDC_CFG_ETX_EXT_Y, IDC_CFG_ETX_EXT_W, IDC_ETX_H, ES_AUTOHSCROLL 100 | DEFPUSHBUTTON "OK", IDOK, IDC_CFG_BTN_OK_X, IDC_CFG_BTN_OK_Y, IDC_BTN_W, IDC_BTN_H, BS_CENTER 101 | PUSHBUTTON "Cancel", IDCANCEL, IDC_CFG_BTN_CAN_X, IDC_CFG_BTN_CAN_Y, IDC_BTN_W, IDC_BTN_H, BS_CENTER 102 | } 103 | -------------------------------------------------------------------------------- /src/res/version.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SessionMgr, A Plugin for Notepad++. SessionMgr is free 3 | software: you can redistribute it and/or modify it under the terms of the 4 | GNU General Public License as published by the Free Software Foundation, 5 | either version 3 of the License, or (at your option) any later version. 6 | This program is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 9 | more details. You should have received a copy of the GNU General Public 10 | License along with this program. If not, see . 11 | *//** 12 | @file version.h 13 | @copyright Copyright 2011-2015 Michael Foster 14 | */ 15 | 16 | #ifndef NPP_PLUGIN_VERSION_H 17 | #define NPP_PLUGIN_VERSION_H 18 | 19 | 20 | #define RES_VERSION_B 1,4,2,0 21 | #define RES_VERSION_S "1.4.2.0" 22 | #define PLUGIN_VERSION _W(RES_VERSION_S) 23 | #define RES_COPYRIGHT "Copyright 2011-2015 Michael Foster. Distributed under the terms of the GNU GPL." 24 | 25 | 26 | #endif // NPP_PLUGIN_VERSION_H 27 | -------------------------------------------------------------------------------- /src/res/version.rc2: -------------------------------------------------------------------------------- 1 | #include "version.h" 2 | 3 | VS_VERSION_INFO VERSIONINFO 4 | FILEVERSION RES_VERSION_B 5 | PRODUCTVERSION RES_VERSION_B 6 | FILEFLAGSMASK 0x3fL 7 | #ifdef _DEBUG 8 | FILEFLAGS 0x1L 9 | #else 10 | FILEFLAGS 0x0L 11 | #endif 12 | FILEOS 0x40004L 13 | FILETYPE 0x2L 14 | FILESUBTYPE 0x0L 15 | BEGIN 16 | BLOCK "StringFileInfo" 17 | BEGIN 18 | BLOCK "040904b0" 19 | BEGIN 20 | VALUE "CompanyName", "Michael Foster (http://mfoster.com/npp/)" 21 | VALUE "FileDescription", "A plugin for Notepad++" 22 | VALUE "FileVersion", RES_VERSION_S 23 | VALUE "InternalName", "SessionMgr" 24 | VALUE "LegalCopyright", RES_COPYRIGHT 25 | VALUE "OriginalFilename", "SessionMgr.dll" 26 | VALUE "ProductName", "Session Manager" 27 | VALUE "ProductVersion", RES_VERSION_S 28 | END 29 | END 30 | BLOCK "VarFileInfo" 31 | BEGIN 32 | VALUE "Translation", 0x409, 1200 33 | END 34 | END 35 | -------------------------------------------------------------------------------- /src/utf8/checked.h: -------------------------------------------------------------------------------- 1 | // Copyright 2006 Nemanja Trifunovic 2 | 3 | /* 4 | Permission is hereby granted, free of charge, to any person or organization 5 | obtaining a copy of the software and accompanying documentation covered by 6 | this license (the "Software") to use, reproduce, display, distribute, 7 | execute, and transmit the Software, and to prepare derivative works of the 8 | Software, and to permit third-parties to whom the Software is furnished to 9 | do so, all subject to the following: 10 | 11 | The copyright notices in the Software and this entire statement, including 12 | the above license grant, this restriction and the following disclaimer, 13 | must be included in all copies of the Software, in whole or in part, and 14 | all derivative works of the Software, unless such copies or derivative 15 | works are solely in the form of machine-executable object code generated by 16 | a source language processor. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 21 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 22 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 23 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | DEALINGS IN THE SOFTWARE. 25 | */ 26 | 27 | 28 | #ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 29 | #define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 30 | 31 | #include "core.h" 32 | #include 33 | 34 | namespace utf8 35 | { 36 | // Base for the exceptions that may be thrown from the library 37 | class exception : public ::std::exception { 38 | }; 39 | 40 | // Exceptions that may be thrown from the library functions. 41 | class invalid_code_point : public exception { 42 | uint32_t cp; 43 | public: 44 | invalid_code_point(uint32_t cp) : cp(cp) {} 45 | virtual const char* what() const throw() { return "Invalid code point"; } 46 | uint32_t code_point() const {return cp;} 47 | }; 48 | 49 | class invalid_utf8 : public exception { 50 | uint8_t u8; 51 | public: 52 | invalid_utf8 (uint8_t u) : u8(u) {} 53 | virtual const char* what() const throw() { return "Invalid UTF-8"; } 54 | uint8_t utf8_octet() const {return u8;} 55 | }; 56 | 57 | class invalid_utf16 : public exception { 58 | uint16_t u16; 59 | public: 60 | invalid_utf16 (uint16_t u) : u16(u) {} 61 | virtual const char* what() const throw() { return "Invalid UTF-16"; } 62 | uint16_t utf16_word() const {return u16;} 63 | }; 64 | 65 | class not_enough_room : public exception { 66 | public: 67 | virtual const char* what() const throw() { return "Not enough space"; } 68 | }; 69 | 70 | /// The library API - functions intended to be called by the users 71 | 72 | template 73 | octet_iterator append(uint32_t cp, octet_iterator result) 74 | { 75 | if (!utf8::internal::is_code_point_valid(cp)) 76 | throw invalid_code_point(cp); 77 | 78 | if (cp < 0x80) // one octet 79 | *(result++) = static_cast(cp); 80 | else if (cp < 0x800) { // two octets 81 | *(result++) = static_cast((cp >> 6) | 0xc0); 82 | *(result++) = static_cast((cp & 0x3f) | 0x80); 83 | } 84 | else if (cp < 0x10000) { // three octets 85 | *(result++) = static_cast((cp >> 12) | 0xe0); 86 | *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); 87 | *(result++) = static_cast((cp & 0x3f) | 0x80); 88 | } 89 | else { // four octets 90 | *(result++) = static_cast((cp >> 18) | 0xf0); 91 | *(result++) = static_cast(((cp >> 12) & 0x3f) | 0x80); 92 | *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); 93 | *(result++) = static_cast((cp & 0x3f) | 0x80); 94 | } 95 | return result; 96 | } 97 | 98 | template 99 | output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement) 100 | { 101 | while (start != end) { 102 | octet_iterator sequence_start = start; 103 | internal::utf_error err_code = utf8::internal::validate_next(start, end); 104 | switch (err_code) { 105 | case internal::UTF8_OK : 106 | for (octet_iterator it = sequence_start; it != start; ++it) 107 | *out++ = *it; 108 | break; 109 | case internal::NOT_ENOUGH_ROOM: 110 | throw not_enough_room(); 111 | case internal::INVALID_LEAD: 112 | out = utf8::append (replacement, out); 113 | ++start; 114 | break; 115 | case internal::INCOMPLETE_SEQUENCE: 116 | case internal::OVERLONG_SEQUENCE: 117 | case internal::INVALID_CODE_POINT: 118 | out = utf8::append (replacement, out); 119 | ++start; 120 | // just one replacement mark for the sequence 121 | while (start != end && utf8::internal::is_trail(*start)) 122 | ++start; 123 | break; 124 | } 125 | } 126 | return out; 127 | } 128 | 129 | template 130 | inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out) 131 | { 132 | static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd); 133 | return utf8::replace_invalid(start, end, out, replacement_marker); 134 | } 135 | 136 | template 137 | uint32_t next(octet_iterator& it, octet_iterator end) 138 | { 139 | uint32_t cp = 0; 140 | internal::utf_error err_code = utf8::internal::validate_next(it, end, cp); 141 | switch (err_code) { 142 | case internal::UTF8_OK : 143 | break; 144 | case internal::NOT_ENOUGH_ROOM : 145 | throw not_enough_room(); 146 | case internal::INVALID_LEAD : 147 | case internal::INCOMPLETE_SEQUENCE : 148 | case internal::OVERLONG_SEQUENCE : 149 | throw invalid_utf8(*it); 150 | case internal::INVALID_CODE_POINT : 151 | throw invalid_code_point(cp); 152 | } 153 | return cp; 154 | } 155 | 156 | template 157 | uint32_t peek_next(octet_iterator it, octet_iterator end) 158 | { 159 | return utf8::next(it, end); 160 | } 161 | 162 | template 163 | uint32_t prior(octet_iterator& it, octet_iterator start) 164 | { 165 | // can't do much if it == start 166 | if (it == start) 167 | throw not_enough_room(); 168 | 169 | octet_iterator end = it; 170 | // Go back until we hit either a lead octet or start 171 | while (utf8::internal::is_trail(*(--it))) 172 | if (it == start) 173 | throw invalid_utf8(*it); // error - no lead byte in the sequence 174 | return utf8::peek_next(it, end); 175 | } 176 | 177 | /// Deprecated in versions that include "prior" 178 | template 179 | uint32_t previous(octet_iterator& it, octet_iterator pass_start) 180 | { 181 | octet_iterator end = it; 182 | while (utf8::internal::is_trail(*(--it))) 183 | if (it == pass_start) 184 | throw invalid_utf8(*it); // error - no lead byte in the sequence 185 | octet_iterator temp = it; 186 | return utf8::next(temp, end); 187 | } 188 | 189 | template 190 | void advance (octet_iterator& it, distance_type n, octet_iterator end) 191 | { 192 | for (distance_type i = 0; i < n; ++i) 193 | utf8::next(it, end); 194 | } 195 | 196 | template 197 | typename std::iterator_traits::difference_type 198 | distance (octet_iterator first, octet_iterator last) 199 | { 200 | typename std::iterator_traits::difference_type dist; 201 | for (dist = 0; first < last; ++dist) 202 | utf8::next(first, last); 203 | return dist; 204 | } 205 | 206 | template 207 | octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) 208 | { 209 | while (start != end) { 210 | uint32_t cp = utf8::internal::mask16(*start++); 211 | // Take care of surrogate pairs first 212 | if (utf8::internal::is_lead_surrogate(cp)) { 213 | if (start != end) { 214 | uint32_t trail_surrogate = utf8::internal::mask16(*start++); 215 | if (utf8::internal::is_trail_surrogate(trail_surrogate)) 216 | cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; 217 | else 218 | throw invalid_utf16(static_cast(trail_surrogate)); 219 | } 220 | else 221 | throw invalid_utf16(static_cast(cp)); 222 | 223 | } 224 | // Lone trail surrogate 225 | else if (utf8::internal::is_trail_surrogate(cp)) 226 | throw invalid_utf16(static_cast(cp)); 227 | 228 | result = utf8::append(cp, result); 229 | } 230 | return result; 231 | } 232 | 233 | template 234 | u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) 235 | { 236 | while (start != end) { 237 | uint32_t cp = utf8::next(start, end); 238 | if (cp > 0xffff) { //make a surrogate pair 239 | *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); 240 | *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); 241 | } 242 | else 243 | *result++ = static_cast(cp); 244 | } 245 | return result; 246 | } 247 | 248 | template 249 | octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) 250 | { 251 | while (start != end) 252 | result = utf8::append(*(start++), result); 253 | 254 | return result; 255 | } 256 | 257 | template 258 | u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) 259 | { 260 | while (start != end) 261 | (*result++) = utf8::next(start, end); 262 | 263 | return result; 264 | } 265 | 266 | // The iterator class 267 | template 268 | class iterator : public std::iterator { 269 | octet_iterator it; 270 | octet_iterator range_start; 271 | octet_iterator range_end; 272 | public: 273 | iterator () {} 274 | explicit iterator (const octet_iterator& octet_it, 275 | const octet_iterator& range_start, 276 | const octet_iterator& range_end) : 277 | it(octet_it), range_start(range_start), range_end(range_end) 278 | { 279 | if (it < range_start || it > range_end) 280 | throw std::out_of_range("Invalid utf-8 iterator position"); 281 | } 282 | // the default "big three" are OK 283 | octet_iterator base () const { return it; } 284 | uint32_t operator * () const 285 | { 286 | octet_iterator temp = it; 287 | return utf8::next(temp, range_end); 288 | } 289 | bool operator == (const iterator& rhs) const 290 | { 291 | if (range_start != rhs.range_start || range_end != rhs.range_end) 292 | throw std::logic_error("Comparing utf-8 iterators defined with different ranges"); 293 | return (it == rhs.it); 294 | } 295 | bool operator != (const iterator& rhs) const 296 | { 297 | return !(operator == (rhs)); 298 | } 299 | iterator& operator ++ () 300 | { 301 | utf8::next(it, range_end); 302 | return *this; 303 | } 304 | iterator operator ++ (int) 305 | { 306 | iterator temp = *this; 307 | utf8::next(it, range_end); 308 | return temp; 309 | } 310 | iterator& operator -- () 311 | { 312 | utf8::prior(it, range_start); 313 | return *this; 314 | } 315 | iterator operator -- (int) 316 | { 317 | iterator temp = *this; 318 | utf8::prior(it, range_start); 319 | return temp; 320 | } 321 | }; // class iterator 322 | 323 | } // namespace utf8 324 | 325 | #endif //header guard 326 | 327 | 328 | -------------------------------------------------------------------------------- /src/utf8/core.h: -------------------------------------------------------------------------------- 1 | // Copyright 2006 Nemanja Trifunovic 2 | 3 | /* 4 | Permission is hereby granted, free of charge, to any person or organization 5 | obtaining a copy of the software and accompanying documentation covered by 6 | this license (the "Software") to use, reproduce, display, distribute, 7 | execute, and transmit the Software, and to prepare derivative works of the 8 | Software, and to permit third-parties to whom the Software is furnished to 9 | do so, all subject to the following: 10 | 11 | The copyright notices in the Software and this entire statement, including 12 | the above license grant, this restriction and the following disclaimer, 13 | must be included in all copies of the Software, in whole or in part, and 14 | all derivative works of the Software, unless such copies or derivative 15 | works are solely in the form of machine-executable object code generated by 16 | a source language processor. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 21 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 22 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 23 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | DEALINGS IN THE SOFTWARE. 25 | */ 26 | 27 | 28 | #ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 29 | #define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 30 | 31 | #include 32 | 33 | namespace utf8 34 | { 35 | // The typedefs for 8-bit, 16-bit and 32-bit unsigned integers 36 | // You may need to change them to match your system. 37 | // These typedefs have the same names as ones from cstdint, or boost/cstdint 38 | typedef unsigned char uint8_t; 39 | typedef unsigned short uint16_t; 40 | typedef unsigned int uint32_t; 41 | 42 | // Helper code - not intended to be directly called by the library users. May be changed at any time 43 | namespace internal 44 | { 45 | // Unicode constants 46 | // Leading (high) surrogates: 0xd800 - 0xdbff 47 | // Trailing (low) surrogates: 0xdc00 - 0xdfff 48 | const uint16_t LEAD_SURROGATE_MIN = 0xd800u; 49 | const uint16_t LEAD_SURROGATE_MAX = 0xdbffu; 50 | const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u; 51 | const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu; 52 | const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10); 53 | const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN; 54 | 55 | // Maximum valid value for a Unicode code point 56 | const uint32_t CODE_POINT_MAX = 0x0010ffffu; 57 | 58 | template 59 | inline uint8_t mask8(octet_type oc) 60 | { 61 | return static_cast(0xff & oc); 62 | } 63 | template 64 | inline uint16_t mask16(u16_type oc) 65 | { 66 | return static_cast(0xffff & oc); 67 | } 68 | template 69 | inline bool is_trail(octet_type oc) 70 | { 71 | return ((utf8::internal::mask8(oc) >> 6) == 0x2); 72 | } 73 | 74 | template 75 | inline bool is_lead_surrogate(u16 cp) 76 | { 77 | return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX); 78 | } 79 | 80 | template 81 | inline bool is_trail_surrogate(u16 cp) 82 | { 83 | return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); 84 | } 85 | 86 | template 87 | inline bool is_surrogate(u16 cp) 88 | { 89 | return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); 90 | } 91 | 92 | template 93 | inline bool is_code_point_valid(u32 cp) 94 | { 95 | return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp)); 96 | } 97 | 98 | template 99 | inline typename std::iterator_traits::difference_type 100 | sequence_length(octet_iterator lead_it) 101 | { 102 | uint8_t lead = utf8::internal::mask8(*lead_it); 103 | if (lead < 0x80) 104 | return 1; 105 | else if ((lead >> 5) == 0x6) 106 | return 2; 107 | else if ((lead >> 4) == 0xe) 108 | return 3; 109 | else if ((lead >> 3) == 0x1e) 110 | return 4; 111 | else 112 | return 0; 113 | } 114 | 115 | template 116 | inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length) 117 | { 118 | if (cp < 0x80) { 119 | if (length != 1) 120 | return true; 121 | } 122 | else if (cp < 0x800) { 123 | if (length != 2) 124 | return true; 125 | } 126 | else if (cp < 0x10000) { 127 | if (length != 3) 128 | return true; 129 | } 130 | 131 | return false; 132 | } 133 | 134 | enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT}; 135 | 136 | /// Helper for get_sequence_x 137 | template 138 | utf_error increase_safely(octet_iterator& it, octet_iterator end) 139 | { 140 | if (++it == end) 141 | return NOT_ENOUGH_ROOM; 142 | 143 | if (!utf8::internal::is_trail(*it)) 144 | return INCOMPLETE_SEQUENCE; 145 | 146 | return UTF8_OK; 147 | } 148 | 149 | #define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;} 150 | 151 | /// get_sequence_x functions decode utf-8 sequences of the length x 152 | template 153 | utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point) 154 | { 155 | if (it == end) 156 | return NOT_ENOUGH_ROOM; 157 | 158 | code_point = utf8::internal::mask8(*it); 159 | 160 | return UTF8_OK; 161 | } 162 | 163 | template 164 | utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point) 165 | { 166 | if (it == end) 167 | return NOT_ENOUGH_ROOM; 168 | 169 | code_point = utf8::internal::mask8(*it); 170 | 171 | UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) 172 | 173 | code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f); 174 | 175 | return UTF8_OK; 176 | } 177 | 178 | template 179 | utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point) 180 | { 181 | if (it == end) 182 | return NOT_ENOUGH_ROOM; 183 | 184 | code_point = utf8::internal::mask8(*it); 185 | 186 | UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) 187 | 188 | code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff); 189 | 190 | UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) 191 | 192 | code_point += (*it) & 0x3f; 193 | 194 | return UTF8_OK; 195 | } 196 | 197 | template 198 | utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point) 199 | { 200 | if (it == end) 201 | return NOT_ENOUGH_ROOM; 202 | 203 | code_point = utf8::internal::mask8(*it); 204 | 205 | UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) 206 | 207 | code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff); 208 | 209 | UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) 210 | 211 | code_point += (utf8::internal::mask8(*it) << 6) & 0xfff; 212 | 213 | UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) 214 | 215 | code_point += (*it) & 0x3f; 216 | 217 | return UTF8_OK; 218 | } 219 | 220 | #undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR 221 | 222 | template 223 | utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point) 224 | { 225 | // Save the original value of it so we can go back in case of failure 226 | // Of course, it does not make much sense with i.e. stream iterators 227 | octet_iterator original_it = it; 228 | 229 | uint32_t cp = 0; 230 | // Determine the sequence length based on the lead octet 231 | typedef typename std::iterator_traits::difference_type octet_difference_type; 232 | const octet_difference_type length = utf8::internal::sequence_length(it); 233 | 234 | // Get trail octets and calculate the code point 235 | utf_error err = UTF8_OK; 236 | switch (length) { 237 | case 0: 238 | return INVALID_LEAD; 239 | case 1: 240 | err = utf8::internal::get_sequence_1(it, end, cp); 241 | break; 242 | case 2: 243 | err = utf8::internal::get_sequence_2(it, end, cp); 244 | break; 245 | case 3: 246 | err = utf8::internal::get_sequence_3(it, end, cp); 247 | break; 248 | case 4: 249 | err = utf8::internal::get_sequence_4(it, end, cp); 250 | break; 251 | } 252 | 253 | if (err == UTF8_OK) { 254 | // Decoding succeeded. Now, security checks... 255 | if (utf8::internal::is_code_point_valid(cp)) { 256 | if (!utf8::internal::is_overlong_sequence(cp, length)){ 257 | // Passed! Return here. 258 | code_point = cp; 259 | ++it; 260 | return UTF8_OK; 261 | } 262 | else 263 | err = OVERLONG_SEQUENCE; 264 | } 265 | else 266 | err = INVALID_CODE_POINT; 267 | } 268 | 269 | // Failure branch - restore the original value of the iterator 270 | it = original_it; 271 | return err; 272 | } 273 | 274 | template 275 | inline utf_error validate_next(octet_iterator& it, octet_iterator end) { 276 | uint32_t ignored; 277 | return utf8::internal::validate_next(it, end, ignored); 278 | } 279 | 280 | } // namespace internal 281 | 282 | /// The library API - functions intended to be called by the users 283 | 284 | // Byte order mark 285 | const uint8_t bom[] = {0xef, 0xbb, 0xbf}; 286 | 287 | template 288 | octet_iterator find_invalid(octet_iterator start, octet_iterator end) 289 | { 290 | octet_iterator result = start; 291 | while (result != end) { 292 | utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end); 293 | if (err_code != internal::UTF8_OK) 294 | return result; 295 | } 296 | return result; 297 | } 298 | 299 | template 300 | inline bool is_valid(octet_iterator start, octet_iterator end) 301 | { 302 | return (utf8::find_invalid(start, end) == end); 303 | } 304 | 305 | template 306 | inline bool starts_with_bom (octet_iterator it, octet_iterator end) 307 | { 308 | return ( 309 | ((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) && 310 | ((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) && 311 | ((it != end) && (utf8::internal::mask8(*it)) == bom[2]) 312 | ); 313 | } 314 | 315 | //Deprecated in release 2.3 316 | template 317 | inline bool is_bom (octet_iterator it) 318 | { 319 | return ( 320 | (utf8::internal::mask8(*it++)) == bom[0] && 321 | (utf8::internal::mask8(*it++)) == bom[1] && 322 | (utf8::internal::mask8(*it)) == bom[2] 323 | ); 324 | } 325 | } // namespace utf8 326 | 327 | #endif // header guard 328 | 329 | 330 | -------------------------------------------------------------------------------- /src/utf8/unchecked.h: -------------------------------------------------------------------------------- 1 | // Copyright 2006 Nemanja Trifunovic 2 | 3 | /* 4 | Permission is hereby granted, free of charge, to any person or organization 5 | obtaining a copy of the software and accompanying documentation covered by 6 | this license (the "Software") to use, reproduce, display, distribute, 7 | execute, and transmit the Software, and to prepare derivative works of the 8 | Software, and to permit third-parties to whom the Software is furnished to 9 | do so, all subject to the following: 10 | 11 | The copyright notices in the Software and this entire statement, including 12 | the above license grant, this restriction and the following disclaimer, 13 | must be included in all copies of the Software, in whole or in part, and 14 | all derivative works of the Software, unless such copies or derivative 15 | works are solely in the form of machine-executable object code generated by 16 | a source language processor. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 21 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 22 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 23 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | DEALINGS IN THE SOFTWARE. 25 | */ 26 | 27 | 28 | #ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 29 | #define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 30 | 31 | #include "core.h" 32 | 33 | namespace utf8 34 | { 35 | namespace unchecked 36 | { 37 | template 38 | octet_iterator append(uint32_t cp, octet_iterator result) 39 | { 40 | if (cp < 0x80) // one octet 41 | *(result++) = static_cast(cp); 42 | else if (cp < 0x800) { // two octets 43 | *(result++) = static_cast((cp >> 6) | 0xc0); 44 | *(result++) = static_cast((cp & 0x3f) | 0x80); 45 | } 46 | else if (cp < 0x10000) { // three octets 47 | *(result++) = static_cast((cp >> 12) | 0xe0); 48 | *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); 49 | *(result++) = static_cast((cp & 0x3f) | 0x80); 50 | } 51 | else { // four octets 52 | *(result++) = static_cast((cp >> 18) | 0xf0); 53 | *(result++) = static_cast(((cp >> 12) & 0x3f)| 0x80); 54 | *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); 55 | *(result++) = static_cast((cp & 0x3f) | 0x80); 56 | } 57 | return result; 58 | } 59 | 60 | template 61 | uint32_t next(octet_iterator& it) 62 | { 63 | uint32_t cp = utf8::internal::mask8(*it); 64 | typename std::iterator_traits::difference_type length = utf8::internal::sequence_length(it); 65 | switch (length) { 66 | case 1: 67 | break; 68 | case 2: 69 | it++; 70 | cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f); 71 | break; 72 | case 3: 73 | ++it; 74 | cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff); 75 | ++it; 76 | cp += (*it) & 0x3f; 77 | break; 78 | case 4: 79 | ++it; 80 | cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff); 81 | ++it; 82 | cp += (utf8::internal::mask8(*it) << 6) & 0xfff; 83 | ++it; 84 | cp += (*it) & 0x3f; 85 | break; 86 | } 87 | ++it; 88 | return cp; 89 | } 90 | 91 | template 92 | uint32_t peek_next(octet_iterator it) 93 | { 94 | return utf8::unchecked::next(it); 95 | } 96 | 97 | template 98 | uint32_t prior(octet_iterator& it) 99 | { 100 | while (utf8::internal::is_trail(*(--it))) ; 101 | octet_iterator temp = it; 102 | return utf8::unchecked::next(temp); 103 | } 104 | 105 | // Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous) 106 | template 107 | inline uint32_t previous(octet_iterator& it) 108 | { 109 | return utf8::unchecked::prior(it); 110 | } 111 | 112 | template 113 | void advance (octet_iterator& it, distance_type n) 114 | { 115 | for (distance_type i = 0; i < n; ++i) 116 | utf8::unchecked::next(it); 117 | } 118 | 119 | template 120 | typename std::iterator_traits::difference_type 121 | distance (octet_iterator first, octet_iterator last) 122 | { 123 | typename std::iterator_traits::difference_type dist; 124 | for (dist = 0; first < last; ++dist) 125 | utf8::unchecked::next(first); 126 | return dist; 127 | } 128 | 129 | template 130 | octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) 131 | { 132 | while (start != end) { 133 | uint32_t cp = utf8::internal::mask16(*start++); 134 | // Take care of surrogate pairs first 135 | if (utf8::internal::is_lead_surrogate(cp)) { 136 | uint32_t trail_surrogate = utf8::internal::mask16(*start++); 137 | cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; 138 | } 139 | result = utf8::unchecked::append(cp, result); 140 | } 141 | return result; 142 | } 143 | 144 | template 145 | u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) 146 | { 147 | while (start < end) { 148 | uint32_t cp = utf8::unchecked::next(start); 149 | if (cp > 0xffff) { //make a surrogate pair 150 | *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); 151 | *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); 152 | } 153 | else 154 | *result++ = static_cast(cp); 155 | } 156 | return result; 157 | } 158 | 159 | template 160 | octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) 161 | { 162 | while (start != end) 163 | result = utf8::unchecked::append(*(start++), result); 164 | 165 | return result; 166 | } 167 | 168 | template 169 | u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) 170 | { 171 | while (start < end) 172 | (*result++) = utf8::unchecked::next(start); 173 | 174 | return result; 175 | } 176 | 177 | // The iterator class 178 | template 179 | class iterator : public std::iterator { 180 | octet_iterator it; 181 | public: 182 | iterator () {} 183 | explicit iterator (const octet_iterator& octet_it): it(octet_it) {} 184 | // the default "big three" are OK 185 | octet_iterator base () const { return it; } 186 | uint32_t operator * () const 187 | { 188 | octet_iterator temp = it; 189 | return utf8::unchecked::next(temp); 190 | } 191 | bool operator == (const iterator& rhs) const 192 | { 193 | return (it == rhs.it); 194 | } 195 | bool operator != (const iterator& rhs) const 196 | { 197 | return !(operator == (rhs)); 198 | } 199 | iterator& operator ++ () 200 | { 201 | ::std::advance(it, utf8::internal::sequence_length(it)); 202 | return *this; 203 | } 204 | iterator operator ++ (int) 205 | { 206 | iterator temp = *this; 207 | ::std::advance(it, utf8::internal::sequence_length(it)); 208 | return temp; 209 | } 210 | iterator& operator -- () 211 | { 212 | utf8::unchecked::prior(it); 213 | return *this; 214 | } 215 | iterator operator -- (int) 216 | { 217 | iterator temp = *this; 218 | utf8::unchecked::prior(it); 219 | return temp; 220 | } 221 | }; // class iterator 222 | 223 | } // namespace utf8::unchecked 224 | } // namespace utf8 225 | 226 | 227 | #endif // header guard 228 | 229 | -------------------------------------------------------------------------------- /src/xml/tinyxml.h: -------------------------------------------------------------------------------- 1 | #ifndef NPP_PLUGIN_TINYXML_H 2 | #define NPP_PLUGIN_TINYXML_H 3 | 4 | #include "tinyxml2.h" 5 | 6 | typedef tinyxml2::XMLHandle tXmlHnd; 7 | typedef tinyxml2::XMLDocument tXmlDoc; 8 | typedef tinyxml2::XMLDocument* tXmlDocP; 9 | typedef tinyxml2::XMLElement* tXmlEleP; 10 | typedef tinyxml2::XMLError tXmlError; 11 | const INT kXmlSuccess = tinyxml2::XML_SUCCESS; 12 | 13 | #endif // NPP_PLUGIN_TINYXML_H 14 | -------------------------------------------------------------------------------- /x.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set sesmgr_old_ver=1.4.1 4 | set sesmgr_new_ver=1.4.2 5 | set release_dir=c:\prj\npp-session-manager\dist\%sesmgr_new_ver% 6 | set zip_exe="c:\Program Files\7-Zip\7z.exe" 7 | set md5_exe=c:\bin\md5sums\md5sums.exe 8 | set npp_plugin_dir=c:\bin\npp\plugins 9 | 10 | set do_c=0 11 | set do_b=0 12 | set do_d=0 13 | set do_r=0 14 | set args="x%*" 15 | if not %args:c=%==%args% set do_c=1 16 | if not %args:b=%==%args% set do_b=1 17 | if not %args:d=%==%args% set do_d=1 18 | if not %args:r=%==%args% set do_r=1 19 | 20 | if %do_c% equ 1 goto clean 21 | if %do_b% equ 1 goto build 22 | if %do_d% equ 1 goto deploy 23 | if %do_r% equ 1 goto release 24 | 25 | echo Usage: x (c|b|d|r)[ ]... 26 | echo where c = clean, b = build, d = deploy, r = release 27 | goto silent_exit 28 | 29 | ::------------------------------------------------------------------------------ 30 | :clean 31 | 32 | echo Cleaning... 33 | nmake clean 34 | if %do_b% equ 1 goto build 35 | if %do_d% equ 1 goto deploy 36 | goto success_exit 37 | 38 | ::------------------------------------------------------------------------------ 39 | :build 40 | 41 | echo Building... 42 | nmake > nmake.log 43 | if errorlevel 1 ( 44 | echo Build ERROR 45 | type nmake.log 46 | goto error_exit 47 | ) 48 | if %do_d% equ 1 goto deploy 49 | goto success_exit 50 | 51 | ::------------------------------------------------------------------------------ 52 | :deploy 53 | 54 | echo Deploying... 55 | if exist %npp_plugin_dir%\SessionMgr.dll ( 56 | if not exist %npp_plugin_dir%\SessionMgr-%sesmgr_old_ver%.dll ( 57 | ren %npp_plugin_dir%\SessionMgr.dll SessionMgr-%sesmgr_old_ver%.dll 58 | if errorlevel 1 ( 59 | echo Backup ERROR 1 60 | goto error_exit 61 | ) 62 | ) else ( 63 | echo Backup ERROR 2 64 | goto error_exit 65 | ) 66 | ) 67 | if exist %npp_plugin_dir%\SessionMgr-%sesmgr_old_ver%.dll ( 68 | if not exist %npp_plugin_dir%\SessionMgr-%sesmgr_old_ver%.dll.bak ( 69 | ren %npp_plugin_dir%\SessionMgr-%sesmgr_old_ver%.dll SessionMgr-%sesmgr_old_ver%.dll.bak 70 | if errorlevel 1 ( 71 | echo Backup ERROR 3 72 | goto error_exit 73 | ) 74 | ) else ( 75 | echo Backup ERROR 4 76 | goto error_exit 77 | ) 78 | ) 79 | xcopy /y /q obj\SessionMgr.dll %npp_plugin_dir%\SessionMgr-%sesmgr_new_ver%.dll 80 | if errorlevel 1 ( 81 | echo Deploy ERROR 82 | goto error_exit 83 | ) 84 | if %do_r% equ 1 goto release 85 | goto success_exit 86 | 87 | ::------------------------------------------------------------------------------ 88 | :release 89 | 90 | echo Releasing... 91 | if exist %release_dir% ( 92 | rmdir /s %release_dir% 93 | ) 94 | xcopy /t /e /q dist\template %release_dir%\ 95 | if errorlevel 1 ( 96 | echo Release ERROR 1 97 | goto error_exit 98 | ) 99 | xcopy /q obj\SessionMgr.dll %release_dir%\plugin\ 100 | xcopy /q doc\* %release_dir%\plugin\doc\ 101 | %zip_exe% a -r -tzip %release_dir%\SessionMgr-%sesmgr_new_ver%-plugin.zip %release_dir%\plugin\* 102 | if errorlevel 1 ( 103 | echo Release ERROR 2 104 | goto error_exit 105 | ) 106 | xcopy /q license.txt %release_dir%\source\npp-session-manager\ 107 | xcopy /q Makefile %release_dir%\source\npp-session-manager\ 108 | xcopy /q README %release_dir%\source\npp-session-manager\ 109 | xcopy /q setenv.cmd %release_dir%\source\npp-session-manager\ 110 | xcopy /q x.cmd %release_dir%\source\npp-session-manager\ 111 | xcopy /s /q src\* %release_dir%\source\npp-session-manager\src\ 112 | xcopy /q doc\* %release_dir%\source\npp-session-manager\doc\ 113 | %zip_exe% a -r -tzip %release_dir%\SessionMgr-%sesmgr_new_ver%-source.zip %release_dir%\source\* 114 | if errorlevel 1 ( 115 | echo Release ERROR 3 116 | goto error_exit 117 | ) 118 | %md5_exe% %release_dir%\*.zip > %release_dir%\md5sums.txt 119 | 120 | ::------------------------------------------------------------------------------ 121 | 122 | :success_exit 123 | 124 | echo SUCCESS 125 | exit /b 0 126 | 127 | :error_exit 128 | 129 | exit /b 1 130 | 131 | :silent_exit 132 | 133 | exit /b 0 134 | --------------------------------------------------------------------------------