Wrap input?

Posted by Neva on Mon 15 Aug 2011 02:01 AM — 25 posts, 92,042 views.

USA #0
Something I've noticed now that I've got a huge monitor on my desktop--it's great because I can spawn a lot of stuff off into a miniwindow, but it's hard to judge how long my input is in "real" 80-character lines because while my output text wraps at column 80, the input text doesn't. It would be nice if one could set a wrap column for both.
USA #1
Any chance on this, still? It's a minor thing but visually annoying when I'm writing a bunch; it's very hard to read things that wide.
USA Global Moderator #2
It's not built in, but it looks like you should easily be able to do this with a combination of the OnPluginCommandChanged() callback and GetCommand() and PushCommand()+SetCommand().

At every call to OnPluginCommandChanged, use GetCommand() to get the current input area text. Then check for the distance between line break characters. If any distance is more than 80 chars, insert a line break. Then use PushCommand() to clear the buffer and then SetCommand(final_text) to replace the input with the newly split text.

If someone else doesn't get to it first before I find the time (probably not today), I'll write up a quick plugin for you.
Amended on Wed 23 Nov 2011 03:45 PM by Fiendish
USA #3
Fiendish said:
At every call to OnPluginCommandChanged, use GetCommand() to get the current input area text. Then check for the distance between line break characters. If any distance is more than 80 chars, insert a line break. Then use PushCommand() to clear the buffer and then SetCommand(final_text) to replace the input with the newly split text.

Wouldn't that effectively break one command into two? If I type "say to SomeBody something really really really really long" (insert as many "really"s as needed here) and the command gets wrapped by this plugin, it would get sent as "say to SomeBody something really really really" and "really long", which is wrong.
USA Global Moderator #4
Of course. This wouldn't be on all the time. Only when one needs to write something formatted, like a note. Aardwolf, for example, leaves wrapping of says and channel messages to the client, but limits (circumventably) forum notes to 79 char width. Players frequently ask about ways to automatically format notes to fit into the width restriction. One way would be to automate the width circumvention, and another would be to automate wrapping like OP seems to want.
Amended on Wed 23 Nov 2011 08:37 PM by Fiendish
USA #5
This might be helpful, then. I use something similar for writing newsposts and journal entries.

<aliases>
  <alias
   match="^\s*compose\s*$"
   enabled="y"
   regexp="y"
   send_to="12"
   omit_from_output="y"
   ignore_case="y"
   keep_evaluating="y"
   sequence="100"
  >
  <send>local text = utils.editbox("Enter your input below.", "Input Box")
if text then
  Send(text)
end</send>
  </alias>
</aliases>


I experimented with reply_width to make the input area wrap closer to 80 characters (which I'm sure you could do precisely with math and font metrics), but it didn't seem to do anything.
Amended on Wed 23 Nov 2011 08:47 PM by Twisol
USA Global Moderator #6
[EDIT] replaced by the version below
Amended on Mon 28 Nov 2011 05:52 AM by Fiendish
USA #7
Okay, yeah. Something that breaks lines? Is NOT going to be useful, here. At all. That would be more annoying than things as they currently are. I don't want multiple lines sent to the server, I just want to be able to see my input the way it's going to show up on the other send, every time.
USA Global Moderator #8
How do you know how it shows up on the other end?
Australia Forum Administrator #9
What you can do is add another three lines that take away the extra linefeeds, like this:



function OnPluginCommandEntered (sText)
  return string.gsub (sText, "\n", " ")
end -- OnPluginCommandEntered 


]]>
</script>
</muclient>


Add the three lines in bold just before the last three lines of the plugin (shown above).
Australia Forum Administrator #10
Fiendish said:

How do you know how it shows up on the other end?


Well if you do: say <blah blah>

Then only the first line is said and the other are rejected as bad commands.
USA #11
That helps a little bit. The "standard" line on this game, also, is always 78-80 characters long, and we have some general guidelines for how many lines long things should be, and it's a little annoying to have to test everything out either in another program or whatever to see how long it all is. The big question then is the ability to edit stuff, which is certainly necessary in anything you're writing that's more than a few words long. I'm poking at the script and I haven't been able to figure out anything that would automatically allow that, yet. I think I could set something else to remove the line breaks, edit, and then add them back, but that, again, is adding just so much extra work to something that I'm not saving time over pasting stuff into a text editor every time.

