Feature Request / Question: Soft Wrap at Vertical Edge (Column 80) regardless of window size
-
@Thorsten-Heuer
You can set vertical edge though but then wrap will not work according to that.- Settings → Preferences → Margins/Border/Edge
- Enable Vertical Edge
- Set it to 80

-
@h-jangra I’ve tried it out:
- Installed the NppVim plugin
- entered the commands
set tw=30andwrap.
After the first command, a thin vertical line is displayed at the position 30; the second command activates text wrapping. But, as in the “usual” NP++, the wrapping is made at the windows right edge, not at the width set with
tw.It works exactly the same way it works in NP++ without NppVim. Which is not surprising because everything is backed by NP++ and Scintilla in the end.
It’s very surprising that Scintilla does not have an option to soft wrap the text at a specified width (not window edge).
-
@fml2 said in Feature Request / Question: Soft Wrap at Vertical Edge (Column 80) regardless of window size:
It’s very surprising that Scintilla does not have an option to soft wrap the text at a specified width (not window edge).
I must be missing something… it’s very surprising to me that if this is important to you, you wouldn’t just resize the window so the edge is where you want the file to wrap.
Two alternatives (though I admit I don’t see why either would be better than just resizing the window):
-
Open something in a docking panel, like View | Document Map, and drag the divider so that it lines up with the place you want to wrap.
-
Open a new tab, move it to the second view, and drag the divider to the place you want to wrap.
-
-
Not that soft wrapping of text at a specified column other than window width is something I do, but I can think of a few reasons why one may wish to avoid resizing the window, particularly so that it’s only 80 columns wide, to accomplish the desired effect: So that the menus and tool bar aren’t adversely affected.
If I wanted to achieve custom soft wrapping myself, I’d prefer NOT changing my window size specifically because I prefer having NPP open in the same custom location and size every time I run it, and I’d have to reverse my window size changes before closing NPP in order to maintain that.
One could also increase the zoom level until the desired wrapping occurs, though that, too, would have the potentially negative side effect of reducing the amount of text visible at a time.
-
@fml2 said in Feature Request / Question: Soft Wrap at Vertical Edge (Column 80) regardless of window size:
That’s interesting! I’d think that a NP++ plugin can only do things that are also possible in NP++ itself since the underlying engine is the same.
There is a way to do it in Scintilla:
SCI_SETMARGINLEFT and SCI_SETMARGINRIGHT set margins, in pixels.A plugin, or a PythonScript, could determine the displayable text width of the Scintilla control (I think that would require getting the client width of the Scintilla control with GetClientRect, then using SCI_GETMARGINS to find the number of active margins and iterating through them with SCI_GETMARGINWIDTHN to subtract the margins; there might be an easier way that hasn’t occurred to me) and the width of a string of characters of the desired length (SCI_TEXTWIDTH with style 0), subtract, divide by two and set that margin on each side.
-
@Coises said in Feature Request / Question: Soft Wrap at Vertical Edge (Column 80) regardless of window size:
There is a way to do it in Scintilla:
SCI_SETMARGINLEFT and SCI_SETMARGINRIGHT set margins, in pixels.Not that I’d use it much, but there were a couple of times I wished the feature was there. Now you have pointed out what the underlying engine can do for this (it works, I’ve checked!).
For the real life, it’s of no use though. Who would want to set the width in pixels? To be usable by an end user, it needs a script that would calculate pixel width for the current font and also handle widows resize.
These are just theoretical thoughts since you also advised a practicl way to set the desired width (with side panels).
Thank you!
-
@fml2 Yes, currently gq in visual line mode works with custom width. I haven’t thought about that and didn’t update wrap command.
-
@fml2 said in Feature Request / Question: Soft Wrap at Vertical Edge (Column 80) regardless of window size:
To be usable by an end user, it needs a script that would calculate pixel width for the current font and also handle widows resize.
Which is why @Coises suggested that the plugin or PythonScript do the calculation, including getting the active window (or really, editor sub-window) size, the margins, and calculating character width based on the font size.
The one thing he didn’t suggest is hooking this function to a specific notification (for “handle windows resize”), but that was rather implied by the solution. In case you’re not sure, I believe that handling SCN_UPDATEUI is the right notification, because there isn’t one specific to resize. In PythonScript, that hook would be set using
editor.callback(functionNameHere, [SCINTILLANOTIFICATION.UPDATEUI])– sofunctionNameHere()would be the function that does the calculations and then sets the marginleft/marginright. (personally, I’d recommend just changing the margin-right based on the full width, rather than dividing it by 2 and splitting between left-and-right) -
My rough implementation of @Coises suggestion is as follows
# encoding=utf-8 """in response to https://community.notepad-plus-plus.org/topic/27351/ Trying to implement @Coises idea for setting the wrap to exactly 80 """ from Npp import * import ctypes from ctypes import wintypes # Define the RECT structure to match Win32 API class RECT(ctypes.Structure): _fields_ = [ ("left", wintypes.LONG), ("top", wintypes.LONG), ("right", wintypes.LONG), ("bottom", wintypes.LONG) ] def width(self): return self.right - self.left def height(self): return self.bottom - self.top def pysc_setWrap80(ed=editor): #console.write("ed={}\n".format(ed)) WRAPCHARS = 80 # Setup the Win32 function prototype user32 = ctypes.windll.user32 user32.GetClientRect.argtypes = [wintypes.HWND, ctypes.POINTER(RECT)] user32.GetClientRect.restype = wintypes.BOOL def get_window_size(hwnd): # 2. Instantiate the RECT structure rect = RECT() # 3. Call GetClientRect passing the rect by reference if user32.GetClientRect(hwnd, ctypes.byref(rect)): # 4. Parse the results # Client coordinates: top-left is always (0,0) return rect else: raise Exception("GetClientRect failed") sz = get_window_size(ed.hwnd) #console.write("{} => {}\n".format(ed.hwnd, {"width": sz.width(), "height": sz.height()})) usableWidth = sz.width() for m in range(0, 1+ed.getMargins()): w = ed.getMarginWidthN(m) usableWidth -= w #console.write("m#{}: {} => usableWidth: {}\n".format(m, w, usableWidth)) widthWrappedChars = ed.textWidth(0,"_"*WRAPCHARS)+1 # one extra pixel to be able to show the VerticalEdge indicator line wantMargin = usableWidth - widthWrappedChars if wantMargin < 1: wantMargin = 0 #console.write("{}\n".format({"windowWidth": sz.width(), "usableWidth": usableWidth, "pixelsFor80Char": widthWrappedChars, "wantMargin": wantMargin})) ed.setMarginRight(wantMargin) ed.setMarginLeft(0) def pysc_setWrap80e1(args=None): pysc_setWrap80(editor1) def pysc_setWrap80e2(args=None): pysc_setWrap80(editor2) def pysc_setWrap80eX(args=None): pysc_setWrap80(editor) editor.callback(pysc_setWrap80eX, [SCINTILLANOTIFICATION.PAINTED]) console.write("SetWrap80 registered callback\n")(this script tested in PythonScript 3)
The FAQ (https://community.notepad-plus-plus.org/topic/23039/faq-how-to-install-and-run-a-script-in-pythonscript) explains how to run a script, or how to make it run automatically at startup
The script registers the PAINTED notification – I found that UPDATEUI doesn’t happen everytime you change the window width, whereas PAINTED does… but it means that the callback is running a lot. I wish I knew of a notification that was better suited to just-on-resize, but I don’t. Maybe one of the other PythonScript experts can chime in with a better notification to use (or other suggestions for improvements). I just figured I’d do a proof of concept.
If you aren’t changing window size all that often, then it would be better to make a copy of that script that just re-adjusts the 80-character margin on demand (ie, when you run the script) by not using the
editor.callback(...)line, and instead just callingpysc_setWrap80(editor)at the end. -
P PeterJones referenced this topic
-
@PeterJones said:
I wish I knew of a notification that was better suited to just-on-resize
Hook the message loop and look for WM_SIZE messages?