Author Topic: That's Imm-Parsable!  (Read 861 times)

Castleberg

  • Newbie
  • *
  • Posts: 37
That's Imm-Parsable!
« on: December 07, 2021, 03:54:21 PM »
Pfeil, first, thank you again for what you do. Both in response to myself, as well as virtually every other response on this forum, I've learned so much from you. It doesn't go unnoticed.

This continues off my prior thread "That's a bold statement, Sir!", But started a new thread as I feel it is sufficiently distinguished to warrent it.

What I would like to do is to have WordPad documents that contain rich text, and then runn a command that will automatically set a variable to equal to the contents of that file, parsing it to make it appropriate along the way. This would allow me to effectively edit variables within voice attack, by simply editing a WordPad file, a handy little trick indeed.

Obviously I can set a txt variable to be equal to a file, but this has never rendered anything remotely usible, but a garbled mess. I have had hope, given our recent discussions, I might employ the inline functions to work some magic on the data, but have yet to find a solution.

While the above would be a great additional all by itself, what would be even better, us if u could have a single declaration WordPad document that looked something like this:

Var1 = "this is var 1"
Var2 = "this is var 2"

Where in I employed a regex or other parsing command to find the desired variable, and set a new variable to be equal to the string between quotes.

In this way, with a single WordPad document, I could edit my profiles.

A simple example, perhaps more readily appreciable to this forum at large, would be a keybinding file. I.e.

ThrustUp = "1"
ThrustDown = "2"
ThrustRight = "3"
ThrustLeft = "4"

Now, if u want to change my voice attack keybindings, I can do so without opening up my keybinds voice attack command, but just change the WordPad document (arguably easier), save, and reinitialize the variables.

In Sum:
1) how do I set a TXT variable to be equal to the richText contents of a WordPad document, such that it is pasteable Luke the literal text example in our adjacent thread.

And

2) one step further, is it possible to search out the desired variable only, I.e, searching for "var1 = "" and what follows until the next " will be assigned to var1 in voice attack.

Possible or not, I'm sure I'll learn a lot from the discussion, thanks in advance!


Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4782
  • RTFM
Re: That's Imm-Parsable!
« Reply #1 on: December 07, 2021, 08:40:17 PM »
What's in the file as much of a "garbled mess" as what you've been using before is. It is literally the same markup used when copying Rich Text Format text, except that VoiceAttack is removing the brackets while getting the contents of the file when you use the "Value from file/URI" option.


If you want to spend the time writing a proper parser for RTF files, the official specifications from Microsoft can be found here (in an almost 70 megabyte PDF).

If you're not concerned about portability, you could instead just assume that "\lang9 " will always precede the contents of the file, store anything up to and including that then remove it from the string, remove any regular newline sequences, remove the closing brace (assuming you're using a non-native method for getting the contents of the file, which you'd want to do to preserve any braces), and split the remaining contents on the "\line" and "\par" sequences.
Using a For loop, you can then find the first " = " sequence in each element of the resulting array, get the text before it as the variable name, and get the text after it as the contents of the variable. Using double quotes is just needless complication, so leave those out entirely.


Some C# documentation you'll want to have a look at, aside from the basics of the language:
File.ReadAllText()
String.IndexOf()
String.Substring()
String.Remove()
String.Split()

Castleberg

  • Newbie
  • *
  • Posts: 37
Re: That's Imm-Parsable!
« Reply #2 on: December 08, 2021, 02:30:42 PM »
I'll see what I can do. Thanks for the point in the right direction.

I am encouraged that, by your post, it seems what I would like to acheive is definitely possible, now I just have to figure it out. :)

Castleberg

  • Newbie
  • *
  • Posts: 37
Re: That's Imm-Parsable!
« Reply #3 on: December 09, 2021, 02:41:14 PM »
Trying to work my way through what would take the ordinary person literally 30 seconds to write.....

Starting at step 1: removing the prefix of the file (up until \lang9) :

I don't seen to be able to use wild cards, so have resorted to using .IndexOf and .Remove to remove the beginning, in what I consider to be a less than elegant solution :

Code: [Select]
using System;
using System.Text;
using System.Windows.Forms;

public class VAInline
{
public void main()
{
string richText = VA.GetText("richText");
int startIndex = richText.IndexOf("\\lang9 ")+7;
richText = richText.Remove(0,startIndex);
if (!String.IsNullOrEmpty(richText))
{
Clipboard.SetText(richText, TextDataFormat.Rtf);
}
else
{
VA.WriteToLog("No text to paste", "red");
}
}
}

