private void TriggerChanges(GherkinFileEditorInfo gherkinFileEditorInfo, ChangeInfo changeInfo, ScenarioEditorInfo firstAffectedScenario = null, ScenarioEditorInfo firstUnchangedScenario = null)
        {
            this.GherkinFileEditorInfo = gherkinFileEditorInfo;

            var textSnapshot = changeInfo.TextSnapshot;
            int startPosition = 0;
            if (firstAffectedScenario != null)
                startPosition = textSnapshot.GetLineFromLineNumber(firstAffectedScenario.StartLine).Start;
            int endPosition = textSnapshot.Length;
            if (firstUnchangedScenario != null)
                endPosition = textSnapshot.GetLineFromLineNumber(firstUnchangedScenario.StartLine).Start;
            var snapshotSpan = new SnapshotSpan(textSnapshot, startPosition, endPosition - startPosition);

            if (ClassificationChanged != null)
            {
                ClassificationChanged(this, new ClassificationChangedEventArgs(snapshotSpan));
            }
            if (TagsChanged != null)
            {
                TagsChanged(this, new SnapshotSpanEventArgs(snapshotSpan));
            }
        }
        private GherkinFileEditorInfo DoScan(string fileContent, ITextSnapshot textSnapshot, int lineOffset, I18n languageService, GherkinFileEditorParserListener gherkinListener, int errorRertyCount, out ScenarioEditorInfo firstUnchangedScenario)
        {
            const int MAX_ERROR_RETRY = 5;
            const int NO_ERROR_RETRY_FOR_LINES = 5;

            firstUnchangedScenario = null;
            try
            {
                Lexer lexer = languageService.lexer(gherkinListener);
                lexer.scan(fileContent, null, 0);
            }
            catch (PartialListeningDoneException partialListeningDoneException)
            {
                firstUnchangedScenario = partialListeningDoneException.FirstUnchangedScenario;
            }
            catch(LexingError lexingError)
            {
                int? errorLine = GetErrorLine(lexingError, lineOffset);
                if (errorLine != null &&
                    errorLine.Value < textSnapshot.LineCount - NO_ERROR_RETRY_FOR_LINES &&
                    errorRertyCount < MAX_ERROR_RETRY)
                {
                    //add error classification & continue

                    var restartLineNumber = errorLine.Value + 1;
                    int restartPosition = textSnapshot.GetLineFromLineNumber(restartLineNumber).Start;
                    string restartFileContent = textSnapshot.GetText(restartPosition, textSnapshot.Length - restartPosition);

                    gherkinListener.LineOffset = restartLineNumber;
                    return DoScan(restartFileContent, textSnapshot,
                                  restartLineNumber, languageService, gherkinListener,
                                  errorRertyCount + 1,
                                  out firstUnchangedScenario);
                }
            }
            // ReSharper disable EmptyGeneralCatchClause
            catch
            // ReSharper restore EmptyGeneralCatchClause
            {
                // unknown error
            }

            return gherkinListener.GetResult();
        }
        private void PartialParse(GherkinFileEditorInfo gherkinFileEditorInfo, ChangeInfo changeInfo, ScenarioEditorInfo firstAffectedScenario)
        {
            int parseStartPosition =
                changeInfo.TextSnapshot.GetLineFromLineNumber(firstAffectedScenario.StartLine).Start;

            string fileContent = changeInfo.TextSnapshot.GetText(parseStartPosition, changeInfo.TextSnapshot.Length - parseStartPosition);
            string fileHeader = changeInfo.TextSnapshot.GetText(0, parseStartPosition);
            I18n languageService = GetLanguageService(fileHeader);

            ScenarioEditorInfo firstUnchangedScenario;
            var partialResult = DoParsePartial(fileContent, languageService,
                                               firstAffectedScenario.StartLine,
                                               out firstUnchangedScenario,
                                               changeInfo.TextSnapshot,
                                               gherkinFileEditorInfo,
                                               changeInfo.ChangeLastLine,
                                               changeInfo.LineCountDelta);

            if (partialResult.HeaderClassificationSpans.Any())
            {
                //TODO: merge to the prev scenario?
                partialResult.HeaderClassificationSpans.Clear();
            }
            partialResult.HeaderClassificationSpans.AddRange(
                gherkinFileEditorInfo.HeaderClassificationSpans
                    .Select(cs => cs.Shift(changeInfo.TextSnapshot, 0)));

            // inserting the non-affected scenarios
            partialResult.ScenarioEditorInfos.InsertRange(0,
                                                          gherkinFileEditorInfo.ScenarioEditorInfos.TakeUntilItemExclusive(firstAffectedScenario)
                                                              .Select(senario => senario.Shift(changeInfo.TextSnapshot, 0, 0)));

            if (firstUnchangedScenario != null)
            {
                // inserting the non-effected scenarios at the end

                partialResult.ScenarioEditorInfos.AddRange(
                    gherkinFileEditorInfo.ScenarioEditorInfos.SkipFromItemInclusive(firstUnchangedScenario)
                        .Select(
                            scenario =>
                            scenario.Shift(changeInfo.TextSnapshot, changeInfo.LineCountDelta, changeInfo.PositionDelta)));
            }

            TriggerChanges(partialResult, changeInfo, firstAffectedScenario, firstUnchangedScenario);
        }
 private GherkinFileEditorInfo DoParsePartial(string fileContent, I18n languageService, int lineOffset, out ScenarioEditorInfo firstUnchangedScenario, ITextSnapshot textSnapshot, GherkinFileEditorInfo previousGherkinFileEditorInfo, int changeLastLine, int changeLineDelta)
 {
     var gherkinListener = new GherkinFileEditorParserListener(textSnapshot, classifications, previousGherkinFileEditorInfo, lineOffset, changeLastLine, changeLineDelta);
     return DoScan(fileContent, textSnapshot, lineOffset, languageService, gherkinListener, 0, out firstUnchangedScenario);
 }
 public PartialListeningDoneException(ScenarioEditorInfo firstUnchangedScenario)
 {
     FirstUnchangedScenario = firstUnchangedScenario;
 }
        private GherkinFileEditorInfo DoParsePartial(string fileContent, I18n languageService, int lineOffset, out ScenarioEditorInfo firstUnchangedScenario, ITextSnapshot textSnapshot, GherkinFileEditorInfo previousGherkinFileEditorInfo, int changeLastLine, int changeLineDelta)
        {
            GherkinScanner scanner = new GherkinScanner(languageService, fileContent, lineOffset);

            var gherkinListener = new GherkinFileEditorParserListener(textSnapshot, classifications, previousGherkinFileEditorInfo, changeLastLine, changeLineDelta);
            firstUnchangedScenario = null;
            try
            {
                scanner.Scan(gherkinListener);
            }
            catch (PartialListeningDoneException partialListeningDoneException)
            {
                firstUnchangedScenario = partialListeningDoneException.FirstUnchangedScenario;
            }

            return gherkinListener.GetResult();
        }
        private void TriggerChanges(GherkinFileEditorInfo gherkinFileEditorInfo, ChangeInfo changeInfo, ScenarioEditorInfo firstAffectedScenario = null, ScenarioEditorInfo firstUnchangedScenario = null)
        {
            this.GherkinFileEditorInfo = gherkinFileEditorInfo;

            var textSnapshot = changeInfo.TextSnapshot;
            int startPosition = 0;
            if (firstAffectedScenario != null)
                startPosition = textSnapshot.GetLineFromLineNumber(firstAffectedScenario.StartLine).Start;
            int endPosition = textSnapshot.Length;
            if (firstUnchangedScenario != null)
                endPosition = textSnapshot.GetLineFromLineNumber(firstUnchangedScenario.StartLine).Start;

            // safety criteria to avoid argument execption in case of a wrong parser result
            if (startPosition >= endPosition)
                return;

            var snapshotSpan = new SnapshotSpan(textSnapshot, startPosition, endPosition - startPosition);

            if (ClassificationChanged != null)
            {
                ClassificationChanged(this, new ClassificationChangedEventArgs(snapshotSpan));
            }
            if (TagsChanged != null)
            {
                TagsChanged(this, new SnapshotSpanEventArgs(snapshotSpan));
            }
        }
        private void PartialParse(GherkinFileEditorInfo gherkinFileEditorInfo, ChangeInfo changeInfo, ScenarioEditorInfo firstAffectedScenario)
        {
            visualStudioTracer.Trace("Start incremental parsing", ParserTraceCategory);
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();

            partialParseCount++;

            int parseStartPosition = 
                changeInfo.TextSnapshot.GetLineFromLineNumber(firstAffectedScenario.StartLine).Start;

            string fileContent = changeInfo.TextSnapshot.GetText(parseStartPosition, changeInfo.TextSnapshot.Length - parseStartPosition);
            string fileHeader = changeInfo.TextSnapshot.GetText(0, parseStartPosition);
            I18n languageService = GetLanguageService(fileHeader);

            ScenarioEditorInfo firstUnchangedScenario;
            var partialResult = DoParsePartial(fileContent, languageService, 
                                               firstAffectedScenario.StartLine, 
                                               out firstUnchangedScenario, 
                                               changeInfo.TextSnapshot,
                                               gherkinFileEditorInfo,
                                               changeInfo.ChangeLastLine,
                                               changeInfo.LineCountDelta);

            if (partialResult.HeaderClassificationSpans.Any())
            {
                //TODO: merge to the prev scenario?
                partialResult.HeaderClassificationSpans.Clear();
            }
            partialResult.HeaderClassificationSpans.AddRange(
                gherkinFileEditorInfo.HeaderClassificationSpans
                    .Select(cs => cs.Shift(changeInfo.TextSnapshot, 0)));

            // inserting the non-affected scenarios
            partialResult.ScenarioEditorInfos.InsertRange(0,
                                                          gherkinFileEditorInfo.ScenarioEditorInfos.TakeUntilItemExclusive(firstAffectedScenario)
                                                              .Select(senario => senario.Shift(changeInfo.TextSnapshot, 0, 0)));

            ScenarioEditorInfo firstUnchangedScenarioShifted = null;
            if (firstUnchangedScenario != null)
            {
                // inserting the non-effected scenarios at the end

                int firstNewScenarioIndex = partialResult.ScenarioEditorInfos.Count;
                partialResult.ScenarioEditorInfos.AddRange(
                    gherkinFileEditorInfo.ScenarioEditorInfos.SkipFromItemInclusive(firstUnchangedScenario)
                        .Select(
                            scenario =>
                            scenario.Shift(changeInfo.TextSnapshot, changeInfo.LineCountDelta, changeInfo.PositionDelta)));

                firstUnchangedScenarioShifted = partialResult.ScenarioEditorInfos.Count > firstNewScenarioIndex
                                             ? partialResult.ScenarioEditorInfos[firstNewScenarioIndex]
                                             : null;
            }

            TriggerChanges(partialResult, changeInfo, firstAffectedScenario, firstUnchangedScenarioShifted);

            stopwatch.Stop();
            TraceFinishParse(stopwatch, "incremental");
        }