Sub a portion of a line with something else

Posted by Charneus on Sun 18 May 2014 11:20 PM — 14 posts, 47,298 views.

#0
I'm a fairly new user to MUSH, and while I love the flexibility of the program compared to what I used to use, there's one thing I'm totally missing, and that's the ease of subbing/psubbing like a former client could do. Here's what I'm looking for as far as this functionality.

I currently have a trigger that take "(K)(M)(I)(G)(H)" and shortens it to "(KMGH)" with the () colorized based on whether "I" is there or not. The problem is, I want it to display the rest of the line as well, colorized as normal. So, for instance, if I have

    (K)(M)(G)(H) a Bag of Aardwolf (241)


and "Bag of" is yellow, "Aardwolf" is red, "(241)" is white and green, I want the script to return:

    (KMGH) a Bag of Aardwolf (241)


with "Bag of" yellow, "Aardwolf" red, and "(241)" white and green.

So, my question is, what's the easiest way to go about this?
Australia Forum Administrator #1
Is the part "(K)(M)(G)(H)" all in one colour or different colours?

To get you started, the basic idea is to omit the matching line from output, and then re-echo it with ColourTell and ColourNote, along these lines:


<triggers>
  <trigger
   enabled="y"
   match="&lt;*&gt;*"
   omit_from_output="y"
   send_to="14"
   sequence="100"
  >
  <send>

ColourTell ("white", "blue", "Prompt: ")
for i, v in ipairs (TriggerStyleRuns) do
  ColourTell (RGBColourToName (v.textcolour), 
              RGBColourToName (v.backcolour), 
              v.text)  
end -- for each style run
Note ("")  -- wrap up line

</send>
  </trigger>
</triggers>


Template:pasting
For advice on how to copy the above, and paste it into MUSHclient, please see Pasting XML.


The client breaks the incoming line into style runs (one for each colour) which you can access from the TriggerStyleRuns table (if you use scripting in the trigger like this, with send to being "script (after omit)").

This example echoes back a prompt line, in the same colours it arrived in, however adding "Prompt: " in front of it.

Depending on whether the letters you are interested in "(K)(M)(I)(G)(H)" are in one or many style runs, the text substitution, and dealing with the colours at this point, will be slightly different.

There is a plugin that lets you quickly find the style run number corresponding to a particular part of the line, so that should simplify that part. See:

http://www.gammon.com.au/forum/?id=7818
#2
It's all in different colors. If you're familiar with Aardwolf, it's the shortflags version of (Keep)(Magic)(Invis)(Glow)(Hum).

This is what I have as far as condensing it to the (KMGH) portion:


local flagsub = {}
if string.match("%1","I") then
table.insert(flagsub,"white")
else
table.insert(flagsub,"gray")
end
table.insert(flagsub,"")
table.insert(flagsub,"(") -- Checks invis flag for (

if string.match("%1","K") then
table.insert(flagsub,"red")
table.insert(flagsub,"")
table.insert(flagsub,"K")
end -- Checks Keep flag

if string.match("%1","M") then
table.insert(flagsub,"blue")
table.insert(flagsub,"")
table.insert(flagsub,"M")
end -- Checks Magic flag

if string.match("%1","G") then
table.insert(flagsub,"white")
table.insert(flagsub,"")
table.insert(flagsub,"G")
end -- Checks Glow flag

if string.match("%1","H") then
table.insert(flagsub,"cyan")
table.insert(flagsub,"")
table.insert(flagsub,"H")
end -- Checks Hum flag

if string.match("%1","I") then
table.insert(flagsub,"white")
else
table.insert(flagsub,"gray")
end
table.insert(flagsub,"")
table.insert(flagsub,")") -- Checks Invis flag for )

ColourNote(table.unpack(flagsub))


Your example seems to be what I'm looking for, for the most part, but how would I work it if the line were:

[ Primary Weapon      ]: (K)(M)(G)(H) Dagger of Aardwolf (241)


I'd still want to keep the colors, and the prefix, but shorten the (K)(M)(G)(H) to (KMGH).

Thanks for your response, by the way!
Australia Forum Administrator #3

if string.match("%1","I") then


This is unnecessarily complex. How about:


if "%1" == "I" then


As for your other question, it helps to know what we are dealing with. Try some sort of variation on this:


<triggers>
  <trigger
   enabled="y"
   match="&lt;*&gt;*"
   send_to="14"
   sequence="100"
  >
  <send>

