PageRenderTime 52ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-0-pre3/org/gjt/sp/jedit/Abbrevs.java

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