Permalink
6854 lines (5859 sloc) 259 KB
// This file is part of Notepad++ project
// Copyright (C)2003 Don HO <don.h@free.fr>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// Note that the GPL places important restrictions on "derived works", yet
// it does not provide a detailed definition of that term. To avoid
// misunderstandings, we consider an application to constitute a
// "derivative work" for the purpose of this license if it does any of the
// following:
// 1. Integrates source code from Notepad++.
// 2. Integrates/includes/aggregates Notepad++ into a proprietary executable
// installer, such as those produced by InstallShield.
// 3. Links to a library or executes a program that does any of the above.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include <time.h>
#include <shlwapi.h>
#include "Notepad_plus.h"
#include "Notepad_plus_Window.h"
#include "FileDialog.h"
#include "Printer.h"
#include "FileNameStringSplitter.h"
#include "lesDlgs.h"
#include "Utf8_16.h"
#include "regExtDlg.h"
#include "RunDlg.h"
#include "ShortcutMapper.h"
#include "preferenceDlg.h"
#include "TaskListDlg.h"
#include "xmlMatchedTagsHighlighter.h"
#include "EncodingMapper.h"
#include "ansiCharPanel.h"
#include "clipboardHistoryPanel.h"
#include "VerticalFileSwitcher.h"
#include "ProjectPanel.h"
#include "documentMap.h"
#include "functionListPanel.h"
#include "fileBrowser.h"
#include "LongRunningOperation.h"
#include "Common.h"
using namespace std;
enum tb_stat {tb_saved, tb_unsaved, tb_ro};
#define DIR_LEFT true
#define DIR_RIGHT false
#define NPP_INTERNAL_FUCTION_STR TEXT("Notepad++::InternalFunction")
int docTabIconIDs[] = {IDI_SAVED_ICON, IDI_UNSAVED_ICON, IDI_READONLY_ICON, IDI_MONITORING_ICON};
ToolBarButtonUnit toolBarIcons[] = {
{IDM_FILE_NEW, IDI_NEW_OFF_ICON, IDI_NEW_ON_ICON, IDI_NEW_OFF_ICON, IDR_FILENEW},
{IDM_FILE_OPEN, IDI_OPEN_OFF_ICON, IDI_OPEN_ON_ICON, IDI_OPEN_OFF_ICON, IDR_FILEOPEN},
{IDM_FILE_SAVE, IDI_SAVE_OFF_ICON, IDI_SAVE_ON_ICON, IDI_SAVE_DISABLE_ICON, IDR_FILESAVE},
{IDM_FILE_SAVEALL, IDI_SAVEALL_OFF_ICON, IDI_SAVEALL_ON_ICON, IDI_SAVEALL_DISABLE_ICON, IDR_SAVEALL},
{IDM_FILE_CLOSE, IDI_CLOSE_OFF_ICON, IDI_CLOSE_ON_ICON, IDI_CLOSE_OFF_ICON, IDR_CLOSEFILE},
{IDM_FILE_CLOSEALL, IDI_CLOSEALL_OFF_ICON, IDI_CLOSEALL_ON_ICON, IDI_CLOSEALL_OFF_ICON, IDR_CLOSEALL},
{IDM_FILE_PRINT, IDI_PRINT_OFF_ICON, IDI_PRINT_ON_ICON, IDI_PRINT_OFF_ICON, IDR_PRINT},
//-------------------------------------------------------------------------------------//
{0, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON},
//-------------------------------------------------------------------------------------//
{IDM_EDIT_CUT, IDI_CUT_OFF_ICON, IDI_CUT_ON_ICON, IDI_CUT_DISABLE_ICON, IDR_CUT},
{IDM_EDIT_COPY, IDI_COPY_OFF_ICON, IDI_COPY_ON_ICON, IDI_COPY_DISABLE_ICON, IDR_COPY},
{IDM_EDIT_PASTE, IDI_PASTE_OFF_ICON, IDI_PASTE_ON_ICON, IDI_PASTE_DISABLE_ICON, IDR_PASTE},
//-------------------------------------------------------------------------------------//
{0, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON},
//-------------------------------------------------------------------------------------//
{IDM_EDIT_UNDO, IDI_UNDO_OFF_ICON, IDI_UNDO_ON_ICON, IDI_UNDO_DISABLE_ICON, IDR_UNDO},
{IDM_EDIT_REDO, IDI_REDO_OFF_ICON, IDI_REDO_ON_ICON, IDI_REDO_DISABLE_ICON, IDR_REDO},
//-------------------------------------------------------------------------------------//
{0, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON},
//-------------------------------------------------------------------------------------//
{IDM_SEARCH_FIND, IDI_FIND_OFF_ICON, IDI_FIND_ON_ICON, IDI_FIND_OFF_ICON, IDR_FIND},
{IDM_SEARCH_REPLACE, IDI_REPLACE_OFF_ICON, IDI_REPLACE_ON_ICON, IDI_REPLACE_OFF_ICON, IDR_REPLACE},
//-------------------------------------------------------------------------------------//
{0, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON},
//-------------------------------------------------------------------------------------//
{IDM_VIEW_ZOOMIN, IDI_ZOOMIN_OFF_ICON, IDI_ZOOMIN_ON_ICON, IDI_ZOOMIN_OFF_ICON, IDR_ZOOMIN},
{IDM_VIEW_ZOOMOUT, IDI_ZOOMOUT_OFF_ICON, IDI_ZOOMOUT_ON_ICON, IDI_ZOOMOUT_OFF_ICON, IDR_ZOOMOUT},
//-------------------------------------------------------------------------------------//
{0, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON},
//-------------------------------------------------------------------------------------//
{IDM_VIEW_SYNSCROLLV, IDI_SYNCV_OFF_ICON, IDI_SYNCV_ON_ICON, IDI_SYNCV_DISABLE_ICON, IDR_SYNCV},
{IDM_VIEW_SYNSCROLLH, IDI_SYNCH_OFF_ICON, IDI_SYNCH_ON_ICON, IDI_SYNCH_DISABLE_ICON, IDR_SYNCH},
//-------------------------------------------------------------------------------------//
{0, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON},
//-------------------------------------------------------------------------------------//
{IDM_VIEW_WRAP, IDI_VIEW_WRAP_OFF_ICON, IDI_VIEW_WRAP_ON_ICON, IDI_VIEW_WRAP_OFF_ICON, IDR_WRAP},
{IDM_VIEW_ALL_CHARACTERS, IDI_VIEW_ALL_CHAR_OFF_ICON, IDI_VIEW_ALL_CHAR_ON_ICON, IDI_VIEW_ALL_CHAR_OFF_ICON, IDR_INVISIBLECHAR},
{IDM_VIEW_INDENT_GUIDE, IDI_VIEW_INDENT_OFF_ICON, IDI_VIEW_INDENT_ON_ICON, IDI_VIEW_INDENT_OFF_ICON, IDR_INDENTGUIDE},
{IDM_LANG_USER_DLG, IDI_VIEW_UD_DLG_OFF_ICON, IDI_VIEW_UD_DLG_ON_ICON, IDI_VIEW_UD_DLG_OFF_ICON, IDR_SHOWPANNEL},
{IDM_VIEW_DOC_MAP, IDI_VIEW_DOC_MAP_OFF_ICON, IDI_VIEW_DOC_MAP_ON_ICON, IDI_VIEW_DOC_MAP_OFF_ICON, IDR_DOCMAP},
//{IDM_VIEW_FUNC_LIST, IDI_VIEW_UD_DLG_OFF_ICON, IDI_VIEW_UD_DLG_ON_ICON, IDI_VIEW_UD_DLG_OFF_ICON, IDR_FUNC_LIST},
{IDM_VIEW_FUNC_LIST, IDI_VIEW_FUNCLIST_OFF_ICON, IDI_VIEW_FUNCLIST_ON_ICON, IDI_VIEW_FUNCLIST_OFF_ICON, IDR_FUNC_LIST},
{IDM_VIEW_FILEBROWSER, IDI_VIEW_FILEBROWSER_OFF_ICON, IDI_VIEW_FILEBROWSER_ON_ICON, IDI_VIEW_FILEBROWSER_OFF_ICON, IDR_FILEBROWSER},
{IDM_VIEW_MONITORING, IDI_VIEW_MONITORING_OFF_ICON, IDI_VIEW_MONITORING_ON_ICON, IDI_VIEW_MONITORING_OFF_ICON, IDR_FILEMONITORING},
//-------------------------------------------------------------------------------------//
{0, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON},
//-------------------------------------------------------------------------------------//
{IDM_MACRO_STARTRECORDINGMACRO, IDI_STARTRECORD_OFF_ICON, IDI_STARTRECORD_ON_ICON, IDI_STARTRECORD_DISABLE_ICON, IDR_STARTRECORD},
{IDM_MACRO_STOPRECORDINGMACRO, IDI_STOPRECORD_OFF_ICON, IDI_STOPRECORD_ON_ICON, IDI_STOPRECORD_DISABLE_ICON, IDR_STOPRECORD},
{IDM_MACRO_PLAYBACKRECORDEDMACRO, IDI_PLAYRECORD_OFF_ICON, IDI_PLAYRECORD_ON_ICON, IDI_PLAYRECORD_DISABLE_ICON, IDR_PLAYRECORD},
{IDM_MACRO_RUNMULTIMACRODLG, IDI_MMPLAY_OFF_ICON, IDI_MMPLAY_ON_ICON, IDI_MMPLAY_DIS_ICON, IDR_M_PLAYRECORD},
{IDM_MACRO_SAVECURRENTMACRO, IDI_SAVERECORD_OFF_ICON, IDI_SAVERECORD_ON_ICON, IDI_SAVERECORD_DISABLE_ICON, IDR_SAVERECORD}
};
Notepad_plus::Notepad_plus()
: _autoCompleteMain(&_mainEditView)
, _autoCompleteSub(&_subEditView)
, _smartHighlighter(&_findReplaceDlg)
{
ZeroMemory(&_prevSelectedRange, sizeof(_prevSelectedRange));
TiXmlDocumentA *nativeLangDocRootA = (NppParameters::getInstance())->getNativeLangA();
_nativeLangSpeaker.init(nativeLangDocRootA);
LocalizationSwitcher & localizationSwitcher = (NppParameters::getInstance())->getLocalizationSwitcher();
const char *fn = _nativeLangSpeaker.getFileName();
if (fn)
{
localizationSwitcher.setFileName(fn);
}
(NppParameters::getInstance())->setNativeLangSpeaker(&_nativeLangSpeaker);
TiXmlDocument *toolIconsDocRoot = (NppParameters::getInstance())->getToolIcons();
if (toolIconsDocRoot)
{
_toolBar.initTheme(toolIconsDocRoot);
}
// Determine if user is administrator.
BOOL is_admin;
winVer ver = NppParameters::getInstance()->getWinVersion();
if (ver >= WV_VISTA || ver == WV_UNKNOWN)
{
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
PSID AdministratorsGroup;
is_admin = AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdministratorsGroup);
if (is_admin)
{
if (!CheckTokenMembership(NULL, AdministratorsGroup, &is_admin))
is_admin = FALSE;
FreeSid(AdministratorsGroup);
}
}
else
is_admin = false;
_isAdministrator = is_admin ? true : false;
}
Notepad_plus::~Notepad_plus()
{
// ATTENTION : the order of the destruction is very important
// because if the parent's window handle is destroyed before
// the destruction of its children windows' handles,
// its children windows' handles will be destroyed automatically!
(NppParameters::getInstance())->destroyInstance();
MainFileManager->destroyInstance();
(WcharMbcsConvertor::getInstance())->destroyInstance();
delete _pTrayIco;
delete _pAnsiCharPanel;
delete _pClipboardHistoryPanel;
delete _pFileSwitcherPanel;
delete _pProjectPanel_1;
delete _pProjectPanel_2;
delete _pProjectPanel_3;
delete _pDocMap;
delete _pFuncList;
delete _pFileBrowser;
}
LRESULT Notepad_plus::init(HWND hwnd)
{
NppParameters *pNppParam = NppParameters::getInstance();
NppGUI & nppGUI = const_cast<NppGUI &>(pNppParam->getNppGUI());
// Menu
_mainMenuHandle = ::GetMenu(hwnd);
int langPos2BeRemoved = MENUINDEX_LANGUAGE+1;
if (nppGUI._isLangMenuCompact)
langPos2BeRemoved = MENUINDEX_LANGUAGE;
::RemoveMenu(_mainMenuHandle, langPos2BeRemoved, MF_BYPOSITION);
//Views
_pDocTab = &_mainDocTab;
_pEditView = &_mainEditView;
_pNonDocTab = &_subDocTab;
_pNonEditView = &_subEditView;
_mainEditView.init(_pPublicInterface->getHinst(), hwnd);
_subEditView.init(_pPublicInterface->getHinst(), hwnd);
_fileEditView.init(_pPublicInterface->getHinst(), hwnd);
MainFileManager->init(this, &_fileEditView); //get it up and running asap.
pNppParam->setFontList(hwnd);
_mainWindowStatus = WindowMainActive;
_activeView = MAIN_VIEW;
const ScintillaViewParams & svp1 = pNppParam->getSVP();
int tabBarStatus = nppGUI._tabStatus;
_toReduceTabBar = ((tabBarStatus & TAB_REDUCE) != 0);
int iconDpiDynamicalSize = pNppParam->_dpiManager.scaleY(_toReduceTabBar?13:20);
_docTabIconList.create(iconDpiDynamicalSize, _pPublicInterface->getHinst(), docTabIconIDs, sizeof(docTabIconIDs)/sizeof(int));
_mainDocTab.init(_pPublicInterface->getHinst(), hwnd, &_mainEditView, &_docTabIconList);
_subDocTab.init(_pPublicInterface->getHinst(), hwnd, &_subEditView, &_docTabIconList);
_mainEditView.display();
_invisibleEditView.init(_pPublicInterface->getHinst(), hwnd);
_invisibleEditView.execute(SCI_SETUNDOCOLLECTION);
_invisibleEditView.execute(SCI_EMPTYUNDOBUFFER);
_invisibleEditView.wrap(false); // Make sure no slow down
// Configuration of 2 scintilla views
_mainEditView.showMargin(ScintillaEditView::_SC_MARGE_LINENUMBER, svp1._lineNumberMarginShow);
_subEditView.showMargin(ScintillaEditView::_SC_MARGE_LINENUMBER, svp1._lineNumberMarginShow);
_mainEditView.showMargin(ScintillaEditView::_SC_MARGE_SYBOLE, svp1._bookMarkMarginShow);
_subEditView.showMargin(ScintillaEditView::_SC_MARGE_SYBOLE, svp1._bookMarkMarginShow);
_mainEditView.showIndentGuideLine(svp1._indentGuideLineShow);
_subEditView.showIndentGuideLine(svp1._indentGuideLineShow);
::SendMessage(hwnd, NPPM_INTERNAL_SETCARETWIDTH, 0, 0);
::SendMessage(hwnd, NPPM_INTERNAL_SETCARETBLINKRATE, 0, 0);
_configStyleDlg.init(_pPublicInterface->getHinst(), hwnd);
_preference.init(_pPublicInterface->getHinst(), hwnd);
_pluginsAdminDlg.init(_pPublicInterface->getHinst(), hwnd);
//Marker Margin config
_mainEditView.setMakerStyle(svp1._folderStyle);
_subEditView.setMakerStyle(svp1._folderStyle);
_mainEditView.defineDocType(_mainEditView.getCurrentBuffer()->getLangType());
_subEditView.defineDocType(_subEditView.getCurrentBuffer()->getLangType());
//Line wrap method
_mainEditView.setWrapMode(svp1._lineWrapMethod);
_subEditView.setWrapMode(svp1._lineWrapMethod);
_mainEditView.execute(SCI_SETCARETLINEVISIBLE, svp1._currentLineHilitingShow);
_subEditView.execute(SCI_SETCARETLINEVISIBLE, svp1._currentLineHilitingShow);
_mainEditView.execute(SCI_SETENDATLASTLINE, not svp1._scrollBeyondLastLine);
_subEditView.execute(SCI_SETENDATLASTLINE, not svp1._scrollBeyondLastLine);
if (svp1._doSmoothFont)
{
_mainEditView.execute(SCI_SETFONTQUALITY, SC_EFF_QUALITY_LCD_OPTIMIZED);
_subEditView.execute(SCI_SETFONTQUALITY, SC_EFF_QUALITY_LCD_OPTIMIZED);
}
_mainEditView.setBorderEdge(svp1._showBorderEdge);
_subEditView.setBorderEdge(svp1._showBorderEdge);
_mainEditView.execute(SCI_SETCARETLINEVISIBLEALWAYS, true);
_subEditView.execute(SCI_SETCARETLINEVISIBLEALWAYS, true);
_mainEditView.wrap(svp1._doWrap);
_subEditView.wrap(svp1._doWrap);
_mainEditView.execute(SCI_SETEDGECOLUMN, svp1._edgeNbColumn);
_mainEditView.execute(SCI_SETEDGEMODE, svp1._edgeMode);
_subEditView.execute(SCI_SETEDGECOLUMN, svp1._edgeNbColumn);
_subEditView.execute(SCI_SETEDGEMODE, svp1._edgeMode);
_mainEditView.showEOL(svp1._eolShow);
_subEditView.showEOL(svp1._eolShow);
_mainEditView.showWSAndTab(svp1._whiteSpaceShow);
_subEditView.showWSAndTab(svp1._whiteSpaceShow);
_mainEditView.showWrapSymbol(svp1._wrapSymbolShow);
_subEditView.showWrapSymbol(svp1._wrapSymbolShow);
_mainEditView.performGlobalStyles();
_subEditView.performGlobalStyles();
_zoomOriginalValue = static_cast<int32_t>(_pEditView->execute(SCI_GETZOOM));
_mainEditView.execute(SCI_SETZOOM, svp1._zoom);
_subEditView.execute(SCI_SETZOOM, svp1._zoom2);
::SendMessage(hwnd, NPPM_INTERNAL_SETMULTISELCTION, 0, 0);
// Make backspace or delete work with multiple selections
_mainEditView.execute(SCI_SETADDITIONALSELECTIONTYPING, true);
_subEditView.execute(SCI_SETADDITIONALSELECTIONTYPING, true);
// Turn virtual space on
_mainEditView.execute(SCI_SETVIRTUALSPACEOPTIONS, SCVS_RECTANGULARSELECTION);
_subEditView.execute(SCI_SETVIRTUALSPACEOPTIONS, SCVS_RECTANGULARSELECTION);
// Turn multi-paste on
_mainEditView.execute(SCI_SETMULTIPASTE, SC_MULTIPASTE_EACH);
_subEditView.execute(SCI_SETMULTIPASTE, SC_MULTIPASTE_EACH);
// Let Scintilla deal with some of the folding functionality
_mainEditView.execute(SCI_SETAUTOMATICFOLD, SC_AUTOMATICFOLD_SHOW);
_subEditView.execute(SCI_SETAUTOMATICFOLD, SC_AUTOMATICFOLD_SHOW);
TabBarPlus::doDragNDrop(true);
if (_toReduceTabBar)
{
HFONT hf = static_cast<HFONT>(::GetStockObject(DEFAULT_GUI_FONT));
if (hf)
{
::SendMessage(_mainDocTab.getHSelf(), WM_SETFONT, reinterpret_cast<WPARAM>(hf), MAKELPARAM(TRUE, 0));
::SendMessage(_subDocTab.getHSelf(), WM_SETFONT, reinterpret_cast<WPARAM>(hf), MAKELPARAM(TRUE, 0));
}
int tabDpiDynamicalHeight = pNppParam->_dpiManager.scaleY(22);
int tabDpiDynamicalWidth = pNppParam->_dpiManager.scaleX(45);
TabCtrl_SetItemSize(_mainDocTab.getHSelf(), tabDpiDynamicalWidth, tabDpiDynamicalHeight);
TabCtrl_SetItemSize(_subDocTab.getHSelf(), tabDpiDynamicalWidth, tabDpiDynamicalHeight);
}
_mainDocTab.display();
TabBarPlus::doDragNDrop((tabBarStatus & TAB_DRAGNDROP) != 0);
TabBarPlus::setDrawTopBar((tabBarStatus & TAB_DRAWTOPBAR) != 0);
TabBarPlus::setDrawInactiveTab((tabBarStatus & TAB_DRAWINACTIVETAB) != 0);
TabBarPlus::setDrawTabCloseButton((tabBarStatus & TAB_CLOSEBUTTON) != 0);
TabBarPlus::setDbClk2Close((tabBarStatus & TAB_DBCLK2CLOSE) != 0);
TabBarPlus::setVertical((tabBarStatus & TAB_VERTICAL) != 0);
drawTabbarColoursFromStylerArray();
//--Splitter Section--//
bool isVertical = (nppGUI._splitterPos == POS_VERTICAL);
_subSplitter.init(_pPublicInterface->getHinst(), hwnd);
_subSplitter.create(&_mainDocTab, &_subDocTab, 8, SplitterMode::DYNAMIC, 50, isVertical);
//--Status Bar Section--//
bool willBeShown = nppGUI._statusBarShow;
_statusBar.init(_pPublicInterface->getHinst(), hwnd, 6);
_statusBar.setPartWidth(STATUSBAR_DOC_SIZE, pNppParam->_dpiManager.scaleX(200));
_statusBar.setPartWidth(STATUSBAR_CUR_POS, pNppParam->_dpiManager.scaleX(260));
_statusBar.setPartWidth(STATUSBAR_EOF_FORMAT, pNppParam->_dpiManager.scaleX(110));
_statusBar.setPartWidth(STATUSBAR_UNICODE_TYPE, pNppParam->_dpiManager.scaleX(120));
_statusBar.setPartWidth(STATUSBAR_TYPING_MODE, pNppParam->_dpiManager.scaleX(30));
_statusBar.display(willBeShown);
_pMainWindow = &_mainDocTab;
_dockingManager.init(_pPublicInterface->getHinst(), hwnd, &_pMainWindow);
if (nppGUI._isMinimizedToTray && _pTrayIco == NULL)
{
HICON icon = ::LoadIcon(_pPublicInterface->getHinst(), MAKEINTRESOURCE(IDI_M30ICON));
_pTrayIco = new trayIconControler(hwnd, IDI_M30ICON, IDC_MINIMIZED_TRAY, icon, TEXT(""));
}
checkSyncState();
// Plugin Manager
NppData nppData;
nppData._nppHandle = hwnd;
nppData._scintillaMainHandle = _mainEditView.getHSelf();
nppData._scintillaSecondHandle = _subEditView.getHSelf();
_scintillaCtrls4Plugins.init(_pPublicInterface->getHinst(), hwnd);
_pluginsManager.init(nppData);
_pluginsManager.loadPluginsV2(pNppParam->getPluginRootDir());
_restoreButton.init(_pPublicInterface->getHinst(), hwnd);
// ------------ //
// Menu Section //
// ------------ //
// Macro Menu
std::vector<MacroShortcut> & macros = pNppParam->getMacroList();
HMENU hMacroMenu = ::GetSubMenu(_mainMenuHandle, MENUINDEX_MACRO);
size_t const posBase = 6;
size_t nbMacro = macros.size();
if (nbMacro >= 1)
::InsertMenu(hMacroMenu, posBase - 1, MF_BYPOSITION, static_cast<UINT>(-1), 0);
for (size_t i = 0 ; i < nbMacro ; ++i)
::InsertMenu(hMacroMenu, static_cast<UINT>(posBase + i), MF_BYPOSITION, ID_MACRO + i, macros[i].toMenuItemString().c_str());
if (nbMacro >= 1)
{
::InsertMenu(hMacroMenu, static_cast<UINT>(posBase + nbMacro + 1), MF_BYPOSITION, static_cast<UINT>(-1), 0);
::InsertMenu(hMacroMenu, static_cast<UINT>(posBase + nbMacro + 2), MF_BYCOMMAND, IDM_SETTING_SHORTCUT_MAPPER_MACRO, TEXT("Modify Shortcut/Delete Macro..."));
}
// Run Menu
std::vector<UserCommand> & userCommands = pNppParam->getUserCommandList();
HMENU hRunMenu = ::GetSubMenu(_mainMenuHandle, MENUINDEX_RUN);
int const runPosBase = 2;
size_t nbUserCommand = userCommands.size();
if (nbUserCommand >= 1)
::InsertMenu(hRunMenu, runPosBase - 1, MF_BYPOSITION, static_cast<UINT>(-1), 0);
for (size_t i = 0 ; i < nbUserCommand ; ++i)
{
::InsertMenu(hRunMenu, static_cast<UINT>(runPosBase + i), MF_BYPOSITION, ID_USER_CMD + i, userCommands[i].toMenuItemString().c_str());
}
if (nbUserCommand >= 1)
{
::InsertMenu(hRunMenu, static_cast<UINT>(runPosBase + nbUserCommand + 1), MF_BYPOSITION, static_cast<UINT>(-1), 0);
::InsertMenu(hRunMenu, static_cast<UINT>(runPosBase + nbUserCommand + 2), MF_BYCOMMAND, IDM_SETTING_SHORTCUT_MAPPER_RUN, TEXT("Modify Shortcut/Delete Command..."));
}
// Updater menu item
if (!nppGUI._doesExistUpdater)
{
::DeleteMenu(_mainMenuHandle, IDM_UPDATE_NPP, MF_BYCOMMAND);
::DeleteMenu(_mainMenuHandle, IDM_CONFUPDATERPROXY, MF_BYCOMMAND);
HMENU hHelpMenu = ::GetSubMenu(_mainMenuHandle, MENUINDEX_PLUGINS + 1);
if (!hHelpMenu)
hHelpMenu = ::GetSubMenu(_mainMenuHandle, MENUINDEX_PLUGINS);
if (hHelpMenu)
::DeleteMenu(hHelpMenu, 7, MF_BYPOSITION); // SEPARATOR
::DrawMenuBar(hwnd);
}
//Languages Menu
HMENU hLangMenu = ::GetSubMenu(_mainMenuHandle, MENUINDEX_LANGUAGE);
// Add external languages to menu
for (int i = 0 ; i < pNppParam->getNbExternalLang() ; ++i)
{
ExternalLangContainer & externalLangContainer = pNppParam->getELCFromIndex(i);
int numLangs = ::GetMenuItemCount(hLangMenu);
const int bufferSize = 100;
TCHAR buffer[bufferSize];
int x;
for (x = 0; (x == 0 || lstrcmp(externalLangContainer._name, buffer) > 0) && x < numLangs; ++x)
{
::GetMenuString(hLangMenu, x, buffer, bufferSize, MF_BYPOSITION);
}
::InsertMenu(hLangMenu, x-1, MF_BYPOSITION, IDM_LANG_EXTERNAL + i, externalLangContainer._name);
}
if (nppGUI._excludedLangList.size() > 0)
{
for (size_t i = 0, len = nppGUI._excludedLangList.size(); i < len ; ++i)
{
int cmdID = pNppParam->langTypeToCommandID(nppGUI._excludedLangList[i]._langType);
const int itemSize = 256;
TCHAR itemName[itemSize];
::GetMenuString(hLangMenu, cmdID, itemName, itemSize, MF_BYCOMMAND);
nppGUI._excludedLangList[i]._cmdID = cmdID;
nppGUI._excludedLangList[i]._langName = itemName;
::DeleteMenu(hLangMenu, cmdID, MF_BYCOMMAND);
DrawMenuBar(hwnd);
}
}
// Add User Defined Languages Entry
int udlpos = ::GetMenuItemCount(hLangMenu) - 1;
for (int i = 0, len = pNppParam->getNbUserLang(); i < len ; ++i)
{
UserLangContainer & userLangContainer = pNppParam->getULCFromIndex(i);
::InsertMenu(hLangMenu, udlpos + i, MF_BYPOSITION, IDM_LANG_USER + i + 1, userLangContainer.getName());
}
//Add recent files
HMENU hFileMenu = ::GetSubMenu(_mainMenuHandle, MENUINDEX_FILE);
int nbLRFile = pNppParam->getNbLRFile();
//int pos = IDM_FILEMENU_LASTONE - IDM_FILE + 1 /* +1 : because of IDM_FILE_PRINTNOW */;
_lastRecentFileList.initMenu(hFileMenu, IDM_FILEMENU_LASTONE + 1, IDM_FILEMENU_EXISTCMDPOSITION, &_accelerator, pNppParam->putRecentFileInSubMenu());
_lastRecentFileList.setLangEncoding(_nativeLangSpeaker.getLangEncoding());
for (int i = 0 ; i < nbLRFile ; ++i)
{
generic_string * stdStr = pNppParam->getLRFile(i);
if (!nppGUI._checkHistoryFiles || PathFileExists(stdStr->c_str()))
{
_lastRecentFileList.add(stdStr->c_str());
}
}
//Plugin menu
bool enablePluginAdmin = _pluginsAdminDlg.isValide();
_pluginsAdminDlg.setPluginsManager(&_pluginsManager);
_pluginsManager.setMenu(_mainMenuHandle, NULL, enablePluginAdmin);
//Main menu is loaded, now load context menu items
pNppParam->getContextMenuFromXmlTree(_mainMenuHandle, _pluginsManager.getMenuHandle());
if (pNppParam->hasCustomContextMenu())
{
_mainEditView.execute(SCI_USEPOPUP, FALSE);
_subEditView.execute(SCI_USEPOPUP, FALSE);
}
generic_string pluginsTrans, windowTrans;
_nativeLangSpeaker.changeMenuLang(_mainMenuHandle, pluginsTrans, windowTrans);
::DrawMenuBar(hwnd);
if (_pluginsManager.hasPlugins() && pluginsTrans != TEXT(""))
{
::ModifyMenu(_mainMenuHandle, MENUINDEX_PLUGINS, MF_BYPOSITION, 0, pluginsTrans.c_str());
}
//Windows menu
_windowsMenu.init(_pPublicInterface->getHinst(), _mainMenuHandle, windowTrans.c_str());
// Update context menu strings (translated)
vector<MenuItemUnit> & tmp = pNppParam->getContextMenuItems();
size_t len = tmp.size();
TCHAR menuName[64];
for (size_t i = 0 ; i < len ; ++i)
{
if (tmp[i]._itemName.empty())
{
::GetMenuString(_mainMenuHandle, tmp[i]._cmdID, menuName, 64, MF_BYCOMMAND);
tmp[i]._itemName = purgeMenuItemString(menuName);
}
}
//Input all the menu item names into shortcut list
//This will automatically do all translations, since menu translation has been done already
vector<CommandShortcut> & shortcuts = pNppParam->getUserShortcuts();
len = shortcuts.size();
for (size_t i = 0; i < len; ++i)
{
CommandShortcut & csc = shortcuts[i];
if (!csc.getName()[0])
{ //no predefined name, get name from menu and use that
::GetMenuString(_mainMenuHandle, csc.getID(), menuName, 64, MF_BYCOMMAND);
csc.setName(purgeMenuItemString(menuName, true).c_str());
}
}
//Translate non-menu shortcuts
_nativeLangSpeaker.changeShortcutLang();
//Update plugin shortcuts, all plugin commands should be available now
pNppParam->reloadPluginCmds();
// Shortcut Accelerator : should be the last one since it will capture all the shortcuts
_accelerator.init(_mainMenuHandle, hwnd);
pNppParam->setAccelerator(&_accelerator);
// Scintilla key accelerator
vector<HWND> scints;
scints.push_back(_mainEditView.getHSelf());
scints.push_back(_subEditView.getHSelf());
_scintaccelerator.init(&scints, _mainMenuHandle, hwnd);
pNppParam->setScintillaAccelerator(&_scintaccelerator);
_scintaccelerator.updateKeys();
::DrawMenuBar(hwnd);
//-- Tool Bar Section --//
toolBarStatusType tbStatus = nppGUI._toolBarStatus;
willBeShown = nppGUI._toolbarShow;
// To notify plugins that toolbar icons can be registered
SCNotification scnN;
scnN.nmhdr.code = NPPN_TBMODIFICATION;
scnN.nmhdr.hwndFrom = hwnd;
scnN.nmhdr.idFrom = 0;
_pluginsManager.notify(&scnN);
_toolBar.init(_pPublicInterface->getHinst(), hwnd, tbStatus, toolBarIcons, sizeof(toolBarIcons)/sizeof(ToolBarButtonUnit));
changeToolBarIcons();
_rebarTop.init(_pPublicInterface->getHinst(), hwnd);
_rebarBottom.init(_pPublicInterface->getHinst(), hwnd);
_toolBar.addToRebar(&_rebarTop);
_rebarTop.setIDVisible(REBAR_BAR_TOOLBAR, willBeShown);
checkMacroState();
//--Init dialogs--//
_findReplaceDlg.init(_pPublicInterface->getHinst(), hwnd, &_pEditView);
_findInFinderDlg.init(_pPublicInterface->getHinst(), hwnd);
_incrementFindDlg.init(_pPublicInterface->getHinst(), hwnd, &_findReplaceDlg, _nativeLangSpeaker.isRTL());
_incrementFindDlg.addToRebar(&_rebarBottom);
_goToLineDlg.init(_pPublicInterface->getHinst(), hwnd, &_pEditView);
_findCharsInRangeDlg.init(_pPublicInterface->getHinst(), hwnd, &_pEditView);
_colEditorDlg.init(_pPublicInterface->getHinst(), hwnd, &_pEditView);
_aboutDlg.init(_pPublicInterface->getHinst(), hwnd);
_debugInfoDlg.init(_pPublicInterface->getHinst(), hwnd, _isAdministrator, _pluginsManager.getLoadedPluginNames());
_runDlg.init(_pPublicInterface->getHinst(), hwnd);
_md5FromFilesDlg.init(_pPublicInterface->getHinst(), hwnd);
_md5FromTextDlg.init(_pPublicInterface->getHinst(), hwnd);
_runMacroDlg.init(_pPublicInterface->getHinst(), hwnd);
_documentPeeker.init(_pPublicInterface->getHinst(), hwnd);
//--User Define Dialog Section--//
int uddStatus = nppGUI._userDefineDlgStatus;
UserDefineDialog *udd = _pEditView->getUserDefineDlg();
bool uddShow = false;
switch (uddStatus)
{
case UDD_SHOW: // show & undocked
{
udd->doDialog(true, _nativeLangSpeaker.isRTL());
_nativeLangSpeaker.changeUserDefineLang(udd);
uddShow = true;
break;
}
case UDD_DOCKED: // hide & docked
{
_isUDDocked = true;
break;
}
case (UDD_SHOW | UDD_DOCKED) : // show & docked
{
udd->doDialog(true, _nativeLangSpeaker.isRTL());
_nativeLangSpeaker.changeUserDefineLang(udd);
::SendMessage(udd->getHSelf(), WM_COMMAND, IDC_DOCK_BUTTON, 0);
uddShow = true;
break;
}
default: // hide & undocked
break;
}
//
// Menu & toolbar for UserDefine Dialog
//
checkMenuItem(IDM_LANG_USER_DLG, uddShow);
_toolBar.setCheck(IDM_LANG_USER_DLG, uddShow);
//
// Initialize the default foreground & background color
//
{
StyleArray & globalStyles = pNppParam->getGlobalStylers();
int i = globalStyles.getStylerIndexByID(STYLE_DEFAULT);
if (i != -1)
{
Style & style = globalStyles.getStyler(i);
pNppParam->setCurrentDefaultFgColor(style._fgColor);
pNppParam->setCurrentDefaultBgColor(style._bgColor);
}
}
//
// launch the plugin dlg memorized at the last session
//
DockingManagerData& dmd = nppGUI._dockingData;
_dockingManager.setDockedContSize(CONT_LEFT , nppGUI._dockingData._leftWidth);
_dockingManager.setDockedContSize(CONT_RIGHT , nppGUI._dockingData._rightWidth);
_dockingManager.setDockedContSize(CONT_TOP , nppGUI._dockingData._topHeight);
_dockingManager.setDockedContSize(CONT_BOTTOM, nppGUI._dockingData._bottomHight);
for (size_t i = 0, len = dmd._pluginDockInfo.size(); i < len ; ++i)
{
PluginDlgDockingInfo& pdi = dmd._pluginDockInfo[i];
if (pdi._isVisible)
{
if (pdi._name == NPP_INTERNAL_FUCTION_STR)
_internalFuncIDs.push_back(pdi._internalID);
else
_pluginsManager.runPluginCommand(pdi._name.c_str(), pdi._internalID);
}
}
for (size_t i = 0, len = dmd._containerTabInfo.size(); i < len; ++i)
{
ContainerTabInfo & cti = dmd._containerTabInfo[i];
_dockingManager.setActiveTab(cti._cont, cti._activeTab);
}
//Load initial docs into doctab
loadBufferIntoView(_mainEditView.getCurrentBufferID(), MAIN_VIEW);
loadBufferIntoView(_subEditView.getCurrentBufferID(), SUB_VIEW);
activateBuffer(_mainEditView.getCurrentBufferID(), MAIN_VIEW);
activateBuffer(_subEditView.getCurrentBufferID(), SUB_VIEW);
//::SetFocus(_mainEditView.getHSelf());
_mainEditView.getFocus();
return TRUE;
}
void Notepad_plus::killAllChildren()
{
_toolBar.destroy();
_rebarTop.destroy();
_rebarBottom.destroy();
if (_pMainSplitter)
{
_pMainSplitter->destroy();
delete _pMainSplitter;
}
_mainDocTab.destroy();
_subDocTab.destroy();
_mainEditView.destroy();
_subEditView.destroy();
_invisibleEditView.destroy();
_subSplitter.destroy();
_statusBar.destroy();
_scintillaCtrls4Plugins.destroy();
_dockingManager.destroy();
}
bool Notepad_plus::saveGUIParams()
{
NppGUI & nppGUI = const_cast<NppGUI &>((NppParameters::getInstance())->getNppGUI());
nppGUI._toolbarShow = _rebarTop.getIDVisible(REBAR_BAR_TOOLBAR);
nppGUI._toolBarStatus = _toolBar.getState();
nppGUI._tabStatus = (TabBarPlus::doDragNDropOrNot()?TAB_DRAWTOPBAR:0) | \
(TabBarPlus::drawTopBar()?TAB_DRAGNDROP:0) | \
(TabBarPlus::drawInactiveTab()?TAB_DRAWINACTIVETAB:0) | \
(_toReduceTabBar?TAB_REDUCE:0) | \
(TabBarPlus::drawTabCloseButton()?TAB_CLOSEBUTTON:0) | \
(TabBarPlus::isDbClk2Close()?TAB_DBCLK2CLOSE:0) | \
(TabBarPlus::isVertical() ? TAB_VERTICAL:0) | \
(TabBarPlus::isMultiLine() ? TAB_MULTILINE:0) |\
(nppGUI._tabStatus & TAB_HIDE) | \
(nppGUI._tabStatus & TAB_QUITONEMPTY);
nppGUI._splitterPos = _subSplitter.isVertical()?POS_VERTICAL:POS_HORIZOTAL;
UserDefineDialog *udd = _pEditView->getUserDefineDlg();
bool b = udd->isDocked();
nppGUI._userDefineDlgStatus = (b?UDD_DOCKED:0) | (udd->isVisible()?UDD_SHOW:0);
// When window is maximized GetWindowPlacement returns window's last non maximized coordinates.
// Save them so that those will be used when window is restored next time.
WINDOWPLACEMENT posInfo;
posInfo.length = sizeof(WINDOWPLACEMENT);
::GetWindowPlacement(_pPublicInterface->getHSelf(), &posInfo);
nppGUI._appPos.left = posInfo.rcNormalPosition.left;
nppGUI._appPos.top = posInfo.rcNormalPosition.top;
nppGUI._appPos.right = posInfo.rcNormalPosition.right - posInfo.rcNormalPosition.left;
nppGUI._appPos.bottom = posInfo.rcNormalPosition.bottom - posInfo.rcNormalPosition.top;
nppGUI._isMaximized = ((IsZoomed(_pPublicInterface->getHSelf()) != 0) || (posInfo.flags & WPF_RESTORETOMAXIMIZED));
saveDockingParams();
(NppParameters::getInstance())->createXmlTreeFromGUIParams();
return true;
}
bool Notepad_plus::saveProjectPanelsParams()
{
if (_pProjectPanel_1)
{
_pProjectPanel_1->checkIfNeedSave(TEXT("Project Panel 1"));
(NppParameters::getInstance())->setWorkSpaceFilePath(0, _pProjectPanel_1->getWorkSpaceFilePath());
}
if (_pProjectPanel_2)
{
_pProjectPanel_2->checkIfNeedSave(TEXT("Project Panel 2"));
(NppParameters::getInstance())->setWorkSpaceFilePath(1, _pProjectPanel_2->getWorkSpaceFilePath());
}
if (_pProjectPanel_3)
{
_pProjectPanel_3->checkIfNeedSave(TEXT("Project Panel 3"));
(NppParameters::getInstance())->setWorkSpaceFilePath(2, _pProjectPanel_3->getWorkSpaceFilePath());
}
return (NppParameters::getInstance())->writeProjectPanelsSettings();
}
bool Notepad_plus::saveFileBrowserParam()
{
if (_pFileBrowser)
{
vector<generic_string> rootPaths = _pFileBrowser->getRoots();
generic_string selectedItemPath = _pFileBrowser->getSelectedItemPath();
return (NppParameters::getInstance())->writeFileBrowserSettings(rootPaths, selectedItemPath);
}
return true; // nothing to save so true is returned
}
void Notepad_plus::saveDockingParams()
{
NppGUI & nppGUI = const_cast<NppGUI &>((NppParameters::getInstance())->getNppGUI());
// Save the docking information
nppGUI._dockingData._leftWidth = _dockingManager.getDockedContSize(CONT_LEFT);
nppGUI._dockingData._rightWidth = _dockingManager.getDockedContSize(CONT_RIGHT);
nppGUI._dockingData._topHeight = _dockingManager.getDockedContSize(CONT_TOP);
nppGUI._dockingData._bottomHight = _dockingManager.getDockedContSize(CONT_BOTTOM);
// clear the container tab information (active tab)
nppGUI._dockingData._containerTabInfo.clear();
// create a vector to save the current information
vector<PluginDlgDockingInfo> vPluginDockInfo;
vector<FloatingWindowInfo> vFloatingWindowInfo;
// save every container
vector<DockingCont*> vCont = _dockingManager.getContainerInfo();
for (size_t i = 0, len = vCont.size(); i < len ; ++i)
{
// save at first the visible Tb's
vector<tTbData *> vDataVis = vCont[i]->getDataOfVisTb();
for (size_t j = 0, len2 = vDataVis.size(); j < len2 ; ++j)
{
if (vDataVis[j]->pszName && vDataVis[j]->pszName[0])
{
PluginDlgDockingInfo pddi(vDataVis[j]->pszModuleName, vDataVis[j]->dlgID, int32_t(i), vDataVis[j]->iPrevCont, true);
vPluginDockInfo.push_back(pddi);
}
}
// save the hidden Tb's
vector<tTbData *> vDataAll = vCont[i]->getDataOfAllTb();
for (size_t j = 0, len3 = vDataAll.size(); j < len3 ; ++j)
{
if ((vDataAll[j]->pszName && vDataAll[j]->pszName[0]) && (!vCont[i]->isTbVis(vDataAll[j])))
{
PluginDlgDockingInfo pddi(vDataAll[j]->pszModuleName, vDataAll[j]->dlgID, int32_t(i), vDataAll[j]->iPrevCont, false);
vPluginDockInfo.push_back(pddi);
}
}
// save the position, when container is a floated one
if (i >= DOCKCONT_MAX)
{
RECT rc;
vCont[i]->getWindowRect(rc);
FloatingWindowInfo fwi(int32_t(i), rc.left, rc.top, rc.right, rc.bottom);
vFloatingWindowInfo.push_back(fwi);
}
// save the active tab
ContainerTabInfo act(int32_t(i), vCont[i]->getActiveTb());
nppGUI._dockingData._containerTabInfo.push_back(act);
}
// add the missing information and store it in nppGUI
UCHAR floatContArray[50];
memset(floatContArray, 0, 50);
for (size_t i = 0, len4 = nppGUI._dockingData._pluginDockInfo.size(); i < len4 ; ++i)
{
BOOL isStored = FALSE;
for (size_t j = 0, len5 = vPluginDockInfo.size(); j < len5; ++j)
{
if (nppGUI._dockingData._pluginDockInfo[i] == vPluginDockInfo[j])
{
isStored = TRUE;
break;
}
}
if (isStored == FALSE)
{
int floatCont = 0;
if (nppGUI._dockingData._pluginDockInfo[i]._currContainer >= DOCKCONT_MAX)
floatCont = nppGUI._dockingData._pluginDockInfo[i]._currContainer;
else
floatCont = nppGUI._dockingData._pluginDockInfo[i]._prevContainer;
if (floatContArray[floatCont] == 0)
{
RECT rc;
if (nppGUI._dockingData.getFloatingRCFrom(floatCont, rc))
{
vFloatingWindowInfo.push_back(FloatingWindowInfo(floatCont, rc.left, rc.top, rc.right, rc.bottom));
}
floatContArray[floatCont] = 1;
}
if (i < nppGUI._dockingData._pluginDockInfo.size()) // to prevent from crash in debug mode
vPluginDockInfo.push_back(nppGUI._dockingData._pluginDockInfo[i]);
}
}
nppGUI._dockingData._pluginDockInfo = vPluginDockInfo;
nppGUI._dockingData._flaotingWindowInfo = vFloatingWindowInfo;
}
void Notepad_plus::saveUserDefineLangs()
{
if (ScintillaEditView::getUserDefineDlg()->isDirty())
(NppParameters::getInstance())->writeUserDefinedLang();
}
void Notepad_plus::saveShortcuts()
{
NppParameters::getInstance()->writeShortcuts();
}
void Notepad_plus::saveFindHistory()
{
_findReplaceDlg.saveFindHistory();
(NppParameters::getInstance())->writeFindHistory();
}
int Notepad_plus::getHtmlXmlEncoding(const TCHAR *fileName) const
{
// Get Language type
TCHAR *ext = PathFindExtension(fileName);
if (*ext == '.') //extension found
{
ext += 1;
}
else
{
return -1;
}
NppParameters *pNppParamInst = NppParameters::getInstance();
LangType langT = pNppParamInst->getLangFromExt(ext);
if ((langT != L_XML) && (langT != L_HTML))
return -1;
// Get the beginning of file data
FILE *f = generic_fopen(fileName, TEXT("rb"));
if (!f)
return -1;
const int blockSize = 1024; // To ensure that length is long enough to capture the encoding in html
char data[blockSize];
size_t lenFile = fread(data, 1, blockSize, f);
fclose(f);
// Put data in _invisibleEditView
_invisibleEditView.execute(SCI_CLEARALL);
_invisibleEditView.execute(SCI_APPENDTEXT, lenFile, reinterpret_cast<LPARAM>(data));
const char *encodingAliasRegExpr = "[a-zA-Z0-9_-]+";
if (langT == L_XML)
{
// find encoding by RegExpr
const char *xmlHeaderRegExpr = "<?xml[ \\t]+version[ \\t]*=[ \\t]*\"[^\"]+\"[ \\t]+encoding[ \\t]*=[ \\t]*\"[^\"]+\"[ \\t]*.*?>";
size_t startPos = 0;
size_t endPos = lenFile-1;
_invisibleEditView.execute(SCI_SETSEARCHFLAGS, SCFIND_REGEXP|SCFIND_POSIX);
_invisibleEditView.execute(SCI_SETTARGETRANGE, startPos, endPos);
auto posFound = _invisibleEditView.execute(SCI_SEARCHINTARGET, strlen(xmlHeaderRegExpr), reinterpret_cast<LPARAM>(xmlHeaderRegExpr));
if (posFound != -1 && posFound != -2)
{
const char *encodingBlockRegExpr = "encoding[ \\t]*=[ \\t]*\"[^\".]+\"";
_invisibleEditView.execute(SCI_SEARCHINTARGET, strlen(encodingBlockRegExpr), reinterpret_cast<LPARAM>(encodingBlockRegExpr));
const char *encodingRegExpr = "\".+\"";
_invisibleEditView.execute(SCI_SEARCHINTARGET, strlen(encodingRegExpr), reinterpret_cast<LPARAM>(encodingRegExpr));
_invisibleEditView.execute(SCI_SEARCHINTARGET, strlen(encodingAliasRegExpr), reinterpret_cast<LPARAM>(encodingAliasRegExpr));
startPos = int(_invisibleEditView.execute(SCI_GETTARGETSTART));
endPos = _invisibleEditView.execute(SCI_GETTARGETEND);
char encodingStr[128];
_invisibleEditView.getText(encodingStr, startPos, endPos);
EncodingMapper *em = EncodingMapper::getInstance();
int enc = em->getEncodingFromString(encodingStr);
return (enc==CP_ACP?-1:enc);
}
return -1;
}
else // if (langT == L_HTML)
{
const char *htmlHeaderRegExpr = "<meta[ \\t]+http-equiv[ \\t]*=[ \\t\"']*Content-Type[ \\t\"']*content[ \\t]*= *[\"']text/html;[ \\t]+charset[ \\t]*=[ \\t]*.+[\"'] */*>";
const char *htmlHeaderRegExpr2 = "<meta[ \\t]+content[ \\t]*= *[\"']text/html;[ \\t]+charset[ \\t]*=[ \\t]*.+[ \\t\"']http-equiv[ \\t]*=[ \\t\"']*Content-Type[ \\t\"']*/*>";
const char *charsetBlock = "charset[ \\t]*=[ \\t]*[^\"']+";
const char *intermediaire = "=[ \\t]*.+";
const char *encodingStrRE = "[^ \\t=]+";
int startPos = 0;
auto endPos = lenFile - 1;
_invisibleEditView.execute(SCI_SETSEARCHFLAGS, SCFIND_REGEXP|SCFIND_POSIX);
_invisibleEditView.execute(SCI_SETTARGETRANGE, startPos, endPos);
int posFound = static_cast<int32_t>(_invisibleEditView.execute(SCI_SEARCHINTARGET, strlen(htmlHeaderRegExpr), reinterpret_cast<LPARAM>(htmlHeaderRegExpr)));
if (posFound == -1 || posFound == -2)
{
posFound = static_cast<int32_t>(_invisibleEditView.execute(SCI_SEARCHINTARGET, strlen(htmlHeaderRegExpr2), reinterpret_cast<LPARAM>(htmlHeaderRegExpr2)));
if (posFound == -1 || posFound == -2)
return -1;
}
_invisibleEditView.execute(SCI_SEARCHINTARGET, strlen(charsetBlock), reinterpret_cast<LPARAM>(charsetBlock));
_invisibleEditView.execute(SCI_SEARCHINTARGET, strlen(intermediaire), reinterpret_cast<LPARAM>(intermediaire));
_invisibleEditView.execute(SCI_SEARCHINTARGET, strlen(encodingStrRE), reinterpret_cast<LPARAM>(encodingStrRE));
startPos = int(_invisibleEditView.execute(SCI_GETTARGETSTART));
endPos = _invisibleEditView.execute(SCI_GETTARGETEND);
char encodingStr[128];
_invisibleEditView.getText(encodingStr, startPos, endPos);
EncodingMapper *em = EncodingMapper::getInstance();
int enc = em->getEncodingFromString(encodingStr);
return (enc==CP_ACP?-1:enc);
}
}
bool Notepad_plus::replaceInOpenedFiles() {
ScintillaEditView *pOldView = _pEditView;
_pEditView = &_invisibleEditView;
Document oldDoc = _invisibleEditView.execute(SCI_GETDOCPOINTER);
Buffer * oldBuf = _invisibleEditView.getCurrentBuffer(); //for manually setting the buffer, so notifications can be handled properly
Buffer * pBuf = NULL;
int nbTotal = 0;
const bool isEntireDoc = true;
if (_mainWindowStatus & WindowMainActive)
{
for (size_t i = 0, len = _mainDocTab.nbItem(); i < len ; ++i)
{
pBuf = MainFileManager->getBufferByID(_mainDocTab.getBufferByIndex(i));
if (pBuf->isReadOnly())
continue;
_invisibleEditView.execute(SCI_SETDOCPOINTER, 0, pBuf->getDocument());
UINT cp = static_cast<UINT>(_invisibleEditView.execute(SCI_GETCODEPAGE));
_invisibleEditView.execute(SCI_SETCODEPAGE, pBuf->getUnicodeMode() == uni8Bit ? cp : SC_CP_UTF8);
_invisibleEditView.setCurrentBuffer(pBuf);
_invisibleEditView.execute(SCI_BEGINUNDOACTION);
nbTotal += _findReplaceDlg.processAll(ProcessReplaceAll, FindReplaceDlg::_env, isEntireDoc);
_invisibleEditView.execute(SCI_ENDUNDOACTION);
}
}
if (_mainWindowStatus & WindowSubActive)
{
for (size_t i = 0, len = _subDocTab.nbItem(); i < len; ++i)
{
pBuf = MainFileManager->getBufferByID(_subDocTab.getBufferByIndex(i));
if (pBuf->isReadOnly())
continue;
_invisibleEditView.execute(SCI_SETDOCPOINTER, 0, pBuf->getDocument());
UINT cp = static_cast<UINT>(_invisibleEditView.execute(SCI_GETCODEPAGE));
_invisibleEditView.execute(SCI_SETCODEPAGE, pBuf->getUnicodeMode() == uni8Bit ? cp : SC_CP_UTF8);
_invisibleEditView.setCurrentBuffer(pBuf);
_invisibleEditView.execute(SCI_BEGINUNDOACTION);
nbTotal += _findReplaceDlg.processAll(ProcessReplaceAll, FindReplaceDlg::_env, isEntireDoc);
_invisibleEditView.execute(SCI_ENDUNDOACTION);
}
}
_invisibleEditView.execute(SCI_SETDOCPOINTER, 0, oldDoc);
_invisibleEditView.setCurrentBuffer(oldBuf);
_pEditView = pOldView;
if (nbTotal < 0)
{
generic_string msg = _nativeLangSpeaker.getLocalizedStrFromID("find-status-replaceinfiles-re-malformed", TEXT("Replace in Opened Files: The regular expression is malformed."));
_findReplaceDlg.setStatusbarMessage(msg, FSNotFound);
}
else
{
if (nbTotal)
enableCommand(IDM_FILE_SAVEALL, true, MENU | TOOLBAR);
generic_string result;
if (nbTotal == 1)
{
result = _nativeLangSpeaker.getLocalizedStrFromID("find-status-replaceinopenedfiles-1-replaced", TEXT("Replace in Opened Files: 1 occurrence was replaced."));
}
else
{
result = _nativeLangSpeaker.getLocalizedStrFromID("find-status-replaceinopenedfiles-nb-replaced", TEXT("Replace in Opened Files: $INT_REPLACE$ occurrences were replaced."));
result = stringReplace(result, TEXT("$INT_REPLACE$"), std::to_wstring(nbTotal));
}
_findReplaceDlg.setStatusbarMessage(result, FSMessage);
}
return true;
}
void Notepad_plus::wsTabConvert(spaceTab whichWay)
{
int tabWidth = static_cast<int32_t>(_pEditView->execute(SCI_GETTABWIDTH));
int currentPos = static_cast<int32_t>(_pEditView->execute(SCI_GETCURRENTPOS));
int lastLine = _pEditView->lastZeroBasedLineNumber();
int docLength = static_cast<int32_t>(_pEditView->execute(SCI_GETLENGTH) + 1);
if (docLength < 2)
return;
int count = 0;
int column = 0;
int newCurrentPos = 0;
int tabStop = static_cast<int32_t>(tabWidth - 1); // remember, counting from zero !
bool onlyLeading = false;
vector<int> bookmarks;
vector<int> folding;
for (int i=0; i<lastLine; ++i)
{
if (bookmarkPresent(i))
bookmarks.push_back(i);
if ((_pEditView->execute(SCI_GETFOLDLEVEL, i) & SC_FOLDLEVELHEADERFLAG))
if (_pEditView->execute(SCI_GETFOLDEXPANDED, i) == 0)
folding.push_back(i);
}
char * source = new char[docLength];
if (source == NULL)
return;
_pEditView->execute(SCI_GETTEXT, docLength, reinterpret_cast<LPARAM>(source));
if (whichWay == tab2Space)
{
// count how many tabs are there
for (const char * ch=source; *ch; ++ch)
{
if (*ch == '\t')
++count;
}
if (count == 0)
{
delete [] source;
return;
}
}
// allocate tabwidth-1 chars extra per tab, just to be safe
size_t newlen = docLength + count * (tabWidth - 1) + 1;
char * destination = new char[newlen];
if (destination == NULL)
{
delete [] source;
return;
}
char * dest = destination;
switch (whichWay)
{
case tab2Space:
{
// rip through each line of the file
for (int i = 0; source[i] != '\0'; ++i)
{
if (source[i] == '\t')
{
int insertTabs = tabWidth - (column % tabWidth);
for (int j = 0; j < insertTabs; ++j)
{
*dest++ = ' ';
if (i <= currentPos)
++newCurrentPos;
}
column += insertTabs;
}
else
{
*dest++ = source[i];
if (i <= currentPos)
++newCurrentPos;
if ((source[i] == '\n') || (source[i] == '\r'))
column = 0;
else if ((source[i] & 0xC0) != 0x80) // UTF_8 support: count only bytes that don't start with 10......
++column;
}
}
*dest = '\0';
break;
}
case space2TabLeading:
{
onlyLeading = true;
}
case space2TabAll:
{
bool nextChar = false;
int counter = 0;
bool nonSpaceFound = false;
for (int i=0; source[i] != '\0'; ++i)
{
if (nonSpaceFound == false)
{
while (source[i + counter] == ' ')
{
if ((column + counter) == tabStop)
{
tabStop += tabWidth;
if (counter >= 1) // counter is counted from 0, so counter >= max-1
{
*dest++ = '\t';
i += counter;
column += counter + 1;
counter = 0;
nextChar = true;
if (i <= currentPos)
++newCurrentPos;
break;
}
else if (source[i+1] == ' ' || source[i+1] == '\t') // if followed by space or TAB, convert even a single space to TAB
{
*dest++ = '\t';
i++;
column += 1;
counter = 0;
if (i <= currentPos)
++newCurrentPos;
}
else // single space, don't convert it to TAB
{
*dest++ = source[i];
column += 1;
counter = 0;
nextChar = true;
if (i <= currentPos)
++newCurrentPos;
break;
}
}
else
++counter;
}
if (nextChar == true)
{
nextChar = false;
continue;
}
if (source[i] == ' ' && source[i + counter] == '\t') // spaces "absorbed" by a TAB on the right
{
*dest++ = '\t';
i += counter;
column = tabStop + 1;
tabStop += tabWidth;
counter = 0;
if (i <= currentPos)
++newCurrentPos;
continue;
}
}
if (onlyLeading == true && nonSpaceFound == false)
nonSpaceFound = true;
if (source[i] == '\n' || source[i] == '\r')
{
*dest++ = source[i];
column = 0;
tabStop = tabWidth - 1;
nonSpaceFound = false;
}
else if (source[i] == '\t')
{
*dest++ = source[i];
column = tabStop + 1;
tabStop += tabWidth;
counter = 0;
}
else
{
*dest++ = source[i];
counter = 0;
if ((source[i] & 0xC0) != 0x80) // UTF_8 support: count only bytes that don't start with 10......
{
++column;
if (column > 0 && column % tabWidth == 0)
tabStop += tabWidth;
}
}
if (i <= currentPos)
++newCurrentPos;
}
*dest = '\0';
break;
}
}
_pEditView->execute(SCI_BEGINUNDOACTION);
_pEditView->execute(SCI_SETTEXT, 0, reinterpret_cast<LPARAM>(destination));
_pEditView->execute(SCI_GOTOPOS, newCurrentPos);
for (size_t i=0; i<bookmarks.size(); ++i)
_pEditView->execute(SCI_MARKERADD, bookmarks[i], MARK_BOOKMARK);
for (size_t i=0; i<folding.size(); ++i)
_pEditView->fold(folding[i], false);
_pEditView->execute(SCI_ENDUNDOACTION);
// clean up
delete [] source;
delete [] destination;
}
void Notepad_plus::doTrim(trimOp whichPart)
{
// whichPart : line head or line tail
FindOption env;
if (whichPart == lineHeader)
{
env._str2Search = TEXT("^[ ]+");
}
else if (whichPart == lineTail)
{
env._str2Search = TEXT("[ ]+$");
}
else
return;
env._str4Replace = TEXT("");
env._searchType = FindRegex;
_findReplaceDlg.processAll(ProcessReplaceAll, &env, true);
}
void Notepad_plus::removeEmptyLine(bool isBlankContained)
{
// whichPart : line head or line tail
FindOption env;
if (isBlankContained)
{
env._str2Search = TEXT("^[\\t ]*$(\\r\\n|\\r|\\n)");
}
else
{
env._str2Search = TEXT("^$(\\r\\n|\\r|\\n)");
}
env._str4Replace = TEXT("");
env._searchType = FindRegex;
_findReplaceDlg.processAll(ProcessReplaceAll, &env, true);
// remove the last line if it's an empty line.
if (isBlankContained)
{
env._str2Search = TEXT("(\\r\\n|\\r|\\n)^[\\t ]*$");
}
else
{
env._str2Search = TEXT("(\\r\\n|\\r|\\n)^$");
}
_findReplaceDlg.processAll(ProcessReplaceAll, &env, true);
}
void Notepad_plus::getMatchedFileNames(const TCHAR *dir, const vector<generic_string> & patterns, vector<generic_string> & fileNames, bool isRecursive, bool isInHiddenDir)
{
generic_string dirFilter(dir);
dirFilter += TEXT("*.*");
WIN32_FIND_DATA foundData;
HANDLE hFile = ::FindFirstFile(dirFilter.c_str(), &foundData);
if (hFile != INVALID_HANDLE_VALUE)
{
if (foundData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (!isInHiddenDir && (foundData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))
{
// do nothing
}
else if (isRecursive)
{
if ((OrdinalIgnoreCaseCompareStrings(foundData.cFileName, TEXT(".")) != 0) && (OrdinalIgnoreCaseCompareStrings(foundData.cFileName, TEXT("..")) != 0))
{
generic_string pathDir(dir);
pathDir += foundData.cFileName;
pathDir += TEXT("\\");
getMatchedFileNames(pathDir.c_str(), patterns, fileNames, isRecursive, isInHiddenDir);
}
}
}
else
{
if (matchInList(foundData.cFileName, patterns))
{
generic_string pathFile(dir);
pathFile += foundData.cFileName;
fileNames.push_back(pathFile.c_str());
}
}
}
while (::FindNextFile(hFile, &foundData))
{
if (foundData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (!isInHiddenDir && (foundData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))
{
// do nothing
}
else if (isRecursive)
{
if ((OrdinalIgnoreCaseCompareStrings(foundData.cFileName, TEXT(".")) != 0) && (OrdinalIgnoreCaseCompareStrings(foundData.cFileName, TEXT("..")) != 0))
{
generic_string pathDir(dir);
pathDir += foundData.cFileName;
pathDir += TEXT("\\");
getMatchedFileNames(pathDir.c_str(), patterns, fileNames, isRecursive, isInHiddenDir);
}
}
}
else
{
if (matchInList(foundData.cFileName, patterns))
{
generic_string pathFile(dir);
pathFile += foundData.cFileName;
fileNames.push_back(pathFile.c_str());
}
}
}
::FindClose(hFile);
}
bool Notepad_plus::replaceInFiles()
{
LongRunningOperation op;
const TCHAR *dir2Search = _findReplaceDlg.getDir2Search();
if (!dir2Search[0] || !::PathFileExists(dir2Search))
{
return false;
}
bool isRecursive = _findReplaceDlg.isRecursive();
bool isInHiddenDir = _findReplaceDlg.isInHiddenDir();
int nbTotal = 0;
ScintillaEditView *pOldView = _pEditView;
_pEditView = &_invisibleEditView;
Document oldDoc = _invisibleEditView.execute(SCI_GETDOCPOINTER);
Buffer * oldBuf = _invisibleEditView.getCurrentBuffer(); //for manually setting the buffer, so notifications can be handled properly
vector<generic_string> patterns2Match;
_findReplaceDlg.getPatterns(patterns2Match);
if (patterns2Match.size() == 0)
{
_findReplaceDlg.setFindInFilesDirFilter(NULL, TEXT("*.*"));
_findReplaceDlg.getPatterns(patterns2Match);
}
vector<generic_string> fileNames;
getMatchedFileNames(dir2Search, patterns2Match, fileNames, isRecursive, isInHiddenDir);
Progress progress(_pPublicInterface->getHinst());
size_t filesCount = fileNames.size();
size_t filesPerPercent = 1;
if (filesCount > 1)
{
if (filesCount >= 200)
filesPerPercent = filesCount / 100;
progress.open(_findReplaceDlg.getHSelf(), TEXT("Replace In Files progress..."));
}
for (size_t i = 0, updateOnCount = filesPerPercent; i < filesCount; ++i)
{
if (progress.isCancelled()) break;
bool closeBuf = false;
BufferID id = MainFileManager->getBufferFromName(fileNames.at(i).c_str());
if (id == BUFFER_INVALID)
{
id = MainFileManager->loadFile(fileNames.at(i).c_str());
closeBuf = true;
}
if (id != BUFFER_INVALID)
{
Buffer * pBuf = MainFileManager->getBufferByID(id);
_invisibleEditView.execute(SCI_SETDOCPOINTER, 0, pBuf->getDocument());
auto cp = _invisibleEditView.execute(SCI_GETCODEPAGE);
_invisibleEditView.execute(SCI_SETCODEPAGE, pBuf->getUnicodeMode() == uni8Bit ? cp : SC_CP_UTF8);
_invisibleEditView.setCurrentBuffer(pBuf);
FindersInfo findersInfo;
findersInfo._pFileName = fileNames.at(i).c_str();
int nbReplaced = _findReplaceDlg.processAll(ProcessReplaceAll, FindReplaceDlg::_env, true, &findersInfo);
nbTotal += nbReplaced;
if (nbReplaced)
{
MainFileManager->saveBuffer(id, pBuf->getFullPathName());
}
if (closeBuf)
MainFileManager->closeBuffer(id, _pEditView);
}
if (i == updateOnCount)
{
updateOnCount += filesPerPercent;
progress.setPercent(int32_t((i * 100) / filesCount), fileNames.at(i).c_str());
}
else
{
progress.setInfo(fileNames.at(i).c_str());
}
}
progress.close();
_invisibleEditView.execute(SCI_SETDOCPOINTER, 0, oldDoc);
_invisibleEditView.setCurrentBuffer(oldBuf);
_pEditView = pOldView;
generic_string result;
if (nbTotal == 1)
{
result = _nativeLangSpeaker.getLocalizedStrFromID("find-status-replaceinfiles-1-replaced", TEXT("Replace in Files: 1 occurrence was replaced."));
}
else
{
result = _nativeLangSpeaker.getLocalizedStrFromID("find-status-replaceinfiles-nb-replaced", TEXT("Replace in Files: $INT_REPLACE$ occurrences were replaced."));
result = stringReplace(result, TEXT("$INT_REPLACE$"), std::to_wstring(nbTotal));
}
_findReplaceDlg.setStatusbarMessage(result, FSMessage);
return true;
}
bool Notepad_plus::findInFinderFiles(FindersInfo *findInFolderInfo)
{
int nbTotal = 0;
ScintillaEditView *pOldView = _pEditView;
_pEditView = &_invisibleEditView;
Document oldDoc = _invisibleEditView.execute(SCI_GETDOCPOINTER);
vector<generic_string> patterns2Match;
_findReplaceDlg.getPatterns(patterns2Match);
if (patterns2Match.size() == 0)
{
_findReplaceDlg.setFindInFilesDirFilter(NULL, TEXT("*.*"));
_findReplaceDlg.getPatterns(patterns2Match);
}
vector<generic_string> fileNames = findInFolderInfo->_pSourceFinder->getResultFilePaths();
findInFolderInfo->_pDestFinder->beginNewFilesSearch();
findInFolderInfo->_pDestFinder->addSearchLine(findInFolderInfo->_findOption._str2Search.c_str());
Progress progress(_pPublicInterface->getHinst());
size_t filesCount = fileNames.size();
size_t filesPerPercent = 1;
if (filesCount > 1)
{
if (filesCount >= 200)
filesPerPercent = filesCount / 100;
progress.open(_findReplaceDlg.getHSelf(), TEXT("Find In Files progress..."));
}
for (size_t i = 0, updateOnCount = filesPerPercent; i < filesCount; ++i)
{
if (progress.isCancelled()) break;
bool closeBuf = false;
BufferID id = MainFileManager->getBufferFromName(fileNames.at(i).c_str());
if (id == BUFFER_INVALID)
{
id = MainFileManager->loadFile(fileNames.at(i).c_str());
closeBuf = true;
}
if (id != BUFFER_INVALID)
{
Buffer * pBuf = MainFileManager->getBufferByID(id);
_invisibleEditView.execute(SCI_SETDOCPOINTER, 0, pBuf->getDocument());
auto cp = _invisibleEditView.execute(SCI_GETCODEPAGE);
_invisibleEditView.execute(SCI_SETCODEPAGE, pBuf->getUnicodeMode() == uni8Bit ? cp : SC_CP_UTF8);
findInFolderInfo->_pFileName = fileNames.at(i).c_str();
nbTotal += _findReplaceDlg.processAll(ProcessFindInFinder, &(findInFolderInfo->_findOption), true, findInFolderInfo);
if (closeBuf)
MainFileManager->closeBuffer(id, _pEditView);
}
if (i == updateOnCount)
{
updateOnCount += filesPerPercent;
progress.setPercent(int32_t((i * 100) / filesCount), fileNames.at(i).c_str());
}
else
{
progress.setInfo(fileNames.at(i).c_str());
}
}
progress.close();
findInFolderInfo->_pDestFinder->finishFilesSearch(nbTotal, findInFolderInfo->_findOption._isMatchLineNumber);
_invisibleEditView.execute(SCI_SETDOCPOINTER, 0, oldDoc);
_pEditView = pOldView;
return true;
}
bool Notepad_plus::findInFiles()
{
const TCHAR *dir2Search = _findReplaceDlg.getDir2Search();
if (not dir2Search[0] || not ::PathFileExists(dir2Search))
{
return false;
}
bool isRecursive = _findReplaceDlg.isRecursive();
bool isInHiddenDir = _findReplaceDlg.isInHiddenDir();
int nbTotal = 0;
ScintillaEditView *pOldView = _pEditView;
_pEditView = &_invisibleEditView;
Document oldDoc = _invisibleEditView.execute(SCI_GETDOCPOINTER);
vector<generic_string> patterns2Match;
_findReplaceDlg.getPatterns(patterns2Match);
if (patterns2Match.size() == 0)
{
_findReplaceDlg.setFindInFilesDirFilter(NULL, TEXT("*.*"));
_findReplaceDlg.getPatterns(patterns2Match);
}
vector<generic_string> fileNames;
getMatchedFileNames(dir2Search, patterns2Match, fileNames, isRecursive, isInHiddenDir);
_findReplaceDlg.beginNewFilesSearch();
Progress progress(_pPublicInterface->getHinst());
size_t filesCount = fileNames.size();
size_t filesPerPercent = 1;
if (filesCount > 1)
{
if (filesCount >= 200)
filesPerPercent = filesCount / 100;
progress.open(_findReplaceDlg.getHSelf(), TEXT("Find In Files progress..."));
}
for (size_t i = 0, updateOnCount = filesPerPercent; i < filesCount; ++i)
{
if (progress.isCancelled()) break;
bool closeBuf = false;
BufferID id = MainFileManager->getBufferFromName(fileNames.at(i).c_str());
if (id == BUFFER_INVALID)
{
id = MainFileManager->loadFile(fileNames.at(i).c_str());
closeBuf = true;
}
if (id != BUFFER_INVALID)
{
Buffer * pBuf = MainFileManager->getBufferByID(id);
_invisibleEditView.execute(SCI_SETDOCPOINTER, 0, pBuf->getDocument());
auto cp = _invisibleEditView.execute(SCI_GETCODEPAGE);
_invisibleEditView.execute(SCI_SETCODEPAGE, pBuf->getUnicodeMode() == uni8Bit ? cp : SC_CP_UTF8);
FindersInfo findersInfo;
findersInfo._pFileName = fileNames.at(i).c_str();
nbTotal += _findReplaceDlg.processAll(ProcessFindAll, FindReplaceDlg::_env, true, &findersInfo);
if (closeBuf)
MainFileManager->closeBuffer(id, _pEditView);
}
if (i == updateOnCount)
{
updateOnCount += filesPerPercent;
progress.setPercent(int32_t((i * 100) / filesCount), fileNames.at(i).c_str());
}
else
{
progress.setInfo(fileNames.at(i).c_str());
}
}
progress.close();
_findReplaceDlg.finishFilesSearch(nbTotal);
_invisibleEditView.execute(SCI_SETDOCPOINTER, 0, oldDoc);
_pEditView = pOldView;
_findReplaceDlg.putFindResult(nbTotal);
FindHistory & findHistory = (NppParameters::getInstance())->getFindHistory();
if (nbTotal && !findHistory._isDlgAlwaysVisible)
_findReplaceDlg.display(false);
return true;
}
bool Notepad_plus::findInOpenedFiles()
{
int nbTotal = 0;
ScintillaEditView *pOldView = _pEditView;
_pEditView = &_invisibleEditView;
Document oldDoc = _invisibleEditView.execute(SCI_GETDOCPOINTER);
Buffer * pBuf = NULL;
const bool isEntireDoc = true;
_findReplaceDlg.beginNewFilesSearch();
if (_mainWindowStatus & WindowMainActive)
{
for (size_t i = 0, len = _mainDocTab.nbItem(); i < len ; ++i)
{
pBuf = MainFileManager->getBufferByID(_mainDocTab.getBufferByIndex(i));
_invisibleEditView.execute(SCI_SETDOCPOINTER, 0, pBuf->getDocument());
auto cp = _invisibleEditView.execute(SCI_GETCODEPAGE);
_invisibleEditView.execute(SCI_SETCODEPAGE, pBuf->getUnicodeMode() == uni8Bit ? cp : SC_CP_UTF8);
FindersInfo findersInfo;
findersInfo._pFileName = pBuf->getFullPathName();
nbTotal += _findReplaceDlg.processAll(ProcessFindAll, FindReplaceDlg::_env, isEntireDoc, &findersInfo);
}
}
if (_mainWindowStatus & WindowSubActive)
{
for (size_t i = 0, len2 = _subDocTab.nbItem(); i < len2 ; ++i)
{
pBuf = MainFileManager->getBufferByID(_subDocTab.getBufferByIndex(i));
_invisibleEditView.execute(SCI_SETDOCPOINTER, 0, pBuf->getDocument());
auto cp = _invisibleEditView.execute(SCI_GETCODEPAGE);
_invisibleEditView.execute(SCI_SETCODEPAGE, pBuf->getUnicodeMode() == uni8Bit ? cp : SC_CP_UTF8);
FindersInfo findersInfo;
findersInfo._pFileName = pBuf->getFullPathName();
nbTotal += _findReplaceDlg.processAll(ProcessFindAll, FindReplaceDlg::_env, isEntireDoc, &findersInfo);
}
}
_findReplaceDlg.finishFilesSearch(nbTotal);
_invisibleEditView.execute(SCI_SETDOCPOINTER, 0, oldDoc);
_pEditView = pOldView;
_findReplaceDlg.putFindResult(nbTotal);
FindHistory & findHistory = (NppParameters::getInstance())->getFindHistory();
if (nbTotal && !findHistory._isDlgAlwaysVisible)
_findReplaceDlg.display(false);
return true;
}
bool Notepad_plus::findInCurrentFile()
{
int nbTotal = 0;
Buffer * pBuf = _pEditView->getCurrentBuffer();
ScintillaEditView *pOldView = _pEditView;
_pEditView = &_invisibleEditView;
Document oldDoc = _invisibleEditView.execute(SCI_GETDOCPOINTER);
const bool isEntireDoc = true;
_findReplaceDlg.beginNewFilesSearch();
_invisibleEditView.execute(SCI_SETDOCPOINTER, 0, pBuf->getDocument());
UINT cp = static_cast<UINT>(_invisibleEditView.execute(SCI_GETCODEPAGE));
_invisibleEditView.execute(SCI_SETCODEPAGE, pBuf->getUnicodeMode() == uni8Bit ? cp : SC_CP_UTF8);
FindersInfo findersInfo;
findersInfo._pFileName = pBuf->getFullPathName();
nbTotal += _findReplaceDlg.processAll(ProcessFindAll, FindReplaceDlg::_env, isEntireDoc, &findersInfo);
_findReplaceDlg.finishFilesSearch(nbTotal);
_invisibleEditView.execute(SCI_SETDOCPOINTER, 0, oldDoc);
_pEditView = pOldView;
_findReplaceDlg.putFindResult(nbTotal);
FindHistory & findHistory = (NppParameters::getInstance())->getFindHistory();
if (nbTotal && !findHistory._isDlgAlwaysVisible)
_findReplaceDlg.display(false);
return true;
}
void Notepad_plus::filePrint(bool showDialog)
{
Printer printer;
int startPos = int(_pEditView->execute(SCI_GETSELECTIONSTART));
int endPos = int(_pEditView->execute(SCI_GETSELECTIONEND));
printer.init(_pPublicInterface->getHinst(), _pPublicInterface->getHSelf(), _pEditView, showDialog, startPos, endPos, _nativeLangSpeaker.isRTL());
printer.doPrint();
}
int Notepad_plus::doSaveOrNot(const TCHAR *fn)
{
return _nativeLangSpeaker.messageBox("DoSaveOrNot",
_pPublicInterface->getHSelf(),
TEXT("Save file \"$STR_REPLACE$\" ?"),
TEXT("Save"),
MB_YESNOCANCEL | MB_ICONQUESTION | MB_APPLMODAL,
0, // not used
fn);
}
int Notepad_plus::doReloadOrNot(const TCHAR *fn, bool dirty)
{
if (dirty)
return _nativeLangSpeaker.messageBox("DoReloadOrNotAndLooseChange",
_pPublicInterface->getHSelf(),
TEXT("\"$STR_REPLACE$\"\r\rThis file has been modified by another program.\rDo you want to reload it and lose the changes made in Notepad++?"),
TEXT("Reload"),
MB_YESNO | MB_APPLMODAL | MB_ICONEXCLAMATION,
0, // not used
fn);
else
return _nativeLangSpeaker.messageBox("DoReloadOrNot",
_pPublicInterface->getHSelf(),
TEXT("\"$STR_REPLACE$\"\r\rThis file has been modified by another program.\rDo you want to reload it?"),
TEXT("Reload"),
MB_YESNO | MB_APPLMODAL | MB_ICONQUESTION,
0, // not used
fn);
}
int Notepad_plus::doCloseOrNot(const TCHAR *fn)
{
return _nativeLangSpeaker.messageBox("DoCloseOrNot",
_pPublicInterface->getHSelf(),
TEXT("The file \"$STR_REPLACE$\" doesn't exist anymore.\rKeep this file in editor?"),
TEXT("Keep non existing file"),
MB_YESNO | MB_ICONQUESTION | MB_APPLMODAL,
0, // not used
fn);
}
int Notepad_plus::doDeleteOrNot(const TCHAR *fn)
{
return _nativeLangSpeaker.messageBox("DoDeleteOrNot",
_pPublicInterface->getHSelf(),
TEXT("The file \"$STR_REPLACE$\"\rwill be moved to your Recycle Bin and this document will be closed.\rContinue?"),
TEXT("Delete file"),
MB_YESNO | MB_ICONQUESTION | MB_APPLMODAL,
0, // not used
fn);
}
void Notepad_plus::enableMenu(int cmdID, bool doEnable) const
{
int flag = doEnable?MF_ENABLED | MF_BYCOMMAND:MF_DISABLED | MF_GRAYED | MF_BYCOMMAND;
::EnableMenuItem(_mainMenuHandle, cmdID, flag);
}
void Notepad_plus::enableCommand(int cmdID, bool doEnable, int which) const
{
if (which & MENU)
{
enableMenu(cmdID, doEnable);
}
if (which & TOOLBAR)
{
_toolBar.enable(cmdID, doEnable);
}
}
void Notepad_plus::checkClipboard()
{
bool hasSelection = (_pEditView->execute(SCI_GETSELECTIONSTART) != _pEditView->execute(SCI_GETSELECTIONEND));
bool canPaste = (_pEditView->execute(SCI_CANPASTE) != 0);
enableCommand(IDM_EDIT_CUT, hasSelection, MENU | TOOLBAR);
enableCommand(IDM_EDIT_COPY, hasSelection, MENU | TOOLBAR);
enableCommand(IDM_EDIT_PASTE, canPaste, MENU | TOOLBAR);
enableCommand(IDM_EDIT_DELETE, hasSelection, MENU | TOOLBAR);
enableCommand(IDM_EDIT_UPPERCASE, hasSelection, MENU);
enableCommand(IDM_EDIT_LOWERCASE, hasSelection, MENU);
enableCommand(IDM_EDIT_PROPERCASE_FORCE, hasSelection, MENU);
enableCommand(IDM_EDIT_PROPERCASE_BLEND, hasSelection, MENU);
enableCommand(IDM_EDIT_SENTENCECASE_FORCE, hasSelection, MENU);
enableCommand(IDM_EDIT_SENTENCECASE_BLEND, hasSelection, MENU);
enableCommand(IDM_EDIT_INVERTCASE, hasSelection, MENU);
enableCommand(IDM_EDIT_RANDOMCASE, hasSelection, MENU);
}
void Notepad_plus::checkDocState()
{
Buffer * curBuf = _pEditView->getCurrentBuffer();
bool isCurrentDirty = curBuf->isDirty();
bool isSeveralDirty = isCurrentDirty;
bool isFileExisting = PathFileExists(curBuf->getFullPathName()) != FALSE;
if (!isCurrentDirty)
{
for (size_t i = 0; i < MainFileManager->getNbBuffers(); ++i)
{
if (MainFileManager->getBufferByIndex(i)->isDirty())
{
isSeveralDirty = true;
break;
}
}
}
bool isCurrentUntitled = curBuf->isUntitled();
enableCommand(IDM_FILE_SAVE, isCurrentDirty, MENU | TOOLBAR);
enableCommand(IDM_FILE_SAVEALL, isSeveralDirty, MENU | TOOLBAR);
enableCommand(IDM_VIEW_GOTO_NEW_INSTANCE, !(isCurrentDirty || isCurrentUntitled), MENU);
enableCommand(IDM_VIEW_LOAD_IN_NEW_INSTANCE, !(isCurrentDirty || isCurrentUntitled), MENU);
bool isSysReadOnly = curBuf->getFileReadOnly();
if (isSysReadOnly)
{
::CheckMenuItem(_mainMenuHandle, IDM_EDIT_SETREADONLY, MF_BYCOMMAND | MF_UNCHECKED);
enableCommand(IDM_EDIT_SETREADONLY, false, MENU);
enableCommand(IDM_EDIT_CLEARREADONLY, true, MENU);
}
else
{
enableCommand(IDM_EDIT_SETREADONLY, true, MENU);
enableCommand(IDM_EDIT_CLEARREADONLY, false, MENU);
bool isUserReadOnly = curBuf->getUserReadOnly();
::CheckMenuItem(_mainMenuHandle, IDM_EDIT_SETREADONLY, MF_BYCOMMAND | (isUserReadOnly?MF_CHECKED:MF_UNCHECKED));
}
enableCommand(IDM_FILE_DELETE, isFileExisting, MENU);
enableCommand(IDM_FILE_RENAME, isFileExisting, MENU);
enableCommand(IDM_FILE_OPEN_CMD, isFileExisting, MENU);
enableCommand(IDM_FILE_OPEN_FOLDER, isFileExisting, MENU);
enableCommand(IDM_FILE_RELOAD, isFileExisting, MENU);
enableCommand(IDM_FILE_OPEN_DEFAULT_VIEWER, isAssoCommandExisting(curBuf->getFullPathName()), MENU);
enableConvertMenuItems(curBuf->getEolFormat());
checkUnicodeMenuItems();
checkLangsMenu(-1);
if (_pAnsiCharPanel)
_pAnsiCharPanel->switchEncoding();
enableCommand(IDM_VIEW_MONITORING, not curBuf->isUntitled(), MENU | TOOLBAR);
enableCommand(IDM_EDIT_SETREADONLY, not curBuf->isMonitoringOn(), MENU);
checkMenuItem(IDM_VIEW_MONITORING, curBuf->isMonitoringOn());
_toolBar.setCheck(IDM_VIEW_MONITORING, curBuf->isMonitoringOn());
}
void Notepad_plus::checkUndoState()
{
enableCommand(IDM_EDIT_UNDO, _pEditView->execute(SCI_CANUNDO) != 0, MENU | TOOLBAR);
enableCommand(IDM_EDIT_REDO, _pEditView->execute(SCI_CANREDO) != 0, MENU | TOOLBAR);
}
void Notepad_plus::checkMacroState()
{
enableCommand(IDM_MACRO_STARTRECORDINGMACRO, !_recordingMacro, MENU | TOOLBAR);
enableCommand(IDM_MACRO_STOPRECORDINGMACRO, _recordingMacro, MENU | TOOLBAR);
enableCommand(IDM_MACRO_PLAYBACKRECORDEDMACRO, !_macro.empty() && !_recordingMacro, MENU | TOOLBAR);
enableCommand(IDM_MACRO_SAVECURRENTMACRO, !_macro.empty() && !_recordingMacro && !_recordingSaved, MENU | TOOLBAR);
enableCommand(IDM_MACRO_RUNMULTIMACRODLG, (!_macro.empty() && !_recordingMacro) || !((NppParameters::getInstance())->getMacroList()).empty(), MENU | TOOLBAR);
}
void Notepad_plus::checkSyncState()
{
bool canDoSync = viewVisible(MAIN_VIEW) && viewVisible(SUB_VIEW);
if (!canDoSync)
{
_syncInfo._isSynScollV = false;
_syncInfo._isSynScollH = false;
checkMenuItem(IDM_VIEW_SYNSCROLLV, false);
checkMenuItem(IDM_VIEW_SYNSCROLLH, false);
_toolBar.setCheck(IDM_VIEW_SYNSCROLLV, false);
_toolBar.setCheck(IDM_VIEW_SYNSCROLLH, false);
}
enableCommand(IDM_VIEW_SYNSCROLLV, canDoSync, MENU | TOOLBAR);
enableCommand(IDM_VIEW_SYNSCROLLH, canDoSync, MENU | TOOLBAR);
}
void doCheck(HMENU mainHandle, int id)
{
MENUITEMINFO mii;
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_SUBMENU | MIIM_FTYPE | MIIM_ID | MIIM_STATE;
int count = ::GetMenuItemCount(mainHandle);
for (int i = 0; i < count; i++)
{
::GetMenuItemInfo(mainHandle, i, MF_BYPOSITION, &mii);
if (mii.fType == MFT_RADIOCHECK || mii.fType == MFT_STRING)
{
if (mii.hSubMenu == 0)
{
if (mii.wID == (unsigned int)id)
{
::CheckMenuRadioItem(mainHandle, 0, count, i, MF_BYPOSITION);
}
else
{
mii.fState = 0;
::SetMenuItemInfo(mainHandle, i, MF_BYPOSITION, &mii);
}
}
else
{
doCheck(mii.hSubMenu, id);
}
}
}
}
void Notepad_plus::checkLangsMenu(int id) const
{
Buffer * curBuf = _pEditView->getCurrentBuffer();
if (id == -1)
{
id = (NppParameters::getInstance())->langTypeToCommandID(curBuf->getLangType());
if (id == IDM_LANG_USER)
{
if (curBuf->isUserDefineLangExt())
{
const TCHAR *userLangName = curBuf->getUserDefineLangName();
const int nbChar = 16;
TCHAR menuLangName[nbChar];
for (int i = IDM_LANG_USER + 1 ; i <= IDM_LANG_USER_LIMIT ; ++i)
{
if (::GetMenuString(_mainMenuHandle, i, menuLangName, nbChar-1, MF_BYCOMMAND))
if (!lstrcmp(userLangName, menuLangName))
{
HMENU _langMenuHandle = ::GetSubMenu(_mainMenuHandle, MENUINDEX_LANGUAGE);
doCheck(_langMenuHandle, i);
return;
}
}
}
}
}
HMENU _langMenuHandle = ::GetSubMenu(_mainMenuHandle, MENUINDEX_LANGUAGE);
doCheck(_langMenuHandle, id);
}
generic_string Notepad_plus::getLangDesc(LangType langType, bool getName)
{
if ((langType >= L_EXTERNAL) && (langType < NppParameters::getInstance()->L_END))
{
ExternalLangContainer & elc = NppParameters::getInstance()->getELCFromIndex(langType - L_EXTERNAL);
if (getName)
return generic_string(elc._name);
else
return generic_string(elc._desc);
}
if (langType > L_EXTERNAL)
langType = L_TEXT;
generic_string str2Show;
if (getName)
str2Show = ScintillaEditView::langNames[langType].shortName;
else
str2Show = ScintillaEditView::langNames[langType].longName;
if (langType == L_USER)
{
Buffer * currentBuf = _pEditView->getCurrentBuffer();
if (currentBuf->isUserDefineLangExt())
{
str2Show += TEXT(" - ");
str2Show += currentBuf->getUserDefineLangName();
}
}
return str2Show;
}
void Notepad_plus::copyMarkedLines()
{
int lastLine = _pEditView->lastZeroBasedLineNumber();
generic_string globalStr = TEXT("");
for (int i = lastLine ; i >= 0 ; i--)
{
if (bookmarkPresent(i))
{
generic_string currentStr = getMarkedLine(i) + globalStr;
globalStr = currentStr;
}
}
str2Cliboard(globalStr);
}
void Notepad_plus::cutMarkedLines()
{
LongRunningOperation op;
int lastLine = _pEditView->lastZeroBasedLineNumber();
generic_string globalStr = TEXT("");
_pEditView->execute(SCI_BEGINUNDOACTION);
for (int i = lastLine ; i >= 0 ; i--)
{
if (bookmarkPresent(i))
{
generic_string currentStr = getMarkedLine(i) + globalStr;
globalStr = currentStr;
deleteMarkedline(i);
}
}
_pEditView->execute(SCI_ENDUNDOACTION);
str2Cliboard(globalStr);
}
void Notepad_plus::deleteMarkedLines(bool isMarked)
{
LongRunningOperation op;
int lastLine = _pEditView->lastZeroBasedLineNumber();
_pEditView->execute(SCI_BEGINUNDOACTION);
for (int i = lastLine ; i >= 0 ; i--)
{
if (bookmarkPresent(i) == isMarked)
deleteMarkedline(i);
}
_pEditView->execute(SCI_ENDUNDOACTION);
}
void Notepad_plus::pasteToMarkedLines()
{
LongRunningOperation op;
int clipFormat;
clipFormat = CF_UNICODETEXT;
BOOL canPaste = ::IsClipboardFormatAvailable(clipFormat);
if (!canPaste)
return;
int lastLine = _pEditView->lastZeroBasedLineNumber();
::OpenClipboard(_pPublicInterface->getHSelf());
HANDLE clipboardData = ::GetClipboardData(clipFormat);
::GlobalSize(clipboardData);
LPVOID clipboardDataPtr = ::GlobalLock(clipboardData);
generic_string clipboardStr = (const TCHAR *)clipboardDataPtr;
::GlobalUnlock(clipboardData);
::CloseClipboard();
_pEditView->execute(SCI_BEGINUNDOACTION);
for (int i = lastLine ; i >= 0 ; i--)
{
if (bookmarkPresent(i))
{
replaceMarkedline(i, clipboardStr.c_str());
}
}
_pEditView->execute(SCI_ENDUNDOACTION);
}
void Notepad_plus::deleteMarkedline(int ln)
{
int lineLen = static_cast<int32_t>(_pEditView->execute(SCI_LINELENGTH, ln));
int lineBegin = static_cast<int32_t>(_pEditView->execute(SCI_POSITIONFROMLINE, ln));
bookmarkDelete(ln);
TCHAR emptyString[2] = TEXT("");
_pEditView->replaceTarget(emptyString, lineBegin, lineBegin + lineLen);
}
void Notepad_plus::inverseMarks()
{
int lastLine = _pEditView->lastZeroBasedLineNumber();
for (int i = 0 ; i <= lastLine ; ++i)
{
if (bookmarkPresent(i))
{
bookmarkDelete(i);
}
else
{
bookmarkAdd(i);
}
}
}
void Notepad_plus::replaceMarkedline(int ln, const TCHAR *str)
{
int lineBegin = static_cast<int32_t>(_pEditView->execute(SCI_POSITIONFROMLINE, ln));
int lineEnd = static_cast<int32_t>(_pEditView->execute(SCI_GETLINEENDPOSITION, ln));
_pEditView->replaceTarget(str, lineBegin, lineEnd);
}
generic_string Notepad_plus::getMarkedLine(int ln)
{
auto lineLen = _pEditView->execute(SCI_LINELENGTH, ln);
auto lineBegin = _pEditView->execute(SCI_POSITIONFROMLINE, ln);
TCHAR * buf = new TCHAR[lineLen+1];
_pEditView->getGenericText(buf, lineLen + 1, lineBegin, lineBegin + lineLen);
generic_string line = buf;
delete [] buf;
return line;
}
void Notepad_plus::findMatchingBracePos(int & braceAtCaret, int & braceOpposite)
{
int caretPos = int(_pEditView->execute(SCI_GETCURRENTPOS));
braceAtCaret = -1;
braceOpposite = -1;
TCHAR charBefore = '\0';
int lengthDoc = int(_pEditView->execute(SCI_GETLENGTH));
if ((lengthDoc > 0) && (caretPos > 0))
{
charBefore = TCHAR(_pEditView->execute(SCI_GETCHARAT, caretPos - 1, 0));
}
// Priority goes to character before caret
if (charBefore && generic_strchr(TEXT("[](){}"), charBefore))
{
braceAtCaret = caretPos - 1;
}
if (lengthDoc > 0 && (braceAtCaret < 0))
{
// No brace found so check other side
TCHAR charAfter = TCHAR(_pEditView->execute(SCI_GETCHARAT, caretPos, 0));
if (charAfter && generic_strchr(TEXT("[](){}"), charAfter))
{
braceAtCaret = caretPos;
}
}
if (braceAtCaret >= 0)
braceOpposite = int(_pEditView->execute(SCI_BRACEMATCH, braceAtCaret, 0));
}
// return true if 1 or 2 (matched) brace(s) is found
bool Notepad_plus::braceMatch()
{
int braceAtCaret = -1;
int braceOpposite = -1;
findMatchingBracePos(braceAtCaret, braceOpposite);
if ((braceAtCaret != -1) && (braceOpposite == -1))
{
_pEditView->execute(SCI_BRACEBADLIGHT, braceAtCaret);
_pEditView->execute(SCI_SETHIGHLIGHTGUIDE, 0);
}
else
{
_pEditView->execute(SCI_BRACEHIGHLIGHT, braceAtCaret, braceOpposite);
if (_pEditView->isShownIndentGuide())
{
int columnAtCaret = int(_pEditView->execute(SCI_GETCOLUMN, braceAtCaret));
int columnOpposite = int(_pEditView->execute(SCI_GETCOLUMN, braceOpposite));
_pEditView->execute(SCI_SETHIGHLIGHTGUIDE, (columnAtCaret < columnOpposite)?columnAtCaret:columnOpposite);
}
}
const bool enable = (braceAtCaret != -1) && (braceOpposite != -1);
enableCommand(IDM_SEARCH_GOTOMATCHINGBRACE, enable, MENU | TOOLBAR);
enableCommand(IDM_SEARCH_SELECTMATCHINGBRACES, enable, MENU);
return (braceAtCaret != -1);
}
void Notepad_plus::setLangStatus(LangType langType)
{
_statusBar.setText(getLangDesc(langType).c_str(), STATUSBAR_DOC_TYPE);
}
void Notepad_plus::setDisplayFormat(EolType format)
{
const TCHAR* str = TEXT("??");
switch (format)
{
case EolType::windows: str = TEXT("Windows (CR LF)"); break;
case EolType::macos: str = TEXT("Macintosh (CR)"); break;
case EolType::unix: str = TEXT("Unix (LF)"); break;
case EolType::unknown: str = TEXT("Unknown"); assert(false); break;
}
_statusBar.setText(str, STATUSBAR_EOF_FORMAT);
}
void Notepad_plus::setUniModeText()
{
Buffer *buf = _pEditView->getCurrentBuffer();
int encoding = buf->getEncoding();
UniMode um = buf->getUnicodeMode();
generic_string uniModeTextString;
if (encoding == -1)
{
switch (um)
{
case uniUTF8:
uniModeTextString = TEXT("UTF-8-BOM"); break;
case uni16BE:
uniModeTextString = TEXT("UCS-2 BE BOM"); break;
case uni16LE:
uniModeTextString = TEXT("UCS-2 LE BOM"); break;
case uni16BE_NoBOM:
uniModeTextString = TEXT("UCS-2 Big Endian"); break;
case uni16LE_NoBOM:
uniModeTextString = TEXT("UCS-2 Little Endian"); break;
case uniCookie:
uniModeTextString = TEXT("UTF-8"); break;
default :
uniModeTextString = TEXT("ANSI");
}
}
else
{
EncodingMapper *em = EncodingMapper::getInstance();
int cmdID = em->getIndexFromEncoding(encoding);
if (cmdID == -1)
{
//printStr(TEXT("Encoding problem. Encoding is not added in encoding_table?"));
return;
}
cmdID += IDM_FORMAT_ENCODE;
const int itemSize = 64;
TCHAR uniModeText[itemSize];
::GetMenuString(_mainMenuHandle, cmdID, uniModeText, itemSize, MF_BYCOMMAND);
uniModeTextString = uniModeText;
}
_statusBar.setText(uniModeTextString.c_str(), STATUSBAR_UNICODE_TYPE);
}
void Notepad_plus::addHotSpot()
{
int startPos = 0;
int endPos = -1;
auto endStyle = _pEditView->execute(SCI_GETENDSTYLED);
_pEditView->getVisibleStartAndEndPosition(&startPos, &endPos);
_pEditView->execute(SCI_SETSEARCHFLAGS, SCFIND_REGEXP|SCFIND_POSIX);
_pEditView->execute(SCI_SETTARGETRANGE, startPos, endPos);
std::vector<unsigned char> hotspotPairs; //= _pEditView->GetHotspotPairs();
unsigned char style_hotspot = 0;
unsigned char mask = INDIC1_MASK;
// INDIC2_MASK == 255 and it represents MSB bit
// only LEX_HTML and LEX_POSTSCRIPT use use INDIC2_MASK bit internally
// LEX_HTML is using INDIC2_MASK bit even though it has only 127 states, so it is safe to overwrite 8th bit
// INDIC2_MASK will be used for LEX_HTML
// LEX_POSTSCRIPT is using INDIC2_MASK bit for "tokenization", and is using mask=31 in lexer,
// therefore hotspot in LEX_POSTSCRIPT will be saved to 5th bit
// there are only 15 states in LEX_POSTSCRIPT, so it is safe to overwrite 5th bit
// rule of the thumb is, any lexet that calls: styler.StartAt(startPos, 255);
// must have special processing here, all other lexers are fine with INDIC1_MASK (7th bit)
LangType type = _pEditView->getCurrentBuffer()->getLangType();
if (type == L_HTML || type == L_PHP || type == L_ASP || type == L_JSP)
mask = INDIC2_MASK;
else if (type == L_PS)
mask = 16;
int posFound = static_cast<int32_t>(_pEditView->execute(SCI_SEARCHINTARGET, strlen(URL_REG_EXPR), reinterpret_cast<LPARAM>(URL_REG_EXPR)));
while (posFound != -1 && posFound != -2)
{
int start = int(_pEditView->execute(SCI_GETTARGETSTART));
int end = int(_pEditView->execute(SCI_GETTARGETEND));
int foundTextLen = end - start;
unsigned char idStyle = static_cast<unsigned char>(_pEditView->execute(SCI_GETSTYLEAT, posFound));
// Search the style
int fs = -1;
for (size_t i = 0, len = hotspotPairs.size(); i < len ; ++i)
{
// make sure to ignore "hotspot bit" when comparing document style with archived hotspot style
if ((hotspotPairs[i] & ~mask) == (idStyle & ~mask))
{
fs = hotspotPairs[i];
_pEditView->execute(SCI_STYLEGETFORE, fs);
break;
}
}
// if we found it then use it to colourize
if (fs != -1)
{
_pEditView->execute(SCI_STARTSTYLING, start, 0xFF);
_pEditView->execute(SCI_SETSTYLING, foundTextLen, fs);
}
else // generalize a new style and add it into a array
{
style_hotspot = idStyle | mask; // set "hotspot bit"
hotspotPairs.push_back(style_hotspot);
unsigned char idStyleMSBunset = idStyle & ~mask;
char fontNameA[128];
Style hotspotStyle;
hotspotStyle._styleID = static_cast<int>(style_hotspot);
_pEditView->execute(SCI_STYLEGETFONT, idStyleMSBunset, reinterpret_cast<LPARAM>(fontNameA));
TCHAR *generic_fontname = new TCHAR[128];
WcharMbcsConvertor *wmc = WcharMbcsConvertor::getInstance();
const wchar_t * fontNameW = wmc->char2wchar(fontNameA, _nativeLangSpeaker.getLangEncoding());
lstrcpy(generic_fontname, fontNameW);
hotspotStyle._fontName = generic_fontname;
hotspotStyle._fgColor = static_cast<COLORREF>(_pEditView->execute(SCI_STYLEGETFORE, idStyleMSBunset));
hotspotStyle._bgColor = static_cast<COLORREF>(_pEditView->execute(SCI_STYLEGETBACK, idStyleMSBunset));
hotspotStyle._fontSize = static_cast<int32_t>(_pEditView->execute(SCI_STYLEGETSIZE, idStyleMSBunset));
auto isBold = _pEditView->execute(SCI_STYLEGETBOLD, idStyleMSBunset);
auto isItalic = _pEditView->execute(SCI_STYLEGETITALIC, idStyleMSBunset);
auto isUnderline = _pEditView->execute(SCI_STYLEGETUNDERLINE, idStyleMSBunset);
hotspotStyle._fontStyle = (isBold?FONTSTYLE_BOLD:0) | (isItalic?FONTSTYLE_ITALIC:0) | (isUnderline?FONTSTYLE_UNDERLINE:0);
int urlAction = (NppParameters::getInstance())->getNppGUI()._styleURL;
if (urlAction == 2)
hotspotStyle._fontStyle |= FONTSTYLE_UNDERLINE;
_pEditView->setHotspotStyle(hotspotStyle);
_pEditView->execute(SCI_STYLESETHOTSPOT, style_hotspot, TRUE);
int activeFG = 0xFF0000;
Style *urlHovered = getStyleFromName(TEXT("URL hovered"));
if (urlHovered)
activeFG = urlHovered->_fgColor;
_pEditView->execute(SCI_SETHOTSPOTACTIVEFORE, TRUE, activeFG);
_pEditView->execute(SCI_SETHOTSPOTSINGLELINE, style_hotspot, 0);
// colourize it!
_pEditView->execute(SCI_STARTSTYLING, start, 0xFF);
_pEditView->execute(SCI_SETSTYLING, foundTextLen, style_hotspot);
}
_pEditView->execute(SCI_SETTARGETRANGE, posFound + foundTextLen, endPos);
posFound = static_cast<int32_t>(_pEditView->execute(SCI_SEARCHINTARGET, strlen(URL_REG_EXPR), reinterpret_cast<LPARAM>(URL_REG_EXPR)));
}
_pEditView->execute(SCI_STARTSTYLING, endStyle, 0xFF);
_pEditView->execute(SCI_SETSTYLING, 0, 0);
}
bool Notepad_plus::isConditionExprLine(int lineNumber)
{
if (lineNumber < 0 || lineNumber > _pEditView->execute(SCI_GETLINECOUNT))
return false;
auto startPos = _pEditView->execute(SCI_POSITIONFROMLINE, lineNumber);
auto endPos = _pEditView->execute(SCI_GETLINEENDPOSITION, lineNumber);
_pEditView->execute(SCI_SETSEARCHFLAGS, SCFIND_REGEXP | SCFIND_POSIX);
_pEditView->execute(SCI_SETTARGETRANGE, startPos, endPos);
const char ifElseForWhileExpr[] = "((else[ \t]+)?if|for|while)[ \t]*[(].*[)][ \t]*|else[ \t]*";
auto posFound = _pEditView->execute(SCI_SEARCHINTARGET, strlen(ifElseForWhileExpr), reinterpret_cast<LPARAM>(ifElseForWhileExpr));
if (posFound != -1 && posFound != -2)
{
auto end = _pEditView->execute(SCI_GETTARGETEND);
if (end == endPos)
return true;
}
return false;
}
int Notepad_plus::findMachedBracePos(size_t startPos, size_t endPos, char targetSymbol, char matchedSymbol)
{
if (startPos == endPos)
return -1;
if (startPos > endPos) // backward
{
int balance = 0;
for (int i = int(startPos); i >= int(endPos); --i)
{
char aChar = static_cast<char>(_pEditView->execute(SCI_GETCHARAT, i));
if (aChar == targetSymbol)
{
if (balance == 0)
return i;
--balance;
}
else if (aChar == matchedSymbol)
{
++balance;
}
}
}
else // forward
{
}
return -1;
}
void Notepad_plus::maintainIndentation(TCHAR ch)
{
int eolMode = static_cast<int32_t>((_pEditView->execute(SCI_GETEOLMODE)));
int curLine = static_cast<int32_t>((_pEditView->getCurrentLineNumber()));
int prevLine = curLine - 1;
int indentAmountPrevLine = 0;
int tabWidth = static_cast<int32_t>(_pEditView->execute(SCI_GETTABWIDTH));
LangType type = _pEditView->getCurrentBuffer()->getLangType();
// Do not alter indentation if we were at the beginning of the line and we pressed Enter
if ((((eolMode == SC_EOL_CRLF || eolMode == SC_EOL_LF) && ch == '\n') ||
(eolMode == SC_EOL_CR && ch == '\r')) && prevLine >= 0 && _pEditView->getLineLength(prevLine) == 0)
return;
if (type == L_C || type == L_CPP || type == L_JAVA || type == L_CS || type == L_OBJC ||
type == L_PHP || type == L_JS || type == L_JAVASCRIPT || type == L_JSP || type == L_CSS)
{
if (((eolMode == SC_EOL_CRLF || eolMode == SC_EOL_LF) && ch == '\n') ||
(eolMode == SC_EOL_CR && ch == '\r'))
{
// Search the non-empty previous line
while (prevLine >= 0 && _pEditView->getLineLength(prevLine) == 0)
prevLine--;
// Get previous line's Indent
if (prevLine >= 0)
{
indentAmountPrevLine = _pEditView->getLineIndent(prevLine);
}
// get previous char from current line
int prevPos = static_cast<int32_t>(_pEditView->execute(SCI_GETCURRENTPOS)) - (eolMode == SC_EOL_CRLF ? 3 : 2);
UCHAR prevChar = (UCHAR)_pEditView->execute(SCI_GETCHARAT, prevPos);
auto curPos = _pEditView->execute(SCI_GETCURRENTPOS);
UCHAR nextChar = (UCHAR)_pEditView->execute(SCI_GETCHARAT, curPos);
if (prevChar == '{')
{
if (nextChar == '}')
{
const char *eolChars;
if (eolMode == SC_EOL_CRLF)
eolChars = "\r\n";
else if (eolMode == SC_EOL_LF)
eolChars = "\n";
else
eolChars = "\r";
_pEditView->execute(SCI_INSERTTEXT, _pEditView->execute(SCI_GETCURRENTPOS), reinterpret_cast<LPARAM>(eolChars));
_pEditView->setLineIndent(curLine + 1, indentAmountPrevLine);
}
_pEditView->setLineIndent(curLine, indentAmountPrevLine + tabWidth);
}
else if (nextChar == '{')
{
_pEditView->setLineIndent(curLine, indentAmountPrevLine);
}
else if (isConditionExprLine(prevLine))
{
_pEditView->setLineIndent(curLine, indentAmountPrevLine + tabWidth);
}
else
{
if (indentAmountPrevLine > 0)
{
if (prevLine > 0 && isConditionExprLine(prevLine - 1))
_pEditView->setLineIndent(curLine, indentAmountPrevLine - tabWidth);
else
_pEditView->setLineIndent(curLine, indentAmountPrevLine);
}
}
}
else if (ch == '{')
{
// if no character in front of {, aligned with prev line's indentation
auto startPos = _pEditView->execute(SCI_POSITIONFROMLINE, curLine);
LRESULT endPos = _pEditView->execute(SCI_GETCURRENTPOS);
for (LRESULT i = endPos - 2; i > 0 && i > startPos; --i)
{
UCHAR aChar = (UCHAR)_pEditView->execute(SCI_GETCHARAT, i);
if (aChar != ' ' && aChar != '\t')
return;
}
// Search the non-empty previous line
while (prevLine >= 0 && _pEditView->getLineLength(prevLine) == 0)
prevLine--;
// Get previous line's Indent
if (prevLine >= 0)
{
indentAmountPrevLine = _pEditView->getLineIndent(prevLine);
auto startPos = _pEditView->execute(SCI_POSITIONFROMLINE, prevLine);
auto endPos = _pEditView->execute(SCI_GETLINEENDPOSITION, prevLine);
_pEditView->execute(SCI_SETSEARCHFLAGS, SCFIND_REGEXP | SCFIND_POSIX);
_pEditView->execute(SCI_SETTARGETRANGE, startPos, endPos);
const char braceExpr[] = "[ \t]*\\{.*";
int posFound = static_cast<int32_t>(_pEditView->execute(SCI_SEARCHINTARGET, strlen(braceExpr), reinterpret_cast<LPARAM>(braceExpr)));
if (posFound != -1 && posFound != -2)
{
int end = int(_pEditView->execute(SCI_GETTARGETEND));
if (end == endPos)
indentAmountPrevLine += tabWidth;
}
}
_pEditView->setLineIndent(curLine, indentAmountPrevLine);
}
else if (ch == '}')
{
// Look backward for the pair {
int startPos = static_cast<int32_t>(_pEditView->execute(SCI_GETCURRENTPOS));
if (startPos != 0)
startPos -= 1;
int posFound = findMachedBracePos(startPos - 1, 0, '{', '}');
// if no { found, do nothing
if (posFound == -1)
return;
// if { is in the same line, do nothing
int matchedPairLine = static_cast<int32_t>(_pEditView->execute(SCI_LINEFROMPOSITION, posFound));
if (matchedPairLine == curLine)
return;
// { is in another line, get its indentation
indentAmountPrevLine = _pEditView->getLineIndent(matchedPairLine);
// aligned } indent with {
_pEditView->setLineIndent(curLine, indentAmountPrevLine);
/*
// indent lines from { to }
for (int i = matchedPairLine + 1; i < curLine; ++i)
_pEditView->setLineIndent(i, indentAmountPrevLine + tabWidth);
*/
}
}
else // Basic indentation mode
{
if (((eolMode == SC_EOL_CRLF || eolMode == SC_EOL_LF) && ch == '\n') ||
(eolMode == SC_EOL_CR && ch == '\r'))
{
// Search the non-empty previous line
while (prevLine >= 0 && _pEditView->getLineLength(prevLine) == 0)
prevLine--;
if (prevLine >= 0)
{
indentAmountPrevLine = _pEditView->getLineIndent(prevLine);
}
if (indentAmountPrevLine > 0)
{
_pEditView->setLineIndent(curLine, indentAmountPrevLine);
}
}
}
}
BOOL Notepad_plus::processFindAccel(MSG *msg) const
{
if (not ::IsChild(_findReplaceDlg.getHSelf(), ::GetFocus()))
return FALSE;
return ::TranslateAccelerator(_findReplaceDlg.getHSelf(), _accelerator.getFindAccTable(), msg);
}
BOOL Notepad_plus::processIncrFindAccel(MSG *msg) const
{
if (not ::IsChild(_incrementFindDlg.getHSelf(), ::GetFocus()))
return FALSE;
return ::TranslateAccelerator(_incrementFindDlg.getHSelf(), _accelerator.getIncrFindAccTable(), msg);
}
void Notepad_plus::setLanguage(LangType langType)
{
//Add logic to prevent changing a language when a document is shared between two views
//If so, release one document
bool reset = false;
Document prev = 0;
if (bothActive())
{
if (_mainEditView.getCurrentBufferID() == _subEditView.getCurrentBufferID())
{
reset = true;
_subEditView.saveCurrentPos();
prev = _subEditView.execute(SCI_GETDOCPOINTER);
_subEditView.execute(SCI_SETDOCPOINTER, 0, 0);
}
}
if (reset)
{
_mainEditView.getCurrentBuffer()->setLangType(langType);
}
else
{
_pEditView->getCurrentBuffer()->setLangType(langType);
}
if (reset)
{
_subEditView.execute(SCI_SETDOCPOINTER, 0, prev);
_subEditView.restoreCurrentPos();
}
};
LangType Notepad_plus::menuID2LangType(int cmdID)
{
switch (cmdID)
{
case IDM_LANG_C :
return L_C;
case IDM_LANG_CPP :
return L_CPP;
case IDM_LANG_JAVA :
return L_JAVA;
case IDM_LANG_CS :
return L_CS;
case IDM_LANG_HTML :
return L_HTML;
case IDM_LANG_XML :
return L_XML;
case IDM_LANG_JS :
return L_JAVASCRIPT;
case IDM_LANG_JSON:
return L_JSON;
case IDM_LANG_PHP :
return L_PHP;
case IDM_LANG_ASP :
return L_ASP;
case IDM_LANG_JSP :
return L_JSP;
case IDM_LANG_CSS :
return L_CSS;
case IDM_LANG_LUA :
return L_LUA;
case IDM_LANG_PERL :
return L_PERL;
case IDM_LANG_PYTHON :
return L_PYTHON;
case IDM_LANG_PASCAL :
return L_PASCAL;
case IDM_LANG_BATCH :
return L_BATCH;
case IDM_LANG_OBJC :
return L_OBJC;
case IDM_LANG_VB :
return L_VB;
case IDM_LANG_SQL :
return L_SQL;
case IDM_LANG_ASCII :
return L_ASCII;
case IDM_LANG_TEXT :
return L_TEXT;
case IDM_LANG_RC :
return L_RC;
case IDM_LANG_MAKEFILE :
return L_MAKEFILE;
case IDM_LANG_INI :
return L_INI;
case IDM_LANG_TEX :
return L_TEX;
case IDM_LANG_FORTRAN :
return L_FORTRAN;
case IDM_LANG_FORTRAN_77 :
return L_FORTRAN_77;
case IDM_LANG_BASH :
return L_BASH;
case IDM_LANG_FLASH :
return L_FLASH;
case IDM_LANG_NSIS :
return L_NSIS;
case IDM_LANG_TCL :
return L_TCL;
case IDM_LANG_LISP :
return L_LISP;
case IDM_LANG_SCHEME :
return L_SCHEME;
case IDM_LANG_ASM :
return L_ASM;
case IDM_LANG_DIFF :
return L_DIFF;
case IDM_LANG_PROPS :
return L_PROPS;
case IDM_LANG_PS:
return L_PS;
case IDM_LANG_RUBY:
return L_RUBY;
case IDM_LANG_SMALLTALK:
return L_SMALLTALK;
case IDM_LANG_VHDL :
return L_VHDL;
case IDM_LANG_KIX :
return L_KIX;
case IDM_LANG_CAML :
return L_CAML;
case IDM_LANG_ADA :
return L_ADA;
case IDM_LANG_VERILOG :
return L_VERILOG;
case IDM_LANG_MATLAB :
return L_MATLAB;
case IDM_LANG_HASKELL :
return L_HASKELL;
case IDM_LANG_AU3 :
return L_AU3;
case IDM_LANG_INNO :
return L_INNO;
case IDM_LANG_CMAKE :
return L_CMAKE;
case IDM_LANG_YAML :
return L_YAML;
case IDM_LANG_COBOL :
return L_COBOL;
case IDM_LANG_D :
return L_D;
case IDM_LANG_GUI4CLI :
return L_GUI4CLI;
case IDM_LANG_POWERSHELL :
return L_POWERSHELL;
case IDM_LANG_R :
return L_R;
case IDM_LANG_COFFEESCRIPT :
return L_COFFEESCRIPT;
case IDM_LANG_BAANC:
return L_BAANC;
case IDM_LANG_SREC :
return L_SREC;
case IDM_LANG_IHEX :
return L_IHEX;
case IDM_LANG_TEHEX :
return L_TEHEX;
case IDM_LANG_SWIFT:
return L_SWIFT;
case IDM_LANG_ASN1 :
return L_ASN1;
case IDM_LANG_AVS :
return L_AVS;
case IDM_LANG_BLITZBASIC :
return L_BLITZBASIC;
case IDM_LANG_PUREBASIC :
return L_PUREBASIC;
case IDM_LANG_FREEBASIC :
return L_FREEBASIC;
case IDM_LANG_CSOUND :
return L_CSOUND;
case IDM_LANG_ERLANG :
return L_ERLANG;
case IDM_LANG_ESCRIPT :
return L_ESCRIPT;
case IDM_LANG_FORTH :
return L_FORTH;
case IDM_LANG_LATEX :
return L_LATEX;
case IDM_LANG_MMIXAL :
return L_MMIXAL;
case IDM_LANG_NIMROD :
return L_NIMROD;
case IDM_LANG_NNCRONTAB :
return L_NNCRONTAB;
case IDM_LANG_OSCRIPT :
return L_OSCRIPT;
case IDM_LANG_REBOL :
return L_REBOL;
case IDM_LANG_REGISTRY :
return L_REGISTRY;
case IDM_LANG_RUST :
return L_RUST;
case IDM_LANG_SPICE :
return L_SPICE;
case IDM_LANG_TXT2TAGS :
return L_TXT2TAGS;
case IDM_LANG_VISUALPROLOG:
return L_VISUALPROLOG;
case IDM_LANG_USER :
return L_USER;
default: {
if (cmdID >= IDM_LANG_USER && cmdID <= IDM_LANG_USER_LIMIT) {
return L_USER;
}
break; }
}
return L_EXTERNAL;
}
void Notepad_plus::setTitle()
{
const NppGUI & nppGUI = NppParameters::getInstance()->getNppGUI();
//Get the buffer
Buffer * buf = _pEditView->getCurrentBuffer();
generic_string result = TEXT("");
if (buf->isDirty())
{
result += TEXT("*");
}
if (nppGUI._shortTitlebar)
{
result += buf->getFileName();
}
else
{
result += buf->getFullPathName();
}
result += TEXT(" - ");
result += _pPublicInterface->getClassName();
if (_isAdministrator)
result += TEXT(" [Administrator]");
::SendMessage(_pPublicInterface->getHSelf(), WM_SETTEXT, 0, reinterpret_cast<LPARAM>(result.c_str()));
}
void Notepad_plus::activateNextDoc(bool direction)
{
int nbDoc = static_cast<int32_t>(_pDocTab->nbItem());
int curIndex = _pDocTab->getCurrentTabIndex();
curIndex += (direction == dirUp)?-1:1;
if (curIndex >= nbDoc)
{
if (viewVisible(otherView()))
switchEditViewTo(otherView());
curIndex = 0;
}
else if (curIndex < 0)
{
if (viewVisible(otherView()))
{
switchEditViewTo(otherView());
nbDoc = static_cast<int32_t>(_pDocTab->nbItem());
}
curIndex = nbDoc - 1;
}
BufferID id = _pDocTab->getBufferByIndex(curIndex);
activateBuffer(id, currentView());
}
void Notepad_plus::activateDoc(size_t pos)
{
size_t nbDoc = _pDocTab->nbItem();
if (pos == static_cast<size_t>(_pDocTab->getCurrentTabIndex()))
{
Buffer * buf = _pEditView->getCurrentBuffer();
buf->increaseRecentTag();
return;
}
if (pos < nbDoc)
{
BufferID id = _pDocTab->getBufferByIndex(pos);
activateBuffer(id, currentView());
}
}
static const char utflen[] = {1,1,2,3};
size_t Notepad_plus::getSelectedCharNumber(UniMode u)
{
size_t result = 0;
int numSel = static_cast<int32_t>(_pEditView->execute(SCI_GETSELECTIONS));
if (u == uniUTF8 || u == uniCookie)
{
for (int i=0; i < numSel; ++i)
{
size_t line1 = _pEditView->execute(SCI_LINEFROMPOSITION, _pEditView->execute(SCI_GETSELECTIONNSTART, i));
size_t line2 = _pEditView->execute(SCI_LINEFROMPOSITION, _pEditView->execute(SCI_GETSELECTIONNEND, i));
for (size_t j = line1; j <= line2; ++j)
{
size_t stpos = _pEditView->execute(SCI_GETLINESELSTARTPOSITION, j);
if (stpos != INVALID_POSITION)
{
size_t endpos = _pEditView->execute(SCI_GETLINESELENDPOSITION, j);
for (size_t pos = stpos; pos < endpos; ++pos)
{
unsigned char c = 0xf0 & static_cast<unsigned char>(_pEditView->execute(SCI_GETCHARAT, pos));
if (c >= 0xc0)
pos += utflen[(c & 0x30) >> 4];
++result;
}
}
}
}
}
else
{
for (int i=0; i < numSel; ++i)
{
size_t stpos = _pEditView->execute(SCI_GETSELECTIONNSTART, i);
size_t endpos = _pEditView->execute(SCI_GETSELECTIONNEND, i);
result += (endpos - stpos);
size_t line1 = _pEditView->execute(SCI_LINEFROMPOSITION, stpos);
size_t line2 = _pEditView->execute(SCI_LINEFROMPOSITION, endpos);
line2 -= line1;
if (_pEditView->execute(SCI_GETEOLMODE) == SC_EOL_CRLF) line2 *= 2;
result -= line2;
}
if (u != uni8Bit && u != uni7Bit) result *= 2;
}
return result;
}
#ifdef _OPENMP
#include <omp.h>
#endif
static inline size_t countUtf8Characters(unsigned char *buf, size_t pos, size_t endpos)
{
size_t result = 0;
while(pos < endpos)
{
unsigned char c = buf[pos++];
if ((c&0xc0) == 0x80 // do not count unexpected continuation bytes (this handles the case where an UTF-8 character is split in the middle)
|| c == '\n' || c == '\r') continue; // do not count end of lines
if (c >= 0xc0)
pos += utflen[(c & 0x30) >> 4];
++result;
}
return result;
}
size_t Notepad_plus::getCurrentDocCharCount(UniMode u)
{
if (u != uniUTF8 && u != uniCookie)
{
size_t numLines = _pEditView->execute(SCI_GETLINECOUNT);
auto result = _pEditView->execute(SCI_GETLENGTH);
size_t lines = numLines==0?0:numLines-1;
if (_pEditView->execute(SCI_GETEOLMODE) == SC_EOL_CRLF) lines *= 2;
result -= lines;
return (result < 0) ? 0 : result;
}
else
{
// Note that counting is not well defined for invalid UTF-8 characters.
// This method is O(filelength) regardless of the number of characters we count (due to SCI_GETCHARACTERPOINTER);
// it would not be appropriate for counting characters in a small selection.
size_t result = 0;
size_t endpos = _pEditView->execute(SCI_GETLENGTH);
unsigned char* buf = (unsigned char*)_pEditView->execute(SCI_GETCHARACTERPOINTER); // Scintilla doc said the pointer can be invalidated by any other "execute"
#ifdef _OPENMP // parallel counting of characters with OpenMP
if (endpos > 50000) // starting threads takes time; for small files it is better to simply count in one thread
{
#pragma omp parallel reduction(+: result)
{
// split in chunks of same size (except last chunk if it's not evenly divisible)
unsigned int num_threads = omp_get_num_threads();
unsigned int thread_num = omp_get_thread_num();
size_t chunk_size = endpos/num_threads;
size_t pos = chunk_size*thread_num;
size_t endpos_local = (thread_num == num_threads-1) ? endpos : pos+chunk_size;
result = countUtf8Characters(buf, pos, endpos_local);
}
}
else
#endif
{
result = countUtf8Characters(buf, 0, endpos);
}
return result;
}
}
bool Notepad_plus::isFormatUnicode(UniMode u)
{
return (u != uni8Bit && u != uni7Bit && u != uniUTF8 && u != uniCookie);
}
int Notepad_plus::getBOMSize(UniMode u)
{
switch(u)
{
case uni16LE:
case uni16BE:
return 2;
case uniUTF8:
return 3;
default:
return 0;
}
}
size_t Notepad_plus::getSelectedAreas()
{
size_t numSel = _pEditView->execute(SCI_GETSELECTIONS);
if (numSel == 1) // either 0 or 1 selection
return (_pEditView->execute(SCI_GETSELECTIONNSTART, 0) == _pEditView->execute(SCI_GETSELECTIONNEND, 0)) ? 0 : 1;
return (_pEditView->execute(SCI_SELECTIONISRECTANGLE)) ? 1 : numSel;
}
size_t Notepad_plus::getSelectedBytes()
{
size_t numSel = _pEditView->execute(SCI_GETSELECTIONS);
size_t result = 0;
for (size_t i = 0; i < numSel; ++i)
result += (_pEditView->execute(SCI_GETSELECTIONNEND, i) - _pEditView->execute(SCI_GETSELECTIONNSTART, i));
return result;
}
int Notepad_plus::wordCount()
{
FindOption env;
env._str2Search = TEXT("[^ \\\\.,;:!?()+\\r\\n\\-\\*/=\\]\\[{}&~\"'`|@$%<>\\^]+");
env._searchType = FindRegex;
return _findReplaceDlg.processAll(ProcessCountAll, &env, true);
}
void Notepad_plus::updateStatusBar()
{
TCHAR strLnCol[128];
TCHAR strSel[64];
int selByte = 0;
int selLine = 0;
_pEditView->getSelectedCount(selByte, selLine);
long selected_length = _pEditView->getUnicodeSelectedLength();
if (selected_length != -1)
wsprintf(strSel, TEXT("Sel : %s | %s"), commafyInt(selected_length).c_str(), commafyInt(selLine).c_str());
else
wsprintf(strSel, TEXT("Sel : %s"), TEXT("N/A"));
wsprintf(strLnCol, TEXT("Ln : %s Col : %s %s"),
commafyInt(_pEditView->getCurrentLineNumber() + 1).c_str(),
commafyInt(_pEditView->getCurrentColumnNumber() + 1).c_str(),
strSel);
_statusBar.setText(strLnCol, STATUSBAR_CUR_POS);
TCHAR strDocLen[256];
wsprintf(strDocLen, TEXT("length : %s lines : %s"),
commafyInt(_pEditView->getCurrentDocLen()).c_str(),
commafyInt(_pEditView->execute(SCI_GETLINECOUNT)).c_str());
_statusBar.setText(strDocLen, STATUSBAR_DOC_SIZE);
_statusBar.setText(_pEditView->execute(SCI_GETOVERTYPE) ? TEXT("OVR") : TEXT("INS"), STATUSBAR_TYPING_MODE);
}
void Notepad_plus::dropFiles(HDROP hdrop)
{
if (hdrop)
{
// Determinate in which view the file(s) is (are) dropped
POINT p;
::DragQueryPoint(hdrop, &p);
HWND hWin = ::RealChildWindowFromPoint(_pPublicInterface->getHSelf(), p);
if (!hWin) return;
if ((_subEditView.getHSelf() == hWin) || (_subDocTab.getHSelf() == hWin))
switchEditViewTo(SUB_VIEW);
else
switchEditViewTo(MAIN_VIEW);
int filesDropped = ::DragQueryFile(hdrop, 0xffffffff, NULL, 0);
BufferID lastOpened = BUFFER_INVALID;
vector<generic_string> folderPaths;
vector<generic_string> filePaths;
for (int i = 0; i < filesDropped; ++i)
{
TCHAR pathDropped[MAX_PATH];
::DragQueryFile(hdrop, i, pathDropped, MAX_PATH);
if (::PathIsDirectory(pathDropped))
{
size_t len = lstrlen(pathDropped);
if (len > 0 && pathDropped[len - 1] != TCHAR('\\'))
{
pathDropped[len] = TCHAR('\\');
pathDropped[len + 1] = TCHAR('\0');
}
folderPaths.push_back(pathDropped);
}
else
{
filePaths.push_back(pathDropped);
}
}
NppParameters *pNppParam = NppParameters::getInstance();
bool isOldMode = pNppParam->getNppGUI()._isFolderDroppedOpenFiles;
if (isOldMode || folderPaths.size() == 0) // old mode or new mode + only files
{
BufferID lastOpened = BUFFER_INVALID;
for (int i = 0; i < filesDropped; ++i)
{
TCHAR pathDropped[MAX_PATH];
::DragQueryFile(hdrop, i, pathDropped, MAX_PATH);
BufferID test = doOpen(pathDropped);
if (test != BUFFER_INVALID)
lastOpened = test;
}
if (lastOpened != BUFFER_INVALID)
{
switchToFile(lastOpened);
}
}
else if (not isOldMode && (folderPaths.size() != 0 && filePaths.size() != 0)) // new mode && both folders & files
{
// display error & do nothing
_nativeLangSpeaker.messageBox("DroppingFolderAsProjectModeWarning",
_pPublicInterface->getHSelf(),
TEXT("You can only drop files or folders but not both, because you're in dropping Folder as Project mode.\ryou have to enable \"Open all files of folder instead of launching Folder as Workspace on folder dropping\" in \"Default Directory\" section of Preferences dialog to make this operation work."),
TEXT("Invalid action"),
MB_OK | MB_APPLMODAL);
}
else if (not isOldMode && (folderPaths.size() != 0 && filePaths.size() == 0)) // new mode && only folders
{
// process new mode
launchFileBrowser(folderPaths);
}
if (lastOpened != BUFFER_INVALID)
{
switchToFile(lastOpened);
}
::DragFinish(hdrop);
// Put Notepad_plus to forefront
// May not work for Win2k, but OK for lower versions
// Note: how to drop a file to an iconic window?
// Actually, it is the Send To command that generates a drop.
if (::IsIconic(_pPublicInterface->getHSelf()))
{
::ShowWindow(_pPublicInterface->getHSelf(), SW_RESTORE);
}
::SetForegroundWindow(_pPublicInterface->getHSelf());
}
}
void Notepad_plus::checkModifiedDocument()
{
//this will trigger buffer updates. If the status changes, Notepad++ will be informed and can do its magic
MainFileManager->checkFilesystemChanges();
}
void Notepad_plus::getMainClientRect(RECT &rc) const
{
_pPublicInterface->getClientRect(rc);
rc.top += _rebarTop.getHeight();
rc.bottom -= rc.top + _rebarBottom.getHeight() + _statusBar.getHeight();
}
void Notepad_plus::showView(int whichOne)
{
if (viewVisible(whichOne)) //no use making visible view visible
return;
if (_mainWindowStatus & WindowUserActive) {
_pMainSplitter->setWin0(&_subSplitter);
_pMainWindow = _pMainSplitter;
} else {
_pMainWindow = &_subSplitter;
}
if (whichOne == MAIN_VIEW) {
_mainEditView.display(true);
_mainDocTab.display(true);
} else if (whichOne == SUB_VIEW) {
_subEditView.display(true);
_subDocTab.display(true);
}
_pMainWindow->display(true);
_mainWindowStatus |= (whichOne==MAIN_VIEW)?WindowMainActive:WindowSubActive;
//Send sizing info to make windows fit
::SendMessage(_pPublicInterface->getHSelf(), WM_SIZE, 0, 0);
}
bool Notepad_plus::viewVisible(int whichOne) {
int viewToCheck = (whichOne == SUB_VIEW?WindowSubActive:WindowMainActive);
return (_mainWindowStatus & viewToCheck) != 0;
}
void Notepad_plus::hideCurrentView()
{
hideView(currentView());
}
void Notepad_plus::hideView(int whichOne)
{
if (!(bothActive())) //cannot close if not both views visible
return;
Window * windowToSet = (whichOne == MAIN_VIEW)?&_subDocTab:&_mainDocTab;
if (_mainWindowStatus & WindowUserActive)
{
_pMainSplitter->setWin0(windowToSet);
}
else
{
// otherwise the main window is the spltter container that we just created
_pMainWindow = windowToSet;
}
_subSplitter.display(false); //hide splitter
//hide scintilla and doctab
if (whichOne == MAIN_VIEW) {
_mainEditView.display(false);
_mainDocTab.display(false);
} else if (whichOne == SUB_VIEW) {
_subEditView.display(false);
_subDocTab.display(false);
}
// resize the main window
::SendMessage(_pPublicInterface->getHSelf(), WM_SIZE, 0, 0);
switchEditViewTo(otherFromView(whichOne));
int viewToDisable = (whichOne == SUB_VIEW?WindowSubActive:WindowMainActive);
_mainWindowStatus &= ~viewToDisable;
}
bool Notepad_plus::loadStyles()
{
NppParameters *pNppParam = NppParameters::getInstance();
return pNppParam->reloadStylers();
}
bool Notepad_plus::canHideView(int whichOne)
{
if (!viewVisible(whichOne))
return false; //cannot hide hidden view
if (!bothActive())
return false; //cannot hide only window
DocTabView * tabToCheck = (whichOne == MAIN_VIEW)?&_mainDocTab:&_subDocTab;
Buffer * buf = MainFileManager->getBufferByID(tabToCheck->getBufferByIndex(0));
bool canHide = ((tabToCheck->nbItem() == 1) && !buf->isDirty() && buf->isUntitled());
return canHide;
}
bool Notepad_plus::isEmpty()
{
if (bothActive()) return false;
DocTabView * tabToCheck = (_mainWindowStatus & WindowMainActive) ? &_mainDocTab : &_subDocTab;
Buffer * buf = MainFileManager->getBufferByID(tabToCheck->getBufferByIndex(0));
bool isEmpty = ((tabToCheck->nbItem() == 1) && !buf->isDirty() && buf->isUntitled());
return isEmpty;
}
void Notepad_plus::loadBufferIntoView(BufferID id, int whichOne, bool dontClose)
{
DocTabView * tabToOpen = (whichOne == MAIN_VIEW)?&_mainDocTab:&_subDocTab;
ScintillaEditView * viewToOpen = (whichOne == MAIN_VIEW)?&_mainEditView:&_subEditView;
//check if buffer exists
int index = tabToOpen->getIndexByBuffer(id);
if (index != -1) //already open, done
return;
BufferID idToClose = BUFFER_INVALID;
//Check if the tab has a single clean buffer. Close it if so
if (!dontClose && tabToOpen->nbItem() == 1)
{
idToClose = tabToOpen->getBufferByIndex(0);
Buffer * buf = MainFileManager->getBufferByID(idToClose);
if (buf->isDirty() || !buf->isUntitled())
{
idToClose = BUFFER_INVALID;
}
}
MainFileManager->addBufferReference(id, viewToOpen);
//close clean doc. Use special logic to prevent flicker of tab showing then hiding
if (idToClose != BUFFER_INVALID)
{
tabToOpen->setBuffer(0, id); //index 0 since only one open
activateBuffer(id, whichOne); //activate. DocTab already activated but not a problem
MainFileManager->closeBuffer(idToClose, viewToOpen); //delete the buffer
if (_pFileSwitcherPanel)
_pFileSwitcherPanel->closeItem(idToClose, whichOne);
}
else
{
tabToOpen->addBuffer(id);
}
}
bool Notepad_plus::removeBufferFromView(BufferID id, int whichOne)
{
DocTabView * tabToClose = (whichOne == MAIN_VIEW) ? &_mainDocTab : &_subDocTab;
ScintillaEditView * viewToClose = (whichOne == MAIN_VIEW) ? &_mainEditView : &_subEditView;
//check if buffer exists
int index = tabToClose->getIndexByBuffer(id);
if (index == -1) //doesn't exist, done
return false;
Buffer * buf = MainFileManager->getBufferByID(id);
//Cannot close doc if last and clean
if (tabToClose->nbItem() == 1)
{
if (!buf->isDirty() && buf->isUntitled())
{
return false;
}
}
int active = tabToClose->getCurrentTabIndex();
if (active == index) //need an alternative (close real doc, put empty one back)
{
if (tabToClose->nbItem() == 1) //need alternative doc, add new one. Use special logic to prevent flicker of adding new tab then closing other
{
BufferID newID = MainFileManager->newEmptyDocument();
MainFileManager->addBufferReference(newID, viewToClose);
tabToClose->setBuffer(0, newID); //can safely use id 0, last (only) tab open
activateBuffer(newID, whichOne); //activate. DocTab already activated but not a problem
}
else
{
int toActivate = 0;
//activate next doc, otherwise prev if not possible
if (size_t(active) == tabToClose->nbItem() - 1) //prev
{
toActivate = active - 1;
}
else
{
toActivate = active; //activate the 'active' index. Since we remove the tab first, the indices shift (on the right side)
}
tabToClose->deletItemAt((size_t)index); //delete first
_isFolding = true; // So we can ignore events while folding is taking place
activateBuffer(tabToClose->getBufferByIndex(toActivate), whichOne); //then activate. The prevent jumpy tab behaviour
_isFolding = false;
}
}
else
{
tabToClose->deletItemAt((size_t)index);
}
MainFileManager->closeBuffer(id, viewToClose);
return true;
}
int Notepad_plus::switchEditViewTo(int gid)
{
if (currentView() == gid) { //make sure focus is ok, then leave
_pEditView->getFocus(); //set the focus
return gid;
}
if (!viewVisible(gid))
return currentView(); //cannot activate invisible view
int oldView = currentView();
int newView = otherView();
_activeView = newView;
//Good old switcheroo
std::swap(_pDocTab, _pNonDocTab);
std::swap(_pEditView, _pNonEditView);
_pEditView->beSwitched();
_pEditView->getFocus(); //set the focus
if (_pDocMap)
{
_pDocMap->initWrapMap();
}
if (NppParameters::getInstance()->getNppGUI().isSnapshotMode())
{
// Before switching off, synchronize backup file
MainFileManager->backupCurrentBuffer();
}
notifyBufferActivated(_pEditView->getCurrentBufferID(), currentView());
return oldView;
}
void Notepad_plus::dockUserDlg()
{
if (!_pMainSplitter)
{
_pMainSplitter = new SplitterContainer;
_pMainSplitter->init(_pPublicInterface->getHinst(), _pPublicInterface->getHSelf());
Window *pWindow;
if (_mainWindowStatus & (WindowMainActive | WindowSubActive))
pWindow = &_subSplitter;
else
pWindow = _pDocTab;
_pMainSplitter->create(pWindow, ScintillaEditView::getUserDefineDlg(), 8, SplitterMode::RIGHT_FIX, 45);
}
if (bothActive())
_pMainSplitter->setWin0(&_subSplitter);
else
_pMainSplitter->setWin0(_pDocTab);
_pMainSplitter->display();
_mainWindowStatus |= WindowUserActive;
_pMainWindow = _pMainSplitter;
::SendMessage(_pPublicInterface->getHSelf(), WM_SIZE, 0, 0);
}
void Notepad_plus::undockUserDlg()
{
// a cause de surchargement de "display"
::ShowWindow(_pMainSplitter->getHSelf(), SW_HIDE);
if (bothActive())
_pMainWindow = &_subSplitter;
else
_pMainWindow = _pDocTab;
::SendMessage(_pPublicInterface->getHSelf(), WM_SIZE, 0, 0);
_mainWindowStatus &= ~WindowUserActive;
(ScintillaEditView::getUserDefineDlg())->display();
}
void Notepad_plus::docOpenInNewInstance(FileTransferMode mode, int x, int y)
{
BufferID bufferID = _pEditView->getCurrentBufferID();
Buffer * buf = MainFileManager->getBufferByID(bufferID);
if (buf->isUntitled() || buf->isDirty())
return;
TCHAR nppName[MAX_PATH];
::GetModuleFileName(NULL, nppName, MAX_PATH);
generic_string command = TEXT("\"");
command += nppName;
command += TEXT("\"");
command += TEXT(" \"$(FULL_CURRENT_PATH)\" -multiInst -nosession");
if (x) {
TCHAR pX[10];
generic_itoa(x, pX, 10);
command += TEXT(" -x");
command += pX;
}
if (y) {
TCHAR pY[10];
generic_itoa(y, pY, 10);
command += TEXT(" -y");
command += pY;
}
command += TEXT(" -l");
command += ScintillaEditView::langNames[buf->getLangType()].lexerName;
command += TEXT(" -n");
command += to_wstring(_pEditView->getCurrentLineNumber() + 1);
command += TEXT(" -c");
command += to_wstring(_pEditView->getCurrentColumnNumber() + 1);
Command cmd(command);
cmd.run(_pPublicInterface->getHSelf());
if (mode == TransferMove)
{
doClose(bufferID, currentView());
if (noOpenedDoc())
::SendMessage(_pPublicInterface->getHSelf(), WM_CLOSE, 0, 0);
}
}
void Notepad_plus::docGotoAnotherEditView(FileTransferMode mode)
{
// Test if it's only doc to transfer on the hidden view
// If so then do nothing
if (mode == TransferMove)
{
if (_pDocTab->nbItem() == 1)
{
ScintillaEditView *pOtherView = NULL;
if (_pEditView == &_mainEditView)
{
pOtherView = &_subEditView;
}
else if (_pEditView == &_subEditView)
{
pOtherView = &_mainEditView;
}
else
return;
if (!pOtherView->isVisible())
return;
}
}
//First put the doc in the other view if not present (if it is, activate it).
//Then if needed close in the original tab
BufferID current = _pEditView->getCurrentBufferID();
int viewToGo = otherView();
int indexFound = _pNonDocTab->getIndexByBuffer(current);
if (indexFound != -1) //activate it
{
activateBuffer(current, otherView());
}
else //open the document, also copying the position
{
// If both the views are visible then first save the position of non-edit view
// So that moving document between views does not lose caret position
// How it works =>
// non-edit view becomes edit view as document from edit view is sent to non edit view