|
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Windows.Threading;
using DigitalSamurai.SpellSharp.InputProcessing;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Tagging;
namespace DigitalSamurai.SpellSharp.Vsx
{
public partial class SpellingTagger : ITagger<SpellingTag>, IDisposable
{
private volatile List<SpellingTag> volatileSpellingTags;
private Dispatcher dispatcher;
private DispatcherTimer timer;
private int isExecutingSpellingChecker;
public ITextBuffer Buffer { get; private set; }
public IServiceProvider ServiceProvider { get; private set; }
#region public event EventHandler<SnapshotSpanEventArgs> TagsChanged { add; remove; protected raise; }
public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
protected void RaiseTagsChangedEvent (SnapshotSpan snapshotSpan)
{
if (snapshotSpan == null)
{
throw new ArgumentNullException ("snapshotSpan");
}
var handler = TagsChanged;
if (handler != null)
{
handler
(
this,
new SnapshotSpanEventArgs (snapshotSpan)
);
}
}
#endregion
public SpellingTagger (ITextBuffer buffer, IServiceProvider serviceProvider)
{
if (buffer == null)
{
throw new ArgumentNullException ("buffer");
}
if (serviceProvider == null)
{
throw new ArgumentNullException ("serviceProvider");
}
Buffer = buffer;
ServiceProvider = serviceProvider;
volatileSpellingTags = new List<SpellingTag> ();
dispatcher = Dispatcher.CurrentDispatcher;
Buffer.Changed += Delayed_QueueExecutionOfSpellingChecker;
Buffer.ContentTypeChanged += Delayed_QueueExecutionOfSpellingChecker;
CustomWordsDictionary.Changed += Delayed_QueueExecutionOfSpellingChecker;
CustomWordsDictionary.Initialize (ServiceProvider);
Delayed_QueueExecutionOfSpellingChecker ();
}
public void Dispose ()
{
if (Buffer != null)
{
timer.Tick -= QueueExecutionOfSpellingChecker;
timer.Stop ();
Buffer.Changed -= Delayed_QueueExecutionOfSpellingChecker;
Buffer.ContentTypeChanged -= Delayed_QueueExecutionOfSpellingChecker;
CustomWordsDictionary.Changed -= Delayed_QueueExecutionOfSpellingChecker;
Buffer = null;
ServiceProvider = null;
}
}
public IEnumerable<ITagSpan<SpellingTag>> GetTags (NormalizedSnapshotSpanCollection spans)
{
if (spans == null)
{
throw new ArgumentNullException ("spans");
}
if (spans.Count == 0)
{
yield break;
}
var localSpellingTags = volatileSpellingTags;
if (localSpellingTags.Count == 0)
{
yield break;
}
foreach (var spellingTag in localSpellingTags)
{
var mappedTag = spellingTag.CreateMappedTagSpanWhenIntersects (spans);
if (mappedTag != null)
{
yield return mappedTag;
}
}
}
private void Delayed_QueueExecutionOfSpellingChecker (object sender, EventArgs args)
{
Delayed_QueueExecutionOfSpellingChecker ();
}
private void Delayed_QueueExecutionOfSpellingChecker ()
{
if (timer == null)
{
timer = new DispatcherTimer (DispatcherPriority.ApplicationIdle, dispatcher)
{
Interval = TimeSpan.FromMilliseconds (500)
};
timer.Tick += QueueExecutionOfSpellingChecker;
}
timer.Stop ();
timer.Start ();
}
private void QueueExecutionOfSpellingChecker (object sender, EventArgs e)
{
timer.Stop ();
if (isExecutingSpellingChecker++ == 0)
{
ThreadPool.QueueUserWorkItem (ExecuteSpellingChecker);
}
else
{
isExecutingSpellingChecker--;
}
}
private void ExecuteSpellingChecker (object state)
{
var newTags = new List<SpellingTag> ();
var wordTokens = ProcessorFactory.Create (DetermineProcessorType ()).EnumerateWordTokensToSpellCheck
(
new DocumentReader
(
new StringReader
(
Buffer.CurrentSnapshot.GetText ()
)
)
);
foreach (var misspelledWord in EnumerateMisspelledWordTokens (wordTokens))
{
var span = new SnapshotSpan
(
Buffer.CurrentSnapshot,
misspelledWord.Start,
misspelledWord.Length
);
newTags.Add
(
new SpellingTag
(
ServiceProvider,
span.Snapshot.CreateTrackingSpan (span, SpanTrackingMode.EdgeExclusive),
misspelledWord.Text
)
);
}
dispatcher.Invoke
(
new Action
(
() =>
{
volatileSpellingTags = newTags;
RaiseTagsChangedEvent
(
new SnapshotSpan
(
Buffer.CurrentSnapshot,
0,
Buffer.CurrentSnapshot.Length
)
);
isExecutingSpellingChecker--;
}
)
);
}
private IEnumerable<DocumentToken> EnumerateMisspelledWordTokens (IEnumerable<DocumentToken> wordTokens)
{
foreach (var wordToken in wordTokens)
{
var word = wordToken.Text;
if (!CustomWordsDictionary.IsCustomWord (word) && !Hunspell.Library.IsSpelledCorrect (word))
{
yield return wordToken;
}
}
}
public ProcessorType DetermineProcessorType ()
{
var contentType = Buffer.ContentType.TypeName;
switch (contentType)
{
case "CSharp":
return ProcessorType.CSharp;
case "plaintext":
return ProcessorType.Text;
case "SQL":
return ProcessorType.TSql;
default:
return ProcessorType.Unknown;
}
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.