require "tprint"
tprint (TriggerStyleRuns)

</send>
  </trigger>
</triggers>


Adjust the trigger to match your line, and see what the tprint of the style runs gives. In my case it was:


1:
  "textcolour"=12632256
  "backcolour"=0
  "length"=1
  "style"=0
  "text"="<"
2:
  "textcolour"=65535
  "backcolour"=0
  "length"=5
  "style"=1
  "text"="24hp "
3:
  "textcolour"=16776960
  "backcolour"=0
  "length"=5
  "style"=1
  "text"="145m "
4:
  "textcolour"=65280
  "backcolour"=0
  "length"=5
  "style"=1
  "text"="110mv"
5:
  "textcolour"=12632256
  "backcolour"=0
  "length"=11
  "style"=0
  "text"="> <#21050> "


You can build up a mental picture here of what to expect. In this case the prompt was:


<24hp 145m 110mv> <#21050> 


You can see that the "<" symbol was one style run, the "24hp" was another, and so on.

Since this stuff is being generated by a program, once you have worked out its system, it is unlikely to change much.

If you are having problems, do what I suggest on an example line, and paste what you get here.
#4
Oh, there's a reason it's string.match and not just if "%1" == "I". See the trigger below - it's doing a range rather than just individually:
<triggers>
  <trigger
   keep_evaluating="y"
   match="^(?:\(\s?\d+\)\s|[.*]:\s|\s{4,})(?:([KIGHM()]+))\s"
   omit_from_output="y"
   regexp="y"
   repeat="y"
   send_to="12"
   sequence="100"
  >
  <send>Code from earlier</send>
  </trigger>
</triggers>


Testing using your code, I get the following when there's nothing preceding the (K)(M)(G)(H) (aside from spaces):
1:
  "backcolour"=0
  "text"="     "
  "length"=5
  "style"=0
  "textcolour"=12632256
2:
  "backcolour"=0
  "text"="(M)"
  "length"=3
  "style"=1
  "textcolour"=16711680
3:
  "backcolour"=0
  "text"="(G)"
  "length"=3
  "style"=1
  "textcolour"=16777215
4:
  "backcolour"=0
  "text"="(H) "
  "length"=4
  "style"=1
  "textcolour"=16776960
5:
  "backcolour"=0
  "text"="a "
  "length"=2
  "style"=0
  "textcolour"=12632256
6:
  "backcolour"=0
  "text"="Bag of "
  "length"=7
  "style"=1
  "textcolour"=65535
7:
  "backcolour"=0
  "text"="Aardwolf"
  "length"=8
  "style"=1
  "textcolour"=255
8:
  "backcolour"=0
  "text"=" "
  "length"=1
  "style"=0
  "textcolour"=12632256
9:
  "backcolour"=0
  "text"="("
  "length"=1
  "style"=1
  "textcolour"=16777215
10:
  "backcolour"=0
  "text"="241"
  "length"=3
  "style"=1
  "textcolour"=65280
11:
  "backcolour"=0
  "text"=")"
  "length"=1
  "style"=1
  "textcolour"=16777215


When I do it via the equipment command, thus making it have wear slots before the string, I get:

1:
  "backcolour"=0
  "text"="[ "
  "length"=2
  "style"=0
  "textcolour"=32768
2:
  "backcolour"=0
  "text"="Primary Weapon      "
  "length"=20
  "style"=1
  "textcolour"=255
3:
  "backcolour"=0
  "text"="]"
  "length"=1
  "style"=0
  "textcolour"=32768
4:
  "backcolour"=0
  "text"=":"
  "length"=1
  "style"=1
  "textcolour"=16777215
5:
  "backcolour"=0
  "text"=" "
  "length"=1
  "style"=0
  "textcolour"=12632256
6:
  "backcolour"=0
  "text"="(K)"
  "length"=3
  "style"=1
  "textcolour"=255
7:
  "backcolour"=0
  "text"="(M)"
  "length"=3
  "style"=1
  "textcolour"=16711680
8:
  "backcolour"=0
  "text"="(G)"
  "length"=3
  "style"=1
  "textcolour"=16777215
9:
  "backcolour"=0
  "text"="(H) "
  "length"=4
  "style"=1
  "textcolour"=16776960
10:
  "backcolour"=0
  "text"="Dagger of "
  "length"=10
  "style"=1
  "textcolour"=65535
