<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Enhance UDL lexer]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/michael-miller31" aria-label="Profile: Michael-Miller31">@<bdi>Michael-Miller31</bdi></a> , <a class="plugin-mentions-user plugin-mentions-a" href="/user/gerald-kirchner" aria-label="Profile: Gerald-Kirchner">@<bdi>Gerald-Kirchner</bdi></a> , <a class="plugin-mentions-user plugin-mentions-a" href="/user/meta-chuh" aria-label="Profile: Meta-Chuh">@<bdi>Meta-Chuh</bdi></a> , <a class="plugin-mentions-user plugin-mentions-a" href="/user/peterjones" aria-label="Profile: PeterJones">@<bdi>PeterJones</bdi></a> <a class="plugin-mentions-user plugin-mentions-a" href="/user/alan-kilborn" aria-label="Profile: Alan-Kilborn">@<bdi>Alan-Kilborn</bdi></a> <a class="plugin-mentions-user plugin-mentions-a" href="/user/guy038" aria-label="Profile: guy038">@<bdi>guy038</bdi></a></p>
<p dir="auto">I opened this thread just to inform you that I have reworked the script a little bit<br />
to make it more user friendly. An additional feature which I think is useful has been<br />
added as well. It is ignoring styling in certain areas like comments and delimiters.<br />
Can be configured within the configuration area.<br />
I know that my English is not the best and therefore would appreciate corrections as well<br />
as thoughts and ideas on the general usage/usability of the script.</p>
<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/guy038" aria-label="Profile: guy038">@<bdi>guy038</bdi></a> - I left, slightly modified, the regex on purpose to demonstrate the usage of different match groups.</p>
<pre><code># -*- coding: utf-8 -*-

from Npp import editor, editor1, editor2, notepad, NOTIFICATION, SCINTILLANOTIFICATION, INDICATORSTYLE
import ctypes
import ctypes.wintypes as wintypes

from collections import OrderedDict
regexes = OrderedDict()

# ------------------------------------------------- configuration area ---------------------------------------------------
#
# define the lexer name like it is shown in the language menu
lexer_name = 'BR! Source'

# define the color and regexes
#   Note, the ordering, which regex gets executed when, is defined by creation.
#   Means the first line defined gets first executed, then the second line, third line and so on.
#
#   The key - value pairs of the dictionary are both tuples of length of 2
#   1. The key tuple is starting with an increasing number followed by the color tuple
#      This allows to define the same color with multiple regexes.
#   2. The value starts with a raw byte string which is the regex whose matches get styled
#      followed by a number which indicates which match group result should be taken
#
#   The skeleton always needs to look like this
#   regexes[(a, b)] = (c, d)
#   regexes = an ordered dictionary which ensures that the regex will be executed in the same order always.
#   a = an unique number - start with 0 and increase by 1 for every next definition
#   b = color in the form of (r,g,b) like (255,0,0) for red
#   c = raw byte string describing the regex to search for - like r'\w+'
#   d = the number of the match group which should be used

# example
# color all text occurrences, containing letters and/or numbers and/or underscore which end with $
# except ones which are starting with fn in a blue like color - result from match group 1 should be taken
regexes[(0, (79, 175, 239))] = (r'fn\w+\$|(\w+\$)', 1)
# color all numbers in an orange like color, result from match group 0, aka default, should be taken
regexes[(1, (252, 173, 67))] = (r'\d', 0)

# define in which area it should not be styled
# 1 = comment line style
# 2 = comment style
# 16 = delimiter1
# ...
# 23 = delimiter8
excluded_styles = [1, 2, 16, 17, 18, 19, 20, 21, 22, 23]

# ------------------------------------------------ /configuration area ---------------------------------------------------

try:
    EnhanceUDLLexer().main()
