File/tab specific word wrap (vs. global enable) -- THREAD REBOOT
-
I thought it might be time to “freshen” the title topic, as it is something that comes up from time to time, and existing references (see the script HERE in the first two postings of the thread) are a little dated – coming up on 7 years old!
Also, the script provided in that thread is a bit awkward, perhaps because it is so old, I don’t know…
Anyway, if you’ve ever wanted the Word wrap setting on the View menu to be in effect on certain file tabs that you have open, and not on others, well, that’s currently a limitation of Notepad++ (the setting is currently “global” to all of your tabs). But with a script, we can do better than that, and achieve true tab-level control of what is wrapped and what isn’t.
With each run of the script, the state of wrapping for the active file will be “toggled” – if wrap was “off” when the script was run, it will be turned “on”; if wrap was “on” at script running, it will be turned “off”.
A note about using the script: If you use it, you need to totally forget and ignore the View menu’s command for Word wrap. Just…forget it; use (by running) the script exclusively to toggle the current setting for the active file/tab. Don’t count on the View menu entry to show you the current state, either – it will often lie to you if you are using the script.
I call the script
WordWrapToggleForActiveTab.py
and here is its listing:# -*- coding: utf-8 -*- # references: # https://community.notepad-plus-plus.org/topic/23855/file-tab-specific-word-wrap-vs-global-enable-thread-reboot # https://community.notepad-plus-plus.org/topic/10985/file-specific-word-wrap-vs-global-enable # https://github.com/notepad-plus-plus/notepad-plus-plus/issues/5232 from Npp import * #------------------------------------------------------------------------------- class WWTFAT(object): def __init__(self): self.wrap_by_buffer_id_dict = {} notepad.callback(self.bufferactivated_callback, [NOTIFICATION.BUFFERACTIVATED]) def bufferactivated_callback(self, args): bid = args['bufferID'] editor.setWrapMode(self.wrap_by_buffer_id_dict[bid] if bid in self.wrap_by_buffer_id_dict else 0) def toggle_wrap_mode(self): bid = notepad.getCurrentBufferID() if bid in self.wrap_by_buffer_id_dict: self.wrap_by_buffer_id_dict[bid] = 1 if self.wrap_by_buffer_id_dict[bid] == 0 else 0 # toggle else: self.wrap_by_buffer_id_dict[bid] = 1 # turn wrap on for current file editor.setWrapMode(self.wrap_by_buffer_id_dict[bid]) self.sb_output('Wrapping is {} for active tab'.format('ON' if self.wrap_by_buffer_id_dict[bid] else 'OFF')) def sb_output(self, *args): # output to N++'s status bar (will be overwritten by N++ e.g. when active tab is changed) notepad.setStatusBar(STATUSBARSECTION.DOCTYPE, ' '.join(map(str, args))) #------------------------------------------------------------------------------- # to run via another file, e.g., startup.py, put these lines (uncommented and unindented) in that file: # import WordWrapToggleForActiveTab # wwtfat = wwtfat.WWTFAT() # when this script is run interactively, it will toggle the wrap setting on the currently active tab if __name__ == '__main__': try: wwtfat except NameError: wwtfat = WWTFAT() wwtfat.toggle_wrap_mode()
For easy access, I like to assign the script to the keycombo Ctrl+Alt+w, and I also have it on the editor right-click context menu:
I achieve the entry on the context menu by putting this line in the appropriate file (see “setting up and using…”) below:
<Item PluginEntryName = "Python Script" PluginCommandItemName = "WordWrapToggleForActiveTab" ItemNameAs = "Toggle wrap on/off for this file Ctrl+Alt+w" />
When the wrap state is changed via the script, the Notepad++ status bar will show the current state, example:
For info on setting up and using a script, see HERE.
-
-
In the time since I rebooted the topic, someone has found it useful, but they have asked for the wrap state of files in the default session to be remembered across runs of Notepad++.
Here’s
WordWrapToggleForActiveTabWithPersistence.py
:# -*- coding: utf-8 -*- from __future__ import print_function # references: # https://community.notepad-plus-plus.org/topic/23855/file-tab-specific-word-wrap-vs-global-enable-thread-reboot # https://community.notepad-plus-plus.org/topic/10985/file-specific-word-wrap-vs-global-enable # https://github.com/notepad-plus-plus/notepad-plus-plus/issues/5232 from Npp import * import os import inspect import json #------------------------------------------------------------------------------- class WWTFATWP(object): def __init__(self): self.debug = True if 0 else False self.this_script_name = inspect.getframeinfo(inspect.currentframe()).filename.split(os.sep)[-1].rsplit('.', 1)[0] self.wrap_by_buffer_id_dict = {} self.pathname_by_buffer_id_dict = {} self.this_script_path_without_ext = inspect.getframeinfo(inspect.currentframe()).filename.rsplit('.', 1)[0] self.settings_json_file_path = self.this_script_path_without_ext + '.json' # read settings written the last time Notepad++ was shut down: pathnames_with_wrap_on_list = [] if os.path.isfile(self.settings_json_file_path): self.dprint('json file found') try: with open(self.settings_json_file_path) as f: pathnames_with_wrap_on_list = json.load(f)['wrap_on_list'] except: self.dprint('problem opening/reading json file') self.dprint('pathnames_with_wrap_on_list:', pathnames_with_wrap_on_list) for (pathname, buffer_id, index, view) in notepad.getFiles(): self.wrap_by_buffer_id_dict[buffer_id] = 1 if pathname in pathnames_with_wrap_on_list else 0 self.pathname_by_buffer_id_dict[buffer_id] = pathname self.dprint('wrap_by_buffer_id_dict:', self.wrap_by_buffer_id_dict) self.dprint('pathname_by_buffer_id_dict:', self.pathname_by_buffer_id_dict) notepad.callback(self.bufferactivated_callback, [NOTIFICATION.BUFFERACTIVATED]) notepad.callback(self.shutdown_notify, [NOTIFICATION.SHUTDOWN]) editor.callback(self.updateui_callback, [SCINTILLANOTIFICATION.UPDATEUI]) self.bufferactivated_callback(None) # artificial call to get the wrap mode set for the current file def updateui_callback(self, args): # this is mainly useful for when a tab is renamed; so that it gets "noticed" by our logic asap self.bufferactivated_callback(None) def bufferactivated_callback(self, args): curr_bid = args['bufferID'] if args else notepad.getCurrentBufferID() curr_pathname = notepad.getCurrentFilename() editor.setWrapMode(self.wrap_by_buffer_id_dict[curr_bid] if curr_bid in self.wrap_by_buffer_id_dict else 0) self.pathname_by_buffer_id_dict[curr_bid] = curr_pathname # maintain link between constant bid and possibly changing pathname def shutdown_notify(self, args): # write settings so they persist between runs of N++ pathnames_with_wrap_on_list = [] for bid in self.pathname_by_buffer_id_dict: pathname_for_buffer_id = self.pathname_by_buffer_id_dict[bid] if bid in self.wrap_by_buffer_id_dict: wrap_for_buffer_id = self.wrap_by_buffer_id_dict[bid] if wrap_for_buffer_id == 1: # only save state for paths that have wrap turned on if pathname_for_buffer_id not in pathnames_with_wrap_on_list: pathnames_with_wrap_on_list.append(pathname_for_buffer_id) else: pass # this part of the code will be reached for the renegade "new x" document that isn't visible! try: with open(self.settings_json_file_path, 'w') as f: f.write(json.dumps({ 'wrap_on_list' : pathnames_with_wrap_on_list }, sort_keys=True, indent=1, default=str)) except: pass def toggle_wrap_mode(self): curr_bid = notepad.getCurrentBufferID() curr_pathname = notepad.getCurrentFilename() if curr_bid in self.wrap_by_buffer_id_dict: self.wrap_by_buffer_id_dict[curr_bid] = 1 if self.wrap_by_buffer_id_dict[curr_bid] == 0 else 0 # toggle else: self.wrap_by_buffer_id_dict[curr_bid] = 1 # turn wrap on for current file editor.setWrapMode(self.wrap_by_buffer_id_dict[curr_bid]) self.sb_output('Wrapping is {} for active tab'.format('ON' if self.wrap_by_buffer_id_dict[curr_bid] else 'OFF')) self.pathname_by_buffer_id_dict[curr_bid] = curr_pathname # maintain link between constant bid and possibly changing pathname def print(self, *args, **kwargs): try: self.print_first except AttributeError: self.print_first = True if self.print_first: console.show() # this will put input focus in the PS console window, at the >>> prompt #console.clear() editor.grabFocus() # put input focus back into the editor window self.print_first = False d_tag = '<DBG>' if 'debug' in kwargs else '' if 'debug' in kwargs: del kwargs['debug'] print(self.__class__.__name__ + d_tag + ':', *args, **kwargs) def dprint(self, *args, **kwargs): # debug print function if self.debug: kwargs['debug'] = True self.print(*args, **kwargs) def sb_output(self, *args): # output to N++'s status bar (will be overwritten by N++ e.g. when active tab is changed) notepad.setStatusBar(STATUSBARSECTION.DOCTYPE, ' '.join(map(str, args))) #------------------------------------------------------------------------------- # to run via another file, e.g., startup.py, put these lines (uncommented and unindented) in that file: # import WordWrapToggleForActiveTabWithPersistence # wwtfatwp = WordWrapToggleForActiveTabWithPersistence.WWTFATWP() if __name__ == '__main__': try: wwtfatwp except NameError: wwtfatwp = WWTFATWP() # when this script is run interactively, it will toggle the wrap setting on the currently active tab wwtfatwp.toggle_wrap_mode()
-
-
-
31 Aug: Great job on the script. Thanks.
I followed the install instructions.
Unfortunately, the persistence is not working for me.
When I run the script, it word-wraps and says “word wrap is ON” at the bottom.
If I restart Notepad++, the file no longer wraps, yet the script remembers the state.
So, when I run the script again, it says “word wrap is OFF,” so it remembered that word wrap should have been ON but it actually wasn’t.
1 Sep follow up:
It was suggested that I input the wrong script so I reversed all the instructions and deleted the file (I couldn’t find instructions to remove a python script, so I assume just deleting the file is enough).
Then I re-ran the instructions for the persistence script and still have the same problem. -
@Clyfton ,
If it’s not applying the persistent wrap-state when you first start Notepad++, check the following:
-
Did you remember to add the lines to your user startup script?
import WordWrapToggleForActiveTabWithPersistence wwtfatwp = WordWrapToggleForActiveTabWithPersistence.WWTFATWP()
That’s required for it to automatically wrap the remembered file(s) after you restart Notepad++. Once you make that change, you will need to restart Notepad++ for it to take effect.
-
Did you change your Plugins > PythonScript > Configuration… > Initialisation setting to
ATSTARTUP
? That is required for it to automatically wrap the remembered file(s) after you restart Notepad++ -
Do you have two Views? If so, then if you have
longline.txt
with persistent-wrap ON in View1, butother.txt
is the active file in View2 when you start Notepad++,longline.txt
won’t actually show as wrapped until you switch the focus to that tab (by clicking on it).
-
-
@PeterJones Thanks! That did the trick. I don’t see the instructions about adding the lines to startup in the original instructions above, but what you added here solved the problem.
-
This thread is older; newer threads about scripts refer one to this site’s FAQ entry, which contains info on running a script from startup.
But, really, I could have been more explicit about what you needed to do to get it to activate upon startup, when I posted the persistent version of the script – sorry about not doing that.
I don’t see the instructions about adding the lines to startup in the original instructions above
For the record, the instructions were in the source code for the script itself, down near the end of the file.