• Login
Community
  • Login

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

Scheduled Pinned Locked Moved General Discussion
6 Posts 3 Posters 1.1k 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.
  • A
    Alan Kilborn
    last edited by Alan Kilborn Dec 6, 2022, 12:09 PM Dec 6, 2022, 11:50 AM

    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
    • A Alan Kilborn referenced this topic on Dec 6, 2022, 11:53 AM
    • A
      Alan Kilborn
      last edited by Dec 30, 2022, 12:27 PM

      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
      • A Alan Kilborn referenced this topic on Dec 30, 2022, 12:27 PM
      • A Alan Kilborn referenced this topic on Aug 23, 2023, 11:22 AM
      • C
        Clyfton
        last edited by Sep 2, 2024, 4:12 AM

        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.

        P 1 Reply Last reply Sep 2, 2024, 4:15 PM Reply Quote 0
        • P
          PeterJones @Clyfton
          last edited by Sep 2, 2024, 4:15 PM

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

          C 1 Reply Last reply Sep 2, 2024, 7:58 PM Reply Quote 0
          • C
            Clyfton @PeterJones
            last edited by Sep 2, 2024, 7:58 PM

            @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
            • A
              Alan Kilborn
              last edited by Alan Kilborn Sep 2, 2024, 8:51 PM Sep 2, 2024, 8:11 PM

              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
              4 out of 6
              • First post
                4/6
                Last post
              The Community of users of the Notepad++ text editor.
              Powered by NodeBB | Contributors