package org.metaborg.spoofax.shell.client.console.impl;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.metaborg.spoofax.shell.client.console.IDisplay;
import org.metaborg.spoofax.shell.client.console.IEditor;
import org.metaborg.spoofax.shell.client.console.IInputHistory;
import org.metaborg.spoofax.shell.client.console.impl.history.JLine2InputHistory;
import org.metaborg.spoofax.shell.client.console.impl.history.JLine2PersistentInputHistory;
import org.metaborg.spoofax.shell.client.console.impl.hooks.ConsoleMessageHook;
import org.metaborg.spoofax.shell.client.console.impl.hooks.ConsoleResultHook;
import org.metaborg.spoofax.shell.core.Repl;
import org.metaborg.spoofax.shell.core.ReplModule;
import org.metaborg.spoofax.shell.hooks.IMessageHook;
import org.metaborg.spoofax.shell.hooks.IResultHook;

import com.google.inject.Provides;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import com.google.inject.name.Names;

/**
 * Bindings for the console REPL.
 */
public class ConsoleReplModule extends ReplModule {

    /**
     * Binds the user interface implementations.
     */
    protected void configureUserInterface() {
        bind(Repl.class).to(ConsoleRepl.class);
        bind(ConsoleRepl.class).in(Singleton.class);
        bind(IInputHistory.class).to(JLine2InputHistory.class);
        bind(JLine2InputHistory.class).to(JLine2PersistentInputHistory.class);

        bind(IEditor.class).to(TerminalUserInterface.class);
        bind(IDisplay.class).to(TerminalUserInterface.class);
        bind(IMessageHook.class).to(ConsoleMessageHook.class);
        bind(IResultHook.class).to(ConsoleResultHook.class);

        bind(InputStream.class).annotatedWith(Names.named("in")).toInstance(System.in);
        bind(OutputStream.class).annotatedWith(Names.named("out")).toInstance(System.out);
        bind(OutputStream.class).annotatedWith(Names.named("err")).toInstance(System.err);

        bindConstant().annotatedWith(Names.named("historyPath"))
            .to(System.getProperty("user.home") + "/.spoofax_history");
    }

    @Override
    protected void configure() {
        super.configure();
        configureUserInterface();
    }

    /**
     * TODO: Replace with "CheckedProvides" because IO in Provider method is bad practice, see:
     * https://github.com/google/guice/wiki/ThrowingProviders.
     *
     * @param in
     *            The {@link InputStream}.
     * @param out
     *            The {@link OutputStream}.
     * @return A {@link jline.console.ConsoleReader} with the given streams.
     * @throws IOException
     *             When an IO error occurs upon construction.
     */
    @Provides
    @Singleton
    protected jline.console.ConsoleReader provideConsoleReader(@Named("in") InputStream in,
                                                               @Named("out") OutputStream out)
        throws IOException {
        return new jline.console.ConsoleReader(in, out);
    }
}

@@ -1443,32 +1443,95 @@
 istory.class);%0A%0A
+        bind(TerminalUserInterface.class).in(Singleton.class);%0A
         bind(IEd

Set TerminalUserInterface to be Singleton scope