Alternative method of UDL association that file suffix possible?
-
I’ve written a scripting ‘language’ whose text files end with “.mscript”.
I use a variation of this scripting language in several applications that i have written, and use Notepad++ to edit those scripts.Each applications uses an ‘.mscript’ file, and each application’s script commands can vary, but the suffix for the files remains the same. For example:
Script1.mscript file contains
Command1
Command 2Script2.mscript file contains
Command 2
Command 3I’d prefer not to have a single UDL for Mscript, containing Commands 1-4, since I only want those commands highlighted for the specific app in which they are used. Short of using a different file suffix (i.e. .mscript1, .mscript2) to differentiate between the languages, I’m wondering is there is some manner to associate the UDL used with the contents of a file rather than the file’s suffix. For example using a keyword, such as a define or pragma, along these lines:
Assuming I have two UDLs, named “Mscript_for_Application1” and MScript_for_Application2", my files would look like this:
Script1.mscript file contains
#UDL=mscript1
Command1
Command 2Script2.mscript file contains
#UDL=mscript2
Command 2
Command 3…allowing the UDL to be selected based upon a keyword within the script, instead of the named suffix of the file.
Possible, or is there another alternative?
-
@Sam-Marrocco said in Alternative method of UDL association that file suffix possible?:
I’m wondering is there is some manner to associate the UDL used with the contents of a file rather than the file’s suffix
Sorry, that’s way beyond the scope of UDL. UDL is very basic syntax highlighting. If you want more complicated lexing (including context-aware lexing like you’re suggesting), it is intended that you either write a full lexer plugin, or write a script (using one of the Scripting Plugins, like the PythonScript plugin) that essentially does lexing.
Forum regular @Ekopalypse published a script called
EnhanceAnyLexer.py
for the PythonScript plugin that would do additional highlighting on top of the standard highlighting for the active UDL or builtin lexer, which he converted into a full-blown plugin EnhanceAnyLexer – so you could look at the source for the script to see a possible way to add your own highlighting using a script, and you can look at the source for the plugin to see how those same concepts get turned into a full-blown plugin.If I were to do this, I would write a script for the PythonScript plugin: I would use the logic/wrappers from
EnhanceAnyLexer.py
to set up the callbacks to be run at the right time, and then I would define the algorithm to be used inside the callback as follows:- Look at first line for
#UDL=mscript\d
, and extract the digit - set up your array of possible keywords based on that digit
- use a similar search-through-the-file command to what was in
EnhanceAnyLexer
(ie, callingeditor.research(regex, lambda-or-callback-function, ...)
), but instead of searching based on a regex read from the .ini file, you would be searching to match one of the keywords. The lambda or callback function would be what “paints” the highlighting on your keywords
But essentially, any solution is going to require a lot of effort on your part, because what you’re asking for is highly custom behavior.
- Look at first line for
-
Thank you for the feedback. I may have over-complicated my description a bit…I don’t actually wish to change the UDL system itself at all; only the option for how a given UDL is chosen for the current file: I wish to have the UDL that Notepad++ is using for a script be ‘picked’ based upon a line (the first line?) in the file that is loaded, so it isn’t determined by the file type suffix.
It seemed relatively simple (it always does when I haven’t written the code) since the file is already being read by NP, to check for a line of type and then change the NP UDL being used to a different existing UDL.
I was thinking along the lines of new code (or a script?) that is read at file loading…
If line 1=#SET_NP_UDL=“MScriptA”
Set_CurrentUDLSelection to SET_NP_UDL
EndStill beyond the scope?
-
@Sam-Marrocco said in Alternative method of UDL association that file suffix possible?:
It seemed relatively simple (it always does when I haven’t written the code)
At least you admit the parenthetical. Most people stop before that, which annoys people who have added code to Notepad++ (or who know programming in other environments), and know how much more difficult it always ends up being than the requestor thinks it will be.
to check for a line of type and then change the NP UDL being used to a different existing UDL.
Notepad++ already has a similar feature for certain built-in lexers (having an XML declaration, or a shebang line, will trigger the appropriate lexer) – but that’s mostly doable because there are a limited number, and those specific strings are known at compile time, rather than being arbitrary user-defined strings. I could imagine how it might possibly be implemented (a new option in Defined Your Language for a First Line Indicator String , which would populate an internal mapping of string-to-UDL-type, and then the logic would have to iterate through all of those mappings as well as through the built-in shebang/declaration checks). So it’s technically possible – but since I don’t know the ins-and-outs of Notepad++ code specifically or GUI/user-interface coding in general, there are probably a lot of things I haven’t considered, which would complicate matters.
But now comes the killer: the developers haven’t added new features to UDL in the seven years since I’ve been involved in the Notepad++ Community, and there are dozens of open UDL feature requests, many of which would be much more usable to the vast majority of UDL users than this more-niche request. I mean, you could put in an official feature request (as described in our FAQ), but I wouldn’t hold my breath while waiting for it to be implemented.
(or a script?) that is read at file loading
Yes, this sort of thing is quite doable in the script, as I suggested above, and that doesn’t require convincing the developers to implement a new feature.
However, unlike your phrasing, it’s not just at load (because of the way the lexing is done, the lexer is re-applied every time to switch into the tab or bring the tab forward into view, because it’s only the active tab that gets lexing updated); and that’s what the wrapper stuff in the
EnhanceAnyLexer.py
is doing – triggering the re-lexing every time the tab is activated.At this point, you’ve piqued my interest enough that as I have free time, I might start looking into creating an
SelectUdlBasedOnShebang.py
script. I guarantee no timeline, and I don’t guarantee that you’d be happy with the result, but I will probably at least give it a try. -
I appreciate your potential efforts, thank you.
Yes, a Load event was the first thing I was thinking would trigger it, but I can see where a tab change (and other) events might also need to watched.
There are no guarantees anyone will be happy when it comes to code, are there? ;)
Please let me know if I can provide any assistance testing.
-
I previously said,
[I’ll] give it a try
This is what I came up with:
INSTALLATION
- Follow the instructions https://community.notepad-plus-plus.org/topic/23039/faq-desk-how-to-install-and-run-a-script-in-pythonscript
to install PythonScript Plugin and save this script asSelectUDLBasedOnShebang.py
- You will want to follow the “Starutp script” instructions in that FAQ as well, with the following two lines
import SelectUDLBasedOnShebang selectUDLBasedOnShebang = SelectUDLBasedOnShebang.SelectUDLBasedOnShebang()
CONFIGURE:
- Go to the line with “CONFIG =” and edit the contents
- the extension should include the dot in the quotes
- the firstLineText is the text that should match the “shebang” line (the first line of your file)
- the NameOfUDL must match the name of your UDL exactly
- Save
- Run the script (Plugins > Python Script > Scripts > SelectUDLBasedOnShebang) or restart Notepad++
SCRIPT:
SelectUDLBasedOnShebang.py
# encoding=utf-8 """in response to https://community.notepad-plus-plus.org/topic/24921/alternative-method-of-udl-association-that-file-suffix-possible If the extension is right, and the shebang line is right, set to a specific UDL INSTALLATION 1. Follow the instructions https://community.notepad-plus-plus.org/topic/23039/faq-desk-how-to-install-and-run-a-script-in-pythonscript to install PythonScript Plugin and save this script as `SelectUDLBasedOnShebang.py` 2. You will want to follow the "Starutp script" instructions in that FAQ as well, with the following two lines import SelectUDLBasedOnShebang selectUDLBasedOnShebang = SelectUDLBasedOnShebang.SelectUDLBasedOnShebang() CONFIGURE: Go to the line with "CONFIG =" and edit the contents - the extension should include the dot in the quotes - the firstLineText is the text that should match the "shebang" line (the first line of your file) - the NameOfUDL must match the name of your UDL exactly Save Run the script (Plugins > Python Script > Scripts > SelectUDLBasedOnShebang) From now on (including after restart), anytime you activate the buffer of a file ending with a known extension (one of the extensions in CONFIG), it will look at the first line, and if the first line exactly matches one of the firstLineText strings in the CONFIG table, then it will activate the UDL that has exactly the NameOfUdl """ from Npp import editor,notepad,console,NOTIFICATION import os class SelectUdlBasedOnShebang(object): CONFIG = { ".mscript" : { # the extension, including the . "#UDL!mscript1": "mscript1", # firstLineText : NameOfUDL "#UDL!mscript2": "mscript2", # firstLineText : NameOfUDL }, ".ext" : { # the extension, including the . "#UDL!ext1": "ext1", # firstLineText : NameOfUDL "#UDL!ext2": "ext2", # firstLineText : NameOfUDL }, } def __init__(self): '''Initialize the new instance''' current_version = notepad.getPluginVersion() if current_version < '2.0.0.0': notepad.messageBox('It is needed to run PythonScript version 2.0.0.0 or higher', 'Unsupported PythonScript verion: {}'.format(current_version)) return # setup callbacks notepad.callback(self.on_bufferactivated, [NOTIFICATION.BUFFERACTIVATED]) console.write("Registered on_bufferactivated callback for SelectUdlBasedOnShebang\n" ) # run the initial check self.check_for_udl(notepad.getCurrentBufferID()) def on_bufferactivated(self, args): ''' This callback called every time document is switched. Triggers the check if the document is of interest. Args: provided by notepad object; the args of interest: args['bufferID']: ID for the activated buffer Return: Nothing ''' self.check_for_udl(args['bufferID']) def check_for_udl(self, bufferID): ''' Check if the active buffer has a known extension for shebang processing If so, trigger the UDL-change Args: bufferID: ID for the buffer of interest Return: Nothing ''' filename = notepad.getBufferFilename(bufferID) (_,ext) = os.path.splitext(filename) if ext in self.CONFIG: self.check_shebang( self.CONFIG[ext] ) def check_shebang(self, shebangs): ''' Check if the active buffer has the right shebang If so, set teh UDL Args: shebangs: dict mapping shebang to corresponding UDL name Return: Nothing ''' firstLine = editor.getLine(0).rstrip(); if firstLine in shebangs: found = shebangs[firstLine] notepad.runMenuCommand('Language', found) if __name__ == '__main__': selectUdlBasedOnShebang = SelectUdlBasedOnShebang()
If I do any more development on this, updated versions can be found at https://github.com/pryrt/nppStuff/blob/main/pythonScripts/nppCommunity/24xxx/24921_SelectUDLBasedOnShebang.py
- Follow the instructions https://community.notepad-plus-plus.org/topic/23039/faq-desk-how-to-install-and-run-a-script-in-pythonscript
-
-