Skip to content

Commit

Permalink
Added configs to support the use of the new NPPM_ALLOCATEINDICATOR me…
Browse files Browse the repository at this point in the history
…ssages to automatically allocate indicator IDs for keyword matcher and error annotator.
  • Loading branch information
blu3mania committed Aug 29, 2023
1 parent 22c2b13 commit bdd76fe
Show file tree
Hide file tree
Showing 15 changed files with 250 additions and 121 deletions.
25 changes: 16 additions & 9 deletions Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,17 @@ In the rare case when a keyword cannot be matched, like when there is a typo, or
definition, unmatched style will be used to highlight. It is configurable as well and by default it is a
red rectangle.

Usually the default indicator ID (17) won't conflict with other plugins. However, there is no guarantee that
will never happen, so this plugin allows you to choose a different indicator if there is a conflict. The
valid numbers are between 9 and 20. Keep in mind other plugins may use indicator IDs as well, for example,
DSpellCheck uses 19. Make sure you **do not** change this ID if everything works fine.
For the indicator ID, it is recommended to ask Notepad++ to auto allocate indicator ID. If all plugins are
doing it this way then there will not be conflicts. Though, due to the limited number of indicator IDs (only
between 9 and 20), if many plugins are using indicators then the pool could be drained by the time this plugin
asks for an allocation. In such a case this plugin will fall back to the configured default indicator ID (by
default 17). Of course it means there will be conflicts but there really isn't a good solution. Try to remove
some unused plugins, and see if the issue is solved. Also, there might be plugins that are still using
hardcoded indicator IDs, and in that case there is no guarantee that the indicator ID allocated by Notepad++
won't conflict with those plugins. In either case, this plugin allows you to choose a default indicator ID
for fallback, or to avoid conflict with plugins using hardcoded indicator IDs. The valid numbers are between
9 and 20. Keep in mind other plugins may use indicator IDs as well, for example, DSpellCheck uses 19. Make
sure you **do not** turn off auto allocation or change this ID if default settings work fine.


## Error Annotator tab
Expand All @@ -94,11 +101,11 @@ in the same annotation box.
Show indications where errors happen. By default, the indicator is a red squiggly line under the word or
operator where error is, similar to what a spell checker does. There are many styles to choose from.

