All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.codehaus.groovy.tools.shell.InteractiveShellRunner.groovy Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2003-2007 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.codehaus.groovy.tools.shell

import jline.ConsoleReader

import jline.History
import jline.Completor
import jline.MultiCompletor

import org.codehaus.groovy.tools.shell.util.Logger

/**
 * Support for running a {@link Shell} interactively using the JLine library.
 *
 * @version $Id$
 * @author Jason Dillon
 */
class InteractiveShellRunner
    extends ShellRunner
    implements Runnable
{
    final ConsoleReader reader
    
    final Closure prompt
    
    final CommandsMultiCompletor completor
    
    InteractiveShellRunner(final Shell shell, final Closure prompt) {
        super(shell)
        
        this.prompt = prompt
        
        this.reader = new ConsoleReader(shell.io.inputStream, new PrintWriter(shell.io.outputStream, true))

        reader.addCompletor(new ReflectionCompletor(shell))
        this.completor = new CommandsMultiCompletor()
        
        reader.addCompletor(completor)
    }
    
    void run() {
        for (command in shell.registry) {
            completor << command
        }

        // Force things to become clean
        completor.refresh()

        // And then actually run
        adjustHistory()
        super.run()
    }
    
    void setHistory(final History history) {
        reader.history = history
    }
    
    void setHistoryFile(final File file) {
        def dir = file.parentFile
        
        if (!dir.exists()) {
            dir.mkdirs()
            
            log.debug("Created base directory for history file: $dir")
        }
        
        log.debug("Using history file: $file")
        
        reader.history.historyFile = file
    }
    
    protected String readLine() {
        try {
            return reader.readLine(prompt.call())
        }
        catch (StringIndexOutOfBoundsException e) {
            log.debug("HACK: Try and work around GROOVY-2152 for now", e)

            return "";
        }
    }

    @Override
    protected boolean work() {
        boolean result= super.work()
        adjustHistory()

        result
    }

    private void adjustHistory() {
        if (shell instanceof Groovysh) {
            shell.historyFull = shell.history.size() >= shell.history.maxSize
            if (shell.historyFull) shell.evictedLine = shell.history.historyList[0]
        }
    }

}

/**
 * Completor for interactive shells.
 *
 * @version $Id$
 * @author Jason Dillon
 */
class CommandsMultiCompletor
    extends MultiCompletor
{
    protected final Logger log = Logger.create(this.class)
    
    List/**/ list = []
    
    private boolean dirty = false
    
    def leftShift(final Command command) {
        assert command
        
        //
        // FIXME: Need to handle completor removal when things like aliases are rebound
        //
        
        def c = command.completor
        
        if (c) {
            list << c
            
            log.debug("Added completor[${list.size()}] for command: $command.name")
            
            dirty = true
        }
    }

    void refresh() {
        log.debug("Refreshing the completor list")

        completors = list as Completor[]
        dirty = false
    }

    int complete(final String buffer, final int pos, final List cand) {
        assert buffer != null
        
        //
        // FIXME: This is a bit of a hack, I'm too lazy to rewrite a more efficient
        //        completor impl that is more dynamic than the jline.MultiCompletor version
        //        so just re-use it and reset the list as needed
        //

        if (dirty) {
            refresh()
        }
        
        return super.complete(buffer, pos, cand)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy