// libvle -- library for building Vim-like applications
// Copyright (C) 2019 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 "Modes.hpp"
#include <cassert>
#include <cwchar>
#include <iterator>
#include <stdexcept>
#include <utility>
#include <vector>
#include "engine/keys.h"
#include "engine/mode.h"
#include "Mode.hpp"
using namespace vle;
// Dispatches handler invocations from the C layer.
static inline void
keyHandler(key_info_t key_info, keys_info_t */*keys_info*/)
{
auto handler = static_cast<std::function<Shortcut::handler_t> *>(
key_info.user_data
);
(*handler)(key_info.count);
}
Modes::Modes() : modeKeyFlags(1)
{
auto silence = [](int /*more*/) { };
vle_keys_init(1, &modeKeyFlags[0], silence);
}
Modes::~Modes()
{
reset();
}
void
Modes::setModes(std::vector<Mode> modesInfo)
{
if (modesInfo.empty()) {
throw std::invalid_argument("There must be at least one mode");
}
reset();
init(std::move(modesInfo));
}
void
Modes::reset()
{
vle_keys_reset();
modeKeyFlags.clear();
modes.clear();
}
void
Modes::init(std::vector<Mode> &&modesInfo)
{
for (Mode &mode : modesInfo) {
if (!modes.emplace(mode.getId(), std::move(mode)).second) {
throw std::invalid_argument("Duplicated mode id:" + mode.getId());
}
}
modeKeyFlags.reserve(modes.size());
for (const auto &entry : modes) {
modeKeyFlags.push_back(entry.second.usesCount() ? MF_USES_COUNT : 0);
}
auto silence = [](int /*more*/) { };
vle_keys_init(modes.size(), &modeKeyFlags[0], silence);
int modeId = 0;
for (const auto &entry : modes) {
std::vector<keys_add_info_t> keys;
for (const Shortcut &sh : entry.second.getShortcuts()) {
keys_add_info_t addInfo = {};
addInfo.info.data.handler = &keyHandler;
addInfo.info.descr = sh.descr.c_str();
addInfo.info.user_data = const_cast<void *>(
static_cast<const void *>(&sh.handler)
);
for (const std::wstring &lhs : sh.shortcuts) {
std::wcscpy(const_cast<wchar_t *>(addInfo.keys), lhs.c_str());
keys.push_back(addInfo);
}
}
int ret_code = vle_keys_add(&keys[0], keys.size(), modeId++);
assert(ret_code == 0 && "Failed to add builtin keys");
(void)ret_code;
}
}
void
Modes::switchTo(const std::string &modeId)
{
auto it = modes.find(modeId);
if (it == modes.end()) {
throw std::invalid_argument("Unknown mode id:" + modeId);
}
vle_mode_set(std::distance(modes.begin(), it), VMT_PRIMARY);
}
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