Column-block Paste problem with source block having jagged right edge



  • Sometimes I need to copy column block data and paste it into the middle (column-wise) of existing text. This works fine as long as all of the lines in the column are full (i.e., all of the columns are populated–if it is an “N” column block, then each column truly has N characters in it); however, it gets messy if some of the lines in the column block are shorter than N.

    Perhaps an example explains better:

    Selecting and copying the column block defined by A and G (including those characters) in the following data:

    aaaaaaaAaaaaaaaaaaaaa
    bbbbbbbbbb
    ccc
    d
    eeee
    ffffffff
    gggggggggggGgggg
    

    …and then pasting that column block into this data immediately to the right of the column of - characters:

    1111111-111111111111111111
    2222222-222222222222222222
    3333333-333333333333333333
    4444444-444444444444444444
    5555555-555555555555555555
    6666666-666666666666666666
    7777777-777777777777777777
    

    (note the nicely aligned right edge!)

    results in:

    1111111-Aaaaa111111111111111111
    2222222-bbb222222222222222222
    3333333-333333333333333333
    4444444-444444444444444444
    5555555-555555555555555555
    6666666-f666666666666666666
    7777777-ggggG777777777777777777
    

    (note the now messy right-edge!)

    but it would be more desirable to result in:

    1111111-Aaaaa111111111111111111
    2222222-bbb  222222222222222222
    3333333-     333333333333333333
    4444444-     444444444444444444
    5555555-     555555555555555555
    6666666-f    666666666666666666
    7777777-ggggG777777777777777777
    

    (note again the nicely aligned right edge!)

    Is there a reasonable way to make Notepad++ do this, (without going to the trouble of padding the shorter source lines with spaces on their right first, in order to “fill out” the column block)?



  • That’s because Npp has a problem with blank spaces: It simply ignores them. I too think that’s a wrong action. It bothers me when I press Home to go to the beginning of a line that starts with blank spaces. Notepad++ always takes me to the beginning of the first non-blank-space word, instead of the very beginning of the line.

    Maybe a new feature… although I heard from posters here that the author is quite stubborn in ignoring feature-requests…

    Peace be with you and this community!



  • @Parpaluck209 said:

    That’s because Npp has a problem with blank spaces: It simply ignores them.

    No, that’s not it. PLEASE try not to spread misinformation via this Community. If you don’t know something to a high degree of certainty, don’t state it. Others might read these postings in the future and be misled by your wrong statements. Sure, everybody is wrong occasionally, but I can tell from what you stated that you have no idea what you are talking about.



  • Hello, @alan-kilborn,

    Alan, the old TextFX plugin has this kind of feature ( TextFX > TextFX Edit > Paddle rectangular selection with spaces )

    But, here is, below, my work-around, with native N++ commands !


    • Perform a single left click after the G letter

    • Press, simultaneously, the Alt and Shift keys and hit, six times, on the Up arrow

    => A 6 x 0 column block should be defined, at column 13

    • Hit the Space key and, right after, the Backspace key

    => This time, the 6 x 0 column block is preceded by some Space characters

    • Now, press, simultaneously, the Alt and Shift keys and hit, five times, on the Left arrow

    => The column block between the letters A and G included, containing space characters, is, then, selected

    • Hit the usual Ctrl + C shortcut to copy this column block selection

    • If you prefer to keep that block unchanged, hit, twice, the Ctrl + Z shortcut

    • Finally, move the caret to the line 1111111-111111111111111111, after the dash character

    • Hit the usual Ctrl + V shortcut to column-paste it, at the caret position

    => The seven “digit-lines” should be, correctly, modified, as below :

    1111111-Aaaaa111111111111111111
    2222222-bbb  222222222222222222
    3333333-     333333333333333333
    4444444-     444444444444444444
    5555555-     555555555555555555
    6666666-f    666666666666666666
    7777777-ggggG777777777777777777
    

    Cheers,

    guy038



  • @guy038

    From reading your description, I thought it was going to be a painful process. But no, it is pretty clean and it works nicely. Nice technique.

    I’ve had a Pythonscript (surprise!) for doing this sort of operation. It works well; I’ve noticed it seems a bit slow on a large chunk of data, but no matter. Also, the source data (in the clipoard) can be a column block or a normal stream block (in which case the varying length lines are turned into a truly rectangular column block upon “pasting”).

    Start by copying some data to the clipboard, then put the caret at the desired Top/Left insertion point. Then invoke PasteAsTrueRectBlock.py:

    import ctypes
    
    def PATRB__GetClipboardText():
        # see https://notepad-plus-plus.org/community/topic/12525/replace-current-line-without-inserting-a-new-line/12
        # not the most error-proof function in the world!
        if ctypes.windll.user32.OpenClipboard(None):
            clipboard_handle = ctypes.windll.user32.GetClipboardData(1)
            if clipboard_handle:
                pointer_to_content = ctypes.windll.kernel32.GlobalLock(clipboard_handle)
                clipboard_data = ctypes.c_char_p(pointer_to_content).value
                ctypes.windll.kernel32.GlobalUnlock(clipboard_handle)
            else:
                return ''  # invalid handle
            ctypes.windll.user32.CloseClipboard()
            return clipboard_data
        else:
            return ''  # error
    
    def PATRB__main():
    
        # "paste" current clipboard contents as a column block with TOP LEFT of resultant block at the caret point
        current_text_in_clipboard = PATRB__GetClipboardText()
        if editor.canPaste() and len(current_text_in_clipboard) > 0 and editor.getSelections() == 1 and editor.getSelectionEmpty():
            line_ending = [ '\r\n', '\r', '\n' ][notepad.getFormatType()]
            lines_list = current_text_in_clipboard.split(line_ending)
            if len(lines_list[-1]) == 0: lines_list.pop()  # if text in clipboard ended with line_ending, need to remove empty element at end of list
            longest_line_length = max([ len(z) for z in lines_list ])
            uniform_horiz_len_lines_list = [ z + ' ' * (longest_line_length - len(z)) for z in lines_list ]  # pad shorter lines out to length of longest
            starting_line_nbr = editor.lineFromPosition(editor.getCurrentPos())
            orig_line_count = editor.getLineCount()
            insert_starting_col = editor.getColumn(editor.getCurrentPos()) + editor.getSelectionNCaretVirtualSpace(0)
            editor.beginUndoAction()
            if starting_line_nbr + len(uniform_horiz_len_lines_list) > orig_line_count - 1:
                # need to add some blank lines at bottom of file to hold line data we will be inserting
                nbr_of_new_lines_to_add = starting_line_nbr + len(uniform_horiz_len_lines_list) - orig_line_count
                editor.appendText(line_ending * nbr_of_new_lines_to_add)
            for line_nbr_offset in xrange(len(uniform_horiz_len_lines_list)):
                editor.gotoPos(editor.findColumn(starting_line_nbr + line_nbr_offset, insert_starting_col))  # try to go to the correct column; if can't, go to last column of the line
                col_data_to_ins = ''
                col_diff = insert_starting_col - editor.getColumn(editor.getCurrentPos())
                if col_diff: col_data_to_ins = ' ' * col_diff  # the correct column does not exist; pad with spaces out to the correct column:
                col_data_to_ins += uniform_horiz_len_lines_list[line_nbr_offset]
                editor.addText(col_data_to_ins)
            editor.endUndoAction()
    
    PATRB__main()


  • I found some deficiencies in PasteAsTrueRectBlock.py. There are situations where the desired rectangular blocking can’t be known at paste time, but only at copy time. So I wrote CopyAsTrueRectBlock.py. Running this new script on a single selection, be it a normal selection or a column-based one, will result in a truly rectangular block in the clipboard, which can subsequently be pasted via a normal paste (e.g., ctrl+v). As a bonus, the logic for this script is simpler and shorter than the earlier script. :-)

    Here’s CopyAsTrueRectBlock.py:

    def CATRB__main():  # (C)opy (A)s (T)rue (R)ectangular (B)lock
        if not editor.getSelectionEmpty():
            if editor.selectionIsRectangle() or editor.getSelections() == 1:
                line_ending = [ '\r\n', '\r', '\n' ][notepad.getFormatType()]
                lines_list = editor.getSelText().split(line_ending)
                if len(lines_list[-1]) == 0: lines_list.pop()  # if text ended with line_ending, need to remove empty element at end of list
                rect_width = 0
                if editor.selectionIsRectangle():
                    rect_anchor = editor.getColumn(editor.getRectangularSelectionAnchor())
                    rect_anchor += editor.getRectangularSelectionAnchorVirtualSpace()
                    rect_caret = editor.getColumn(editor.getRectangularSelectionCaret())
                    rect_caret += editor.getRectangularSelectionCaretVirtualSpace()
                    rect_width = abs(rect_anchor - rect_caret)
                longest_line_length = max([ len(line) for line in lines_list ] + [ rect_width ])
                # pad shorter lines out to length of longest:
                truly_rectangular_lines_list = [ line + ' ' * (longest_line_length - len(line)) for line in lines_list ]
                remember_active_file = notepad.getCurrentFilename()
                notepad.new()
                editor.addText(line_ending.join(truly_rectangular_lines_list) + line_ending)
                editor.setSel(0, (longest_line_length + len(line_ending)) * len(truly_rectangular_lines_list))
                editor.setSelectionMode(SELECTIONMODE.RECTANGLE)
                editor.copy()
                editor.undo()
                notepad.close()
                notepad.activateFile(remember_active_file)
    
    CATRB__main()

Log in to reply