4 using System.Text.RegularExpressions;
7 using HtmlHelp.ChmDecoding;
11 namespace TechBot.Commands.MSDN
13 [Command("api", Help = "!api <apiname>")]
14 public class ApiCommand : Command
16 private bool IsVerbose = false;
18 private HtmlHelpSystem chm;
25 [CommandParameter("api", "The API name")]
28 get { return Parameters; }
29 set { Parameters = value; }
32 private void WriteIfVerbose(string message)
38 private void LoadCHM()
40 string CHMFilename = Path.Combine(Settings.Default.ChmPath, Settings.Default.MainChm);
41 chm = new HtmlHelpSystem();
42 chm.OpenFile(CHMFilename, null);
44 Console.WriteLine(String.Format("Loaded main CHM: {0}",
45 Path.GetFileName(CHMFilename)));
46 foreach (string filename in Directory.GetFiles(Settings.Default.ChmPath))
48 if (!Path.GetExtension(filename).ToLower().Equals(".chm"))
50 if (Path.GetFileName(filename).ToLower().Equals(Settings.Default.MainChm))
53 Console.WriteLine(String.Format("Loading CHM: {0}",
54 Path.GetFileName(filename)));
57 chm.MergeFile(filename);
61 Console.WriteLine(String.Format("Could not load CHM: {0}. Exception {1}",
62 Path.GetFileName(filename),
66 Console.WriteLine(String.Format("Loaded {0} CHMs",
67 chm.FileList.Length));
70 public override void ExecuteCommand()
72 if (Name.Trim().Equals(String.Empty))
74 Say("Please give me a keyword.");
82 private bool SearchIndex(
87 IndexItem item = chm.Index.SearchIndex(keyword,
88 IndexType.KeywordLinks);
89 if (item != null && item.Topics.Count > 0)
91 WriteIfVerbose(String.Format("Keyword {0} found in index",
93 IndexTopic indexTopic = item.Topics[0] as IndexTopic;
94 return DisplayResult( keyword,
99 WriteIfVerbose(String.Format("Keyword {0} not found in index",
108 private void SearchFullText(string keyword)
110 string sort = "Rating ASC";
111 WriteIfVerbose(String.Format("Searching fulltext database for {0}",
114 bool partialMatches = false;
115 bool titlesOnly = true;
116 int maxResults = 100;
117 DataTable results = chm.PerformSearch(keyword,
121 WriteIfVerbose(String.Format("results.Rows.Count = {0}",
123 results.Rows.Count.ToString() : "(none)"));
124 if (results != null && results.Rows.Count > 0)
126 results.DefaultView.Sort = sort;
127 if (!DisplayResult(keyword,
139 private void Search(string keyword)
141 if (!SearchIndex(keyword))
142 SearchFullText(keyword);
145 private bool DisplayResult(string keyword,
146 IndexTopic indexTopic)
148 keyword = keyword.Trim().ToLower();
149 string url = indexTopic.URL;
150 WriteIfVerbose(String.Format("URL from index search {0}",
152 string prototype = ExtractPrototype(url);
153 if (prototype == null || prototype.Trim().Equals(String.Empty))
155 string formattedPrototype = FormatPrototype(prototype);
156 Say(formattedPrototype);
160 private bool DisplayResult(string keyword,
163 keyword = keyword.Trim().ToLower();
164 for (int i = 0; i < results.DefaultView.Count; i++)
166 DataRowView row = results.DefaultView[i];
167 string title = row["Title"].ToString();
168 WriteIfVerbose(String.Format("Examining {0}", title));
169 if (title.Trim().ToLower().Equals(keyword))
171 string location = row["Location"].ToString();
172 string rating = row["Rating"].ToString();
173 string url = row["Url"].ToString();
174 string prototype = ExtractPrototype(url);
175 if (prototype == null || prototype.Trim().Equals(String.Empty))
177 string formattedPrototype = FormatPrototype(prototype);
178 Say(formattedPrototype);
185 private void DisplayNoResult(MessageContext context,
188 TechBot.ServiceOutput.WriteLine(context,
189 String.Format("I don't know about keyword {0}",
193 private string ReplaceComments(string s)
195 return Regex.Replace(s, "//(.+)\r\n", "");
198 private string ReplaceLineEndings(string s)
200 return Regex.Replace(s, "(\r\n)+", " ");
203 private string ReplaceSpaces(string s)
205 return Regex.Replace(s, @" +", " ");
208 private string ReplaceSpacesBeforeLeftParenthesis(string s)
210 return Regex.Replace(s, @"\( ", @"(");
213 private string ReplaceSpacesBeforeRightParenthesis(string s)
215 return Regex.Replace(s, @" \)", @")");
218 private string ReplaceSemicolon(string s)
220 return Regex.Replace(s, @";", @"");
223 private string FormatPrototype(string prototype)
225 string s = ReplaceComments(prototype);
226 s = ReplaceLineEndings(s);
227 s = ReplaceSpaces(s);
228 s = ReplaceSpacesBeforeLeftParenthesis(s);
229 s = ReplaceSpacesBeforeRightParenthesis(s);
230 s = ReplaceSemicolon(s);
234 private string ExtractPrototype(string url)
236 string page = GetPage(url);
237 Match match = Regex.Match(page,
238 "<PRE class=\"?syntax\"?>(.+)</PRE>",
239 RegexOptions.Multiline |
240 RegexOptions.Singleline);
241 if (match.Groups.Count > 1)
243 string prototype = match.Groups[1].ToString();
244 return StripHtml(StripAfterSlashPre(prototype));
250 private string StripAfterSlashPre(string html)
252 int index = html.IndexOf("</PRE>");
255 return html.Substring(0, index);
261 private string StripHtml(string html)
263 return Regex.Replace(html, @"<(.|\n)*?>", String.Empty);
266 private string GetPage(string url)
268 string CHMFileName = "";
269 string topicName = "";
271 CHMStream.CHMStream baseStream;
272 if (!chm.BaseStream.GetCHMParts(url, ref CHMFileName, ref topicName, ref anchor))
274 baseStream = chm.BaseStream;
275 CHMFileName = baseStream.CHMFileName;
281 baseStream = GetBaseStreamFromCHMFileName(CHMFileName);
284 if ((topicName == "") || (CHMFileName == "") || (baseStream == null))
289 return baseStream.ExtractTextFile(topicName);
292 private CHMStream.CHMStream GetBaseStreamFromCHMFileName(string CHMFileName)
294 foreach (CHMFile file in chm.FileList)
296 WriteIfVerbose(String.Format("Compare: {0} <> {1}",
299 if (file.ChmFilePath.ToLower().Equals(CHMFileName.ToLower()))
301 return file.BaseStream;
304 WriteIfVerbose(String.Format("Could not find loaded CHM file in list: {0}",