UDL: /* block comment in one line, error */

  • Hello, I’ve been working to get UDL set up for DSM4COM.cfg (pavgmbh.de) files.

    ;line comment, ok
    name = "test" ;inline comment, ok
    block comment, ok
    /* block comment in one line, error */

    I found nothing working with ((EOL)). Even with delimiter style not.

  • welcome to the notepad++ community, @Gerald-Kirchner

    if i set the block comment start to /* and stop to */, block comments work as they are supposed to, as seen at this screenshot
    (the udl comment settings are shown there too):


    to clarify what you mean by end of line at comment blocks, it is best if you export your udl to a separate xml file and post it here.
    (or make a screenshot of all your relevant settings)

    also a longer code sample would help, as well as your debug information.
    (? > debug info... > copy debug info to clipboard)

    many thanks in advance

  • Thanks for the answer. That makes everything green.
    I do not want to color one-line comments with /* */ green. Better red.
    I can not separate the two variants.

    <Keywords name="Comments">00; 01 02 03/*((EOL)) 04((EOL))*/</Keywords>
    <Keywords name="Delimiters">00/* 01 02*/ 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23</Keywords>


    Notepad++ v7.6.2 (64-bit)
    Build time : Jan 1 2019 - 00:02:38
    Path : C:\Program Files\Notepad++\notepad++.exe
    Admin mode : OFF
    Local Conf mode : OFF
    OS : Windows 10 (64-bit)
    Plugins : DSpellCheck.dll mimeTools.dll NppConverter.dll

  • @Gerald-Kirchner

    i am deeply sorry, that i made the comments green, as you did not give any information about that at forehand, and i am not yet able to read your mind 😉

    now serious:
    you just have to remove the ((EOL)) and leave /* and */ only, as seen at my screenshot above.
    a sequence of /*((EOL)) will only be triggered, if you have exactly this string in a line.
    a rule like /*((EOL)) will only be triggered by a line that contains /* and nothing else.
    (if the next character after /* is not a line feed, it will not be triggered as a comment block start, because you defined this rule that way, by stating, that the next character has to be ((EOL)))

  • @Gerald-Kirchner

    for the sake of your eyes and for the fun of it: here are the comments in red 😉😂


    side note: you don’t need to put /* and */ at the delimiter section at all, just at the block comment section.

    it is recommended never to use the same strings on different udl styler elements, as the rules will usually only be triggered once, and only by the styler with the highest priority, which will lead to nearly unpredictable results, especially when nested.

  • We talk past each other. Now again with a detailed description of the goal. The colors are easy to set.

    block comment, several lines, green
    /* block comment, several lines, green
    block comment, several lines, green */
    /* block comment in one line, forbidden, red */

  • @Gerald-Kirchner

    i apologise, i’ve misread the line

    I do not want to color one-line comments with /* */ green. Better red.

    which clearly states that only one line comment blocks should be red, sorry about that.

    yes, this is more tricky, if you want to differentiate them.

  • The variants 2 and 3 would not matter to me when marking. Important is variant 1 good and variant 4 bad. At least one EOL is good.
    I had to wait because as a new user I can only write every 20 minutes.

  • @Gerald-Kirchner

    I had to wait because as a new user I can only write every 20 minutes.

    this restriction will disappear shortly, it’s a necessary and automatic spam prevention.

    unfortunately i’ve reached the end of my knowledge on if it can be done, and how to do that if it can be done.

    first because the udl’s styler rules work as cases, so once a case is found, they will not look if any other styler rule can be applied (except nesting rules)

    second because ((EOL)) can apparently only be used as a stand alone item, and not be used as part of a string.

    third because udl does not have any negation or cascaded rules like “must be more than one line” or “trigger if x is found, but not if y is missing”.

    i hope that one of our community’s udl gurus or devs will read this thread in the next few days and finds a trick to solve this specific problem.

    if it eases a bit: at least i finally understand exactly what you need, regarding one line block comments and using ((EOL)) as part of a styler/delimiter string 😉

  • Examples at https://ivan-radic.github.io/udl-documentation/keywords/ will suggest

    /*\r\n    or    /*\r    or    /*\n

    in keywords must work for /*(CR)(LF). That does not work.

  • @Gerald-Kirchner

    i’ve played around a bit with the pythonscript plugin to add/compensate this feature to the dsm4com udl and i think i got it working the way you need.

    block-comments in a single line are marked red, but all other line or block-comments are kept green.

    here is a screenshot:


    please tell us, if you need help installing or using the pythonscript plugin.

    here’s the script, to be used as pythonscript startup script:

    # -*- coding: utf-8 -*-
    from Npp import editor, editor1, editor2, notepad, NOTIFICATION, SCINTILLANOTIFICATION, INDICATORSTYLE
    import ctypes
    import ctypes.wintypes as wintypes
    from collections import OrderedDict
    except NameError:
        user32 = wintypes.WinDLL('user32')
        WM_USER = 1024
        NPPMSG = WM_USER+1000
        class SingletonEnhanceUDLLexer(type):
            _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):
            __metaclass__ = SingletonEnhanceUDLLexer
            def rgb(r,g,b):
                return (b << 16) + (g << 8) + r
            def paint_it(color, pos, length):
                if pos >= 0:
                    editor.indicatorFillRange(pos, length)
            def style(self):
                start_line = editor.getFirstVisibleLine()
                # fix: The area which needs to be styled is wrongly calculated if there are folded parts within this area (Eko palypse)
                # end_line = start_line + editor.linesOnScreen()
                end_line = editor.docLineFromVisible(start_line + editor.linesOnScreen())
                start_position = editor.positionFromLine(start_line)
                end_position = editor.getLineEndPosition(end_line)
                editor.indicatorClearRange(0, editor.getTextLength())
                for color, regex in self.regexes.items():
                                    lambda m: self.paint_it(color[1],
                                                            m.span(regex[1])[1] - m.span(regex[1])[0]),
            def configure(self):
                SC_INDICVALUEBIT = 0x1000000
                SC_INDICFLAG_VALUEFORE = 1
                # editor.indicSetFore(0, (181, 188, 201))
                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()
                # configuration area
                # self.regexes is a dictionary, basically a key=value list
                # the key is tuple starting with an increasing number and
                # the color which should be used, ored with SC_INDICVALUEBIT
                # the value is a raw bytestring which is the regex whose
                # matches get styled with the previously defined color
                # using OrderedDict ensures that the regex will be
                # always executed in the same order.
                # This might matter if more than one regex is used.
                self.regexes[(0, self.rgb(255, 50, 50)  | SC_INDICVALUEBIT)] = (r'^\/\*(.*?)\*\/$', 0)
                # self.regexes[(1, self.rgb(79, 175, 239)  | SC_INDICVALUEBIT)] = (r'([A-Za-z0-9_]+?\$)', 1)
                # defining the lexer_name ensures that
                # only this type of document get styled
                # should be the same name as displayed in first field of statusbar
                # self.lexer_name = 'udf - DSM4COM'
            def get_lexer_name(self):
                    returns the text which is shown in the
                    first field of the statusbar
                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 lexername in configure should look like - npp restart needed
                return buffer.value
            def __init__(self):
                editor.callbackSync(self.on_updateui, [SCINTILLANOTIFICATION.UPDATEUI])
                notepad.callback(self.on_langchanged, [NOTIFICATION.LANGCHANGED])
                notepad.callback(self.on_bufferactivated, [NOTIFICATION.BUFFERACTIVATED])
                self.__is_lexer_doc = False
                self.lexer_name = 'User Defined language file - DSM4COM'
                self.npp_hwnd = user32.FindWindowW(u'Notepad++', None)
            def set_lexer_doc(self, bool_value):
                editor.setProperty(self.__class__.__name__, 1 if bool_value is True else -1)
                self.__is_lexer_doc = bool_value
            def on_bufferactivated(self, args):
                if (self.get_lexer_name() == self.lexer_name) and (editor.getPropertyInt(self.__class__.__name__) != -1):
                    self.__is_lexer_doc = True
                    self.__is_lexer_doc = False
            def on_updateui(self, args):
                if self.__is_lexer_doc:
            def on_langchanged(self, args):
                self.set_lexer_doc(True if self.get_lexer_name() == self.lexer_name else False)
            def main(self):

  • @Meta-Chuh said:

    self.lexer_name = ‘udf - DSM4COM’

    this would only be returned when using notepad.getLanguageName(notepad.getLangType()) but
    the script uses windows/notepad API functions which means it should return something
    like User Defined language file - DSM4COM
    I guess you’ve already saw it but there is a little bug in the style function, as described here.

  • @Eko-palypse

    thanks, i’m not very experienced in python and the pythonscript plugin, but after your modified suffix script, i thought i give it a try and do the same for this older, unsolved thread.

    now that you are here, i have two more questions that you might be able to answer:

    why is it called udf - MyUDL if we use notepad.getLanguageName(), and not udl - MyUDL ?

    how do you kill a running pythonscript without restarting notepad++ ?

    1. Because. My guess is that at one point, it was “user defined format” or something similar in someone’s mind.
    2. Plugins > PythonScript > Stop Script

  • thanks @PeterJones

    1. at first i thought UDF was a typo while coding, but the keys L and F are too far apart for that, unless it happened when hitting the D at the edge to F, triggering both, resulting in UDFL, followed by backspacing the L instead of deleting the F.

    2. this just stops a sequentially running script, but not event handlers or callbacks like this EnhanceUDLLexer.
      is it impossible to stop those without exiting notepad++, as this event handler kind of just passes all its specs to scintilla, which processes the rest, without any further involvement of pythonscript ?

  • @Meta-Chuh said:

    1. Notepad++ internals see here
    2. High level view
      Here we have to define what a running script means.
      PS is a kind of python REPL like the standard python shell
      which runs when you start python on the commandline.
      The difference is that every script starts in a separate thread,
      but those will, if no endless loop is written, end, normally, shortly after the start.
      Callbacks are responsible that it looks like the script is still running.
      The reason is that PS (python) remembers that there are objects (callbacks) that can not yet be destroyed
      and therefore continue to live in this REPL and then be accessed by PS if necessary.
      So to “end” this script, which is already finished, completely, it is needed
      to terminate the callbacks, which means to destory its references to these objects.
      This will be done with editor/notepad.clearCallbacks methods.
      The topic is of course a lot more complex than I’ve explained briefly but basically you can say
      no matter what kind of script is started, if PS did not show up in the menu Stop Script it ended.
      If this also means that functionality is still running.

    I hope this makes sense to you.

  • I do not get Python Script in the Plugins menu.
    First installed plugin manager. Then error message when installing Python Script:
    “A file needed by the plugin manager (gpup.exe) is not present under the updater directory. You should update or reinstall the Plugin Manager plugin to fix this problem. Notepad++ will not restart.”
    Manual copy as described in PythonScript.chm did not work either.
    Then completely uninstalled and deleted all leftovers in %ProgramFiles% and %appdata%.
    npp.7.6.3.bin.x64.7z and PythonScript_Full_1. unpacked in the same directory. It does not work.

  • @Gerald-Kirchner

    unfortunately plugin installation is a little bit of a mess at the moment.
    Would you mind posting your current debug-info from ?-menu
    and in the meantime extract the PythonScript_Full_1. to a folder of your choice.

    Once we know how your current setup looks like we can give the information what needs
    to be copied/moved where to.

  • @Eko-palypse

    As described fresh portable installation.
    “npp.7.6.3.bin.x64.7z” and “PythonScript_Full_1.” unpacked in the same directory.

    Notepad++ v7.6.3 (64-bit)
    Build time : Jan 27 2019 - 17:16:47
    Path : D:\Daten\PortableApps\Notepad++\notepad++.exe
    Admin mode : OFF
    Local Conf mode : ON
    OS : Windows 10 (64-bit)
    Plugins : DSpellCheck.dll mimeTools.dll NppConverter.dll

  • @Gerald-Kirchner said:

    Local Conf mode : ON

    Local Conf mode : ON tells us, that the local install directory
    is searched for the plugins and configs.

    This means, from the extracted PythonScript folder copy
    the plugins folder into D:\Daten\PortableApps\Notepad++\
    which basically asks for overwritting the plugins folder.

    The move the file PythonScript.dll from

    Finally copy the python27.dll from the extracted 7z into

    layout should be


    Restart npp and you should see PythonScript plugin in the menu

Log in to reply