Fourth 'style' parameter for non-Lua languages

Posted by Worstje on Thu 10 May 2007 06:19 PM — 9 posts, 25,759 views.

Netherlands #0
I think the topic says it all.

If the reason only Lua supports this is because of the fact that Lua somehow doesn't mind a superfluous parameter when calling a function, how about checking with the scripting interface for the amount of parameters the function associated with said trigger has? I believe that should be possible, and that check would only have to be done while loading.

While I love Lua, it's not a language I'm as productive in, so being able to use it in Python would be quite awesome.
Australia Forum Administrator #1
I don't know if you can do that check.

I know it warns you if you have the wrong number, but this is the code that does that:


    if (hr == 0x800a01c2)   // wrong number of arguments
      ::AfxMessageBox (CFormat ("Wrong number of arguments for script subroutine \"%s\" when %s"
                                "\n\nWe expected your subroutine to have %i argument%s",
                               (LPCTSTR) szProcedure,
                               (LPCTSTR) szReason,
                               PLURAL (params.cArgs)));
    else
      ::AfxMessageBox (CFormat ("Unable to invoke script subroutine \"%s\" when %s",
                               (LPCTSTR) szProcedure,
                               (LPCTSTR) szReason));


As you can see, all I get from the script engine is an error code indicating the wrong number of arguments, not the number I actually got.

Also, I think some languages (like Perl) don't even indicate how many arguments they expect, for example:


sub OnTeleport
{

my ($thename, $theoutput, $wildcards) = @_;

... 


You can see that the definition for OnTeleport does not even specify an argument list, so I don't see how the script engine can know how many you expect to get.

The only way I can think of accomodating this idea is to have another selector for GetTriggerInfo, where you can retrieve the style runs there. However the drawback is that for this to work, style runs would always have to be saved, which takes time and memory, although many people would not use them.
Netherlands #2
How about retrying calling the function with -4- arguments if calling it with -3- arguments fails due to an incorrect amount of parameters? If that also fails, you can throw the error as usual.

Of course, this leaves the issue with what you should try first for those languages that accept any kind of parameter (like perl). Maybe this is one of those things a global setting would be useful for?

O Always try to send style information to triggerscripts before degrading. (use for languages with open paramaters, e.g. Perl)
O Assume triggerscripts are simple, only sending more if the trigger requires more information.
O Never send style information (in case someone wants old behaviour for any reason).

Of course, this is kind of an ugly way to facilitate this; however, this is the only thing I can think of with the limited code shown. Sadly, I had almost no knowledge of C++ and none of the scripting host what-so-ever.
Australia Forum Administrator #3
What is wrong with just using GetLineInfo and GetStyleInfo, which is already available, and getting the style runs that way?
Netherlands #4
Because I think it makes code look horrible?

Seriously, though. GetLineInfo seems an awkward way to access it. Do local MUSHclient wordwrap settings affect it? If I use a trigger pattern that only matches a very small part of a sentence, how can I reliably find the information for the part of the line I am interested in? (Okay, I haven't needed this just yet but it just comes to mind..) And multi-line triggers could also get tricky, I think.

But I suppose I can deal with GetLineInfo if it gives the exact same output as the style parameter would. I just don't like it very much. :)
Australia Forum Administrator #5
Quote:

Because I think it makes code look horrible?


Well this is crying out to be turned into a function. It is admittedly a bit fiddly, but make a helper function, get it right, and you can forget about it.

Quote:

GetLineInfo seems an awkward way to access it. Do local MUSHclient wordwrap settings affect it?


Well, we need to look at the correct way of extracting line information for multiple lines. I have covered this ground before, but will do it again with the help of a graphic.

The thing about the way MUSHclient displays lines is that there are two main concepts here:

  • A "line" is a physical line which appears on a single line of the output window. It may be part or all of a "paragraph".
  • A "paragraph" is a logical line, ending in a newline (\n). It may span multiple physical lines if the line is long enough to wrap around.


Triggers fire at the end of a paragraph - that is, when a newline is received. Thus, a trigger may span multiple lines. The fourth argument to a trigger in Lua is a table of style runs for the entire paragraph. This effectively is done by the code I will present below, which works backwards through the physical lines in the output window, building up the paragraph. Thus, using GetLineInfo and GetStyleInfo retrieves the same information.

The next post has an example of some paragraphs, some of which span multiple lines.
Amended on Sat 12 May 2007 11:35 PM by Nick Gammon
Australia Forum Administrator #6

Note:

  • Paragraphs, boxed in green (some are also single lines). Subsequent lines in a paragraph are indented (this is a configuration option).
  • An example line, boxed in cyan. In this case it is part of a larger paragraph.
  • Line breaks (newlines) indicated by the magenta box.
Amended on Sat 12 May 2007 11:34 PM by Nick Gammon
Australia Forum Administrator #7
Now to successfully turn that into the equivalent of the Lua style runs argument we need to do this:

  • Find the last line in the output buffer using GetLinesInBufferCount.
  • Skip any note lines that other triggers or plugins might have added since the trigger fired (in this example "Note line A" and "Note line B".
  • Walk backwards until we get the newline from the *previous* paragraph (in this case the "Public Notices" line).
  • Add one, which now gives us the first line of the paragraph.
  • For each line, GetLineInfo tells us how many styles are in that line.
  • For each line found in the steps above we can now use GetStyleInfo for each style in the line to find the text, colour, column, and so on for that style run.


This example code does that:


line = GetLinesInBufferCount ()  -- last line in buffer

-- skip notes or player input
while GetLineInfo (line, 4) or GetLineInfo (line, 5) do
  line = line - 1
end -- notes or player input

-- this is now the end of the paragraph
last_line_in_paragraph = line

-- find start of paragraph
repeat
  line = line - 1
until GetLineInfo (line, 3)  -- until newline

-- paragraph starts at end of previous paragraph, + 1
first_line_in_paragraph = line + 1

for line = first_line_in_paragraph, last_line_in_paragraph do
  styles = GetLineInfo (line, 11)  -- number of style runs
 
  for style = 1, styles do
     Note ("line: ", line, ", style: ", style, ", text: ",
           GetStyleInfo (line, style, 1))
  end -- of each style

end -- each line


The code is in Lua, but you can adapt the idea to any other language.

Running that on the example lines above gives this result:


line: 427, style: 1, text: Here the citizens of the city come to read and trade information about the
line: 428, style: 1, text: events of their time. A large board hangs on the far wall, serving to carry
line: 429, style: 1, text: the word of the common people one to another, and people mill slowly by,
line: 430, style: 1, text: reading and perusing notes in the silent atmosphere.

Australia Forum Administrator #8
Quote:

If I use a trigger pattern that only matches a very small part of a sentence, how can I reliably find the information for the part of the line I am interested in?


The same problem applies to using the Lua argument as well. See this post:

http://mushclient.com/forum/?id=7818

Once you have the style runs, you can work your way through them to find a column (or word) as described there.

Quote:

And multi-line triggers could also get tricky, I think.


You have the same problem with the Lua interface. The fourth argument is only the style run for the matching line. It doesn't retain the style runs for all lines in a multi-line trigger (which might be 100).

The function GetRecentLines can be used to assemble the text of recent multi-line triggers. For style information you simply have to use GetLineInfo, even if you code in Lua. Bear in mind for multi-line triggers, that some of the lines may have been omitted by other triggers, and there will probably be note lines and player input in the middle of them.

http://www.gammon.com.au/scripts/doc.php?function=GetRecentLines