• Login
Community
  • Login

Alternative method of UDL association that file suffix possible?

Scheduled Pinned Locked Moved Help wanted · · · – – – · · ·
6 Posts 2 Posters 806 Views
Loading More Posts
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S
    Sam Marrocco
    last edited by Sep 14, 2023, 4:12 PM

    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 2

    Script2.mscript file contains
    Command 2
    Command 3

    I’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 2

    Script2.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?

    P 1 Reply Last reply Sep 14, 2023, 4:48 PM Reply Quote 0
    • P
      PeterJones @Sam Marrocco
      last edited by Sep 14, 2023, 4:48 PM

      @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:

      1. Look at first line for #UDL=mscript\d, and extract the digit
      2. set up your array of possible keywords based on that digit
      3. use a similar search-through-the-file command to what was in EnhanceAnyLexer (ie, calling editor.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.

      S 1 Reply Last reply Sep 15, 2023, 1:22 PM Reply Quote 3
      • S
        Sam Marrocco @PeterJones
        last edited by Sep 15, 2023, 1:22 PM

        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
        End

        Still beyond the scope?

        P 1 Reply Last reply Sep 15, 2023, 3:31 PM Reply Quote 0
        • P
          PeterJones @Sam Marrocco
          last edited by PeterJones Sep 15, 2023, 3:32 PM Sep 15, 2023, 3:31 PM

          @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.

          S P 2 Replies Last reply Sep 15, 2023, 3:51 PM Reply Quote 1
          • S
            Sam Marrocco @PeterJones
            last edited by Sep 15, 2023, 3:51 PM

            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.

            1 Reply Last reply Reply Quote 0
            • P
              PeterJones @PeterJones
              last edited by Sep 17, 2023, 10:25 PM

              I previously said,

              [I’ll] give it a try

              This is what I came up with:

              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:

              1. 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
              2. Save
              3. 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

              1 Reply Last reply Reply Quote 4
              • P PeterJones referenced this topic on Sep 17, 2023, 10:25 PM
              • E Ekopalypse referenced this topic on Oct 19, 2023, 11:18 AM
              4 out of 6
              • First post
                4/6
                Last post
              The Community of users of the Notepad++ text editor.
              Powered by NodeBB | Contributors