PageRenderTime 46ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-5-pre1/org/gjt/sp/jedit/gui/CompleteWord.java

#
Java | 508 lines | 376 code | 71 blank | 61 comment | 68 complexity | 0cb899081f303b6e9305e5649baaddb6 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * CompleteWord.java - Complete word dialog
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2000, 2001 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. package org.gjt.sp.jedit.gui;
  23. //{{{ Imports
  24. import java.awt.Component;
  25. import java.awt.Font;
  26. import java.awt.Point;
  27. import java.awt.event.KeyEvent;
  28. import java.util.HashSet;
  29. import java.util.Set;
  30. import java.util.TreeSet;
  31. import java.util.Arrays;
  32. import java.util.Collection;
  33. import javax.swing.DefaultListCellRenderer;
  34. import javax.swing.JList;
  35. import javax.swing.SwingUtilities;
  36. import org.gjt.sp.jedit.Buffer;
  37. import org.gjt.sp.jedit.EditPane;
  38. import org.gjt.sp.jedit.visitors.JEditVisitorAdapter;
  39. import org.gjt.sp.jedit.jEdit;
  40. import org.gjt.sp.jedit.MiscUtilities;
  41. import org.gjt.sp.jedit.TextUtilities;
  42. import org.gjt.sp.jedit.View;
  43. import org.gjt.sp.jedit.syntax.KeywordMap;
  44. import org.gjt.sp.jedit.textarea.JEditTextArea;
  45. import org.gjt.sp.util.StandardUtilities;
  46. //}}}
  47. /**
  48. * A completion popup class.
  49. */
  50. public class CompleteWord extends CompletionPopup
  51. {
  52. //{{{ completeWord() method
  53. public static void completeWord(View view)
  54. {
  55. JEditTextArea textArea = view.getTextArea();
  56. Buffer buffer = view.getBuffer();
  57. int caretLine = textArea.getCaretLine();
  58. int caret = textArea.getCaretPosition();
  59. if(!buffer.isEditable())
  60. {
  61. textArea.getToolkit().beep();
  62. return;
  63. }
  64. KeywordMap keywordMap = buffer.getKeywordMapAtOffset(caret);
  65. String noWordSep = getNonAlphaNumericWordChars(
  66. buffer,keywordMap);
  67. String word = getWordToComplete(buffer,caretLine,
  68. caret,noWordSep);
  69. if(word == null)
  70. {
  71. textArea.getToolkit().beep();
  72. return;
  73. }
  74. Completion[] completions = getCompletions(buffer,word,caret);
  75. if(completions.length == 0)
  76. {
  77. textArea.getToolkit().beep();
  78. }
  79. //{{{ if there is only one competion, insert in buffer
  80. else if(completions.length == 1)
  81. {
  82. Completion c = completions[0];
  83. if(c.text.equals(word))
  84. {
  85. textArea.getToolkit().beep();
  86. }
  87. else
  88. {
  89. textArea.replaceSelection(c.text.substring(
  90. word.length()));
  91. }
  92. } //}}}
  93. //{{{ show popup if > 1
  94. else
  95. {
  96. String longestPrefix = MiscUtilities.getLongestPrefix(
  97. completions,
  98. keywordMap != null
  99. ? keywordMap.getIgnoreCase()
  100. : false);
  101. if (word.length() < longestPrefix.length())
  102. {
  103. buffer.insert(caret,longestPrefix.substring(
  104. word.length()));
  105. }
  106. textArea.scrollToCaret(false);
  107. Point location = textArea.offsetToXY(
  108. caret - word.length());
  109. location.y += textArea.getPainter().getLineHeight();
  110. SwingUtilities.convertPointToScreen(location,
  111. textArea.getPainter());
  112. new CompleteWord(view,longestPrefix,
  113. completions,location,noWordSep);
  114. } //}}}
  115. } //}}}
  116. //{{{ CompleteWord constructor
  117. public CompleteWord(View view, String word, Completion[] completions,
  118. Point location, String noWordSep)
  119. {
  120. super(view, location);
  121. this.noWordSep = noWordSep;
  122. this.view = view;
  123. this.textArea = view.getTextArea();
  124. this.buffer = view.getBuffer();
  125. this.word = word;
  126. reset(new Words(completions), true);
  127. } //}}}
  128. //{{{ Private members
  129. //{{{ getNonAlphaNumericWordChars() method
  130. private static String getNonAlphaNumericWordChars(Buffer buffer,
  131. KeywordMap keywordMap)
  132. {
  133. // figure out what constitutes a word character and what
  134. // doesn't
  135. String noWordSep = buffer.getStringProperty("noWordSep");
  136. if(noWordSep == null)
  137. noWordSep = "";
  138. if(keywordMap != null)
  139. {
  140. String keywordNoWordSep = keywordMap.getNonAlphaNumericChars();
  141. if(keywordNoWordSep != null)
  142. noWordSep += keywordNoWordSep;
  143. }
  144. return noWordSep;
  145. } //}}}
  146. //{{{ getWordToComplete() method
  147. private static String getWordToComplete(Buffer buffer, int caretLine,
  148. int caret, String noWordSep)
  149. {
  150. CharSequence line = buffer.getLineSegment(caretLine);
  151. int dot = caret - buffer.getLineStartOffset(caretLine);
  152. if(dot == 0)
  153. return null;
  154. char ch = line.charAt(dot-1);
  155. if(!Character.isLetterOrDigit(ch)
  156. && noWordSep.indexOf(ch) == -1)
  157. {
  158. // attempting to expand non-word char
  159. return null;
  160. }
  161. int wordStart = TextUtilities.findWordStart(line,dot-1,noWordSep);
  162. CharSequence word = line.subSequence(wordStart,dot);
  163. if(word.length() == 0)
  164. return null;
  165. return word.toString();
  166. } //}}}
  167. //{{{ getVisibleBuffers() method
  168. private static Collection<Buffer> getVisibleBuffers()
  169. {
  170. final Set<Buffer> buffers = new HashSet<Buffer>();
  171. jEdit.visit(new JEditVisitorAdapter()
  172. {
  173. @Override
  174. public void visit(EditPane editPane)
  175. {
  176. buffers.add(editPane.getBuffer());
  177. }
  178. });
  179. return buffers;
  180. } //}}}
  181. //{{{ getCompletions() method
  182. private static Completion[] getCompletions(final Buffer buffer, final String word,
  183. final int caret)
  184. {
  185. // build a list of unique words in all buffers, or visible buffers,
  186. // depending on completeFromAllBuffers
  187. final Set<Completion> completions = new TreeSet<Completion>(new StandardUtilities
  188. .StringCompare<Completion>());
  189. // only complete current buffer's keyword map
  190. final KeywordMap keywordMap = buffer.getKeywordMapAtOffset(caret);
  191. final String noWordSep = getNonAlphaNumericWordChars(
  192. buffer,keywordMap);
  193. final Collection<Buffer> sourceBuffers =
  194. jEdit.getBooleanProperty("completeFromAllBuffers") ?
  195. Arrays.asList(jEdit.getBuffers()) :
  196. getVisibleBuffers();
  197. for (Buffer b : sourceBuffers)
  198. {
  199. // only complete current buffer's keyword map
  200. KeywordMap _keywordMap;
  201. if(b == buffer)
  202. _keywordMap = keywordMap;
  203. else
  204. _keywordMap = null;
  205. int offset = (b == buffer ? caret : 0);
  206. getCompletions(b,word,keywordMap,noWordSep,
  207. offset,completions);
  208. }
  209. Completion[] completionArray = completions
  210. .toArray(new Completion[completions.size()]);
  211. return completionArray;
  212. } //}}}
  213. //{{{ getCompletions() method
  214. private static void getCompletions(Buffer buffer, String word,
  215. KeywordMap keywordMap, String noWordSep, int caret,
  216. Set<Completion> completions)
  217. {
  218. int wordLen = word.length();
  219. //{{{ try to find matching keywords
  220. if(keywordMap != null)
  221. {
  222. String[] keywords = keywordMap.getKeywords();
  223. for(int i = 0; i < keywords.length; i++)
  224. {
  225. String _keyword = keywords[i];
  226. if(_keyword.regionMatches(keywordMap.getIgnoreCase(),
  227. 0,word,0,wordLen))
  228. {
  229. Completion keyword = new Completion(_keyword,true);
  230. if(!completions.contains(keyword))
  231. {
  232. completions.add(keyword);
  233. }
  234. }
  235. }
  236. } //}}}
  237. //{{{ loop through all lines of current buffer
  238. for(int i = 0; i < buffer.getLineCount(); i++)
  239. {
  240. CharSequence line = buffer.getLineSegment(i);
  241. int start = buffer.getLineStartOffset(i);
  242. // check for match at start of line
  243. if (StandardUtilities.startsWith(line, word) &&
  244. caret != start + word.length())
  245. {
  246. String _word = completeWord(line,0,noWordSep);
  247. Completion comp = new Completion(_word,false);
  248. // remove duplicates
  249. if(!completions.contains(comp))
  250. {
  251. completions.add(comp);
  252. }
  253. }
  254. // check for match inside line
  255. int len = line.length() - word.length();
  256. for(int j = 0; j < len; j++)
  257. {
  258. char c = line.charAt(j);
  259. if(!Character.isLetterOrDigit(c) && noWordSep.indexOf(c) == -1)
  260. {
  261. if (StandardUtilities.regionMatches(line,j + 1,word,0,wordLen)
  262. && caret != start + j + word.length() + 1)
  263. {
  264. String _word = completeWord(line,j + 1,noWordSep);
  265. Completion comp = new Completion(_word,false);
  266. // remove duplicates
  267. if(!completions.contains(comp))
  268. {
  269. completions.add(comp);
  270. }
  271. }
  272. }
  273. }
  274. } //}}}
  275. } //}}}
  276. //{{{ completeWord() method
  277. private static String completeWord(CharSequence line, int offset, String noWordSep)
  278. {
  279. // '+ 1' so that findWordEnd() doesn't pick up the space at the start
  280. int wordEnd = TextUtilities.findWordEnd(line,offset + 1,noWordSep);
  281. return line.subSequence(offset,wordEnd).toString();
  282. } //}}}
  283. //{{{ Instance variables
  284. private View view;
  285. private JEditTextArea textArea;
  286. private Buffer buffer;
  287. private String word;
  288. private String noWordSep;
  289. //}}}
  290. //{{{ Completion class
  291. private static class Completion
  292. {
  293. final String text;
  294. final boolean keyword;
  295. Completion(String text, boolean keyword)
  296. {
  297. this.text = text;
  298. this.keyword = keyword;
  299. }
  300. public String toString()
  301. {
  302. return text;
  303. }
  304. public int hashCode()
  305. {
  306. return text.hashCode();
  307. }
  308. public boolean equals(Object obj)
  309. {
  310. if(obj instanceof Completion)
  311. return ((Completion)obj).text.equals(text);
  312. else
  313. return false;
  314. }
  315. } //}}}
  316. //{{{ Words class
  317. private class Words implements Candidates
  318. {
  319. private final DefaultListCellRenderer renderer;
  320. private final Completion[] completions;
  321. public Words(Completion[] completions)
  322. {
  323. this.renderer = new DefaultListCellRenderer();
  324. this.completions = completions;
  325. }
  326. public int getSize()
  327. {
  328. return completions.length;
  329. }
  330. public boolean isValid()
  331. {
  332. return true;
  333. }
  334. public void complete(int index)
  335. {
  336. String insertion = completions[index].toString().substring(word.length());
  337. textArea.replaceSelection(insertion);
  338. }
  339. public Component getCellRenderer(JList list, int index,
  340. boolean isSelected, boolean cellHasFocus)
  341. {
  342. renderer.getListCellRendererComponent(list,
  343. null, index, isSelected, cellHasFocus);
  344. Completion comp = completions[index];
  345. String text = comp.text;
  346. Font font = list.getFont();
  347. if(index < 9)
  348. text = (index + 1) + ": " + text;
  349. else if(index == 9)
  350. text = "0: " + text;
  351. if(comp.keyword)
  352. font = font.deriveFont(Font.BOLD);
  353. renderer.setText(text);
  354. renderer.setFont(font);
  355. return renderer;
  356. }
  357. public String getDescription(int index)
  358. {
  359. return null;
  360. }
  361. } //}}}
  362. //{{{ resetWords() method
  363. private void resetWords(String newWord)
  364. {
  365. int caret = textArea.getCaretPosition();
  366. Completion[] completions = getCompletions(
  367. buffer,newWord,caret);
  368. if(completions.length > 0)
  369. {
  370. word = newWord;
  371. reset(new Words(completions), true);
  372. }
  373. else
  374. {
  375. dispose();
  376. }
  377. } //}}}
  378. //}}}
  379. //{{{ keyPressed() medhod
  380. protected void keyPressed(KeyEvent e)
  381. {
  382. if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE)
  383. {
  384. textArea.backspace();
  385. e.consume();
  386. if(word.length() == 1)
  387. {
  388. dispose();
  389. }
  390. else
  391. {
  392. resetWords(word.substring(0,word.length() - 1));
  393. }
  394. }
  395. } //}}}
  396. //{{{ keyTyped() medhod
  397. protected void keyTyped(KeyEvent e)
  398. {
  399. char ch = e.getKeyChar();
  400. if(Character.isDigit(ch))
  401. {
  402. int index = ch - '0';
  403. if(index == 0)
  404. index = 9;
  405. else
  406. index--;
  407. if(index < getCandidates().getSize())
  408. {
  409. setSelectedIndex(index);
  410. if(doSelectedCompletion())
  411. {
  412. e.consume();
  413. dispose();
  414. }
  415. return;
  416. }
  417. else
  418. /* fall through */;
  419. }
  420. // \t handled above
  421. if(ch != '\b' && ch != '\t')
  422. {
  423. /* eg, foo<C+b>, will insert foobar, */
  424. if(!Character.isLetterOrDigit(ch) && noWordSep.indexOf(ch) == -1)
  425. {
  426. doSelectedCompletion();
  427. textArea.userInput(ch);
  428. e.consume();
  429. dispose();
  430. return;
  431. }
  432. textArea.userInput(ch);
  433. e.consume();
  434. resetWords(word + ch);
  435. }
  436. } //}}}
  437. }