except NameError:

    user32 = wintypes.WinDLL('user32')

    WM_USER = 1024
    NPPMSG = WM_USER+1000
    NPPM_GETLANGUAGEDESC = NPPMSG+84


    class SingletonEnhanceUDLLexer(type):
        '''
            Ensures, more or less, that only one
            instance of main class can be instantiated
        '''
        _instance = None
        def __call__(cls, *args, **kwargs):
            if cls._instance is None:
                cls._instance = super(SingletonEnhanceUDLLexer, cls).__call__(*args, **kwargs)
            return cls._instance


    class EnhanceUDLLexer(object):
        '''
            Provides additional coloring possibility and should be used together with the built-in UDL feature.
            To avoid style clashes an indicator is used. Although the scintilla documentation states that
            indicators 0-7 are reserved for the lexers, UDL isn't allocating any, so this class is using indicator 0.

            Even when using more than one regex, there is no need to define more than one indicator
            as the class is using SC_INDICFLAG_VALUEFORE flag.
            See https://www.scintilla.org/ScintillaDoc.html#Indicators for more information on that topic
        '''
        __metaclass__ = SingletonEnhanceUDLLexer

        @staticmethod
        def rgb(r, g, b):
            '''
                Helper function
                retrieves rgb color triple and converts it
                into its integer representation

                Args:
                    r = integer, red color value in range of 0-255
                    g = integer, green color value in range of 0-255
                    b = integer, blue color value in range of 0-255
                Returns:
                    integer
            '''
            return (b &lt;&lt; 16) + (g &lt;&lt; 8) + r


        @staticmethod
        def paint_it(color, pos, length):
            '''
                This is were the actual coloring happens
                retrieves the color, the position of the first char
                and the length of the text to be colored

                Args:
                    color = integer, expected in range of 0-16777215
                    pos = integer,  denotes the start position
                    length = integer, denotes how many chars need to be colored.
                Returns:
                    None
            '''
            if pos &gt;= 0:
                if editor.getStyleAt(pos) in excluded_styles:
                    return
                editor.setIndicatorCurrent(0)
                editor.setIndicatorValue(color)
                editor.indicatorFillRange(pos, length)


        def style(self):
            '''
                Calculates the text range of the current document
                and calls the regexes to retrieve the position
                and length of the text to be colored.
                Clears the old indicators prior to setting new ones.

                Args:
                    None
                Returns:
                    None
            '''
            start_line = editor.getFirstVisibleLine()
            end_line = editor.docLineFromVisible(start_line + editor.linesOnScreen())
            start_position = editor.positionFromLine(start_line)
            end_position = editor.getLineEndPosition(end_line)
            editor.setIndicatorCurrent(0)
            editor.indicatorClearRange(0, editor.getTextLength())
            for color, regex in self.regexes.items():
                editor.research(regex[0],
                                lambda m: self.paint_it(color[1],
                                                        m.span(regex[1])[0],
                                                        m.span(regex[1])[1] - m.span(regex[1])[0]),
                                0,
                                start_position,
                                end_position)


        def configure(self):
            '''
                Define basic indicator settings, the needed regexes as well as the lexer name.

                Args:
                    None
                Returns:
                    None
            '''

            SC_INDICVALUEBIT = 0x1000000
            SC_INDICFLAG_VALUEFORE = 1

            editor1.indicSetStyle(0, INDICATORSTYLE.TEXTFORE)
            editor1.indicSetFlags(0, SC_INDICFLAG_VALUEFORE)
            editor2.indicSetStyle(0, INDICATORSTYLE.TEXTFORE)
            editor2.indicSetFlags(0, SC_INDICFLAG_VALUEFORE)
            self.regexes = OrderedDict([ ((k[0], self.rgb(*k[1]) | SC_INDICVALUEBIT), v) for k, v in regexes.items() ])
            self.lexer_name = 'User Defined language file - %s' % lexer_name


        def get_lexer_name(self):
            '''
                Returns the text which is shown in the first field of the statusbar

                Normally one might use notepad.getLanguageName(notepad.getLangType())
                but because this resulted in some strange crashes on my environment ctypes is used.

                Args:
                    None
                Returns:
                    None

            '''
            language = notepad.getLangType()
            length = user32.SendMessageW(self.npp_hwnd, NPPM_GETLANGUAGEDESC, language, None)
            buffer = ctypes.create_unicode_buffer(u' ' * length)
            user32.SendMessageW(self.npp_hwnd, NPPM_GETLANGUAGEDESC, language, ctypes.byref(buffer))
            # print buffer.value  # uncomment if unsure how the lexer name in configure should look like - npp restart needed
            return buffer.value


        def __init__(self):
            '''
                Instantiated the class,
                because of __metaclass__ = ... usage, is called once only.
            '''
            editor.callbackSync(self.on_updateui, [SCINTILLANOTIFICATION.UPDATEUI])
            notepad.callback(self.on_langchanged, [NOTIFICATION.LANGCHANGED])
            notepad.callback(self.on_bufferactivated, [NOTIFICATION.BUFFERACTIVATED])
            self.doc_is_of_interest = False
            self.lexer_name = None
            self.npp_hwnd = user32.FindWindowW(u'Notepad++', None)
            self.configure()


        def set_lexer_doc(self, bool_value):
            '''
                Sets the document of interest flag
                by setting an editor property to 1 or -1
                Property name is the class name

                Args:
                    bool_value = boolean, True sets 1, False sets -1
                Returns:
                    None
            '''
            editor.setProperty(self.__class__.__name__, 1 if bool_value is True else -1)
            self.doc_is_of_interest = bool_value


        def on_bufferactivated(self, args):
            '''
                Callback which gets called every time one switches a document.
                Checks if the document is of interest by checking the lexer name
                and the editor property and sets the document flag.

                Args:
                    provided by notepad object but none are of interest
                Returns:
                    None
            '''
            if (self.get_lexer_name() == self.lexer_name) and (editor.getPropertyInt(self.__class__.__name__) != -1):
                self.doc_is_of_interest = True
            else:
                self.doc_is_of_interest = False


        def on_updateui(self, args):
            '''
                Callback which gets called every time scintilla
                (aka the editor) changed something within the document.

                Triggers the styling function if the document is of interest.

                Args:
                    provided by scintilla but none are of interest
                Returns:
                    None
            '''
            if self.doc_is_of_interest:
                self.style()


        def on_langchanged(self, args):
            '''
                Callback gets called every time one uses the Language menu to set a lexer
                Triggers the setting of document of interest flag

                Args:
                    provided by notepad object but none are of interest
                Returns:
                    None
            '''
            self.set_lexer_doc(True if self.get_lexer_name() == self.lexer_name else False)


        def main(self):
            '''
                Main function entry point.
                Simulates two events to force detection of current document.

                Args:
                    None
                Returns:
                    None
            '''
            self.on_bufferactivated(None)
            self.on_updateui(None)

    EnhanceUDLLexer().main()

