Package henplus.commands

Source Code of henplus.commands.KeyBindCommand

/*
* This is free software, licensed under the Gnu Public License (GPL) get a copy from <http://www.gnu.org/licenses/gpl.html>
*
* author: Henner Zeller <H.Zeller@acm.org>
*/
package henplus.commands;

import henplus.AbstractCommand;
import henplus.CommandDispatcher;
import henplus.HenPlus;
import henplus.SQLSession;
import henplus.io.ConfigurationContainer;
import henplus.view.Column;
import henplus.view.ColumnMetaData;
import henplus.view.TableRenderer;
import henplus.view.util.NameCompleter;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.StringTokenizer;
import java.util.TreeMap;

import org.gnu.readline.Readline;

/**
* Command to bind function keys to commands.
*/
public class KeyBindCommand extends AbstractCommand {

    private static final String KEYBIND_FILENAME = "key-bindings";
    private static final ColumnMetaData[] DRV_META;
    static {
        DRV_META = new ColumnMetaData[2];
        DRV_META[0] = new ColumnMetaData("Key");
        DRV_META[1] = new ColumnMetaData("execute command");
    }

    private final ConfigurationContainer _config;

    /** Map from keyname to readline names */
    private final Map<String, String[]> _keyNames;
    private final NameCompleter _functionKeyNameCompleter;
    /** map from keyname to binding name */
    private final Map<String, String> _bindings;

    /**
     * returns the command-strings this command can handle.
     */
    @Override
    public String[] getCommandList() {
        return new String[] { "list-key-bindings", "bind-key-cmd",
        // "unbind-key",
        // "test-bind-all" // uncomment for tests.
        };
    }

    public KeyBindCommand(final HenPlus henplus) {
        _keyNames = new HashMap<String, String[]>();
        // -- there are different mappings for some function keys and terminals
        _keyNames.put("F1", new String[] { "\"\\e[11~\"", "\"\\e[[a\"", "\"\\eOP\"" });
        _keyNames.put("Shift-F1", new String[] { "\"\\e[25~\"", "\"\\eO2P\"" });
        _keyNames.put("F2", new String[] { "\"\\e[12~\"", "\"\\e[[b\"", "\"\\eOQ\"" });
        _keyNames.put("Shift-F2", new String[] { "\"\\e[26~\"", "\"\\eO2Q\"" });
        _keyNames.put("F3", new String[] { "\"\\e[13~\"", "\"\\e[[c\"", "\"\\eOR\"" });
        _keyNames.put("Shift-F3", new String[] { "\"\\e[28~\"", "\"\\eO2R\"" });
        _keyNames.put("F4", new String[] { "\"\\e[14~\"", "\"\\e[[d\"", "\"\\eOS\"" });
        _keyNames.put("Shift-F4", new String[] { "\"\\e[29~\"", "\"\\eO2S\"" });
        _keyNames.put("F5", new String[] { "\"\\e[15~\"", "\"\\e[[e\"" });
        _keyNames.put("Shift-F5", new String[] { "\"\\e[15;2~\"", "\"\\e[31~\"" });
        _keyNames.put("F6", new String[] { "\"\\e[17~\"" });
        _keyNames.put("Shift-F6", new String[] { "\"\\e[17;2~\"", "\"\\e[32~\"" });
        _keyNames.put("F7", new String[] { "\"\\e[18~\"" });
        _keyNames.put("Shift-F7", new String[] { "\"\\e[18;2~\"", "\"\\e[33~\"" });
        _keyNames.put("F8", new String[] { "\"\\e[19~\"" });
        _keyNames.put("Shift-F8", new String[] { "\"\\e[19;2~\"", "\"\\e[34~\"" });
        // for the linux console, there seem no bindings for F9-F12
        _keyNames.put("F9", new String[] { "\"\\e[20~\"" });
        _keyNames.put("Shift-F9", new String[] { "\"\\e[20;2~\"" });
        _keyNames.put("F10", new String[] { "\"\\e[21~\"" });
        _keyNames.put("Shift-F10", new String[] { "\"\\e[21;2~\"" });
        _keyNames.put("F11", new String[] { "\"\\e[23~\"" });
        _keyNames.put("Shift-F11", new String[] { "\"\\e[23;2~\"" });
        _keyNames.put("F12", new String[] { "\"\\e[24~\"" });
        _keyNames.put("Shift-F12", new String[] { "\"\\e[24;2~\"" });
        _functionKeyNameCompleter = new NameCompleter(_keyNames.keySet());
        _config = henplus.createConfigurationContainer(KEYBIND_FILENAME);
        _bindings = new TreeMap<String, String>();
        bindKey("F1", "help\n"); // a common default binding.
        load();
    }

