001    /*
002     * Copyright (C) 2012 eXo Platform SAS.
003     *
004     * This is free software; you can redistribute it and/or modify it
005     * under the terms of the GNU Lesser General Public License as
006     * published by the Free Software Foundation; either version 2.1 of
007     * the License, or (at your option) any later version.
008     *
009     * This software is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012     * Lesser General Public License for more details.
013     *
014     * You should have received a copy of the GNU Lesser General Public
015     * License along with this software; if not, write to the Free
016     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018     */
019    package org.crsh.lang.script;
020    
021    import org.crsh.cli.impl.Delimiter;
022    import org.crsh.cli.impl.completion.CompletionMatch;
023    import org.crsh.cli.spi.Completion;
024    import org.crsh.shell.impl.command.RuntimeContextImpl;
025    import org.crsh.shell.impl.command.spi.CommandCreationException;
026    import org.crsh.shell.impl.command.spi.CommandInvoker;
027    import org.crsh.shell.impl.command.spi.ShellCommand;
028    import org.crsh.command.SyntaxException;
029    import org.crsh.repl.Repl;
030    import org.crsh.repl.ReplSession;
031    import org.crsh.shell.ErrorType;
032    import org.crsh.shell.ShellResponse;
033    import org.crsh.repl.EvalResponse;
034    import org.crsh.text.Chunk;
035    import org.crsh.util.Utils;
036    
037    import java.util.logging.Level;
038    import java.util.logging.Logger;
039    
040    /** @author Julien Viet */
041    public class ScriptRepl implements Repl {
042    
043      /** . */
044      private static final ScriptRepl instance = new ScriptRepl();
045    
046      /** . */
047      static final Logger log = Logger.getLogger(ScriptRepl.class.getName());
048    
049      public static ScriptRepl getInstance() {
050        return instance;
051      }
052    
053      private ScriptRepl() {
054      }
055    
056      @Override
057      public boolean isActive() {
058        return true;
059      }
060    
061      public String getName() {
062        return "script";
063      }
064    
065      @Override
066      public String getDescription() {
067        return "The Script repl provides command line interpreter with a bash like syntax";
068      }
069    
070      public EvalResponse eval(ReplSession session, String request) {
071        PipeLineFactory factory;
072        try {
073          factory = Token.parse(request).createFactory();
074        }
075        catch (SyntaxException e) {
076          return new EvalResponse.Response(ShellResponse.error(ErrorType.EVALUATION, e.getMessage()));
077        }
078        if (factory != null) {
079          try {
080            CommandInvoker<Void, Chunk> invoker = factory.create(session);
081            return new EvalResponse.Invoke(invoker);
082          }
083          catch (CommandCreationException e) {
084            log.log(Level.FINER, "Could not create command", e);
085            return new EvalResponse.Response(ShellResponse.unknownCommand(e.getCommandName()));
086          }
087        } else {
088          return new EvalResponse.Response(ShellResponse.noCommand());
089        }
090      }
091    
092      public CompletionMatch complete(ReplSession session, String prefix) {
093        Token ast = Token.parse(prefix);
094        String termPrefix;
095        if (ast != null) {
096          Token last = ast.getLast();
097          termPrefix = Utils.trimLeft(last.value);
098        } else {
099          termPrefix = "";
100        }
101    
102        //
103        log.log(Level.FINE, "Retained term prefix is " + termPrefix);
104        CompletionMatch completion;
105        int pos = termPrefix.indexOf(' ');
106        if (pos == -1) {
107          Completion.Builder builder = Completion.builder(termPrefix);
108          for (String name : session.getCommandNames()) {
109            if (name.startsWith(termPrefix)) {
110              builder.add(name.substring(termPrefix.length()), true);
111            }
112          }
113          completion = new CompletionMatch(Delimiter.EMPTY, builder.build());
114        } else {
115          String commandName = termPrefix.substring(0, pos);
116          termPrefix = termPrefix.substring(pos);
117          try {
118            ShellCommand<?> command = session.getCommand(commandName);
119            if (command != null) {
120              completion = command.complete(new RuntimeContextImpl(session, session.getContext().getAttributes()), termPrefix);
121            } else {
122              completion = new CompletionMatch(Delimiter.EMPTY, Completion.create());
123            }
124          }
125          catch (CommandCreationException e) {
126            log.log(Level.FINE, "Could not create command for completion of " + prefix, e);
127            completion = new CompletionMatch(Delimiter.EMPTY, Completion.create());
128          }
129        }
130    
131        //
132        return completion;
133      }
134    }