</code></pre>
]]></description><link>https://community.notepad-plus-plus.org/topic/17134/enhance-udl-lexer</link><generator>RSS for Node</generator><lastBuildDate>Thu, 16 Jul 2026 14:26:26 GMT</lastBuildDate><atom:link href="https://community.notepad-plus-plus.org/topic/17134.rss" rel="self" type="application/rss+xml"/><pubDate>Sun, 17 Feb 2019 13:38:48 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Enhance UDL lexer on Wed, 12 Jan 2022 18:48:09 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/c-siebester" aria-label="Profile: c-siebester">@<bdi>c-siebester</bdi></a></p>
<p dir="auto">The only pitfall I see at the moment might be that your UDL name is not ml but something else.<br />
When you run the script, do you see any errors in the console?<br />
I assume you copied the whole script and not just the part you mentioned here, right?<br />
If you click on the script from the Python script menu while holding down the CTRL key, will the expected script open in Npp?</p>
]]></description><link>https://community.notepad-plus-plus.org/post/72907</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/72907</guid><dc:creator><![CDATA[Ekopalypse]]></dc:creator><pubDate>Wed, 12 Jan 2022 18:48:09 GMT</pubDate></item><item><title><![CDATA[Reply to Enhance UDL lexer on Wed, 12 Jan 2022 15:33:59 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/ekopalypse" aria-label="Profile: ekopalypse">@<bdi>ekopalypse</bdi></a><br />
You’re right.  I changed it to the following.<br />
ml_regexes [(0, (0, 0, 224))] = (r’\d*‘, 0)<br />
ml_regexes [(1, (224, 0, 0))] = (r’\w*', 0)</p>
<p dir="auto">Obviously I have more interesting things I will want to match, I’m just trying to get it working.  I’m still not getting any highlighting in my test document with the hello and 12345.  Maybe I don’t have the setup right?</p>
]]></description><link>https://community.notepad-plus-plus.org/post/72898</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/72898</guid><dc:creator><![CDATA[c siebester]]></dc:creator><pubDate>Wed, 12 Jan 2022 15:33:59 GMT</pubDate></item><item><title><![CDATA[Reply to Enhance UDL lexer on Wed, 12 Jan 2022 07:52:19 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/c-siebester" aria-label="Profile: c-siebester">@<bdi>c-siebester</bdi></a> said in <a href="/post/72878">Enhance UDL lexer</a>:</p>
<p dir="auto">An error has crept in here that</p>
<pre><code class="language-py">ml_regexes = [(0, (0, 0, 224))] = (r’\d’, 0)
ml_regexes = [(1, (224, 0, 0))] = (r’\w’, 0)
</code></pre>
<p dir="auto">is not valid Python code, it must be like this</p>
<pre><code class="language-py">ml_regexes[(0, (0, 0, 224))] = (r’\d’, 0)
ml_regexes[(1, (224, 0, 0))] = (r’\w’, 0)
</code></pre>
<p dir="auto">If you open the PythonScript Console, this should also appear as an error when you run the script.</p>
<p dir="auto">Regarding match groups, we assume the following regular expression <code>\d\d\d</code>.<br />
This expression returns at most one match if it can find 3 consecutive digits. If the expression were <code>\d(\d)\d</code>, the regex engine would produce two matches, the standard match of the 3 digits and a second match of the middle digit. This is reflected by the number in the regular expression. If there is a 0, the standard match, which is always present if something is found, is determined and coloured. If there were a 1, only the 2nd match would be taken into account. Of course, only if there is a corresponding regular expression, as in my second example.</p>
<p dir="auto">Does that make sense?</p>
]]></description><link>https://community.notepad-plus-plus.org/post/72888</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/72888</guid><dc:creator><![CDATA[Ekopalypse]]></dc:creator><pubDate>Wed, 12 Jan 2022 07:52:19 GMT</pubDate></item><item><title><![CDATA[Reply to Enhance UDL lexer on Tue, 11 Jan 2022 18:26:14 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/ekopalypse" aria-label="Profile: ekopalypse">@<bdi>ekopalypse</bdi></a><br />
I have now had a chance to give this a solid go and have not been able to get it working.  To start with I installed the PythonScript plugin.</p>
<p dir="auto">In your comments I do not understand what is meant by  “d = integer, denotes which match group should be considered” because I’m not clear on what a match group does.</p>
<p dir="auto">I defined my own user defined language ml and then just tried to highlight letters in one color and digits in another.  I followed your examples and now have the following in the file:</p>
<p dir="auto">ml_regexes = _dict()<br />
ml_regexes = [(0, (0, 0, 224))] = (r’\d’, 0)<br />
ml_regexes = [(1, (224, 0, 0))] = (r’\w’, 0)<br />
ml_excluded_styles = []<br />
_enhance_lexer = EnhanceLexer()<br />
_enhance_lecer.register_lexer(‘ml’, ml_regexes, ml_excluded_styles)</p>
<p dir="auto">I saved the modified code as <a href="http://ml.py" rel="nofollow ugc">ml.py</a> in the folder C:\Users\CS_laptop\AppData\Roaming\Notepad++\plugins\config\PythonScript\scripts</p>
<p dir="auto">Then I made a new file to test with containing the following:<br />
hello<br />
12345</p>
<p dir="auto">I set language to the empty user defined language ml.<br />
Then I went to Plugins&gt;Python Scripts&gt;scripts&gt; and selected ml.<br />
This produced no result.</p>
<p dir="auto">Please let me know where I have gone wrong.  Thanks for your help.</p>
]]></description><link>https://community.notepad-plus-plus.org/post/72878</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/72878</guid><dc:creator><![CDATA[c siebester]]></dc:creator><pubDate>Tue, 11 Jan 2022 18:26:14 GMT</pubDate></item><item><title><![CDATA[Reply to Enhance UDL lexer on Tue, 04 Jan 2022 19:07:05 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/c-siebester" aria-label="Profile: c-siebester">@<bdi>c-siebester</bdi></a></p>
<p dir="auto">You must have installed the PythonScript plugin, which you can do via PluginAdmin in the plugin menu.</p>
<p dir="auto">Use plugins-&gt;pythonscript-&gt;new script and save it under a meaningful name. Copy the content from <a href="https://github.com/Ekopalypse/NppPythonScripts/blob/master/npp/EnhanceAnyLexer.py" rel="nofollow ugc">here</a> into the script.</p>
<p dir="auto">Save it. Now you need to define the regexes to add additional colours to the lexer. The script is commented, let me know if anything is unclear.</p>
]]></description><link>https://community.notepad-plus-plus.org/post/72639</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/72639</guid><dc:creator><![CDATA[Ekopalypse]]></dc:creator><pubDate>Tue, 04 Jan 2022 19:07:05 GMT</pubDate></item><item><title><![CDATA[Reply to Enhance UDL lexer on Tue, 04 Jan 2022 18:48:36 GMT]]></title><description><![CDATA[<p dir="auto">I found this and am quite interested in it but am not sure how to implement this.  I’m an engineer not a CS so my programing is only fair.  Can someone tell me how to actually use this in notepad++ or where to go to read what I will need to get it going?  Thanks</p>
]]></description><link>https://community.notepad-plus-plus.org/post/72637</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/72637</guid><dc:creator><![CDATA[c siebester]]></dc:creator><pubDate>Tue, 04 Jan 2022 18:48:36 GMT</pubDate></item><item><title><![CDATA[Reply to Enhance UDL lexer on Tue, 11 Feb 2020 18:55:57 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/haseneder" aria-label="Profile: Haseneder">@<bdi>Haseneder</bdi></a></p>
<p dir="auto">If this is still an issue for you, let me know.</p>
<p dir="auto">The idea of the script is to enhance the existing UDL<br />
with coloring which otherwise isn’t possible to do<br />
with the builtin lexer, means, script, normally,<br />
runs together with the UDL lexer.</p>
]]></description><link>https://community.notepad-plus-plus.org/post/50527</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/50527</guid><dc:creator><![CDATA[Ekopalypse]]></dc:creator><pubDate>Tue, 11 Feb 2020 18:55:57 GMT</pubDate></item><item><title><![CDATA[Reply to Enhance UDL lexer on Mon, 20 Jan 2020 17:07:44 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/ekopalypse" aria-label="Profile: Ekopalypse">@<bdi>Ekopalypse</bdi></a><br />
What is this script for, please ?<br />
I have come here, because I was looking up existing Notepad++ issues, have found this <a href="https://github.com/notepad-plus-plus/notepad-plus-plus/issues/7622" rel="nofollow ugc">https://github.com/notepad-plus-plus/notepad-plus-plus/issues/7622</a> and followed a link in a comment pointing to here.</p>
<p dir="auto">My problem is that I am trying to configure a UDL in Notebook++ for Jenkins Pipeline syntax,<br />
but the UDL lexer in Notepad++ does not find and colour string “stage” if there is “stage(”.</p>
<p dir="auto">Can I use your script to replace the Notepad++’ lexer ?</p>
<p dir="auto">BR<br />
Rainer<br />
<img src="/assets/uploads/files/1579540028282-notepadpp_keyword_stage_notfound.jpg" alt="NotepadPP_keyword_stage_NotFound.JPG" class=" img-fluid img-markdown" /></p>
]]></description><link>https://community.notepad-plus-plus.org/post/49980</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/49980</guid><dc:creator><![CDATA[Haseneder]]></dc:creator><pubDate>Mon, 20 Jan 2020 17:07:44 GMT</pubDate></item><item><title><![CDATA[Reply to Enhance UDL lexer on Tue, 19 Feb 2019 00:33:52 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/ekopalypse" aria-label="Profile: Ekopalypse">@<bdi>Ekopalypse</bdi></a></p>
<blockquote>
<p dir="auto">Hopefully this will be implemented soon.</p>
</blockquote>
<p dir="auto">my experience says this is rather “en attendant godot” or <a href="https://de.wikipedia.org/wiki/Warten_auf_Godot" rel="nofollow ugc">“warten auf godot”</a> ;-)</p>
]]></description><link>https://community.notepad-plus-plus.org/post/40027</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/40027</guid><dc:creator><![CDATA[Meta Chuh]]></dc:creator><pubDate>Tue, 19 Feb 2019 00:33:52 GMT</pubDate></item><item><title><![CDATA[Reply to Enhance UDL lexer on Tue, 19 Feb 2019 00:31:40 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/ekopalypse" aria-label="Profile: Ekopalypse">@<bdi>Ekopalypse</bdi></a> said:</p>
<blockquote>
<p dir="auto">I’ve opened two issues one here and one there to address this.</p>
</blockquote>
<p dir="auto">I don’t mean to be a debbie downer but good luck with the “there” one. The “here” one is much more likely to happen, although it seems that even PS development has slowed way down after being encouragingly active for a while.</p>
]]></description><link>https://community.notepad-plus-plus.org/post/40026</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/40026</guid><dc:creator><![CDATA[Alan Kilborn]]></dc:creator><pubDate>Tue, 19 Feb 2019 00:31:40 GMT</pubDate></item><item><title><![CDATA[Reply to Enhance UDL lexer on Tue, 19 Feb 2019 00:05:25 GMT]]></title><description><![CDATA[<p dir="auto">In order to be able to solve the issue about scrolling the second editor<br />
instance and having styling in it, it is needed to have a way to identify which<br />
scintilla instance sent which scintilla notification.<br />
This can be achieved by using the SCI_SETIDENTIFIER as described <a href="https://www.scintilla.org/ScintillaDoc.html#SCI_SETIDENTIFIER" rel="nofollow ugc">here</a>.</p>
<p dir="auto">I’ve opened two issues one <a href="https://github.com/bruderstein/PythonScript/issues/121" rel="nofollow ugc">here</a> and one <a href="https://github.com/notepad-plus-plus/notepad-plus-plus/issues/5327" rel="nofollow ugc">there</a> to address this.<br />
Hopefully this will be implemented soon.</p>
<p dir="auto">The issue about zooming and word wrap, actually it is a word wrap only issue,<br />
should be solved with this version, also the documentation fix is implemented ;-)</p>
<pre><code># -*- coding: utf-8 -*-