On to step 2? Or have I already botched something? :)

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4782
  • RTFM
Re: That's Imm-Parsable!
« Reply #4 on: December 09, 2021, 11:09:29 PM »
That pretty much is how it's done. You could write your own method to obfuscate it, but internally that'd still need to use IndexOf() (or the equivalent of what IndexOf() does internally by stepping through the string, if you want to reinvent the wheel)

If you want to use concepts like wildcards, that is possible with regular expressions, but that has its own drawbacks (performance and readability, mainly)



The next step could be copying the substring containing the header (I.E. everything up to and including "\lang9 ") to a variable, so you can add it back in later, before outputting to the clipboard.


Within the inline function, however, the actual first step would probably be getting the contents of the file directly, so that braces are preserved

Castleberg

  • Newbie
  • *
  • Posts: 37
Re: That's Imm-Parsable!
« Reply #5 on: December 16, 2021, 11:50:40 AM »
As I'm working through this, I'm more and more seeing the value and power of using inline functions over native VA.

For example: I notice that the very first time I created a function to import the file, and then store it in a VA variable....it just worked. I was shocked, as I didn't even have the code to do all the replacements yet. Upon reviewing the results, I realize it is because by using the inline function, I skipped the "Set Text Value" field, as well as some other triggers that cause VA to strip the data. But, as soon as I store it in a variable, and then have VA reassign that variable and export it, I'm back to where I started.


That is to say, it seems like a lot of my problems are dealing with the VA parser....

With that preamble out of the way, I have a few questions / curiosities:

1) Are there downsides to using inline functions, in particular regarding variable management? (i.e speed / memory / etc.)
2) what does the "Retain instance" of the Inline function dialogue do? - I assume it allows the function to continue running in the background...but
3) How is that persistent instance managed or terminated? (I assume just by its own internal code/logic)

My current plan was to read rich text from wordPad, store it in a VA variable, and then when needed, set that variable to the clipboard using another inline function.

I am wondering if this would be more efficent to allocate these to C# variables within an persistant inline function.

However, I'm not sure I would be able to access the variables across inline instances, and just importing the variables back into VA, via VA.SetText(VoiceAttack Variable, c# variable) seems the safest way to go.

TLDR:

1) What are the drawbacks of using inline function vs VA.
2) If I set a Inline function instance to be retained, will any Inline function be able to access variable created across instances?
3) Any advice on using an inline function to allocate the VA variables Per above, vs. keeping it within inline function?

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4782
  • RTFM
Re: That's Imm-Parsable!
« Reply #6 on: December 16, 2021, 01:08:58 PM »
If you escape your values correctly, the token parser will not alter them aside from removing one escape character, as mentioned.

In addition, the token parser does not run when assigning a value to, or reading a value from a VoiceAttack variable, using an inline function, or when assigning one variable the value of another variable, using the "Another Variable" field of the relevant value-setting action.

When you retrieve the value of a variable using a token, the token parser obviously does run.


In other words, if you store a value using the SetText() method, and retrieve it using the GetText() method, the parser will not run, so you can pass values between different (instances of) inline functions without the token parser altering them.


Inline functions will keep running in the background until their main() method returns, or, provided they're running synchronously (I.E. the "Wait for the inline function to finish before continuing" option is enabled), when the command is stopped.

The "Retain Instance" option does not affect when an inline function stops actively executing, however when enabled it retains the instance of the class so that data associated with it remains in memory, even after the main() method has returned.

I assumed this might apply to the "SessionState" dictionary, but as that is currently not available to inline functions at all, I'm not sure how retaining the instance would allow access to that data. I've inquired with Gary about that.




Non-precompiled Inline functions are compiled on-the-fly the first time a command containing it is executed, but that should have no noticeable performance impact in most cases (if your inline function is so large that it would, compiling it to a file or using a plugin would likely be more appropriate).

Memory usage is proportional to what resources your inline function creates, just as it would be with native actions. Unless you enable the "Retain Instance" option, the memory used would be freed after the inline function, and/or the command containing it, have finished executing.

Inline function can be faster than native actions in theory, as they don't have the safeguards in place that those do, though practically speaking that should be negligible, especially when using the "Resource balance offset" option. However, this also means the responsibility is with you.

The variable-related methods used by inline functions (and plugins) should be pretty much identical to those used internally by native actions.


Generally, regarding "efficiency" and optimization, consider that the user is normally the slowest component, and that, presumably, you're not running VoiceAttack on an 8-bit microcontroller.
If you find something is actually noticeably slow, then you can try to optimize.