All bookmarks list view
-
A recent FEATURE REQUEST, while it doesn’t make a lot of sense the way it is described, could be made to work well with an extension to the existing bookmarking feature. One of the problems with bookmarks is that there isn’t an overall “manager” to let you see all bookmarks that are currently set, in some sort of list view.
Perhaps there exists a plugin with such functionality, but I couldn’t find any. Bookmarks@Dook may come closest, but it only shows (in a list) the bookmarks for the currently active tab.
As a proposal to improve the aforementioned feature request, and bookmarks in general, I wrote a little demo in PythonScript for listing bookmarks in all opened documents. The idea here would be that the demo could be used as a model for a native implementation of a bookmarks lister/manager.
With little further ado, here’s the proposal and demo.
I call the PythonScript
BookmarksInOpenDocsList.py
and here’s its listing:# -*- coding: utf-8 -*- from __future__ import print_function import os import re import time from ctypes import (WinDLL) #------------------------------------------------------------------------------- class SaveAndRestoreActiveViewAndDocument(object): # a "context manager" to be used with "with" def __init__(self): self.view_and_index_tuple = None def __enter__(self): self.view_and_index_tuple = (notepad.getCurrentView(), notepad.getCurrentDocIndex(notepad.getCurrentView())) def __exit__(self, exc_type, exc_value, exc_traceback): notepad.activateIndex(*self.view_and_index_tuple) return False #------------------------------------------------------------------------------- class BIODL(object): def __init__(self): self.header_line_to_look_for = 'BOOKMARKS IN OPEN DOCS (double-click a bottom-level line to jump to that bookmark and close this window; hold Shift to keep this window open)' editor.callback(self.doubleclick_callback, [SCINTILLANOTIFICATION.DOUBLECLICK]) def is_shift_held(self): user32 = WinDLL('user32') VK_SHIFT = 0x10 return (user32.GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0 def doubleclick_callback(self, args): dclick_line_nbr = args['line'] if dclick_line_nbr > 0: header_line = editor.getLine(0).rstrip() if header_line == self.header_line_to_look_for: editor.setEmptySelection(args['position']) dclick_line_contents = editor.getLine(dclick_line_nbr) m = re.match(r'\tLine (?P<source_line_nbr>\d+)', dclick_line_contents) if m: source_line_nbr = int(m.group('source_line_nbr')) - 1 while dclick_line_nbr > 0: line_content = editor.getLine(dclick_line_nbr - 1).rstrip() m = re.match(r' "(?P<filename>.+?)"(?: in "(?P<dirname>.+?)")?', line_content) if m: filename = m.group('filename') dirname = m.group('dirname') pathname = dirname + filename if dirname else filename if not self.is_shift_held(): notepad.close() notepad.open(pathname) time.sleep(0.1) # sometimes a slow double-click will end up affecting the file switching to... editor.setFirstVisibleLine(editor.visibleFromDocLine(source_line_nbr) - editor.linesOnScreen() / 2) editor.setEmptySelection(editor.positionFromLine(source_line_nbr)) editor.chooseCaretX() # if up or down key is used from here, stay in column 1 break dclick_line_nbr -= 1 def run(self): NPP_BOOKMARK_MARKER_ID_NUMBER = 24 # from N++ source code: MARK_BOOKMARK = 24; NPP_BOOKMARK_MARKER_MASK = 1 << NPP_BOOKMARK_MARKER_ID_NUMBER line_nbr_and_content_tup_by_path_dict = {} with SaveAndRestoreActiveViewAndDocument(): for (pathname, buffer_id, index, view) in notepad.getFiles(): notepad.activateFile(pathname) line_nbr = editor.markerNext(0, NPP_BOOKMARK_MARKER_MASK) bm_list = [] while line_nbr != -1: line_content = editor.getLine(line_nbr).strip() bm_list.append((line_nbr, line_content)) line_nbr = editor.markerNext(line_nbr + 1, NPP_BOOKMARK_MARKER_MASK) if len(bm_list) > 0: line_nbr_and_content_tup_by_path_dict[pathname] = bm_list if len(line_nbr_and_content_tup_by_path_dict) > 0: notepad.new() notepad.setLangType(LANGTYPE.PYTHON) # provide fold points as a nicety eol = ['\r\n', '\r', '\n'][editor.getEOLMode()] editor.addText(self.header_line_to_look_for + eol) for pathname in line_nbr_and_content_tup_by_path_dict: directory = pathname.rsplit(os.sep, 1)[0] filename = pathname.rsplit(os.sep, 1)[-1] dir_to_show = '' if filename == directory else ' in "{D}{S}"'.format(D=directory, S=os.sep) editor.addText(' "{F}"{DTS}'.format(F=filename, DTS=dir_to_show) + eol) for bm in line_nbr_and_content_tup_by_path_dict[pathname]: colon = ':' if len(bm[1]) > 0 else '' editor.addText('\tLine {L}{c} {C}'.format(L=bm[0] + 1, c=colon, C=bm[1]) + eol) editor.setSavePoint() notepad.menuCommand(MENUCOMMAND.EDIT_SETREADONLY) #------------------------------------------------------------------------------- if __name__ == '__main__': try: biodl except NameError: biodl = BIODL() biodl.run()
To demo it, have some files with bookmarks set; here’s an example:
Run the script and it will produce this in a new tab:
Double-click one of the
Line xxx
lines and it will change the active tab and jump to the bookmarked line (in the original file tab) that was chosen.Notes:
-
To collect the bookmark info for all open docs, the demo has to sequentially activate each tab that a user has open. While this causes screen flash, and could be slow if a user has a lot of open tabs and/or large files, this is just a demo.
-
I set the language of the tab showing the output to Python so that it would have “fold points”. Python may not be ideal, but another idea I had for this hit somewhat of a DEAD END.
So the overall idea is to implement something like the output I show in a native Notepad++ control, ideally as part of core Notepad++.
Thoughts/criticisms/extensions welcomed…
-
-
Isn’t the requirement completely covered by the bookmark feature that is already available? Or what am I missing? Even if the point is to have a direct jump, I would argue that depending on where you are in the code, it takes at most three steps to get to where you want to be.
@alan-kilborn
Assuming the point is to edit text at the destination marks, the “bookmark list view” can quickly become invalid. So something like an update location mechanism would be needed, or am I misunderstanding the point of the script? -
@ekopalypse said in All bookmarks list view:
am I misunderstanding the point of the script?
I think maybe you are. The script is just a simple demo of how a real bookmarks “manager” could work, and at that, just the basics. (I don’t know that I like the word “manager” but having trouble with a good name.)
The point of the discussion and the demo is just to solicit comments, rather than simply describing something with words in an issue.
I do like the “style” of the output in the demo (if I do say so, myself) which works very similarly to the Search result window, so it is something users would already be very comfortable with.
@ekopalypse said in All bookmarks list view:
Isn’t the requirement completely covered by the bookmark feature that is already available?
Hardly. Bookmarks are great if I set one or two. Beyond that, without some kind of “manager” I quickly lose “context” of where I’ve set them. The plugin I mentioned before provides some of this context, but only at a per-file level.
@ekopalypse said in All bookmarks list view:
if the point is to have a direct jump
That’s one point. Another point, which I might argue is equally important, is where the bookmarks currently are. Without this, all I know is that I have some quantity of bookmarks, set somewhere.
@ekopalypse said in All bookmarks list view:
it takes at most three steps to get to where you want to be.
Hmm. Currently if I have 10 bookmarks set in a single file, and my caret is somewhere between the 6th and 7th bookmarks, and I want to go to the 2nd bookmark (presuming I can remember what logical line that is set at – to know I want that one), how many steps does that take?
@ekopalypse said in All bookmarks list view:
Assuming the point is to edit text at the destination marks, the “bookmark list view” can quickly become invalid. So something like an update location mechanism would be needed
Even with the demo, it could be used in an “invoke” -> “jump” (which autocloses the original results) -> “edit” -> “(re)invoke” -> etc. cycle, where the reinvoke freshens any changed locations in the output.
But again, just a demo, a real version could certainly remain open at all times and be freshened automatically.
Your comments make me feel as if I’m really missing the (book)mark on this, if you’ll excuse the pun. :-(
-
Sorry, I did not express myself clearly. The first part of my comment should refer to your mentioned feature request. There it asks for a goto extension for 5 or 5 additional goto locations. I don’t see the added value there compared to the bookmarks.
-
@ekopalypse said in All bookmarks list view:
it asks for a goto extension for 5 or 5 additional goto locations. I don’t see the added value there compared to the bookmarks.
I see. I think maybe the originator of that request doesn’t even know about the bookmarking feature.
But the request really made me start thinking about bookmarks and the fact that I don’t use them much, mainly because I can’t mentally keep track of them. But why should I have to mentally keep track of them when I have a computer to do it.
-
@alan-kilborn said in All bookmarks list view:
But why should I have to mentally keep track of them when I have a computer to do it.
Agree. I whipped up an NppExec script to list bookmarks as well and provide the double-click/goto feature from the NppExec console. I still don’t use Bookmarks all that often though.
Cheers.
-
I don’t use them much, mainly because I can’t mentally keep track of them.
I still don’t use Bookmarks all that often
The only times I use Bookmarks are for the temporary search-and-select benefits that the Search > Bookmark menu gives you. I do not remember leaving multiple bookmarks active beyond my memory’s ability to track them. About the only thing that a “long-term” bookmark would help me with is getting back to the particular function I was editing: since I said the word “function”, it’s obviously easier to get there with the Function List panel for me. I just don’t have enough non-code text files that are big enough to benefit from bookmarks… and when I do, I usually make a UDL+FunctionList for them anyway, so they are effectively code with some pattern that gets me to the right ballpark. I cannot think of any truly random, non-patterened places that I would ever have a need to mark.
But I know that my Notepad++ usage model is different from many (as has been evidenced time and again in this Community), and I do agree that if someone did have a need for more than one or two long-term bookmarks, having a Manager for that would likely be helpful. I somehow doubt that TPTB would find much use in that, so it will probably be relegated to Plugin land. At which point, I would probably hit up Bookmarks@Dook to see if Dook was willing to add a way to track/show all tabs’ bookmarks in one view. Oh, issue #11 starts with “all bookmarks of all opened files” request, and that was more than six months ago – and Dook rejected the multi-tab portion of that request because “NPP does not provide API to retrieve information from open tabs withouts switching to them”. (Unfortunately, that plugin hides the source code; otherwise, someone could learn from the way it was implemented, or suggest a PR to the author.)
I am tempted to suggest a workaround to Dook. I probably will, actually. (Addendum: added my comment there)
-
@peterjones said in All bookmarks list view:
Dook
To me, “Dook” doesn’t seem like much of a “team player”. Not posting your source code for such an item is in bad taste. Personally, I’d not count on Dook for anything.
@peterjones said in All bookmarks list view:
I am tempted to suggest a workaround to Dook. I probably will, actually.
Curious as to what this might be.
-
@peterjones said in All bookmarks list view:
I do not remember leaving multiple bookmarks active beyond my memory’s ability to track them
This is my “problem” too, as I said.
But, I wonder if I might feel differently and use this feature more if it had a nice “manager”. I guess I won’t get this answered until there IS a real manager. :-)
-
Curious as to what this might be.
I don’t know that it’s all that brilliant: but since bookmarks don’t change except when a given tab is active anyway, just do a single scan of all files during plugin initialization, and then have the plugin behave normally for tracking the changes on the active tab’s bookmarks. But maybe I’m missing something obvious why that wouldn’t work.
-
@alan-kilborn said in All bookmarks list view:
@peterjones said in All bookmarks list view:
I do not remember leaving multiple bookmarks active beyond my memory’s ability to track them
This is my “problem” too, as I said.
I think I phrased that poorly. My “I do not remember” portion meant more, “I cannot now think of a time when I left multiple bookmarks active beyond my memory’s ability to track them”. Or said another way, “I’ve never run into the situation where I needed to manage a bookmark long-term”
-
@alan-kilborn well these bookmarks are saved collectively of all notes. i think its not good approach to save them collectively. because in situation like me where you have 70+ notes open in notepad++ and if am currently working in note # 3 and this bookmark file will open with a lot of other bookmarks and you have to switch between bookmark tab and your note tab back and forth. this approach is good for normal users but not for developers. if jump points for single note is maintain within its CTRL + G modal then will be good and when note is close it should be destroyed with it.
-
@alan-kilborn
For me this is very useful script. Thank you!
But I’m very beginner in Python and can’t think out how to add a possibility to “Go back to previous location”? In case I decide not to go to any bookmark, or if I see that I haven’t set bookmark to right place.
I would be very thankful if you find time to help with this. -
@andi-kiissel said in All bookmarks list view:
“Go back to previous location”? In case I decide not to go to any bookmark
For this case you would simply close the the “new X” (X is a digit) tab; you should be returned to the point where you were editing when you invoked the script.
But it maybe feels like I’m misunderstanding something…?
-
@alan-kilborn
Perhaps I have missed or misunderstod some setting?
By default new tab opens as last rightmost tab. If I close it, then activates new last rightmost tab. If I have 10 tabs and run script from 3rd tab, then after closing this 11th tab I will be in 10th tab, not in 3rd. -
@andi-kiissel said in All bookmarks list view:
By default new tab opens as last rightmost tab. If I close it, then activates new last rightmost tab
Ah, you must have changed this setting away from the default; default shown here:
I find that if I create a new file, do something to it, then close it, it makes the most sense to then be left editing the file I “most-recently-used”, instead of whatever happens to be the right-most existing tab.
The script is meant to be a simple demo, but if you do not want to tick the option I show (for some reason), I could see what I can do about “fixing” the script.
-
@alan-kilborn
I’m sorry! I don’t like this Document Switcher.
But now I think I found a bug: without Enable Document Switcher
sometimes Enable MRU is greyed out:
and sometimes not:
If I enable MRU then yes, last edited tab will be activated. -
@andi-kiissel said in All bookmarks list view:
I don’t like this Document Switcher.
I’m not sure what you mean by this.
If you don’t like the Ctrl+Tab feature, don’t use it.now I think I found a bug
If you can provide some steps to reproduce, an actual bug report can be created.
-
@alan-kilborn said in All bookmarks list view:
If you don’t like the Ctrl+Tab feature, don’t use it.
I do like Ctrl+Tab feature, but don’t like table like this:
Ctrl+Tab feature works fine without Document Switcher been enabled!If you can provide some steps to reproduce, an actual bug report can be created.
Well, starting position:
Switch off first “Enable”, “Enable MRU…” switches off too and stays grey:
Restart N++, both are available:
And I can switch “Enable MRU…” on alone:
I’m not sure that I can describe this good enough for official bug report. And perhaps there is some logic.Anyway, now I got things work how I like.
Thank you! -
The marker ID used for bookmarks changed in Notepad++ 8.4.6 (and later). It is now 20, instead of 24. So, all references to 24 in this thread and/or its script(s), should be changed to 20.