Linked text to open other files into Notepad++
-
That would be marvelous! Need to say here that my standard app for, amongst others, .jpg, .png and .gif files is picture viewer IrfanView 64-bit, or not?
Thanks in advance.
-
@J-Brouwer said in Linked text to open other files into Notepad++:
Need to say here that my standard app for, amongst others, .jpg, .png and .gif files is picture viewer IrfanView 64-bit, or not?
Is IrfanView what opens when you double-click any files of these types from Explorer? If yes, then No, you don’t need to say it.
I’ll add the capability; check back in a day or two…
-
So what follows is the
UriIndicatorAltClick2.py
script. This version handles opening the default viewer/editor for linked text that is not a known type to the script.The script as written makes
.txt
and.log
files the known types, so those will be opened in Notepad++. To change this, simply changeedit_with_npp_lowercase_extension_list
in the code to add/subtract…even a non-coder can do this.Other types are unspecified, but an example would be
.jpg
files – these will be opened by whatever program is associated with them in the operating system.Examples:
edit:c:\test.txt
<-- will be underlined and if Alt+clicked will open test.txt in N++edit:d:\image.jpg
<-- will be underline and if Alt+clicked will open image.jpg in the default program for the jpg file type
As to spaces in the pathnames, as per the original version of the script, these will need to be replaced with
%20
in order for the entire pathname to be recognized as a clickable link, example:edit:d:\my%20image.jpg
.The script listing:
# -*- coding: utf-8 -*- # see https://community.notepad-plus-plus.org/topic/22274/linked-text-to-open-other-files-into-notepad from Npp import * import os import re import ctypes class UIAC2(object): def __init__(self): self.edit_with_npp_lowercase_extension_list = [ 'txt', 'log' ] self.URL_INDIC = 8 # URL_INDIC is used in N++ source code self.ALT_MODIFIER = 4 self.backslash = '\\' ; self.two_backslashes = self.backslash * 2 self.alt_held_at_click = False self.installed = False self.install() def install(self): if not self.installed: # https://www.scintilla.org/ScintillaDoc.html#SCN_INDICATORCLICK editor.callback(self.indicator_click_callback, [SCINTILLANOTIFICATION.INDICATORCLICK]) # https://www.scintilla.org/ScintillaDoc.html#SCN_INDICATORRELEASE editor.callback(self.indicator_release_callback, [SCINTILLANOTIFICATION.INDICATORRELEASE]) self.installed = True def uninstall(self): if self.installed: editor.clearCallbacks(self.indicator_click_callback) editor.clearCallbacks(self.indicator_release_callback) self.installed = False def is_installed(self): return self.installed def mb(self, msg, flags=0, title=''): return notepad.messageBox(msg, title, flags) def extension_from_path(self, path): l = path.rsplit('.', 1) ext = l[1] if len(l) == 2 else '' return ext def shell_open(self, uri_text, args=None): SW_SHOW = 5 return ctypes.windll.Shell32.ShellExecuteA(None, 'open', uri_text, args, None, SW_SHOW) > 32 def get_indicator_range(self, indic_number): # similar to ScintillaEditView::getIndicatorRange() in N++ source # https://github.com/notepad-plus-plus/notepad-plus-plus/blob/8f38707d33d869a5b8f5014dbb18619b166486a0/PowerEditor/src/ScitillaComponent/ScintillaEditView.h#L562 curr_pos = editor.getCurrentPos() indic_mask = editor.indicatorAllOnFor(curr_pos) if (indic_mask & (1 << indic_number)) != 0: start_pos = editor.indicatorStart(indic_number, curr_pos) end_pos = editor.indicatorEnd(indic_number, curr_pos) if curr_pos >= start_pos and curr_pos <= end_pos: return (start_pos, end_pos) return (0, 0) def indicator_click_callback(self, args): # example: INDICATORCLICK: {'position': 12294, 'idFrom': 0, 'modifiers': 4, 'code': 2023, 'hwndFrom': 1577146} #print('UriIndicatorAltClick indicator click callback') self.alt_held_at_click = (args['modifiers'] & self.ALT_MODIFIER) != 0 def indicator_release_callback(self, args): # example: INDICATORRELEASE: {'position': 12294, 'idFrom': 0, 'modifiers': 0, 'code': 2024, 'hwndFrom': 1577146} #print('UriIndicatorAltClick indicator release callback') if not self.alt_held_at_click: return self.alt_held_at_click = False (start_pos, end_pos) = self.get_indicator_range(self.URL_INDIC) if start_pos == end_pos: return # if click on indicator that is not URL_INDIC uri_text = editor.getTextRange(start_pos, end_pos) (uri_scheme, _, uri_path) = uri_text.partition(':') uri_path = uri_path.replace('%20', ' ').replace('%24', '$').replace('/', self.backslash) # check for optional syntax at end: edit:....txt(L127,C12) goto_line = goto_col = 0 m = re.search(r'\(L(-?\d+)(?:,C(\d+))?\)$', uri_path) if m: uri_path = uri_path[:-len(m.group())] goto_line = int(m.group(1)) if m.group(2): goto_col = int(m.group(2)) if not os.path.isfile(uri_path): # look for a relative path, relative to currently active document try: (valid_dir_of_active_doc, _) = notepad.getCurrentFilename().rsplit(os.sep, 1) except ValueError: # we started out in a "new 1" file, no path on that whatsoever self.mb('Cannot find file:\r\n\r\n{}'.format(uri_path)) return test_path_in_active_doc_dir = os.path.join(valid_dir_of_active_doc, uri_path) if os.path.isfile(test_path_in_active_doc_dir): uri_path = test_path_in_active_doc_dir else: (test_dir, test_filename) = test_path_in_active_doc_dir.rsplit(os.sep, 1) if os.path.isdir(test_dir): expanded_test_dir = os.path.abspath(test_dir) if expanded_test_dir != test_dir: self.mb('Cannot find file:\r\n\r\n{}\r\n\r\nLooked in this dir:\r\n\r\n{}'.format(test_filename, expanded_test_dir)) return self.mb('Cannot find file:\r\n\r\n{}'.format(uri_path)) return opened_in_npp = False if self.extension_from_path(uri_path).lower() in self.edit_with_npp_lowercase_extension_list: notepad.open(uri_path) opened_in_npp = True else: self.shell_open(uri_path) if opened_in_npp and goto_line != 0: if goto_line == -1: goto_line = editor.getLineCount() goto_line -= 1 if goto_col != 0: goto_col_pos = editor.findColumn(goto_line, goto_col) editor.gotoPos(goto_col_pos) else: editor.gotoLine(goto_line) if __name__ == '__main__': if 'uiac2' not in globals(): uiac2 = UIAC2() # will automatically "install" it else: # each running the script toggles install/uninstall: uiac2.uninstall() if uiac2.is_installed() else uiac2.install() print('uiac2 installed?:', uiac2.is_installed())
-
-
Wow, nice and working! Now we got a real workaround for this space character deficiency problem in NPP.
I, being a genuine nag, have found another issue, yet. There is a problem with opening files containing special - or even not that “special” - characters, like the following: edit:C:\Users\Jack\Desktop\probleem%20voor%20alldup\kopiëren.txt, where that “ë” is the culprit here. Is it because of “coding: utf-8”, in line 1 of your script, maybe?
UTF-8 is selected as the character set in my version of NPP, so that should be OK, I guess. -
@J-Brouwer said in Linked text to open other files into Notepad++:
kopiëren.txt, where that “ë” is the culprit here…
Ok, so there are 2 problems:
-
I don’t use such characters when I name files (which means I don’t typically code for that situation – but I understand that others want to name files with ‘special’ characters)
-
The non-beta PythonScript plugin uses Python2, which makes it a bit of a painful experience to write code that deals with the situation
That being said, I managed to mod the script a bit, and it seems to work when I test it with your filename in my file system – but I really have no idea how “fragile” it might be.
I’ll dub it the “2a” version of the script and here are the changes:
-
change
editor.getTextRange(start_pos, end_pos)
to beunicode(editor.getTextRange(start_pos, end_pos), 'utf-8')
-
change
ShellExecuteA(None, 'open'
to beShellExecuteW(None, u'open'
-
-
I have changed the two line fragments in v. 2, and have saved it as v. 2a.
But now, unfortunately, it does not work anymore, besides of underlining the text of the urn; after an Alt-LClick in that line, just nothing happens.
I have opened the Python console, and here is what it reports:
Python 2.7.18 (v2.7.18:8d21aa21f2, Apr 20 2020, 13:25:05) [MSC v.1500 64 bit (AMD64)] Initialisation took 32ms Ready. Traceback (most recent call last): File "C:\Program Files\Notepad++\plugins\PythonScript\scripts\Samples\UriIndicatorAltClick2a.py", line 116, in indicator_release_callback notepad.open(uri_path) Boost.Python.ArgumentError: Python argument types in Notepad.open(Notepad, unicode) did not match C++ signature: open(class NppPythonScript::NotepadPlusWrapper {lvalue}, char const * __ptr64 filename) Traceback (most recent call last): File "C:\Program Files\Notepad++\plugins\PythonScript\scripts\Samples\UriIndicatorAltClick2a.py", line 116, in indicator_release_callback notepad.open(uri_path) Boost.Python.ArgumentError: Python argument types in Notepad.open(Notepad, unicode) did not match C++ signature: open(class NppPythonScript::NotepadPlusWrapper {lvalue}, char const * __ptr64 filename)
I believe this is twice the same traceback.
-
@J-Brouwer said in Linked text to open other files into Notepad++:
But now, unfortunately, it does not work anymore
Hmm, yea, apparently I didn’t retest that part (opening a link into Notepad++)…sorry.
I think this falls into the “fragile” realm I mentioned before. Hack something to mix unicode into Python2, something else breaks…
It probably gets a lot cleaner with Python3 and the beta version of the PythonScript plugin. As I haven’t really dipped into that realm yet, I don’t have an instant solution for the problem at hand.
But this may be a good opportunity for me to test the waters with the newer PythonScript. I’ve been writing Python3 code for years, just not with Notepad++.
I’ll post something more when I have something…check back in a bit…
-
Ok, I had some free time earlier than expected…
I started with the beta 3.10.2 version of PythonScript.
Then I took theUriIndicatorAltClick2.py
version of the script (above from Sept 12 9:58 posting) and made a single-character change to it:- change
ShellExecuteA
toShellExecuteW
(If we need to refer to it further, maybe this becomes the
2b
version)And with that everything seemed to work, for files with or without “special characters” in their names.
So, @J-Brouwer , my suggestion is that you give that a try.
- change
-
@Alan-Kilborn said in Linked text to open other files into Notepad++:
I started with the beta 3.10.2 version of PythonScript.
Where could that version be found? I searched the internet for it, and all that I could find were versions below v. 2. The PythonScript plugin installed within my version of NPP is 2.
Anyway, I have tried to use the 2b version, but to no avail. According to the Python console traceback, the same error in line 116 occured.
Now I have loaded v. 2 again, so a sort of a downgrade that is. But that version is working in my situation, to a great extent.
All of this is becoming too complicated for me. Like I said before, I am not a coder. Moreover, English is not my native tongue.
Finally, I want to remark that in many languages diacritical characters (like ë, though we got Emily Brontë :-)) are (quite) more common than in English.
In my own language spelling “kopieren”, instead of “kopiëren” (Dutch, meaning “to copy”), would just be wrong. -
@J-Brouwer said in Linked text to open other files into Notepad++:
All of this is becoming too complicated for me.
All of what? What does this mean? You’re giving up on it?
You, who’s been asked to put exactly zero effort in along the way?
Ok, then, I won’t put any more effort in either… -
@J-Brouwer said in Linked text to open other files into Notepad++:
Where could that version be found?
The same github repository where the non-beta version comes from. You can find out this repository by going to Notepad++'s Plugins > Plugins Admin, clicking on the Installed tab ‡, and clicking on PythonScript – it will show you the
Homepage: ...
. You paste that into your browser, click on the Releases link on the right, and voila, you can see “v3.0.14 [Pre-Release]” right there at the top of the releases page.(‡: it’s on the Installed tab for you, because you already have PythonScript v2 installed. If someone else found these instructions but they don’t yet have PythonScript installed at all, they will have to look on the Available tab instead.)
I searched the internet for it
You might want to spend some time refining your search, then. When I searched for “Notepad++ PythonScript v3”, the first link was the old sourceforge home for PythonScript (understandable as a first hit, but it’s not the current home); the second link was a 2019 post in this forum (which predated v3); but the third link was a post from this June which talks about how to install the v3 PythonScript – success in 3 links! That’s pretty good for the first combination of search terms I tried.
-
???
-
@PeterJones said in Linked text to open other files into Notepad++:
success in 3 links! That’s pretty good for the first combination of search terms I tried.
Well, not in my case then. With about the same search words, that third hit was not given at all. As we know, everyone individually - person, machine, IP-address -, is put in “bubbles” by search engines. So, after having seen about 15 results, I gave up that effort.
-
@PeterJones said in Linked text to open other files into Notepad++:
success in 3 links!
Same for me (3rd hit) – which in my case was the current github home for the plugin.
My choice of search phrase was not influenced by Peter’s as I purposefully avoided looking at his before trying my own.
Mine was:notepad++ python script plugin
It IS unfortunate that the first hit we both obtained is for a really old version of PythonScript on sourceforge (ugh), but that page makes it fairly clear that the version there is 1.0.8.0, and since this thread was discussion version 3.0.12 (in my earlier post, I just used something 3-ish that I had on hand, I didn’t seek out the latest which appears to be 3.14), it should be obvious that the sourceforge one is not the one wanted here. BTW, any version of “3” should work for purposes of this thread.
I suppose in the future we should probably do more spoonfeeding and post exact links, for those that have trouble searching the internet. More work for the people already doing the work, I guess. :-(
-
@J-Brouwer said in Linked text to open other files into Notepad++:
Well, not in my case then. With about the same search words, that third hit was not given at all. As we know, everyone individually - person, machine, IP-address -, is put in “bubbles” by search engines. So, after having seen about 15 results, I gave up that effort.
Okay, when google’s bubble fails you, then search the forum instead. When sorting results by date (so that more recent links to pythonscript will be found), “pythonscript v3” finds a link to the PythonScript v3.0.14 as the second match (after my post above – so it would have been the first match before you asked this question).
But instead of arguing about search skills, have you been able to follow the instructions I gave on how to find the link inside Notepad++ itself? If so, have you been able to download PythonScript v3.0.14? Or have you just given up, and I’m wasting my time trying to help you learn?
-
Sure, I have found it now. Thanks. But, my initial aim was to find this PythonScript v3.0.14, and, after having read its features, maybe download it. This is my general approach when seeing stable versions against other versions.
And this time, I decided not to download this version. I only can hope that you do not think this way of acting is “forbidden” or ungrateful, after having got an, indeed, useful link from one of the forum members.
I do not really see what would have caused this disapproval towards me; really, things became too complicated for me indeed. Seemingly, there is a broad gap between coders and non-coders.
The course of events in this discussion is making me very shy.
-
@J-Brouwer said in Linked text to open other files into Notepad++:
The course of events in this discussion is making me very shy.
I’m sorry about that.
I wrote a whole many-paragraphs-long post going into the reasons for reactions … but instead, I will just sum it up in the next brief paragraph:
The more willingness you show to follow the suggestions and instructions given during a conversation in a forum like this, the better the answers you will get (in my decades on the internet, I have found this to be nearly universally true – not just in this forum). If you have difficulties, ask for help, explaining exactly what you tried or where you are having difficulty with the process. If you show a willingness to try what’s suggested and to learn, and ask polite questions for clarification without complaining, I think you will find that we will do our best to help you through problems with Notepad++.
-
@J-Brouwer said in Linked text to open other files into Notepad++:
…find this PythonScript v3.0.14, and, after having read its features, maybe download it. This is my general approach when seeing stable versions against other versions.
And this time, I decided not to download this versionThis is mainly for other readers that come along and wonder about trying out this thread’s solutions, and are worried about the statement I quoted just now.
The reason that PythonScript v3.x is not the version “recommended” by PluginsAdmin, and thus is not the easiest to obtain by users, is not because it lacks stability. Surely the people here providing help are not going to recommend you use something with real problems!
So, for interested parties, I’d recommend trying what I said to do above, in my Sep 14 1:23pm posting, to try out embedded Notepad++ text links to any file type, optionally with spaces and “special characters” in the path. I’d be interested in hearing some feedback (good or bad) on how it goes.
-
Just wanted to thank the Alan for his code and instructions and offer a couple of clarifications. This “add on” to NotePad++ has made my work much more productive.
First- When configuring NotePad++ preferences, “Cloud & Link” panel, URI Customized schemes- be aware that the items are separated by a space character. The display on my machine didn’t make this clear and I fumbled around for quite a time before I added a space before the “edit:” addition I made. One might mention that once the preference change is made, the edit URIs in text will start to act like non-working links. Do that first to be sure you got the preference change right.
Two- I am using the UriIndicatorAltClick2.py code because my main use case is opening up images pointed to in my text.
In the startup.py file, I had to add these 2 lines-import UriIndicatorAltClick2 uiac2 = UriIndicatorAltClick.UIAC2()
Three- I also use lots of non-ASCII unicode in my text, but, so far all my file names are simple ASCII, so I don’t have to worry about the py code handling unicode properly and updating to PythionScript3.x
All of my python dev experience has been with python 3 so I was concerned about whether PythonScript2.0 using Python 2 would cause problems. As far as I can see, the Python 2 stuff is isolated to the one dll installed in the plugin folder.Thanks again.
Richard Otter -