001: /*
002: * HelpIndex.java - Index for help searching feature
003: * :tabSize=8:indentSize=8:noTabs=false:
004: * :folding=explicit:collapseFolds=1:
005: *
006: * Copyright (C) 2002 Slava Pestov
007: *
008: * This program is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU General Public License
010: * as published by the Free Software Foundation; either version 2
011: * of the License, or any later version.
012: *
013: * This program is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: * GNU General Public License for more details.
017: *
018: * You should have received a copy of the GNU General Public License
019: * along with this program; if not, write to the Free Software
020: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
021: */
022:
023: package org.gjt.sp.jedit.help;
024:
025: //{{{ Imports
026: import java.io.*;
027: import java.net.*;
028: import java.util.zip.*;
029: import java.util.*;
030: import org.gjt.sp.jedit.io.*;
031: import org.gjt.sp.jedit.*;
032: import org.gjt.sp.util.Log;
033:
034: //}}}
035:
036: class HelpIndex {
037: //{{{ HelpIndex constructor
038: public HelpIndex() {
039: words = new HashMap();
040: files = new ArrayList();
041:
042: ignoreWord("a");
043: ignoreWord("an");
044: ignoreWord("and");
045: ignoreWord("are");
046: ignoreWord("as");
047: ignoreWord("be");
048: ignoreWord("by");
049: ignoreWord("can");
050: ignoreWord("do");
051: ignoreWord("for");
052: ignoreWord("from");
053: ignoreWord("how");
054: ignoreWord("i");
055: ignoreWord("if");
056: ignoreWord("in");
057: ignoreWord("is");
058: ignoreWord("it");
059: ignoreWord("not");
060: ignoreWord("of");
061: ignoreWord("on");
062: ignoreWord("or");
063: ignoreWord("s");
064: ignoreWord("that");
065: ignoreWord("the");
066: ignoreWord("this");
067: ignoreWord("to");
068: ignoreWord("will");
069: ignoreWord("with");
070: ignoreWord("you");
071: } //}}}
072:
073: /* //{{{ HelpIndex constructor
074: public HelpIndex(String fileListPath, String wordIndexPath)
075: {
076: this();
077: } //}}} */
078:
079: //{{{ indexEditorHelp() method
080: /**
081: * Indexes all available help, including the jEdit user's guide, FAQ,]
082: * and plugin documentation.
083: */
084: public void indexEditorHelp() {
085: try {
086: String jEditHome = jEdit.getJEditHome();
087: if (jEditHome != null) {
088: indexDirectory(MiscUtilities.constructPath(jEditHome,
089: "doc", "users-guide"));
090: indexDirectory(MiscUtilities.constructPath(jEditHome,
091: "doc", "FAQ"));
092: indexDirectory(MiscUtilities.constructPath(jEditHome,
093: "doc", "news43"));
094: }
095: } catch (Throwable e) {
096: Log.log(Log.ERROR, this , "Error indexing editor help");
097: Log.log(Log.ERROR, this , e);
098: }
099:
100: PluginJAR[] jars = jEdit.getPluginJARs();
101: for (int i = 0; i < jars.length; i++) {
102: try {
103: indexJAR(jars[i].getZipFile());
104: } catch (Throwable e) {
105: Log.log(Log.ERROR, this , "Error indexing JAR: "
106: + jars[i].getPath());
107: Log.log(Log.ERROR, this , e);
108: }
109: }
110:
111: Log.log(Log.DEBUG, this , "Indexed " + words.size() + " words");
112: } //}}}
113:
114: //{{{ indexDirectory() method
115: /**
116: * Indexes all HTML and text files in the specified directory.
117: * @param dir The directory
118: */
119: public void indexDirectory(String dir) throws Exception {
120: String[] files = VFSManager.getFileVFS()._listDirectory(null,
121: dir, "*.{html,txt}", true, null);
122:
123: for (int i = 0; i < files.length; i++) {
124: indexURL(files[i]);
125: }
126: } //}}}
127:
128: //{{{ indexJAR() method
129: /**
130: * Indexes all HTML and text files in the specified JAR file.
131: * @param jar The JAR file
132: */
133: public void indexJAR(ZipFile jar) throws Exception {
134: Enumeration e = jar.entries();
135: while (e.hasMoreElements()) {
136: ZipEntry entry = (ZipEntry) e.nextElement();
137: String name = entry.getName();
138: String lname = name.toLowerCase();
139: if (lname.endsWith(".html")/* || lname.endsWith(".txt") */) {
140: // only works for jEdit plugins
141: String url = "jeditresource:/"
142: + MiscUtilities.getFileName(jar.getName())
143: + "!/" + name;
144: Log.log(Log.DEBUG, this , url);
145: indexStream(jar.getInputStream(entry), url);
146: }
147: }
148: } //}}}
149:
150: //{{{ indexURL() method
151: /**
152: * Reads the specified HTML file and adds all words defined therein to the
153: * index.
154: * @param url The HTML file's URL
155: */
156: public void indexURL(String url) throws Exception {
157: InputStream _in;
158:
159: if (MiscUtilities.isURL(url))
160: _in = new URL(url).openStream();
161: else {
162: _in = new FileInputStream(url);
163: // hack since HelpViewer needs a URL...
164: url = "file:" + url;
165: }
166:
167: indexStream(_in, url);
168: } //}}}
169:
170: //{{{ lookupWord() method
171: public Word lookupWord(String word) {
172: Object o = words.get(word);
173: if (o == IGNORE)
174: return null;
175: else
176: return (Word) o;
177: } //}}}
178:
179: //{{{ getFile() method
180: public HelpFile getFile(int index) {
181: return (HelpFile) files.get(index);
182: } //}}}
183:
184: //{{{ Private members
185: // used to mark words to ignore (see constructor for the list)
186: private static Object IGNORE = new Object();
187: private HashMap words;
188: private ArrayList files;
189:
190: //{{{ ignoreWord() method
191: private void ignoreWord(String word) {
192: words.put(word, IGNORE);
193: } //}}}
194:
195: //{{{ indexStream() method
196: /**
197: * Reads the specified HTML file and adds all words defined therein to the
198: * index.
199: * @param _in The input stream
200: * @param file The file
201: */
202: private void indexStream(InputStream _in, String fileName)
203: throws Exception {
204: HelpFile file = new HelpFile(fileName);
205: files.add(file);
206: int index = files.size() - 1;
207:
208: StringBuffer titleText = new StringBuffer();
209:
210: BufferedReader in = new BufferedReader(new InputStreamReader(
211: _in));
212:
213: try {
214: StringBuffer word = new StringBuffer();
215: boolean insideTag = false;
216: boolean insideEntity = false;
217:
218: boolean title = false;
219:
220: int c;
221: while ((c = in.read()) != -1) {
222: char ch = (char) c;
223: if (insideTag) {
224: if (ch == '>') {
225: if (word.toString().equals("title"))
226: title = true;
227: insideTag = false;
228: word.setLength(0);
229: } else
230: word.append(ch);
231: } else if (insideEntity) {
232: if (ch == ';')
233: insideEntity = false;
234: } else if (ch == '<') {
235: if (title)
236: title = false;
237:
238: if (word.length() != 0) {
239: addWord(word.toString(), index, title);
240: word.setLength(0);
241: }
242:
243: insideTag = true;
244: } else if (ch == '&')
245: insideEntity = true;
246: else if (title)
247: titleText.append(ch);
248: else if (!Character.isLetterOrDigit(ch)) {
249: if (word.length() != 0) {
250: addWord(word.toString(), index, title);
251: word.setLength(0);
252: }
253: } else
254: word.append(ch);
255: }
256: } finally {
257: in.close();
258: }
259:
260: if (titleText.length() == 0)
261: file.title = fileName;
262: else
263: file.title = titleText.toString();
264: } //}}}
265:
266: //{{{ addWord() method
267: private void addWord(String word, int file, boolean title) {
268: word = word.toLowerCase();
269:
270: Object o = words.get(word);
271: if (o == IGNORE)
272: return;
273:
274: if (o == null)
275: words.put(word, new Word(word, file, title));
276: else
277: ((Word) o).addOccurrence(file, title);
278: } //}}}
279:
280: //}}}
281:
282: //{{{ Word class
283: static class Word {
284: // how much an occurrence in the title is worth
285: static final int TITLE_OCCUR = 10;
286:
287: // the word
288: String word;
289:
290: // files it occurs in
291: int occurCount = 0;
292: Occurrence[] occurrences;
293:
294: Word(String word, int file, boolean title) {
295: this .word = word;
296: occurrences = new Occurrence[5];
297: addOccurrence(file, title);
298: }
299:
300: void addOccurrence(int file, boolean title) {
301: for (int i = 0; i < occurCount; i++) {
302: if (occurrences[i].file == file) {
303: occurrences[i].count += (title ? TITLE_OCCUR : 1);
304: return;
305: }
306: }
307:
308: if (occurCount >= occurrences.length) {
309: Occurrence[] newOccur = new Occurrence[occurrences.length * 2];
310: System.arraycopy(occurrences, 0, newOccur, 0,
311: occurCount);
312: occurrences = newOccur;
313: }
314:
315: occurrences[occurCount++] = new Occurrence(file, title);
316: }
317:
318: static class Occurrence {
319: int file;
320: int count;
321:
322: Occurrence(int file, boolean title) {
323: this .file = file;
324: this .count = (title ? TITLE_OCCUR : 1);
325: }
326: }
327: } //}}}
328:
329: //{{{ HelpFile class
330: static class HelpFile {
331: String file;
332: String title;
333:
334: HelpFile(String file) {
335: this .file = file;
336: }
337:
338: public String toString() {
339: return title;
340: }
341:
342: public boolean equals(Object o) {
343: if (o instanceof HelpFile)
344: return ((HelpFile) o).file.equals(file);
345: else
346: return false;
347: }
348: } //}}}
349: }
|