public void AugmentPeekSession(IPeekSession session, IList <IPeekableItem> peekableItems) { try { XSharpModel.ModelWalker.Suspend(); if (!string.Equals(session.RelationshipName, PredefinedPeekRelationships.Definitions.Name, StringComparison.OrdinalIgnoreCase)) { return; } // var tp = session.GetTriggerPoint(_textBuffer.CurrentSnapshot); if (!tp.HasValue) { return; } // var triggerPoint = tp.Value; IToken stopToken; // // Check if we can get the member where we are XMemberDefinition member = XSharpLanguage.XSharpTokenTools.FindMember(triggerPoint.GetContainingLine().LineNumber, _file); XTypeDefinition currentNamespace = XSharpLanguage.XSharpTokenTools.FindNamespace(triggerPoint.Position, _file); var lineNumber = triggerPoint.GetContainingLine().LineNumber; var snapshot = _textBuffer.CurrentSnapshot; List <String> tokenList = XSharpTokenTools.GetTokenList(triggerPoint.Position, lineNumber, snapshot, out stopToken, true, _file, false, member); // LookUp for the BaseType, reading the TokenList (From left to right) CompletionElement gotoElement; String currentNS = ""; if (currentNamespace != null) { currentNS = currentNamespace.Name; } CompletionType cType = XSharpLanguage.XSharpTokenTools.RetrieveType(_file, tokenList, member, currentNS, stopToken, out gotoElement, snapshot, lineNumber, _file.Project.Dialect); // if ((gotoElement != null) && (gotoElement.IsSourceElement)) { peekableItems.Add(new XSharpDefinitionPeekItem(gotoElement.SourceElement, _peekResultFactory)); } } catch (Exception ex) { XSettings.DisplayOutputMessage("XSharpPeekItemSource.AugmentPeekSession failed : "); XSettings.DisplayException(ex); } finally { ModelWalker.Resume(); } }
public override bool OnSynchronizeDropdowns( Microsoft.VisualStudio.Package.LanguageService languageService, IVsTextView textView, int line, int col, ArrayList dropDownTypes, ArrayList dropDownMembers, ref int selectedType, ref int selectedMember) { // var sortItems = _optionsPage.SortNavigationBars; var includeFields = _optionsPage.IncludeFieldsInNavigationBars; var currentTypeOnly = _optionsPage.ShowMembersOfCurrentTypeOnly; if (_optionsPage.DisableEditorDropdowns) { dropDownTypes.Clear(); dropDownMembers.Clear(); selectedType = selectedMember = -1; return(true); } // when the line did not change, we do nothing for performance reasons // this speeds up typing for buffers with lots of entities if (line == lastLine) { // same line, no changes return(false); } lastLine = line; IVsTextLines buffer; textView.GetBuffer(out buffer); var file = _lang.getFile(buffer); if (file == null || file.TypeList == null) { return(false); } XEntityDefinition selectedElement = file.FindMemberAtRow(line); if (selectedElement != null && selectedElement.Range.StartLine > line) { // we may be before the first element. THen rebuild the list selectedElement = null; } else if (selectedElement == _lastSelected && selectedElement != null) { // Same element, no changes return(false); } // check if we are on the same type. When not then we need to reload the members. // Note that the first item in the members combo can also be a type (Classname) XTypeDefinition parentType = null; if (selectedElement is XMemberDefinition) { parentType = (XTypeDefinition)selectedElement.Parent; } else if (selectedElement is XTypeDefinition) { parentType = selectedElement as XTypeDefinition; } else { parentType = file.GlobalType; } bool newType = true; if (parentType != null && _lastType != null && parentType.FullName == _lastType.FullName) { newType = false; } // when we are on the same type and there are no new methods then we can // select the element in the members combo and we do not have to rebuild the members // list. We must set the selectedType and selectedMember if (!newType && file.ContentHashCode == _lastHashCode && lastIncludeFields == includeFields && lastCurrentTypeOnly == currentTypeOnly) { // no need to rebuild the list. Just focus to another element // locate item in members collection selectedMember = -1; selectedType = -1; if (selectedElement != null) { for (int i = 0; i < dropDownMembers.Count; i++) { var member = (XDropDownMember)dropDownMembers[i]; if (member.Element.ComboPrototype == selectedElement.ComboPrototype) { selectedMember = i; break; } } } // find the parentType in the types combo if (selectedMember != -1 && parentType != null) // should never be null { for (int i = 0; i < dropDownTypes.Count; i++) { var member = (XDropDownMember)dropDownTypes[i]; var type = member.Element as XTypeDefinition; if (type.FullName == parentType.FullName) { selectedType = i; break; } } } // normally we should always find it. But if it fails then we simply build the list below. if (selectedMember != -1 && selectedType != -1) { // remember for later. No need to remember the type because it has not changed _lastSelected = selectedElement; return(true); } } dropDownTypes.Clear(); dropDownMembers.Clear(); int nSelType = -1; int nSelMbr = -1; //int distanceM = int.MaxValue; DROPDOWNFONTATTR ft; // // if (file.TypeList.Count > 0) { nSelType = 0; } List <XTypeDefinition> xList = file.TypeList.Values.ToList <XTypeDefinition>(); if (sortItems) { xList.Sort(delegate(XTypeDefinition elt1, XTypeDefinition elt2) { return(elt1.FullName.CompareTo(elt2.FullName)); }); } XTypeDefinition typeGlobal = null; int nSelect = 0; XMemberDefinition currentMember = null; XTypeDefinition currentType = null; if (selectedElement is XMemberDefinition) { currentMember = selectedElement as XMemberDefinition; currentType = (XTypeDefinition)currentMember.Parent; } else if (selectedElement is XTypeDefinition) { currentType = selectedElement as XTypeDefinition; currentMember = null; } nSelect = 0; XDropDownMember elt; // C# shows all items PLAIN // but when the selection is not really on an item, but for example on a comment // between methods, or on the comments between the namespace and the first class // then the next method/class is selected and displayed in GRAY // C# also includes members (for partial classes) that are defined in other source files // these are colored GRAY foreach (XTypeDefinition eltType in xList) { if (eltType.Kind == Kind.Namespace) { continue; } // if (XTypeDefinition.IsGlobalType(eltType)) { typeGlobal = eltType; } TextSpan sp = this.TextRangeToTextSpan(eltType.Range); ft = DROPDOWNFONTATTR.FONTATTR_PLAIN; string name = eltType.FullName; if (string.IsNullOrEmpty(name)) { name = "?"; } elt = new XDropDownMember(name, sp, eltType.Glyph, ft, eltType); nSelect = dropDownTypes.Add(elt); if (eltType?.FullName == currentType?.FullName) { nSelType = nSelect; } } if (currentType == null) { currentType = typeGlobal; } bool hasPartial = false; if (currentType != null) // should not happen since all files have a global type { nSelMbr = 0; var members = new List <XEntityDefinition>(); if (currentTypeOnly) { if (currentType != typeGlobal && currentType.IsPartial) { // retrieve members from other files ? var usings = new List <string>(); usings.Add(currentType.Namespace); var fullType = file.Project.Lookup(currentType.Name, usings); hasPartial = true; members.AddRange(fullType.XMembers); } else { members.AddRange(currentType.XMembers); foreach (XTypeDefinition child in currentType.Children) { members.Add(child); members.AddRange(child.XMembers); } } } else { members.AddRange(file.EntityList.Where(member => includeFields || (member.Kind != Kind.Field && member.Kind != Kind.VODefine))); foreach (var ent in file.EntityList) { if (ent is XTypeDefinition) { var xType = ent as XTypeDefinition; if (xType.IsPartial) { // load methods from other files var usings = new List <string>(); usings.Add(xType.Namespace); var fullType = file.Project.Lookup(xType.Name, usings); hasPartial = true; foreach (var member in fullType.XMembers) { if (string.Compare(member.File.FullPath, file.FullPath, true) != 0) { if (includeFields || (member.Kind != Kind.Field && member.Kind != Kind.VODefine)) { members.Add(member); } } } } } } } if (sortItems) { members = members.OrderBy(x => x.FullName).ToList(); } // Add member for class declaration. This also makes sure that there at least one // element in the members list, which is convenient. TextSpan spM = this.TextRangeToTextSpan(currentType.Range); ft = DROPDOWNFONTATTR.FONTATTR_PLAIN; if (currentTypeOnly) { // Add a 'root' element for the type. if (currentType != typeGlobal) { if (currentType.Kind != Kind.Delegate) { elt = new XDropDownMember("(" + currentType.Name + ")", spM, currentType.Glyph, ft, currentType); dropDownMembers.Add(elt); } } else { elt = new XDropDownMember(currentType.Name, spM, currentType.Glyph, ft, currentType); dropDownMembers.Add(elt); } } foreach (XEntityDefinition member in members) { bool otherFile; if (includeFields || (member.Kind != Kind.Field && member.Kind != Kind.VODefine)) { spM = this.TextRangeToTextSpan(member.Range); otherFile = false; ft = DROPDOWNFONTATTR.FONTATTR_PLAIN; if (hasPartial) { otherFile = string.Compare(member.File.FullPath, file.FullPath, true) != 0; } string prototype = member.ComboPrototype; bool addPrefix = false; if (currentTypeOnly) { if (member.Parent != currentType && member.Kind.IsClassMember(file.Project.Dialect)) { addPrefix = true; } } else { if (member.Parent is XEntityDefinition && member.Parent.Name != XLiterals.GlobalName && member.Kind.IsClassMember(file.Project.Dialect)) { addPrefix = true; } } if (addPrefix) { var parent = member.Parent as XEntityDefinition; if (member.Modifiers.HasFlag(Modifiers.Static) || member is XTypeDefinition) { prototype = parent.ComboPrototype + "." + prototype; } else { prototype = parent.ComboPrototype + ":" + prototype; } } if (otherFile) { ft = DROPDOWNFONTATTR.FONTATTR_GRAY; prototype += " (" + System.IO.Path.GetFileName(member.File.SourcePath) + ")"; } elt = new XDropDownMember(prototype, spM, member.Glyph, ft, member); nSelect = dropDownMembers.Add(elt); if (member.Range.ContainsInclusive(line, col)) { nSelMbr = nSelect; } } } } // save the info so we can optimize the next call. _members = dropDownMembers; _file = file; _lastSelected = selectedElement; _lastType = currentType; _lastHashCode = file.ContentHashCode; selectedType = nSelType; selectedMember = nSelMbr; lastIncludeFields = includeFields; lastCurrentTypeOnly = currentTypeOnly; return(true); }
//static bool skipFirst = true; public void AugmentQuickInfoSession(IQuickInfoSession session, IList <object> qiContent, out ITrackingSpan applicableToSpan) { applicableToSpan = null; //if (skipFirst) //{ // skipFirst = false; // return; //} //else //{ // skipFirst = true; //} if (XSharpProjectPackage.Instance.DebuggerIsRunning) { return; } try { XSharpModel.ModelWalker.Suspend(); if (XSettings.DisableQuickInfo) { return; } // Map the trigger point down to our buffer. SnapshotPoint?subjectTriggerPoint = session.GetTriggerPoint(_subjectBuffer.CurrentSnapshot); if (!subjectTriggerPoint.HasValue) { return; } ITextSnapshot currentSnapshot = subjectTriggerPoint.Value.Snapshot; WriteOutputMessage($"Triggerpoint: {subjectTriggerPoint.Value.Position}"); if ((subjectTriggerPoint.Value.Position == lastTriggerPoint) && (lastVersion == currentSnapshot.Version.VersionNumber)) { if (lastHelp != null) { var description = new TextBlock(); description.Inlines.AddRange(lastHelp); qiContent.Add(description); if (lastxmldoc != null) { qiContent.Add(lastxmldoc); } WriteOutputMessage($"Return last help content: {lastHelp}"); } if (lastSpan != null) { applicableToSpan = lastSpan; } return; } // We don't want to lex the buffer. So get the tokens from the last lex run // and when these are too old, then simply bail out var tokens = _subjectBuffer.GetTokens(); if (tokens != null) { if (tokens.SnapShot.Version != currentSnapshot.Version) { return; } } lastTriggerPoint = subjectTriggerPoint.Value.Position; //look for occurrences of our QuickInfo words in the span ITextStructureNavigator navigator = _provider.NavigatorService.GetTextStructureNavigator(_subjectBuffer); TextExtent extent = navigator.GetExtentOfWord(subjectTriggerPoint.Value); string searchText = extent.Span.GetText(); // First, where are we ? int caretPos = subjectTriggerPoint.Value.Position; int lineNumber = subjectTriggerPoint.Value.GetContainingLine().LineNumber; var snapshot = session.TextView.TextBuffer.CurrentSnapshot; if (_file == null) { return; } // Then, the corresponding Type/Element if possible IToken stopToken; //ITokenStream tokenStream; XMemberDefinition member = XSharpLanguage.XSharpTokenTools.FindMember(lineNumber, _file); XTypeDefinition currentNamespace = XSharpLanguage.XSharpTokenTools.FindNamespace(caretPos, _file); // adjust caretpos, for other completions we need to stop before the caret. Now we include the caret List <String> tokenList = XSharpLanguage.XSharpTokenTools.GetTokenList(caretPos + 1, lineNumber, tokens.TokenStream, out stopToken, true, _file, false, member); // Check if we can get the member where we are //if (tokenList.Count > 1) //{ // tokenList.RemoveRange(0, tokenList.Count - 1); //} // LookUp for the BaseType, reading the TokenList (From left to right) XSharpLanguage.CompletionElement gotoElement; string currentNS = ""; if (currentNamespace != null) { currentNS = currentNamespace.Name; } XSharpModel.CompletionType cType = XSharpLanguage.XSharpTokenTools.RetrieveType(_file, tokenList, member, currentNS, stopToken, out gotoElement, snapshot, lineNumber, _file.Project.Dialect); // // if ((gotoElement != null) && (gotoElement.IsInitialized)) { IClassificationType kwType = _registry.GetClassificationType("keyword"); IClassificationFormatMap fmap = _formatMap.GetClassificationFormatMap(category: "text"); Microsoft.VisualStudio.Text.Formatting.TextFormattingRunProperties kwFormat = fmap.GetTextProperties(kwType); kwType = _registry.GetClassificationType("text"); fmap = _formatMap.GetClassificationFormatMap(category: "text"); Microsoft.VisualStudio.Text.Formatting.TextFormattingRunProperties txtFormat = fmap.GetTextProperties(kwType); // // Ok, find it ! Let's go ;) applicableToSpan = currentSnapshot.CreateTrackingSpan ( extent.Span.Start, searchText.Length, SpanTrackingMode.EdgeInclusive ); if (gotoElement.Result != null) { if (gotoElement.Result.Kind == Kind.Constructor) { if (gotoElement.Result.Parent != null) { var xtype = gotoElement.Result.Parent as IXType; var qitm = new QuickInfoTypeAnalysis(xtype, kwFormat.ForegroundBrush, txtFormat.ForegroundBrush); var description = new TextBlock(); description.Inlines.AddRange(qitm.WPFDescription); qiContent.Add(description); } } else if (gotoElement.Result is IXMember) { QuickInfoTypeMember qitm = new QuickInfoTypeMember((IXMember)gotoElement.Result, kwFormat.ForegroundBrush, txtFormat.ForegroundBrush); var description = new TextBlock(); description.Inlines.AddRange(qitm.WPFDescription); qiContent.Add(description); } else if (gotoElement.Result is IXVariable) { QuickInfoVariable qitm = new QuickInfoVariable((IXVariable)gotoElement.Result, kwFormat.ForegroundBrush, txtFormat.ForegroundBrush); var description = new TextBlock(); description.Inlines.AddRange(qitm.WPFDescription); qiContent.Add(description); } else if (gotoElement.Result is IXType) { var xtype = gotoElement.Result as IXType; var qitm = new QuickInfoTypeAnalysis(xtype, kwFormat.ForegroundBrush, txtFormat.ForegroundBrush); var description = new TextBlock(); description.Inlines.AddRange(qitm.WPFDescription); qiContent.Add(description); } else { var description = new TextBlock(); Run temp; temp = new Run(gotoElement.Result.Description); temp.Foreground = txtFormat.ForegroundBrush; // description.Inlines.Add(temp); qiContent.Add(description); } } if (qiContent.Count > 0) { TextBlock description; description = qiContent[0] as TextBlock; if (qiContent.Count > 1) { lastxmldoc = qiContent[1] as String; } else { lastxmldoc = null; } if (description != null) { lastHelp = new Inline[description.Inlines.Count]; description.Inlines.CopyTo(lastHelp, 0); lastSpan = applicableToSpan; lastVersion = currentSnapshot.Version.VersionNumber; WriteOutputMessage($"Found new help content: {description.Text}"); } } return; } } catch (Exception ex) { XSharpProjectPackage.Instance.DisplayOutPutMessage("XSharpQuickInfo.AugmentQuickInfoSession failed : "); XSharpProjectPackage.Instance.DisplayException(ex); } finally { XSharpModel.ModelWalker.Resume(); } }