11:
  "backcolour"=0
  "text"="Aardwolf"
  "length"=8
  "style"=1
  "textcolour"=255
12:
  "backcolour"=0
  "text"=" "
  "length"=1
  "style"=0
  "textcolour"=12632256
13:
  "backcolour"=0
  "text"="("
  "length"=1
  "style"=1
  "textcolour"=16777215
14:
  "backcolour"=0
  "text"="241"
  "length"=3
  "style"=1
  "textcolour"=65280
15:
  "backcolour"=0
  "text"=")"
  "length"=1
  "style"=1
  "textcolour"=16777215


Nifty function there, by the way. It's things like this, and responses such as yours, that's making me a convert to MUSH. Learning to convert my scripts over has been super fun so far.
Amended on Mon 19 May 2014 09:31 AM by Charneus
Australia Forum Administrator #5
Thanks. :)

It looks like you are in luck, because each of the special cases (like "(K)") is in its own style run. That will make it super-easy to fix.

For example:


6:
  "backcolour"=0
  "text"="(K)"
  "length"=3
  "style"=1
  "textcolour"=255



So, you want to get rid of the brackets, and change the colour. Well this is just table data and you can change it. Given it has the index 6 (and you can just "walk" the table to find the index, eg. compare to "%(.%)" in a (Lua) regular expression), you can change it.


For example:


TriggerStyleRuns [6].text = "K"
TriggerStyleRuns [6].length = 1   -- not strictly necessary in this case
TriggerStyleRuns [6].textcolour = ColourNameToRGB ("yellow")



Now, your result will be a bit more complex (the 6 will be a variable) but you get the idea. Then just echo back the style runs as I showed earlier.

This is an example of that sort of style-fiddling:


<triggers>
  <trigger
   enabled="y"
   match="&lt;*&gt;*"
   omit_from_output="y"
   send_to="14"
   sequence="100"
  >
  <send>

-- fiddle with style runs

for i = 1, #TriggerStyleRuns do
 
  TriggerStyleRuns [i].text = string.upper (TriggerStyleRuns [i].text)
  TriggerStyleRuns [i].textcolour = ColourNameToRGB ("green")

end -- for

-- add a new item in position 4

table.insert (TriggerStyleRuns, 
              4,  -- position
              { text = "hello", length = 5, backcolour = 0, textcolour = ColourNameToRGB ("yellow") } )

-- now display them

for i, v in ipairs (TriggerStyleRuns) do
  ColourTell (RGBColourToName (v.textcolour), 
              RGBColourToName (v.backcolour), 
              v.text)  
end -- for each style run
Note ("")  -- wrap up line

</send>
  </trigger>
</triggers>


This example changes each style run to upper case, and its colour to green. Then it inserts a new item in position 4 (the old position 4 now becomes position 5).

Then the whole lot gets echoed back.

This inserting of a new style could be how you would put the brackets back, after removing them from each individual item.
Amended on Mon 19 May 2014 08:07 PM by Nick Gammon
USA Global Moderator #6
I know Nick will disagree up, down, and sideways, but for sub/psub functionality you really want to be using Simulate and not ColourTell/ColourNote. Primary functionality of substitution is allowing the line to also match for other substitutions. Note functions break if you match on the same line for multiple patterns. Just remember to simulate CRLF too.
Amended on Tue 20 May 2014 02:06 AM by Fiendish
#7
Oddest thing... I start working on something I hope would at least get me started in the right direction, and all of a sudden, TriggerStyleRuns isn't working. This is the error I get:

( 4) (K)(M)(G)(H) a Bag of Aardwolf (241)
Run-time error
World: Aardwolf
Immediate execution
E:\MUSHclient\lua\tprint.lua:34: bad argument #1 to 'pairs' (table expected, got nil)
stack traceback:
        [C]: in function 'pairs'
        E:\MUSHclient\lua\tprint.lua:34: in function 'tprint'
        [string "Trigger: "]:2: in main chunk


I'm... very confused about this, and maybe this should go in a different thread, but as it's all related, I figured there's no harm in putting it here, I hope.
USA Global Moderator #8
Charneus said:
all of a sudden, TriggerStyleRuns isn't working.


TriggerStyleRuns only exists if you send to script after omit, not just send to script.
#9
Fiendish said:

Charneus said:
all of a sudden, TriggerStyleRuns isn't working.


TriggerStyleRuns only exists if you send to script after omit, not just send to script.


