Copy with line numbers



  • I think TextFX plugin had a “copy with line numbers” option, but I’ve long since stopped using TextFX and moved to N++ 64-bit where there is no TextFX option. Most of it’s features are available anyway. But “copy with line numbers” is very useful for the few and far between times I do need to use it.

    I’m pretty good with NppExec, so here’s a little script I whipped up to do “copy with line numbers”:

    SCI_SENDMSG SCI_GETSELECTIONSTART
    SCI_SENDMSG SCI_LINEFROMPOSITION $(MSG_RESULT)
    SET LOCAL START = $(MSG_RESULT)
    
    SCI_SENDMSG SCI_GETSELECTIONEND
    SCI_SENDMSG SCI_LINEFROMPOSITION $(MSG_RESULT)
    SET LOCAL END = $(MSG_RESULT)
    
    SCI_SENDMSG SCI_GETCURRENTPOS 
    SCI_SENDMSG SCI_GETCOLUMN $(MSG_RESULT)
    SET LOCAL COLUMNEND = $(MSG_RESULT)
    
    :LOOP
    IF $(START)==$(END) THEN
        IF $(COLUMNEND)==0 GOTO END
        ENDIF
    ENDIF
    SCI_SENDMSG SCI_GETLINE $(START) @""
    SET LOCAL LINE ~ $(START) + 1
    ECHO $(LINE):	$(MSG_LPARAM)
    IF $(START)==$(END) GOTO END
    SET LOCAL START ~ $(START) + 1
    GOTO LOOP
    
    :END
    

    Note the “space” between the colon and dollar sign in the `ECHO $(LINE): $(MSG_LPARAM)" line is actually a TAB which makes the output look better. Of course, this only outputs to the NppExec Console; you need to then highlight it and copy to be able to paste it somewhere.

    NppExec has a “clip_settext” command which can set the clipboard text, but you can see the problem in my loop is that i output the text rather than concatenate it to a variable.

    QUESTION:
    It seems NppExec doesn’t have a way to do “string addition” or string concatenation? Unless I’m missing something?

    I’m sure this is pretty trivial in [Python|Lua]Script plugins.

    Cheers.



  • @Michael-Vincent said in Copy with line numbers:

    It seems NppExec doesn’t have a way to do “string addition” or string concatenation?

    No, it has.

    Please remind: NppExec works like a console script language, not like a normal programming language.

    Type the following commands into a NppExec console window or add them as a script to the npes_saved.txt file:

    set local Foo = Bar
    echo $(Foo)
    set local Foo = $(Foo) Bar
    echo $(Foo)
    set local Foo = $(Foo) $(Foo)
    echo $(Foo)
    

    You can also use the following notation:

    set local $(Foo) = Bar
    echo $(Foo)
    set local $(Foo) = $(Foo) Bar
    ...
    


  • @dinkumoil said in Copy with line numbers:

    No, it has.

    I’m embarrassed to say I didn’t even try that and of course it “works” but it’s not preserving the line endings so it’s just adding one big line of text. Partial success.

    my first line
    my second line
    my third line

    Output should be:

    1 my first line
    2 my second line
    3 my third line

    but instead is:

    1 my first line2 my second line3 my third line

    I think the ECHO in my first “solution” is helping by adding in that carriage return / line feed which I was assuming should be part of the captured text from the SCI_GETLINE call.

    Cheers.



  • @Michael-Vincent

    OK - weird workaround, but pasting a unix line ending into Windows Notepad results in a zero-length character that you can actually “highlight” (it doesn’t look like anything highlights) and then copy and paste it into the script:

    ECHO $(LINE):	$(MSG_LPARAM)
    

    becomes:

    SET LOCAL OUTTEXT = $(OUTTEXT)$(LINE):	$(MSG_LPARAM)
    

    where the zero-length carriage return is between …EXT)[HERE]$(LIN…

    And then after :END, use:

    CLIP_SETTEXT $(OUTTEXT)
    

    Cheers.



  • @Michael-Vincent said in Copy with line numbers:

    I’m sure this is pretty trivial in [Python|Lua]Script plugins.

    Yep, the following Pythonscript will copy to the clipboard the lines touched by the currently active selection, prepended with their line numbers:

    # -*- coding: utf-8 -*-
    
    from Npp import editor, notepad, NOTIFICATION
    import math
    
    def main():
        start_line = editor.lineFromPosition(editor.getSelectionStart())
        sel_end = editor.getSelectionEnd()
        end_line = editor.lineFromPosition(sel_end)
        if editor.positionFromLine(end_line) == sel_end: end_line -= 1
        field_width_for_line_number = int(math.log(end_line + 1, 10)) + 1
        accum = ''
        for line_number in range(start_line, end_line + 1):
            accum += '{ln:{width}}:{contents}'.format(ln=line_number+1, width=field_width_for_line_number, contents=editor.getLine(line_number))
        editor.copyText(accum)
    
    main()
    

    Example output:

     8:    sel_end = editor.getSelectionEnd()
     9:    end_line = editor.lineFromPosition(sel_end)
    10:    if editor.positionFromLine(end_line) == sel_end: end_line -= 1
    


  • @Michael-Vincent said in Copy with line numbers:

    OK - weird workaround

    Much better:

    ::copylinenums
    NPP_CONSOLE keep
    
    SET LOCAL CR ~ STRFROMHEX 0xd
    SET LOCAL LF ~ STRFROMHEX 0xa
    
    SCI_SENDMSG SCI_GETSELECTIONSTART
    SCI_SENDMSG SCI_LINEFROMPOSITION $(MSG_RESULT)
    SET LOCAL START = $(MSG_RESULT)
    
    SCI_SENDMSG SCI_GETSELECTIONEND
    SCI_SENDMSG SCI_LINEFROMPOSITION $(MSG_RESULT)
    SET LOCAL END = $(MSG_RESULT)
    
    SCI_SENDMSG SCI_GETCURRENTPOS
    SCI_SENDMSG SCI_GETCOLUMN $(MSG_RESULT)
    SET LOCAL COLUMNEND = $(MSG_RESULT)
    
    :LOOP
    IF $(START)==$(END) THEN
        IF $(COLUMNEND)==0 GOTO END
        ENDIF
    ENDIF
    SCI_SENDMSG SCI_GETLINE $(START) @""
    SET LOCAL LINE ~ $(START) + 1
    // ECHO $(LINE):	$(MSG_LPARAM)
    SET LOCAL OUTTEXT = $(OUTTEXT)$(LINE):	$(MSG_LPARAM)$(CR)$(LF)
    IF $(START)==$(END) GOTO END
    SET LOCAL START ~ $(START) + 1
    GOTO LOOP
    
    :END
    CLIP_SETTEXT $(OUTTEXT)
    

    Cheers.


Log in to reply