Is this really that hard to implement in the program itself? I'm not against using a script if it works, but I've never really understood why this is a simple option available for output but not input.
USA #12
Low-tech workaround: resize your window so the input bar only has enough room for 80 characters.
USA Global Moderator #13
[EDIT]found bugs, so pulled code for now.

Quote:
Low-tech workaround: resize your window so the input bar only has enough room for 80 characters.
This isn't viable at all for miniwindow-based layouts unless you like the idea of constantly resizing your world window.

Quote:
What you can do is add another three lines that take away the extra linefeeds, like this:
I actually don't think that would have worked as expected for several of my test cases.

Nick Gammon said:
Fiendish said:
How do you know how it shows up on the other end?
Well if you do: say <blah blah>
Then only the first line is said and the other are rejected as bad commands.
That says nothing about what another player would see if you type a command longer than 80 characters. This sort of answers, but not really:
Quote:
The "standard" line on this game, also, is always 78-80 characters long

Unless the MUD is wrapping everything you send to fit within an 80 character width, e.g. if you send "say a_line_longer_than_80_chars" then the MUD displays "player says '80 chars\r\n80chars\r\n etc.'", then I don't see the value in this. But maybe that's what is going on. But then this can't generically account for that initial "player says" bit, so it'll still not be ideal. Not sure how to get around that last problem. I can only hope that your mud starts the 80-wide paragraph on a new line while I work on a way to make editing in the middle of lines work without any bugs. :p
Amended on Fri 25 Nov 2011 03:09 AM by Fiendish
USA Global Moderator #14
This version should wrap the input bar non-destructively so that data gets sent with only those newlines that were added explicitly by the player. It also allows modifications/insertions mid-line. The comment about me not seeing the point of this still applies, but if this is what the OP wants, then this is what the OP gets.

To get a version that sends with the wrap line breaks included (useful for automatically formatting Aardwolf notes, for example, if you change 80 to 79), just remove these three lines
function OnPluginCommandEntered(sText)
   return stripLoneLF(sText)
end

And, of course, modify the plugin name/purpose appropriately, as it's no longer non-destructive.

Template:saveplugin=AutoWrapInput
To save and install the AutoWrapInput plugin do this:
  1. Copy the code below (in the code box) to the Clipboard
  2. Open a text editor (such as Notepad) and paste the plugin code into it
  3. Save to disk on your PC, preferably in your plugins directory, as AutoWrapInput.xml
    • The "plugins" directory is usually under the "worlds" directory inside where you installed MUSHclient.
  4. Go to the MUSHclient File menu -> Plugins
  5. Click "Add"
  6. Choose the file AutoWrapInput.xml (which you just saved in step 3) as a plugin
  7. Click "Close"
  8. Save your world file, so that the plugin loads next time you open it.


<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<muclient>
<plugin
   name="AutoWrapInput_non_destructive"
   author="Fiendish"
   id="0620f3f9b9bf0ea4d2f5703b"
   language="Lua"
   purpose="Wraps input at 80 characters non-destructively"
   save_state="y"
   date_written="2011-11-23 19:36:00"
   requires="4.79"
   version="1.0"
   >

</plugin>

<aliases>
<alias
   match="^wrap_input( (.*))?$"
   enabled="y"
   regexp="y"
   sequence="100"
   ignore_case="y"
   script="activate_wrapping"
></alias>
</aliases>
<script>