That would be the issue, thanks.

Now I've written what I think should work, but upon testing, it doesn't, not by a long shot.

Here's the code in all its glory, including my debugging method:

<triggers>
  <trigger
   enabled="y"
   keep_evaluating="y"
   match="^(?:\(\s?\d+\)\s|\[.*\]:\s|\s{4,})(?:([KIGHM()]+))\s"
   omit_from_output="y"
   regexp="y"
   repeat="y"
   send_to="14"
   sequence="100"
  >
  <send>require 'tprint'
tprint(TriggerStyleRuns)

for i = 1, #TriggerStyleRuns do

TSRt = TriggerStyleRuns[i].text
TriggerStyleRuns[i].text = string.gsub(TSRt,"%((%w)%)","%1")
end
 

for i,v in pairs(TriggerStyleRuns) do
  ColourTell (RGBColourToName (v.textcolour),
  RGBColourToName (v.backcolour),
  v.text)
end
Note ("")</send>
  </trigger>
</triggers>


Instead of:

( 4) KMGH a Bag of Aardwolf (241)


which is what I expect it to return, it returns (with the tprint debug to see before the changes are made):


1:
  "backcolour"=0
  "text"="( 4) "
  "length"=5
  "style"=1
  "textcolour"=16777215
2:
  "backcolour"=0
  "text"="(K)"
  "length"=3
  "style"=1
  "textcolour"=255
3:
  "backcolour"=0
  "text"="(M)"
  "length"=3
  "style"=1
  "textcolour"=16711680
4:
  "backcolour"=0
  "text"="(G)"
  "length"=3
  "style"=1
  "textcolour"=16777215
5:
  "backcolour"=0
  "text"="(H) "
  "length"=4
  "style"=1
  "textcolour"=16776960
6:
  "backcolour"=0
  "text"="a "
  "length"=2
  "style"=0
  "textcolour"=12632256
7:
  "backcolour"=0
  "text"="Bag of "
  "length"=7
  "style"=1
  "textcolour"=65535
8:
  "backcolour"=0
  "text"="Aardwolf"
  "length"=8
  "style"=1
  "textcolour"=255
9:
  "backcolour"=0
  "text"=" "
  "length"=1
  "style"=0
  "textcolour"=12632256
10:
  "backcolour"=0
  "text"="("
  "length"=1
  "style"=1
  "textcolour"=16777215
11:
  "backcolour"=0
  "text"="241"
  "length"=3
  "style"=1
  "textcolour"=65280
12:
  "backcolour"=0
  "text"=")"
  "length"=1
  "style"=1
  "textcolour"=16777215
( 4) (K)(M)(G)(H)(K)(M)(G)(H)(K)(M)(G)(H)(K)(M)(G)(H) a Bag of Aardwolf (241)


Each group of (K)(M)(G)(H) is one single color. Group 1 is the red from what K should be. Group 2 is blue (M's color), group 3 is white (G's color), and group 4 is cyan (H's color).

Where did I go wrong in this script?
Amended on Wed 21 May 2014 02:45 AM by Nick Gammon
Australia Forum Administrator #10

TriggerStyleRuns[i].text = string.gsub(TSRt,"%((%w)%)","%1")


Inside a trigger or alias "send-to" field, %1 has a specific meaning, namely "replace with wildcard #1".

This happens before Lua gets to it, and judging by your results, wildcard #1 is "(K)(M)(G)(H)".

So, to make it work as documented for string.gsub you need to replace the % with %% in the string.gsub, eg.


TriggerStyleRuns[i].text = string.gsub(TSRt,"%%((%%w)%%)","%%1")
Amended on Wed 21 May 2014 02:51 AM by Nick Gammon
Australia Forum Administrator #11
If you had called a script function (eg. in the script file) then that wouldn't be necessary as the %1 would not be expanded in that way.
#12
SWEET! I've got my flagsubs back, and learned some new info. Thanks! Now to complete the rest of this script!
Australia Forum Administrator #13
You may find it easier to use a script function. Instead of putting everything inside the trigger, just call a function (put its name in the "script" box).

This lets you have the style runs as a function argument (fourth argument) and you also don't have to double the % symbols wherever you need to do a find and replace.

The function goes into a separate file.

See this video if this isn't clear:

http://www.gammon.com.au/forum/?id=10212

(I just watched that, perhaps it doesn't actually mention using the script file, but there are some other helpful tips).