Parse Requests and Dispatchers
Parse requests are created to request that syntax/semantic analysis be performed on some text. CodeDocument is capable of automatically making parse requests when its text changes, so long as its ISyntaxLanguage has an IParser service registered.
A parse request dispatcher is notified of incoming parse requests and queues them. It uses one or more worker threads to execute the requested parsing operations in prioritized order, thereby preventing any blocking of the main UI thread.
Initializing an Ambient Parse Request Dispatcher for an Application
An IParseRequestDispatcher is an object that is capable of receiving parse requests (IParseRequest instances). Upon receipt of a request, it will generally queue the request, possibly disposing of similar previous requests that are still on the queue.
One or more worker threads are then used to perform parsing operations, one by one, based on the data in the requests. More than one worker thread is advantageous when there are potentially many parsing requests queued, while editing of a code document (via a SyntaxEditor control for instance) is taking place. This allows the requests made by the code document to continue to get handled fast, intermixed with the other queued requests.
By default, no ambient IParseRequestDispatcher is installed meaning parsing from code documents (explained in next section) will be done in the main UI thread. Configure an ambient parse request dispatcher (see below) to ensure parsing operations are offloaded into worker threads.
ThreadedParseRequestDispatcher is the default implementation of an IParseRequestDispatcher that ships with the parsing framework. It is capable of handling parse requests on one or more worker threads.
By default it creates a maximum number of worker threads that is equal to your machine's processor core count minus one. Thus on a quad-core machine, up to three worker threads may be created. If a worker thread is not used for some time, it will be disposed of.
Configuring the Ambient Parse Request Dispatcher
As described below, code documents are capable of making automatic parse requests. They need to know which IParseRequestDispatcher to use though. If they can't find one, then they execute the parsing operation in the main UI thread, which can block UI if the parsing operation takes time.
The AmbientParseRequestDispatcherProvider class is used to indicate which IParseRequestDispatcher should be used by default. Code documents look at the AmbientParseRequestDispatcherProvider, and any manual parse requests should too.
This code is executed at application startup and creates a ThreadedParseRequestDispatcher for use as the ambient parse request dispatcher.
AmbientParseRequestDispatcherProvider.Dispatcher = new ThreadedParseRequestDispatcher();
Once the code above is executed, worker threads will now be used to execute parsing operations.
At application shutdown, this code can be used to remove the ambient parse request dispatcher, kill its worker threads, and empty its parse queue.
IParseRequestDispatcher dispatcher = AmbientParseRequestDispatcherProvider.Dispatcher; AmbientParseRequestDispatcherProvider.Dispatcher = null; dispatcher.Dispose();
CodeDocument Makes Automatic Parse Requests
Code documents (CodeDocument instances) have special features built into them such that when a text change occurs, they look at the ISyntaxLanguage that is attached to the document, if any. If the language has an IParser registered as a service, an IParseRequest is automatically generated and sent to the IParseRequestDispatcher specified by the AmbientParseRequestDispatcherProvider to be queued for processing.
As indicated above, if no ambient parse request dispatcher is configured, parsing operations will be performed in the main UI thread, possibly blocking it if the parsing operations take time to complete.
All of the parse request generation occurs automatically, as long as a parser is found on the language. The results of the parse operation are returned asynchronously to the ICodeDocument.ParseData property, at which time the document's ParseDataChanged event fires.
Manually Triggering CodeDocument Parse Requests
Sometimes there are situations where a configuration option that the parser uses has changed but the text of an ICodeDocument has not been modified. Thus the parse data for the document may no longer be valid.
The ICodeDocument.QueueParseRequest method can be called in this scenario to manually queue up a parse request for the document. Once the parse request is processed, the document's ParseData property will be updated. As discussed above, like all parsing operations, this process may be asynchronous.
Creating a Parse Request Manually
Parse requests can be created manually for any bit of text. No document is necessary. Say that you are loading a C# project and would like to load compilation unit data for each one of the files in the project. In that case you could queue up parsing requests for each of the files. It is best to use a low priority so that the queued requests don't interfere with normal editor/code document parsing.
- A string source key that identifies the source
- An ITextBufferReader that is used by the parser to scan text
- The ISyntaxLanguage (preferred) or IParser that should be used to perform the parsing operation
- The IParseTarget that is notified once the parsing is completed
The source key is generally a filename but really can be anything you like that uniquely identifies the text content being parsed.
The ISyntaxLanguage is a language that has an IParser. If no ISyntaxLanguage is available, then an IParser instance can be passed in its place, but it is better to pass the language instance. The IParser is any object that has a Parse that accepts an IParseRequest and returns an IParseData result.
The IParseTarget is an object that has a unique ID identifying it, along with a method that is called after a request has been processed and completed.
This code shows how to create a manual request without a language available and queue it:
// Create the request string sourceKey = @"c:\myfilename.txt"; ITextBufferReader reader = new StringTextBufferReader("Text to parse"); IParser parser = new MyTextParser(); // Some class implementing IParser IParseTarget parseTarget = this; // Assuming class that executes this code implements IParseTarget IParseRequest request = new ParseRequest(sourceKey, reader, parser, parseTarget); request.Priority = ParseRequest.LowPriority; // Queue the request if (AmbientParseRequestDispatcherProvider.Dispatcher != null) AmbientParseRequestDispatcherProvider.Dispatcher.QueueRequest(request);
Other Parse Request Features
The IParseRequest has some additional useful features.
Creation and Identification
The CreatedDateTime property indicates when the request was created.
Queueing - Priority and Optimization
The Priority property allows the priority of the request to be set. Manual parse requests should generally use the priority specified by ParseRequest.LowPriority. Code document requests use MediumPriority. IParseRequestDispatcher implementations generally use the priority setting to determine how to queue requests.
The RepeatedRequestPause property lets you indicate the number of milliseconds to pause if there are repeated attempts for the same request. This scenario can happen if an editor is working on a code document and a lot of typing is occurring. By introducing a small pause, performance is optimized. The default value is
Originating Text Snapshot
The Snapshot property returns a ITextSnapshot that indicates the snapshot from which the request was made, if available. Note that while this property is automatically populated when CodeDocument creates the request, manually-created parse requests may choose not to specify a snapshot.
Other Parse Request Dispatcher Features
Generally it is not necessary to call any additional methods on IParseRequestDispatcher since the entire queue and dispatch processing is mostly automated for your convenience. However there are a number of useful members on the dispatcher that can tell you what it is currently doing, etc.
The RemovePendingRequests method accepts a parse hash key and removes any queued instances of requests with that hash key, if there are any.
Blocking Until a Request Has Been Processed
The WaitForParse method can be used to block the calling thread until a pending request with the specified hash key is completed, or a certain timespan is elapsed. The standard timespan used is
This method is generally used before building contextual data for IntelliPrompt display since ideally you want the IntelliPrompt UI to have the most up-to-date data in it.