<![CDATA[

SetVariable("wrapping", GetVariable("wrapping") or "off")
local wrapping = (GetVariable("wrapping") == "on")

function activate_wrapping(name, line, wildcards)
   if wildcards[1] == "" then
      Note("Input wrapping is currently: "..GetVariable("wrapping"))
   elseif wildcards[2] == "on" or wildcards[2] == "off" then
      SetVariable("wrapping", wildcards[2])
      wrapping = (wildcards[2] == "on")
      Note("Input wrapping set to: "..wildcards[2])
   else
      Note("WRAP_INPUT ERROR: Expected either 'wrap_input on' or 'wrap_input off'.")
   end
end

-- We distinguish between \n and \r\n given an assumption that on Windows (and through Wine)
-- the Enter key always inserts \r\n so that \n can be used to display wrapped lines (MUSHclient handles this)
-- while differentiating line breaks inserted by the user.

function lines(str)
  local t = {}
  local function helper(line) table.insert(t, line) return "" end
  helper((str:gsub("(.-)\r\n", helper)))
  return t
end

function OnPluginCommandEntered(sText)
   return stripLoneLF(sText)
end

function stripLoneLF(sText)
   return string.gsub(sText,"([^\r])\n","%1")
end

function OnPluginCommandChanged()
   if not wrapping then 
      return 
   end
   
   local user_input = GetCommand()
   local user_input_lines = lines(stripLoneLF(user_input))
   for i,v in ipairs(user_input_lines) do
      local char_count = 80
      local line_len = #v
      while line_len > char_count do
         if string.sub(user_input_lines[i],char_count+1,char_count+1) ~= "\n" then
            user_input_lines[i] = string.sub(user_input_lines[i],1,char_count).."\n"..string.sub(user_input_lines[i],char_count+1)
            char_count = char_count + 1
            line_len = line_len + 1
         end
         char_count = char_count + 80
      end
   end
   final_input = table.concat(user_input_lines,"\r\n")
   
   -- prevent display errors if the user has input auto-resizing enabled
   -- by temporarily changing the minimum number of lines to the amount that
   -- the user has typed
   if GetOption ("auto_resize_command_window") == 1 then
      min_lines = GetOption ("auto_resize_minimum_lines")
      max_lines = GetOption ("auto_resize_maximum_lines")
      SetOption ("auto_resize_minimum_lines", math.min(max_lines,#user_input_lines))
   end
      
   -- enable insertion/deletion in the middle of sections
   local selection_start = GetInfo(236)
   local selection_end = math.max(0,selection_start-1)
   
   SetCommandSelection (1, -1) -- select everything
   PasteCommand(final_input) -- overwrite with wrapped version
   
   -- put the cursor back in the right place after mid-line insertion/deletions
   local count = 0
   for i in string.gmatch(string.sub(user_input,1,selection_end),"[^\r]\n") do
      count = count - 1
   end
   for i in string.gmatch(string.sub(final_input,1,selection_end),"[^\r]\n") do
      count = count + 1
   end
   SetCommandSelection (selection_start+count, selection_end+count)
   
   -- undo the above resize change
   if GetOption ("auto_resize_command_window") == 1 then
      SetOption ("auto_resize_minimum_lines", min_lines)
   end
end


]]>
</script>
</muclient>
Amended on Mon 28 Nov 2011 06:13 AM by Fiendish
USA #15
Just to kinda clarify purpose, here:

I have my output set to wrap at 80 chars. The game tells people, "Wrap at 80 chars, or things may not look right to you," and sets guidelines like, "This thing should be about X lines long," where that actually means 80X characters. But my input box naturally wraps at the screen width, which is more like 160 characters on this computer and markedly more on that on my other one, so I have to mentally figure out--okay, this thing should be five lines at 80, so 2.5 lines on my laptop screen. (And I'm not even sure how many on my big monitor.) This other thing should be no more than twenty lines at 80... etc. A lot of it is about preventing too much spam or blocks of things people won't read, or else general guidelines for how much detail something should have. I typically, until this point, have pasted stuff into a text editor that I can set to wrap at 80, because that much math in my head is just annoying.

Pretty much no input MUSH servers will include line breaks; we have to replace them with %R's.

So, that part said! I finally got the chance to try this and... it doesn't work. After poking at it, I was able to determine that basically, the input window just doesn't see \n as a line break. Have you actually been running this, Fiendish? Is it displaying okay for you?

(The same text pasted into Notepad++ shows the line feeds, but not in regular old Notepad, so I'm guessing this has to do with the default Windows edit control.)
USA #16
Also noticed in the process that this kills undo. Hmm...
USA #17
Okay, so, I'm not going to upload this because it doesn't work very well, but long story short, switching to using \r\r\n instead of just \n and then changing around some of the checks and stuff makes it work as far as that goes, but again, the undo becomes completely broken and as far as I can tell, that's controlled by something I don't think scripting can touch?

It seems like it would be considerably easier in the long run to just set a margin on the edit box in the program based on the same basic calculations that figure out how many characters can fit when you're wrapping to screen on the output?

(Not that I know anything about C++, but a little cursory Googling implies this should be possible, although it also implies that I would have to evidently drop $800 for the right to have the libraries to actually compile MUSHclient, and... not today.)
USA Global Moderator #18
Neva said:

So, that part said! I finally got the chance to try this and... it doesn't work. After poking at it, I was able to determine that basically, the input window just doesn't see \n as a line break. Have you actually been running this, Fiendish? Is it displaying okay for you?

Well damn. Yes I tried it and it works for me...in Wine. If it won't work the same way in both Wine and Windows, then I don't know what to suggest yet. I had thought that \r\r\n was displaying garbage characters for me on the input bar in Wine, but I'll try that again.
USA #19
I'm guessing that in Wine, it's just emulating the Windows edit control, so it behaves a little differently.

I'm glad at least you're on Linux, I didn't think of that at first and I was having some definite hair-tearing-out time wondering why the heck it would break for me if I couldn't imagine how you possibly wrote it without ever running the thing!

At least as far as my purposes go, aside from a weird bit still where the second line for some reason cuts off early, I think the script is basically workable, but I'm not sure about the wrap-versus-undo tradeoff. Will have to see.
Australia Forum Administrator #20
This overall issue I addressed when writing my Area Editor something like 10 years ago.

What I did then was (for builders keying in room descriptions) let you type into a free-format edit box. Then there was a button that let you do the wrapping at the last moment. Like this:



The box was designed so it would wrap at column 80 anyway (with soft wraps, that is as you typed it would re-wrap). But then if you hit the "Wrap to Edge" button it would convert them to hard wraps (that is, put the newlines in).

Now I don't know if this helps a little or not at all, but is this the sort of thing you have in mind? You are of course free to download the Area Editor and just use it as a "text wrapper".

The other thing you might do is use the Lua utils.editbox function. You can set up various things there (like fixed-pitch font, exact box size etc.). By carefully setting that up you could make a box that wraps "softly" at 80 columns (or 79 or whatever) and then when you hit OK it does the hard wrap for you, and sends it.

Presumably this careful wrapping is not needed all the time, but doing things like descriptions, etc.?
USA #21
Pose length is also a potential issue, so pretty much all the time, yeah. I already have a text editor I can and do paste into pretty regularly, but it seems like a very bad solution to the problem.

On the other hand, since it turns out impoverished students *can* get access to Visual Studio for free... I think I have it working. Once I'm sure of that, I'll contribute it back!
Australia Forum Administrator #22
Well that would be nice. :)

However MUSHclient uses MFC which isn't part of the free Visual Studio, funny about that.

The problem from the window point of view is that the MUSHclient "world" frame is split into two parts (one above the other) using a Splitter class. The splitting is a horizontal line, so whatever the size of one window, the other one is the same (unless there was some third split or something).

I think a plugin that showed an edit box (utils.editbox) which you could call up when required (eg. F5 or something) would probably be the easiest way to do it. Just make sure the box is the right size, and add the hard returns when finished, if required.
USA #23
Out of curiosity, how do other people on this MUD handle the issue?
USA #24
I added a new thread in Dev, but just to do a last couple replies:

No, MFC isn't in Express. MS is now giving the *full* Visual Studio 2010 away to college students, though, evidently: https://www.dreamspark.com/ And despite my total lack of knowing C++, evidently the online help files and a bit of trial-and-error were good enough.

To get a little into specifics, the window itself is the same size it always was, but CEdit controls can have internal margin space that forces it to wrap somewhere before the end of the window, so that's all my little hack does. All of which I pretty much got to entirely on the basis of, "I'm pretty sure there must be some way to do this!" So I'm proud of myself. ;)

As far as other people on the game go, some folks just wing it, some people do the pasting thing, some people run with the client only taking up part of the window--I think I'm the only one who even knows what a Miniwindow is, in all likelihood--and a number of people use SimpleMU, which, while it doesn't wrap, has always had an informational box taking up part of the lower part of the window. So it's kinda all over the place. I figure at least some people will appreciate it, and I am happy as a clam, so.