xaizek / libvle (License: GPLv3+) (since 2019-04-21)
Library for building Vim-like applications.
<root> / README.md (491162804435f3fa29e48133c3922f830d0d47e1) (4,309B) (mode 100644) [raw]
**libvle**, _2019 – 2022_

_This file last updated on 8 February, 2022_

### Brief Description ###

This is a C++11 library that provides basic classes for implementing Vim-like
behaviour.  Although the interface is in C++, core of the implementation is in
C.

VLE stands for Vim-Like Engine/Experience.

#### Goals ####

The obvious purpose is to avoid reimplementing Vim-like functionality over and
over again and instead do it once in a reusable manner.

#### Implementation state ####

It was extracted out of [Vifm] for a couple of projects, has minimally
necessary functionality and can change quite a bit in the future.  The
implementations might diverge as there is currently no synchronization process
in place.

#### Throw-in library state ####

There is no build system and nothing is getting built for the client.  To use
it clone the repository (possibly as a submodule) and handle the building with
the build system that's used by the main project.  Compile C++ files with C++11
enabled.

Alternatively one can use [xmake] to consume submodule as a subproject (example
assumes it's stored under `libs/`):
```
add_includedirs("libs")
includes("libs/*/xmake.lua")
```

### Prerequisites ###

* C++11 capable compiler

### Structure ###

#### API ####

The API consists of classes in the `vle` namespace.

#### What's available ####

As noted above, API is extended to accommodate use cases and currently includes
only:

 * `Modes` -- handles initialization, deinitialization and switching modes
 * `Mode` -- contains mode configuration
 * `Shortcut` -- shortcuts with optional support of count
 * `KeyDispatcher` -- input processor for key shortcuts
 * `Commands` -- parses and executes a single command-line :command

#### How to use shortcut implementation ####

1. Create `Mode` objects and populate them with instances of `Shortcut`.
2. Put `Mode` objects into `Modes`.
3. Feed input to `KeyDispatcher`, which will trigger shortcut handlers.

#### How to use command implementation ####

1. Create an instance of `Commands` and populate it with `Command` objects.
2. Get :command from somewhere (e.g., user input or file).
3. Pass :command to `Commands`, which will trigger appropriate command handler.

### Samples ###

#### Shortcuts example ####

Very minimal application:

```cxx
#include <cstdlib>

#include <iostream>
#include <string>

#include "vle/KeyDispatcher.hpp"
#include "vle/Mode.hpp"
#include "vle/Modes.hpp"

int
main()
{
    vle::Mode normalMode("normal");
    normalMode.setUsesCount(true);
    normalMode.addShortcut({ L"gg", [&]() {
        std::wcout << L"go to the top\n";
    }, "go to the top" });
    normalMode.addShortcut({ L"j", [&](int i) {
        std::wcout << L"go down " << (i == -1 ? 1 : i) << L" item(s)\n";
    }, "go down" });

    std::vector<vle::Mode> allModes;
    allModes.emplace_back(std::move(normalMode));

    vle::Modes modes;
    modes.setModes(std::move(allModes));
    modes.switchTo("normal");

    vle::KeyDispatcher dispatcher;

    for (std::wstring ws; std::wcout << L"  User input: ",
                          std::getline(std::wcin, ws); ) {
        for (wchar_t wc : ws) {
            std::wcout << L"  > Sending in: " << wc << L'\n';
            dispatcher.dispatch(wc);
            std::wcout << L"  > Buffered: " << dispatcher.getPendingInput()
                       << L'\n';
        }
        std::wcout << L"\n";
    }

    return EXIT_SUCCESS;
}
```

#### Commands example ####

Very minimal application:

```cxx
#include <cstdlib>

#include <iostream>
#include <string>

#include "vle/Commands.hpp"

int
main()
{
    bool quit = false;

    vle::Commands commands;
    commands.addCommand({ "q", "quit", "exit the app", 0, 0, [&](...) {
        quit = true;
    }});
    commands.addCommand({ "", "echo", "print arguments", 0, -1,
                        [&](const std::vector<std::string> &args) {
        for (const auto &arg : args) {
            std::cout << arg << '\n';
        }
    }});

    for (std::string s; !quit && (std::cout << "  User input: ") &&
                        std::getline(std::cin, s); ) {
        if (!commands.execute(s)) {
            std::cout << "Some kind of error has occurred.\n";
        }
    }

    return EXIT_SUCCESS;
}
```

[Vifm]: https://vifm.info/
[xmake]: https://xmake.io/
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