Skip to content

Commit c59092a

Browse files
committed
sync with 8df348a aka 3.0.21
1 parent 47cc09e commit c59092a

File tree

14 files changed

+128
-48
lines changed

14 files changed

+128
-48
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# -*- coding: utf-8 -*-
2+
import unittest
3+
from Npp import notepad, editor
4+
5+
class SearchReplaceInvalidArgumentTestCase(unittest.TestCase):
6+
def setUp(self):
7+
notepad.new()
8+
9+
def tearDown(self):
10+
notepad.close()
11+
12+
def test_invalid_search_argument(self):
13+
for invalid_arg in ["", None]:
14+
for method in [editor.research, editor.search, editor.replace, editor.rereplace]:
15+
self.assertRaises(TypeError, method, invalid_arg, None)
16+
17+
def test_invalid_replace_argument(self):
18+
for method in [editor.replace, editor.rereplace]:
19+
self.assertRaises(TypeError, method, "abc", None)
20+
21+
22+
suite = unittest.TestLoader().loadTestsFromTestCase(SearchReplaceInvalidArgumentTestCase)

PythonScript/res/PythonScript.rc

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,18 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
2525
// TEXTINCLUDE
2626
//
2727

28-
1 TEXTINCLUDE
28+
1 TEXTINCLUDE
2929
BEGIN
3030
"resource.h\0"
3131
END
3232

33-
2 TEXTINCLUDE
33+
2 TEXTINCLUDE
3434
BEGIN
3535
"#include ""afxres.h""\r\n"
3636
"\0"
3737
END
3838

39-
3 TEXTINCLUDE
39+
3 TEXTINCLUDE
4040
BEGIN
4141
"\r\n"
4242
"\0"
@@ -57,7 +57,7 @@ FONT 8, "MS Shell Dlg", 400, 0, 0x1
5757
BEGIN
5858
DEFPUSHBUTTON "OK",IDOK,143,168,50,14
5959
CTEXT "Python Script",IDC_STATIC,144,7,49,8
60-
CTEXT "(C) 2010-2024 Dave Brotherstone",IDC_STATIC,92,30,154,8
60+
CTEXT "(C) 2010-2025 Dave Brotherstone",IDC_STATIC,92,30,154,8
6161
CONTROL IDB_PYTHONPOWERED,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,122,42,93,34
6262
EDITTEXT IDC_COPYRIGHT,7,84,324,74,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL
6363
CTEXT "1.0",IDC_VERSION,144,19,49,8
@@ -73,13 +73,13 @@ BEGIN
7373
COMBOBOX IDC_COMBO1,25,156,125,50,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
7474
END
7575

76-
IDD_SCRIPTCONFIG DIALOGEX 0, 0, 377, 412
76+
IDD_SCRIPTCONFIG DIALOGEX 0, 0, 377, 435
7777
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
7878
CAPTION "Python Script Configuration"
7979
FONT 8, "MS Shell Dlg", 400, 0, 0x1
8080
BEGIN
81-
DEFPUSHBUTTON "OK",IDOK,265,391,50,14
82-
PUSHBUTTON "Cancel",IDCANCEL,320,391,50,14
81+
DEFPUSHBUTTON "OK",IDOK,265,414,50,14
82+
PUSHBUTTON "Cancel",IDCANCEL,320,414,50,14
8383
CONTROL "",IDC_FILETREE,"SysTreeView32",TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_SHOWSELALWAYS | WS_BORDER | WS_HSCROLL | WS_TABSTOP,14,31,343,105
8484
GROUPBOX "Scripts",IDC_STATIC,7,7,363,136
8585
CONTROL "Machine Scripts",IDC_RADMACHINE,"Button",BS_AUTORADIOBUTTON,19,18,65,10
@@ -106,8 +106,11 @@ BEGIN
106106
CONTROL "Color output from run statements differently",IDC_CHECKCOLORIZEOUTPUT,
107107
"Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | BS_NOTIFY | WS_TABSTOP,11,370,157,10
108108
PUSHBUTTON "Choose a color...",IDC_COLORCHOOSER,169,367,65,14
109+
CONTROL "Color console errors differently",IDC_CONSOLEERRORCOLOR,
110+
"Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | BS_NOTIFY | WS_TABSTOP,11,382,117,10
111+
PUSHBUTTON "Choose a color...",IDC_COLORCHOOSER2,169,379,65,14
109112
CONTROL "DISABLE another script is running popup warning",IDC_DISABLEPOPUPWARNING,
110-
"Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | BS_NOTIFY | WS_TABSTOP,11,384,170,10
113+
"Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | BS_NOTIFY | WS_TABSTOP,11,395,170,10
111114
END
112115