from Npp import editor, editor1, editor2, notepad, NOTIFICATION, SCINTILLANOTIFICATION, INDICATORSTYLE
import ctypes
import ctypes.wintypes as wintypes

from collections import OrderedDict
regexes = OrderedDict()

# ------------------------------------------------- configuration area ---------------------------------------------------
#
# Define the lexer name exactly as it can be found in the Language menu
lexer_name = 'BR! Source'

# Definition of colors and regular expressions
#   Note, the order in which regular expressions will be processed
#   is determined by its creation, that is, the first definition is processed first, then the 2nd, and so on
#
#   The basic structure always looks like this
#
#   regexes[(a, b)] = (c, d)
#
#   regexes = an ordered dictionary which ensures that the regular expressions are always processed in the same order
#   a = a unique number - suggestion, start with 0 and always increase by one
#   b = color in the form of (r,g,b) such as (255,0,0) for the color red
#   c = raw byte string, describes the regular expression. Example r'\w+'
#   d = number of the match group to be used


# Examples:
#   All found words which may consist of letter, numbers and the underscore,
#   with the exception of those that begin with fn, are displayed in a blue-like color.
#   The results from match group 1 should be used for this.
regexes[(0, (79, 175, 239))] = (r'fn\w+\$|(\w+\$)', 1)

