33#include " Notepad_Plus_msgs.h"
44#include " DockingDlgInterface.h"
55#include " Scintilla.h"
6+ #include " SciLexer.h"
67#include " resource.h"
78#include " PythonConsole.h"
89
@@ -34,6 +35,7 @@ void ConsoleDialog::init(HINSTANCE hInst, NppData nppData, ConsoleInterface* con
3435 // Window::init(hInst, nppData._nppHandle);
3536 createOutputWindow (nppData._nppHandle );
3637 m_console = console;
38+
3739}
3840
3941BOOL ConsoleDialog::run_dlgProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
@@ -80,6 +82,25 @@ BOOL ConsoleDialog::run_dlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM l
8082 // MessageBox(NULL, _T("Command") , _T("Python Command"), 0);
8183 return TRUE ;
8284 }
85+ case WM_NOTIFY:
86+ {
87+ LPNMHDR nmhdr = reinterpret_cast <LPNMHDR>(lParam);
88+ if (m_scintilla == nmhdr->hwndFrom )
89+ {
90+ switch (nmhdr->code )
91+ {
92+ case SCN_STYLENEEDED:
93+ onStyleNeeded (reinterpret_cast <SCNotification*>(lParam));
94+ return FALSE ;
95+
96+ case SCN_HOTSPOTCLICK:
97+ case SCN_HOTSPOTDOUBLECLICK:
98+ onHotspotClick (reinterpret_cast <SCNotification*>(lParam));
99+ return FALSE ;
100+ }
101+ }
102+ return TRUE ;
103+ }
83104 default :
84105 return DockingDlgInterface::run_dlgProc (message, wParam, lParam);
85106
@@ -280,7 +301,14 @@ void ConsoleDialog::createOutputWindow(HWND hParentWindow)
280301 ::SendMessage (m_scintilla, SCI_STYLESETSIZE, 0 /* = style number */ , 8 /* = size in points */ );
281302 ::SendMessage (m_scintilla, SCI_STYLESETSIZE, 1 /* = style number */ , 8 /* = size in points */ );
282303 ::SendMessage (m_scintilla, SCI_STYLESETFORE, 1 , RGB(250 , 0 , 0 ));
283-
304+ ::SendMessage (m_scintilla, SCI_STYLESETSIZE, 2 /* = style number */ , 8 /* = size in points */ );
305+ ::SendMessage (m_scintilla, SCI_STYLESETUNDERLINE, 2 /* = style number */ , 1 /* = underline */ );
306+ ::SendMessage (m_scintilla, SCI_STYLESETSIZE, 3 /* = style number */ , 8 /* = size in points */ );
307+ ::SendMessage (m_scintilla, SCI_STYLESETFORE, 3 , RGB(250 , 0 , 0 ));
308+ ::SendMessage (m_scintilla, SCI_STYLESETUNDERLINE, 3 /* = style number */ , 1 /* = underline */ );
309+ ::SendMessage (m_scintilla, SCI_STYLESETHOTSPOT, 2 , 1 );
310+ ::SendMessage (m_scintilla, SCI_STYLESETHOTSPOT, 3 , 1 );
311+ ::SendMessage (m_scintilla, SCI_SETLEXER, SCLEX_CONTAINER, 0 );
284312}
285313
286314void ConsoleDialog::writeText (int length, const char *text)
@@ -297,19 +325,24 @@ void ConsoleDialog::writeText(int length, const char *text)
297325
298326void ConsoleDialog::writeError (int length, const char *text)
299327{
300-
301-
302-
303- ::SendMessage (m_scintilla, SCI_SETREADONLY, 0 , 0 );
304-
305- ::SendMessage (m_scintilla, SCI_APPENDTEXT, length, reinterpret_cast <LPARAM>(text));
306- ::SendMessage (m_scintilla, SCI_SETREADONLY, 1 , 0 );
307-
308- int docLength = ::SendMessage (m_scintilla, SCI_GETLENGTH, 0 , 0 );
309- ::SendMessage (m_scintilla, SCI_STARTSTYLING, docLength - length, 255 );
310- ::SendMessage (m_scintilla, SCI_SETSTYLING, length, 1 );
311- ::SendMessage (m_scintilla, SCI_GOTOPOS, docLength, 0 );
328+ /*
329+ char *buffer = new char[length * 2];
330+ for(int pos = 0; pos < length; ++pos)
331+ {
332+ buffer[pos * 2] = text[pos];
333+ buffer[(pos * 2) + 1] = 1;
334+ }
335+ */
336+ int docLength = callScintilla (SCI_GETLENGTH);
337+ callScintilla (SCI_SETREADONLY, 0 );
338+ callScintilla (SCI_APPENDTEXT, length, reinterpret_cast <LPARAM>(text));
339+ callScintilla (SCI_SETREADONLY, 1 );
340+ callScintilla (SCI_STARTSTYLING, docLength, 0x01 );
341+ callScintilla (SCI_SETSTYLING, length, 1 );
342+ // delete[] buffer;
312343
344+ callScintilla (SCI_COLOURISE, docLength, -1 );
345+ callScintilla (SCI_GOTOPOS, docLength + length);
313346}
314347
315348
@@ -369,4 +402,244 @@ void ConsoleDialog::clearText()
369402 ::SendMessage (m_scintilla, SCI_SETREADONLY, 0 , 0 );
370403 ::SendMessage (m_scintilla, SCI_CLEARALL, 0 , 0 );
371404 ::SendMessage (m_scintilla, SCI_SETREADONLY, 1 , 0 );
405+ }
406+
407+
408+ void ConsoleDialog::onStyleNeeded (SCNotification* notification)
409+ {
410+ int startPos = callScintilla (SCI_GETENDSTYLED);
411+ int startLine = callScintilla (SCI_LINEFROMPOSITION, startPos);
412+ startPos = callScintilla (SCI_POSITIONFROMLINE, startLine);
413+ int endPos = notification->position ;
414+ int endLine = callScintilla (SCI_LINEFROMPOSITION, endPos);
415+
416+
417+ LineDetails lineDetails;
418+ for (int lineNumber = startLine; lineNumber <= endLine; ++lineNumber)
419+ {
420+ lineDetails.lineLength = callScintilla (SCI_GETLINE, lineNumber);
421+
422+ if (lineDetails.lineLength > 0 )
423+ {
424+ lineDetails.line = new char [lineDetails.lineLength + 1 ];
425+ callScintilla (SCI_GETLINE, lineNumber, reinterpret_cast <LPARAM>(lineDetails.line ));
426+ lineDetails.line [lineDetails.lineLength ] = ' \0 ' ;
427+
428+
429+
430+ if (parseLine (&lineDetails))
431+ {
432+ int startPos = callScintilla (SCI_POSITIONFROMLINE, lineNumber);
433+
434+ callScintilla (SCI_STARTSTYLING, startPos + lineDetails.filenameStart , 0x02 );
435+ callScintilla (SCI_SETSTYLING, lineDetails.filenameEnd - lineDetails.filenameStart , 0x02 );
436+ callScintilla (SCI_STARTSTYLING, startPos + lineDetails.filenameEnd , 0x02 );
437+ callScintilla (SCI_SETSTYLING, lineDetails.lineLength - lineDetails.filenameEnd , 0x00 );
438+ }
439+
440+ delete[] lineDetails.line ;
441+
442+ }
443+ }
444+
445+ }
446+
447+ bool ConsoleDialog::parseLine (LineDetails *lineDetails)
448+ {
449+ if (0 == strncmp (lineDetails->line , " File \" " , 8 ))
450+ {
451+ return parsePythonErrorLine (lineDetails);
452+ }
453+
454+ if (0 == strncmp (lineDetails->line + 1 , " :\\ " , 2 ))
455+ {
456+ return parseVSErrorLine (lineDetails);
457+ }
458+
459+ return false ;
460+ }
461+
462+ bool ConsoleDialog::parseVSErrorLine (LineDetails *lineDetails)
463+ {
464+ enum StyleState
465+ {
466+ SS_FILENAME,
467+ SS_LINENUMBER,
468+ SS_EXIT
469+ } styleState;
470+
471+ bool retVal = false ;
472+ styleState = SS_FILENAME;
473+
474+ int pos = 0 ;
475+ lineDetails->filenameStart = 0 ;
476+ lineDetails->errorLineNo = -1 ;
477+
478+ while (styleState != SS_EXIT)
479+ {
480+ switch (styleState)
481+ {
482+ case SS_FILENAME:
483+ while (lineDetails->line [pos] != ' (' && pos < lineDetails->lineLength )
484+ {
485+ ++pos;
486+ }
487+
488+ if (lineDetails->line [pos] == ' (' ) // Found the opening bracket for line no
489+ {
490+ ++pos;
491+ styleState = SS_LINENUMBER;
492+ }
493+ else
494+ {
495+ styleState = SS_EXIT;
496+ }
497+ break ;
498+
499+ case SS_LINENUMBER:
500+ {
501+ int startLineNoPos = pos;
502+ while (lineDetails->line [pos] >= ' 0' && lineDetails->line [pos] <= ' 9' && pos < lineDetails->lineLength )
503+ {
504+ ++pos;
505+ }
506+ if (pos < (lineDetails->lineLength + 1 )
507+ && lineDetails->line [pos] == ' )'
508+ && lineDetails->line [pos+1 ] == ' :' )
509+ {
510+ lineDetails->errorLineNo = atoi (lineDetails->line + startLineNoPos) - 1 ;
511+ lineDetails->filenameEnd = startLineNoPos - 1 ;
512+ retVal = true ;
513+ styleState = SS_EXIT;
514+ }
515+ else
516+ {
517+ pos = startLineNoPos + 1 ;
518+ styleState = SS_FILENAME;
519+ }
520+ break ;
521+ }
522+
523+ case SS_EXIT:
524+ break ;
525+
526+ default :
527+ styleState = SS_EXIT;
528+ break ;
529+ }
530+ }
531+ return retVal;
532+ }
533+
534+ bool ConsoleDialog::parsePythonErrorLine (LineDetails *lineDetails)
535+ {
536+ enum StyleState
537+ {
538+ SS_BEGIN,
539+ SS_FILENAME,
540+ SS_EXPECTLINE,
541+ SS_LINENUMBER,
542+ SS_EXIT
543+ } styleState;
544+
545+ bool retVal = false ;
546+ styleState = SS_BEGIN;
547+ lineDetails->errorLineNo = -1 ;
548+ int pos = 0 ;
549+ while (styleState != SS_EXIT)
550+ {
551+ switch (styleState)
552+ {
553+ case SS_BEGIN:
554+ if (strncmp (lineDetails->line , " File \" " , 8 ) == 0 )
555+ {
556+ pos = 8 ;
557+ lineDetails->filenameStart = 8 ;
558+ styleState = SS_FILENAME;
559+ }
560+ else
561+ {
562+ styleState = SS_EXIT;
563+ }
564+ break ;
565+
566+ case SS_FILENAME:
567+ while (lineDetails->line [pos] != ' \" ' && pos < lineDetails->lineLength )
568+ {
569+ ++pos;
570+ }
571+
572+ if (pos >= lineDetails->lineLength ) // Not found, so revert to default style
573+ {
574+ styleState = SS_EXIT;
575+ }
576+ else
577+ {
578+ lineDetails->filenameEnd = pos;
579+ retVal = true ;
580+ styleState = SS_EXPECTLINE;
581+ }
582+ break ;
583+
584+ case SS_EXPECTLINE:
585+ if (strncmp (lineDetails->line + pos, " \" , line " , 8 ) == 0 )
586+ {
587+ pos += 8 ;
588+ styleState = SS_LINENUMBER;
589+ }
590+ else
591+ {
592+ styleState = SS_EXIT;
593+ }
594+ break ;
595+
596+ case SS_LINENUMBER:
597+ lineDetails->errorLineNo = atoi (lineDetails->line + pos) - 1 ;
598+ styleState = SS_EXIT;
599+ break ;
600+
601+ default :
602+ styleState = SS_EXIT;
603+ break ;
604+ }
605+ }
606+
607+ return retVal;
608+ }
609+
610+
611+
612+
613+ void ConsoleDialog::styleDefaultLine (int lineNumber, int lineLength, const char * /* line */ )
614+ {
615+
616+ int linePosition = callScintilla (SCI_POSITIONFROMLINE, lineNumber);
617+ // Set the mask to the hotspot bit (0x02)
618+
619+ callScintilla (SCI_STARTSTYLING, linePosition, 0x02 );
620+ // and declare no hotspots
621+ callScintilla (SCI_SETSTYLING, lineLength, 0 );
622+
623+ }
624+
625+
626+ void ConsoleDialog::onHotspotClick (SCNotification* notification)
627+ {
628+
629+ int lineNumber = callScintilla (SCI_LINEFROMPOSITION, notification->position );
630+ LineDetails lineDetails;
631+ lineDetails.lineLength = callScintilla (SCI_GETLINE, lineNumber);
632+
633+ if (lineDetails.lineLength > 0 )
634+ {
635+ lineDetails.line = new char [lineDetails.lineLength + 1 ];
636+ callScintilla (SCI_GETLINE, lineNumber, reinterpret_cast <LPARAM>(lineDetails.line ));
637+ lineDetails.line [lineDetails.lineLength ] = ' \0 ' ;
638+ if (parseLine (&lineDetails))
639+ {
640+ lineDetails.line [lineDetails.filenameEnd ] = ' \0 ' ;
641+ m_console->openFile (lineDetails.line + lineDetails.filenameStart , lineDetails.errorLineNo );
642+ }
643+ }
644+
372645}
0 commit comments