/plugins/Console/tags/release-4-0-1/console/SystemShell.java

# · Java · 1068 lines · 752 code · 142 blank · 174 comment · 160 complexity · b066be1d4c6830f96a612feeedfa8d5f MD5 · raw file

  1. /*
  2. * SystemShell.java - Executes OS commands
  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 console;
  23. //{{{ Imports
  24. import java.io.*;
  25. import java.util.*;
  26. import org.gjt.sp.jedit.browser.VFSBrowser;
  27. import org.gjt.sp.jedit.*;
  28. import org.gjt.sp.util.Log;
  29. //}}}
  30. public class SystemShell extends Shell
  31. {
  32. //{{{ SystemShell constructor
  33. public SystemShell()
  34. {
  35. super("System");
  36. lineSep = toASCII(System.getProperty("line.separator"));
  37. } //}}}
  38. //{{{ printInfoMessage() method
  39. public void printInfoMessage(Output output)
  40. {
  41. output.print(null,jEdit.getProperty("console.shell.info"));
  42. } //}}}
  43. //{{{ printPrompt() method
  44. /**
  45. * Prints a prompt to the specified console.
  46. * @param output The output
  47. */
  48. public void printPrompt(Console console, Output output)
  49. {
  50. String currentDirectory;
  51. if(getConsoleState(console) == null)
  52. currentDirectory = System.getProperty("user.dir");
  53. else
  54. {
  55. currentDirectory = getConsoleState(console)
  56. .currentDirectory;
  57. }
  58. output.writeAttrs(ConsolePane.colorAttributes(
  59. console.getInfoColor()),
  60. jEdit.getProperty("console.shell.prompt",
  61. new String[] { currentDirectory }));
  62. output.writeAttrs(null," ");
  63. } //}}}
  64. //{{{ execute() method
  65. public void execute(Console console, String input, Output output,
  66. Output error, String command)
  67. {
  68. ConsoleState state = getConsoleState(console);
  69. if(state.process != null)
  70. {
  71. PipedOutputStream out = state.process.getPipeOutput();
  72. if(out != null)
  73. {
  74. try
  75. {
  76. out.write(toASCII(command));
  77. out.write(lineSep);
  78. out.flush();
  79. }
  80. catch(IOException e)
  81. {
  82. throw new RuntimeException(e);
  83. }
  84. }
  85. return;
  86. }
  87. // comments, for possible future scripting support
  88. if(command.startsWith("#"))
  89. {
  90. output.commandDone();
  91. error.commandDone();
  92. return;
  93. }
  94. // lazily initialize aliases and variables
  95. init();
  96. Vector args = parse(command);
  97. // will be null if the command is an empty string
  98. if(args == null)
  99. {
  100. output.commandDone();
  101. error.commandDone();
  102. return;
  103. }
  104. args = preprocess(console.getView(),console,args);
  105. String commandName = (String)args.elementAt(0);
  106. if(commandName.charAt(0) == '%')
  107. {
  108. // a console built-in
  109. args.removeElementAt(0);
  110. executeBuiltIn(console,output,error,commandName,args);
  111. output.commandDone();
  112. error.commandDone();
  113. return;
  114. }
  115. // if current working directory doesn't exist, print an error.
  116. String cwd = state.currentDirectory;
  117. if(!new File(cwd).exists())
  118. {
  119. error.print(console.getErrorColor(),
  120. jEdit.getProperty(
  121. "console.shell.error.working-dir",
  122. new String[] { cwd }));
  123. output.commandDone();
  124. error.commandDone();
  125. return;
  126. }
  127. String fullPath = MiscUtilities.constructPath(
  128. cwd,commandName);
  129. // Java resolves this relative to user.dir, not
  130. // the directory we pass to exec()...
  131. if(commandName.startsWith("./")
  132. || commandName.startsWith("." + File.separator))
  133. {
  134. args.setElementAt(fullPath,0);
  135. }
  136. if(new File(fullPath).isDirectory() && args.size() == 1)
  137. {
  138. args.setElementAt(fullPath,0);
  139. executeBuiltIn(console,output,error,"%cd",args);
  140. output.commandDone();
  141. error.commandDone();
  142. }
  143. else
  144. {
  145. boolean foreground;
  146. if(args.elementAt(args.size() - 1).equals("&"))
  147. {
  148. // run in background
  149. args.removeElementAt(args.size() - 1);
  150. foreground = false;
  151. output.commandDone();
  152. error.commandDone();
  153. }
  154. else
  155. {
  156. // run in foreground
  157. foreground = true;
  158. }
  159. String[] _args = new String[args.size()];
  160. args.copyInto(_args);
  161. String[] env;
  162. if(ProcessRunner.getProcessRunner()
  163. .supportsEnvironmentVariables())
  164. {
  165. env = new String[variables.size()];
  166. int counter = 0;
  167. Enumeration keys = variables.keys();
  168. while(keys.hasMoreElements())
  169. {
  170. Object key = keys.nextElement();
  171. env[counter++]= (key + "=" + variables.get(key));
  172. }
  173. }
  174. else
  175. env = null;
  176. ConsoleProcess proc = new ConsoleProcess(
  177. console,output,error,_args,
  178. env,state,foreground);
  179. /* If startup failed its no longer running */
  180. if(foreground && proc.isRunning())
  181. {
  182. console.getErrorSource().clear();
  183. state.process = proc;
  184. }
  185. if(input != null)
  186. {
  187. try
  188. {
  189. OutputStream out = proc.getPipeOutput();
  190. out.write(toASCII(input));
  191. out.close();
  192. }
  193. catch(IOException e)
  194. {
  195. throw new RuntimeException(e);
  196. }
  197. }
  198. }
  199. } //}}}
  200. //{{{ stop() method
  201. public void stop(Console console)
  202. {
  203. ConsoleState consoleState = getConsoleState(console);
  204. ConsoleProcess process = consoleState.process;
  205. if(process != null)
  206. process.stop();
  207. else
  208. {
  209. console.print(console.getErrorColor(),
  210. jEdit.getProperty("console.shell.noproc"));
  211. }
  212. } //}}}
  213. //{{{ waitFor() method
  214. public boolean waitFor(Console console)
  215. {
  216. ConsoleState consoleState = getConsoleState(console);
  217. ConsoleProcess process = consoleState.process;
  218. if(process != null)
  219. {
  220. try
  221. {
  222. synchronized(process)
  223. {
  224. process.wait();
  225. }
  226. }
  227. catch(InterruptedException e)
  228. {
  229. }
  230. return process.getExitStatus();
  231. }
  232. else
  233. return true;
  234. } //}}}
  235. //{{{ endOfFile() method
  236. /**
  237. * Sends an end of file.
  238. * @param console The console
  239. */
  240. public void endOfFile(Console console)
  241. {
  242. ConsoleState state = getConsoleState(console);
  243. if(state.process != null)
  244. {
  245. console.writeAttrs(
  246. ConsolePane.colorAttributes(
  247. console.getInfoColor()),"^D\n");
  248. PipedOutputStream out = state.process.getPipeOutput();
  249. try
  250. {
  251. out.close();
  252. }
  253. catch(IOException e)
  254. {
  255. }
  256. }
  257. } //}}}
  258. //{{{ getCompletions() method
  259. /**
  260. * Returns possible completions for the specified command.
  261. * @param console The console instance
  262. * @param command The command
  263. * @since Console 3.6
  264. */
  265. public CompletionInfo getCompletions(Console console, String command)
  266. {
  267. // lazily initialize aliases and variables
  268. init();
  269. View view = console.getView();
  270. String currentDirectory = (console == null
  271. ? System.getProperty("user.dir")
  272. : SystemShell.getConsoleState(console)
  273. .currentDirectory);
  274. final String fileDelimiters = "=\'\" \\"+File.pathSeparator;
  275. String lastArgEscaped, lastArg;
  276. if (File.separatorChar == '\\')
  277. {
  278. // Escaping impossible
  279. lastArgEscaped = (String)parse(command).lastElement();
  280. lastArg = lastArgEscaped;
  281. }
  282. else
  283. {
  284. // Escaping possible
  285. // I use findLastArgument and then unescape instead of
  286. // (String)parse(command).lastElement() because there's no way
  287. // to get parse(String) to also return the original length
  288. // of the unescaped argument, which we need to calculate the
  289. // completion offset.
  290. lastArgEscaped = findLastArgument(command, fileDelimiters);
  291. lastArg = unescape(lastArgEscaped, fileDelimiters);
  292. }
  293. CompletionInfo completionInfo = new CompletionInfo();
  294. completionInfo.offset = command.length() - lastArg.length();
  295. if(completionInfo.offset == 0)
  296. {
  297. completionInfo.completions = (String[])getCommandCompletions(
  298. view,currentDirectory,lastArg).toArray(new String[0]);
  299. }
  300. else
  301. {
  302. completionInfo.completions = (String[])getFileCompletions(
  303. view,currentDirectory,lastArg,false).toArray(
  304. new String[0]);
  305. }
  306. // On systems where the file separator is the same as the escape
  307. // character (Windows), it's impossible to do escaping properly,
  308. // so we just assume that escaping is not needed (which is true
  309. // for windows).
  310. if(File.separatorChar != '\\')
  311. {
  312. for(int i = 0; i < completionInfo.completions.length; i++)
  313. {
  314. completionInfo.completions[i] = escape(completionInfo.completions[i], fileDelimiters);
  315. }
  316. }
  317. // We add a double quote at the beginning of any completion with
  318. // special characters because the current argument parsing
  319. // (done in parse()) uses StreamTokenizer, which only handles
  320. // escaping if it's done within a string. The purpose here is
  321. // dual - to get parse() to unescape the characters and to get
  322. // it to recognize the string as a single argument.
  323. // On systems where we don't support escaping, we do this
  324. // only for the 2nd purpose.
  325. boolean isDoubleQuoted = (completionInfo.offset > 0) && (command.charAt(completionInfo.offset - 1) == '\"');
  326. if(!isDoubleQuoted)
  327. {
  328. final String specialCharacters = (File.separatorChar == '\\') ? " " : fileDelimiters;
  329. for(int i = 0; i < completionInfo.completions.length; i++){
  330. String result = completionInfo.completions[i];
  331. if (containsCharacters(result, specialCharacters))
  332. result = "\"" + result;
  333. completionInfo.completions[i] = result;
  334. }
  335. }
  336. return completionInfo;
  337. } //}}}
  338. //{{{ expandVariables() method
  339. public String expandVariables(View view, String arg)
  340. {
  341. StringBuffer buf = new StringBuffer();
  342. String varName;
  343. for(int i = 0; i < arg.length(); i++)
  344. {
  345. char c = arg.charAt(i);
  346. switch(c)
  347. {
  348. case dosSlash:
  349. buf.append('\\');
  350. break;
  351. //{{{ DOS-style variable (%name%)
  352. case '%':
  353. int index = arg.indexOf('%',i + 1);
  354. if(index != -1)
  355. {
  356. if(index == i + 1)
  357. {
  358. // %%
  359. break;
  360. }
  361. varName = arg.substring(i + 1,index);
  362. i = index;
  363. String expansion = getVariableValue(view,varName);
  364. if(expansion != null)
  365. buf.append(expansion);
  366. }
  367. else
  368. buf.append('%');
  369. break;
  370. //}}}
  371. //{{{ Unix-style variables ($name, ${name})
  372. case '$':
  373. if(i == arg.length() - 1)
  374. {
  375. buf.append(c);
  376. break;
  377. }
  378. if(arg.charAt(i + 1) == '{')
  379. {
  380. index = arg.indexOf('}',i + 1);
  381. if(index == -1)
  382. index = arg.length();
  383. varName = arg.substring(i + 2,index);
  384. i = index;
  385. }
  386. else
  387. {
  388. for(index = i + 1; index < arg.length(); index++)
  389. {
  390. char ch = arg.charAt(index);
  391. if(!Character.isLetterOrDigit(ch)
  392. && ch != '_' && ch != '$')
  393. {
  394. break;
  395. }
  396. }
  397. varName = arg.substring(i + 1,index);
  398. i = index - 1;
  399. if(varName.startsWith("$"))
  400. {
  401. buf.append(varName);
  402. break;
  403. }
  404. else if(varName.length() == 0)
  405. break;
  406. }
  407. String expansion = getVariableValue(view,varName);
  408. if(expansion != null)
  409. buf.append(expansion);
  410. break;
  411. //}}}
  412. //{{{ Home directory (~)
  413. case '~':
  414. String home = System.getProperty("user.home");
  415. if(arg.length() == 1)
  416. {
  417. buf.append(home);
  418. break;
  419. }
  420. boolean ok = true;
  421. if(i != 0)
  422. {
  423. c = arg.charAt(i - 1);
  424. if(c != '=')
  425. ok = false;
  426. }
  427. if(i != arg.length() - 1)
  428. {
  429. c = arg.charAt(i + 1);
  430. if(c != '/' && c != File.separatorChar)
  431. ok = false;
  432. }
  433. if(ok)
  434. {
  435. buf.append(home);
  436. break;
  437. }
  438. else
  439. buf.append('~');
  440. break;
  441. //}}}
  442. default:
  443. buf.append(c);
  444. break;
  445. }
  446. }
  447. return buf.toString();
  448. } //}}}
  449. //{{{ getVariableValue() method
  450. public String getVariableValue(View view, String varName)
  451. {
  452. init();
  453. if(view == null)
  454. return (String)variables.get(varName);
  455. String expansion;
  456. // Expand some special variables
  457. Buffer buffer = view.getBuffer();
  458. if(varName.equals("$") || varName.equals("%"))
  459. expansion = varName;
  460. else if(varName.equals("d"))
  461. {
  462. expansion = MiscUtilities.getParentOfPath(
  463. buffer.getPath());
  464. if(expansion.endsWith("/")
  465. || expansion.endsWith(File.separator))
  466. {
  467. expansion = expansion.substring(0,
  468. expansion.length() - 1);
  469. }
  470. }
  471. else if(varName.equals("u"))
  472. {
  473. expansion = buffer.getPath();
  474. if(!MiscUtilities.isURL(expansion))
  475. {
  476. expansion = "file:/" + expansion
  477. .replace(File.separatorChar,'/');
  478. }
  479. }
  480. else if(varName.equals("f"))
  481. expansion = buffer.getPath();
  482. else if(varName.equals("n"))
  483. expansion = buffer.getName();
  484. else if(varName.equals("c"))
  485. expansion = ConsolePlugin.getClassName(buffer);
  486. else if(varName.equals("PKG"))
  487. {
  488. expansion = ConsolePlugin.getPackageName(buffer);
  489. if(expansion == null)
  490. expansion = "";
  491. }
  492. else if(varName.equals("ROOT"))
  493. expansion = ConsolePlugin.getPackageRoot(buffer);
  494. else if(varName.equals("BROWSER_DIR"))
  495. {
  496. VFSBrowser browser = (VFSBrowser)view
  497. .getDockableWindowManager()
  498. .getDockable("vfs.browser");
  499. if(browser == null)
  500. expansion = null;
  501. else
  502. expansion = browser.getDirectory();
  503. }
  504. else
  505. expansion = (String)variables.get(varName);
  506. return expansion;
  507. } //}}}
  508. //{{{ getAliases() method
  509. public Hashtable getAliases()
  510. {
  511. init();
  512. return aliases;
  513. } //}}}
  514. //{{{ Package-private members
  515. //{{{ consoleOpened() method
  516. static void consoleOpened(Console console)
  517. {
  518. consoleStateMap.put(console,new ConsoleState());
  519. } //}}}
  520. //{{{ consoleClosed() method
  521. static void consoleClosed(Console console)
  522. {
  523. ConsoleProcess process = getConsoleState(console).process;
  524. if(process != null)
  525. process.stop();
  526. consoleStateMap.remove(console);
  527. } //}}}
  528. //{{{ getConsoleState() method
  529. static ConsoleState getConsoleState(Console console)
  530. {
  531. return (ConsoleState)consoleStateMap.get(console);
  532. } //}}}
  533. //{{{ getVariables() method
  534. Hashtable getVariables()
  535. {
  536. init();
  537. return variables;
  538. } //}}}
  539. //{{{ propertiesChanged() method
  540. static void propertiesChanged()
  541. {
  542. //aliases = null;
  543. //variables = null;
  544. // next time execute() is called, init() will reload everything
  545. } //}}}
  546. //}}}
  547. //{{{ Private members
  548. //{{{ Instance variables
  549. private static Hashtable consoleStateMap = new Hashtable();
  550. private final char dosSlash = 127;
  551. private Hashtable aliases;
  552. private Hashtable variables;
  553. private Hashtable commands;
  554. private boolean initialized;
  555. private byte[] lineSep;
  556. //}}}
  557. //{{{ toASCII() method
  558. private static byte[] toASCII(String str)
  559. {
  560. try
  561. {
  562. return str.getBytes("ASCII");
  563. }
  564. catch(UnsupportedEncodingException e)
  565. {
  566. throw new RuntimeException(e);
  567. }
  568. } //}}}
  569. //{{{ init() method
  570. private void init()
  571. {
  572. if(initialized)
  573. return;
  574. initialized = true;
  575. initCommands();
  576. initAliases();
  577. initVariables();
  578. } //}}}
  579. //{{{ initCommands() method
  580. private void initCommands()
  581. {
  582. commands = new Hashtable();
  583. commands.put("%alias", new SystemShellBuiltIn.alias());
  584. commands.put("%aliases", new SystemShellBuiltIn.aliases());
  585. commands.put("%browse", new SystemShellBuiltIn.browse());
  586. commands.put("%cd", new SystemShellBuiltIn.cd());
  587. commands.put("%clear", new SystemShellBuiltIn.clear());
  588. commands.put("%dirstack", new SystemShellBuiltIn.dirstack());
  589. commands.put("%detach", new SystemShellBuiltIn.detach());
  590. commands.put("%echo", new SystemShellBuiltIn.echo());
  591. commands.put("%edit", new SystemShellBuiltIn.edit());
  592. commands.put("%env", new SystemShellBuiltIn.env());
  593. commands.put("%help", new SystemShellBuiltIn.help());
  594. commands.put("%kill", new SystemShellBuiltIn.kill());
  595. commands.put("%popd", new SystemShellBuiltIn.popd());
  596. commands.put("%pushd", new SystemShellBuiltIn.pushd());
  597. commands.put("%pwd", new SystemShellBuiltIn.pwd());
  598. commands.put("%run", new SystemShellBuiltIn.run());
  599. commands.put("%set", new SystemShellBuiltIn.set());
  600. commands.put("%unalias", new SystemShellBuiltIn.unalias());
  601. commands.put("%unset", new SystemShellBuiltIn.unset());
  602. commands.put("%version", new SystemShellBuiltIn.version());
  603. } //}}}
  604. //{{{ initAliases() method
  605. private void initAliases()
  606. {
  607. aliases = new Hashtable();
  608. // some built-ins can be invoked without the % prefix
  609. aliases.put("cd","%cd");
  610. aliases.put("pwd","%pwd");
  611. aliases.put("-","%cd -");
  612. // load aliases from properties
  613. /* String alias;
  614. int i = 0;
  615. while((alias = jEdit.getProperty("console.shell.alias." + i)) != null)
  616. {
  617. aliases.put(alias,jEdit.getProperty("console.shell.alias."
  618. + i + ".expansion"));
  619. i++;
  620. } */
  621. } //}}}
  622. //{{{ initVariables() method
  623. private void initVariables()
  624. {
  625. ProcessRunner osSupport = ProcessRunner.getProcessRunner();
  626. osSupport.setUpDefaultAliases(aliases);
  627. variables = osSupport.getEnvironmentVariables();
  628. if(jEdit.getJEditHome() != null)
  629. variables.put("JEDIT_HOME",jEdit.getJEditHome());
  630. if(jEdit.getSettingsDirectory() != null)
  631. variables.put("JEDIT_SETTINGS",jEdit.getSettingsDirectory());
  632. // for the sake of Unix programs that try to be smart
  633. variables.put("TERM","dumb");
  634. // load variables from properties
  635. /* String varname;
  636. i = 0;
  637. while((varname = jEdit.getProperty("console.shell.variable." + i)) != null)
  638. {
  639. variables.put(varname,jEdit.getProperty("console.shell.variable."
  640. + i + ".value"));
  641. i++;
  642. } */
  643. } //}}}
  644. //{{{ parse() method
  645. /**
  646. * Convert a command into a vector of arguments.
  647. */
  648. private Vector parse(String command)
  649. {
  650. Vector args = new Vector();
  651. // We replace \ with a non-printable char because
  652. // StreamTokenizer handles \ specially, which causes
  653. // problems on Windows as \ is the file separator
  654. // there.
  655. // After parsing is done, the non printable char is
  656. // changed to \ once again.
  657. // StreamTokenizer needs a way to disable backslash
  658. // handling...
  659. if (File.separatorChar == '\\')
  660. command = command.replace('\\',dosSlash);
  661. StreamTokenizer st = new StreamTokenizer(new StringReader(command));
  662. st.resetSyntax();
  663. st.wordChars('!',255);
  664. st.whitespaceChars(0,' ');
  665. st.quoteChar('"');
  666. st.quoteChar('\'');
  667. try
  668. {
  669. loop: for(;;)
  670. {
  671. switch(st.nextToken())
  672. {
  673. case StreamTokenizer.TT_EOF:
  674. break loop;
  675. case StreamTokenizer.TT_WORD:
  676. case '"':
  677. case '\'':
  678. if (File.separatorChar == '\\')
  679. args.addElement(st.sval.replace(dosSlash,'\\'));
  680. else
  681. args.addElement(st.sval);
  682. break;
  683. }
  684. }
  685. }
  686. catch(IOException io)
  687. {
  688. // won't happen
  689. }
  690. if(args.size() == 0)
  691. return null;
  692. else
  693. return args;
  694. } //}}}
  695. //{{{ preprocess() method
  696. /**
  697. * Expand aliases, variables and globs.
  698. */
  699. private Vector preprocess(View view, Console console, Vector args)
  700. {
  701. Vector newArgs = new Vector();
  702. // expand aliases
  703. String commandName = (String)args.elementAt(0);
  704. String expansion = (String)aliases.get(commandName);
  705. if(expansion != null)
  706. {
  707. Vector expansionArgs = parse(expansion);
  708. for(int i = 0; i < expansionArgs.size(); i++)
  709. {
  710. expandGlobs(view,newArgs,(String)expansionArgs
  711. .elementAt(i));
  712. }
  713. }
  714. else
  715. expandGlobs(view,newArgs,commandName);
  716. // add remaining arguments
  717. for(int i = 1; i < args.size(); i++)
  718. expandGlobs(view,newArgs,(String)args.elementAt(i));
  719. return newArgs;
  720. } //}}}
  721. //{{{ expandGlobs() method
  722. private void expandGlobs(View view, Vector args, String arg)
  723. {
  724. // XXX: to do
  725. args.addElement(expandVariables(view,arg));
  726. } //}}}
  727. //{{{ executeBuiltIn() method
  728. public void executeBuiltIn(Console console, Output output, Output error,
  729. String command, Vector args)
  730. {
  731. SystemShellBuiltIn builtIn = (SystemShellBuiltIn)commands.get(command);
  732. if(builtIn == null)
  733. {
  734. String[] pp = { command };
  735. error.print(console.getErrorColor(),jEdit.getProperty(
  736. "console.shell.unknown-builtin",pp));
  737. }
  738. else
  739. {
  740. builtIn.execute(console,output,error,args);
  741. }
  742. } //}}}
  743. //{{{ getFileCompletions() method
  744. private List getFileCompletions(View view, String currentDirName,
  745. String typedFilename, boolean directoriesOnly)
  746. {
  747. String expandedTypedFilename = expandVariables(view, typedFilename);
  748. int lastSeparatorIndex = expandedTypedFilename.lastIndexOf(File.separator);
  749. // The directory part of what the user typed, including the file separator.
  750. String typedDirName = lastSeparatorIndex == -1 ? "" : expandedTypedFilename.substring(0, lastSeparatorIndex+1);
  751. // The file typed by the user.
  752. File typedFile = new File(expandedTypedFilename).isAbsolute() ?
  753. new File(expandedTypedFilename) :
  754. new File(currentDirName, expandedTypedFilename);
  755. boolean directory = expandedTypedFilename.endsWith(File.separator)
  756. || expandedTypedFilename.length() == 0;
  757. // The parent directory of the file typed by the user (or itself if it's already a directory).
  758. File dir = directory ? typedFile : typedFile.getParentFile();
  759. // The filename part of the file typed by the user, or "" if it's a directory.
  760. String fileName = directory ? "" : typedFile.getName();
  761. // The list of files we're going to try to match
  762. String [] filenames = dir.list();
  763. if ((filenames == null) || (filenames.length == 0))
  764. return null;
  765. boolean isOSCaseSensitive = ProcessRunner.getProcessRunner().isCaseSensitive();
  766. ArrayList matchingFilenames = new ArrayList(filenames.length);
  767. int matchingFilenamesCount = 0;
  768. String matchedString = isOSCaseSensitive ? fileName : fileName.toLowerCase();
  769. for(int i = 0; i < filenames.length; i++)
  770. {
  771. String matchedAgainst = isOSCaseSensitive ? filenames[i] : filenames[i].toLowerCase();
  772. if(matchedAgainst.startsWith(matchedString))
  773. {
  774. String match;
  775. File matchFile = new File(dir, filenames[i]);
  776. if(directoriesOnly && !matchFile.isDirectory())
  777. continue;
  778. match = typedDirName + filenames[i];
  779. // Add a separator at the end if it's a directory
  780. if(matchFile.isDirectory() && !match.endsWith(File.separator))
  781. match = match + File.separator;
  782. matchingFilenames.add(match);
  783. }
  784. }
  785. return matchingFilenames;
  786. } //}}}
  787. //{{{ getCommandCompletions() method
  788. private List getCommandCompletions(View view, String currentDirName,
  789. String command)
  790. {
  791. ArrayList list = new ArrayList();
  792. Iterator iter = commands.keySet().iterator();
  793. while(iter.hasNext())
  794. {
  795. String cmd = (String)iter.next();
  796. if(cmd.startsWith(command))
  797. list.add(cmd);
  798. }
  799. iter = aliases.keySet().iterator();
  800. while(iter.hasNext())
  801. {
  802. String cmd = (String)iter.next();
  803. if(cmd.startsWith(command))
  804. list.add(cmd);
  805. }
  806. list.addAll(getFileCompletions(view,currentDirName,command,false));
  807. return list;
  808. } //}}}
  809. //{{{ findLastArgument() method
  810. /**
  811. * Returns the last argument in the given command by using the given
  812. * delimiters. The delimiters can be escaped.
  813. */
  814. private static String findLastArgument(String command, String delimiters)
  815. {
  816. int i = command.length() - 1;
  817. while(i >= 0)
  818. {
  819. char c = command.charAt(i);
  820. if(delimiters.indexOf(c) != -1)
  821. {
  822. if((i == 0) || (command.charAt(i - 1) != '\\'))
  823. break;
  824. else
  825. i--;
  826. }
  827. i--;
  828. }
  829. return command.substring(i+1);
  830. } //}}}
  831. //{{{ unescape() method
  832. /**
  833. * Unescapes the given delimiters in the given string.
  834. */
  835. private static String unescape(String s, String delimiters)
  836. {
  837. StringBuffer buf = new StringBuffer(s.length());
  838. int i = s.length() - 1;
  839. while(i >= 0)
  840. {
  841. char c = s.charAt(i);
  842. buf.append(c);
  843. if(delimiters.indexOf(c) != -1)
  844. {
  845. if(s.charAt(i - 1) == '\\')
  846. i--;
  847. }
  848. i--;
  849. }
  850. return buf.reverse().toString();
  851. } //}}}
  852. //{{{ escape() method
  853. /**
  854. * Escapes the given delimiters in the given string.
  855. */
  856. private static String escape(String s, String delimiters)
  857. {
  858. StringBuffer buf = new StringBuffer();
  859. int length = s.length();
  860. for(int i = 0; i < length; i++)
  861. {
  862. char c = s.charAt(i);
  863. if (delimiters.indexOf(c) != -1)
  864. buf.append('\\');
  865. buf.append(c);
  866. }
  867. return buf.toString();
  868. } //}}}
  869. //{{{ containsWhitespace() method
  870. /**
  871. * Returns <code>true</code> if the first string contains any of the
  872. * characters in the second string. Returns <code>false</code> otherwise.
  873. */
  874. private static boolean containsCharacters(String s, String characters)
  875. {
  876. int stringLength = s.length();
  877. for (int i = 0; i < stringLength; i++)
  878. if (characters.indexOf(s.charAt(i)) != -1)
  879. return true;
  880. return false;
  881. } //}}}
  882. //}}}
  883. //{{{ ConsoleState class
  884. static class ConsoleState
  885. {
  886. String currentDirectory = System.getProperty("user.dir");
  887. String lastDirectory = System.getProperty("user.dir");
  888. Stack directoryStack = new Stack();
  889. ConsoleProcess process;
  890. void gotoLastDirectory(Console console)
  891. {
  892. String[] pp = { lastDirectory };
  893. if(new File(lastDirectory).exists())
  894. {
  895. String newLastDir = currentDirectory;
  896. currentDirectory = lastDirectory;
  897. lastDirectory = newLastDir;
  898. console.print(console.getInfoColor(),
  899. jEdit.getProperty(
  900. "console.shell.cd.ok",pp));
  901. }
  902. else
  903. {
  904. console.print(console.getErrorColor(),
  905. jEdit.getProperty(
  906. "console.shell.cd.error",pp));
  907. }
  908. }
  909. void setCurrentDirectory(Console console, String newDir)
  910. {
  911. String[] pp = { newDir };
  912. if(new File(newDir).exists())
  913. {
  914. lastDirectory = currentDirectory;
  915. currentDirectory = newDir;
  916. }
  917. else
  918. {
  919. console.print(console.getErrorColor(),
  920. jEdit.getProperty(
  921. "console.shell.cd.error",pp));
  922. }
  923. }
  924. } //}}}
  925. }