//===================================================================== /// <summary> /// Search for members that match the search conditions /// </summary> /// <param name="sender">The sender of the event</param> /// <param name="e">The event arguments</param> private void btnFind_Click(object sender, EventArgs e) { ApiEntryType entryType; ApiVisibility visibility; ListViewItem lvi; string id, nodeText, subgroup; int pos, ignoreCase = Convert.ToInt32(!chkCaseSensitive.Checked), fullyQualified = Convert.ToInt32(chkFullyQualified.Checked); List<NodeInfo> nodeList; NodeInfo newNode; XPathNavigator subsubgroup; epErrors.Clear(); if(txtSearchText.Text.Trim().Length == 0) { epErrors.SetError(txtSearchText, "A search expression is required"); return; } try { Regex reSearch = new Regex(txtSearchText.Text); } catch(ArgumentException ex) { epErrors.SetError(txtSearchText, "The search regular " + "expression is not valid: " + ex.Message); return; } try { this.Cursor = Cursors.WaitCursor; btnGoto.Enabled = btnInclude.Enabled = btnExclude.Enabled = false; // Use the custom XPath function matches-regex to perform // a regular expression search for matching nodes. The // custom XPath function resolve-name is used to convert the // API names to their display format for the search. XPathFunctionContext context = new XPathFunctionContext(); XPathExpression expr = navigator.Compile(String.Format( CultureInfo.InvariantCulture, "api[matches-regex(" + "resolve-name(node(), boolean({0})), '{1}', boolean({2}))]", fullyQualified, txtSearchText.Text, ignoreCase)); // The first search uses the documented APIs expr.SetContext(context); lvSearchResults.Items.Clear(); nodeList = new List<NodeInfo>(); // The results are stored in the list view with each list // item's Tag property referencing the matching node. foreach(XPathNavigator nav in navigator.Select(expr)) { id = nav.GetAttribute("id", String.Empty); if(id[0] == 'N') { entryType = ApiEntryType.Namespace; visibility = ApiVisibility.Public; nodeText = id.Substring(2); } else { subsubgroup = nav.SelectSingleNode("apidata/@subsubgroup"); if(subsubgroup != null) subgroup = subsubgroup.Value; else subgroup = nav.SelectSingleNode("apidata/@subgroup").Value; entryType = NodeInfo.EntryTypeFromId(id[0], subgroup); visibility = NodeInfo.DetermineVisibility(id[0], ((IHasXmlNode)nav).GetNode()); pos = id.IndexOf('('); if(pos != -1) id = id.Substring(0, pos); pos = id.LastIndexOf('.'); if(pos != -1) nodeText = id.Substring(pos + 1); else nodeText = id.Substring(2); } // Only include the wanted items if(((CheckBox)pnlOptions.Controls[ (int)entryType + 1]).Checked && ((CheckBox)pnlOptions.Controls[ (int)visibility + 14]).Checked) { newNode = new NodeInfo(nodeText, id.Substring(2)); newNode.ApiNode = ((IHasXmlNode)nav).GetNode(); nodeList.Add(newNode); } } // Search inherited APIs as well. Namespaces first... expr = navigator.Compile(String.Format( CultureInfo.InvariantCulture, "api/elements/element/containers/namespace[matches-regex(" + "string(@api), '{0}', boolean({1}))]", txtSearchText.Text, ignoreCase)); expr.SetContext(context); foreach(XPathNavigator nav in navigator.Select(expr)) { id = nav.GetAttribute("api", String.Empty).Substring(2); // Only include the wanted items if(((CheckBox)pnlOptions.Controls[ (int)ApiEntryType.Namespace + 1]).Checked) { newNode = new NodeInfo(id, id); newNode.ApiNode = ((IHasXmlNode)nav).GetNode(); nodeList.Add(newNode); } } // ... then types ... expr = navigator.Compile(String.Format( CultureInfo.InvariantCulture, "api/elements/element/containers/type[matches-regex(" + "resolve-name(node(), boolean({0})), '{1}', boolean({2}))]", fullyQualified, txtSearchText.Text, ignoreCase)); expr.SetContext(context); foreach(XPathNavigator nav in navigator.Select(expr)) { id = nav.GetAttribute("api", String.Empty).Substring(2); pos = id.LastIndexOf('.'); if(pos != -1) nodeText = id.Substring(pos + 1); else nodeText = id; // Only include the wanted items. Since we can't tell the // actual API type, we'll assume Class for these. if(((CheckBox)pnlOptions.Controls[ (int)ApiEntryType.Class + 1]).Checked) { newNode = new NodeInfo(nodeText, id); newNode.ApiNode = ((IHasXmlNode)nav).GetNode(); nodeList.Add(newNode); } } // ... and then members. expr = navigator.Compile(String.Format( CultureInfo.InvariantCulture, "api/elements/element[matches-regex(resolve-name(" + "node(), boolean({0})), '{1}', boolean({2})) and containers]", fullyQualified, txtSearchText.Text, ignoreCase)); expr.SetContext(context); foreach(XPathNavigator nav in navigator.Select(expr)) if(nav.HasChildren) { id = nav.GetAttribute("api", String.Empty); if(id[0] == 'N') { entryType = ApiEntryType.Namespace; visibility = ApiVisibility.Public; nodeText = id; } else { subsubgroup = nav.SelectSingleNode("apidata/@subsubgroup"); if(subsubgroup != null) subgroup = subsubgroup.Value; else subgroup = nav.SelectSingleNode("apidata/@subgroup").Value; entryType = NodeInfo.EntryTypeFromId(id[0], subgroup); visibility = NodeInfo.DetermineVisibility(id[0], ((IHasXmlNode)nav).GetNode()); pos = id.IndexOf('('); if(pos != -1) id = id.Substring(0, pos); pos = id.LastIndexOf('.'); if(pos != -1) nodeText = id.Substring(pos + 1); else nodeText = id; } // Only include the wanted items if(((CheckBox)pnlOptions.Controls[ (int)entryType + 1]).Checked && ((CheckBox)pnlOptions.Controls[ (int)visibility + 14]).Checked) { newNode = new NodeInfo(nodeText, id.Substring(2)); newNode.ApiNode = ((IHasXmlNode)nav).GetNode(); nodeList.Add(newNode); } } if(nodeList.Count == 0) lvSearchResults.Items.Add(new ListViewItem( "Nothing found", 0)); else { nodeList.Sort( delegate(NodeInfo x, NodeInfo y) { int result = (int)x.EntryType - (int)y.EntryType; if(result == 0) result = String.Compare(x.Id, y.Id, StringComparison.CurrentCulture); return result; }); foreach(NodeInfo ni in nodeList) if(!lvSearchResults.Items.ContainsKey(ni.Id)) { lvi = new ListViewItem(ni.NodeText, (int)ni.EntryType + ((int)ni.Visibility * 11)); lvi.Name = ni.Id; lvi.Tag = ni; nodeText = ni.Id; // Use the display name for the member if(ni.EntryType >= ApiEntryType.Class && ni.EntryType <= ApiEntryType.Operator) { pos = nodeText.LastIndexOf('.'); if(pos != -1) nodeText = nodeText.Substring(0, pos + 1) + ni.NodeText; else nodeText = ni.NodeText; // Resolve templates in the type name if((ni.EntryType == ApiEntryType.Constructor || ni.EntryType == ApiEntryType.Method) && nodeText.IndexOf('`') != -1) nodeText = ResolveNameFunction.ReplaceTypeTemplateMarker( ni.ApiNode, nodeText); } else if(nodeText.IndexOf('`') != -1) nodeText = ResolveNameFunction.ReplaceTypeTemplateMarker( ni.ApiNode, nodeText); lvi.SubItems.Add(new ListViewItem.ListViewSubItem( lvi, nodeText)); lvSearchResults.Items.Add(lvi); } } } catch(Exception ex) { MessageBox.Show("Unexpected error occurred while performing " + "the search: " + ex.Message, Constants.AppName, MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { this.Cursor = Cursors.Default; btnGoto.Enabled = btnInclude.Enabled = btnExclude.Enabled = (lvSearchResults.Items.Count != 0); } }
/// <summary> /// This is called to invoke the <b>resolve-name</b> method /// </summary> /// <param name="xsltContext">The XSLT context for the function call</param> /// <param name="args">The arguments for the function call</param> /// <param name="docContext">The context node for the function call</param> /// <returns>An object representing the return value of the function (the name string)</returns> /// <exception cref="ArgumentException">This is thrown if the number of arguments for the function is /// not two.</exception> public object Invoke(XsltContext xsltContext, object[] args, XPathNavigator docContext) { XPathNavigator nav; XmlNode apiNode; XmlNodeList templates; StringBuilder sb = new StringBuilder(100); string nodeText; bool fullyQualified; int pos, idx = 1; char nodeType; if (args.Length != 2) { throw new ArgumentException("There must be two parameters passed to the 'resolve-name' function", nameof(args)); } nav = ((XPathNodeIterator)args[0]).Current; apiNode = ((IHasXmlNode)nav).GetNode(); fullyQualified = Convert.ToBoolean(args[1], CultureInfo.InvariantCulture); if (apiNode.Name == "api") { templates = apiNode.SelectNodes("templates/template"); nodeText = apiNode.Attributes["id"].Value; } else { nodeText = apiNode.Attributes["api"].Value; templates = apiNode.SelectNodes("specialization/template"); if (templates.Count == 0) { templates = apiNode.SelectNodes("specialization/type"); } } nodeType = nodeText[0]; nodeText = nodeText.Substring(2); if (nodeType == 'N') { if (nodeText.Length == 0 && !fullyQualified) { nodeText = "(global)"; } } else { // Strip parameters pos = nodeText.IndexOf('('); if (pos != -1) { nodeText = nodeText.Substring(0, pos); } // Remove the namespace and type if not fully qualified. Note the last period's position though // as we'll need it to skip generic markers in the name type name. pos = nodeText.LastIndexOf('.'); if (!fullyQualified && pos != -1) { nodeText = nodeText.Substring(pos + 1); pos = 0; } if (nodeType != 'T') { // Replace certain values to make it more readable if (nodeText.IndexOf("#cctor", StringComparison.Ordinal) != -1) { nodeText = nodeText.Replace("#cctor", "Static Constructor"); } else if (nodeText.IndexOf("#ctor", StringComparison.Ordinal) != -1) { nodeText = nodeText.Replace("#ctor", "Constructor"); } else { if (nodeText.IndexOf('#') != -1) { nodeText = nodeText.Replace('#', '.'); } if (pos == 0) { if (nodeText.StartsWith("op_", StringComparison.Ordinal)) { nodeText = nodeText.Substring(3) + " Operator"; } } else if (nodeText.IndexOf("op_", pos, StringComparison.Ordinal) != -1) { nodeText = nodeText.Substring(0, pos + 1) + nodeText.Substring(pos + 4) + " Operator"; } } } // Replace generic template markers with the names if (pos != -1) { pos = nodeText.IndexOf('`', pos); } if (pos != -1) { nodeText = nodeText.Substring(0, pos); foreach (XmlNode template in templates) { if (sb.Length != 0) { sb.Append(','); } if (template.Name != "type") { sb.Append(template.Attributes["name"].Value); } else { // For specializations of types, we don't want to show the type but a generic placeholder sb.Append('T'); if (idx > 1) { sb.Append(idx); } idx++; } } if (sb.Length != 0) { sb.Insert(0, "<"); sb.Append('>'); nodeText += sb.ToString(); } } // Replace generic template markers in the type name if fully qualified if (fullyQualified && nodeText.IndexOf('`') != -1) { nodeText = XPathFunctionContext.ReplaceTypeTemplateMarker(apiNode, nodeText); } } return(nodeText); }