PageRenderTime 50ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/jEdit/tags/jedit-4-3-pre5/org/gjt/sp/jedit/Abbrevs.java

#
Java | 594 lines | 400 code | 73 blank | 121 comment | 82 complexity | 48c3cb77af08c2a767f47f4bcc1ccff7 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. * Abbrevs.java - Abbreviation manager
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1999, 2004 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;
  23. //{{{ Imports
  24. import java.io.*;
  25. import java.util.*;
  26. import org.gjt.sp.jedit.gui.AddAbbrevDialog;
  27. import org.gjt.sp.jedit.textarea.*;
  28. import org.gjt.sp.util.Log;
  29. //}}}
  30. /**
  31. * Abbreviation manager.
  32. * @author Slava Pestov
  33. * @version $Id: Abbrevs.java 5337 2006-01-23 23:04:25Z ezust $
  34. */
  35. public class Abbrevs
  36. {
  37. public static final String ENCODING = "UTF8";
  38. //{{{ getExpandOnInput() method
  39. /**
  40. * Returns if abbreviations should be expanded after the
  41. * user finishes typing a word.
  42. */
  43. public static boolean getExpandOnInput()
  44. {
  45. return expandOnInput;
  46. } //}}}
  47. //{{{ setExpandOnInput() method
  48. /**
  49. * Sets if abbreviations should be expanded after the
  50. * user finishes typing a word.
  51. * @param expandOnInput If true, typing a non-alphanumeric character
  52. * will automatically attempt to expand the current abbrev
  53. */
  54. public static void setExpandOnInput(boolean expandOnInput)
  55. {
  56. Abbrevs.expandOnInput = expandOnInput;
  57. } //}}}
  58. //{{{ expandAbbrev() method
  59. /**
  60. * Expands the abbrev at the caret position in the specified
  61. * view.
  62. * @param view The view
  63. * @param add If true and abbrev not found, will ask user if
  64. * it should be added
  65. * @since jEdit 2.6pre4
  66. */
  67. public static boolean expandAbbrev(View view, boolean add)
  68. {
  69. //{{{ Figure out some minor things
  70. Buffer buffer = view.getBuffer();
  71. JEditTextArea textArea = view.getTextArea();
  72. if(!buffer.isEditable())
  73. {
  74. view.getToolkit().beep();
  75. return false;
  76. }
  77. int line = textArea.getCaretLine();
  78. int lineStart = buffer.getLineStartOffset(line);
  79. int caret = textArea.getCaretPosition();
  80. String lineText = buffer.getLineText(line);
  81. if(lineText.length() == 0)
  82. {
  83. if(add)
  84. view.getToolkit().beep();
  85. return false;
  86. }
  87. int pos = caret - lineStart;
  88. if(pos == 0)
  89. {
  90. if(add)
  91. view.getToolkit().beep();
  92. return false;
  93. } //}}}
  94. // we reuse the 'pp' vector to save time
  95. m_pp.removeAllElements();
  96. int wordStart;
  97. String abbrev;
  98. //{{{ Handle abbrevs of the form abbrev#pos1#pos2#pos3#...
  99. if(lineText.charAt(pos-1) == '#')
  100. {
  101. wordStart = lineText.indexOf('#');
  102. wordStart = TextUtilities.findWordStart(lineText,wordStart,
  103. buffer.getStringProperty("noWordSep") + '#');
  104. abbrev = lineText.substring(wordStart,pos - 1);
  105. // positional parameters will be inserted where $1, $2, $3, ...
  106. // occurs in the expansion
  107. int lastIndex = 0;
  108. for(int i = 0; i < abbrev.length(); i++)
  109. {
  110. if(abbrev.charAt(i) == '#')
  111. {
  112. m_pp.addElement(abbrev.substring(lastIndex,i));
  113. lastIndex = i + 1;
  114. }
  115. }
  116. m_pp.addElement(abbrev.substring(lastIndex));
  117. // the first element of pp is the abbrev itself
  118. abbrev = (String)m_pp.elementAt(0);
  119. m_pp.removeElementAt(0);
  120. } //}}}
  121. //{{{ Handle ordinary abbrevs
  122. else
  123. {
  124. wordStart = TextUtilities.findWordStart(lineText,pos - 1,
  125. buffer.getStringProperty("noWordSep"));
  126. abbrev = lineText.substring(wordStart,pos);
  127. } //}}}
  128. Expansion expand = expandAbbrev(buffer.getMode().getName(),
  129. abbrev,(buffer.getBooleanProperty("noTabs") ?
  130. buffer.getTabSize() : 0),m_pp);
  131. //{{{ Maybe show add abbrev dialog
  132. if(expand == null)
  133. {
  134. if(add)
  135. new AddAbbrevDialog(view,abbrev);
  136. return false;
  137. } //}}}
  138. //{{{ Insert the expansion
  139. else
  140. {
  141. buffer.remove(lineStart + wordStart,
  142. pos - wordStart);
  143. int whitespace = buffer.insertIndented(
  144. lineStart + wordStart,
  145. expand.text);
  146. int newlines = countNewlines(expand.text,
  147. expand.caretPosition);
  148. if(expand.caretPosition != -1)
  149. {
  150. textArea.setCaretPosition(lineStart + wordStart
  151. + expand.caretPosition
  152. + newlines * whitespace);
  153. }
  154. if(expand.posParamCount != m_pp.size())
  155. {
  156. view.getStatus().setMessageAndClear(
  157. jEdit.getProperty(
  158. "view.status.incomplete-abbrev",
  159. new Integer[] { new Integer(m_pp.size()),
  160. new Integer(expand.posParamCount) }));
  161. }
  162. return true;
  163. } //}}}
  164. } //}}}
  165. //{{{ getGlobalAbbrevs() method
  166. /**
  167. * Returns the global abbreviation set.
  168. * @since jEdit 2.3pre1
  169. */
  170. public static Hashtable getGlobalAbbrevs()
  171. {
  172. if(!loaded)
  173. load();
  174. return globalAbbrevs;
  175. } //}}}
  176. //{{{ setGlobalAbbrevs() method
  177. /**
  178. * Sets the global abbreviation set.
  179. * @param globalAbbrevs The new global abbrev set
  180. * @since jEdit 2.3pre1
  181. */
  182. public static void setGlobalAbbrevs(Hashtable globalAbbrevs)
  183. {
  184. abbrevsChanged = true;
  185. Abbrevs.globalAbbrevs = globalAbbrevs;
  186. } //}}}
  187. //{{{ getModeAbbrevs() method
  188. /**
  189. * Returns the mode-specific abbreviation set.
  190. * @since jEdit 2.3pre1
  191. */
  192. public static Hashtable getModeAbbrevs()
  193. {
  194. if(!loaded)
  195. load();
  196. return modes;
  197. } //}}}
  198. //{{{ setModeAbbrevs() method
  199. /**
  200. * Sets the mode-specific abbreviation set.
  201. * @param modes The new mode abbrev set
  202. * @since jEdit 2.3pre1
  203. */
  204. public static void setModeAbbrevs(Hashtable modes)
  205. {
  206. abbrevsChanged = true;
  207. Abbrevs.modes = modes;
  208. } //}}}
  209. //{{{ addGlobalAbbrev() method
  210. /**
  211. * Adds an abbreviation to the global abbreviation list.
  212. * @param abbrev The abbreviation
  213. * @param expansion The expansion
  214. * @since jEdit 3.1pre1
  215. */
  216. public static void addGlobalAbbrev(String abbrev, String expansion)
  217. {
  218. if(!loaded)
  219. load();
  220. globalAbbrevs.put(abbrev,expansion);
  221. abbrevsChanged = true;
  222. } //}}}
  223. //{{{ addModeAbbrev() method
  224. /**
  225. * Adds a mode-specific abbrev.
  226. * @param mode The edit mode
  227. * @param abbrev The abbrev
  228. * @param expansion The expansion
  229. * @since jEdit 3.1pre1
  230. */
  231. public static void addModeAbbrev(String mode, String abbrev, String expansion)
  232. {
  233. if(!loaded)
  234. load();
  235. Hashtable modeAbbrevs = (Hashtable)modes.get(mode);
  236. if(modeAbbrevs == null)
  237. {
  238. modeAbbrevs = new Hashtable();
  239. modes.put(mode,modeAbbrevs);
  240. }
  241. modeAbbrevs.put(abbrev,expansion);
  242. abbrevsChanged = true;
  243. } //}}}
  244. //{{{ save() method
  245. static void save()
  246. {
  247. jEdit.setBooleanProperty("view.expandOnInput",expandOnInput);
  248. String settings = jEdit.getSettingsDirectory();
  249. if(abbrevsChanged && settings != null)
  250. {
  251. File file1 = new File(MiscUtilities.constructPath(settings,"#abbrevs#save#"));
  252. File file2 = new File(MiscUtilities.constructPath(settings,"abbrevs"));
  253. if(file2.exists() && file2.lastModified() != abbrevsModTime)
  254. {
  255. Log.log(Log.WARNING,Abbrevs.class,file2 + " changed on disk;"
  256. + " will not save abbrevs");
  257. }
  258. else
  259. {
  260. jEdit.backupSettingsFile(file2);
  261. try
  262. {
  263. saveAbbrevs(new OutputStreamWriter(
  264. new FileOutputStream(file1),
  265. ENCODING));
  266. file2.delete();
  267. file1.renameTo(file2);
  268. }
  269. catch(Exception e)
  270. {
  271. Log.log(Log.ERROR,Abbrevs.class,"Error while saving " + file1);
  272. Log.log(Log.ERROR,Abbrevs.class,e);
  273. }
  274. abbrevsModTime = file2.lastModified();
  275. }
  276. }
  277. } //}}}
  278. //{{{ Private members
  279. //{{{ Instance variables
  280. private static boolean loaded;
  281. private static boolean abbrevsChanged;
  282. private static long abbrevsModTime;
  283. private static boolean expandOnInput;
  284. private static Hashtable globalAbbrevs;
  285. private static Hashtable modes;
  286. /** Vector of Positional Parameters */
  287. private static Vector m_pp = new Vector();
  288. //}}}
  289. private Abbrevs() {}
  290. static
  291. {
  292. expandOnInput = jEdit.getBooleanProperty("view.expandOnInput");
  293. }
  294. //{{{ load() method
  295. private static void load()
  296. {
  297. globalAbbrevs = new Hashtable();
  298. modes = new Hashtable();
  299. String settings = jEdit.getSettingsDirectory();
  300. if(settings != null)
  301. {
  302. File file = new File(MiscUtilities.constructPath(settings,"abbrevs"));
  303. abbrevsModTime = file.lastModified();
  304. try
  305. {
  306. loadAbbrevs(new InputStreamReader(
  307. new FileInputStream(file),ENCODING));
  308. loaded = true;
  309. }
  310. catch(FileNotFoundException fnf)
  311. {
  312. }
  313. catch(Exception e)
  314. {
  315. Log.log(Log.ERROR,Abbrevs.class,"Error while loading " + file);
  316. Log.log(Log.ERROR,Abbrevs.class,e);
  317. }
  318. }
  319. // only load global abbrevs if user abbrevs file could not be loaded
  320. if(!loaded)
  321. {
  322. try
  323. {
  324. loadAbbrevs(new InputStreamReader(Abbrevs.class
  325. .getResourceAsStream("default.abbrevs"),
  326. ENCODING));
  327. }
  328. catch(Exception e)
  329. {
  330. Log.log(Log.ERROR,Abbrevs.class,"Error while loading default.abbrevs");
  331. Log.log(Log.ERROR,Abbrevs.class,e);
  332. }
  333. loaded = true;
  334. }
  335. } //}}}
  336. //{{{ countNewlines() method
  337. private static int countNewlines(String s, int end)
  338. {
  339. int counter = 0;
  340. for(int i = 0; i < end; i++)
  341. {
  342. if(s.charAt(i) == '\n')
  343. counter++;
  344. }
  345. return counter;
  346. } //}}}
  347. //{{{ expandAbbrev() method
  348. private static Expansion expandAbbrev(String mode, String abbrev,
  349. int softTabSize, Vector pp)
  350. {
  351. m_pp = pp;
  352. if(!loaded)
  353. load();
  354. // try mode-specific abbrevs first
  355. String expand = null;
  356. Hashtable modeAbbrevs = (Hashtable)modes.get(mode);
  357. if(modeAbbrevs != null)
  358. expand = (String)modeAbbrevs.get(abbrev);
  359. if(expand == null)
  360. expand = (String)globalAbbrevs.get(abbrev);
  361. if(expand == null)
  362. return null;
  363. else
  364. return new Expansion(expand,softTabSize,m_pp);
  365. } //}}}
  366. //{{{ loadAbbrevs() method
  367. private static void loadAbbrevs(Reader _in) throws Exception
  368. {
  369. BufferedReader in = new BufferedReader(_in);
  370. try
  371. {
  372. Hashtable currentAbbrevs = globalAbbrevs;
  373. String line;
  374. while((line = in.readLine()) != null)
  375. {
  376. int index = line.indexOf('|');
  377. if(line.length() == 0)
  378. continue;
  379. else if(line.startsWith("[") && index == -1)
  380. {
  381. if(line.equals("[global]"))
  382. currentAbbrevs = globalAbbrevs;
  383. else
  384. {
  385. String mode = line.substring(1,
  386. line.length() - 1);
  387. currentAbbrevs = (Hashtable)modes.get(mode);
  388. if(currentAbbrevs == null)
  389. {
  390. currentAbbrevs = new Hashtable();
  391. modes.put(mode,currentAbbrevs);
  392. }
  393. }
  394. }
  395. else if(index != -1)
  396. {
  397. currentAbbrevs.put(line.substring(0,index),
  398. line.substring(index + 1));
  399. }
  400. }
  401. }
  402. finally
  403. {
  404. in.close();
  405. }
  406. } //}}}
  407. //{{{ saveAbbrevs() method
  408. private static void saveAbbrevs(Writer _out) throws Exception
  409. {
  410. BufferedWriter out = new BufferedWriter(_out);
  411. String lineSep = System.getProperty("line.separator");
  412. // write global abbrevs
  413. out.write("[global]");
  414. out.write(lineSep);
  415. saveAbbrevs(out,globalAbbrevs);
  416. // write mode abbrevs
  417. Enumeration keys = modes.keys();
  418. Enumeration values = modes.elements();
  419. while(keys.hasMoreElements())
  420. {
  421. out.write('[');
  422. out.write((String)keys.nextElement());
  423. out.write(']');
  424. out.write(lineSep);
  425. saveAbbrevs(out,(Hashtable)values.nextElement());
  426. }
  427. out.close();
  428. } //}}}
  429. //{{{ saveAbbrevs() method
  430. private static void saveAbbrevs(Writer out, Hashtable abbrevs)
  431. throws Exception
  432. {
  433. String lineSep = System.getProperty("line.separator");
  434. Enumeration keys = abbrevs.keys();
  435. Enumeration values = abbrevs.elements();
  436. while(keys.hasMoreElements())
  437. {
  438. String abbrev = (String)keys.nextElement();
  439. out.write(abbrev);
  440. out.write('|');
  441. out.write(values.nextElement().toString());
  442. out.write(lineSep);
  443. }
  444. } //}}}
  445. //}}}
  446. //{{{ Expansion class
  447. static class Expansion
  448. {
  449. String text;
  450. int caretPosition = -1;
  451. int lineCount;
  452. // number of positional parameters in abbreviation expansion
  453. int posParamCount;
  454. //{{{ Expansion constructor
  455. Expansion(String text, int softTabSize, Vector pp)
  456. {
  457. StringBuffer buf = new StringBuffer();
  458. boolean backslash = false;
  459. for(int i = 0; i < text.length(); i++)
  460. {
  461. char ch = text.charAt(i);
  462. //{{{ Handle backslash
  463. if(backslash)
  464. {
  465. backslash = false;
  466. if(ch == '|')
  467. caretPosition = buf.length();
  468. else if(ch == 'n')
  469. {
  470. buf.append('\n');
  471. lineCount++;
  472. }
  473. else if(ch == 't')
  474. {
  475. if(softTabSize == 0)
  476. buf.append('\t');
  477. else
  478. {
  479. for(int j = 0; j < softTabSize; j++)
  480. buf.append(' ');
  481. }
  482. }
  483. else
  484. buf.append(ch);
  485. }
  486. else if(ch == '\\')
  487. backslash = true;
  488. //}}}
  489. //{{{ Handle $
  490. else if(ch == '$')
  491. {
  492. if(i != text.length() - 1)
  493. {
  494. ch = text.charAt(i + 1);
  495. if(Character.isDigit(ch) && ch != '0')
  496. {
  497. i++;
  498. int pos = ch - '0';
  499. posParamCount = Math.max(pos,posParamCount);
  500. // $n is 1-indexed, but vector
  501. // contents is zero indexed
  502. if(pos <= pp.size())
  503. buf.append(pp.elementAt(pos - 1));
  504. }
  505. else
  506. {
  507. // $key will be $key, for
  508. // example
  509. buf.append('$');
  510. }
  511. }
  512. else
  513. buf.append('$'); // $ at end is literal
  514. } //}}}
  515. else
  516. buf.append(ch);
  517. }
  518. this.text = buf.toString();
  519. } //}}}
  520. } //}}}
  521. }