public SnapshotSpan GetSpanOfEnclosing(SnapshotSpan activeSpan) { if (!XmlBackgroundParser.TryGetParser(activeSpan.Snapshot.TextBuffer, out var parser)) { return(codeNavigator.GetSpanOfEnclosing(activeSpan)); } // use last parse if it's up to date, which is most likely will be // else use a spine from the end of the selection and update as needed var lastParse = parser.LastOutput; List <XObject> nodePath; XmlSpineParser spine = null; if (lastParse != null && lastParse.TextSnapshot.Version.VersionNumber == activeSpan.Snapshot.Version.VersionNumber) { var n = lastParse.XDocument.FindAtOrBeforeOffset(activeSpan.Start.Position); nodePath = n.GetPath(); } else { spine = parser.GetSpineParser(activeSpan.Start); nodePath = spine.AdvanceToNodeEndAndGetNodePath(activeSpan.Snapshot); } // this is a little odd because it was ported from MonoDevelop, where it has to maintain its own stack of state // for contract selection. it describes the current semantic selection as a node path, the index of the node in that path // that's selected, and the kind of selection that node has. int selectedNodeIndex = nodePath.Count; SelectionLevel selectionLevel = default; // keep on expanding the selection until we find one that contains the current selection but is a little bigger while (ExpandSelection(nodePath, spine, activeSpan, ref selectedNodeIndex, ref selectionLevel)) { var selectionSpan = GetSelectionSpan(activeSpan.Snapshot, nodePath, ref selectedNodeIndex, ref selectionLevel); if (selectionSpan is TextSpan s && s.Start <= activeSpan.Start && s.End >= activeSpan.End && s.Length > activeSpan.Length) { var selectionSnapshotSpan = new SnapshotSpan(activeSpan.Snapshot, s.Start, s.Length); // if we're in content, the code navigator may be able to make a useful smaller expansion if (selectionLevel == SelectionLevel.Content) { var codeNavigatorSpan = codeNavigator.GetSpanOfEnclosing(activeSpan); if (selectionSnapshotSpan.Contains(codeNavigatorSpan)) { return(codeNavigatorSpan); } } return(selectionSnapshotSpan); } } return(codeNavigator.GetSpanOfEnclosing(activeSpan)); }
public bool TryGetUE4Macro(SnapshotPoint triggerPoint, out UE4MacroStatement ue4MacroStatement) { ue4MacroStatement = null; var currentPoint = triggerPoint - 1; var extent = _navigator.GetExtentOfWord(currentPoint); var statement = _navigator.GetSpanOfEnclosing(extent.Span); var statementText = statement.GetText(); var match = Regex.Match(statementText, $@"({UE4Statics.MacroNamesRegExPatern})\((.*)\)", RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(100)); if (!match.Success) { return(false); } if (!match.Groups[1].Success || !match.Groups[2].Success) { return(false); } var contentPosition = statement.Start + match.Groups[2].Index; var contentEnd = contentPosition + match.Groups[2].Length; var specifiersSpan = new SnapshotSpan(contentPosition, contentEnd); var macro = (UE4Macros)Enum.Parse(typeof(UE4Macros), match.Groups[1].Value.ToUpper()); ue4MacroStatement = new UE4MacroStatement(specifiersSpan, macro); return(true); }
public void AugmentQuickInfoSession(IQuickInfoSession session, IList <object> qiContent, out ITrackingSpan applicableToSpan) { // Map the trigger point down to our buffer. SnapshotPoint?subjectTriggerPoint = session.GetTriggerPoint(_mSubjectBuffer.CurrentSnapshot); if (!subjectTriggerPoint.HasValue) { applicableToSpan = null; return; } ITextSnapshot currentSnapshot = subjectTriggerPoint.Value.Snapshot; //look for occurrences of our QuickInfo words in the span ITextStructureNavigator navigator = _mProvider.NavigatorService.GetTextStructureNavigator(_mSubjectBuffer); TextExtent extent = navigator.GetExtentOfWord(subjectTriggerPoint.Value); if (extent.IsSignificant) { var tt1 = navigator.GetSpanOfNextSibling(extent.Span); var tt2 = navigator.GetSpanOfFirstChild(extent.Span); var tt3 = navigator.GetSpanOfPreviousSibling(extent.Span); var tt4 = navigator.GetSpanOfEnclosing(extent.Span); var t1 = tt1.GetText(); var t2 = tt2.GetText(); var t3 = tt3.GetText(); } string searchText = extent.Span.GetText(); foreach (string key in _mDictionary.Keys) { int foundIndex = searchText.IndexOf(key, StringComparison.CurrentCultureIgnoreCase); if (foundIndex > -1) { applicableToSpan = currentSnapshot.CreateTrackingSpan ( //querySpan.Start.Add(foundIndex).Position, 9, SpanTrackingMode.EdgeInclusive extent.Span.Start + foundIndex, key.Length, SpanTrackingMode.EdgeInclusive ); string value; _mDictionary.TryGetValue(key, out value); qiContent.Add(value ?? ""); return; } } applicableToSpan = null; }
private UE4Statement TrackUE4MacroSpecifier(SnapshotPoint triggerPoint, out bool inMeta) { SnapshotPoint currentPoint = triggerPoint - 1; ITextStructureNavigator navigator = m_sourceProvider.NavigatorService.GetTextStructureNavigator(m_textBuffer); TextExtent extent = navigator.GetExtentOfWord(currentPoint); SnapshotSpan statement = navigator.GetSpanOfEnclosing(extent.Span); var statementText = statement.GetText(); inMeta = false; var macros = typeof(UE4Macros).GetEnumNames().Aggregate("", (a, e) => a += "|" + e); var match = Regex.Match(statementText, $@"({macros})\((.*)\)", RegexOptions.IgnoreCase); if (!match.Success) { return(null); } if (!match.Groups[1].Success || !match.Groups[2].Success) { return(null); } var contentPosition = statement.Start + match.Groups[2].Index; var contentEnd = contentPosition + match.Groups[2].Length; if (extent.Span.Start < contentPosition || extent.Span.End > contentEnd) { return(null); } var macroConst = (UE4Macros)Enum.Parse(typeof(UE4Macros), match.Groups[1].Value.ToUpper()); List <string> specifiersList; List <string> metaList; ParseSpecifiers(match.Groups[2].Value, extent, contentPosition, out inMeta, out specifiersList, out metaList); return(new UE4Statement { MacroConst = macroConst, Specifiers = specifiersList.ToArray(), MetaSpecifiers = metaList.ToArray() }); }
public static int?GetSubwordBoundary(this ITextStructureNavigator navigator, SnapshotPoint point, bool forward) { var wordSpan = navigator.GetExtentOfWord(point).Span; wordSpan = new SnapshotSpan(navigator.GetSpanOfPreviousSibling(wordSpan).Start, navigator.GetSpanOfNextSibling(wordSpan).End); if (wordSpan.Length == 0) { return(null); } int step = forward ? 1 : -1; SnapshotSpan wordSpanPrev; do { var word = wordSpan.GetText(); int i = point.Position - wordSpan.Start; while (0 < i && i < word.Length) { if (IsSubwordBoundary(word, i, forward)) { return(wordSpan.Start + i); } i += step; } point = wordSpan.Start + i; wordSpanPrev = wordSpan; wordSpan = navigator.GetSpanOfEnclosing(wordSpan); } while (wordSpan != wordSpanPrev); return(null); }
public SnapshotSpan GetSpanOfEnclosing(SnapshotSpan activeSpan) { return(_delegateNavigator.GetSpanOfEnclosing(activeSpan)); }
public SnapshotSpan GetSpanOfEnclosing(SnapshotSpan activeSpan) { return(_plainTextNavigator.GetSpanOfEnclosing(activeSpan)); }
private ReadOnlyCollection <ITagSpan <IntraTextAdornmentTag> > GetTagsCore(SnapshotSpan span) { var list = new List <ITagSpan <IntraTextAdornmentTag> >(); var offset = span.Start.Position; var snapshot = span.Snapshot; // vars used in loop SnapshotSpan cbSpan; CBAdornmentData cbAdornmentData; CBETagControl tagElement; int cbStartPosition; int cbEndPosition; int cbHeaderPosition; string cbHeader; IntraTextAdornmentTag cbTag; SnapshotSpan cbSnapshotSpan; TagSpan <IntraTextAdornmentTag> cbTagSpan; bool isSingleLineComment = false; bool isMultiLineComment = false; #if DEBUG // Stop time if (watch == null) { watch = new System.Diagnostics.Stopwatch(); } watch.Restart(); #endif try { // Find all closing bracets for (int i = 0; i < span.Length; i++) { var position = i + offset; var chr = snapshot[position]; // Skip comments switch (chr) { case '/': if (position > 0) { if (snapshot[position - 1] == '/') { isSingleLineComment = true; } if (snapshot[position - 1] == '*') { if (!isMultiLineComment) { // Multiline comment was not started in this span // Every tag until now was inside a comment foreach (var tag in list) { RemoveFromCache((tag.Tag.Adornment as CBETagControl).AdornmentData); } list.Clear(); } isMultiLineComment = false; } } break; case '*': if (position > 0 && snapshot[position - 1] == '/') { isMultiLineComment = true; } break; case (char)10: isSingleLineComment = false; break; case (char)13: isSingleLineComment = false; break; } if (chr != '}' || isSingleLineComment || isMultiLineComment) { continue; } // getting start and end position of code block cbEndPosition = position; if (position >= 0 && snapshot[position - 1] == '{') { // empty code block {} cbStartPosition = position - 1; cbSpan = new SnapshotSpan(snapshot, cbStartPosition, cbEndPosition - cbStartPosition); } else { // create inner span to navigate to get code block start cbSpan = _TextStructureNavigator.GetSpanOfEnclosing(new SnapshotSpan(snapshot, position - 1, 1)); cbStartPosition = cbSpan.Start; } // Don't display tag for code blocks on same line if (!snapshot.GetText(cbSpan).Contains('\n')) { continue; } // getting the code blocks header cbHeaderPosition = -1; if (snapshot[cbStartPosition] == '{') { // cbSpan does not contain the header cbHeader = GetCodeBlockHeader(cbSpan, out cbHeaderPosition); } else { // cbSpan does contain the header cbHeader = GetCodeBlockHeader(cbSpan, out cbHeaderPosition, position); } // Trim header if (cbHeader != null && cbHeader.Length > 0) { cbHeader = cbHeader.Trim() .Replace(Environment.NewLine, "") .Replace('\t', ' '); // Strip unnecessary spaces while (cbHeader.Contains(" ")) { cbHeader = cbHeader.Replace(" ", " "); } } // Skip tag if option "only when header not visible" if (_VisibleSpan != null && !IsTagVisible(cbHeaderPosition, cbEndPosition, _VisibleSpan, snapshot)) { continue; } var iconMoniker = Microsoft.VisualStudio.Imaging.KnownMonikers.QuestionMark; if (CBETagPackage.CBEDisplayMode != (int)CBEOptionPage.DisplayModes.Text && !string.IsNullOrWhiteSpace(cbHeader) && !cbHeader.Contains("{")) { iconMoniker = IconMonikerSelector.SelectMoniker(cbHeader); } // use cache or create new tag cbAdornmentData = _adornmentCache .Where(o => o.StartPosition == cbStartPosition && o.EndPosition == cbEndPosition) .FirstOrDefault(); if (cbAdornmentData?.Adornment != null) { tagElement = cbAdornmentData.Adornment as CBETagControl; } else { // create new adornment tagElement = new CBETagControl() { Text = cbHeader, IconMoniker = iconMoniker, DisplayMode = CBETagPackage.CBEDisplayMode }; tagElement.TagClicked += Adornment_TagClicked; cbAdornmentData = new CBAdornmentData(cbStartPosition, cbEndPosition, cbHeaderPosition, tagElement); tagElement.AdornmentData = cbAdornmentData; _adornmentCache.Add(cbAdornmentData); } tagElement.LineHeight = _FontSize * CBETagPackage.CBETagScale; // Add new tag to list cbTag = new IntraTextAdornmentTag(tagElement, null); cbSnapshotSpan = new SnapshotSpan(snapshot, position + 1, 0); cbTagSpan = new TagSpan <IntraTextAdornmentTag>(cbSnapshotSpan, cbTag); list.Add(cbTagSpan); } } catch (NullReferenceException) { // May happen, when closing a text editor } #if DEBUG watch.Stop(); if (watch.Elapsed.Milliseconds > 100) { System.Diagnostics.Debug.WriteLine("Time elapsed: " + watch.Elapsed + " on Thread: " + System.Threading.Thread.CurrentThread.ManagedThreadId + " in Span: " + span.Start.Position + ":" + span.End.Position + " length: " + span.Length); } #endif return(new ReadOnlyCollection <ITagSpan <IntraTextAdornmentTag> >(list)); }
public SnapshotSpan GetSpanOfEnclosing(SnapshotSpan activeSpan) { if (!XmlBackgroundParser.TryGetParser(activeSpan.Snapshot.TextBuffer, out var parser)) { return(xmlNavigator.GetSpanOfEnclosing(activeSpan)); } // use last parse if it's up to date, which is most likely will be // else use a spine from the end of the selection and update as needed var lastParse = parser.LastOutput; List <XObject> nodePath; XmlSpineParser spine = null; if (lastParse != null && lastParse.TextSnapshot.Version.VersionNumber == activeSpan.Snapshot.Version.VersionNumber) { var n = lastParse.XDocument.FindAtOrBeforeOffset(activeSpan.Start.Position); nodePath = n.GetPath(); } else { spine = parser.GetSpineParser(activeSpan.Start); nodePath = spine.AdvanceToNodeEndAndGetNodePath(activeSpan.Snapshot); } if (nodePath.Count > 0) { var leaf = nodePath[nodePath.Count - 1]; if (leaf is XAttribute || leaf is XText) { var syntax = MSBuildElementSyntax.Get(nodePath); if (syntax != null) { int offset; string text; bool isCondition = false; if (leaf is XText t) { offset = t.Span.Start; text = t.Text; } else { var att = (XAttribute)leaf; offset = att.ValueOffset; text = att.Value; isCondition = true; } var expr = isCondition ? ExpressionParser.ParseCondition(text, offset) : ExpressionParser.Parse(text, ExpressionOptions.ItemsMetadataAndLists, offset); var expansion = Expand(activeSpan, expr, out var isText); if (expansion is SnapshotSpan expandedSpan) { if (isText) { var xmlNavigatorSpan = xmlNavigator.GetSpanOfEnclosing(activeSpan); if (expandedSpan.Contains(xmlNavigatorSpan)) { return(xmlNavigatorSpan); } } return(expandedSpan); } } } } return(xmlNavigator.GetSpanOfEnclosing(activeSpan)); }
private ReadOnlyCollection <ITagSpan <IntraTextAdornmentTag> > GetTagsCore(SnapshotSpan span) { var list = new List <ITagSpan <IntraTextAdornmentTag> >(); var offset = span.Start.Position; var snapshot = span.Snapshot; // vars used in loop var isSingleLineComment = false; var isMultiLineComment = false; // Find all closing bracets for (int i = 0; i < span.Length; i++) { var position = i + offset; // Skip comments switch (snapshot[position]) { case '/': if (position > 0) { if (snapshot[position - 1] == '/') { isSingleLineComment = true; } if (snapshot[position - 1] == '*') { if (!isMultiLineComment) { // Multiline comment was not started in this span // Every tag until now was inside a comment foreach (var tag in list) { RemoveFromCache((tag.Tag.Adornment as CBETagControl).AdornmentData); } list.Clear(); } isMultiLineComment = false; } } break; case '*': if (position > 0 && snapshot[position - 1] == '/') { isMultiLineComment = true; } break; case '\n': case '\r': isSingleLineComment = false; break; } if (snapshot[position] != '}' || isSingleLineComment || isMultiLineComment) { continue; } SnapshotSpan cbSpan; int cbStartPosition; // getting start and end position of code block var cbEndPosition = position; if (position >= 0 && snapshot[position - 1] == '{') { // empty code block {} cbStartPosition = position - 1; cbSpan = new SnapshotSpan(snapshot, position - 1, 1); } else { // create inner span to navigate to get code block start cbSpan = _TextStructureNavigator.GetSpanOfEnclosing(new SnapshotSpan(snapshot, position - 1, 1)); cbStartPosition = cbSpan.Start; } // Don't display tag for code blocks on same line if (!snapshot.GetText(cbSpan).Contains('\n')) { continue; } // getting the code blocks header var cbHeaderPosition = -1; string cbHeader; if (snapshot[cbStartPosition] == '{') { // cbSpan does not contain the header cbHeader = GetCodeBlockHeader(cbSpan, out cbHeaderPosition); } else { // cbSpan does contain the header cbHeader = GetCodeBlockHeader(cbSpan, out cbHeaderPosition, position); } // Trim header if (cbHeader != null && cbHeader.Length > 0) { cbHeader = cbHeader.Trim() .Replace(Environment.NewLine, "") .Replace('\t', ' '); // Strip unnecessary spaces while (cbHeader.Contains(" ")) { cbHeader = cbHeader.Replace(" ", " "); } } // Skip tag if option "only when header not visible" if (_VisibleSpan != null && !IsTagVisible(cbHeaderPosition, cbEndPosition, _VisibleSpan, snapshot)) { continue; } var iconMoniker = Microsoft.VisualStudio.Imaging.KnownMonikers.QuestionMark; if (CBETagPackage.CBEDisplayMode != (int)CBEOptionPage.DisplayModes.Text && !string.IsNullOrWhiteSpace(cbHeader) && !cbHeader.Contains("{")) { iconMoniker = IconMonikerSelector.SelectMoniker(cbHeader); } // use cache or create new tag var cbAdornmentData = _adornmentCache .Find(x => x.StartPosition == cbStartPosition && x.EndPosition == cbEndPosition); CBETagControl tagElement; if (cbAdornmentData?.Adornment != null) { tagElement = cbAdornmentData.Adornment as CBETagControl; } else { // create new adornment tagElement = new CBETagControl() { Text = cbHeader, IconMoniker = iconMoniker, DisplayMode = CBETagPackage.CBEDisplayMode }; tagElement.TagClicked += Adornment_TagClicked; cbAdornmentData = new CBAdornmentData(cbStartPosition, cbEndPosition, cbHeaderPosition, tagElement); tagElement.AdornmentData = cbAdornmentData; _adornmentCache.Add(cbAdornmentData); } tagElement.LineHeight = _FontSize * CBETagPackage.CBETagScale; // Add new tag to list var cbTag = new IntraTextAdornmentTag(tagElement, null); var cbSnapshotSpan = new SnapshotSpan(snapshot, position + 1, 0); var cbTagSpan = new TagSpan <IntraTextAdornmentTag>(cbSnapshotSpan, cbTag); list.Add(cbTagSpan); } return(new ReadOnlyCollection <ITagSpan <IntraTextAdornmentTag> >(list)); }
public void AugmentQuickInfoSession(IQuickInfoSession session, IList <object> qiContent, out ITrackingSpan applicableToSpan) { // Map the trigger point down to our buffer. SnapshotPoint?subjectTriggerPoint = session.GetTriggerPoint(this.subjectBuffer.CurrentSnapshot); if (!subjectTriggerPoint.HasValue) { applicableToSpan = null; return; } ITextSnapshot currentSnapshot = subjectTriggerPoint.Value.Snapshot; SnapshotSpan querySpan = new SnapshotSpan(subjectTriggerPoint.Value, 0); //look for occurrences of our QuickInfo words in the span ITextStructureNavigator navigator = this.provider.NavigatorService.GetTextStructureNavigator(this.subjectBuffer); var extent = navigator.GetSpanOfEnclosing(new SnapshotSpan(this.subjectBuffer.CurrentSnapshot, querySpan)); string searchText = extent.GetText()?.Trim('"'); Guid parsedId; var allFiles = Rainbow.Repository.rainbowFiles.Values.ToList(); if (Guid.TryParse(searchText, out parsedId)) { var file = allFiles.FirstOrDefault(f => f != null && parsedId.Equals(f.Id)); if (file != null) { applicableToSpan = currentSnapshot.CreateTrackingSpan ( extent.Span.Start, file.Id.ToString().Length, SpanTrackingMode.EdgeInclusive ); try { qiContent.Add($"Sitecore path: {file.Path}"); } catch (InvalidOperationException ex) { // The collection may be modified, so we can't add anything here right now Debug.Write($"Exception occurred when trying to add path {file.Path} (skipping as it is not essential): {ex.Message}"); } return; } } else { foreach (var file in allFiles.Where(f => f != null && f.Id != Guid.Empty && f.Path != null).OrderByDescending(f => f.Path)) { int foundIndex = searchText.IndexOf(file.Path, StringComparison.CurrentCultureIgnoreCase); if (foundIndex > -1) { applicableToSpan = currentSnapshot.CreateTrackingSpan ( extent.Span.Start + foundIndex, file.Id.ToString().Length, SpanTrackingMode.EdgeInclusive ); try { qiContent.Add($"Sitecore ID: {{{file.Id}}}"); } catch (InvalidOperationException ex) { // The collection may be modified, so we can't add anything here right now Debug.Write($"Exception occurred when trying to add ID {file.Id} (skipping as it is not essential): {ex.Message}"); } return; } } } applicableToSpan = null; }
void IQuickInfoSource.AugmentQuickInfoSession(IQuickInfoSession session, IList <object> quickInfoContent, out ITrackingSpan applicableToSpan) { // Map the trigger point down to our buffer. SnapshotPoint?subjectTriggerPoint = session.GetTriggerPoint(m_subjectBuffer.CurrentSnapshot); if (!subjectTriggerPoint.HasValue) { applicableToSpan = null; return; } ITextSnapshot currentSnapshot = subjectTriggerPoint.Value.Snapshot; SnapshotSpan querySpan = new SnapshotSpan(subjectTriggerPoint.Value, 0); //look for occurrences of our QuickInfo words in the span ITextStructureNavigator navigator = m_provider.NavigatorService.GetTextStructureNavigator(m_subjectBuffer); TextExtent extent = navigator.GetExtentOfWord(subjectTriggerPoint.Value); string searchText = extent.Span.GetText(); if (searchText.Length < 2)//一般都是一个符号 { applicableToSpan = null; return; } SnapshotSpan ssPrevious = navigator.GetSpanOfPreviousSibling(extent.Span); SnapshotSpan ssEnclosing = navigator.GetSpanOfEnclosing(extent.Span); string strPreText = ssPrevious.GetText(); string strEnclosing = ssEnclosing.GetText(); string desText, strCtrlName; if (strPreText == "<" || strPreText == "</" || strEnclosing.StartsWith("</"))//控件名 { SouiData.GetInstance().GetKeyInf(searchText, out desText, currentSnapshot, out applicableToSpan, querySpan); if (desText != null) { quickInfoContent.Add(desText); } else { applicableToSpan = null; } return; } else if (strPreText == "=\"")//属性值 { applicableToSpan = null; return; } //属性名 else if (strEnclosing.StartsWith("<")) { strCtrlName = navigator.GetExtentOfWord(ssEnclosing.Start + 1).Span.GetText(); if (strCtrlName == null || strCtrlName.Length == 0) { applicableToSpan = null; return; } SouiData.GetInstance().GetProInf(strCtrlName, searchText, out desText, currentSnapshot, out applicableToSpan, querySpan); if (desText != null) { quickInfoContent.Add(desText); return; } } else if (strPreText.StartsWith("<")) { strCtrlName = navigator.GetExtentOfWord(ssPrevious.Start + 1).Span.GetText(); if (strCtrlName == null || strCtrlName.Length == 0) { applicableToSpan = null; return; } SouiData.GetInstance().GetProInf(strCtrlName, searchText, out desText, currentSnapshot, out applicableToSpan, querySpan); if (desText != null) { quickInfoContent.Add(desText); return; } } strCtrlName = strPreText; while (ssPrevious.Start > 0) { if (strPreText == "<") { SouiData.GetInstance().GetProInf(strCtrlName, searchText, out desText, currentSnapshot, out applicableToSpan, querySpan); if (desText != null) { quickInfoContent.Add(desText); return; } break; } strCtrlName = strPreText; ssPrevious = navigator.GetExtentOfWord(ssPrevious.Start - 1).Span; strPreText = ssPrevious.GetText(); } applicableToSpan = null; }