internal override void BuildResult(Scanner s, out MatchResult result, Match m) { this.NewMatchResult(out result); this.m_pattern.BuildMatchResult(m, s.Reader.PosCurrent, s.PosWindowStart, ref result); SetPositionsInResult(ref result); return; }
private void DoRegionEndOffsets(int idxResult, ref MatchResult match) { switch (this.OffSetType) { case OffsetType.MatchEnd: match.PosAfterMatch = idxResult; if (Whence.Start == this.Whence) { match.PosAfterMatch++; } return; case OffsetType.HighlightEnd: match.PosAfterHighlight = idxResult; return; case OffsetType.RegionEnd: match.PosAfterRegion = idxResult; return; } }
private static void SetPositionsInResult(ref MatchResult result) { if (result.Success) { if (0 == result.PosHighlightStart) { result.PosHighlightStart = result.PosMatchStart; } if (0 == result.PosAfterHighlight) { result.PosAfterHighlight = result.PosAfterMatch; } } }
internal abstract void StartScopeForSuccesfulMatch(Scanner s, MatchResult match);
private void DoScan(SlidingWindowReader reader, ICodeFormatter formatter, bool writeAsynchronously) { ArgumentValidator.ThrowIfNull(formatter, "formatter"); this.Reader = reader; if (this.m_isFirstRun) { this.m_scopeStack = new List<Scope>(8); this.m_modes = new List<KeyValuePair<int, HighlightMode>>(64); this.m_possibleKeyword = new StringBuilder(this.m_syntaxDefinition.MaxKeywordLength + 1); this.m_isFirstRun = false; } else { this.m_scopeStack.Clear(); this.m_modes.Clear(); this.m_possibleKeyword.Length = 0; } this.m_pendingMatch = new MatchResult(); this.m_pendingMatch.PosMatchStart = int.MaxValue; this.m_posDontMatchUntil = -1; this.m_posAfterKeepend = int.MaxValue; this.m_scopeStack.Add(Scope.BuildBackgroundScope(this.m_syntaxDefinition.MainContext.TopItems)); this.BuildHighlightModes(); this.m_outputWriter = new HighlightedOutputWriter(formatter, writeAsynchronously); this.LoadInputWindow(this.Reader.CurrentWindow); this.Vrooom(); }
private void NewMatchResult(out MatchResult result) { result = new MatchResult(); result.MatchType = MatchType.Match; result.ContainerItem = this; }
internal void Match(Scanner s, int idxPosition, string[] externalCaptures, ref MatchResult result) { if (null == externalCaptures || externalCaptures.Length == 0) { this.Match(s, idxPosition, this.CachedRegex, ref result); return; } StringBuilder regexBuilder = new StringBuilder(this.RawRegex); int idxLastUsableCapture = Math.Min(externalCaptures.Length, this.LastExternalMatch); for (int i = 1; i <= idxLastUsableCapture; i++) { regexBuilder.Replace(StringExtensions.Fi("\\z{0}", i), externalCaptures[i - 1]); } Regex r = this.InstantiateRegex(regexBuilder.ToString(), false); this.Match(s, idxPosition, r, ref result); }
internal void BuildMatchResult(Match m, int posMatchedAt, int posWindowStart, ref MatchResult result) { result.Success = true; int posMatchStart = posMatchedAt + this.LeadingContext; int posAfterMatch = posMatchedAt + m.Length; if (this.HasMatchStartGroup) { for (int i = 0; i < m.Groups["zs"].Captures.Count; i++) { posMatchStart = Math.Max(posMatchStart, m.Groups["zs"].Captures[i].Index + posWindowStart); } } if (this.HasMatchEndGroup) { posAfterMatch = 0; for (int i = 0; i < m.Groups["ze"].Captures.Count; i++) { posAfterMatch = Math.Max(posAfterMatch, m.Groups["ze"].Captures[i].Index + posWindowStart); } } result.PosMatchedAt = posMatchedAt; result.PosMatchStart = posMatchStart; result.PosAfterMatch = posAfterMatch; for (int i = 0; i < this.m_offsets.Count; i++) { this.m_offsets[i].Apply(ref result, posMatchedAt, posAfterMatch); } if (this.CntExternalGroups > 0) { result.ExternalCaptures = new string[this.CntExternalGroups]; for (int i = 1; i <= this.CntExternalGroups; i++) { string capture = m.Groups["z" + i].Value; if (StringExtensions.HasMagicRegexChars(capture)) { capture = Regex.Escape(capture); } result.ExternalCaptures[i - 1] = capture; } } return; }
private void NewMatchResult(out MatchResult result) { result = new MatchResult(); result.MatchType = MatchType.RegionStart; result.ContainerItem = this; }
private void DoMatchOffsets(int posResult, ref MatchResult match) { switch (this.OffSetType) { case OffsetType.MatchStart: match.PosMatchStart = posResult; return; case OffsetType.MatchEnd: match.PosAfterMatch = posResult; return; case OffsetType.HighlightStart: match.PosHighlightStart = posResult; return; case OffsetType.HighlightEnd: match.PosAfterHighlight = posResult; return; } }
internal abstract void BuildResult(Scanner s, out MatchResult result, Match m);
internal override void StartScopeForSuccesfulMatch(Scanner s, MatchResult match) { Scope newScope = this.BuildNewScope(match, s.TopScope); s.PushScope(newScope); return; }
private Scope BuildNewScope(MatchResult result, Scope currentTopScope) { Scope scope = new Scope(); scope.PosMatchedAt = result.PosMatchedAt; scope.PosStart = result.PosMatchStart; scope.PosAfter = result.PosAfterMatch; scope.PosHighlightStart = result.PosHighlightStart; scope.PosAfterHighlight = result.PosAfterHighlight; scope.SyntaxItem = this; scope.Extend = this.Extend; scope.EatNewLineInRegion = this.Pattern.EatNewLine; scope.ActiveSyntaxItems = this.GetMatchableItems(currentTopScope); return scope; }
internal bool TryEnding(Scanner s, Scope scope) { int posMatchAt = s.Reader.PosCurrent; if (posMatchAt <= scope.PosEndSkippedUntil || scope.PosAfter != int.MaxValue) { return false; } if (this.TrySkips(s, scope, posMatchAt)) { return false; } MatchResult result = new MatchResult(); result.MatchType = MatchType.RegionEnd; for (int i = 0; i < this.m_endPatterns.Count; i++) { this.m_endPatterns[i].Match(s, posMatchAt, scope.ExternalCaptures, ref result); if (result.Success) { scope.PosAfter = result.PosAfterMatch; bool hasHighlightMode = this.m_endPatterns[i].HasHighlightMode; if (0 == result.PosAfterRegion && hasHighlightMode) { result.PosAfterRegion = result.PosMatchStart; } if (0 == result.PosAfterHighlight) { result.PosAfterHighlight = result.PosAfterMatch; } if (hasHighlightMode && result.PosAfterRegion < result.PosAfterHighlight) { s.SendMode(this.m_endPatterns[i].HighlightMode, result.PosAfterRegion); } if (result.PosAfterHighlight < result.PosAfterMatch) { s.BuildHighlightModes(result.PosAfterHighlight); } return true; } } return false; }
internal bool TrySkips(Scanner s, Scope scope, int posMatchAt) { if (posMatchAt <= scope.PosEndSkippedUntil || scope.PosAfter != int.MaxValue) { return false; } MatchResult result = new MatchResult(); result.MatchType = MatchType.RegionSkip; for (int i = 0; i < this.m_skipPatterns.Count; i++) { this.m_skipPatterns[i].Match(s, posMatchAt, scope.ExternalCaptures, ref result); if (result.Success) { if (result.PosAfterMatch <= s.PosWindowEnd) { if ('\n' == s[result.PosAfterMatch]) { result.PosAfterMatch++; } } scope.PosEndSkippedUntil = result.PosAfterMatch - 1; return true; } } return false; }
private bool TryFindEndWithinLine(Scanner s, int posStartAt, string[] externalCaptures) { MatchResult result = new MatchResult(); int position = posStartAt; while (position <= s.PosWindowEnd) { result.MatchType = MatchType.RegionSkip; for (int i = 0; i < this.m_skipPatterns.Count; i++) { this.m_skipPatterns[i].Match(s, position, externalCaptures, ref result); if (result.Success) { while (position < result.PosAfterMatch) { position++; if ('\n' == s.InputWindow[position]) { return false; } } break; } } for (int i = 0; i < this.m_endPatterns.Count; i++) { this.m_endPatterns[i].Match(s, position, externalCaptures, ref result); if (result.Success) { return true; } } if ('\n' == s.InputWindow[position]) { return false; } position++; } return false; }
private void DoRegionSkipOffsets(int idxResult, ref MatchResult match) { switch (this.OffSetType) { case OffsetType.MatchEnd: match.PosAfterMatch = idxResult; return; } }
internal void Match(Scanner s, int idxPosition, ref MatchResult result) { if (0 < this.LastExternalMatch) { string msg = StringExtensions.Fi("Invalid call to Match(): no external captures were passed, but Pattern '{0}' expects them", this); throw new InvalidOperationException(msg); } this.Match(s, idxPosition, this.CachedRegex, ref result); }
private void DoRegionStartOffsets(int idxResult, ref MatchResult match) { switch (this.OffSetType) { case OffsetType.MatchStart: match.PosMatchStart = idxResult; return; case OffsetType.HighlightStart: match.PosHighlightStart = idxResult; return; case OffsetType.RegionStart: match.PosRegionStart = idxResult; return; } }
private void Match(Scanner s, int idxPosition, Regex r, ref MatchResult result) { int idxMatchAt = idxPosition; if (this.LeadingContext > 0) { idxMatchAt -= this.LeadingContext; // SHOULD: idxMatchAt = Math.Min(idxMatchAt, s.GetIdxLineStartFor(s.m_idxMatchHead)); idxMatchAt = Math.Max(0, idxMatchAt); } Match m = r.Match(s.InputWindow.Window, idxMatchAt - s.PosWindowStart); if (m.Success) { this.BuildMatchResult(m, idxMatchAt, s.PosWindowStart, ref result); } else { result.Success = false; } }
/// <summary> /// /// </summary> /// <devdoc> /// Vim patterns are pretty quirky and inconsistent. See the file 'OffsetExperiments.vim' - it contains /// some experiments that show the behavior of offsets in Vim. /// </devdoc> internal void Apply(ref MatchResult match, int posOriginalStart, int posOriginalAfter) { int posWhence = (Whence.Start == this.Whence) ? posOriginalStart : posOriginalAfter; int posResult = posWhence + this.Offset; if ((this.OffSetType == OffsetType.MatchStart) || (this.OffSetType == OffsetType.HighlightStart)) { if (Whence.End == this.Whence) { posResult--; } } if (OffsetType.MatchStart == this.OffSetType) { if (posResult < posOriginalStart) { // Vim allows one to specify a negative offset for the match start, which should in theory make your match // happen earlier than it was actually found. No syntax files use this so we don't support it string msg = StringExtensions.Fi("Error applying offset to pattern - Iris does not support changing the start of a match " + "to a position BEFORE the unaltered start. Offset was '{0}', unaltered start was '{1}'", this, posOriginalStart); throw new AssertionViolationException(msg); } } switch (match.MatchType) { case MatchType.Match: this.DoMatchOffsets(posResult, ref match); break; case MatchType.RegionStart: this.DoRegionStartOffsets(posResult, ref match); break; case MatchType.RegionSkip: this.DoRegionSkipOffsets(posResult, ref match); break; case MatchType.RegionEnd: this.DoRegionEndOffsets(posResult, ref match); break; default: string msg = StringExtensions.Fi("Unhandled MatchType: '{0}'", match.MatchType); throw new AssertionViolationException(msg); } }
internal override void BuildResult(Scanner s, out MatchResult result, Match m) { if (this.IsOneLine) { result = this.TryMatch(s); return; } this.NewMatchResult(out result); for (int i = 0; i < this.m_startPatterns.Count; i++) { if (m.Groups["s" + i].Success) { result.Pattern = this.m_startPatterns[i]; this.m_startPatterns[i].BuildMatchResult(m, s.Reader.PosCurrent, s.PosWindowStart, ref result); return; } } string msg = StringExtensions.Fi("Unable to find pattern that matched for region '{0}'", this); throw new AssertionViolationException(msg); }
private bool TryVimMatchesAndRegions(ref int posAdvanceTo) { int posMatchAt = this.Reader.PosCurrent; if (this.m_pendingMatch.PosMatchStart < posMatchAt) { this.m_pendingMatch.PosMatchStart = int.MaxValue; } if (this.m_posDontMatchUntil < posMatchAt && this.TopScope.ActiveSyntaxItems.HasMatchesOrRegions) { int idxMatchedItem; MatchResult result = this.TopScope.ActiveSyntaxItems.TryMatchOrRegionStart(this, out idxMatchedItem); for (int i = idxMatchedItem; i < this.TopScope.ActiveSyntaxItems.Items.Length; i++) { bool firstIteration = idxMatchedItem == i; if (!firstIteration) { result = ((ContainerItem) this.TopScope.ActiveSyntaxItems.Items[i]).TryMatch(this); } ContainerItem matchCandidate = result.ContainerItem; // the check below prevents infinite recursion when an item contains itself. It's still possible // to get infinite recursion using two items that contain each other. if ((matchCandidate == this.ItemInScope) && (posMatchAt == this.TopScope.PosMatchedAt)) { continue; } if (result.Success) { if (result.ContainerItem is VimMatch && result.PosAfterMatch == posMatchAt) { continue; } if (result.PosMatchStart < this.m_pendingMatch.PosMatchStart || (result.PosMatchStart == this.m_pendingMatch.PosMatchStart && this.m_pendingMatch.PositionInSyntaxFile < matchCandidate.PositionInSyntaxDefinition) ) { this.m_pendingMatch = result; this.m_pendingMatch.PositionInSyntaxFile = matchCandidate.PositionInSyntaxDefinition; // if the match starts at the match head, we'll call it the best possible match. In _theory_, we could find a match with // a negative start offset, but this would always force us to try every match, which would kill performance. Vim behaves like // we do. I imagine it's for the same reason. if (result.PosMatchStart <= posMatchAt) { break; } } } } } if (this.m_pendingMatch.PosMatchStart <= posMatchAt) { ContainerItem matchedItem = this.m_pendingMatch.ContainerItem; matchedItem.StartScopeForSuccesfulMatch(this, this.m_pendingMatch); this.ClearPendingMatch(); posAdvanceTo = this.TopScope.PosStart; return true; } return false; }
internal override void StartScopeForSuccesfulMatch(Scanner s, MatchResult match) { Scope newScope = this.BuildNewScope(s.TopScope); newScope.PosMatchedAt = match.PosMatchedAt; newScope.ExternalCaptures = match.ExternalCaptures; bool hasHighlightMode = match.Pattern.HasHighlightMode; if (0 == match.PosRegionStart) { match.PosRegionStart = hasHighlightMode ? match.PosAfterMatch : match.PosMatchStart; } if (0 == match.PosHighlightStart) { match.PosHighlightStart = match.PosMatchStart; } if (hasHighlightMode && match.PosHighlightStart < match.PosRegionStart) { s.SendMode(match.Pattern.HighlightMode, match.PosHighlightStart); } newScope.PosStart = hasHighlightMode ? match.PosRegionStart : match.PosMatchStart; newScope.PosHighlightStart = hasHighlightMode ? match.PosRegionStart : match.PosHighlightStart; newScope.PosEndSkippedUntil = hasHighlightMode ? match.PosRegionStart - 1 : match.PosAfterMatch - 1; newScope.EatNewLineInRegion = match.Pattern.EatNewLine; s.PushScope(newScope); }
private bool TryVimMatchesAndRegions(ref int posAdvanceTo) { int posMatchAt = this.Reader.PosCurrent; if (this.m_pendingMatch.PosMatchStart < posMatchAt) { this.m_pendingMatch.PosMatchStart = int.MaxValue; } if (this.m_posDontMatchUntil < posMatchAt && this.TopScope.ActiveSyntaxItems.HasMatchesOrRegions) { int idxMatchedItem; MatchResult result = this.TopScope.ActiveSyntaxItems.TryMatchOrRegionStart(this, out idxMatchedItem); for (int i = idxMatchedItem; i < this.TopScope.ActiveSyntaxItems.Items.Length; i++) { bool firstIteration = idxMatchedItem == i; if (!firstIteration) { result = ((ContainerItem)this.TopScope.ActiveSyntaxItems.Items[i]).TryMatch(this); } ContainerItem matchCandidate = result.ContainerItem; // the check below prevents infinite recursion when an item contains itself. It's still possible // to get infinite recursion using two items that contain each other. if ((matchCandidate == this.ItemInScope) && (posMatchAt == this.TopScope.PosMatchedAt)) { continue; } if (result.Success) { if (result.ContainerItem is VimMatch && result.PosAfterMatch == posMatchAt) { continue; } if (result.PosMatchStart < this.m_pendingMatch.PosMatchStart || (result.PosMatchStart == this.m_pendingMatch.PosMatchStart && this.m_pendingMatch.PositionInSyntaxFile < matchCandidate.PositionInSyntaxDefinition) ) { this.m_pendingMatch = result; this.m_pendingMatch.PositionInSyntaxFile = matchCandidate.PositionInSyntaxDefinition; // if the match starts at the match head, we'll call it the best possible match. In _theory_, we could find a match with // a negative start offset, but this would always force us to try every match, which would kill performance. Vim behaves like // we do. I imagine it's for the same reason. if (result.PosMatchStart <= posMatchAt) { break; } } } } } if (this.m_pendingMatch.PosMatchStart <= posMatchAt) { ContainerItem matchedItem = this.m_pendingMatch.ContainerItem; matchedItem.StartScopeForSuccesfulMatch(this, this.m_pendingMatch); this.ClearPendingMatch(); posAdvanceTo = this.TopScope.PosStart; return(true); } return(false); }