private void loadTypeCombos(int nLine) { _types.Clear(); var sortItems = XSettings.EditorNavigationSorted; XDropDownMember elt; int nSelect = 0; DROPDOWNFONTATTR ft; List <XSourceTypeSymbol> xList = _file.TypeList.Values.ToList <XSourceTypeSymbol>(); if (sortItems) { xList.Sort(delegate(XSourceTypeSymbol elt1, XSourceTypeSymbol elt2) { return(elt1.FullName.CompareTo(elt2.FullName)); }); } if (xList.Count == 0) { xList.Add(_file.GlobalType); } foreach (XSourceTypeSymbol eltType in xList) { if (eltType.Kind == Kind.Namespace) { continue; } // 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 = _types.Count; _types.Add(elt); if (eltType.Range.StartLine <= nLine && eltType.Range.EndLine >= nLine) { _selectedTypeIndex = nSelect; _lastType = eltType; } } return; }
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 package = XSharp.Project.XSharpProjectPackage.Instance; var optionsPage = package.GetIntellisenseOptionsPage(); 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; Source src = languageService.GetSource(textView); string srcFile = src.GetFilePath(); // XFile file = XSolution.FindFullPath(srcFile); if (file == null || file.TypeList == null) { return(false); } XElement selectedElement = file.FindMemberAtRow(line); if (selectedElement == _lastSelected) { // 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) XElement parentType = null; if (selectedElement is XTypeMember) { parentType = selectedElement.Parent; } else if (selectedElement is XType) { parentType = selectedElement as XType; } 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; 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 XType; 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 <XType> xList = file.TypeList.Values.ToList <XType>(); if (sortItems) { xList.Sort(delegate(XType elt1, XType elt2) { return(elt1.Name.CompareTo(elt2.Name)); }); } XType typeGlobal = null; int nSelect = 0; XElement currentMember = null; XType currentType = null; if (selectedElement is XTypeMember) { currentMember = selectedElement as XTypeMember; currentType = ((XTypeMember)currentMember).Parent; } else if (selectedElement is XType) { currentType = selectedElement as XType; 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 (XType eltType in xList) { if (eltType.Kind == Kind.Namespace) { continue; } // if (XType.IsGlobalType(eltType)) { typeGlobal = eltType; } TextSpan sp = this.TextRangeToTextSpan(eltType.Range); ft = DROPDOWNFONTATTR.FONTATTR_PLAIN; string name = eltType.Name; if (string.IsNullOrEmpty(name)) { name = "?"; } elt = new XDropDownMember(name, sp, eltType.Glyph, ft); elt.Element = 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 <XElement>(); if (currentTypeOnly) { if (currentType != typeGlobal && currentType.IsPartial) { // retrieve members from other files ? var fullType = file.Project.Lookup(currentType.FullName, true); hasPartial = true; members.AddRange(fullType.Members); } else { members.AddRange(currentType.Members); } } 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 XType) { var xType = ent as XType; if (xType.IsPartial) { // load methods from other files var fullType = file.Project.Lookup(xType.FullName, true); hasPartial = true; foreach (var member in fullType.Members) { if (!members.Contains(member)) { 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); elt.Element = currentType; dropDownMembers.Add(elt); } } else { elt = new XDropDownMember(currentType.Name, spM, currentType.Glyph, ft); elt.Element = currentType; dropDownMembers.Add(elt); } } foreach (XElement 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 = member.File != file; } string prototype = member.ComboPrototype; if (!currentTypeOnly && member.Parent != null && member.Parent != typeGlobal) { if (member.Modifiers.HasFlag(Modifiers.Static)) { prototype = member.Parent.Name + "." + prototype; } else { prototype = member.Parent.Name + ":" + prototype; } } if (otherFile) { ft = DROPDOWNFONTATTR.FONTATTR_GRAY; prototype += " (" + System.IO.Path.GetFileName(member.File.SourcePath) + ")"; } elt = new XDropDownMember(prototype, spM, member.Glyph, ft); nSelect = dropDownMembers.Add(elt); elt.Element = member; if (member == currentMember) { 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); }
private void loadMemberCombos(int selectedType, int nLine) { var sortItems = XSettings.EditorNavigationSorted; var includeFields = XSettings.EditorNavigationIncludeFields; var currentTypeOnly = XSettings.EditorNavigationMembersOfCurrentTypeOnly; if (selectedType >= _types.Count) { return; } var currentType = (XSourceTypeSymbol)(selectedType > -1 ? _types[selectedType].Entity : _types[0].Entity); var globalType = _file.GlobalType; DROPDOWNFONTATTR ft; bool hasPartial = !currentType.IsGlobal && currentType.IsPartial; _members.Clear(); _relatedFiles.Clear(); AddSourceFile(_file.SourcePath); var members = new List <XSourceEntity>(); if (currentTypeOnly) { members.AddRange(GetTypeMembers(currentType)); } else { // get members of types in this file and members of partial types in other files. members.AddRange(GetAllMembers()); } if (sortItems) { members = members.OrderBy(x => x.FullName).ToList(); } // now either load all members or just the members of the current type // 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; XDropDownMember elt; if (currentTypeOnly) { // Add a 'root' element for the type. if (currentType != globalType) { if (currentType.Kind != Kind.Delegate) { elt = new XDropDownMember("(" + currentType.Name + ")", spM, currentType.Glyph, ft, currentType); _members.Add(elt); } } else { elt = new XDropDownMember(currentType.Name, spM, currentType.Glyph, ft, currentType); _members.Add(elt); } } foreach (XSourceEntity 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 (member.Parent is XSourceTypeSymbol typedef && typedef.IsPartial) { otherFile = string.Compare(member.File.FullPath, _file.FullPath, true) != 0; } string prototype = member.ComboPrototype; bool addPrefix = false; if (currentTypeOnly) { addPrefix = false; } else { if (member.Parent is XSourceEntity && member.Parent.Name != XLiterals.GlobalName && member.Kind.IsClassMember(_file.Project.Dialect)) { addPrefix = true; } } if (addPrefix) { var parent = member.Parent as XSourceEntity; if (member.Modifiers.HasFlag(Modifiers.Static) || member is XSourceTypeSymbol) { prototype = parent.ComboPrototype + "." + prototype; } else { prototype = parent.ComboPrototype + ":" + prototype; } } if (member.Kind.IsLocal()) { prototype = member.Parent.Name + "." + prototype; } if (otherFile) { AddSourceFile(member.File.SourcePath); ft = DROPDOWNFONTATTR.FONTATTR_GRAY; prototype += " (" + System.IO.Path.GetFileName(member.File.SourcePath) + ")"; } elt = new XDropDownMember(prototype, spM, member.Glyph, ft, member); var nSelect = _members.Count; _members.Add(elt); if (member.Range.ContainsInclusive(nLine, 0)) { _selectedMemberIndex = nSelect; _lastSelected = member; } } } }