public GherkinFileEditorParserListener(ITextSnapshot textSnapshot, GherkinFileEditorClassifications classifications, GherkinFileEditorInfo previousGherkinFileEditorInfo, int changeLastLine, int changeLineDelta) { this.textSnapshot = textSnapshot; this.changeLineDelta = changeLineDelta; this.changeLastLine = changeLastLine; this.classifications = classifications; this.previousGherkinFileEditorInfo = previousGherkinFileEditorInfo; gherkinFileEditorInfo = new GherkinFileEditorInfo(); }
public GherkinFileEditorParserListener(ITextSnapshot textSnapshot, GherkinFileEditorClassifications classifications, GherkinFileEditorInfo previousGherkinFileEditorInfo, int lineOffset, int changeLastLine, int changeLineDelta) { this.textSnapshot = textSnapshot; this.changeLineDelta = changeLineDelta; this.changeLastLine = changeLastLine; this.lineOffset = lineOffset; this.classifications = classifications; this.previousGherkinFileEditorInfo = previousGherkinFileEditorInfo; gherkinFileEditorInfo = new GherkinFileEditorInfo(); beforeFeature = !isPartialParsing; }
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 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 void ParseAndTriggerChanges(GherkinFileEditorInfo gherkinFileEditorInfo, ChangeInfo changeInfo) { if (gherkinFileEditorInfo == null) { // initial parsing FullParse(changeInfo); return; } // incremental parsing var firstAffectedScenario = gherkinFileEditorInfo.ScenarioEditorInfos.LastOrDefault( s => s.StartLine <= changeInfo.ChangeFirstLine); if (firstAffectedScenario == null) { FullParse(changeInfo); return; } PartialParse(gherkinFileEditorInfo, changeInfo, firstAffectedScenario); }
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); }
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 ParseAndTriggerChanges(GherkinFileEditorInfo gherkinFileEditorInfo, ChangeInfo changeInfo) { if (gherkinFileEditorInfo == null) { // initial parsing FullParse(changeInfo); return; } if (partialParseCount >= PartialParseCountLimit) { visualStudioTracer.Trace("Forced full parse after " + partialParseCount + " incremental parse", ParserTraceCategory); FullParse(changeInfo); return; } // incremental parsing var firstAffectedScenario = gherkinFileEditorInfo.ScenarioEditorInfos.LastOrDefault( s => s.StartLine <= changeInfo.ChangeFirstLine); if (firstAffectedScenario == null) { // We would not need to do a full parse when the header chenges, but it would // be too complicated to bring this case through the logic now. // So the side-effect is that we do a full parse when the header changes instead of an incremental. FullParse(changeInfo); return; } PartialParse(gherkinFileEditorInfo, changeInfo, firstAffectedScenario); }
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"); }