Similar to Keyword Matcher's indicator ID, Error Annotator's indicator ID can be changed as well. The
default ID (18) should not cause conflict usually, but if it does, follow the same instructions provided
in [Keyword Matcher tab](#keyword-matcher-tab) section. *Note*, after changing it, existing indications
may be rendered incorrectly if edits have been made. You can recompile the script to make them show
correctly again, or simply fix all bugs reported against your script. 😀
Similar to Keyword Matcher's indicator ID, Error Annotator's indicator ID can be changed as well. Follow
the same instructions provided in [Keyword Matcher tab](#keyword-matcher-tab) section. *Note*, after
changing indicator ID, existing indications may be rendered incorrectly if edits have been made. You can
recompile the script to make them show correctly again, or simply fix all bugs reported against your
script. 😀


## Compiler tab
Expand Down
20 changes: 20 additions & 0 deletions src/Plugin/Common/NotepadPlusPlus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.

#include "NotepadPlusPlus.hpp"

#include "StringUtil.hpp"

#include "..\..\external\gsl\include\gsl\util"
#include "..\..\external\npp\Notepad_plus_msgs.h"
#include "..\..\external\npp\PluginInterface.h"

namespace utility {

Expand Down Expand Up @@ -51,4 +54,21 @@ namespace utility {
return bufferID;
}

std::wstring getApplicableFilePathOnView(HWND nppHandle, npp_view_t view) {
// Make sure it is a Papyrus script
std::wstring filePath = getActiveFilePathOnView(nppHandle, view);
if (endsWith(filePath, L".psc") || endsWith(filePath, L".pas")) {
return filePath;
}

return std::wstring();
}

void clearIndications(HWND handle, int indicatorID) {
// Need to specify which indicator to be cleared.
::SendMessage(handle, SCI_SETINDICATORCURRENT, indicatorID, 0);
npp_length_t docLength = ::SendMessage(handle, SCI_GETLENGTH, 0, 0);
::SendMessage(handle, SCI_INDICATORCLEARRANGE, 0, docLength);
}

} // namespace
6 changes: 6 additions & 0 deletions src/Plugin/Common/NotepadPlusPlus.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,10 @@ namespace utility {
return (bufferID != 0 ? getFilePathFromBuffer(nppHandle, bufferID) : std::wstring());
}

// Retrieve the full file path of the active document on a given view, if it is a Papyrus script
std::wstring getApplicableFilePathOnView(HWND nppHandle, npp_view_t view);

// Clear existing indications drawn with a given indicator
void clearIndications(HWND handle, int indicatorID);

} // namespace
2 changes: 2 additions & 0 deletions src/Plugin/Common/Resources.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define IDC_SETTINGS_MATCHER_INDICATOR_ID_LABEL (IDC_SETTINGS_MATCHER + 21)
#define IDC_SETTINGS_MATCHER_INDICATOR_ID (IDC_SETTINGS_MATCHER_INDICATOR_ID_LABEL + 1)
#define IDS_SETTINGS_MATCHER_INDICATOR_ID_TOOLTIP (IDC_SETTINGS_MATCHER_INDICATOR_ID + 1)
#define IDC_SETTINGS_MATCHER_INDICATOR_ID_AUTO_ALLOCATE (IDC_SETTINGS_MATCHER_INDICATOR_ID + 2)
#define IDC_SETTINGS_MATCHER_MATCHED_STYLE_LABEL (IDC_SETTINGS_MATCHER + 31)
#define IDC_SETTINGS_MATCHER_MATCHED_STYLE_DROPDOWN (IDC_SETTINGS_MATCHER_MATCHED_STYLE_LABEL + 1)
#define IDC_SETTINGS_MATCHER_MATCHED_FGCOLOR_LABEL (IDC_SETTINGS_MATCHER_MATCHED_STYLE_LABEL + 2)
Expand All @@ -144,6 +145,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define IDC_SETTINGS_ANNOTATOR_INDICATOR_ID_LABEL (IDC_SETTINGS_ANNOTATOR_ENABLE_INDICATION + 2)
#define IDC_SETTINGS_ANNOTATOR_INDICATOR_ID (IDC_SETTINGS_ANNOTATOR_INDICATOR_ID_LABEL + 1)
#define IDS_SETTINGS_ANNOTATOR_INDICATOR_ID_TOOLTIP (IDC_SETTINGS_ANNOTATOR_INDICATOR_ID + 1)
#define IDC_SETTINGS_ANNOTATOR_INDICATOR_ID_AUTO_ALLOCATE (IDC_SETTINGS_ANNOTATOR_INDICATOR_ID + 2)
#define IDC_SETTINGS_ANNOTATOR_INDICATOR_STYLE_LABEL (IDC_SETTINGS_ANNOTATOR_ENABLE_INDICATION + 11)
#define IDC_SETTINGS_ANNOTATOR_INDICATOR_STYLE_DROPDOWN (IDC_SETTINGS_ANNOTATOR_INDICATOR_STYLE_LABEL + 1)
#define IDC_SETTINGS_ANNOTATOR_INDICATOR_FGCOLOR_LABEL (IDC_SETTINGS_ANNOTATOR_INDICATOR_STYLE_LABEL + 2)
Expand Down
99 changes: 53 additions & 46 deletions src/Plugin/CompilationErrorHandling/ErrorAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.

#include "ErrorAnnotator.hpp"

#include "..\Common\Logger.hpp"
#include "..\Common\StringUtil.hpp"

#include "..\..\external\gsl\include\gsl\util"
Expand All @@ -43,7 +44,8 @@ namespace papyrus {
subscribableSettings.isAnnotationBold.subscribe([&](auto) { updateAnnotationStyle(); });

subscribableSettings.enableIndication.subscribe([&](auto) { updateIndicatorStyle(); });
subscribableSettings.indicatorID.subscribe([&](auto eventData) { changeIndicator(eventData.oldValue); });
subscribableSettings.autoAllocateIndicatorID.subscribe([&](auto) { changeIndicator(); });
subscribableSettings.defaultIndicatorID.subscribe([&](auto) { changeIndicator(); });
subscribableSettings.indicatorStyle.subscribe([&](auto) { updateIndicatorStyle(); });
subscribableSettings.indicatorForegroundColor.subscribe([&](auto) { updateIndicatorStyle(); });
}
Expand All @@ -62,11 +64,11 @@ namespace papyrus {
errors.clear();

// Check and clear all annotations from both views.
if (!getApplicableFilePathOnView(MAIN_VIEW).empty()) {
if (!utility::getApplicableFilePathOnView(nppData._nppHandle, MAIN_VIEW).empty()) {
clearAnnotations(nppData._scintillaMainHandle);
clearIndications(nppData._scintillaMainHandle);
}
if (!getApplicableFilePathOnView(SUB_VIEW).empty()) {
if (!utility::getApplicableFilePathOnView(nppData._nppHandle, SUB_VIEW).empty()) {
clearAnnotations(nppData._scintillaSecondHandle);
clearIndications(nppData._scintillaSecondHandle);
}
Expand Down Expand Up @@ -131,19 +133,9 @@ namespace papyrus {
// Private methods
//

std::wstring ErrorAnnotator::getApplicableFilePathOnView(npp_view_t view) const {
// Make sure it is a Papyrus script
std::wstring filePath = utility::getActiveFilePathOnView(nppData._nppHandle, view);
if (utility::endsWith(filePath, L".psc") || utility::endsWith(filePath, L".pas")) {
return filePath;
}

return std::wstring();
}

void ErrorAnnotator::annotate(npp_view_t view) {
// Annotate current file on the given view if it's Papyrus script.
std::wstring filePath = getApplicableFilePathOnView(view);
std::wstring filePath = utility::getApplicableFilePathOnView(nppData._nppHandle, view);
if (!filePath.empty()) {
annotate(view, filePath);
} else {
Expand All @@ -158,14 +150,7 @@ namespace papyrus {
}

void ErrorAnnotator::clearIndications(HWND handle) const {
clearIndications(handle, settings.indicatorID);
}

void ErrorAnnotator::clearIndications(HWND handle, int indicator) const {
// Need to specify which indicator to be cleared.
::SendMessage(handle, SCI_SETINDICATORCURRENT, indicator, 0);
npp_length_t docLength = ::SendMessage(handle, SCI_GETLENGTH, 0, 0);
::SendMessage(handle, SCI_INDICATORCLEARRANGE, 0, docLength);
utility::clearIndications(handle, indicatorID);
}

void ErrorAnnotator::showAnnotations(HWND handle) const {
Expand All @@ -177,19 +162,19 @@ namespace papyrus {
}

void ErrorAnnotator::showIndications(HWND handle) const {
::SendMessage(handle, SCI_INDICSETSTYLE, settings.indicatorID, settings.indicatorStyle);
::SendMessage(handle, SCI_INDICSETSTYLE, indicatorID, settings.indicatorStyle);
}

void ErrorAnnotator::hideIndications(HWND handle) const {
::SendMessage(handle, SCI_INDICSETSTYLE, settings.indicatorID, INDIC_HIDDEN);
::SendMessage(handle, SCI_INDICSETSTYLE, indicatorID, INDIC_HIDDEN);
}

void ErrorAnnotator::updateAnnotationStyle() {
// Update annotation style of the current file on the given view if it's Papyrus script.
if (!getApplicableFilePathOnView(MAIN_VIEW).empty()) {
if (!utility::getApplicableFilePathOnView(nppData._nppHandle, MAIN_VIEW).empty()) {
updateAnnotationStyle(MAIN_VIEW, nppData._scintillaMainHandle);
}
if (!getApplicableFilePathOnView(SUB_VIEW).empty()) {
if (!utility::getApplicableFilePathOnView(nppData._nppHandle, SUB_VIEW).empty()) {
updateAnnotationStyle(SUB_VIEW, nppData._scintillaSecondHandle);
}
}
Expand Down Expand Up @@ -217,40 +202,62 @@ namespace papyrus {
}

// Since indication locations are not tracked after they were draw, calling this method could cause newly rendered indications to be off.
void ErrorAnnotator::changeIndicator(int oldIndicator) {
// Clear indications from both views if they are Papyrus scripts.
std::wstring mainViewFilePath = getApplicableFilePathOnView(MAIN_VIEW);
if (!mainViewFilePath.empty()) {
clearIndications(nppData._scintillaMainHandle, oldIndicator);
}
std::wstring secondViewFilePath = getApplicableFilePathOnView(SUB_VIEW);
if (!secondViewFilePath.empty()) {
clearIndications(nppData._scintillaSecondHandle, oldIndicator);
}
void ErrorAnnotator::changeIndicator() {
int oldIndicatorID = indicatorID;
if (settings.autoAllocateIndicatorID) {
if (allocatedIndicatorID == 0) {
if (!static_cast<bool>(::SendMessage(nppData._nppHandle, NPPM_ALLOCATEINDICATOR, 1, reinterpret_cast<LPARAM>(&allocatedIndicatorID)))) {
// Likely no available indicator ID left.
allocatedIndicatorID = -1;
}
//utility::logger.log(L"Allocated error annotator indicator ID: " + std::to_wstring(allocatedIndicatorID));
}

// Draw new indications if needed.
if (!mainViewFilePath.empty()) {
updateIndicatorStyleOnFile(nppData._scintillaMainHandle, mainViewFilePath);
if (allocatedIndicatorID > 0) {
indicatorID = allocatedIndicatorID;
} else if (settings.defaultIndicatorID > 0) {
indicatorID = settings.defaultIndicatorID;
}
} else if (settings.defaultIndicatorID > 0) {
indicatorID = settings.defaultIndicatorID;
}
if (!secondViewFilePath.empty()) {
updateIndicatorStyleOnFile(nppData._scintillaSecondHandle, secondViewFilePath);
//utility::logger.log(L"Error annotator uses indicator ID: " + std::to_wstring(indicatorID));

if (indicatorID != oldIndicatorID) {
// Clear indications from both views if they are Papyrus scripts.
std::wstring mainViewFilePath = utility::getApplicableFilePathOnView(nppData._nppHandle, MAIN_VIEW);
if (!mainViewFilePath.empty()) {
utility::clearIndications(nppData._scintillaMainHandle, oldIndicatorID);
}
std::wstring secondViewFilePath = utility::getApplicableFilePathOnView(nppData._nppHandle, SUB_VIEW);
if (!secondViewFilePath.empty()) {
utility::clearIndications(nppData._scintillaSecondHandle, oldIndicatorID);
}

// Draw new indications if needed.
if (!mainViewFilePath.empty()) {
updateIndicatorStyleOnFile(nppData._scintillaMainHandle, mainViewFilePath);
}
if (!secondViewFilePath.empty()) {
updateIndicatorStyleOnFile(nppData._scintillaSecondHandle, secondViewFilePath);
}
}
}

void ErrorAnnotator::updateIndicatorStyle() {
// Update indicator style of the current file on the given view if it's Papyrus script.
if (!getApplicableFilePathOnView(MAIN_VIEW).empty()) {
if (!utility::getApplicableFilePathOnView(nppData._nppHandle, MAIN_VIEW).empty()) {
updateIndicatorStyle(nppData._scintillaMainHandle);
}
if (!getApplicableFilePathOnView(SUB_VIEW).empty()) {
if (!utility::getApplicableFilePathOnView(nppData._nppHandle, SUB_VIEW).empty()) {
updateIndicatorStyle(nppData._scintillaSecondHandle);
}
}

void ErrorAnnotator::updateIndicatorStyle(HWND handle) const {
::SendMessage(handle, SCI_INDICSETFORE, settings.indicatorID, settings.indicatorForegroundColor);
::SendMessage(handle, SCI_SETINDICATORCURRENT, settings.indicatorID, 0);
::SendMessage(handle, SCI_INDICSETOUTLINEALPHA, settings.indicatorID, 255); // Always make indicator's outline opaque
::SendMessage(handle, SCI_INDICSETFORE, indicatorID, settings.indicatorForegroundColor);
::SendMessage(handle, SCI_SETINDICATORCURRENT, indicatorID, 0);
::SendMessage(handle, SCI_INDICSETOUTLINEALPHA, indicatorID, 255); // Always make indicator's outline opaque

settings.enableIndication ? showIndications(handle) : hideIndications(handle);
}
Expand Down
16 changes: 7 additions & 9 deletions src/Plugin/CompilationErrorHandling/ErrorAnnotator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,11 @@ namespace papyrus {

using FileErrors = std::list<LineError>;

// Get current file path on the given view, if it's a applicable
std::wstring getApplicableFilePathOnView(npp_view_t view) const;

// Annotate current buffer on a given view, if it has errors
void annotate(npp_view_t view);

void clearAnnotations(HWND handle) const;
void clearIndications(HWND handle) const;
void clearIndications(HWND handle, int indicator) const;

void showAnnotations(HWND handle) const;
void hideAnnotations(HWND handle) const;
Expand All @@ -73,11 +69,10 @@ namespace papyrus {

void drawAnnotations(HWND handle, const LineError& lineError) const;

// Change indiator ID.
// Scintilla reserves indicator 8-31 for containers. Notepad++ itself uses 8, and SciLexher.h defines most
// of IDs above 20, which NPP uses.
// By default 18 is used ny this plugin, but other plugins could cause conflicts, e.g. DSpellCheck uses 19.
void changeIndicator(int oldIndicator);
// Change indicator ID.
// Scintilla reserves indicator 8-31 for containers. Notepad++ itself uses 8, and SciLexher.h defines most of IDs above 20, which NPP uses.
// By default 18 is used for error annotation, but other plugins could cause conflicts, e.g. DSpellCheck uses 19. It is recommended to auto allocate.
void changeIndicator();

void updateIndicatorStyle();
void updateIndicatorStyle(HWND handle) const;
Expand All @@ -91,6 +86,9 @@ namespace papyrus {
const ErrorAnnotatorSettings& settings;
std::map<std::wstring, FileErrors> errors;

int indicatorID {0};
int allocatedIndicatorID {0};

int mainViewStyleAssigned {0};
int secondViewStyleAssigned {0};
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ namespace papyrus {
utility::PrimitiveTypeValueMonitor<bool> isAnnotationItalic;
utility::PrimitiveTypeValueMonitor<bool> isAnnotationBold;
utility::PrimitiveTypeValueMonitor<bool> enableIndication;
utility::PrimitiveTypeValueMonitor<int> indicatorID;
utility::PrimitiveTypeValueMonitor<bool> autoAllocateIndicatorID;
utility::PrimitiveTypeValueMonitor<int> defaultIndicatorID;
utility::PrimitiveTypeValueMonitor<int> indicatorStyle;
utility::PrimitiveTypeValueMonitor<COLORREF> indicatorForegroundColor;
};
Expand Down
Loading

0 comments on commit bdd76fe

Please sign in to comment.