2

I am new .. or more precisely.. never used RX so I was wondering whether I can use it for this situation: I want to add a sort of Resharper Live Templates functionality to my app that allows users to enter short sequences of characters followed by a [Tab] and my app would replace the previously typed characters with the elsewhere specified, full text.

Now I have a list of character arrays, each of them representing one possible sequence. I want some sort of stopwords/-keys that break the chain (e.g. space). I have an event that is raised on each KeyPress in my application, now (how) can I use RX to observe this event and check against that aforementioned list whether one of the sequences has been fulfilled and finally [Tab] has been pressed?

Jörg Battermann
  • 4,044
  • 5
  • 42
  • 79

1 Answers1

4

I don't know if it's too late, but I have an answer for you.

The Rx extension method you need to use is BufferWithCount.

I'll assume you know how to turn key press events into an IObservable<char>.

So given you have a list of character sequences that you want to detect and then perform an action I suggest using a Dictionary<string, Action> to hold this data, like so:

var matches = new Dictionary<string, Action>()
{
    { "ba", () => Console.WriteLine("ba") },
    { "aba", () => Console.WriteLine("aba") },
    { "baa", () => Console.WriteLine("baa") },
    { "abc\t", () => Console.WriteLine("abc\\t") },
};

So here's the Rx (and IEnumerable) queries required:

int max =
    matches
    .Select(m => m.Key.Length)
    .Max();

IObservable<string> chords =
    Enumerable
    .Range(2, max - 1)
    .Select(n => keys
        .BufferWithCount(n, 1)
        .Select(cs => new string(cs.ToArray())))
    .Merge();

IObservable<Action> actions =
    chords
    .Where(s => matches.ContainsKey(s))
    .Select(s => matches[s]);

So finally you just have an IObservable<Action> that you can subscribe to and you just invoke the Action.

If you want to test out that this works use the following code:

IConnectableObservable<char> keys = "ababc\tdabaababc\tebad"
    .ToObservable()
    .Publish();
//`.Publish()` makes a cold observable become hot,
// but you must call `Connect()` to start producing values.

//insert above `matches` definition here.
//insert above queries here.

actions.Subscribe(a => a());

keys.Connect();

The result should be:

ba
aba
abc\t
ba
aba
baa
ba
aba
abc\t
ba

Enjoy!

Enigmativity
  • 113,464
  • 11
  • 89
  • 172