diff --git a/.github/workflows/CI_build.yml b/.github/workflows/CI_build.yml index 555720a0..cc41accb 100644 --- a/.github/workflows/CI_build.yml +++ b/.github/workflows/CI_build.yml @@ -13,7 +13,7 @@ jobs: steps: - name: Checkout repo - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: submodules: 'true' diff --git a/.github/workflows/msvc_analysis.yml b/.github/workflows/msvc_analysis.yml index a2fd03c6..be0653ed 100644 --- a/.github/workflows/msvc_analysis.yml +++ b/.github/workflows/msvc_analysis.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: submodules: recursive diff --git a/NppPlugin/include/Common.h b/NppPlugin/include/Common.h index 7c624ab0..782ec971 100644 --- a/NppPlugin/include/Common.h +++ b/NppPlugin/include/Common.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -168,6 +169,7 @@ std::wstring stringTakeWhileAdmissable(const std::wstring& input, const std::wst double stodLocale(const std::wstring& str, _locale_t loc, size_t* idx = NULL); bool str2Clipboard(const std::wstring &str2cpy, HWND hwnd); +std::wstring strFromClipboard(); class Buffer; bool buf2Clipboard(const std::vector& buffers, bool isFullPath, HWND hwnd); @@ -296,3 +298,45 @@ bool doesPathExist(const wchar_t* path, DWORD milliSec2wait = 0, bool* isTimeout bool isWindowVisibleOnAnyMonitor(const RECT& rectWndIn); bool isCoreWindows(); + + +#define IDT_HIDE_TOOLTIP 1001 + +class ControlInfoTip final +{ +public: + ControlInfoTip() {}; + ~ControlInfoTip() { + if (_hWndInfoTip) { + hide(); + } + }; + bool init(HINSTANCE hInst, HWND ctrl2attached, HWND ctrl2attachedParent, const std::wstring& tipStr, bool isRTL, unsigned int remainTimeMillisecond = 0, int maxWidth = 200); // remainTimeMillisecond = 0: no timeout + + bool isValid() const { + return _hWndInfoTip != nullptr; + }; + + HWND getTipHandle() const { + return _hWndInfoTip; + }; + + enum showPosition {beginning, middle, end}; + void show(showPosition pos = middle) const; + + void hide(); + +private: + HWND _hWndInfoTip = nullptr; + TOOLINFO _toolInfo = {}; + + ControlInfoTip(const ControlInfoTip&) = delete; + ControlInfoTip& operator=(const ControlInfoTip&) = delete; +}; + + +#define NPP_UAC_SAVE_SIGN L"#UAC-SAVE#" +#define NPP_UAC_SETFILEATTRIBUTES_SIGN L"#UAC-SETFILEATTRIBUTES#" +#define NPP_UAC_MOVEFILE_SIGN L"#UAC-MOVEFILE#" +#define NPP_UAC_CREATEEMPTYFILE_SIGN L"#UAC-CREATEEMPTYFILE#" +DWORD invokeNppUacOp(std::wstring& strCmdLineParams); diff --git a/NppPlugin/include/Notepad_plus_msgs.h b/NppPlugin/include/Notepad_plus_msgs.h index 6dcb8cb7..03e1cbff 100644 --- a/NppPlugin/include/Notepad_plus_msgs.h +++ b/NppPlugin/include/Notepad_plus_msgs.h @@ -1,5 +1,5 @@ // This file is part of Notepad++ project -// Copyright (C)2024 Don HO +// Copyright (C)2025 Don HO // 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 @@ -26,7 +26,7 @@ enum LangType {L_TEXT, L_PHP , L_C, L_CPP, L_CS, L_OBJC, L_JAVA, L_RC,\ L_HTML, L_XML, L_MAKEFILE, L_PASCAL, L_BATCH, L_INI, L_ASCII, L_USER,\ - L_ASP, L_SQL, L_VB, L_JS, L_CSS, L_PERL, L_PYTHON, L_LUA, \ + L_ASP, L_SQL, L_VB, L_JS_EMBEDDED, L_CSS, L_PERL, L_PYTHON, L_LUA, \ L_TEX, L_FORTRAN, L_BASH, L_FLASH, L_NSIS, L_TCL, L_LISP, L_SCHEME,\ L_ASM, L_DIFF, L_PROPS, L_PS, L_RUBY, L_SMALLTALK, L_VHDL, L_KIX, L_AU3,\ L_CAML, L_ADA, L_VERILOG, L_MATLAB, L_HASKELL, L_INNO, L_SEARCHRESULT,\ @@ -39,7 +39,7 @@ enum LangType {L_TEXT, L_PHP , L_C, L_CPP, L_CS, L_OBJC, L_JAVA, L_RC,\ L_REGISTRY, L_RUST, L_SPICE, L_TXT2TAGS, L_VISUALPROLOG,\ L_TYPESCRIPT, L_JSON5, L_MSSQL, L_GDSCRIPT, L_HOLLYWOOD,\ L_GOLANG, L_RAKU, L_TOML, L_SAS, L_ERRORLIST, \ - // Don't use L_JS, use L_JAVASCRIPT instead + // Don't use L_JS_EMBEDDED, use L_JAVASCRIPT instead // The end of enumerated language type, so it should be always at the end L_EXTERNAL}; enum class ExternalLexerAutoIndentMode { Standard, C_Like, Custom }; @@ -1025,7 +1025,20 @@ enum Platform { PF_UNKNOWN, PF_X86, PF_X64, PF_IA64, PF_ARM64 }; // Return toolbar icon set choice as an integer value. Here are 5 possible values: // 0 (Fluent UI: small), 1 (Fluent UI: large), 2 (Filled Fluent UI: small), 3 (Filled Fluent UI: large) and 4 (Standard icons: small). - // For RUNCOMMAND_USER + #define NPPM_GETNPPSETTINGSDIRPATH (NPPMSG + 119) + // int NPPM_GETNPPSETTINGSDIRPATH(size_t strLen, wchar_t *settingsDirPath) + // Get path for the active Notepad++ settings: it will use -settingsDir path if that's defined; if not, it will use Cloud directory if that's defined; + // if not, it will use the AppData settings directory, or finally the installation path. This allows plugins to have one interface to find out + // where the active Notepad++ settings are stored, whichever location they are currently set to. + // wParam[in]: strLen - size of allocated buffer "settingsDirPath" + // lParam[out]: settingsDirPath - Users should call it with settingsDirPath be NULL to get the required number of wchar_t (not including the terminating nul character), + // allocate settingsDirPath buffer with the return value + 1, then call it again to get the path. + // Returns the number of wchar_t copied/to copy. If the return value is 0, then the "strLen" is not enough to copy the path, or the settings path could not be determined. + // + // Note: This message is for the active Notepad++ configuration location. If you are looking for the settings directory for plugins (...\Plugins\Config\), + // use NPPM_GETPLUGINSCONFIGDIR instead. + +// For RUNCOMMAND_USER #define VAR_NOT_RECOGNIZED 0 #define FULL_CURRENT_PATH 1 #define CURRENT_DIRECTORY 2 @@ -1224,10 +1237,28 @@ enum Platform { PF_UNKNOWN, PF_X86, PF_X64, PF_IA64, PF_ARM64 }; //scnNotification->nmhdr.hwndFrom = hwndNpp; //scnNotification->nmhdr.idFrom = 0; - #define NPPN_CMDLINEPLUGINMSG (NPPN_FIRST + 28) // To notify plugins that the new argument for plugins (via '-pluginMessage="YOUR_PLUGIN_ARGUMENT"' in command line) is available + #define NPPN_CMDLINEPLUGINMSG (NPPN_FIRST + 28) // To notify plugins that there are plugin arguments pluginMessage (wchar_t*) is available //scnNotification->nmhdr.code = NPPN_CMDLINEPLUGINMSG; //scnNotification->nmhdr.hwndFrom = hwndNpp; //scnNotification->nmhdr.idFrom = pluginMessage; //where pluginMessage is pointer of type wchar_t + // + // User can pass arguments to plugins via command line argument using: + // -pluginMessage="PLUGIN1_ARG1=V1;PLUGIN1_ARG2=V2;PLUGIN2_ARG=V;..." + // + // The full string (wchar_t*) will be delivered to all plugins via the NPPN_CMDLINEPLUGINMSG notification. Each plugins can parse and extract the arguments relevant to itself. + // + // To avoid the collisions among plugins, the following protocol should be followed: + // 1. Each plugin must use its unique namespace (its folder name in plugins directory) as a prefix for its argument names. + // 2. The symbol ';' must be used as the delimiter between arguments when there are 2 or more arguments in the pluginMessage string. + // 3. The symbol '=' must be used as delimiter between argument names and their values. + // + // Example (via the command line): + // -pluginMessage="NppExecScriptPath=C:\Program Files\Notepad++\plugins\NppExec\init.py;NppExecArg2=arg2Value;mimeToolsSettings=disable;pluginYInfo=show" + // + // Interpretation: + // - Plugin "NppExec" processes: NppExecScriptPath=C:\Program Files\Notepad++\plugins\NppExec\init.py & NppExecArg2=arg2Value + // - Plugin "mimeTools" processes: mimeToolsSettings=disable + // - Plugin "pluginY" processes: pluginYInfo=show #define NPPN_EXTERNALLEXERBUFFER (NPPN_FIRST + 29) // To notify lexer plugins that the buffer (in idFrom) is just applied to a external lexer //scnNotification->nmhdr.code = NPPN_EXTERNALLEXERBUFFER; diff --git a/NppPlugin/include/menuCmdID.h b/NppPlugin/include/menuCmdID.h index cea3a7c7..137329dd 100644 --- a/NppPlugin/include/menuCmdID.h +++ b/NppPlugin/include/menuCmdID.h @@ -594,10 +594,10 @@ #define IDM_SETTING (IDM + 8000) -// #define IDM_SETTING_TAB_SIZE (IDM_SETTING + 1) -// #define IDM_SETTING_TAB_REPLACESPACE (IDM_SETTING + 2) -// #define IDM_SETTING_HISTORY_SIZE (IDM_SETTING + 3) -// #define IDM_SETTING_EDGE_SIZE (IDM_SETTING + 4) +// #define IDM_SETTING_TAB_SIZE (IDM_SETTING + 1) +// #define IDM_SETTING_TAB_REPLACESPACE (IDM_SETTING + 2) +// #define IDM_SETTING_HISTORY_SIZE (IDM_SETTING + 3) +// #define IDM_SETTING_EDGE_SIZE (IDM_SETTING + 4) #define IDM_SETTING_IMPORTPLUGIN (IDM_SETTING + 5) #define IDM_SETTING_IMPORTSTYLETHEMES (IDM_SETTING + 6) #define IDM_SETTING_TRAYICON (IDM_SETTING + 8) @@ -643,6 +643,8 @@ #define IDM_WINDOW_SORT_FT_DSC (IDR_WINDOWS_MENU + 7) #define IDM_WINDOW_SORT_FS_ASC (IDR_WINDOWS_MENU + 8) #define IDM_WINDOW_SORT_FS_DSC (IDR_WINDOWS_MENU + 9) + #define IDM_WINDOW_SORT_FD_ASC (IDR_WINDOWS_MENU + 10) + #define IDM_WINDOW_SORT_FD_DSC (IDR_WINDOWS_MENU + 11) #define IDM_WINDOW_MRU_FIRST (IDR_WINDOWS_MENU + 20) #define IDM_WINDOW_MRU_LIMIT (IDR_WINDOWS_MENU + 59) #define IDM_WINDOW_COPY_NAME (IDM_WINDOW_MRU_LIMIT + 1) diff --git a/NppPlugin/src/NppDarkModeDummy.cpp b/NppPlugin/src/NppDarkModeDummy.cpp index f719f69f..63470b70 100644 --- a/NppPlugin/src/NppDarkModeDummy.cpp +++ b/NppPlugin/src/NppDarkModeDummy.cpp @@ -1,16 +1,54 @@ #include "stdafx.h" //ADDED BY PYTHONSCRIPT #include "NppDarkMode.h" +#include "PluginInterface.h" + +//extern NppData nppData; + +static constexpr COLORREF HEXRGB(DWORD rrggbb) { + // from 0xRRGGBB like natural #RRGGBB + // to the little-endian 0xBBGGRR + return + ((rrggbb & 0xFF0000) >> 16) | + ((rrggbb & 0x00FF00)) | + ((rrggbb & 0x0000FF) << 16); +} + namespace NppDarkMode { bool isEnabled() { - return false; + return false; // ::SendMessage(nppData._nppHandle, NPPM_ISDARKMODEENABLED, 0, 0); } HBRUSH getDlgBackgroundBrush() { - return 0; + return ::CreateSolidBrush(HEXRGB(0x202020)); + } + + HBRUSH getDarkerBackgroundBrush() + { + return ::CreateSolidBrush(HEXRGB(0x202020)); + } + + COLORREF getTextColor() + { + return HEXRGB(0xE0E0E0); + } + + COLORREF getDarkerTextColor() + { + return HEXRGB(0xC0C0C0); + } + + COLORREF getLinkTextColor() + { + return HEXRGB(0xFFFF00); + } + + COLORREF getDarkerBackgroundColor() + { + return HEXRGB(0x202020); } void setDarkTitleBar(HWND /*hwnd*/) @@ -19,6 +57,19 @@ namespace NppDarkMode bool isWindows10() { - return true; + return false; + } + + LRESULT onCtlColorDarker(HDC hdc) + { + if (!NppDarkMode::isEnabled()) + { + return FALSE; + } + + ::SetTextColor(hdc, NppDarkMode::getTextColor()); + ::SetBkColor(hdc, NppDarkMode::getDarkerBackgroundColor()); + return reinterpret_cast(NppDarkMode::getDarkerBackgroundBrush()); } + } diff --git a/NppPlugin/src/StaticDialog.cpp b/NppPlugin/src/StaticDialog.cpp index dfda93c4..5c2efb68 100644 --- a/NppPlugin/src/StaticDialog.cpp +++ b/NppPlugin/src/StaticDialog.cpp @@ -274,6 +274,8 @@ void StaticDialog::create(int dialogID, bool isRTL, bool msgDestParent) // if the destination of message NPPM_MODELESSDIALOG is not its parent, then it's the grand-parent ::SendMessage(msgDestParent ? _hParent : (::GetParent(_hParent)), NPPM_MODELESSDIALOG, MODELESSDIALOGADD, reinterpret_cast(_hSelf)); + //Modified for darkmode support + ::SendMessage(msgDestParent ? _hParent : (::GetParent(_hParent)), NPPM_DARKMODESUBCLASSANDTHEME, static_cast(NppDarkMode::dmfInit), reinterpret_cast(_hSelf)); } intptr_t CALLBACK StaticDialog::dlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) diff --git a/PythonScript.Tests/gtest b/PythonScript.Tests/gtest index c67de117..373af2e3 160000 --- a/PythonScript.Tests/gtest +++ b/PythonScript.Tests/gtest @@ -1 +1 @@ -Subproject commit c67de117379f4d1c889c7581a0a76aa0979c2083 +Subproject commit 373af2e3df71599b87a40ce0e37164523849166b diff --git a/PythonScript/project/packages.config b/PythonScript/project/packages.config index d03e385c..00d70c76 100644 --- a/PythonScript/project/packages.config +++ b/PythonScript/project/packages.config @@ -1,6 +1,6 @@  - + diff --git a/PythonScript/src/NotepadPlusWrapper.cpp b/PythonScript/src/NotepadPlusWrapper.cpp index 6523c37f..40afca72 100644 --- a/PythonScript/src/NotepadPlusWrapper.cpp +++ b/PythonScript/src/NotepadPlusWrapper.cpp @@ -486,6 +486,13 @@ boost::python::str NotepadPlusWrapper::getSettingsOnCloudPath() return boost::python::str(const_cast(WcharMbcsConverter::tchar2char(result).get())); } +boost::python::str NotepadPlusWrapper::getSettingsDirPath() +{ + LRESULT size = callNotepad(NPPM_GETNPPSETTINGSDIRPATH, 0, NULL); + wchar_t* result(new wchar_t[size + 1]); + callNotepad(NPPM_GETNPPSETTINGSDIRPATH, size + 1, reinterpret_cast(result)); + return boost::python::str(const_cast(WcharMbcsConverter::tchar2char(result).get())); +} intptr_t NotepadPlusWrapper::getBookMarkID() { diff --git a/PythonScript/src/NotepadPlusWrapper.h b/PythonScript/src/NotepadPlusWrapper.h index b821e797..bfefc669 100644 --- a/PythonScript/src/NotepadPlusWrapper.h +++ b/PythonScript/src/NotepadPlusWrapper.h @@ -636,6 +636,8 @@ enum MenuCommands NPPIDM_WINDOW_SORT_FT_DSC = IDM_WINDOW_SORT_FT_DSC, NPPIDM_WINDOW_SORT_FS_ASC = IDM_WINDOW_SORT_FS_ASC, NPPIDM_WINDOW_SORT_FS_DSC = IDM_WINDOW_SORT_FS_DSC, + NPPIDM_WINDOW_SORT_FD_ASC = IDM_WINDOW_SORT_FD_ASC, + NPPIDM_WINDOW_SORT_FD_DSC = IDM_WINDOW_SORT_FD_DSC, NPPIDM_WINDOW_MRU_FIRST = IDM_WINDOW_MRU_FIRST, NPPIDM_WINDOW_MRU_LIMIT = IDM_WINDOW_MRU_LIMIT, NPPIDM_WINDOW_COPY_NAME = IDM_WINDOW_COPY_NAME, @@ -719,6 +721,8 @@ class NotepadPlusWrapper boost::python::str getSettingsOnCloudPath(); + boost::python::str getSettingsDirPath(); + intptr_t getBookMarkID(); void menuCommand(int commandID); diff --git a/PythonScript/src/NotepadPython.cpp b/PythonScript/src/NotepadPython.cpp index e4b2f3e4..05ad332e 100644 --- a/PythonScript/src/NotepadPython.cpp +++ b/PythonScript/src/NotepadPython.cpp @@ -159,7 +159,7 @@ void export_notepad() .value("ASP", L_ASP) .value("SQL", L_SQL) .value("VB", L_VB) - .value("JS", L_JS) + .value("JS", L_JS_EMBEDDED) .value("CSS", L_CSS) .value("PERL", L_PERL) .value("PYTHON", L_PYTHON) @@ -861,6 +861,8 @@ void export_notepad() .value("WINDOW_SORT_FT_DSC", NPPIDM_WINDOW_SORT_FT_DSC) .value("WINDOW_SORT_FS_ASC", NPPIDM_WINDOW_SORT_FS_ASC) .value("WINDOW_SORT_FS_DSC", NPPIDM_WINDOW_SORT_FS_DSC) + .value("WINDOW_SORT_FD_ASC", NPPIDM_WINDOW_SORT_FD_ASC) + .value("WINDOW_SORT_FD_DSC", NPPIDM_WINDOW_SORT_FD_DSC) .value("WINDOW_MRU_FIRST", NPPIDM_WINDOW_MRU_FIRST) .value("WINDOW_MRU_LIMIT", NPPIDM_WINDOW_MRU_LIMIT) .value("WINDOW_COPY_NAME", NPPIDM_WINDOW_COPY_NAME) diff --git a/PythonScript/src/PythonScriptVersion.h b/PythonScript/src/PythonScriptVersion.h index 1c9452f2..16c7c76b 100644 --- a/PythonScript/src/PythonScriptVersion.h +++ b/PythonScript/src/PythonScriptVersion.h @@ -1,7 +1,7 @@ #ifndef _PYTHONSCRIPTVERSION_H #define _PYTHONSCRIPTVERSION_H -#define PYSCR_VERSION_NUMERIC 3,0,23,0 -#define PYSCR_VERSION_STRING "3.0.23.0" +#define PYSCR_VERSION_NUMERIC 3,0,24,0 +#define PYSCR_VERSION_STRING "3.0.24.0" #endif diff --git a/PythonScript/src/ScintillaPython.cpp b/PythonScript/src/ScintillaPython.cpp index 7a52094d..71f9822a 100644 --- a/PythonScript/src/ScintillaPython.cpp +++ b/PythonScript/src/ScintillaPython.cpp @@ -128,6 +128,7 @@ BOOST_PYTHON_MODULE(Npp) .def("selectAll", &ScintillaWrapper::SelectAll, "Select all the text in the document.") .def("setSavePoint", &ScintillaWrapper::SetSavePoint, "Remember the current position in the undo history as the position\nat which the document was saved.") .def("getStyledTextFull", &ScintillaWrapper::GetStyledTextFull, boost::python::args("start", "end"), "Retrieve a buffer of cells that can be past 2GB.\nReturns the number of bytes in the buffer not including terminating NULs.") + .def("getStyledText", &ScintillaWrapper::GetStyledTextFull, boost::python::args("start", "end"), "Retrieve a buffer of cells that can be past 2GB.\nReturns the number of bytes in the buffer not including terminating NULs.") .def("canRedo", &ScintillaWrapper::CanRedo, "Are there any redoable actions in the undo history?") .def("markerLineFromHandle", &ScintillaWrapper::MarkerLineFromHandle, boost::python::args("markerHandle"), "Retrieve the line number at which a particular marker is located.") .def("markerDeleteHandle", &ScintillaWrapper::MarkerDeleteHandle, boost::python::args("markerHandle"), "Delete a marker.") @@ -375,6 +376,7 @@ BOOST_PYTHON_MODULE(Npp) .def("setPrintColourMode", &ScintillaWrapper::SetPrintColourMode, boost::python::args("mode"), "Modify colours when printing for clearer printed text.") .def("getPrintColourMode", &ScintillaWrapper::GetPrintColourMode, "Returns the print colour mode.") .def("findTextFull", &ScintillaWrapper::FindTextFull, boost::python::args("searchFlags", "start", "end", "ft"), "Find some text in the document.") + .def("findText", &ScintillaWrapper::FindTextFull, boost::python::args("searchFlags", "start", "end", "ft"), "Find some text in the document.") .def("setChangeHistory", &ScintillaWrapper::SetChangeHistory, boost::python::args("changeHistory"), "Enable or disable change history.") .def("getChangeHistory", &ScintillaWrapper::GetChangeHistory, "Report change history status.") .def("setUndoSelectionHistory", &ScintillaWrapper::SetUndoSelectionHistory, boost::python::args("undoSelectionHistory"), "Enable or disable undo selection history.") @@ -393,6 +395,7 @@ BOOST_PYTHON_MODULE(Npp) .def("setSel", &ScintillaWrapper::SetSel, boost::python::args("anchor", "caret"), "Select a range of text.") .def("getSelText", &ScintillaWrapper::GetSelText, "Retrieve the selected text.\nReturn the length of the text.\nResult is NUL-terminated.") .def("getTextRangeFull", &ScintillaWrapper::GetTextRangeFull, boost::python::args("start", "end"), "Retrieve a range of text that can be past 2GB.\nReturn the length of the text.") + .def("getTextRange", &ScintillaWrapper::GetTextRangeFull, boost::python::args("start", "end"), "Retrieve a range of text that can be past 2GB.\nReturn the length of the text.") .def("hideSelection", &ScintillaWrapper::HideSelection, boost::python::args("hide"), "Draw the selection either highlighted or in normal (non-highlighted) style.") .def("getSelectionHidden", &ScintillaWrapper::GetSelectionHidden, "") .def("pointXFromPosition", &ScintillaWrapper::PointXFromPosition, boost::python::args("pos"), "Retrieve the x value of the point in the window where a position is displayed.") diff --git a/appveyor.yml b/appveyor.yml index 1e98464b..658208bb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 3.0.23.{build} +version: 3.0.24.{build} image: Visual Studio 2022