#   All numbers are to be displayed in an orange-like color, the results from
#   matchgroup 0, the standard matchgroup, should be used for this.
regexes[(1, (252, 173, 67))] = (r'\d', 0)

# Definition of which area should not be styled
# 1 = comment style
# 2 = comment line style
# 16 = delimiter1
# ...
# 23 = delimiter8
excluded_styles = [1, 2, 16, 17, 18, 19, 20, 21, 22, 23]

# ------------------------------------------------ /configuration area ---------------------------------------------------

try:
    EnhanceUDLLexer().main()
except NameError:

    user32 = wintypes.WinDLL('user32')

    WM_USER = 1024
    NPPMSG = WM_USER+1000
    NPPM_GETLANGUAGEDESC = NPPMSG+84
    SC_INDICVALUEBIT = 0x1000000
    SC_INDICFLAG_VALUEFORE = 1


    class SingletonEnhanceUDLLexer(type):
        '''
            Ensures, more or less, that only one
            instance of the main class can be instantiated
        '''
        _instance = None
        def __call__(cls, *args, **kwargs):
            if cls._instance is None:
                cls._instance = super(SingletonEnhanceUDLLexer, cls).__call__(*args, **kwargs)
            return cls._instance


    class EnhanceUDLLexer(object):
        '''
            Provides additional color options and should be used in conjunction with the built-in UDL function.
            An indicator is used to avoid style collisions.
            Although the Scintilla documentation states that indicators 0-7 are reserved for the lexers,
            indicator 0 is used because UDL uses none internally.

            Even when using more than one regex, it is not necessary to define more than one indicator
            because the class uses the flag SC_INDICFLAG_VALUEFORE.
            See https://www.scintilla.org/ScintillaDoc.html#Indicators for more information on that topic
        '''
        __metaclass__ = SingletonEnhanceUDLLexer

        def __init__(self):
            '''
                Instantiated the class,
                because of __metaclass__ = ... usage, is called once only.
            '''
            editor.callbackSync(self.on_updateui, [SCINTILLANOTIFICATION.UPDATEUI])
            notepad.callback(self.on_langchanged, [NOTIFICATION.LANGCHANGED])
            notepad.callback(self.on_bufferactivated, [NOTIFICATION.BUFFERACTIVATED])
            self.doc_is_of_interest = False
            self.lexer_name = None
            self.npp_hwnd = user32.FindWindowW(u'Notepad++', None)
            self.configure()


        @staticmethod
        def rgb(r, g, b):
            '''
                Helper function
                Retrieves rgb color triple and converts it
                into its integer representation

                Args:
                    r = integer, red color value in range of 0-255
                    g = integer, green color value in range of 0-255
                    b = integer, blue color value in range of 0-255
                Returns:
                    integer
            '''
            return (b &lt;&lt; 16) + (g &lt;&lt; 8) + r


        @staticmethod
        def paint_it(color, pos, length):
            '''
                This is where the actual coloring takes place.
                Color, the position of the first character and
                the length of the text to be colored must be provided.
                Coloring occurs only if the position is not within the excluded range.

                Args:
                    color = integer, expected in range of 0-16777215
                    pos = integer,  denotes the start position
                    length = integer, denotes how many chars need to be colored.
                Returns:
                    None
            '''
            if pos &lt; 0 or editor.getStyleAt(pos) in excluded_styles:
                return
            editor.setIndicatorCurrent(0)
            editor.setIndicatorValue(color)
            editor.indicatorFillRange(pos, length)


        def style(self):
            '''
                Calculates the text area to be searched for in the current document.
                Calls up the regexes to find the position and
                calculates the length of the text to be colored.
                Deletes the old indicators before setting new ones.

                Args:
                    None
                Returns:
                    None
            '''
            start_line = editor.docLineFromVisible(editor.getFirstVisibleLine())
            end_line = editor.docLineFromVisible(start_line + editor.linesOnScreen())
            start_position = editor.positionFromLine(start_line)
            end_position = editor.getLineEndPosition(end_line)
            editor.setIndicatorCurrent(0)
            editor.indicatorClearRange(0, editor.getTextLength())
            for color, regex in self.regexes.items():
                editor.research(regex[0],
                                lambda m: self.paint_it(color[1],
                                                        m.span(regex[1])[0],
                                                        m.span(regex[1])[1] - m.span(regex[1])[0]),
                                0,
                                start_position,
                                end_position)


        def configure(self):
            '''
                Define basic indicator settings, the needed regexes as well as the lexer name.

                Args:
                    None
                Returns:
                    None
            '''
            editor1.indicSetStyle(0, INDICATORSTYLE.TEXTFORE)
            editor1.indicSetFlags(0, SC_INDICFLAG_VALUEFORE)
            editor2.indicSetStyle(0, INDICATORSTYLE.TEXTFORE)
            editor2.indicSetFlags(0, SC_INDICFLAG_VALUEFORE)
            self.regexes = OrderedDict([ ((k[0], self.rgb(*k[1]) | SC_INDICVALUEBIT), v) for k, v in regexes.items() ])
            self.lexer_name = u'User Defined language file - %s' % lexer_name


        def check_lexer(self):
            '''
                Checks if the current document is of interest
                and sets the flag accordingly

                Args:
                    None
                Returns:
                    None
            '''
            language = notepad.getLangType()
            length = user32.SendMessageW(self.npp_hwnd, NPPM_GETLANGUAGEDESC, language, None)
            buffer = ctypes.create_unicode_buffer(u' ' * length)
            user32.SendMessageW(self.npp_hwnd, NPPM_GETLANGUAGEDESC, language, ctypes.byref(buffer))
            self.doc_is_of_interest = True if buffer.value == self.lexer_name else False


        def on_bufferactivated(self, args):
            '''
                Callback which gets called every time one switches a document.
                Triggers the check if the document is of interest.

                Args:
                    provided by notepad object but none are of interest
                Returns:
                    None
            '''
            self.check_lexer()


        def on_updateui(self, args):
            '''
                Callback which gets called every time scintilla
                (aka the editor) changed something within the document.

                Triggers the styling function if the document is of interest.

                Args:
                    provided by scintilla but none are of interest
                Returns:
                    None
            '''
            if self.doc_is_of_interest:
                self.style()


        def on_langchanged(self, args):
            '''
                Callback gets called every time one uses the Language menu to set a lexer
                Triggers the check if the document is of interest

                Args:
                    provided by notepad object but none are of interest
                Returns:
                    None
            '''
            self.check_lexer()


        def main(self):
            '''
                Main function entry point.
                Simulates two events to enforce detection of current document
                and potential styling.

                Args:
                    None
                Returns:
                    None
            '''
            self.on_bufferactivated(None)
            self.on_updateui(None)

    EnhanceUDLLexer().main()

