[Feature Request] MD5 in the context menu



  • Helo,
    I have a proposition of small feature similar to Open File on selection (Edit\On Selection\Open File) generating MD5 hash form the linked file. The Tool\MD5\Generate from files… is a bit cumbersome with many checksum to update for files linked at different folders. Item in the menu “Edit\On Selection\Generate MD5 from file” or in context menu will making work easier.
    Regards
    Jan



  • So, if I understand right, you want to be able to select a list of file-paths in your document, use this “on-selection”-based command, and have the MD5 generated for each of those files? As far as I know, that’s not possible natively.

    It might be scriptable using PythonScript, but I’m not sure how easy it would be to fill in the forms automatically. With Perl, using a combination of my [Win32::Mechanize::NotepadPlusPlus](https://metacpan.org/pod/Win32%3A%3AMechanize%3A%3ANotepadPlusPlus and the standard Win32::GuiTest, I believe I could hack something together. I guess, saying that, if I could think how I would do that in Perl, @Ekopalypse could probably come up with a similar solution in PythonScript after aliasing in the right win32-api commands, which he’s good at doing (though I don’t know how busy he is right now, and I make no guarantees that he will have the availability and/or interest.)

    I’ll see if I can find some mental free time to work on the Perl version today or this weekend – though it probably wouldn’t help you, since I doubt you have Perl, or are willing to install it. PythonScript would be easier, since it’s a Plugin that can be easily installed. However, I’m still not sure it’s worth doing inside notepad++: if someone is going to make specialty code to do it, it would probably make more sense to use the MD5 library available to that language (I know Perl has Digest::MD5, and I’m sure Python has a similar library) rather than try to figure out how to send signals to the right dialog box to automatically fill out the GUI-form.

    --------

    Tangent

    Hmm, instead of hijacking the thread, I’ll create my own topic tangential to this one.



  • Trying to hack together the GUI commands to manually fill out the dialog box looks like it would be quite annoying, without much payoff. It is much simpler to use a programming language’s easier access to its own MD5 library.

    For example, in Perl, grabbing the selection from Notepad++ and running the Digest::MD5 to get the name ends up being about 8 lines of real code, plus error handling, including modules, and comments. I have added it to the Win32::Mechanize::NotepadPlusPlus examples folder.

    #!/usr/bin/env perl
    # https://community.notepad-plus-plus.org/topic/19015/feature-request-md5-in-the-context-menu
    #
    # Installation:
    #   1) Save this file as c:\path\to\npp_selection_filenames_md5.pl
    #   2) Install perl (such as from strawberryperl.com)
    #   3) Install required modules:
    #       cpanm Digest::MD5 Win32::Mechanize::NotepadPlusPlus
    #
    # Instructions:
    #   1) select a list of filenames in Notepad++, one filename per line
    #   2) run this script
    #       * Run > Run: c:\strawberry\perl\bin\perl.exe c:\path\to\npp_selection_filenames_md5.pl
    #   3) the script will print out the MD5 list, similar to Tools > MD5 > Generate from files...
    #       but doesn't require using the dialog boxes
    #
    use strict;
    use warnings;
    use Win32::Mechanize::NotepadPlusPlus qw/:all/;
    use Digest::MD5;
    use autodie;
    
    my $eol = ("\r\n", "\r", "\n")[editor->getEOLMode()];
    
    my $txt = editor->getSelText();
    if( $txt eq "\0" or length($txt)<1) {
        die "\nusage: make a selection of filename-per-line in Notepad++, then run this script\n\n";
    }
    
    my @lines = split /$eol/, editor->getSelText();
    for my $fname (@lines) {
        #printf qq(>>%s<<\n), $fname;
        my $ctx = Digest::MD5->new;
        open my $fh, '<', $fname;
        $ctx->addfile($fh);
        printf qq(%32.32s  %s\n), $ctx->hexdigest, $fname;
    }
    

    So, if you select a few lines of filenames in Notepad++, like

    C:\usr\local\share\PassThru\perl\nppCommunity\19015-md5-on-list-of-files.pl
    C:\usr\local\share\PassThru\perl\nppCommunity\gen-md.pl
    

    and Run > Run cmd /k c:\strawberry\perl\bin\perl.exe c:\path\to\npp_selection_filenames_md5.pl while the selection is still active, it will print the hashes to STDOUT, which you can then easily copy/paste back into Notepad++

    9b09a8de81cb5861670d012958423d4e  19015-md5-on-list-of-files.pl
    b6d8e167ca1dc1d444b646a2985bd6bf  gen-md.pl
    

    Of course, you could also download GnuWin32’s CoreUtils, which includes md5sum.exe, and do the same thing purely from the command line.

    If @Ekopalypse doesn’t beat me to it, I might try to look up what the Python MD5 library/syntax is, and post the PythonScript version, which has the benefit of being better integrated to Notepad++.



  • And the PythonScript version:

    # encoding=utf-8
    """in response to https://community.notepad-plus-plus.org/topic/19015/feature-request-md5-in-the-context-menu
    
    Installation:
    1) Install PythonScript using Plugins Admin or manually
    2) **PythonScript > New Script**, `npp_selection_filenames_md5.py`
    
    Instructions
    1) Select a list of filenames in Notepad++, one filename per line
    2) Run this script: **PythonScript > Scripts > `npp_selection_filenames_md5`**
    3) The digests will be printed to the PythonScript console
    
    select these two lines:
    C:\usr\local\apps\notepad++\plugins\Config\PythonScript\scripts\19015-md5-on-filename-list.py
    C:\usr\local\share\PassThru\perl\nppCommunity\19015-md5-on-list-of-files.pl
    
    example output:
    f798a465f8019eec4f06287dbeb2f7f8  C:\usr\local\apps\notepad++\plugins\Config\PythonScript\scripts\19015-md5-on-filename-list.py
    1908fff7063f4dcf46866367adcd14c2  C:\usr\local\share\PassThru\perl\nppCommunity\19015-md5-on-list-of-files.pl
    
    """
    from Npp import *
    import hashlib
    
    def forum_post19015_FunctionName():
        console.show()
        console.clear()
    
        eol_tuple = ("\r\n", "\r", "\n")
        eol = eol_tuple[editor.getEOLMode()]
    
        txt = editor.getSelText()
    
        if txt == "\0" or len(txt)<1:
            console.writeError("\nusage: make a selection of filename-per-line in Notepad++, then run this script\n\n")
            return
    
        lines = txt.split(eol)
        for filename in lines:
            if len(filename)>0:
                md5str = hashlib.md5(open(filename,"rb").read()).hexdigest()
                console.write("{}  {}\n".format(md5str, filename))
    
    if __name__ == '__main__': forum_post19015_FunctionName()
    


  • @PeterJones - nice one :-)



  • @jankoza ,

    Sorry, I forgot to say earlier: while we hope these non-native solutions will help you, they don’t make the feature native to Notepad++.

    If after evaluating the alternatives, you still would like the feature added natively, then you will need to read the feature-request FAQ, create an issue, and come back here and provide us a link to your submitted issue.

    Please note that not all good feature ideas are implemented, and even approved ones may be weeks or months or more before being implemented. That’s why in this forum, we often focus on giving people alternate solutions.



  • Thanks PeterJones.
    Your Python script works perfectly on the absolute path. But, what needs to be changed to make the script work on internal links in the form of relative path to the edited file, such as:
    xlink:href="abcd/efgh/abcd.xml

    IOError: [Errno 2] No such file or directory: ‘abcd/efgh/abcd.xml’

    Thanks in advance.
    Jan



  • @jankoza said in [Feature Request] MD5 in the context menu:

    make the script work on internal links in the form of relative path to the edited file,

    I added this line:

    if not os.path.isfile(filename): filename = notepad.getCurrentFilename().rsplit(os.sep, 1)[0] + os.sep + filename
    

    right above the md5str = … line (and indented the same amount as that line), and it seemed to work for the relative path case.

    One could certainly do more error-checking; like say check for the existence of the newly formed filename before trying to open it…



  • @Alan-Kilborn said in [Feature Request] MD5 in the context menu:

    I added this line:

    I add as you suggest

        lines = txt.split(eol)
        for filename in lines:
            if len(filename)>0:
                if not os.path.isfile(filename): filename = notepad.getCurrentFilename().rsplit(os.sep, 1)[0] + os.sep + filename
                md5str = hashlib.md5(open(filename,"rb").read()).hexdigest()
                console.write("{}  {}\n".format(md5str, filename))
    

    and I get an error:
    NameError: global name ‘os’ is not defined



  • @jankoza said in [Feature Request] MD5 in the context menu:

    global name ‘os’ is not defined

    Ah, yes. You also need to add near the top of the file, perhaps a good spot is after the similar line for hashlib:

    import os
    

    The reason I forget this is because I have other scripts that “import” these definitions that have run earlier, and thus when this script runs it is already there.



  • @PeterJones, @Alan-Kilborn

    It works. Thanks a lot.


Log in to reply