File Commands.cpp added (mode: 100644) (index 0000000..87db1e2) |
|
1 |
|
// libvle -- library for building Vim-like applications |
|
2 |
|
// Copyright (C) 2022 xaizek <xaizek@posteo.net> |
|
3 |
|
// |
|
4 |
|
// This file is part of libvle. |
|
5 |
|
// |
|
6 |
|
// libvle is free software: you can redistribute it and/or modify |
|
7 |
|
// it under the terms of the GNU General Public License as published by |
|
8 |
|
// the Free Software Foundation, either version 3 of the License, or |
|
9 |
|
// (at your option) any later version. |
|
10 |
|
// |
|
11 |
|
// libvle is distributed in the hope that it will be useful, |
|
12 |
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 |
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
14 |
|
// GNU General Public License for more details. |
|
15 |
|
// |
|
16 |
|
// You should have received a copy of the GNU General Public License |
|
17 |
|
// along with libvle. If not, see <https://www.gnu.org/licenses/>. |
|
18 |
|
|
|
19 |
|
#include "Commands.hpp" |
|
20 |
|
|
|
21 |
|
#include <cstring> |
|
22 |
|
|
|
23 |
|
#include <deque> |
|
24 |
|
#include <functional> |
|
25 |
|
#include <string> |
|
26 |
|
#include <utility> |
|
27 |
|
#include <vector> |
|
28 |
|
|
|
29 |
|
#include "engine/cmds.h" |
|
30 |
|
|
|
31 |
|
using namespace vle; |
|
32 |
|
|
|
33 |
|
static int completeLine(const char cmd_line[], void *extra_arg); |
|
34 |
|
static int completeArgs(int id, const cmd_info_t *cmd_info, int arg_pos, |
|
35 |
|
void *extra_arg); |
|
36 |
|
static int swapRange(void); |
|
37 |
|
static int resolveMark(char mark); |
|
38 |
|
static char * expandMacros(const char str[], int for_shell, int *usr1, |
|
39 |
|
int *usr2); |
|
40 |
|
static char * expandEnvVars(const char *str); |
|
41 |
|
static void post(int id); |
|
42 |
|
static void selectRange(int id, const cmd_info_t *cmd_info); |
|
43 |
|
static int skipAtBeginning(int id, const char *args); |
|
44 |
|
static int cmdHandler(const cmd_info_t *cmd_info); |
|
45 |
|
|
|
46 |
|
Commands::Commands() |
|
47 |
|
{ |
|
48 |
|
auto conf = new cmds_conf_t(); |
|
49 |
|
conf->complete_line = &completeLine; |
|
50 |
|
conf->complete_args = &completeArgs; |
|
51 |
|
conf->swap_range = &swapRange; |
|
52 |
|
conf->resolve_mark = &resolveMark; |
|
53 |
|
conf->expand_macros = &expandMacros; |
|
54 |
|
conf->expand_envvars = &expandEnvVars; |
|
55 |
|
conf->post = &post; |
|
56 |
|
conf->select_range = &selectRange; |
|
57 |
|
conf->skip_at_beginning = &skipAtBeginning; |
|
58 |
|
|
|
59 |
|
cmds_conf = conf; |
|
60 |
|
} |
|
61 |
|
|
|
62 |
|
Commands::~Commands() |
|
63 |
|
{ |
|
64 |
|
delete static_cast<cmds_conf_t *>(cmds_conf); |
|
65 |
|
} |
|
66 |
|
|
|
67 |
|
bool |
|
68 |
|
Commands::execute(const std::string &cmd) |
|
69 |
|
{ |
|
70 |
|
setup(); |
|
71 |
|
return (vle_cmds_run(cmd.c_str()) >= 0); |
|
72 |
|
} |
|
73 |
|
|
|
74 |
|
void |
|
75 |
|
Commands::setup() |
|
76 |
|
{ |
|
77 |
|
auto conf = static_cast<cmds_conf_t *>(cmds_conf); |
|
78 |
|
if(conf->inner != nullptr) |
|
79 |
|
{ |
|
80 |
|
vle_cmds_init(/*udf=*/1, conf); |
|
81 |
|
return; |
|
82 |
|
} |
|
83 |
|
|
|
84 |
|
vle_cmds_init(/*udf=*/1, conf); |
|
85 |
|
|
|
86 |
|
std::vector<cmd_add_t> cmdsInfo; |
|
87 |
|
cmdsInfo.reserve(commands.size()); |
|
88 |
|
for (auto &cmd : commands) { |
|
89 |
|
cmd_add_t info = {}; |
|
90 |
|
info.name = cmd.name.c_str(); |
|
91 |
|
info.abbr = (cmd.abbr.empty() ? nullptr : cmd.abbr.c_str()); |
|
92 |
|
info.descr = cmd.descr.c_str(); |
|
93 |
|
info.user_data = &cmd; |
|
94 |
|
info.handler = &cmdHandler; |
|
95 |
|
info.min_args = cmd.minArgs; |
|
96 |
|
info.max_args = (cmd.maxArgs < 0 ? NOT_DEF : cmd.maxArgs); |
|
97 |
|
cmdsInfo.push_back(info); |
|
98 |
|
} |
|
99 |
|
|
|
100 |
|
vle_cmds_add(cmdsInfo.data(), cmdsInfo.size()); |
|
101 |
|
} |
|
102 |
|
|
|
103 |
|
void |
|
104 |
|
Commands::addCommand(Command cmd) |
|
105 |
|
{ |
|
106 |
|
commands.push_back(std::move(cmd)); |
|
107 |
|
} |
|
108 |
|
|
|
109 |
|
static int |
|
110 |
|
completeLine(const char cmd_line[], void *extra_arg) |
|
111 |
|
{ return 0; } |
|
112 |
|
|
|
113 |
|
static int |
|
114 |
|
completeArgs(int id, const cmd_info_t *cmd_info, int arg_pos, void *extra_arg) |
|
115 |
|
{ return 0; } |
|
116 |
|
|
|
117 |
|
static int |
|
118 |
|
swapRange(void) |
|
119 |
|
{ return 1; } |
|
120 |
|
|
|
121 |
|
static int |
|
122 |
|
resolveMark(char mark) |
|
123 |
|
{ return -1; } |
|
124 |
|
|
|
125 |
|
static char * |
|
126 |
|
expandMacros(const char str[], int for_shell, int *usr1, int *usr2) |
|
127 |
|
{ return strdup(str); } |
|
128 |
|
|
|
129 |
|
static char * |
|
130 |
|
expandEnvVars(const char *str) |
|
131 |
|
{ return strdup(str); } |
|
132 |
|
|
|
133 |
|
static void |
|
134 |
|
post(int id) |
|
135 |
|
{ } |
|
136 |
|
|
|
137 |
|
static void |
|
138 |
|
selectRange(int id, const cmd_info_t *cmd_info) |
|
139 |
|
{ } |
|
140 |
|
|
|
141 |
|
static int |
|
142 |
|
skipAtBeginning(int id, const char *args) |
|
143 |
|
{ return -1; } |
|
144 |
|
|
|
145 |
|
// Dispatches handler invocations from the C layer. |
|
146 |
|
static int |
|
147 |
|
cmdHandler(const cmd_info_t *cmd_info) |
|
148 |
|
{ |
|
149 |
|
std::vector<std::string> args; |
|
150 |
|
args.reserve(cmd_info->argc); |
|
151 |
|
|
|
152 |
|
for (int i = 0; i < cmd_info->argc; ++i) { |
|
153 |
|
args.push_back(cmd_info->argv[i]); |
|
154 |
|
} |
|
155 |
|
|
|
156 |
|
auto cmd = static_cast<const Command *>(cmd_info->user_data); |
|
157 |
|
cmd->handler(args); |
|
158 |
|
return 0; |
|
159 |
|
} |
File Commands.hpp added (mode: 100644) (index 0000000..3ede6f2) |
|
1 |
|
// libvle -- library for building Vim-like applications |
|
2 |
|
// Copyright (C) 2022 xaizek <xaizek@posteo.net> |
|
3 |
|
// |
|
4 |
|
// This file is part of libvle. |
|
5 |
|
// |
|
6 |
|
// libvle is free software: you can redistribute it and/or modify |
|
7 |
|
// it under the terms of the GNU General Public License as published by |
|
8 |
|
// the Free Software Foundation, either version 3 of the License, or |
|
9 |
|
// (at your option) any later version. |
|
10 |
|
// |
|
11 |
|
// libvle is distributed in the hope that it will be useful, |
|
12 |
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 |
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
14 |
|
// GNU General Public License for more details. |
|
15 |
|
// |
|
16 |
|
// You should have received a copy of the GNU General Public License |
|
17 |
|
// along with libvle. If not, see <https://www.gnu.org/licenses/>. |
|
18 |
|
|
|
19 |
|
#ifndef LIBVLE__COMMANDS_HPP__ |
|
20 |
|
#define LIBVLE__COMMANDS_HPP__ |
|
21 |
|
|
|
22 |
|
#include <deque> |
|
23 |
|
#include <functional> |
|
24 |
|
#include <string> |
|
25 |
|
#include <vector> |
|
26 |
|
|
|
27 |
|
namespace vle { |
|
28 |
|
|
|
29 |
|
// A command. |
|
30 |
|
struct Command |
|
31 |
|
{ |
|
32 |
|
// Canonical (the most complete) type of handler. |
|
33 |
|
using handler_t = void(const std::vector<std::string> &args); |
|
34 |
|
|
|
35 |
|
std::string abbr; // Shortest name (prefix of the longest one). |
|
36 |
|
std::string name; // Longest name. |
|
37 |
|
std::string descr; // Description of the command. |
|
38 |
|
|
|
39 |
|
int minArgs; // Minimal number of arguments (>= 0). |
|
40 |
|
int maxArgs; // Maximum number of arguments or a negative value (means |
|
41 |
|
// "unlimited"). |
|
42 |
|
|
|
43 |
|
std::function<handler_t> handler; // Handler to be called on match. |
|
44 |
|
}; |
|
45 |
|
|
|
46 |
|
// Dispatches command-line commands. |
|
47 |
|
class Commands |
|
48 |
|
{ |
|
49 |
|
public: |
|
50 |
|
// Setups an empty state. |
|
51 |
|
Commands(); |
|
52 |
|
~Commands(); |
|
53 |
|
|
|
54 |
|
Commands(const Commands &rhs) = delete; |
|
55 |
|
Commands(Commands &&rhs) = delete; |
|
56 |
|
Commands & operator=(const Commands &rhs) = delete; |
|
57 |
|
Commands & operator=(Commands &&rhs) = delete; |
|
58 |
|
|
|
59 |
|
public: |
|
60 |
|
// Runs a command. Returns `false` on error (from parser or handler). |
|
61 |
|
bool execute(const std::string &cmd); |
|
62 |
|
|
|
63 |
|
// Registers a shortcut. Throws `std::invalid_argument` if shortcut is too |
|
64 |
|
// long or a duplicate. |
|
65 |
|
void addCommand(Command cmd); |
|
66 |
|
|
|
67 |
|
private: |
|
68 |
|
// Prepares engine for use of this set of commands. |
|
69 |
|
void setup(); |
|
70 |
|
|
|
71 |
|
private: |
|
72 |
|
std::deque<Command> commands; // List of registered commands. |
|
73 |
|
void *cmds_conf; // Settings for the cmds unit. |
|
74 |
|
}; |
|
75 |
|
|
|
76 |
|
} |
|
77 |
|
|
|
78 |
|
#endif // LIBVLE__COMMANDS_HPP__ |
File README.md changed (mode: 100644) (index ac0a57f..51ee1c0) |
1 |
|
**libvle**, _2019_ |
|
|
1 |
|
**libvle**, _2019 – 2022_ |
2 |
2 |
|
|
3 |
|
_This file last updated on 21 April, 2019_ |
|
|
3 |
|
_This file last updated on 7 February, 2022_ |
4 |
4 |
|
|
5 |
5 |
### Brief Description ### |
### Brief Description ### |
6 |
6 |
|
|
|
... |
... |
This is a C++11 library that provides basic classes for implementing Vim-like |
8 |
8 |
behaviour. Although the interface is in C++, core of the implementation is in |
behaviour. Although the interface is in C++, core of the implementation is in |
9 |
9 |
C. |
C. |
10 |
10 |
|
|
11 |
|
VLE stands for Vim-Like Engine. |
|
|
11 |
|
VLE stands for Vim-Like Engine/Experience. |
12 |
12 |
|
|
13 |
13 |
#### Goals #### |
#### Goals #### |
14 |
14 |
|
|
|
... |
... |
over again and instead do it once in a reusable manner. |
17 |
17 |
|
|
18 |
18 |
#### Implementation state #### |
#### Implementation state #### |
19 |
19 |
|
|
20 |
|
It was extracted out of [vifm][vifm] for a couple of projects, has minimally |
|
|
20 |
|
It was extracted out of [Vifm] for a couple of projects, has minimally |
21 |
21 |
necessary functionality and can change quite a bit in the future. The |
necessary functionality and can change quite a bit in the future. The |
22 |
22 |
implementations might diverge as there is currently no synchronization process |
implementations might diverge as there is currently no synchronization process |
23 |
23 |
in place. |
in place. |
|
... |
... |
The API consists of classes in the `vle` namespace. |
41 |
41 |
|
|
42 |
42 |
#### What's available #### |
#### What's available #### |
43 |
43 |
|
|
44 |
|
As noted above, API is extended to accomodate use cases and currently includes |
|
|
44 |
|
As noted above, API is extended to accommodate use cases and currently includes |
45 |
45 |
only: |
only: |
46 |
46 |
|
|
47 |
47 |
* `Modes` -- handles initialization, deinitialization and switching modes |
* `Modes` -- handles initialization, deinitialization and switching modes |
48 |
48 |
* `Mode` -- contains mode configuration |
* `Mode` -- contains mode configuration |
49 |
49 |
* `Shortcut` -- shortcuts with optional support of count |
* `Shortcut` -- shortcuts with optional support of count |
50 |
|
* `KeyDispatcher` -- input processor |
|
|
50 |
|
* `KeyDispatcher` -- input processor for key shortcuts |
|
51 |
|
* `Commands` -- parses and executes a single command-line :command |
51 |
52 |
|
|
52 |
|
#### How to use #### |
|
|
53 |
|
#### How to use shortcut implementation #### |
53 |
54 |
|
|
54 |
|
1. Create `Mode` objects and populate them with `Shortcut` objects. |
|
|
55 |
|
1. Create `Mode` objects and populate them with instances of `Shortcut`. |
55 |
56 |
2. Put `Mode` objects into `Modes`. |
2. Put `Mode` objects into `Modes`. |
56 |
57 |
3. Feed input to `KeyDispatcher`, which will trigger shortcut handlers. |
3. Feed input to `KeyDispatcher`, which will trigger shortcut handlers. |
57 |
58 |
|
|
58 |
|
### Sample ### |
|
|
59 |
|
#### How to use command implementation #### |
|
60 |
|
|
|
61 |
|
1. Create an instance of `Commands` and populate it with `Command` objects. |
|
62 |
|
2. Get :command from somewhere (e.g., user input or file). |
|
63 |
|
3. Pass :command to `Commands`, which will trigger appropriate command handler. |
|
64 |
|
|
|
65 |
|
### Samples ### |
|
66 |
|
|
|
67 |
|
#### Shortcuts example #### |
59 |
68 |
|
|
60 |
69 |
Very minimal application: |
Very minimal application: |
61 |
70 |
|
|
|
... |
... |
main() |
105 |
114 |
} |
} |
106 |
115 |
``` |
``` |
107 |
116 |
|
|
108 |
|
[vifm]: https://vifm.info/ |
|
|
117 |
|
#### Commands example #### |
|
118 |
|
|
|
119 |
|
Very minimal application: |
|
120 |
|
|
|
121 |
|
```cxx |
|
122 |
|
#include <cstdlib> |
|
123 |
|
|
|
124 |
|
#include <iostream> |
|
125 |
|
#include <string> |
|
126 |
|
|
|
127 |
|
#include "vle/Commands.hpp" |
|
128 |
|
|
|
129 |
|
int |
|
130 |
|
main() |
|
131 |
|
{ |
|
132 |
|
bool quit = false; |
|
133 |
|
|
|
134 |
|
vle::Commands commands; |
|
135 |
|
commands.addCommand({ "q", "quit", "exit the app", 0, 0, [&](...) { |
|
136 |
|
quit = true; |
|
137 |
|
}}); |
|
138 |
|
commands.addCommand({ "", "echo", "print arguments", 0, -1, |
|
139 |
|
[&](const std::vector<std::string> &args) { |
|
140 |
|
for (const auto &arg : args) { |
|
141 |
|
std::cout << arg << '\n'; |
|
142 |
|
} |
|
143 |
|
}}); |
|
144 |
|
|
|
145 |
|
for (std::string s; !quit && (std::cout << " User input: ") && |
|
146 |
|
std::getline(std::cin, s); ) { |
|
147 |
|
if (!commands.execute(s)) { |
|
148 |
|
std::cout << "Some kind of error has occurred.\n"; |
|
149 |
|
} |
|
150 |
|
} |
|
151 |
|
|
|
152 |
|
return EXIT_SUCCESS; |
|
153 |
|
} |
|
154 |
|
``` |
|
155 |
|
|
|
156 |
|
[Vifm]: https://vifm.info/ |
File utils/utils.c changed (mode: 100644) (index 4670233..ff04c0c) |
21 |
21 |
#include <stddef.h> /* size_t */ |
#include <stddef.h> /* size_t */ |
22 |
22 |
#include <stdlib.h> /* qsort() */ |
#include <stdlib.h> /* qsort() */ |
23 |
23 |
|
|
24 |
|
#define LOG_ERROR_MSG(...) |
|
25 |
|
|
|
26 |
24 |
void |
void |
27 |
25 |
expand_squotes_escaping(char s[]) |
expand_squotes_escaping(char s[]) |
28 |
26 |
{ |
{ |
|
... |
... |
expand_dquotes_escaping(char s[]) |
68 |
66 |
/* e0 */ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" |
/* e0 */ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" |
69 |
67 |
/* f0 */ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"; |
/* f0 */ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"; |
70 |
68 |
|
|
71 |
|
char *str = s; |
|
72 |
69 |
char *p; |
char *p; |
73 |
70 |
|
|
74 |
71 |
p = s; |
p = s; |
|
... |
... |
expand_dquotes_escaping(char s[]) |
82 |
79 |
s++; |
s++; |
83 |
80 |
if(*s == '\0') |
if(*s == '\0') |
84 |
81 |
{ |
{ |
85 |
|
LOG_ERROR_MSG("Escaped eol in \"%s\"", str); |
|
86 |
82 |
break; |
break; |
87 |
83 |
} |
} |
88 |
84 |
*p++ = table[(int)*s++]; |
*p++ = table[(int)*s++]; |