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;
26 [CommandParameter("api", "The API name")]
29 get { return Parameters; }
30 set { Parameters = value; }
33 private void WriteIfVerbose(string message)
41 string CHMFilename = Path.Combine(Settings.Default.ChmPath, Settings.Default.MainChm);
42 chm = new HtmlHelpSystem();
43 chm.OpenFile(CHMFilename, null);
45 Console.WriteLine(String.Format("Loaded main CHM: {0}",
46 Path.GetFileName(CHMFilename)));
47 foreach (string filename in Directory.GetFiles(Settings.Default.ChmPath))
49 if (!Path.GetExtension(filename).ToLower().Equals(".chm"))
51 if (Path.GetFileName(filename).ToLower().Equals(Settings.Default.MainChm))
54 Console.WriteLine(String.Format("Loading CHM: {0}",
55 Path.GetFileName(filename)));
58 chm.MergeFile(filename);
62 Console.WriteLine(String.Format("Could not load CHM: {0}. Exception {1}",
63 Path.GetFileName(filename),
67 Console.WriteLine(String.Format("Loaded {0} CHMs",
68 chm.FileList.Length));
71 public override void ExecuteCommand()
73 if (Name.Trim().Equals(String.Empty))
75 Say("Please give me a keyword.");
83 private bool SearchIndex(
88 IndexItem item = chm.Index.SearchIndex(keyword,
89 IndexType.KeywordLinks);
90 if (item != null && item.Topics.Count > 0)
92 WriteIfVerbose(String.Format("Keyword {0} found in index",
94 IndexTopic indexTopic = item.Topics[0] as IndexTopic;
95 return DisplayResult( keyword,
100 WriteIfVerbose(String.Format("Keyword {0} not found in index",
109 private void SearchFullText(string keyword)
111 string sort = "Rating ASC";
112 WriteIfVerbose(String.Format("Searching fulltext database for {0}",
115 bool partialMatches = false;
116 bool titlesOnly = true;
117 int maxResults = 100;
118 DataTable results = chm.PerformSearch(keyword,
122 WriteIfVerbose(String.Format("results.Rows.Count = {0}",
124 results.Rows.Count.ToString() : "(none)"));
125 if (results != null && results.Rows.Count > 0)
127 results.DefaultView.Sort = sort;
128 if (!DisplayResult(keyword,
140 private void Search(string keyword)
142 if (!SearchIndex(keyword))
143 SearchFullText(keyword);
146 private bool DisplayResult(string keyword,
147 IndexTopic indexTopic)
149 keyword = keyword.Trim().ToLower();
150 string url = indexTopic.URL;
151 WriteIfVerbose(String.Format("URL from index search {0}",
153 string prototype = ExtractPrototype(url);
154 if (prototype == null || prototype.Trim().Equals(String.Empty))
156 string formattedPrototype = FormatPrototype(prototype);
157 Say(formattedPrototype);
161 private bool DisplayResult(string keyword,
164 keyword = keyword.Trim().ToLower();
165 for (int i = 0; i < results.DefaultView.Count; i++)
167 DataRowView row = results.DefaultView[i];
168 string title = row["Title"].ToString();
169 WriteIfVerbose(String.Format("Examining {0}", title));
170 if (title.Trim().ToLower().Equals(keyword))
172 string location = row["Location"].ToString();
173 string rating = row["Rating"].ToString();
174 string url = row["Url"].ToString();
175 string prototype = ExtractPrototype(url);
176 if (prototype == null || prototype.Trim().Equals(String.Empty))
178 string formattedPrototype = FormatPrototype(prototype);
179 Say(formattedPrototype);
186 private void DisplayNoResult(MessageContext context,
189 TechBot.ServiceOutput.WriteLine(context,
190 String.Format("I don't know about keyword {0}",
194 private string ReplaceComments(string s)
196 return Regex.Replace(s, "//(.+)\r\n", "");
199 private string ReplaceLineEndings(string s)
201 return Regex.Replace(s, "(\r\n)+", " ");
204 private string ReplaceSpaces(string s)
206 return Regex.Replace(s, @" +", " ");
209 private string ReplaceSpacesBeforeLeftParenthesis(string s)
211 return Regex.Replace(s, @"\( ", @"(");
214 private string ReplaceSpacesBeforeRightParenthesis(string s)
216 return Regex.Replace(s, @" \)", @")");
219 private string ReplaceSemicolon(string s)
221 return Regex.Replace(s, @";", @"");
224 private string FormatPrototype(string prototype)
226 string s = ReplaceComments(prototype);
227 s = ReplaceLineEndings(s);
228 s = ReplaceSpaces(s);
229 s = ReplaceSpacesBeforeLeftParenthesis(s);
230 s = ReplaceSpacesBeforeRightParenthesis(s);
231 s = ReplaceSemicolon(s);
235 private string ExtractPrototype(string url)
237 string page = GetPage(url);
238 Match match = Regex.Match(page,
239 "<PRE class=\"?syntax\"?>(.+)</PRE>",
240 RegexOptions.Multiline |
241 RegexOptions.Singleline);
242 if (match.Groups.Count > 1)
244 string prototype = match.Groups[1].ToString();
245 return StripHtml(StripAfterSlashPre(prototype));
251 private string StripAfterSlashPre(string html)
253 int index = html.IndexOf("</PRE>");
256 return html.Substring(0, index);
262 private string StripHtml(string html)
264 return Regex.Replace(html, @"<(.|\n)*?>", String.Empty);
267 private string GetPage(string url)
269 string CHMFileName = "";
270 string topicName = "";
272 CHMStream.CHMStream baseStream;
273 if (!chm.BaseStream.GetCHMParts(url, ref CHMFileName, ref topicName, ref anchor))
275 baseStream = chm.BaseStream;
276 CHMFileName = baseStream.CHMFileName;
282 baseStream = GetBaseStreamFromCHMFileName(CHMFileName);
285 if ((topicName == "") || (CHMFileName == "") || (baseStream == null))
290 return baseStream.ExtractTextFile(topicName);
293 private CHMStream.CHMStream GetBaseStreamFromCHMFileName(string CHMFileName)
295 foreach (CHMFile file in chm.FileList)
297 WriteIfVerbose(String.Format("Compare: {0} <> {1}",
300 if (file.ChmFilePath.ToLower().Equals(CHMFileName.ToLower()))
302 return file.BaseStream;
305 WriteIfVerbose(String.Format("Could not find loaded CHM file in list: {0}",