Source

YouCantSpell / src / YouCantSpell.ReSharper.Shared / TagMarkupSpellCheckDaemonStageProcessBase.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using JetBrains.Application;
using JetBrains.DocumentModel;
using JetBrains.ReSharper.Daemon;
using JetBrains.ReSharper.Psi;
using JetBrains.ReSharper.Psi.Tree;
using JetBrains.Util;
using YouCantSpell.CStyle;

namespace YouCantSpell.ReSharper
{
	public abstract class TagMarkupSpellCheckDaemonStageProcessBase<TCodeFile>
		: IDaemonStageProcess
		where TCodeFile : class, IFile
	{

		private const int MinWordSize = 2;

		protected TagMarkupSpellCheckDaemonStageProcessBase(IDaemonProcess daemonProcess, TCodeFile codeFile)
		{
			if(null == daemonProcess) throw new ArgumentNullException("daemonProcess");
			if(null == codeFile) throw new ArgumentNullException("codeFile");
			DaemonProcess = daemonProcess;
			CodeFile = codeFile;

			SpellCheckResources = Shell.Instance.GetComponent<ShellSpellCheckResources>();
			PsiSourceFile = daemonProcess.SourceFile;
			Document = daemonProcess.Document;
		}

		public IDaemonProcess DaemonProcess { get; private set; }

		public TCodeFile CodeFile { get; private set; }

		public ShellSpellCheckResources SpellCheckResources { get; private set; }

		public IPsiSourceFile PsiSourceFile { get; private set; }

		public IDocument Document { get; private set; }

		protected DocumentRange? FindTrueDocumentRange(TreeTextRange range) {
			return CodeFile.GetIntersectingRanges(range)
				.SingleOrDefault(x => x.Document == PsiSourceFile.Document);
		}

		protected bool WordIsIgnored(string word) {
			return String.IsNullOrEmpty(word)
				|| word.Length < MinWordSize
				|| SpellCheckResources.IsIgnoredInsensitive(word)
				|| CStyleFreeTextParser.LooksLikeCodeWord(word);
		}

		protected IEnumerable<HighlightingInfo> FindWordHighlightings(ITreeNode node) {
			var validRange = FindTrueDocumentRange(node.GetTreeTextRange());
			if(!validRange.HasValue) return Enumerable.Empty<HighlightingInfo>();

			return FindWordHighlightings(node, node.GetText(), validRange.Value);
		}

		protected IEnumerable<HighlightingInfo> FindWordHighlightings(ITreeNode node, string text, DocumentRange textRange) {
			var highlights = new List<HighlightingInfo>(0);
			if(WordIsIgnored(text))
				return highlights;

			var parser = new CStyleFreeTextParser();
			var wordParts = parser.ParseSentenceWordsForSpellCheck(new TextSubString(text));
			foreach(var wordPart in wordParts) {
				var word = wordPart.SubText;

				// Make sure that the word is not to be ignored for any reason.
				if(WordIsIgnored(word)) continue;

				// Finally we check the spelling of the word.
				if(SpellCheckResources.Primary.Check(word)) continue;

				// If we got this far we need to offer spelling suggestions.
				var wordPartDocumentOffset = textRange.TextRange.StartOffset + wordPart.Offset;
				var wordRange = new DocumentRange(Document, new TextRange(wordPartDocumentOffset, wordPartDocumentOffset + word.Length));
				var highlight = CreateHighlighting(node, wordRange, word, null);
				highlights.Add(new HighlightingInfo(wordRange, highlight));
			}
			return highlights;
		}

		public abstract void Execute(Action<DaemonStageResult> committer);

		protected abstract SpellingErrorHighlightingBase CreateHighlighting(ITreeNode node, DocumentRange errorRange, string wordInError, Func<string, string[]> getSuggestions);

	}
}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.