Community
    • Login

    File/tab specific word wrap (vs. global enable) -- THREAD REBOOT

    Scheduled Pinned Locked Moved General Discussion
    6 Posts 3 Posters 784 Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • Alan KilbornA
      Alan Kilborn
      last edited by Alan Kilborn

      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:

      aec5af23-1d66-42be-a103-88f787927b31-image.png

      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:

      23c97418-0b1c-42e5-8eac-82abc42df4b1-image.png

      For info on setting up and using a script, see HERE.

      1 Reply Last reply Reply Quote 2
      • Alan KilbornA Alan Kilborn referenced this topic on
      • Alan KilbornA
        Alan Kilborn
        last edited by

        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()
        
        1 Reply Last reply Reply Quote 1
        • Alan KilbornA Alan Kilborn referenced this topic on
        • Alan KilbornA Alan Kilborn referenced this topic on
        • ClyftonC
          Clyfton
          last edited by

          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.

          PeterJonesP 1 Reply Last reply Reply Quote 0
          • PeterJonesP
            PeterJones @Clyfton
            last edited by

            @Clyfton ,

            If it’s not applying the persistent wrap-state when you first start Notepad++, check the following:

            1. 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.

            2. 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++

            3. Do you have two Views? If so, then if you have longline.txt with persistent-wrap ON in View1, but other.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).

            ClyftonC 1 Reply Last reply Reply Quote 0
            • ClyftonC
              Clyfton @PeterJones
              last edited by

              @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.

              1 Reply Last reply Reply Quote 1
              • Alan KilbornA
                Alan Kilborn
                last edited by Alan Kilborn

                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.

                1 Reply Last reply Reply Quote 2
                • First post
                  Last post
                The Community of users of the Notepad++ text editor.
                Powered by NodeBB | Contributors