Community
    • Login

    Function List and PL/SQL packages

    Scheduled Pinned Locked Moved Help wanted · · · – – – · · ·
    29 Posts 5 Posters 35.7k Views 3 Watching
    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.
    • Claudia FrankC Offline
      Claudia Frank
      last edited by

      second part

      def current_regex():
          return editor2.getCurLine().rstrip()
      
      # -----------------------------------------------------------------------------
      
      def regex_tester_doc_is_current_doc():
          return REGEX_TESTER_INPUT_TAB == notepad.getCurrentBufferID()
      
      # -----------------------------------------------------------------------------
      
      def scroll_to_position(_position):
          if _position is not None:
              start_pos, end_pos = _position
              editor1.setIndicatorCurrent(13)
              editor1.indicatorFillRange(start_pos, end_pos-start_pos)
              current_line = editor1.lineFromPosition(start_pos)
              editor1.ensureVisible(current_line)
              editor1.gotoPos(start_pos)
              editor1.verticalCentreCaret()
              editor1.setXCaretPolicy(CARETPOLICY.EVEN|CARETPOLICY.JUMPS,10)
              editor1.scrollCaret()
      
      # -----------------------------------------------------------------------------
      
      def get_current_regex_position_and_length():
          current_line = editor2.lineFromPosition(editor2.getCurrentPos())
          if current_line != 0 and not editor2.getLine(current_line).startswith(COMMENT_CHAR):
              lenght_line = editor2.lineLength(current_line)
              position = editor2.positionFromLine(current_line)
              return position, lenght_line
          return None, None
      
      # -----------------------------------------------------------------------------
      
      def mark_regex_line(match_indicator):
          position, lenght = get_current_regex_position_and_length()
          if position:
              if match_indicator == REGEX_LINE_NO_MATCH:
                      editor2.setIndicatorCurrent(14)
                      editor2.indicatorFillRange(position, lenght)
              elif match_indicator == REGEX_LINE_INVALID:
                  editor2.setIndicatorCurrent(11)
                  editor2.indicatorFillRange(position, lenght)
              else:
                  for i in [11,14]:
                      editor2.setIndicatorCurrent(i)
                      editor2.indicatorClearRange(0, editor2.getTextLength())
      
      # -----------------------------------------------------------------------------
      
      def regex_tester_updateui_callback(args):
          if (regex_tester_doc_is_current_doc() and PREVIOUS_REGEX.get(CURRENT_BUFFER_ID, '') != current_regex()):
              mark_regex_line(REGEX_LINE_CLEAR)
              regex()
              if NO_MATCH_FOUND and INFORM_ABOUT_NO_MATCHES:
                  mark_regex_line(REGEX_LINE_NO_MATCH)
              elif NO_MATCH_FOUND is None:
                  mark_regex_line(REGEX_LINE_INVALID)
              # else:
                  # scroll_to_position(POS_FIRST_OCCURANCE)
      # -----------------------------------------------------------------------------
      
      def regex_tester_file_before_close_callback(args):
          if (args['bufferID'] == REGEX_TESTER_INPUT_TAB):
              stop_regex_tester()
      
      # -----------------------------------------------------------------------------
      
      def regex_tester_buffer_activated_callback(args):
          global PREVIOUS_REGEX
          set_current_buffer_id()
      
          if not PREVIOUS_REGEX.has_key(CURRENT_BUFFER_ID):
              PREVIOUS_REGEX[CURRENT_BUFFER_ID] = ''
      
          if not REGEX_TESTER_IS_RUNNING:
              global COLORED_DOCS_LIST
              if args['bufferID'] in COLORED_DOCS_LIST:
                  clear_indicator()
                  COLORED_DOCS_LIST.remove(args['bufferID'])
      
              if len(COLORED_DOCS_LIST) == 0:
                  notepad.clearCallbacks([NOTIFICATION.BUFFERACTIVATED])
      
      # -----------------------------------------------------------------------------
      
      def jump_through_matches(search_direction):
          global MATCH_POSITIONS
          global LAST_POSITION
      
          if MATCH_POSITIONS.has_key(CURRENT_BUFFER_ID):
              editor1.setIndicatorCurrent(13)
              editor1.indicatorClearRange(0,editor1.getTextLength())
      
              match_count = len(MATCH_POSITIONS[CURRENT_BUFFER_ID])
      
              if match_count == 0:
                  return
      
              elif match_count == 1:
                  _position = MATCH_POSITIONS[CURRENT_BUFFER_ID][0]
      
              else:
                  current_position = editor1.getCurrentPos()
      
                  if search_direction == 0:
                      while True:
                          _position = MATCH_POSITIONS[CURRENT_BUFFER_ID].pop(0)
                          MATCH_POSITIONS[CURRENT_BUFFER_ID].append(_position)
      
                          if _position[0] != LAST_POSITION:
                              break
                  else:
                      while True:
                          _position = MATCH_POSITIONS[CURRENT_BUFFER_ID].pop()
                          MATCH_POSITIONS[CURRENT_BUFFER_ID].insert(0, _position)
      
                          if _position[0] != LAST_POSITION:
                              break
      
              LAST_POSITION = _position[0]
              scroll_to_position(_position)
      
      # -----------------------------------------------------------------------------
      
      def regex_tester_doc_already_exists():
          files = notepad.getFiles()
          f = [i[1][1] for i in enumerate(files) if i[1][0].upper() == TEMP_FILE_NAME.upper()]
          if f:
              return f[0]
          else:
              return 0
      
      # -----------------------------------------------------------------------------
      
      def color_regex_tester_status():
          status_line = editor2.getLine(0)
          if REGEX_TESTER_IS_RUNNING:
              start = status_line.find('[')
              stop = status_line.find(']')+1
              editor2.setIndicatorCurrent(12)
              editor2.indicatorFillRange(0,20)
              editor2.setIndicatorCurrent(12)
              editor2.indicatorFillRange(start,stop-start)
          else:
              editor2.setIndicatorCurrent(12)
              editor2.indicatorClearRange(0,len(status_line))
      
      # -----------------------------------------------------------------------------
      
      def start_regex_tester():
          if TEMP_FILE_NAME == '':
              notepad.messageBox('You need to indicate, in the TEMP_FILE_NAME variable,\n' +
                                 'the fully qualified file name of the TEXT file containing ' +
                                 'the REGEX(ES) to test', 'TEMP_FILE_NAME is not set')
              return False
      
          current_document = 0 if notepad.getCurrentView() == 1 else notepad.getCurrentBufferID()
      
          global REGEX_TESTER_INPUT_TAB
          REGEX_TESTER_INPUT_TAB = regex_tester_doc_already_exists()
          if REGEX_TESTER_INPUT_TAB == 0 :
              notepad.open(TEMP_FILE_NAME)
              if notepad.getCurrentFilename().upper() == TEMP_FILE_NAME.upper():
                  REGEX_TESTER_INPUT_TAB = notepad.getCurrentBufferID()
              else:
                  notepad.messageBox('Could not open specified file\n' +
                                     '{0}'.format(TEMP_FILE_NAME),
                                     'Regex Tester Startup Failed', 0)
                  return False
          else:
              notepad.activateBufferID(REGEX_TESTER_INPUT_TAB)
      
          if notepad.getCurrentView() != 1:
              notepad.menuCommand(MENUCOMMAND.VIEW_GOTO_ANOTHER_VIEW)
      
          STATUS_LINE = 'RegexTester isActive [] flags:sitp, '
      
          STATUS_LINE += 'fwd:{}  bwd:{}\r\n'.format(JUMP_FORWARD_SHORTCUT,
                                                     JUMP_BACKWARD_SHORTCUT,)
      
          current_status_line = editor2.getLine(0)
          if 'RegexTester' in current_status_line:
              editor2.replace('RegexTester inActive', 'RegexTester isActive')
          else:
              editor2.insertText(0, STATUS_LINE)
      
      
          global REGEX_TESTER_IS_RUNNING
          REGEX_TESTER_IS_RUNNING = True
      
          color_regex_tester_status()
      
          set_current_buffer_id()
      
          global PREVIOUS_REGEX
          PREVIOUS_REGEX[CURRENT_BUFFER_ID] = ''
      
          editor.callbackSync(regex_tester_updateui_callback, [SCINTILLANOTIFICATION.UPDATEUI])
      
          if current_document != 0:
              notepad.activateBufferID(current_document)
      
          editor2.setFocus(True)
          editor2.gotoLine(0)
          notepad.save()
      
          global REGEX_TESTER_HWND
          REGEX_TESTER_HWND = get_focused_window()
      
          notepad.callback(regex_tester_file_before_close_callback, [NOTIFICATION.FILEBEFORECLOSE])
          notepad.callback(regex_tester_buffer_activated_callback, [NOTIFICATION.BUFFERACTIVATED])
      
          return True
      
      # -----------------------------------------------------------------------------
      
      def stop_regex_tester():
          editor.clearCallbacks([SCINTILLANOTIFICATION.UPDATEUI])
          notepad.clearCallbacks([NOTIFICATION.FILEBEFORECLOSE])
      
          notepad.activateBufferID(REGEX_TESTER_INPUT_TAB)
      
          if regex_tester_doc_is_current_doc():
              editor2.replace('RegexTester isActive', 'RegexTester inActive')
              notepad.save()
      
          global REGEX_TESTER_IS_RUNNING
          REGEX_TESTER_IS_RUNNING = False
      
          clear_indicator()
          color_regex_tester_status()
          mark_regex_line(0)
      
          global MATCH_POSITIONS
          MATCH_POSITIONS = {}
      
          _hook.unregister()
      
          editor1.setFocus(True)
      
      # -----------------------------------------------------------------------------
      
      class Hook():
      
          def __init__(self):
              self.nppHandle = windll.user32.FindWindowA('Notepad++',None)
              self.oldWndProc = None
      
              self.SHIFT_PRESSED = False
              self.CTRL_PRESSED = False
              self.ALT_PRESSED = False
      
          def register(self):
              if REGEX_TESTER_HWND:
                  self.new_wnd_proc = WndProcType(self.sciWndProc)
                  windll.kernel32.SetLastError(0)
                  self.oldWndProc = windll.user32.SetWindowLongA(REGEX_TESTER_HWND, GWL_WNDPROC, self.new_wnd_proc)
      
                  if self.oldWndProc:
                      global OLD_WND_PROC
                      OLD_WND_PROC = self.oldWndProc
                  else:
                      _err = 'GetLastError:{}'.format(windll.kernel32.GetLastError())
                      notepad.messageBox('Could not register hook:\n{}\n'.format(_err) +
                                          'Shortcuts won\'t work',
                                          'Register Hook Failure', 0)
      
          def unregister(self):
              if OLD_WND_PROC:
                  self.oldWndProc = OLD_WND_PROC
                  windll.kernel32.SetLastError(0)
                  dummy = windll.user32.SetWindowLongA(REGEX_TESTER_HWND, GWL_WNDPROC, self.oldWndProc)
                  if not dummy:
                      _err = 'GetLastError:{}'.format(windll.kernel32.GetLastError())
                      notepad.messageBox('Could not unregister hook:\n{}\n'.format(_err) +
                                          'It is recommended to save data and restart npp to prevent data loss',
                                          'Unregister Hook Failure', 0)
      
          def sciWndProc(self, hWnd, msg, wParam, lParam):
              if msg in [WM_KEYDOWN, WM_SYSKEYDOWN]:
                  if wParam == VK_SHIFT:
                      self.SHIFT_PRESSED = True
                  elif wParam == VK_CONTROL:
                      self.CTRL_PRESSED = True
                  elif wParam == VK_ALT:
                      self.ALT_PRESSED = True
      
              elif msg in [WM_KEYUP,WM_SYSKEYUP]:
                  if wParam == VK_SHIFT:
                      self.SHIFT_PRESSED = False
                  elif wParam == VK_CONTROL:
                      self.CTRL_PRESSED = False
                  elif wParam == VK_ALT:
                      self.ALT_PRESSED = False
                  else:
                      modifier = 'SHIFT+' if self.SHIFT_PRESSED else ''
                      modifier += 'CTRL+' if self.CTRL_PRESSED else ''
                      modifier += 'ALT+' if self.ALT_PRESSED else ''
                      if wParam in FUNC_KEYS:
                          key_combo = '{}{}'.format(modifier,FUNC_KEYS[wParam])
                      else:
                          key_combo = '{}{}'.format(modifier,chr(wParam))
      
                      func = dict_func.get(key_combo, None)
                      if func:
                          func()
      
              elif msg == WM_KILLFOUCS:
                  self.SHIFT_PRESSED = False
                  self.CTRL_PRESSED = False
                  self.ALT_PRESSED = False
      
              return windll.user32.CallWindowProcA (self.oldWndProc, hWnd, msg, wParam, lParam)
      
      # -----------------------------------------------------------------------------
      
      def main():
          if REGEX_TESTER_IS_RUNNING:
              stop_regex_tester()
          else:
              if start_regex_tester():
                  _hook.register()
      
      # -----------------------------------------------------------------------------
      
      dict_func={JUMP_FORWARD_SHORTCUT  : lambda: jump_through_matches(FORWARD_SEARCH),
                 JUMP_BACKWARD_SHORTCUT : lambda: jump_through_matches(BACKWARD_SEARCH),}
                 # JUMP_TO_FIRST_SHORTCUT : lambda: scroll_to_position(POS_FIRST_OCCURANCE),
                 # JUMP_TO_LAST_SHORTCUT  : lambda: scroll_to_position(POS_LAST_OCCURANCE)}
      
      
      _hook = Hook()
      main()
      
      1 Reply Last reply Reply Quote 0
      • MAPJe71M Offline
        MAPJe71
        last edited by

        Thanx!
        Will give it a try.

        Claudia FrankC 1 Reply Last reply Reply Quote 0
        • Claudia FrankC Offline
          Claudia Frank @MAPJe71
          last edited by

          @MAPJe71

          one other thing.
          The script doesn’t rerun the same regexes. Meaning,
          if one line has

          ^def.*()
          

          and the next line also and you move the cursor from the first to the next line
          it doesn’t trigger another research. There must be a difference within the regexes.

          Cheers
          Claudia

          1 Reply Last reply Reply Quote 0
          • Claudia FrankC Offline
            Claudia Frank
            last edited by Claudia Frank

            One thing I forgot to mention,
            special thanks to Scott and Guy which provided
            a lot of information and doing beta testing.
            Without there patient it wouldn’t be what it is.

            THANK YOU!!
            Claudia

            1 Reply Last reply Reply Quote 1
            • Jean-Marc MalmedyJ Offline
              Jean-Marc Malmedy @MAPJe71
              last edited by

              @MAPJe71 said:

              Although my regular expressions work in RegexBuddy I’m not able to get them to show any packages in Notepad++ Function List.
              This needs more investigation, sorry I can’t give you a solution any time soon :(

              I’m not surprised since my regular expression worked too outside Function List.
              Anyway, thank you very much for trying.

              1 Reply Last reply Reply Quote 0
              • MAPJe71M Offline
                MAPJe71
                last edited by

                @Jean-Marc-Malmedy after using @Claudia-Frank 's (thanks Claudia, awesome script!) script I was able to create a working parser. Needs some fine tuning/cleaning though.

                1 Reply Last reply Reply Quote 0
                • MAPJe71M Offline
                  MAPJe71
                  last edited by

                  @Jean-Marc-Malmedy could you try this one:

                  			<parser
                  				displayName="SQL-mehods"
                  				id         ="sql_syntax"
                  				commentExpr="(?x)                                               # Utilize inline comments (see `RegEx - Pattern Modifiers`)
                  								(?s:\x2F\x2A.*?\x2A\x2F)                        # Multi Line Comment
                  							|	(?m-s:-{2}.*$)                                  # Single Line Comment
                  							"
                  			>
                  				<classRange
                  					mainExpr    ="(?x)                                          # Utilize inline comments (see `RegEx - Pattern Modifiers`)
                  							(?mi)                                               # case insensitive
                  							^\h*                                                # optional leading blanks
                  							CREATE\s+(?:OR\s+REPLACE\s+)?PACKAGE\s+(?:BODY\s+)? # start-of-package indicator
                  							(?:\w+\.)?                                          # schema name, optional
                  							(?'PACKAGE_ID'\w+)                                  # package name
                  							(?s:.*?)                                            # whatever, until...
                  							^\h*END(?:\s+\k'PACKAGE_ID')?\s*;                   # ...end-of-package indicator
                  						"
                  				>
                  					<className>
                  						<nameExpr expr="(?i:PACKAGE\s+(?:BODY\s+)?)\K(?:\w+\.)?\w+" />
                  					</className>
                  					<function
                  						mainExpr="^\h*(?i:FUNCTION|PROCEDURE)\s+\K\w+\s*\([^()]*\)"
                  					>
                  						<functionName>
                  							<funcNameExpr expr="\w+" />
                  						</functionName>
                  					</function>
                  				</classRange>
                  				<function
                  					mainExpr="^\h*(?i:FUNCTION|PROCEDURE)\s+\K\w+\s*\([^()]*\)"
                  				>
                  					<functionName>
                  						<nameExpr expr="\w+" />
                  					</functionName>
                  				</function>
                  			</parser>
                  
                  1 Reply Last reply Reply Quote 0
                  • Jean-Marc MalmedyJ Offline
                    Jean-Marc Malmedy
                    last edited by

                    Wonderful, it works.

                    I just had to make to small modifications:

                    • making the parenthesis optional for the declaration of function or procedure
                    • starting the declaration of a function or procedure outside a package with “create or replace”

                    This is my final version of the parser:

                            <parser
                                displayName="SQL-mehods"
                                id         ="sql_syntax"
                                commentExpr="(?x)                                               # Utilize inline comments (see `RegEx - Pattern Modifiers`)
                                                (?s:\x2F\x2A.*?\x2A\x2F)                        # Multi Line Comment
                                            |   (?m-s:-{2}.*$)                                  # Single Line Comment
                                            "
                            >
                                <classRange
                                    mainExpr    ="(?x)                                          # Utilize inline comments (see `RegEx - Pattern Modifiers`)
                                            (?mi)                                               # case insensitive
                                            ^\h*                                                # optional leading blanks
                                            CREATE\s+(?:OR\s+REPLACE\s+)?PACKAGE\s+(?:BODY\s+)? # start-of-package indicator
                                            (?:\w+\.)?                                          # schema name, optional
                                            (?'PACKAGE_ID'\w+)                                  # package name
                                            (?s:.*?)                                            # whatever, until...
                                            ^\h*END(?:\s+\k'PACKAGE_ID')?\s*;                   # ...end-of-package indicator
                                        "
                                >
                                    <className>
                                        <nameExpr expr="(?i:PACKAGE\s+(?:BODY\s+)?)\K(?:\w+\.)?\w+" />
                                    </className>
                                    <function
                                        mainExpr="^\h*(?i:FUNCTION|PROCEDURE)\s+\K\w+\s*(\([^()]*\)){0,1}"
                                    >
                                        <functionName>
                                            <funcNameExpr expr="\w+" />
                                        </functionName>
                                    </function>
                                </classRange>
                                <function
                                    mainExpr="^\h*CREATE\s+(?:OR\s+REPLACE\s+)?(?i:FUNCTION|PROCEDURE)\s+\K\w+\s*(\([^()]*\)){0,1}"
                                >
                                    <functionName>
                                        <nameExpr expr="\w+" />
                                    </functionName>
                                </function>
                            </parser>
                    

                    Many many thanks for your help.

                    Jean-Marc

                    1 Reply Last reply Reply Quote 0
                    • MAPJe71M Offline
                      MAPJe71
                      last edited by

                      @Jean-Marc-Malmedy FYI: {0,1} can be replaced with a ?.

                      1 Reply Last reply Reply Quote 0
                      • Jean-Marc MalmedyJ Offline
                        Jean-Marc Malmedy
                        last edited by

                        Yes, indeed. Thanks for the suggestion.

                        1 Reply Last reply Reply Quote 0
                        • MAPJe71M Offline
                          MAPJe71
                          last edited by

                          You’re welcome!

                          1 Reply Last reply Reply Quote 0
                          • Gábor MadácsG Offline
                            Gábor Madács
                            last edited by Gábor Madács

                            HI! Wonderful, I came here for this… :D

                            I have tried his solution, but immediately bumped into a serious problem:
                            I can see only the first method in my package. :(

                            if i understand correctly, the classRange - mainExpr should match for the whole package body.
                            I think the problem lies here at the last line:

                            ^\h*END(?:\s+\k'PACKAGE_ID')?\s*;
                            

                            this matches the first “end;” in the code.

                            In a real-world code there is lots of “end;” statements, as we can close methods with it, and even there is unnamed blocks inside them.

                            Example:

                            CREATE OR REPLACE PACKAGE BODY sch_001.pck_001 AS
                              PROCEDURE p_proc_001(pn_id PLS_INTEGER) IS
                                sd date;
                              BEGIN
                                 -- unnamed block begin: "try-catch" in PL/SQL
                                 begin
                                    select sysdate into sd from dual;
                                 exception when others then
                                     sd := null;
                                 end;
                                 -- do something else
                              END;
                            END pck_001;
                            /
                            

                            Please help me on this.
                            Unfortunately I’m not really familiar with greedy multi-line regexp statements…

                            For start, it would be OK, if it could end only on the end of file…

                            It would be a huge help for us! :)

                            MAPJe71M 1 Reply Last reply Reply Quote 0
                            • MAPJe71M Offline
                              MAPJe71 @Gábor Madács
                              last edited by

                              @Gábor-Madács
                              I don’t understand your problem.

                              1 Reply Last reply Reply Quote 0
                              • Gábor MadácsG Offline
                                Gábor Madács
                                last edited by

                                Thank you for the quick response!

                                Your results are better than mine… :)

                                What parser do you use? This is by the one from the last post from Jean-Marc Malmedy.
                                I have also tried the one before this - posted by you - that is showed the second procedure too, but out of the body.
                                (That’s because of here no “CREATE” in the procedure name - that is a difference between the two version. “CREATE” is for procedures not in packages.)

                                Please post your fine parser version! :)

                                Gabor

                                MAPJe71M 1 Reply Last reply Reply Quote 0
                                • MAPJe71M Offline
                                  MAPJe71 @Gábor Madács
                                  last edited by

                                  @Gábor-Madács See my post on GitHub.

                                  1 Reply Last reply Reply Quote 0
                                  • Gábor MadácsG Offline
                                    Gábor Madács
                                    last edited by

                                    @MAPJe71 Wow… Thank you very much! :D
                                    (May I note, now the “I don’t understand your problem.” seems somewhat unfounded… ;) )

                                    Work like a charm! (Looks like a charm, indeed… ;) )

                                    Hope, it will be part of the official NPP distribution!

                                    Thank you again!

                                    Gabor

                                    1 Reply Last reply Reply Quote 0
                                    • Marco GonzalezM Offline
                                      Marco Gonzalez
                                      last edited by

                                      Beautiful work! But i have a little bit problem.
                                      When the procedure or function name is missing after the “end”, it seems the parser consumes the file to the end skipping other functions!

                                      Example:
                                      function foo is
                                      Begin
                                      –Todo function logic…
                                      null;
                                      End;

                                      function bar is…

                                      In this case function bar (and other functions after it) will be skipped! I know it is not the best practice but it’s pretty common.
                                      although it’s simple to fix that on the source code I will appreciate your help to fix the parser.

                                      Thanks in advance!

                                      1 Reply Last reply Reply Quote 0
                                      • Marco GonzalezM Offline
                                        Marco Gonzalez
                                        last edited by

                                        Hi guys, after a few little changes it seems to work now for all my Plsql files…
                                        <?xml version=“1.0” encoding=“UTF-8” ?>
                                        <!-- ==========================================================================\

                                        To learn how to make your own language parser, please check the following
                                        link:
                                        https://npp-user-manual.org/docs/function-list/

                                        |
                                        =========================================================================== -->
                                        <NotepadPlus>
                                        <functionList>
                                        <!-- ========================================================= [ PL/SQL ] -->
                                        <parser
                                        displayName=“SQL-mehods”
                                        id =“sql_syntax”
                                        commentExpr=“(?x) # Utilize inline comments (see RegEx - Pattern Modifiers)
                                        (?s:\x2F\x2A.?\x2A\x2F) # Multi Line Comment
                                        | (?m-s:-{2}.
                                        $) # Single Line Comment
                                        " >
                                        <classRange
                                        mainExpr =”(?x) # Utilize inline comments (see RegEx - Pattern Modifiers)
                                        (?mi) # case insensitive
                                        ^\h* # optional leading blanks
                                        (CREATE\s+(?:OR\s+REPLACE\s+)?)?PACKAGE\s+(?:BODY\s+)? # start-of-package indicator
                                        (?:\w+.)? # schema name, optional
                                        (?‘PACKAGE_ID’\w+) # package name
                                        (?s:.?) # whatever, until…
                                        ^\h
                                        END(?:\s+\k’PACKAGE_ID’)\s*; # …end-of-package indicator
                                        " >
                                        <className><nameExpr expr=“(?i:PACKAGE\s+(?:BODY\s+)?)\K(?:\w+.)?\w+” /></className>
                                        <function mainExpr=“^\h*(?i:FUNCTION|PROCEDURE)\s+\K\w+\s*(([^()]))?“>
                                        <functionName><funcNameExpr expr=”\w+" /></functionName>
                                        </function>
                                        </classRange>
                                        <function mainExpr="^\h
                                        (CREATE\s+(?:OR\s+REPLACE\s+)?)?(?i:FUNCTION|PROCEDURE)\s+\K\w+\s*(([^()]*))?” >
                                        <functionName><nameExpr expr=“\w+” /></functionName>
                                        </function>
                                        </parser>
                                        </functionList>
                                        </NotepadPlus>

                                        I also indented it my own way, sorry for that, enjoy it!

                                        1 Reply Last reply Reply Quote 1

                                        Hello! It looks like you're interested in this conversation, but you don't have an account yet.

                                        Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

                                        With your input, this post could be even better 💗

                                        Register Login
                                        • First post
                                          Last post
                                        The Community of users of the Notepad++ text editor.
                                        Powered by NodeBB | Contributors