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!
-
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 nameself.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()