One of the harder parts of writing a text service is learning how to 'think' text services. Here are a couple of rules that I've developed (the hard way) after writing a text service:
The first rule of writing a text service is: Keep the edit sessions fast, and keep the edit sessions small. When your text service is running an edit session, the UI for the entire system is blocked. (Switching focus sends TSF notifications, which can't be delivered if your text service is in an edit session.) Displaying modal UI from an edit session is very very very bad. Of course, you'll probably discover this the hard way when your system locks up, but I thought I'd bring it up now and save you the effort.
The second rule of writing a text service is: Avoid Synchronous edit sessions. There are a number of text stores (namely, the 500 pound gorilla of text stores - Microsoft Word) that never grant synchronous edit sessions. (The only exception is when Microsoft Word asks for reconversions.) If you start your design with this assumption, you will avoid a painful redesign when you start testing with Microsoft Word, and you find that nothing works.
The third rule of writing a text service is: Text service code is hard to maintain. Because document modifications have to be done in an edit session, which may not run synchronously, you can't write code that expects to, for example, grab some text, inspect it, and do something from (for example) an event handler, or a keystroke handler. Instead, your handlers consist of a lot of edit sessions, and the edit sessions usually end by firing a callback (or expecting some other event handler to fire as a result of the change in the edit session).
The end result is a big pile of spaghetti code. The only way to avoid this would be to write your text service in a language other than C, which has the following feature set:
- supports closures and anonymous functions (to simplify the inherently asynchronous nature of text services)
- doesn't have a large runtime (because text services get loaded into a lot of processes),
- compiles to efficient native code (because text services run inside the event loop, and have to be fast)
- supports COM efficiently (because TSF is COM-based)
As far as I know, no language has that feature set. The last three features are much more important than the first one; if your text service slows down the system by 50%, or increases the working set of the typical application by 30%, people aren't going to leave your text service running for very long.