</code></pre>
]]></description><link>https://community.notepad-plus-plus.org/post/40024</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/40024</guid><dc:creator><![CDATA[Ekopalypse]]></dc:creator><pubDate>Tue, 19 Feb 2019 00:05:25 GMT</pubDate></item><item><title><![CDATA[Reply to Enhance UDL lexer on Mon, 18 Feb 2019 19:07:43 GMT]]></title><description><![CDATA[<p dir="auto">LOL :-D</p>
]]></description><link>https://community.notepad-plus-plus.org/post/40016</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/40016</guid><dc:creator><![CDATA[Ekopalypse]]></dc:creator><pubDate>Mon, 18 Feb 2019 19:07:43 GMT</pubDate></item><item><title><![CDATA[Reply to Enhance UDL lexer on Mon, 18 Feb 2019 19:06:38 GMT]]></title><description><![CDATA[<p dir="auto">thanks for the insight, <a class="plugin-mentions-user plugin-mentions-a" href="/user/ekopalypse" aria-label="Profile: Ekopalypse">@<bdi>Ekopalypse</bdi></a><br />
the combination of all, name, mishap at work, and this community, gives way to a perfect book title:</p>
<p dir="auto">… the holy apocalypse and his fantastic 4 riders … 😂😂👍</p>
]]></description><link>https://community.notepad-plus-plus.org/post/40015</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/40015</guid><dc:creator><![CDATA[Meta Chuh]]></dc:creator><pubDate>Mon, 18 Feb 2019 19:06:38 GMT</pubDate></item><item><title><![CDATA[Reply to Enhance UDL lexer on Mon, 18 Feb 2019 18:55:45 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/meta-chuh" aria-label="Profile: Meta-Chuh">@<bdi>Meta-Chuh</bdi></a></p>
<p dir="auto">well my name is eren and a nickname is eko.<br />
And you are absolutely right about apocalypse.<br />
In my first week at work, everyone learned that I could be called eko.<br />
At one time I did something terribly wrong which lead to an failure of the<br />
whole production system. My colleague said something like<br />
“this must be the feeling when the 4 apocalyptic riders arrive” and another one<br />
managed to make eko and apocalyptic to result in ekopalypse.<br />
So here comes the ekopalypse :-D</p>
]]></description><link>https://community.notepad-plus-plus.org/post/40013</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/40013</guid><dc:creator><![CDATA[Ekopalypse]]></dc:creator><pubDate>Mon, 18 Feb 2019 18:55:45 GMT</pubDate></item><item><title><![CDATA[Reply to Enhance UDL lexer on Mon, 18 Feb 2019 18:49:17 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/gerald-kirchner" aria-label="Profile: Gerald-Kirchner">@<bdi>Gerald-Kirchner</bdi></a></p>
<p dir="auto">starting from line <a href="https://github.com/notepad-plus-plus/notepad-plus-plus/blob/ef13902206f80e00dcfd7d85b342066ed6f86d66/scintilla/include/SciLexer.h#L266" rel="nofollow ugc">266</a>.</p>
]]></description><link>https://community.notepad-plus-plus.org/post/40012</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/40012</guid><dc:creator><![CDATA[Ekopalypse]]></dc:creator><pubDate>Mon, 18 Feb 2019 18:49:17 GMT</pubDate></item><item><title><![CDATA[Reply to Enhance UDL lexer on Mon, 18 Feb 2019 18:47:25 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/ekopalypse" aria-label="Profile: Ekopalypse">@<bdi>Ekopalypse</bdi></a></p>
<p dir="auto">omg … you are german speaking … that’s the last thing i would have expected … your name sounded so apocalyptically greek 😉</p>
]]></description><link>https://community.notepad-plus-plus.org/post/40011</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/40011</guid><dc:creator><![CDATA[Meta Chuh]]></dc:creator><pubDate>Mon, 18 Feb 2019 18:47:25 GMT</pubDate></item><item><title><![CDATA[Reply to Enhance UDL lexer on Mon, 18 Feb 2019 18:45:02 GMT]]></title><description><![CDATA[<p dir="auto">Ok, :-D</p>
<p dir="auto">the outcome of the discussion is that I need to post another version of the script<br />
which hopefully adresses <a class="plugin-mentions-user plugin-mentions-a" href="/user/guy038" aria-label="Profile: guy038">@<bdi>guy038</bdi></a>  findings as well,</p>
<p dir="auto">So dear future reader,<br />
if you have read until here - forget about everything you read and hope that you will find<br />
a new version of the script as another post after this one.<br />
:-D</p>
]]></description><link>https://community.notepad-plus-plus.org/post/40010</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/40010</guid><dc:creator><![CDATA[Ekopalypse]]></dc:creator><pubDate>Mon, 18 Feb 2019 18:45:02 GMT</pubDate></item><item><title><![CDATA[Reply to Enhance UDL lexer on Mon, 18 Feb 2019 18:43:44 GMT]]></title><description><![CDATA[<p dir="auto">In the source code I find the place where the numbers are assigned or do not arise.<br />
I would like to find that to be able to understand it.<br />
Then the template would have to be adjusted.</p>
]]></description><link>https://community.notepad-plus-plus.org/post/40009</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/40009</guid><dc:creator><![CDATA[Gerald Kirchner]]></dc:creator><pubDate>Mon, 18 Feb 2019 18:43:44 GMT</pubDate></item><item><title><![CDATA[Reply to Enhance UDL lexer on Mon, 18 Feb 2019 18:40:57 GMT]]></title><description><![CDATA[<p dir="auto">But thanks, <a class="plugin-mentions-user plugin-mentions-a" href="/user/alan-kilborn" aria-label="Profile: Alan-Kilborn">@<bdi>Alan-Kilborn</bdi></a>,</p>
<p dir="auto">Chrome used to be my backup browser, but I’ve recently switched to it being my primary, and I didn’t know there was an easy RClick&gt;Translate option in Chrome.  When I ran it on the German on this page, it translated okay for me.   (Which is good, because my 2 years of highschool German from more than a quarter-century ago just didn’t cut it.)</p>
<p dir="auto">But I do agree that the forum’s default language is English, and if people want help here, they should at least provide the translation for us.  I understand that some of the posters might be more comfortable (or equally comfortable) in German; and it’s fine for someone fluent in German to answer in German; but <em>also</em> provide a translation to English, so the other people who read this thread – both for those who have started to help, and got lost when it switched language; and for those who come here searching for a solution to a similar problem, and find that the actual answer is buried in another language, when it started in English.</p>
]]></description><link>https://community.notepad-plus-plus.org/post/40008</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/40008</guid><dc:creator><![CDATA[PeterJones]]></dc:creator><pubDate>Mon, 18 Feb 2019 18:40:57 GMT</pubDate></item><item><title><![CDATA[Reply to Enhance UDL lexer on Mon, 18 Feb 2019 18:38:20 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/alan-kilborn" aria-label="Profile: Alan-Kilborn">@<bdi>Alan-Kilborn</bdi></a></p>
<blockquote>
<p dir="auto">(AFAIK, the accepted language of this forum in English.)</p>
</blockquote>
<p dir="auto">maybe one accepted language as we see more often :-)</p>
]]></description><link>https://community.notepad-plus-plus.org/post/40007</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/40007</guid><dc:creator><![CDATA[Ekopalypse]]></dc:creator><pubDate>Mon, 18 Feb 2019 18:38:20 GMT</pubDate></item><item><title><![CDATA[Reply to Enhance UDL lexer on Mon, 18 Feb 2019 18:36:08 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/alan-kilborn" aria-label="Profile: Alan-Kilborn">@<bdi>Alan-Kilborn</bdi></a></p>
<p dir="auto">Manager summary :-)</p>
<p dir="auto">I failed at the documentation by stating that comment style is using id 2 and<br />
comment line style is using 1 whereas it is exactly the opposite.</p>
]]></description><link>https://community.notepad-plus-plus.org/post/40006</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/40006</guid><dc:creator><![CDATA[Ekopalypse]]></dc:creator><pubDate>Mon, 18 Feb 2019 18:36:08 GMT</pubDate></item><item><title><![CDATA[Reply to Enhance UDL lexer on Mon, 18 Feb 2019 18:35:42 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/ekopalypse" aria-label="Profile: Ekopalypse">@<bdi>Ekopalypse</bdi></a></p>
<p dir="auto">I’d say the burden is on posters to post in English, not others to translate later.  (AFAIK, the accepted language of this forum in English.)</p>
]]></description><link>https://community.notepad-plus-plus.org/post/40005</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/40005</guid><dc:creator><![CDATA[Alan Kilborn]]></dc:creator><pubDate>Mon, 18 Feb 2019 18:35:42 GMT</pubDate></item><item><title><![CDATA[Reply to Enhance UDL lexer on Mon, 18 Feb 2019 18:33:48 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/alan-kilborn" aria-label="Profile: Alan-Kilborn">@<bdi>Alan-Kilborn</bdi></a></p>
<p dir="auto">:-D<br />
<a href="https://www.deepl.com/translator" rel="nofollow ugc">https://www.deepl.com/translator</a></p>
]]></description><link>https://community.notepad-plus-plus.org/post/40004</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/40004</guid><dc:creator><![CDATA[Ekopalypse]]></dc:creator><pubDate>Mon, 18 Feb 2019 18:33:48 GMT</pubDate></item><item><title><![CDATA[Reply to Enhance UDL lexer on Mon, 18 Feb 2019 18:34:14 GMT]]></title><description><![CDATA[<p dir="auto">English, anyone?</p>
<p dir="auto">Normally I wouldn’t complain, except Chrome right-click Translate to English failed on this.</p>
]]></description><link>https://community.notepad-plus-plus.org/post/40003</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/40003</guid><dc:creator><![CDATA[Alan Kilborn]]></dc:creator><pubDate>Mon, 18 Feb 2019 18:34:14 GMT</pubDate></item></channel></rss>