113116
IDD_PROMPTDIALOG DIALOGEX 0, 0, 313, 105
@@ -151,7 +154,7 @@ BEGIN
151154
LEFTMARGIN, 7
152155
RIGHTMARGIN, 370
153156
TOPMARGIN, 7
154-
BOTTOMMARGIN, 405
157+
BOTTOMMARGIN, 428
155158
END
156159

157160
IDD_PROMPTDIALOG, DIALOG
0 Bytes
Binary file not shown.

PythonScript/res/resource.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,11 @@
4343
#define IDC_CHECKCOLORIZEOUTPUT 1023
4444
#define IDC_COLORCHOOSER 1024
4545
#define IDC_DISABLEPOPUPWARNING 1025
46+
#define IDC_CONSOLEERRORCOLOR 1026
47+
#define IDC_COLORCHOOSER2 1027
4648

4749
// Next default values for new objects
48-
//
50+
//
4951
#ifdef APSTUDIO_INVOKED
5052
#ifndef APSTUDIO_READONLY_SYMBOLS
5153
#define _APS_NEXT_RESOURCE_VALUE 122

PythonScript/src/ConfigFile.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ void ConfigFile::initSettings()
4949
setSetting(_T("DISABLEPOPUPWARNING"), _T("0"));
5050
setSetting(_T("PREFERINSTALLEDPYTHON"), _T("0"));
5151
setSetting(_T("STARTUP"), _T("LAZY"));
52+
setSetting(_T("CUSTOMCONSOLEERRORCOLOR"), _T("-1"));
5253
}
5354

5455
void ConfigFile::readConfig()

PythonScript/src/ConsoleDialog.cpp

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ ConsoleDialog::ConsoleDialog() :
3232
m_hContext(NULL),
3333
m_nppData{0,0,0},
3434
m_colorOutput(false),
35-
m_user_color(-1)
35+
m_user_color(-1),
36+
m_customizeConsoleErrorColor(false),
37+
m_customConsoleErrorColor(-1)
3638
{}
3739

3840

@@ -76,15 +78,22 @@ void ConsoleDialog::initDialog(HINSTANCE hInst, NppData& nppData, ConsoleInterfa
7678
{
7779
DockingDlgInterface::init(hInst, nppData._nppHandle);
7880

79-
try
81+
auto getColorSetting = [](const TCHAR* settingName, int& output)
8082
{
81-
m_user_color = stoi(ConfigFile::getInstance()->getSetting(_T("COLORIZEOUTPUT")));
82-
m_colorOutput = m_user_color > -1;
83-
}
84-
catch (const std::exception&)
85-
{
86-
m_colorOutput = false;
87-
}
83+
try
84+
{
85+
output = stoi(ConfigFile::getInstance()->getSetting(settingName));
86+
return true;
87+
}
88+
catch (const std::exception&)
89+
{
90+
return false;
91+
}
92+
};
93+
94+
m_colorOutput = getColorSetting(_T("COLORIZEOUTPUT"), m_user_color) && m_user_color > -1;
95+
m_customizeConsoleErrorColor = getColorSetting(_T("CUSTOMCONSOLEERRORCOLOR"), m_customConsoleErrorColor) && m_customConsoleErrorColor > -1;
96+
8897
m_standardPrompt = ConfigFile::getInstance()->getSetting(_T("ADDEXTRALINETOOUTPUT")) == _T("1") ? m_standardPrompt.insert(0, "\n") : m_standardPrompt;
8998
m_currentPrompt = m_standardPrompt;
9099
//Window::init(hInst, nppData._nppHandle);
@@ -381,7 +390,8 @@ void ConsoleDialog::createOutputWindow(HWND hParentWindow)
381390

382391
// 1 is stderr, red text
383392
callScintilla(SCI_STYLESETSIZE, 1 /* = style number */, 8 /* = size in points */);
384-
callScintilla(SCI_STYLESETFORE, 1, RGB(250, 0, 0));
393+
COLORREF consoleErrorColor = m_customizeConsoleErrorColor ? m_customConsoleErrorColor : RGB(250, 0, 0);
394+
callScintilla(SCI_STYLESETFORE, 1, consoleErrorColor);
385395

386396
// 2 is stdout, black text, underline hotspot
387397
callScintilla(SCI_STYLESETSIZE, 2 /* = style number */, 8 /* = size in points */);

PythonScript/src/ConsoleDialog.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,8 @@ class ConsoleDialog : public DockingDlgInterface
9797
HMENU m_hContext;
9898
bool m_colorOutput;
9999
int m_user_color;
100-
100+
bool m_customizeConsoleErrorColor;
101+
int m_customConsoleErrorColor;
101102
};
102103

103104
enum ErrorLevel

PythonScript/src/PythonHandler.cpp

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ void PythonHandler::initPython()
9494
Py_NoSiteFlag = 1;
9595

9696
Py_Initialize();
97-
// Initialise threading and create & acquire Global Interpreter Lock
97+
// Initialise threading and create & acquire Global Interpreter Lock
9898
PyEval_InitThreads();
9999