    /**
     * execute the command given.
     */
    @Override
    public int execute(final SQLSession session, final String cmd, final String param) {
        final StringTokenizer st = new StringTokenizer(param);
        final int argc = st.countTokens();

        if ("list-key-bindings".equals(cmd)) {
            if (argc != 0) {
                return SYNTAX_ERROR;
            }
            showKeyBindings();
            return SUCCESS;
        } else if ("test-bind-all".equals(cmd)) {
            testBindAll();
            return SUCCESS;
        } else /* bind-key-cmd-string */{
            if (!st.hasMoreTokens()) {
                return SYNTAX_ERROR;
            }

            String key = st.nextToken();
            key = _functionKeyNameCompleter.findCaseInsensitive(key);
            if (key == null) {
                return SYNTAX_ERROR;
            }

            String value = param.substring(key.length() + 1).trim();
            value = stripQuotes(value);
            if (value.length() == 0) {
                return SYNTAX_ERROR;
            }

            return bindKey(key, value) ? SUCCESS : EXEC_FAILED;
        }
    }

    @Override
    public Iterator<String> complete(final CommandDispatcher disp, final String partialCommand, final String lastWord) {
        if (argumentCount(partialCommand) > ("".equals(lastWord) ? 1 : 2)) {
            return null;
        }
        return _functionKeyNameCompleter.getAlternatives(lastWord);
    }

    private String stripQuotes(String value) {
        if (value.length() < 2) {
            return value;
        }
        if (value.startsWith("\"") && value.endsWith("\"")) {
            value = value.substring(1, value.length() - 1);
        } else if (value.startsWith("\'") && value.endsWith("\'")) {
            value = value.substring(1, value.length() - 1);
        }
        return value;
    }

    /**
     * For tests: bind the key to its name representation.
     */
    private void testBindAll() {
        for (String keyName : _keyNames.keySet()) {
            bindKey(keyName, keyName);
        }
    }

    /**
     * Bind a key with the symbolic name to the given string.
     */
    private boolean bindKey(final String keyName, final String cmd) {
        final String[] terminalValues = _keyNames.get(keyName);
        if (terminalValues == null) {
            return false;
        }
        _bindings.put(keyName, cmd);

        /* quote "-characters */
        final StringBuilder binding = new StringBuilder();
        int pos = 0;
        int nowPos = 0;
        while ((nowPos = cmd.indexOf('"', pos)) >= 0) {
            binding.append(cmd.substring(pos, nowPos));
            binding.append("\\\"");
            pos = nowPos + 1;
        }
        if (pos < cmd.length()) {
            binding.append(cmd.substring(pos));
        }

        final String bindCmd = binding.toString();
        for (int i = 0; i < terminalValues.length; ++i) {
            Readline.parseAndBind(terminalValues[i] + ": \"" + bindCmd + "\"");
        }
        return true;
    }

    @Override
    public void shutdown() {
        _config.storeProperties(_bindings, true, "Key-Bindings..");
    }

    /**
     * initial load of key bindings
     */
    private void load() {
        final Map<String,String> bindings = _config.readProperties(_bindings);
        for (Entry<String,String> entry : bindings.entrySet()) {
            bindKey(entry.getKey(), entry.getValue());
        }
    }

    private void showKeyBindings() {
        DRV_META[0].resetWidth();
        DRV_META[1].resetWidth();
        final TableRenderer table = new TableRenderer(DRV_META, HenPlus.out());
        for (Entry<String,String> entry : _bindings.entrySet()) {
            final Column[] row = new Column[2];
            row[0] = new Column(entry.getKey());
            row[1] = new Column(entry.getValue());
            table.addRow(row);
        }
        table.closeTable();
    }

    @Override
    public boolean requiresValidSession(final String cmd) {
        return false;
    }

    /**
     * return a descriptive string.
     */
    @Override
    public String getShortDescription() {
        return "handle function key bindings";
    }

    @Override
    public String getSynopsis(final String cmd) {
        if ("bind-key-cmd".equals(cmd)) {
            return cmd + " <function-key> <command>";
        }
        return cmd;
    }

    @Override
    public String getLongDescription(final String cmd) {
        String dsc = null;
        if ("list-key-bindings".equals(cmd)) {
            dsc = "\tList all key bindings that have been set with\n" + "\tbind-key-cmd";
        } else if ("bind-key-cmd".equals(cmd)) {
            dsc = "\tBind a key to a command. Keys can be the function keys\n" + "\tF1, F2...F12 or Shift-F1...Shift-F12";
        }
        return dsc;
    }
}

/*
* Local variables: c-basic-offset: 4 compile-command:
* "ant -emacs -find build.xml" End:
*/ 
TOP

Related Classes of henplus.commands.KeyBindCommand

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.