• Login
Community
  • Login

Maintain Indent While Pasting Multiple Lines

Scheduled Pinned Locked Moved Help wanted · · · – – – · · ·
26 Posts 9 Posters 4.3k 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.
  • D
    Dennis Bareis @Alan Kilborn
    last edited by Jan 5, 2024, 2:36 AM

    @Alan-Kilborn said in Maintain Indent While Pasting Multiple Lines:

    @PeterJones said in Maintain Indent While Pasting Multiple Lines:

    I think you should hold judgement and wait on the script – I don’t know how saving some reformatting after a paste would disrupt a workflow

    I could be wrong but I took it as sarcasm 😀

    A 1 Reply Last reply Jan 5, 2024, 11:41 AM Reply Quote 0
    • A
      Alan Kilborn @Dennis Bareis
      last edited by Jan 5, 2024, 11:41 AM

      @Dennis-Bareis said in Maintain Indent While Pasting Multiple Lines:

      I could be wrong but I took it as sarcasm

      PJ is rarely sarcastic (as a moderator here he is somewhat required to be “even keel”). Usually, the farthest he’ll go is something like this:

      …recent “improvements”…

      1 Reply Last reply Reply Quote 1
      • S
        StoopidoMan
        last edited by StoopidoMan May 11, 2024, 2:45 AM May 11, 2024, 2:28 AM

        I would really want this too
        I posted about it on reddit:
        https://www.reddit.com/r/notepadplusplus/comments/1cp6r8x/apply_autoindent_on_multiline_paste_is_there_away/

        I keep a lot of notes on Notepad++ and I use the Auto-indent feature a lot but it doesn’t work when you paste text.

        for example:

        How to do X?
                                    1) just do the X
                                    2) Blah Blah X 
        

        When I paste something from the clipboard I expect it to look like this:

        How to do X?
                                    1) just do the X
                                    2) Blah Blah X 
                                     Random copied text from internet line 1
                                     Random copied text from internet line 2
                                            Random copied text from internet line 3
                                            Random copied text from internet line 4
        

        but it get pasted like this:

        How to do X?
                                    1) just do the X
                                    2) Blah Blah X 
                                    Random copied text from internet line 1
        Random copied text from internet line 2
               Random copied text from internet line 3
               Random copied text from internet line 4
        

        So since I pressed enter and pasted the text, the first pasted line respect the auto-indent, but the subsequent lines does not.

        I think this would be a nice optional feature to add on top of Notepad++ Auto-indent setting, as Follow auto-indent on paste

        ☐ Auto-indent 
               ☐ follow auto-indent on paste
        
        1 Reply Last reply Reply Quote 0
        • G
          guy038
          last edited by guy038 May 11, 2024, 7:13 AM May 11, 2024, 6:39 AM

          Hello, @stoopidoman and All,

          The example provided by @stoopidoman is not clearly explained ! I suppose that what he wants to say is :

          I have this text in a new tab, after hitting the Enter key right after the X char and the trailing space, of the second line :

          How to do X?
                                      1) just do the X
                                      2) Blah Blah X 
                                      
          

          So, the cursor is presently right before the 2) string, but on the third line, after some tabulation or space chars

          Be aware that some plugins may change the default indent behaviour of Notepad++, like, for example, the Elastic Tabstops plugin. In this case, before doing the test, simply disable the plugin !


          Now, I pasted the text , below, from Internet :

          Random copied text from internet line 1
          Random copied text from internet line 2
                 Random copied text from internet line 3
                 Random copied text from internet line 4
          

          When I paste the above text in my new tab, I get the following text :

          How to do X?
                                      1) just do the X
                                      2) Blah Blah X 
                                      Random copied text from internet line 1
          Random copied text from internet line 2
                 Random copied text from internet line 3
                 Random copied text from internet line 4
          

          However, I would have expected this kind of text :

          How to do X?
                                      1) just do the X
                                      2) Blah Blah X 
                                      Random copied text from internet line 1
                                      Random copied text from internet line 2
                                          Random copied text from internet line 3
                                          Random copied text from internet line 4
          

          How to get this last behaviour with pasted text ?

          Best Regards,

          guy038

          IMPORTANT POINT :

          To respect the same displaying as the @stoopidoman’s one, I had to do the following operation, too :

          Edit > Blank Operations > TAB to Space

          Thus, all this story is a bit tricky !


          Certainly, @stoopidoman, previously configured his N++ installation as :

          • Go to Settings > Preferences... > Language > Tab Settings

          • In the list, choose the Normal option

          • Uncheck the Use Default Value option

          • Don’t change the Tab size option

          • Check the Replace by space option

          1 Reply Last reply Reply Quote 1
          • A
            Alan Kilborn
            last edited by May 11, 2024, 11:22 AM

            Sorry all… earlier in this thread I promised a script… and I haven’t delivered.
            It IS more difficult to do a comprehensive solution on this than one would think – and sometimes that can keep one from finishing something to their own satisfaction.
            Let me see what I can do about dumbing it down and at least getting something posted…

            A 1 Reply Last reply May 11, 2024, 8:36 PM Reply Quote 1
            • M
              mpheath @Dennis Bareis
              last edited by May 11, 2024, 2:19 PM

              Quite fresh code that uses PythonScript. Got the getClipboardText() idea from a post by @Alan-Kilborn .

              from Npp import editor, notepad
              import re
              
              def main():
                  def getClipboardText():
                      editor = notepad.createScintilla()
                      editor.paste()
                      editor.convertEOLs(eolMode)
                      text = editor.getText()
                      notepad.destroyScintilla(editor)
                      return text
              
                  def repl(m):
                      if useTabs:
                          result = m.group(1).replace(' ' * tabWidth, '\t')
                          size = result.count('\t')
                      else:
                          result = m.group(1).replace('\t', ' ' * tabWidth)
                          size = result.count(' ' * tabWidth)
              
                      if not minSize[0] or size < minSize[0]:
                          minSize[0] = size
              
                      return result
              
                  pos = editor.getCurrentPos()
                  tabWidth = editor.getTabWidth()
                  useTabs = editor.getUseTabs()
                  eolMode = editor.getEOLMode()
                  eol = ['\r\n', '\r', '\n'][eolMode]
                  minSize = [0]
                  text = getClipboardText()
              
                  if not text:
                      return
              
                  parts = re.split(r'\r?\n', text)
              
                  # Normalize indents.
                  re_indents = re.compile(r'^([\t ]+)')
              
                  for index, line in enumerate(parts):
                      modified = re_indents.sub(repl, line)
                      parts[index] = modified
              
                  # Remove indents to flatten.
                  tabLiteral = '\t' if useTabs else ' ' * tabWidth
              
                  while minSize[0]:
                      for index, line in enumerate(parts):
                          parts[index] = line.replace(tabLiteral, '', 1)
              
                      minSize[0] -= 1
              
                  # Add indents to finalize.
                  line = editor.lineFromPosition(pos)
                  indentSize = editor.getLineIndentation(line)
              
                  while indentSize > 0:
                      for index, line in enumerate(parts):
                          if index > 0:
                              parts[index] = tabLiteral + line
              
                      indentSize -= tabWidth
              
                  # Join lines and insert into editor.
                  text = eol.join(parts)
                  editor.insertText(pos, text)
              
              main()
              

              It should get the text from the clipboard, normalize and flatten the indenting, add indents from position from the current editor line and then insert into the editor.

              1 Reply Last reply Reply Quote 2
              • A
                Alan Kilborn @Alan Kilborn
                last edited by PeterJones May 15, 2024, 12:50 PM May 11, 2024, 8:36 PM

                @Alan-Kilborn said in Maintain Indent While Pasting Multiple Lines:

                Let me see what I can do about dumbing it down and at least getting something posted…

                Here’s my entry; I call the script PasteSpecialAtCurrentIndentColumn.py.

                # -*- coding: utf-8 -*-
                from __future__ import print_function
                
                #########################################
                #
                #  PasteSpecialAtCurrentIndentColumn (PSACIC)
                #
                #########################################
                
                # references:
                #  https://community.notepad-plus-plus.org/topic/25295
                #  for newbie info on PythonScripts, see https://community.notepad-plus-plus.org/topic/23039/faq-desk-how-to-install-and-run-a-script-in-pythonscript
                
                #-------------------------------------------------------------------------------
                
                from Npp import *
                import os, re # script modified by moderator; see May 11 9:27p posting (by mpheath) below
                
                #-------------------------------------------------------------------------------
                
                try:
                    editor3h  # third editor, hidden
                except NameError:
                    editor3h = notepad.createScintilla()
                
                #-------------------------------------------------------------------------------
                
                class PSACIC(object):
                
                    def __init__(self):
                
                        if not editor.canPaste() or not editor3h.canPaste():
                            return
                
                        rect_sel_mode = editor.getSelectionMode() in [ SELECTIONMODE.RECTANGLE, SELECTIONMODE.THIN ]
                        if rect_sel_mode:
                            self.mb('Cannot use this paste-special when in column-block mode.')
                            return
                
                        if editor.getSelections() > 1:
                            self.mb('Cannot use this paste-special when more than a single caret is active.')
                            return
                
                        if len(editor.getSelText()) > 0:
                            self.mb('Cannot use this paste-special when text is selected.')
                            return
                
                        curr_pos = editor.getCurrentPos()
                        curr_line_starting_pos = editor.positionFromLine(editor.lineFromPosition(curr_pos))
                        if curr_pos == curr_line_starting_pos:
                            # caret at start of line; just do normal/simple paste
                            editor.paste()
                            return
                
                        curr_line_text_before_caret = editor.getTextRange(curr_line_starting_pos, curr_pos)
                        if re.search(r'\S', curr_line_text_before_caret):
                            self.mb('Cannot use this paste-special at an insertion point with non-whitespace to its left.')
                            return
                
                        clipboard_text = self.clipboard_get_text()
                        eol = [ '\r\n', '\r', '\n' ][editor.getEOLMode()]
                        if eol not in clipboard_text:
                            # no 2nd+ line(s) in data to paste, so nothing to adjust; just do normal/simple paste
                            editor.paste()
                            return
                
                        clipboard_lines_list = clipboard_text.splitlines()
                
                        # see if there's a common all-whitespace prefix on the clipboard lines
                        m = re.search(r'^\s+', os.path.commonprefix(clipboard_lines_list))
                        common_ws_prefix_on_clipboard_lines = m.group(0) if m else ''
                
                        # remove any common all-whitespace prefix on the clipboard lines
                        clipboard_lines_list = [ re.sub('^' + common_ws_prefix_on_clipboard_lines, '', s) for s in clipboard_lines_list ]
                
                        # prepend the current line's indentation whitespace to all of the clipboard lines:
                        first_clipboard_line_text = clipboard_lines_list[0]  # remember the first clipboard line before indenting all the rest
                        # add new indentation to all of the modified clipboard lines except the first line:
                        clipboard_lines_list = [ re.sub('^', curr_line_text_before_caret, s) for s in clipboard_lines_list[1:] ]
                        clipboard_lines_list.insert(0, first_clipboard_line_text)  # put the first line back into the list at its old position
                
                        # do our modified "paste" and set new caret appropriately:
                        old_doc_len = editor.getLength()
                        editor.insertText(curr_pos, eol.join(clipboard_lines_list) + eol)  # "paste" in the appropriately indented new text
                        new_caret_pos = curr_pos + editor.getLength() - old_doc_len
                        editor.setSel(new_caret_pos, new_caret_pos)  # set caret at end of "pasted" text; scroll viewport if needed
                
                    def clipboard_get_text(self, eol_mode=None):
                        # if eol_mode arg is not-specified, use the current editor's eol mode:
                        editor3h.setEOLMode(editor.getEOLMode() if eol_mode is None else eol_mode)
                        editor3h.clearAll()
                        editor3h.paste()
                        retval = editor3h.getText()
                        return retval
                
                    def mb(self, msg, flags=0, title=''):  # a message-box function
                        return notepad.messageBox(msg, title if title else 'PSACIC', flags)
                
                #-------------------------------------------------------------------------------
                
                if __name__ == '__main__': PSACIC()
                
                M D 2 Replies Last reply May 12, 2024, 1:27 AM Reply Quote 4
                • A Alan Kilborn referenced this topic on May 11, 2024, 8:36 PM
                • M
                  mpheath @Alan Kilborn
                  last edited by May 12, 2024, 1:27 AM

                  @Alan-Kilborn You probably have the os and re modules imported in a previous script as your posted script does not import those modules and can produce NameError tracebacks.

                  Imports:

                  from Npp import *
                  import os, re
                  

                  Added near the top of the script fixes it.

                  The script looks interesting. The comparison between both scripts may suggest some ideas for improvement. ;)

                  A 1 Reply Last reply May 12, 2024, 10:51 AM Reply Quote 4
                  • A
                    Alan Kilborn @mpheath
                    last edited by Alan Kilborn May 12, 2024, 12:56 PM May 12, 2024, 10:51 AM

                    @mpheath said in Maintain Indent While Pasting Multiple Lines:

                    You probably have the os and re modules imported

                    Ah, yea, sorry. :-(

                    That’s what I get for “hurrying” to catch up with you in getting something posted (but again, that’s an artifact of me not posting a script much earlier). I’d be surprised if there aren’t further errors in the script I posted. :-)

                    My startup.py does a lot of things, and imports os and re out of necessity there. I usually test scripts I’m going to post with a vanilla setup which would have discovered the error, but this time I didn’t. :-(


                    The comparison between both scripts may suggest some ideas for improvement

                    Yes, for sure!

                    Your script futzes with tab characters vs. space characters; in my script I chose to handle it this way (or, largely not-handle it):

                    • require any common leading whitespace on all lines in the clipboard to be identical for it to be removed
                    • use the leading whitespace on the line where the paste-special is invoked to be used “as is” when prepended to the clipboard lines

                    If users can’t get their tab vs. space indentation consistent (i.e., one way or the other)…I consider this “not my problem”.

                    1 Reply Last reply Reply Quote 4
                    • A Alan Kilborn referenced this topic on Sep 24, 2024, 9:21 PM
                    • Mark OlsonM Mark Olson referenced this topic on Sep 25, 2024, 8:31 PM
                    • A Alan Kilborn referenced this topic on Jan 14, 2025, 8:17 PM
                    • D
                      Dennis Bareis @Alan Kilborn
                      last edited by Dennis Bareis Feb 16, 2025, 10:18 PM Feb 16, 2025, 9:53 PM

                      @Alan-Kilborn

                      Its been a while but I finally got some time to look and this again.

                      Now that I saw the comment in the code pointing to PythonScript and setting up a HotKey it ended up being quite easy.

                      Your script seems to do the right thing for what I need and if it doesn’t I’ll learn enough Python to update it and update this post.

                      1 Reply Last reply Reply Quote 2
                      • First post
                        Last post
                      The Community of users of the Notepad++ text editor.
                      Powered by NodeBB | Contributors