Source code: org/gjt/sp/jedit/help/HelpIndex.java
1 /*
2 * HelpIndex.java - Index for help searching feature
3 * :tabSize=8:indentSize=8:noTabs=false:
4 * :folding=explicit:collapseFolds=1:
5 *
6 * Copyright (C) 2002 Slava Pestov
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 */
22
23 package org.gjt.sp.jedit.help;
24
25 //{{{ Imports
26 import java.io.*;
27 import java.net.*;
28 import java.util.zip.*;
29 import java.util.*;
30 import org.gjt.sp.jedit.io.*;
31 import org.gjt.sp.jedit.*;
32 import org.gjt.sp.util.Log;
33 //}}}
34
35 class HelpIndex
36 {
37 //{{{ HelpIndex constructor
38 public HelpIndex()
39 {
40 words = new HashMap();
41 files = new ArrayList();
42
43 ignoreWord("a");
44 ignoreWord("an");
45 ignoreWord("and");
46 ignoreWord("are");
47 ignoreWord("as");
48 ignoreWord("be");
49 ignoreWord("by");
50 ignoreWord("can");
51 ignoreWord("do");
52 ignoreWord("for");
53 ignoreWord("from");
54 ignoreWord("how");
55 ignoreWord("i");
56 ignoreWord("if");
57 ignoreWord("in");
58 ignoreWord("is");
59 ignoreWord("it");
60 ignoreWord("not");
61 ignoreWord("of");
62 ignoreWord("on");
63 ignoreWord("or");
64 ignoreWord("s");
65 ignoreWord("that");
66 ignoreWord("the");
67 ignoreWord("this");
68 ignoreWord("to");
69 ignoreWord("will");
70 ignoreWord("with");
71 ignoreWord("you");
72 } //}}}
73
74 /* //{{{ HelpIndex constructor
75 public HelpIndex(String fileListPath, String wordIndexPath)
76 {
77 this();
78 } //}}} */
79
80 //{{{ indexEditorHelp() method
81 /**
82 * Indexes all available help, including the jEdit user's guide, FAQ,]
83 * and plugin documentation.
84 */
85 public void indexEditorHelp()
86 {
87 try
88 {
89 String jEditHome = jEdit.getJEditHome();
90 if(jEditHome != null)
91 {
92 indexDirectory(MiscUtilities.constructPath(jEditHome,"doc","users-guide"));
93 indexDirectory(MiscUtilities.constructPath(jEditHome,"doc","FAQ"));
94 indexDirectory(MiscUtilities.constructPath(jEditHome,"doc","news42"));
95 }
96 }
97 catch(Throwable e)
98 {
99 Log.log(Log.ERROR,this,"Error indexing editor help");
100 Log.log(Log.ERROR,this,e);
101 }
102
103 PluginJAR[] jars = jEdit.getPluginJARs();
104 for(int i = 0; i < jars.length; i++)
105 {
106 try
107 {
108 indexJAR(jars[i].getZipFile());
109 }
110 catch(Throwable e)
111 {
112 Log.log(Log.ERROR,this,"Error indexing JAR: "
113 + jars[i].getPath());
114 Log.log(Log.ERROR,this,e);
115 }
116 }
117
118 Log.log(Log.DEBUG,this,"Indexed " + words.size() + " words");
119 } //}}}
120
121 //{{{ indexDirectory() method
122 /**
123 * Indexes all HTML and text files in the specified directory.
124 * @param dir The directory
125 */
126 public void indexDirectory(String dir) throws Exception
127 {
128 String[] files = VFSManager.getFileVFS()
129 ._listDirectory(null,dir,"*.{html,txt}",true,null);
130
131 for(int i = 0; i < files.length; i++)
132 {
133 indexURL(files[i]);
134 }
135 } //}}}
136
137 //{{{ indexJAR() method
138 /**
139 * Indexes all HTML and text files in the specified JAR file.
140 * @param jar The JAR file
141 */
142 public void indexJAR(ZipFile jar) throws Exception
143 {
144 Enumeration enum = jar.entries();
145 while(enum.hasMoreElements())
146 {
147 ZipEntry entry = (ZipEntry)enum.nextElement();
148 String name = entry.getName();
149 String lname = name.toLowerCase();
150 if(lname.endsWith(".html")/* || lname.endsWith(".txt") */)
151 {
152 // only works for jEdit plugins
153 String url = "jeditresource:/" +
154 MiscUtilities.getFileName(jar.getName())
155 + "!/" + name;
156 Log.log(Log.DEBUG,this,url);
157 indexStream(jar.getInputStream(entry),url);
158 }
159 }
160 } //}}}
161
162 //{{{ indexURL() method
163 /**
164 * Reads the specified HTML file and adds all words defined therein to the
165 * index.
166 * @param url The HTML file's URL
167 */
168 public void indexURL(String url) throws Exception
169 {
170 InputStream _in;
171
172 if(MiscUtilities.isURL(url))
173 _in = new URL(url).openStream();
174 else
175 {
176 _in = new FileInputStream(url);
177 // hack since HelpViewer needs a URL...
178 url = "file:" + url;
179 }
180
181 indexStream(_in,url);
182 } //}}}
183
184 //{{{ lookupWord() method
185 public Word lookupWord(String word)
186 {
187 Object o = words.get(word);
188 if(o == IGNORE)
189 return null;
190 else
191 return (Word)o;
192 } //}}}
193
194 //{{{ getFile() method
195 public HelpFile getFile(int index)
196 {
197 return (HelpFile)files.get(index);
198 } //}}}
199
200 //{{{ Private members
201 private static Word.Occurrence[] EMPTY_ARRAY = new Word.Occurrence[0];
202 // used to mark words to ignore (see constructor for the list)
203 private static Object IGNORE = new Object();
204 private HashMap words;
205 private ArrayList files;
206
207 //{{{ ignoreWord() method
208 private void ignoreWord(String word)
209 {
210 words.put(word,IGNORE);
211 } //}}}
212
213 //{{{ indexStream() method
214 /**
215 * Reads the specified HTML file and adds all words defined therein to the
216 * index.
217 * @param _in The input stream
218 * @param file The file
219 */
220 private void indexStream(InputStream _in, String fileName) throws Exception
221 {
222 HelpFile file = new HelpFile(fileName);
223 files.add(file);
224 int index = files.size() - 1;
225
226 BufferedReader in = new BufferedReader(new InputStreamReader(_in));
227
228 StringBuffer titleText = new StringBuffer();
229
230 try
231 {
232 StringBuffer word = new StringBuffer();
233 boolean insideTag = false;
234 boolean insideEntity = false;
235
236 boolean title = false;
237
238 int c;
239 while((c = in.read()) != -1)
240 {
241 char ch = (char)c;
242 if(insideTag)
243 {
244 if(ch == '>')
245 {
246 if(word.toString().equals("title"))
247 title = true;
248 insideTag = false;
249 word.setLength(0);
250 }
251 else
252 word.append(ch);
253 }
254 else if(insideEntity)
255 {
256 if(ch == ';')
257 insideEntity = false;
258 }
259 else if(ch == '<')
260 {
261 if(title)
262 title = false;
263
264 if(word.length() != 0)
265 {
266 addWord(word.toString(),index,title);
267 word.setLength(0);
268 }
269
270 insideTag = true;
271 }
272 else if(ch == '&')
273 insideEntity = true;
274 else if(title)
275 titleText.append(ch);
276 else if(!Character.isLetterOrDigit(ch))
277 {
278 if(word.length() != 0)
279 {
280 addWord(word.toString(),index,title);
281 word.setLength(0);
282 }
283 }
284 else
285 word.append(ch);
286 }
287 }
288 finally
289 {
290 in.close();
291 }
292
293 if(titleText.length() == 0)
294 file.title = fileName;
295 else
296 file.title = titleText.toString();
297 } //}}}
298
299 //{{{ addWord() method
300 private void addWord(String word, int file, boolean title)
301 {
302 word = word.toLowerCase();
303
304 Object o = words.get(word);
305 if(o == IGNORE)
306 return;
307
308 if(o == null)
309 words.put(word,new Word(word,file,title));
310 else
311 ((Word)o).addOccurrence(file,title);
312 } //}}}
313
314 //}}}
315
316 //{{{ Word class
317 static class Word
318 {
319 // how much an occurrence in the title is worth
320 static final int TITLE_OCCUR = 10;
321
322 // the word
323 String word;
324
325 // files it occurs in
326 int occurCount = 0;
327 Occurrence[] occurrences;
328
329 Word(String word, int file, boolean title)
330 {
331 this.word = word;
332 occurrences = new Occurrence[5];
333 addOccurrence(file,title);
334 }
335
336 void addOccurrence(int file, boolean title)
337 {
338 for(int i = 0; i < occurCount; i++)
339 {
340 if(occurrences[i].file == file)
341 {
342 occurrences[i].count += (title ? TITLE_OCCUR : 1);
343 return;
344 }
345 }
346
347 if(occurCount >= occurrences.length)
348 {
349 Occurrence[] newOccur = new Occurrence[occurrences.length * 2];
350 System.arraycopy(occurrences,0,newOccur,0,occurCount);
351 occurrences = newOccur;
352 }
353
354 occurrences[occurCount++] = new Occurrence(file,title);
355 }
356
357 static class Occurrence
358 {
359 int file;
360 int count;
361
362 Occurrence(int file, boolean title)
363 {
364 this.file = file;
365 this.count = (title ? TITLE_OCCUR : 1);
366 }
367 }
368 } //}}}
369
370 //{{{ HelpFile class
371 static class HelpFile
372 {
373 String file;
374 String title;
375
376 HelpFile(String file)
377 {
378 this.file = file;
379 this.title = title;
380 }
381
382 public String toString()
383 {
384 return title;
385 }
386
387 public boolean equals(Object o)
388 {
389 if(o instanceof HelpFile)
390 return ((HelpFile)o).file.equals(file);
391 else
392 return false;
393 }
394 } //}}}
395 }