100100

@@ -110,30 +110,30 @@ void PythonHandler::initPython()
110110

111111

112112
// Init paths
113-
char initBuffer[1024];
114-
char pathCommands[500];
113+
char initBuffer[1024]{};
114+
char pathCommands[500]{};
115115

116116
// If the user wants to use their installed python version, append the paths.
117117
// If not (and they want to use the bundled python install), the default, then prepend the paths
118-
if (ConfigFile::getInstance()->getSetting(_T("PREFERINSTALLEDPYTHON")) == _T("1")) {
119-
strcpy_s<500>(pathCommands, "import sys\n"
120-
"sys.path.append(r'%slib'%s)\n"
121-
"sys.path.append(r'%slib'%s)\n"
122-
"sys.path.append(r'%sscripts'%s)\n"
123-
"sys.path.append(r'%sscripts'%s)\n"
118+
if (ConfigFile::getInstance()->getSetting(_T("PREFERINSTALLEDPYTHON")) == _T("1")) {
119+
strcpy_s<500>(pathCommands, "import sys\n"
120+
"sys.path.append(r'%slib'%s)\n"
121+
"sys.path.append(r'%slib'%s)\n"
122+
"sys.path.append(r'%sscripts'%s)\n"
123+
"sys.path.append(r'%sscripts'%s)\n"
124124
"sys.path.append(r'%slib\\lib-tk'%s)\n" );
125125
} else {
126-
strcpy_s<500>(pathCommands, "import sys\n"
127-
"sys.path.insert(0,r'%slib'%s)\n"
128-
"sys.path.insert(1,r'%slib'%s)\n"
129-
"sys.path.insert(2,r'%sscripts'%s)\n"
130-
"sys.path.insert(3,r'%sscripts'%s)\n"
131-
"sys.path.insert(4,r'%slib\\lib-tk'%s)\n"
126+
strcpy_s<500>(pathCommands, "import sys\n"
127+
"sys.path.insert(0,r'%slib'%s)\n"
128+
"sys.path.insert(1,r'%slib'%s)\n"
129+
"sys.path.insert(2,r'%sscripts'%s)\n"
130+
"sys.path.insert(3,r'%sscripts'%s)\n"
131+
"sys.path.insert(4,r'%slib\\lib-tk'%s)\n"
132132
);
133133
}
134134

135135
_snprintf_s(initBuffer, 1024, 1024,
136-
pathCommands,
136+
pathCommands,
137137
smachineDir.c_str(),
138138
machineIsUnicode ? ".decode('utf8')" : "",
139139

PythonScript/src/Replacer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class BoostRegexMatch : public Match
6464
m_text = rhs.m_text;
6565
m_match = rhs.m_match;
6666

67-
/* We explicitely don't copy the list, as the allocatedGroupDetails will simply be destructed when this object gets destroyed.
67+
/* We explicitly don't copy the list, as the allocatedGroupDetails will simply be destructed when this object gets destroyed.
6868
* In theory, this would be bad, as we would delete the allocated GroupDetail objects when this object is deleted,
6969
* even though the various groups may still be in use.
7070
* In practice however, these GroupDetails don't actually live as long as this object, as we've created a ReplaceEntry

PythonScript/src/ScintillaWrapper.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,15 @@ void ScintillaWrapper::replaceImpl(boost::python::object searchStr, boost::pytho
802802
intptr_t currentDocumentCodePage = this->GetCodePage();
803803

804804
std::string searchChars = extractEncodedString(searchStr, currentDocumentCodePage);
805+
806+
if (searchStr.is_none() || searchChars.empty()) {
807+
throw NppPythonScript::ArgumentException("search parameter must not be none or an empty string");
808+
}
809+
810+
if (replaceStr.is_none()) {
811+
throw NppPythonScript::ArgumentException("replace parameter must not be none");
812+
}
813+
805814
std::string replaceChars;
806815
bool isPythonReplaceFunction = true;
807816

@@ -947,6 +956,11 @@ void ScintillaWrapper::searchImpl(boost::python::object searchStr,
947956

948957
std::string searchChars = extractEncodedString(searchStr, currentDocumentCodePage);
949958

959+
if (searchStr.is_none() || searchChars.empty())
960+
{
961+
throw NppPythonScript::ArgumentException("search parameter must not be none or an empty string");
962+
}
963+
950964
if (!PyCallable_Check(matchFunction.ptr()))
951965
{
952966
throw NppPythonScript::ArgumentException("match parameter must be callable, i.e. either a function or a lambda expression");
@@ -1070,4 +1084,4 @@ std::string ScintillaWrapper::iso_latin_1_to_utf8(const std::string& ansi_input)
10701084
return output;
10711085
}
10721086

1073-
}
1087+
}

0 commit comments

Comments
 (0)