xaizek / libvle (License: GPLv3+) (since 2019-04-21)
Library for building Vim-like applications.
<root> / Commands.cpp (87db1e2d528921dbe8153cd2509652494d3e0f58) (3,995B) (mode 100644) [raw]
// libvle -- library for building Vim-like applications
// Copyright (C) 2022 xaizek <xaizek@posteo.net>
//
// This file is part of libvle.
//
// libvle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// libvle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with libvle.  If not, see <https://www.gnu.org/licenses/>.

#include "Commands.hpp"

#include <cstring>

#include <deque>
#include <functional>
#include <string>
#include <utility>
#include <vector>

#include "engine/cmds.h"

using namespace vle;

static int completeLine(const char cmd_line[], void *extra_arg);
static int completeArgs(int id, const cmd_info_t *cmd_info, int arg_pos,
                        void *extra_arg);
static int swapRange(void);
static int resolveMark(char mark);
static char * expandMacros(const char str[], int for_shell, int *usr1,
                           int *usr2);
static char * expandEnvVars(const char *str);
static void post(int id);
static void selectRange(int id, const cmd_info_t *cmd_info);
static int skipAtBeginning(int id, const char *args);
static int cmdHandler(const cmd_info_t *cmd_info);

Commands::Commands()
{
    auto conf = new cmds_conf_t();
	conf->complete_line = &completeLine;
	conf->complete_args = &completeArgs;
	conf->swap_range = &swapRange;
	conf->resolve_mark = &resolveMark;
	conf->expand_macros = &expandMacros;
	conf->expand_envvars = &expandEnvVars;
	conf->post = &post;
	conf->select_range = &selectRange;
	conf->skip_at_beginning = &skipAtBeginning;

    cmds_conf = conf;
}

Commands::~Commands()
{
    delete static_cast<cmds_conf_t *>(cmds_conf);
}

bool
Commands::execute(const std::string &cmd)
{
    setup();
    return (vle_cmds_run(cmd.c_str()) >= 0);
}

void
Commands::setup()
{
    auto conf = static_cast<cmds_conf_t *>(cmds_conf);
    if(conf->inner != nullptr)
    {
        vle_cmds_init(/*udf=*/1, conf);
        return;
    }

    vle_cmds_init(/*udf=*/1, conf);

    std::vector<cmd_add_t> cmdsInfo;
    cmdsInfo.reserve(commands.size());
    for (auto &cmd : commands) {
        cmd_add_t info = {};
        info.name = cmd.name.c_str();
        info.abbr = (cmd.abbr.empty() ? nullptr : cmd.abbr.c_str());
        info.descr = cmd.descr.c_str();
        info.user_data = &cmd;
        info.handler = &cmdHandler;
        info.min_args = cmd.minArgs;
        info.max_args = (cmd.maxArgs < 0 ? NOT_DEF : cmd.maxArgs);
        cmdsInfo.push_back(info);
    }

    vle_cmds_add(cmdsInfo.data(), cmdsInfo.size());
}

void
Commands::addCommand(Command cmd)
{
    commands.push_back(std::move(cmd));
}

static int
completeLine(const char cmd_line[], void *extra_arg)
{ return 0; }

static int
completeArgs(int id, const cmd_info_t *cmd_info, int arg_pos, void *extra_arg)
{ return 0; }

static int
swapRange(void)
{ return 1; }

static int
resolveMark(char mark)
{ return -1; }

static char *
expandMacros(const char str[], int for_shell, int *usr1, int *usr2)
{ return strdup(str); }

static char *
expandEnvVars(const char *str)
{ return strdup(str); }

static void
post(int id)
{ }

static void
selectRange(int id, const cmd_info_t *cmd_info)
{ }

static int
skipAtBeginning(int id, const char *args)
{ return -1; }

// Dispatches handler invocations from the C layer.
static int
cmdHandler(const cmd_info_t *cmd_info)
{
    std::vector<std::string> args;
    args.reserve(cmd_info->argc);

    for (int i = 0; i < cmd_info->argc; ++i) {
        args.push_back(cmd_info->argv[i]);
    }

    auto cmd = static_cast<const Command *>(cmd_info->user_data);
    cmd->handler(args);
    return 0;
}
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/libvle

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/libvle

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master