1
1
mirror of https://github.com/mawww/kakoune.git synced 2024-08-16 16:20:38 +03:00

Also check shell parameters for kak_* references

This makes it easier to pass shell fragments as arguments so that
%sh{ eval "$@" } just works even if arguments refer to Kakoune's
vars.
This commit is contained in:
Maxime Coste 2024-06-07 18:59:30 +10:00
parent 688e87d668
commit 1bdae3f9c4
4 changed files with 48 additions and 25 deletions

View File

@ -3,6 +3,10 @@
This changelog contains major and/or breaking changes to Kakoune between This changelog contains major and/or breaking changes to Kakoune between
released versions. released versions.
== Development version
* Expose env vars that are mentionned in the arguments passed to shell expansions
== Kakoune 2024.05.18 == Kakoune 2024.05.18
* Fixed tests on Alpine Linux and *BSD * Fixed tests on Alpine Linux and *BSD

View File

@ -146,14 +146,16 @@ and unquote them, then execute the resulting `set` command, which sets
the shell's argument variables to the items from `$kak_selections`. The the shell's argument variables to the items from `$kak_selections`. The
`while` loop with `shift` iterates through the arguments one by one. `while` loop with `shift` iterates through the arguments one by one.
Only variables actually mentioned in the body of the shell expansion will Only variables actually mentioned in the body of the shell expansion or
be exported into the shell's environment. For example: in passed arguments will be exported into the shell's environment.
For example:
---- ----
echo %sh{ env | grep ^kak_ } echo %sh{ env | grep ^kak_ }
---- ----
... will find none of Kakoune's special environment variables, but: ... will not find any of Kakoune's special environment variables, but:
---- ----
echo %sh{ env | grep ^kak_ # kak_session } echo %sh{ env | grep ^kak_ # kak_session }
@ -162,6 +164,15 @@ echo %sh{ env | grep ^kak_ # kak_session }
... will find the `$kak_session` variable because it was mentioned by name ... will find the `$kak_session` variable because it was mentioned by name
in a comment, even though it wasn't directly used. in a comment, even though it wasn't directly used.
----
define-command -params .. eval-shell %{ echo %sh{ eval "$@" } }
eval-shell 'echo $kak_session'
----
... will also find the `$kak_session` variable because it was mentioned by name
in the command arguments, which are automatically made available to shell blocks
as "$@"
TIP: These environment variables are also available in other contexts where TIP: These environment variables are also available in other contexts where
Kakoune uses a shell command, such as the `|`, `!` or `$` normal mode commands Kakoune uses a shell command, such as the `|`, `!` or `$` normal mode commands
(See <<keys#,`:doc keys`>>). (See <<keys#,`:doc keys`>>).

View File

@ -45,6 +45,9 @@ struct {
unsigned int version; unsigned int version;
StringView notes; StringView notes;
} constexpr version_notes[] = { { } constexpr version_notes[] = { {
0,
"» kak_* appearing in shell arguments will be added to the environment\n"
}, {
20240518, 20240518,
"» Fix tests failing on some platforms\n" "» Fix tests failing on some platforms\n"
}, { }, {

View File

@ -141,30 +141,35 @@ Shell spawn_shell(const char* shell, StringView cmdline,
} }
template<typename GetValue> template<typename GetValue>
Vector<String> generate_env(StringView cmdline, const Context& context, GetValue&& get_value) Vector<String> generate_env(StringView cmdline, ConstArrayView<String> params, const Context& context, GetValue&& get_value)
{ {
static const Regex re(R"(\bkak_(quoted_)?(\w+)\b)"); static const Regex re(R"(\bkak_(quoted_)?(\w+)\b)");
Vector<String> env; Vector<String> env;
for (auto&& match : RegexIterator{cmdline.begin(), cmdline.end(), re}) auto add_matches = [&](StringView s) {
{ for (auto&& match : RegexIterator{s.begin(), s.end(), re})
StringView name{match[2].first, match[2].second};
StringView shell_name{match[0].first, match[0].second};
auto match_name = [&](const String& s) {
return s.substr(0_byte, shell_name.length()) == shell_name and
s.substr(shell_name.length(), 1_byte) == "=";
};
if (any_of(env, match_name))
continue;
try
{ {
StringView quoted{match[1].first, match[1].second}; StringView name{match[2].first, match[2].second};
Quoting quoting = match[1].matched ? Quoting::Shell : Quoting::Raw; StringView shell_name{match[0].first, match[0].second};
env.push_back(format("kak_{}{}={}", quoted, name, get_value(name, quoting)));
} catch (runtime_error&) {} auto match_name = [&](const String& s) {
} return s.substr(0_byte, shell_name.length()) == shell_name and
s.substr(shell_name.length(), 1_byte) == "=";
};
if (any_of(env, match_name))
continue;
try
{
StringView quoted{match[1].first, match[1].second};
Quoting quoting = match[1].matched ? Quoting::Shell : Quoting::Raw;
env.push_back(format("kak_{}{}={}", quoted, name, get_value(name, quoting)));
} catch (runtime_error&) {}
}
};
add_matches(cmdline);
for (auto&& param : params)
add_matches(param);
return env; return env;
} }
@ -265,13 +270,13 @@ std::pair<String, int> ShellManager::eval(
const DebugFlags debug_flags = context.options()["debug"].get<DebugFlags>(); const DebugFlags debug_flags = context.options()["debug"].get<DebugFlags>();
const bool profile = debug_flags & DebugFlags::Profile; const bool profile = debug_flags & DebugFlags::Profile;
if (debug_flags & DebugFlags::Shell) if (debug_flags & DebugFlags::Shell)
write_to_debug_buffer(format("shell:\n{}\n----\n", cmdline)); write_to_debug_buffer(format("shell:\n{}\n----\nargs: {}\n----\n", cmdline, join(shell_context.params | transform(shell_quote), ' ')));
auto start_time = profile ? Clock::now() : Clock::time_point{}; auto start_time = profile ? Clock::now() : Clock::time_point{};
Optional<CommandFifos> command_fifos; Optional<CommandFifos> command_fifos;
auto kak_env = generate_env(cmdline, context, [&](StringView name, Quoting quoting) { auto kak_env = generate_env(cmdline, shell_context.params, context, [&](StringView name, Quoting quoting) {
if (name == "command_fifo" or name == "response_fifo") if (name == "command_fifo" or name == "response_fifo")
{ {
if (not command_fifos) if (not command_fifos)
@ -377,7 +382,7 @@ std::pair<String, int> ShellManager::eval(
Shell ShellManager::spawn(StringView cmdline, const Context& context, Shell ShellManager::spawn(StringView cmdline, const Context& context,
bool open_stdin, const ShellContext& shell_context) bool open_stdin, const ShellContext& shell_context)
{ {
auto kak_env = generate_env(cmdline, context, [&](StringView name, Quoting quoting) { auto kak_env = generate_env(cmdline, shell_context.params, context, [&](StringView name, Quoting quoting) {
if (auto it = shell_context.env_vars.find(name); it != shell_context.env_vars.end()) if (auto it = shell_context.env_vars.find(name); it != shell_context.env_vars.end())
return it->value; return it->value;
return join(get_val(name, context) | transform(quoter(quoting)), ' ', false); return join(get_val(name, context) | transform(quoter(quoting)), ' ', false);