Community
    • Login

    Replace 1 + lines?

    Scheduled Pinned Locked Moved General Discussion
    43 Posts 7 Posters 34.1k 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.
    • Claudia FrankC
      Claudia Frank @guy038
      last edited by

      @guy038, @scott-sumner

      Hi Guy,

      sorry, family celebration was a bit longer than expected.
      Just did the script and some basic tests and discovered that encoding
      is an issue like Scott already mentioned.
      Will try to find a way to make it work regardless which encoding is used.

      Cheers
      Claudia

      1 Reply Last reply Reply Quote 0
      • guy038G
        guy038
        last edited by

        Hi, @claudia-frank,

        Don’t worry, Claudia and just enjoy these family’s moments ! Luckily, we, all, own more valuable things than Notepad++ and some Python scripts :-D

        …I’m just thinking about actualities and the death’s celebration of Helmut Kohl. Thanks to him and some important European women and men, we all enjoy, in Europe, a peace period, of near 75 years ! and THIS, it’s a basic point !!

        Best Regards,

        guy038

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

          From my basic tests it looks like it should do the trick.
          Tested utf-8, ansi, winows-1250, winows-1251 and winows-1252.
          It works only with normal selection - not with column mode selection.

          import ctypes
          from ctypes.wintypes import BOOL, HWND, LPARAM
          
          WNDENUMPROC = ctypes.WINFUNCTYPE(BOOL, HWND, LPARAM)
          
          FindWindow = ctypes.windll.user32.FindWindowW
          FindWindowEx = ctypes.windll.user32.FindWindowExW
          SendMessage = ctypes.windll.user32.SendMessageW
          EnumChildWindows = ctypes.windll.user32.EnumChildWindows
          GetClassName = ctypes.windll.user32.GetClassNameW
          GetWindowText = ctypes.windll.user32.GetWindowTextW
          GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW
          SetWindowText = ctypes.windll.user32.SetWindowTextW
          GetACP = ctypes.windll.kernel32.GetACP
          create_unicode_buffer = ctypes.create_unicode_buffer
          
          replace_tab_caption  = u'Replace'
          replacewith_caption = u'Rep&lace with :'
          replacewith_is_next_ctrl = False
          replacewith_handle = None
          replacewith_text = None
          findwhat_caption = u'&Find what :'
          findwhat_is_next_ctrl = False
          findwhat_handle = None
          findwhat_text = None
          
          
          def EnumCallback(hwnd, lparam):
              global replacewith_is_next_ctrl
              global findwhat_is_next_ctrl
              global replacewith_handle
              global findwhat_handle
              curr_class = create_unicode_buffer(256)
              GetClassName(hwnd, curr_class, 256)
              length = GetWindowTextLength(hwnd)
              buff = ctypes.create_unicode_buffer(length + 1)
              GetWindowText(hwnd, buff, length + 1)
              if curr_class.value.lower() == 'static':
                  if buff.value == replacewith_caption:
                      replacewith_is_next_ctrl = True
                  elif buff.value == findwhat_caption:
                      findwhat_is_next_ctrl = True
              elif curr_class.value.lower() == 'edit':
                  if findwhat_is_next_ctrl:
                      findwhat_handle = hwnd
                      findwhat_is_next_ctrl = False
                  elif replacewith_is_next_ctrl:
                      replacewith_handle = hwnd
                      replacewith_is_next_ctrl = False
                      return False  # stop enumeration
              return True  # let enumeration continue
          
          def return_proper_string(selected_text):
              if notepad.getEncoding() == BUFFERENCODING.ENC8BIT:
                  _selected_text = unicode(selected_text, '{}'.format(GetACP()))
              else:
                  _selected_text = unicode(selected_text, 'utf-8')
              return _selected_text
          
          def main():
              msg = ''
              if editor.getSelections() == 2:
                  if editor.getSelectionMode() == 0 and not editor.getSelectionEmpty():
                      _find_what = editor.getTextRange(editor.getSelectionNStart(0), editor.getSelectionNEnd(0))
                      _replace_with = editor.getTextRange(editor.getSelectionNStart(1), editor.getSelectionNEnd(1))
          
                      if len(_find_what) > 2046:
                          _find_what = _find_what[:2046]
                          msg += 'Warning:  Selected text too long for find-what box; truncating to 2046 characters.  '
                              
                      if len(_replace_with) > 2046:
                          _replace_with = _replace_with[:2046]
                          msg += 'Warning:  Selected text too long for replace-with box; truncating to 2046 characters.  '
                                                  
                      notepad.menuCommand(MENUCOMMAND.SEARCH_REPLACE)
                      find_dialog_hwnd = FindWindow(None, replace_tab_caption)
                      
                      if find_dialog_hwnd:
                          EnumChildWindows(find_dialog_hwnd, WNDENUMPROC(EnumCallback), 0)
                          if findwhat_handle and replacewith_handle:
                              if SetWindowText(findwhat_handle, return_proper_string(_find_what)) == 0:
                                  msg += 'Error:  Problem setting find-what text'
                              if SetWindowText(replacewith_handle, return_proper_string(_replace_with)) == 0:
                                  msg += 'Error:  Problem setting replace-with text'
                          else:
                              msg += 'Error:  Bad value for replacewith_handle'
                      else:
                          msg += 'Error:  Bad value for find_dialog_hwnd'
                  else:
                      msg += 'Error:  Either empty selection or unsupported selection mode detected'
              else:
                  msg += 'Warning:  Only two selections are possible. Received:{}'.format(editor.getSelections())
              if len(msg) > 0: notepad.messageBox(msg)
          
          main()
          

          Cheers
          Claudia

          1 Reply Last reply Reply Quote 0
          • guy038G
            guy038
            last edited by guy038

            Hello, @claudia-frank,

            What to say else ? Just wonderful and awesome, indeed !!!

            I already tested the case of rectangular selection(s) and the upper limit of 2046 characters => No problem, it acts as expected :-)


            Now, as always, when building a program, there’s a small bug with the lower limit of 0 character !

            I, successively, tried to make an empty search selection, then an empty replace selection and, finally, both search and replace selections empty.

            Note : To obtain, physically, a zero-length selection, I just select one character with the mouse, then move back the mouse, with a possible hit on the CTRL key, to only get the caret

            Results :

            • If both selections are empty, the message Error: Either empty selection or unsupported selection mode detected occurs, as expected. Nice !

            • If, ONLY, the search selection is empty, the Find/Replace opens normally. May be, in that case, Claudia, a message would be better !

            • If, ONLY, the replace selection is empty, the Find/Replace opens normally, with the Find what: box filled and the Replace with: empty. That the expected behaviour, in order to delete all the search blocks of text found

            I also noticed that if I Ctrl + click and select some text, ONLY, it is, logically, inserted in the Replace with box, leaving the Find what: box empty :-D

            But, if I, simply, click, without the Ctrl key, and select some text, the message Warning: Only two selections are possible. Received:1 occurs. However, Claudia, I think it’s a valid case.

            So, in the case of a normal selection 0, only, the Find/Replace dialog should pop up and contain :

            • A Find what: box, filled with the selection contents

            • A Replace with: box, wiped out of any [previous] character

            Best Regards,

            guy038

            P.S. :

            I found out something weird, but logic : If I build a one-line rectangular selection, this selection is correctly written in the Find what: box !!

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

              @guy038

              Guy, here the updated one.
              A “one-selection” action results in opening the standard replace dialog behavior.
              A “two-selections” action, even with an empty one, results in modifying the fields.
              I see it as a benefit that you are able to decide that only one of the fields should be filled
              and the other should be empty in any case.

              import ctypes
              from ctypes.wintypes import BOOL, HWND, LPARAM
              
              WNDENUMPROC = ctypes.WINFUNCTYPE(BOOL, HWND, LPARAM)
              
              FindWindow = ctypes.windll.user32.FindWindowW
              FindWindowEx = ctypes.windll.user32.FindWindowExW
              SendMessage = ctypes.windll.user32.SendMessageW
              EnumChildWindows = ctypes.windll.user32.EnumChildWindows
              GetClassName = ctypes.windll.user32.GetClassNameW
              GetWindowText = ctypes.windll.user32.GetWindowTextW
              GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW
              SetWindowText = ctypes.windll.user32.SetWindowTextW
              GetACP = ctypes.windll.kernel32.GetACP
              create_unicode_buffer = ctypes.create_unicode_buffer
              
              replace_tab_caption  = u'Replace'
              replacewith_caption = u'Rep&lace with :'
              replacewith_is_next_ctrl = False
              replacewith_handle = None
              replacewith_text = None
              findwhat_caption = u'&Find what :'
              findwhat_is_next_ctrl = False
              findwhat_handle = None
              findwhat_text = None
              
              
              def EnumCallback(hwnd, lparam):
                  global replacewith_is_next_ctrl
                  global findwhat_is_next_ctrl
                  global replacewith_handle
                  global findwhat_handle
                  curr_class = create_unicode_buffer(256)
                  GetClassName(hwnd, curr_class, 256)
                  length = GetWindowTextLength(hwnd)
                  buff = ctypes.create_unicode_buffer(length + 1)
                  GetWindowText(hwnd, buff, length + 1)
                  if curr_class.value.lower() == 'static':
                      if buff.value == replacewith_caption:
                          replacewith_is_next_ctrl = True
                      elif buff.value == findwhat_caption:
                          findwhat_is_next_ctrl = True
                  elif curr_class.value.lower() == 'edit':
                      if findwhat_is_next_ctrl:
                          findwhat_handle = hwnd
                          findwhat_is_next_ctrl = False
                      elif replacewith_is_next_ctrl:
                          replacewith_handle = hwnd
                          replacewith_is_next_ctrl = False
                          return False  # stop enumeration
                  return True  # let enumeration continue
              
              def return_proper_string(selected_text):
                  if notepad.getEncoding() == BUFFERENCODING.ENC8BIT:
                      _selected_text = unicode(selected_text, '{}'.format(GetACP()))
                  else:
                      _selected_text = unicode(selected_text, 'utf-8')
                  return _selected_text
              
              def main():
                  msg = ''
                  if editor.getSelections() == 1:
                      notepad.menuCommand(MENUCOMMAND.SEARCH_REPLACE)
                  elif editor.getSelections() == 2:
                      if editor.getSelectionMode() == 0 and not editor.getSelectionEmpty():
                          _find_what = editor.getTextRange(editor.getSelectionNStart(0), editor.getSelectionNEnd(0))
                          _replace_with = editor.getTextRange(editor.getSelectionNStart(1), editor.getSelectionNEnd(1))
              
                          if len(_find_what) > 2046:
                              _find_what = _find_what[:2046]
                              msg += 'Warning:  Selected text too long for find-what box; truncating to 2046 characters.  '
                                  
                          if len(_replace_with) > 2046:
                              _replace_with = _replace_with[:2046]
                              msg += 'Warning:  Selected text too long for replace-with box; truncating to 2046 characters.  '
                                                      
                          notepad.menuCommand(MENUCOMMAND.SEARCH_REPLACE)
                          find_dialog_hwnd = FindWindow(None, replace_tab_caption)
                          
                          if find_dialog_hwnd:
                              EnumChildWindows(find_dialog_hwnd, WNDENUMPROC(EnumCallback), 0)
                              if findwhat_handle and replacewith_handle:
                                  if SetWindowText(findwhat_handle, return_proper_string(_find_what)) == 0:
                                      msg += 'Error:  Problem setting find-what text'
                                  if SetWindowText(replacewith_handle, return_proper_string(_replace_with)) == 0:
                                      msg += 'Error:  Problem setting replace-with text'
                              else:
                                  msg += 'Error:  Bad value for replacewith_handle'
                          else:
                              msg += 'Error:  Bad value for find_dialog_hwnd'
                      else:
                          msg += 'Error:  Either empty selection or unsupported selection mode detected'
                  else:
                      msg += 'Warning:  Only one or two selections are possible. Received:{}'.format(editor.getSelections())
                  if len(msg) > 0: notepad.messageBox(msg)
              
              main()
              

              Cheers
              Claudia

              1 Reply Last reply Reply Quote 2
              • guy038G
                guy038
                last edited by guy038

                Hello, @claudia-frank, @Scott-sumner, @pouemes44, @go2to, @jorge-campos, @herofiles, @azjio-azjio, @alan-kilborn and All

                Thanks to @claudia-frank, this present topic and the discussions, below, about multi-lines search AND multi-lines Replacement :

                https://notepad-plus-plus.org/community/topic/13823/replace-function/1

                https://notepad-plus-plus.org/community/topic/13684/feature-request-textarea-search-replace/1

                have, now, an ELEGANT solution, with her Python’s script, just above !

                You just need to be able to do multiple selections ( Option Settings > Preferences… > Editing > Multi-Editing Settings > Enable CHECKED )


                BTW, the upper limit of 2046 characters, in the Find what: box of the Find/Replace dialog, only, could be by-passed, easily :-). Indeed, just use the Regular expression search mode and use the generic regex (?s)Left-boundary.+?Right-boundary !

                For instance, you can choose a particular character, which does not exist,yet, in your file(s) to be modified, and build the regex :

                (?s)(#####\R).+?\1

                This regex contains any non-null amount of characters between TWO same complete lines #####, with their line-breaks

                So :

                • Do a normal selection of this regex (?s)(#####\R).+?\1, using the mouse

                • Then, with a Ctrl + Left Click action, simply, select your Replace block, multi-lines or not

                • Run the Claudia’s script above

                => Immediately, the Find/Replace dialog pops-up and :

                • The Find what: box is filled with the regex (?s)(#####\R).+?\1

                • The Replace with: box is filled with the block of text, which must replace the searched text

                Best Regards,

                guy038

                P.S. :

                @claudia-frank, I understand your point of view. Your script is quite flexible :-D. For instance, I was able to :

                • First, do a Ctrl + Clic selection of a multi-lines block of text

                • Run your script => Find what: box empty and Replace with: box filled with that multi-lines block

                • Select an second file, containing the text (?s)(#####\R).+?\1

                • Do a normal selection of that regex

                • Run again, your script => The find.Replace dialog, presently in the background, is, then, updated with this regex, filled in the Find what: box

                • Select a third file, containing the ##### boundaries lines

                • Perform the S/R on the contents of this third file

                Et voilà !!

                Many thanks, again, for this very, very, valuable script, indeed !!!

                Hum… Already 3 h 25 !! I’d better go to bed : working tomorrow !

                1 Reply Last reply Reply Quote 1
                • AZJIO AZJIOA
                  AZJIO AZJIO
                  last edited by

                  It would be nice if the author would make an additional window when the button is clicked
                  [http://radikal.ru/big/m0wcdchejv3ve](link url)

                  1 Reply Last reply Reply Quote 0
                  • AZJIO AZJIOA
                    AZJIO AZJIO
                    last edited by

                    The external program is working. I make a plugin and no longer works (EnumChildWindows).

                    1 Reply Last reply Reply Quote 0
                    • Eko palypseE
                      Eko palypse
                      last edited by

                      Sorry, but what are you try to tell us?
                      Which external program and which meaning has EnumChildWindows API in this context?

                      1 Reply Last reply Reply Quote 0
                      • AZJIO AZJIOA
                        AZJIO AZJIO
                        last edited by

                        I wrote a program for the test of regular expressions. It serves as a database. When you click a button, it fills in the search and replace fields.
                        I decided to make a plugin that will do the same. But the same program (exe and dll) work differently. EXE fills the fields, but the DLL can not fill.
                        I tried using EnumChildWindows to find the elements of the window, as is done in the examples above. But as a result, he found only 3 elements.
                        0 hwnd = 725602 Class = Button Title = Caption
                        1 hwnd = 2233572 Class = Static Title =
                        2 hwnd = 1707882 Class = SysTabControl32 Title = Tab1

                        Eko palypseE 1 Reply Last reply Reply Quote 0
                        • Eko palypseE
                          Eko palypse @AZJIO AZJIO
                          last edited by

                          @AZJIO-AZJIO

                          without seeing/understanding the actual code it is hard to say what might be the issue
                          but, personally, I would not recommend using EnumChildWindows when trying to find a
                          dialog control window handle, instead use GetDlgItem.

                          1 Reply Last reply Reply Quote 0
                          • AZJIO AZJIOA
                            AZJIO AZJIO
                            last edited by

                            ; PureBasic
                            hwnd = FindWindowEx_(NppData_nppHandle, 0, “#32770”, 0) ; hwnd = yes
                            If Not IsWindowVisible_(hwnd)
                            SendMessage_(NppData_nppHandle, #NPPM_MENUCOMMAND, 0, #IDM_SEARCH_REPLACE) ; Показать диалог поиска используя команду меню
                            EndIf
                            hwndEdit_1 = GetDlgItem_(hwnd, 1601) ; hwndEdit_1 = 0
                            hwndEdit_2 = GetDlgItem_(hwnd, 1602) ; hwndEdit_2 = 0
                            SendMessage_(hwndEdit_1,#WM_SETTEXT,0,GetGadgetItemText(#Combo_2 , n-1, 0))
                            SendMessage_(hwndEdit_2,#WM_SETTEXT,0,GetGadgetItemText(#Combo_2 , n-1, 1))

                            1 Reply Last reply Reply Quote 0
                            • Eko palypseE
                              Eko palypse
                              last edited by

                              @AZJIO-AZJIO said:

                              #32770

                              be careful about searching for the ordinal only, as every dialog uses it.
                              https://docs.microsoft.com/en-us/windows/desktop/winmsg/about-window-classes
                              Most plugins and internal npp windows are dialogs.

                              1 Reply Last reply Reply Quote 0
                              • AZJIO AZJIOA
                                AZJIO AZJIO
                                last edited by

                                I know it. I do not set the window class. I have no way to change this. The external program, as I said, works.
                                https://a.radikal.ru/a21/1902/55/0723e06a798a.png

                                Eko palypseE 1 Reply Last reply Reply Quote 0
                                • Eko palypseE
                                  Eko palypse @AZJIO AZJIO
                                  last edited by

                                  @AZJIO-AZJIO

                                  Sorry, didn’t recognize the update.
                                  Windows, sometimes, treats retrieving external and internal information differently.
                                  Means, something you retrieved from an exe might differ from something
                                  you want to retrieve within its own process.

                                  In python, I would it do like this

                                  import ctypes
                                  user32 = ctypes.WinDLL('user32')
                                  hwnd = user32.FindWindowExW(None, None, u'#32770', u'Replace')
                                  hwndEdit_1 = user32.GetDlgItem(hwnd, 1601)
                                  hwndEdit_2 = user32.GetDlgItem(hwnd, 1602)
                                  

                                  This takes care that only the dialog with name Replace is found.

                                  1 Reply Last reply Reply Quote 1
                                  • AZJIO AZJIOA
                                    AZJIO AZJIO
                                    last edited by

                                    I have done just that. Keyword only “Extended”. But using AutoIt3

                                    $hWnd = WinGetHandle(“[CLASS:Notepad++]”)
                                    If Not @error Then
                                    If BitAND(WinGetState($hWnd), 16) Then WinActivate($hWnd)
                                    _SendMessage($hWnd, $NPPM_MENUCOMMAND, 0, $IDM_SEARCH_REPLACE)
                                    $hWnd = WinWait(“[CLASS:#32770]”, “Extended”, 2)
                                    If $hWnd Then
                                    ControlSetText($hWnd, “Extended”, “Edit1”, _GUICtrlRichEdit_GetText($hRichEdit_SPE))
                                    ControlSetText($hWnd, “Extended”, “Edit2”, GUICtrlRead($PtnRep))
                                    ControlCommand($hWnd, “Extended”, “Button18”, ‘Check’) ; 18 - regular expression (16 - normal)
                                    EndIf
                                    EndIf


                                    on PureBasic code is the same for exe and dll. Search window “#32770” starts at the top, so it does not cause a problem. There are either no such windows or they are below.

                                    1 Reply Last reply Reply Quote 0
                                    • Eko palypseE
                                      Eko palypse
                                      last edited by

                                      Maybe I have a wrong assumption what you are actually doing.
                                      When you talk about an exe I assume that this is a different standalone program, correct?
                                      When you talked about dll I assumed that this might be a npp plugin.
                                      Now I get the feeling this is incorrect. Would you mind to explain what exactly is what
                                      and what your ultimate goal is?

                                      1 Reply Last reply Reply Quote 0
                                      • AZJIO AZJIOA
                                        AZJIO AZJIO
                                        last edited by

                                        Thank! The previous code helped. I saw in it the absence of a handle in FindWindowExW(None
                                        I am intensively writing 2 plugins

                                        1 Reply Last reply Reply Quote 1
                                        • AZJIO AZJIOA
                                          AZJIO AZJIO
                                          last edited by

                                          As a result, several plugins, but there is much to strive for.
                                          https://yadi.sk/d/VYtvMq8ECMou9g

                                          1 Reply Last reply Reply Quote 1
                                          • Alan KilbornA Alan Kilborn referenced this topic on
                                          • Alan KilbornA Alan Kilborn referenced this topic on
                                          • First post
                                            Last post
                                          The Community of users of the Notepad++ text editor.
                                          Powered by NodeBB | Contributors