UDL highlight hex numbers



  • In my language every single number is by default treated as hexadecimal, no prefix or suffix needed. num,bers can be strictly LOWERCASE numbers, everything else is treated as variable. I’d like to detect and highlight these numbers. When it comes to operators, no space is necessary, so making: D=e a totally valid state. Hexadecimal numbers can have question mark (as wildcard) as part of them, so actually I can treat them as a valid hex character (it would be even better and amazing to handle differently, so I could use different color for wildcards).

    I’ve tried every combination I could using the UDL GUI, but I couldn’t find a well-working version which works in every case.

    Do you have any good idea how could I achieve this highlighting? Or is it impossible to do with UDL?

    Thanks a lot!



  • @Unc3nZureD

    It sounds like one of those areas which aren’t possible to solve by UDL but I have to admit that
    I didn’t fully understand how your language works.

    A.) Do you mind sharing some examples of how it is and should look like?
    B.) I have something in mind which would involve pythonscript plugin.Would you be interested in?
    If yes, I would need, again, some example data for testing.



  • Sure. It’s mostly some custom and private thing, which I can’t fully reveal (company related), but I’ll try to give some example which might make you understand some basics.

    ; Comment. These all are checks if variable D equals to the hex number given on the right
    D==de07ed76            ; 0xde07ed76    
    D==e                   ; 0xe
    D == 123               ; 0x123   - note that spaces doesn't matter
    
    ; This is some pattern finding code. Everything is treated as hex and ?? marks are allowed. Note that spaces are UNNECESSARY and OPTIONAL here.
    [3ff] (
        68 ?? ?? 40 00   
      )
    

    I hope you can more or less understand me now :)

    I’ve never tried pythonscripted plugin, but sure, if it’s interesting, then why not? :)



  • Being back to work, partially, lunch break over :-)
    Will come back later this day



  • So what I was thinking about is to use the UDL as the main lexer while
    using this script to do additional colorings.
    To use this script you need to install PythonScript plugin, create a new script,
    paste content from below, safe it.

    Then modify it to your needs - see configure section for more details.
    Basically add/modify the regexes and more important modify the lexer name

    self.lexer_name = 'User Defined language file'

    Once done, save it and run it. It should, hopefully, go hand ind hand with your UDL
    I have added two regular expressions just to show you how it can be extended.
    From the problem given, I assume you only need the second one.

    from Npp import editor, notepad, NOTIFICATION, SCINTILLANOTIFICATION, INDICATORSTYLE
    import ctypes
    import ctypes.wintypes as wintypes
    
    from collections import OrderedDict
    
    try:
        EnhanceUDLLexer().main()
    except NameError:
    
        user32 = wintypes.WinDLL('user32')
    
        WM_USER = 1024
        NPPMSG = WM_USER+1000
        NPPM_GETLANGUAGEDESC = NPPMSG+84
    
    
        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
    
            @staticmethod
            def rgb(r,g,b):
                return (b << 16) + (g << 8) + r
    
    
            @staticmethod
            def paint_it(color, pos, length):
                editor.setIndicatorCurrent(0)
                editor.setIndicatorValue(color)
                editor.indicatorFillRange(pos, length)
    
    
            def style(self):
                start_line = editor.getFirstVisibleLine()
                end_line = 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,
                                    lambda m: self.paint_it(color[1], m.span()[0], m.span()[1] - m.span()[0]),
                                    0,
                                    start_position,
                                    end_position)
    
    
            def configure(self):
                SC_INDICVALUEBIT = 0x1000000
                SC_INDICFLAG_VALUEFORE = 1
                editor.indicSetFore(0, (181, 188, 201))
                editor.indicSetStyle(0, INDICATORSTYLE.TEXTFORE)
                editor.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(79, 175, 239)  | SC_INDICVALUEBIT)] = r'\b([A-F0-9]+[\s\?]*)+\b'
                self.regexes[(1, self.rgb(189, 102, 216) | SC_INDICVALUEBIT)] = r'\b([a-f0-9]+[\s\?]*)+\b'
    
                # defining the lexer_name ensures that
                # only this type of document get stlyed
                # should be the same name as displayed in first field of statusbar
                self.lexer_name = 'User Defined language file'
    
    
    
            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
                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 = None
                self.npp_hwnd = user32.FindWindowW(u'Notepad++', None)
                self.configure()
    
    
            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
                else:
                    self.__is_lexer_doc = False
    
    
            def on_updateui(self, args):
                if self.__is_lexer_doc:
                    self.style()
    
    
            def on_langchanged(self, args):
                self.set_lexer_doc(True if self.get_lexer_name() == self.lexer_name else False)
    
    
            def main(self):
                self.set_lexer_doc(True)
                self.style()
    
    
        EnhanceUDLLexer().main()
    

Log in to reply