Merge branch 'master' into ranked-word-completion

This commit is contained in:
Maxime Coste 2015-10-27 13:33:15 +00:00
commit 2eba789610
16 changed files with 264 additions and 160 deletions

View File

@ -787,6 +787,7 @@ attributes is a string of letters each defining an attributes:
* `B`: Blink * `B`: Blink
* `d`: Dim * `d`: Dim
* `i`: Italic * `i`: Italic
* `e`: Exclusive, override previous faces instead of merging with them
Using named faces instead of facespec permits to change the effective faces Using named faces instead of facespec permits to change the effective faces
afterwards. afterwards.

View File

@ -68,17 +68,6 @@ def -hidden _c-family-indent-on-closing-curly-brace %[
try %[ exec -draft "hm;<a-?>(class|struct|union)<ret><a-k>\`(class|struct|union)[^{}\n]+(\n)?\s*\{\'<ret><a-;>ma;<esc>" ] try %[ exec -draft "hm;<a-?>(class|struct|union)<ret><a-k>\`(class|struct|union)[^{}\n]+(\n)?\s*\{\'<ret><a-;>ma;<esc>" ]
] ]
decl str c_astyle_options ""
def c-format-astyle -docstring "Format C/C++/Obj-C code using the astyle utility" %{
%sh{
readonly x=$((kak_cursor_column - 1))
readonly y="${kak_cursor_line}"
echo "exec -draft %{%|astyle<space>${kak_opt_c_astyle_options// /<space>}<ret>}"
echo "exec gg ${y}g ${x}l"
}
}
# Regions definition are the same between c++ and objective-c # Regions definition are the same between c++ and objective-c
%sh{ %sh{
for ft in c cpp objc; do for ft in c cpp objc; do
@ -135,7 +124,7 @@ hook global WinSetOption filetype=(c|cpp|objc) %[
alias window comment-selection c-family-comment-selection alias window comment-selection c-family-comment-selection
alias window comment-line c-family-comment-line alias window comment-line c-family-comment-line
alias window format-code c-format-astyle set window formatcmd "astyle"
] ]
hook global WinSetOption filetype=(?!(c|cpp|objc)$).* %[ hook global WinSetOption filetype=(?!(c|cpp|objc)$).* %[
@ -145,8 +134,6 @@ hook global WinSetOption filetype=(?!(c|cpp|objc)$).* %[
unalias window alt c-family-alternative-file unalias window alt c-family-alternative-file
unalias window comment-selection c-family-comment-selection unalias window comment-selection c-family-comment-selection
unalias window comment-line c-family-comment-line unalias window comment-line c-family-comment-line
unalias window format-code c-format-astyle
] ]
hook global WinSetOption filetype=c %[ addhl ref c ] hook global WinSetOption filetype=c %[ addhl ref c ]

View File

@ -70,17 +70,6 @@ def -hidden _dlang-indent-on-closing-curly-brace %[
try %[ exec -itersel -draft <a-h><a-k>^\h+\}$<ret>hms\`|.\'<ret>1<a-&> ] try %[ exec -itersel -draft <a-h><a-k>^\h+\}$<ret>hms\`|.\'<ret>1<a-&> ]
] ]
decl str dlang_dfmt_options ""
def dlang-format-dfmt -docstring "Format the code using the dfmt utility" %{
%sh{
readonly x=$((kak_cursor_column - 1))
readonly y="${kak_cursor_line}"
echo "exec -draft %{%|dfmt<space>${kak_opt_dlang_dfmt_options// /<space>}<ret>}"
echo "exec gg ${y}g ${x}l"
}
}
# Initialization # Initialization
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾ # ‾‾‾‾‾‾‾‾‾‾‾‾‾‾
@ -93,7 +82,7 @@ hook global WinSetOption filetype=dlang %{
hook window InsertChar \{ -group dlang-indent _dlang-indent-on-opening-curly-brace hook window InsertChar \{ -group dlang-indent _dlang-indent-on-opening-curly-brace
hook window InsertChar \} -group dlang-indent _dlang-indent-on-closing-curly-brace hook window InsertChar \} -group dlang-indent _dlang-indent-on-closing-curly-brace
alias window format-code dlang-format-dfmt set window formatcmd "dfmt"
} }
hook global WinSetOption filetype=(?!dlang).* %{ hook global WinSetOption filetype=(?!dlang).* %{
@ -101,6 +90,4 @@ hook global WinSetOption filetype=(?!dlang).* %{
rmhooks window dlang-hooks rmhooks window dlang-hooks
rmhooks window dlang-indent rmhooks window dlang-indent
unalias window format-code dlang-format-dfmt
} }

14
rc/formatter.kak Normal file
View File

@ -0,0 +1,14 @@
decl str formatcmd ""
def format -docstring "Format the entire buffer with an external utility" %{
%sh{
if [ ! -z "${kak_opt_formatcmd}" ]; then
## Save the current position of the cursor
readonly x=$((kak_cursor_column - 1))
readonly y="${kak_cursor_line}"
echo "exec -draft %{%|${kak_opt_formatcmd// /<space>}<ret>}"
## Try to restore the position of the cursor as it was prior to formatting
echo "exec gg ${y}g ${x}l"
fi
}
}

View File

@ -62,16 +62,6 @@ def -hidden _golang-indent-on-closing-curly-brace %[
try %[ exec -itersel -draft <a-h><a-k>^\h+\}$<ret>hms\`|.\'<ret>1<a-&> ] try %[ exec -itersel -draft <a-h><a-k>^\h+\}$<ret>hms\`|.\'<ret>1<a-&> ]
] ]
def golang-format-gofmt -docstring "Format the code using the gofmt utility" %{
%sh{
readonly x=$((kak_cursor_column - 1))
readonly y="${kak_cursor_line}"
echo "exec -draft %{%|gofmt<ret>}"
echo "exec gg ${y}g ${x}l"
}
}
# Initialization # Initialization
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾ # ‾‾‾‾‾‾‾‾‾‾‾‾‾‾
@ -84,7 +74,7 @@ hook global WinSetOption filetype=golang %{
hook window InsertChar \{ -group golang-indent _golang-indent-on-opening-curly-brace hook window InsertChar \{ -group golang-indent _golang-indent-on-opening-curly-brace
hook window InsertChar \} -group golang-indent _golang-indent-on-closing-curly-brace hook window InsertChar \} -group golang-indent _golang-indent-on-closing-curly-brace
alias window format-code golang-format-gofmt set window formatcmd "gofmt"
} }
hook global WinSetOption filetype=(?!golang).* %{ hook global WinSetOption filetype=(?!golang).* %{
@ -92,6 +82,4 @@ hook global WinSetOption filetype=(?!golang).* %{
rmhooks window golang-hooks rmhooks window golang-hooks
rmhooks window golang-indent rmhooks window golang-indent
unalias window format-code golang-format-gofmt
} }

118
rc/perl.kak Normal file
View File

@ -0,0 +1,118 @@
# https://www.perl.org/
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
# Detection
# ‾‾‾‾‾‾‾‾‾
hook global BufSetOption mimetype=text/x-perl %{
set buffer filetype perl
}
hook global BufCreate .*\.pl %{
set buffer filetype perl
}
# Highlighters
# ‾‾‾‾‾‾‾‾‾‾‾‾
addhl -group / regions -default code perl \
command '(?:[^\$]|^)`' '`' '' \
command '\<qx/' (?<!\\)(\\\\)*/ '' \
double_string '(?:[^\$]|^)"' (?<!\\)(\\\\)*" '' \
double_string '\<q(q|w)/' (?<!\\)(\\\\)*/ '' \
single_string "(?:[^\$]|^)'" (?<!\\)(\\\\)*' '' \
single_string "\<q/" (?<!\\)(\\\\)*/ '' \
comment '(?:[^\$]|^)#' $ ''
addhl -group /perl/command fill magenta
addhl -group /perl/double_string fill string
addhl -group /perl/single_string fill string
addhl -group /perl/comment fill comment
addhl -group /perl/code regex \<__(DATA|END|FILE|LINE|PACKAGE)__\> 0:value
addhl -group /perl/code regex \<(ARGV|STDERR|STDOUT|ARGVOUT|STDIN)\> 0:value
addhl -group /perl/code regex (?!\$)-?([0-9]*\.(?!0[xXbB]))?\<([0-9]+|0[xX][0-9a-fA-F]+|0[bb][01_]+)\.?([eE][+-]?[0-9]+)?i?\> 0:value
addhl -group /perl/code regex %{\$!|\$"|\$#|\$\$|\$%|\$&|\$'|\$\(|\$\)|\$\*|\$\+|\$,|\$_|\$-|\$`|\$\.|\$/|\$:|\$;|\$<|\$=|\$>|\$\?|\$@|\$\[|\$\\|\$\]|\$\^|\$\||\$~|%!|@\+|@-|@_} 0:value
addhl -group /perl/code regex (%ENV|%INC|%OVERLOAD|%SIG|@ARGV|@INC|@LAST_MATCH_START) 0:value
addhl -group /perl/code regex %{%\^(H)\>} 0:value
addhl -group /perl/code regex \$\^(S|T|V|W|X|A|C|D|E|F|H|I|L|M|N|O|P|R)\> 0:value
addhl -group /perl/code regex \$\^(RE_TRIE_MAXBUF|TAINT|UNICODE|UTF8LOCALE|WARNING_BITS|WIDE_SYSTEM_CALLS|CHILD_ERROR_NATIVE|ENCODING|OPEN|RE_DEBUG_FLAGS)\> 0:value
addhl -group /perl/code regex \$[0-9]+ 0:attribute
addhl -group /perl/code regex \<-(B|b|C|c|d|e|f|g|k|l|M|O|o|p|r|R|S|s|T|t|u|w|W|X|x|z)\> 0:attribute
addhl -group /perl/code regex \<(END|AUTOLOAD|BEGIN|CHECK|UNITCHECK|INIT|DESTROY)\> 0:attribute
addhl -group /perl/code regex \<(length|setpgrp|endgrent|link|setpriority|endhostent|listen|setprotoent|endnetent|local|setpwent)\> 0:attribute
addhl -group /perl/code regex \<(endprotoent|localtime|setservent|endpwent|log|setsockopt|endservent|lstat|shift|eof|map|shmctl|eval|mkdir|shmget|exec|msgctl|shmread)\> 0:attribute
addhl -group /perl/code regex \<(exists|msgget|shmwrite|msgrcv|shutdown|fcntl|msgsnd|sin|fileno|sleep|flock|next|socket|fork|socketpair|format|oct|sort)\> 0:attribute
addhl -group /perl/code regex \<(formline|open|splice|getc|opendir|split|getgrent|ord|sprintf|getgrgid|our|sqrt|getgrnam|pack|srand|gethostbyaddr|pipe|stat|gethostbyname)\> 0:attribute
addhl -group /perl/code regex \<(pop|state|gethostent|pos|study|getlogin|print|substr|getnetbyaddr|printf|symlink|abs|getnetbyname|prototype|syscall|accept|getnetent)\> 0:attribute
addhl -group /perl/code regex \<(push|sysopen|alarm|getpeername|quotemeta|sysread|atan2|getpgrp|rand|sysseek|getppid|read|system|getpriority|readdir|syswrite|bind)\> 0:attribute
addhl -group /perl/code regex \<(getprotobyname|readline|tell|binmode|getprotobynumber|readlink|telldir|bless|getprotoent|readpipe|tie|getpwent|recv|tied|caller)\> 0:attribute
addhl -group /perl/code regex \<(getpwnam|redo|time|chdir|getpwuid|ref|times|getservbyname|rename|truncate|chmod|getservbyport|require|uc|chomp|getservent|reset|ucfirst)\> 0:attribute
addhl -group /perl/code regex \<(chop|getsockname|umask|chown|getsockopt|reverse|undef|chr|glob|rewinddir|chroot|gmtime|rindex|unlink|close|rmdir|unpack)\> 0:attribute
addhl -group /perl/code regex \<(closedir|grep|say|unshift|connect|hex|scalar|untie|cos|index|seek|use|crypt|seekdir|utime|dbmclose|int|select|values|dbmopen|ioctl|semctl)\> 0:attribute
addhl -group /perl/code regex \<(vec|defined|join|semget|wait|delete|keys|semop|waitpid|kill|send|wantarray|die|last|setgrent|warn|dump|lc|sethostent|write|each|lcfirst|setnetent)\> 0:attribute
addhl -group /perl/code regex \<(else|lock|qw|elsif|lt|qx|eq||exp|ne|sub|for|no|my|not|tr|goto|and|foreach|or|break|exit|unless|cmp|ge|package|until|continue|gt|while|if|qq|xor|do|le|qr|return)\> 0:keyword
addhl -group /perl/code regex %{(?:\<[stqrmwy]+)?/[^\n/]*/([msixpodualngecr]+\>)?} 0:magenta
addhl -group /perl/code regex %{(?:\<[stqrmwy]+)?/[^\n/]+/[^\n/]*/([msixpeodualngcr]+\>)?} 0:magenta
addhl -group /perl/code regex \$[a-zA-Z_][a-zA-Z0-9_]* 0:blue
addhl -group /perl/code regex \$(a|b|LAST_REGEXP_CODE_RESULT|LIST_SEPARATOR|MATCH|MULTILINE_MATCHING|NR|OFMT|OFS|ORS|OS_ERROR|OSNAME|OUTPUT_AUTO_FLUSH|OUTPUT_FIELD_SEPARATOR|OUTPUT_RECORD_SEPARATOR)\> 0:value
addhl -group /perl/code regex \$(LAST_REGEXP_CODE_RESULT|LIST_SEPARATOR|MATCH|MULTILINE_MATCHING|NR|OFMT|OFS|ORS|OS_ERROR|OSNAME|OUTPUT_AUTO_FLUSH|OUTPUT_FIELD_SEPARATOR|OUTPUT_RECORD_SEPARATOR|PERL_VERSION|ACCUMULATOR|PERLDB|ARG|PID|ARGV|POSTMATCH|PREMATCH|BASETIME|PROCESS_ID|CHILD_ERROR|PROGRAM_NAME|COMPILING|REAL_GROUP_ID|DEBUGGING|REAL_USER_ID|EFFECTIVE_GROUP_ID|RS|EFFECTIVE_USER_ID|SUBSCRIPT_SEPARATOR|EGID|SUBSEP|ERRNO|SYSTEM_FD_MAX|EUID|UID|EVAL_ERROR|WARNING|EXCEPTIONS_BEING_CAUGHT|EXECUTABLE_NAME|EXTENDED_OS_ERROR|FORMAT_FORMFEED|FORMAT_LINE_BREAK_CHARACTERS|FORMAT_LINES_LEFT|FORMAT_LINES_PER_PAGE|FORMAT_NAME|FORMAT_PAGE_NUMBER|FORMAT_TOP_NAME|GID|INPLACE_EDIT|INPUT_LINE_NUMBER|INPUT_RECORD_SEPARATOR|LAST_MATCH_END|LAST_PAREN_MATCH)\> 0:value
# Commands
# ‾‾‾‾‾‾‾‾
def -hidden _perl-indent-on-new-line %~
eval -draft -itersel %=
# preserve previous line indent
try %{ exec -draft \;K<a-&> }
# indent after lines ending with { or (
try %[ exec -draft k<a-x> <a-k> [{(]\h*$ <ret> j<a-gt> ]
# cleanup trailing white spaces on the previous line
try %{ exec -draft k<a-x> s \h+$ <ret>d }
# align to opening paren of previous line
try %{ exec -draft [( <a-k> \`\([^\n]+\n[^\n]*\n?\' <ret> s \`\(\h*.|.\' <ret> '<a-;>' & }
# copy // comments prefix
try %{ exec -draft \;<c-s>k<a-x> s ^\h*\K/{2,} <ret> y<c-o><c-o>P<esc> }
# indent after a switch's case/default statements
try %[ exec -draft k<a-x> <a-k> ^\h*(case|default).*:$ <ret> j<a-gt> ]
# indent after if|else|while|for
try %[ exec -draft \;<a-F>)MB <a-k> \`(if|else|while|for)\h*\(.*\)\h*\n\h*\n?\' <ret> s \`|.\' <ret> 1<a-&>1<a-space><a-gt> ]
=
~
def -hidden _perl-indent-on-opening-curly-brace %[
# align indent with opening paren when { is entered on a new line after the closing paren
try %[ exec -draft -itersel h<a-F>)M <a-k> \`\(.*\)\h*\n\h*\{\' <ret> s \`|.\' <ret> 1<a-&> ]
]
def -hidden _perl-indent-on-closing-curly-brace %[
# align to opening curly brace when alone on a line
try %[ exec -itersel -draft <a-h><a-k>^\h+\}$<ret>hms\`|.\'<ret>1<a-&> ]
]
# Initialization
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾
hook global WinSetOption filetype=perl %{
addhl ref perl
# cleanup trailing whitespaces when exiting insert mode
hook window InsertEnd .* -group perl-hooks %{ try %{ exec -draft <a-x>s^\h+$<ret>d } }
hook window InsertChar \n -group perl-indent _perl-indent-on-new-line
hook window InsertChar \{ -group perl-indent _perl-indent-on-opening-curly-brace
hook window InsertChar \} -group perl-indent _perl-indent-on-closing-curly-brace
set window formatcmd "perltidy"
}
hook global WinSetOption filetype=(?!perl).* %{
rmhl perl
rmhooks window perl-hooks
rmhooks window perl-indent
}

View File

@ -310,7 +310,7 @@ TokenList parse(StringView line)
if (not str.empty()) if (not str.empty())
result.emplace_back(Token::Type::Raw, start, reader.pos, result.emplace_back(Token::Type::Raw, start, reader.pos,
coord, std::move(unescape(str, "%", '\\'))); coord, unescape(str, "%", '\\'));
} }
if (is_command_separator(*reader)) if (is_command_separator(*reader))
@ -323,8 +323,7 @@ TokenList parse(StringView line)
} }
String expand_token(const Token& token, const Context& context, String expand_token(const Token& token, const Context& context,
ConstArrayView<String> shell_params, const ShellContext& shell_context)
const EnvVarMap& env_vars)
{ {
auto& content = token.content(); auto& content = token.content();
switch (token.type()) switch (token.type())
@ -332,20 +331,20 @@ String expand_token(const Token& token, const Context& context,
case Token::Type::ShellExpand: case Token::Type::ShellExpand:
return ShellManager::instance().eval(content, context, {}, return ShellManager::instance().eval(content, context, {},
ShellManager::Flags::WaitForStdout, ShellManager::Flags::WaitForStdout,
shell_params, env_vars).first; shell_context).first;
case Token::Type::RegisterExpand: case Token::Type::RegisterExpand:
return context.main_sel_register_value(content).str(); return context.main_sel_register_value(content).str();
case Token::Type::OptionExpand: case Token::Type::OptionExpand:
return context.options()[content].get_as_string(); return context.options()[content].get_as_string();
case Token::Type::ValExpand: case Token::Type::ValExpand:
{ {
auto it = env_vars.find(content); auto it = shell_context.env_vars.find(content);
if (it != env_vars.end()) if (it != shell_context.env_vars.end())
return it->value; return it->value;
return ShellManager::instance().get_val(content, context); return ShellManager::instance().get_val(content, context);
} }
case Token::Type::RawEval: case Token::Type::RawEval:
return expand(content, context, shell_params, env_vars); return expand(content, context, shell_context);
case Token::Type::Raw: case Token::Type::Raw:
case Token::Type::RawQuoted: case Token::Type::RawQuoted:
return content; return content;
@ -357,8 +356,7 @@ String expand_token(const Token& token, const Context& context,
} }
String expand(StringView str, const Context& context, String expand(StringView str, const Context& context,
ConstArrayView<String> shell_params, const ShellContext& shell_context)
const EnvVarMap& env_vars)
{ {
Reader reader{str}; Reader reader{str};
String res; String res;
@ -380,7 +378,7 @@ String expand(StringView str, const Context& context,
{ {
res += reader.substr_from(beg); res += reader.substr_from(beg);
Token token = parse_percent_token<true>(reader); Token token = parse_percent_token<true>(reader);
res += expand_token(token, context, shell_params, env_vars); res += expand_token(token, context, shell_context);
beg = (++reader).pos; beg = (++reader).pos;
} }
else else
@ -407,6 +405,7 @@ CommandManager::find_command(const Context& context, const String& name) const
void CommandManager::execute_single_command(CommandParameters params, void CommandManager::execute_single_command(CommandParameters params,
Context& context, Context& context,
const ShellContext& shell_context,
CharCoord pos) const CharCoord pos) const
{ {
if (params.empty()) if (params.empty())
@ -421,7 +420,7 @@ void CommandManager::execute_single_command(CommandParameters params,
{ {
ParametersParser parameter_parser(param_view, ParametersParser parameter_parser(param_view,
command_it->second.param_desc); command_it->second.param_desc);
command_it->second.command(parameter_parser, context); command_it->second.command(parameter_parser, context, shell_context);
} }
catch (runtime_error& error) catch (runtime_error& error)
{ {
@ -431,9 +430,7 @@ void CommandManager::execute_single_command(CommandParameters params,
} }
void CommandManager::execute(StringView command_line, void CommandManager::execute(StringView command_line,
Context& context, Context& context, const ShellContext& shell_context)
ConstArrayView<String> shell_params,
const EnvVarMap& env_vars)
{ {
TokenList tokens = parse<true>(command_line); TokenList tokens = parse<true>(command_line);
if (tokens.empty()) if (tokens.empty())
@ -448,15 +445,14 @@ void CommandManager::execute(StringView command_line,
if (it->type() == Token::Type::CommandSeparator) if (it->type() == Token::Type::CommandSeparator)
{ {
execute_single_command(params, context, command_coord); execute_single_command(params, context, shell_context, command_coord);
params.clear(); params.clear();
} }
// Shell expand are retokenized // Shell expand are retokenized
else if (it->type() == Token::Type::ShellExpand) else if (it->type() == Token::Type::ShellExpand)
{ {
auto shell_tokens = parse<true>(expand_token(*it, context, auto shell_tokens = parse<true>(expand_token(*it, context,
shell_params, shell_context));
env_vars));
it = tokens.erase(it); it = tokens.erase(it);
for (Token& token : shell_tokens) for (Token& token : shell_tokens)
it = ++tokens.emplace(it, std::move(token)); it = ++tokens.emplace(it, std::move(token));
@ -467,10 +463,9 @@ void CommandManager::execute(StringView command_line,
it -= shell_tokens.size() + 1; it -= shell_tokens.size() + 1;
} }
else else
params.push_back(expand_token(*it, context, shell_params, params.push_back(expand_token(*it, context, shell_context));
env_vars));
} }
execute_single_command(params, context, command_coord); execute_single_command(params, context, shell_context, command_coord);
} }
CommandInfo CommandManager::command_info(const Context& context, StringView command_line) const CommandInfo CommandManager::command_info(const Context& context, StringView command_line) const

View File

@ -19,11 +19,15 @@ namespace Kakoune
class Context; class Context;
using CommandParameters = ConstArrayView<String>; using CommandParameters = ConstArrayView<String>;
using Command = std::function<void (const ParametersParser& parser, Context& context)>; using Command = std::function<void (const ParametersParser& parser,
Context& context,
const ShellContext& shell_context)>;
using CommandCompleter = std::function<Completions (const Context& context, using CommandCompleter = std::function<Completions (const Context& context,
CompletionFlags, CompletionFlags,
CommandParameters, CommandParameters,
size_t, ByteCount)>; size_t, ByteCount)>;
using CommandHelper = std::function<String (const Context& context, CommandParameters)>; using CommandHelper = std::function<String (const Context& context, CommandParameters)>;
enum class CommandFlags enum class CommandFlags
@ -61,8 +65,7 @@ class CommandManager : public Singleton<CommandManager>
{ {
public: public:
void execute(StringView command_line, Context& context, void execute(StringView command_line, Context& context,
ConstArrayView<String> shell_params = {}, const ShellContext& shell_context = ShellContext{});
const EnvVarMap& env_vars = EnvVarMap{});
Completions complete(const Context& context, CompletionFlags flags, Completions complete(const Context& context, CompletionFlags flags,
StringView command_line, ByteCount cursor_pos); StringView command_line, ByteCount cursor_pos);
@ -85,7 +88,9 @@ public:
private: private:
void execute_single_command(CommandParameters params, void execute_single_command(CommandParameters params,
Context& context, CharCoord pos) const; Context& context,
const ShellContext& shell_context,
CharCoord pos) const;
struct CommandDescriptor struct CommandDescriptor
{ {
@ -104,8 +109,7 @@ private:
}; };
String expand(StringView str, const Context& context, String expand(StringView str, const Context& context,
ConstArrayView<String> shell_params = {}, const ShellContext& shell_context = ShellContext{});
const EnvVarMap& env_vars = EnvVarMap{});
} }

View File

@ -120,11 +120,11 @@ struct CommandDesc
CommandFlags flags; CommandFlags flags;
CommandHelper helper; CommandHelper helper;
CommandCompleter completer; CommandCompleter completer;
void (*func)(const ParametersParser&, Context&); void (*func)(const ParametersParser&, Context&, const ShellContext&);
}; };
template<bool force_reload> template<bool force_reload>
void edit(const ParametersParser& parser, Context& context) void edit(const ParametersParser& parser, Context& context, const ShellContext&)
{ {
if (parser.positional_count() == 0 and not force_reload) if (parser.positional_count() == 0 and not force_reload)
throw wrong_argument_count(); throw wrong_argument_count();
@ -215,7 +215,7 @@ const CommandDesc force_edit_cmd = {
edit<true> edit<true>
}; };
void write_buffer(const ParametersParser& parser, Context& context) void write_buffer(const ParametersParser& parser, Context& context, const ShellContext&)
{ {
Buffer& buffer = context.buffer(); Buffer& buffer = context.buffer();
@ -256,7 +256,7 @@ const CommandDesc writeall_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser&, Context&){ write_all_buffers(); } [](const ParametersParser&, Context&, const ShellContext&){ write_all_buffers(); }
}; };
const CommandDesc kill_cmd = { const CommandDesc kill_cmd = {
@ -267,7 +267,7 @@ const CommandDesc kill_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser&, Context&){ throw kill_session{}; } [](const ParametersParser&, Context&, const ShellContext&){ throw kill_session{}; }
}; };
template<bool force> template<bool force>
@ -307,7 +307,7 @@ const CommandDesc quit_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser&, Context&){ quit<false>(); } [](const ParametersParser&, Context&, const ShellContext&){ quit<false>(); }
}; };
const CommandDesc force_quit_cmd = { const CommandDesc force_quit_cmd = {
@ -320,7 +320,7 @@ const CommandDesc force_quit_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser&, Context&){ quit<true>(); } [](const ParametersParser&, Context&, const ShellContext&){ quit<true>(); }
}; };
const CommandDesc write_quit_cmd = { const CommandDesc write_quit_cmd = {
@ -331,9 +331,9 @@ const CommandDesc write_quit_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext& shell_context)
{ {
write_buffer(parser, context); write_buffer(parser, context, shell_context);
quit<false>(); quit<false>();
} }
}; };
@ -347,9 +347,9 @@ const CommandDesc force_write_quit_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext& shell_context)
{ {
write_buffer(parser, context); write_buffer(parser, context, shell_context);
quit<true>(); quit<true>();
} }
}; };
@ -362,7 +362,7 @@ const CommandDesc writeall_quit_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
write_all_buffers(); write_all_buffers();
quit<false>(); quit<false>();
@ -377,7 +377,7 @@ const CommandDesc buffer_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
buffer_completer, buffer_completer,
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
Buffer* oldbuf = &context.buffer(); Buffer* oldbuf = &context.buffer();
Buffer& buffer = BufferManager::instance().get_buffer(parser[0]); Buffer& buffer = BufferManager::instance().get_buffer(parser[0]);
@ -392,7 +392,7 @@ const CommandDesc buffer_cmd = {
}; };
template<bool next> template<bool next>
void cycle_buffer(const ParametersParser& parser, Context& context) void cycle_buffer(const ParametersParser& parser, Context& context, const ShellContext&)
{ {
Buffer* oldbuf = &context.buffer(); Buffer* oldbuf = &context.buffer();
auto it = find_if(BufferManager::instance(), auto it = find_if(BufferManager::instance(),
@ -446,7 +446,7 @@ const CommandDesc bufferprev_cmd = {
}; };
template<bool force> template<bool force>
void delete_buffer(const ParametersParser& parser, Context& context) void delete_buffer(const ParametersParser& parser, Context& context, const ShellContext&)
{ {
BufferManager& manager = BufferManager::instance(); BufferManager& manager = BufferManager::instance();
Buffer& buffer = parser.positional_count() == 0 ? context.buffer() : manager.get_buffer(parser[0]); Buffer& buffer = parser.positional_count() == 0 ? context.buffer() : manager.get_buffer(parser[0]);
@ -490,7 +490,7 @@ const CommandDesc namebuf_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
if (not context.buffer().set_name(parser[0])) if (not context.buffer().set_name(parser[0]))
throw runtime_error(format("unable to change buffer name to '{}'", parser[0])); throw runtime_error(format("unable to change buffer name to '{}'", parser[0]));
@ -585,7 +585,7 @@ const CommandDesc add_highlighter_cmd = {
return ""; return "";
}, },
add_highlighter_completer, add_highlighter_completer,
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
HighlighterRegistry& registry = HighlighterRegistry::instance(); HighlighterRegistry& registry = HighlighterRegistry::instance();
@ -616,7 +616,7 @@ const CommandDesc rm_highlighter_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
rm_highlighter_completer, rm_highlighter_completer,
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
StringView path = parser[0]; StringView path = parser[0];
auto sep_it = find(reversed(path), '/'); auto sep_it = find(reversed(path), '/');
@ -661,7 +661,7 @@ const CommandDesc add_hook_cmd = {
} }
return {}; return {};
}, },
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
Regex regex(parser[2].begin(), parser[2].end(), Regex regex(parser[2].begin(), parser[2].end(),
Regex::optimize | Regex::nosubs | Regex::ECMAScript); Regex::optimize | Regex::nosubs | Regex::ECMAScript);
@ -675,8 +675,8 @@ const CommandDesc add_hook_cmd = {
ScopedSetBool disable_history{context.history_disabled()}; ScopedSetBool disable_history{context.history_disabled()};
if (regex_match(param.begin(), param.end(), regex)) if (regex_match(param.begin(), param.end(), regex))
CommandManager::instance().execute(command, context, {}, CommandManager::instance().execute(command, context,
{ { "hook_param", param.str() } }); { {}, { { "hook_param", param.str() } } });
}; };
auto group = parser.get_switch("group").value_or(StringView{}); auto group = parser.get_switch("group").value_or(StringView{});
get_scope(parser[0], context).hooks().add_hook(parser[1], group.str(), hook_func); get_scope(parser[0], context).hooks().add_hook(parser[1], group.str(), hook_func);
@ -705,7 +705,7 @@ const CommandDesc rm_hook_cmd = {
} }
return {}; return {};
}, },
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
get_scope(parser[0], context).hooks().remove_hooks(parser[1]); get_scope(parser[0], context).hooks().remove_hooks(parser[1]);
} }
@ -719,7 +719,7 @@ Vector<String> params_to_shell(const ParametersParser& parser)
return vars; return vars;
} }
void define_command(const ParametersParser& parser, Context& context) void define_command(const ParametersParser& parser, Context& context, const ShellContext&)
{ {
const String& cmd_name = parser[0]; const String& cmd_name = parser[0];
auto& cm = CommandManager::instance(); auto& cm = CommandManager::instance();
@ -737,14 +737,14 @@ void define_command(const ParametersParser& parser, Context& context)
if (parser.get_switch("shell-params")) if (parser.get_switch("shell-params"))
{ {
desc = ParameterDesc{ {}, ParameterDesc::Flags::SwitchesAsPositional }; desc = ParameterDesc{ {}, ParameterDesc::Flags::SwitchesAsPositional };
cmd = [=](const ParametersParser& parser, Context& context) { cmd = [=](const ParametersParser& parser, Context& context, const ShellContext&) {
CommandManager::instance().execute(commands, context, params_to_shell(parser)); CommandManager::instance().execute(commands, context, { params_to_shell(parser) });
}; };
} }
else else
{ {
desc = ParameterDesc{ {}, ParameterDesc::Flags::SwitchesAsPositional, 0, 0 }; desc = ParameterDesc{ {}, ParameterDesc::Flags::SwitchesAsPositional, 0, 0 };
cmd = [=](const ParametersParser& parser, Context& context) { cmd = [=](const ParametersParser& parser, Context& context, const ShellContext&) {
CommandManager::instance().execute(commands, context); CommandManager::instance().execute(commands, context);
}; };
} }
@ -795,13 +795,15 @@ void define_command(const ParametersParser& parser, Context& context)
{ {
if (flags == CompletionFlags::Fast) // no shell on fast completion if (flags == CompletionFlags::Fast) // no shell on fast completion
return Completions{}; return Completions{};
EnvVarMap vars = {
{ "token_to_complete", to_string(token_to_complete) }, ShellContext shell_context{
{ "pos_in_token", to_string(pos_in_token) } params,
{ { "token_to_complete", to_string(token_to_complete) },
{ "pos_in_token", to_string(pos_in_token) } }
}; };
String output = ShellManager::instance().eval(shell_cmd, context, {}, String output = ShellManager::instance().eval(shell_cmd, context, {},
ShellManager::Flags::WaitForStdout, ShellManager::Flags::WaitForStdout,
params, vars).first; shell_context).first;
return Completions{ 0_byte, pos_in_token, split(output, '\n', 0) }; return Completions{ 0_byte, pos_in_token, split(output, '\n', 0) };
}; };
} }
@ -852,7 +854,7 @@ const CommandDesc alias_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
if (not CommandManager::instance().command_defined(parser[2])) if (not CommandManager::instance().command_defined(parser[2]))
throw runtime_error(format("Command '{}' does not exist", parser[2])); throw runtime_error(format("Command '{}' does not exist", parser[2]));
@ -871,7 +873,7 @@ const CommandDesc unalias_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
AliasRegistry& aliases = get_scope(parser[0], context).aliases(); AliasRegistry& aliases = get_scope(parser[0], context).aliases();
if (parser.positional_count() == 3 and if (parser.positional_count() == 3 and
@ -894,7 +896,7 @@ const CommandDesc echo_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
String message = join(parser, ' ', false); String message = join(parser, ' ', false);
if (parser.get_switch("debug")) if (parser.get_switch("debug"))
@ -924,7 +926,7 @@ const CommandDesc debug_cmd = {
auto c = {"info", "buffers", "options", "memory", "shared-strings"}; auto c = {"info", "buffers", "options", "memory", "shared-strings"};
return { 0_byte, cursor_pos, complete(prefix, cursor_pos, c) }; return { 0_byte, cursor_pos, complete(prefix, cursor_pos, c) };
} }), } }),
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
if (parser[0] == "info") if (parser[0] == "info")
{ {
@ -975,7 +977,7 @@ const CommandDesc source_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
filename_completer, filename_completer,
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
String file_content = read_file(parse_filename(parser[0]), true); String file_content = read_file(parse_filename(parser[0]), true);
try try
@ -1016,23 +1018,26 @@ const CommandDesc set_option_cmd = {
CommandParameters params, size_t token_to_complete, CommandParameters params, size_t token_to_complete,
ByteCount pos_in_token) -> Completions ByteCount pos_in_token) -> Completions
{ {
if (token_to_complete == 0) const bool add = params.size() > 1 and params[0] == "-add";
return { 0_byte, params[0].length(), const int start = add ? 1 : 0;
complete(params[0], pos_in_token, scopes) };
else if (token_to_complete == 1) if (token_to_complete == start)
return { 0_byte, params[1].length(), return { 0_byte, params[start].length(),
GlobalScope::instance().option_registry().complete_option_name(params[1], pos_in_token) }; complete(params[start], pos_in_token, scopes) };
else if (token_to_complete == 2 and else if (token_to_complete == start + 1)
GlobalScope::instance().option_registry().option_exists(params[1])) return { 0_byte, params[start + 1].length(),
GlobalScope::instance().option_registry().complete_option_name(params[start + 1], pos_in_token) };
else if (not add and token_to_complete == start + 2 and
GlobalScope::instance().option_registry().option_exists(params[start + 1]))
{ {
OptionManager& options = get_scope(params[0], context).options(); OptionManager& options = get_scope(params[start], context).options();
String val = options[params[1]].get_as_string(); String val = options[params[start + 1]].get_as_string();
if (prefix_match(val, params[2])) if (prefix_match(val, params[start + 2]))
return { 0_byte, params[2].length(), { std::move(val) } }; return { 0_byte, params[start + 2].length(), { std::move(val) } };
} }
return Completions{}; return Completions{};
}, },
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
Option& opt = get_scope(parser[0], context).options().get_local_option(parser[1]); Option& opt = get_scope(parser[0], context).options().get_local_option(parser[1]);
if (parser.get_switch("add")) if (parser.get_switch("add"))
@ -1063,7 +1068,7 @@ const CommandDesc unset_option_cmd = {
GlobalScope::instance().option_registry().complete_option_name(params[1], pos_in_token) }; GlobalScope::instance().option_registry().complete_option_name(params[1], pos_in_token) };
return Completions{}; return Completions{};
}, },
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
if (parser[0] == "global") if (parser[0] == "global")
throw runtime_error("Cannot unset options in global scope"); throw runtime_error("Cannot unset options in global scope");
@ -1093,7 +1098,7 @@ const CommandDesc declare_option_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
Option* opt = nullptr; Option* opt = nullptr;
@ -1171,7 +1176,7 @@ const CommandDesc map_key_cmd = {
} }
return {}; return {};
}, },
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
KeymapManager& keymaps = get_scope(parser[0], context).keymaps(); KeymapManager& keymaps = get_scope(parser[0], context).keymaps();
KeymapMode keymap_mode = parse_keymap_mode(parser[1]); KeymapMode keymap_mode = parse_keymap_mode(parser[1]);
@ -1311,7 +1316,7 @@ const CommandDesc exec_string_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
context_wrap(parser, context, [](const ParametersParser& parser, Context& context) { context_wrap(parser, context, [](const ParametersParser& parser, Context& context) {
KeyList keys; KeyList keys;
@ -1333,7 +1338,7 @@ const CommandDesc eval_string_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
context_wrap(parser, context, [](const ParametersParser& parser, Context& context) { context_wrap(parser, context, [](const ParametersParser& parser, Context& context) {
String command = join(parser, ' ', false); String command = join(parser, ' ', false);
@ -1354,7 +1359,7 @@ const CommandDesc prompt_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& params, Context& context) [](const ParametersParser& params, Context& context, const ShellContext&)
{ {
if (params[1].length() != 1) if (params[1].length() != 1)
throw runtime_error("register name should be a single character"); throw runtime_error("register name should be a single character");
@ -1388,7 +1393,7 @@ const CommandDesc menu_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
const bool with_select_cmds = (bool)parser.get_switch("select-cmds"); const bool with_select_cmds = (bool)parser.get_switch("select-cmds");
const bool markup = (bool)parser.get_switch("markup"); const bool markup = (bool)parser.get_switch("markup");
@ -1434,7 +1439,7 @@ const CommandDesc onkey_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
String reg = parser[0]; String reg = parser[0];
String command = parser[1]; String command = parser[1];
@ -1459,7 +1464,7 @@ const CommandDesc info_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
context.ui().info_hide(); context.ui().info_hide();
if (parser.positional_count() > 0) if (parser.positional_count() > 0)
@ -1501,7 +1506,7 @@ const CommandDesc try_catch_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext& shell_context)
{ {
if (parser.positional_count() == 2) if (parser.positional_count() == 2)
throw wrong_argument_count(); throw wrong_argument_count();
@ -1513,12 +1518,12 @@ const CommandDesc try_catch_cmd = {
CommandManager& command_manager = CommandManager::instance(); CommandManager& command_manager = CommandManager::instance();
try try
{ {
command_manager.execute(parser[0], context); command_manager.execute(parser[0], context, shell_context);
} }
catch (Kakoune::runtime_error& e) catch (Kakoune::runtime_error& e)
{ {
if (do_catch) if (do_catch)
command_manager.execute(parser[2], context); command_manager.execute(parser[2], context, shell_context);
} }
} }
}; };
@ -1538,13 +1543,13 @@ const CommandDesc face_cmd = {
"facespec format is <fg color>[,<bg color>][+<attributes>]\n" "facespec format is <fg color>[,<bg color>][+<attributes>]\n"
"colors are either a color name, or rgb:###### values.\n" "colors are either a color name, or rgb:###### values.\n"
"attributes is a combination of:\n" "attributes is a combination of:\n"
" u: underline, r: reverse, b: bold, B: blink, d: dim\n" " u: underline, r: reverse, b: bold, B: blink, d: dim, e: exclusive\n"
"facespec can as well just be the name of another face" , "facespec can as well just be the name of another face" ,
ParameterDesc{{}, ParameterDesc::Flags::None, 2, 2}, ParameterDesc{{}, ParameterDesc::Flags::None, 2, 2},
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
PerArgumentCommandCompleter({ complete_face, complete_face }), PerArgumentCommandCompleter({ complete_face, complete_face }),
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
FaceRegistry::instance().register_alias(parser[0], parser[1], true); FaceRegistry::instance().register_alias(parser[0], parser[1], true);
@ -1561,7 +1566,7 @@ const CommandDesc set_client_name_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
if (ClientManager::instance().validate_client_name(parser[0])) if (ClientManager::instance().validate_client_name(parser[0]))
context.set_name(parser[0]); context.set_name(parser[0]);
@ -1578,7 +1583,7 @@ const CommandDesc set_register_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
RegisterManager::instance()[parser[0]] = ConstArrayView<String>(parser[1]); RegisterManager::instance()[parser[0]] = ConstArrayView<String>(parser[1]);
} }
@ -1592,7 +1597,7 @@ const CommandDesc select_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
context.selections_write_only() = selection_list_from_string(context.buffer(), parser[0]); context.selections_write_only() = selection_list_from_string(context.buffer(), parser[0]);
} }
@ -1606,7 +1611,7 @@ const CommandDesc change_working_directory_cmd = {
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
filename_completer, filename_completer,
[](const ParametersParser& parser, Context&) [](const ParametersParser& parser, Context&, const ShellContext&)
{ {
if (chdir(parse_filename(parser[0]).c_str()) != 0) if (chdir(parse_filename(parser[0]).c_str()) != 0)
throw runtime_error(format("cannot change to directory '{}'", parser[0])); throw runtime_error(format("cannot change to directory '{}'", parser[0]));
@ -1647,7 +1652,7 @@ void exec_keys(ConstArrayView<Key> keys, Context& context)
void register_commands() void register_commands()
{ {
CommandManager& cm = CommandManager::instance(); CommandManager& cm = CommandManager::instance();
cm.register_command("nop", [](const ParametersParser&, Context&){}, "do nothing", {}); cm.register_command("nop", [](const ParametersParser&, Context&, const ShellContext&){}, "do nothing", {});
auto register_command = [&](const CommandDesc& c) auto register_command = [&](const CommandDesc& c)
{ {

View File

@ -10,12 +10,13 @@ namespace Kakoune
enum class Attribute : int enum class Attribute : int
{ {
Normal = 0, Normal = 0,
Underline = 1 << 1, Exclusive = 1 << 1,
Reverse = 1 << 2, Underline = 1 << 2,
Blink = 1 << 3, Reverse = 1 << 3,
Bold = 1 << 4, Blink = 1 << 4,
Dim = 1 << 5, Bold = 1 << 5,
Italic = 1 << 6, Dim = 1 << 6,
Italic = 1 << 7,
}; };
template<> struct WithBitOps<Attribute> : std::true_type {}; template<> struct WithBitOps<Attribute> : std::true_type {};
@ -45,9 +46,10 @@ constexpr bool operator!=(const Face& lhs, const Face& rhs)
constexpr Face merge_faces(const Face& base, const Face& face) constexpr Face merge_faces(const Face& base, const Face& face)
{ {
return { face.fg == Color::Default ? base.fg : face.fg, return face.attributes & Attribute::Exclusive ?
face.bg == Color::Default ? base.bg : face.bg, face : Face{ face.fg == Color::Default ? base.fg : face.fg,
face.attributes | base.attributes }; face.bg == Color::Default ? base.bg : face.bg,
face.attributes | base.attributes };
} }
} }

View File

@ -24,6 +24,7 @@ static Face parse_face(StringView facedesc)
{ {
switch (*attr_it) switch (*attr_it)
{ {
case 'e': res.attributes |= Attribute::Exclusive; break;
case 'u': res.attributes |= Attribute::Underline; break; case 'u': res.attributes |= Attribute::Underline; break;
case 'r': res.attributes |= Attribute::Reverse; break; case 'r': res.attributes |= Attribute::Reverse; break;
case 'b': res.attributes |= Attribute::Bold; break; case 'b': res.attributes |= Attribute::Bold; break;

View File

@ -485,7 +485,7 @@ HighlighterAndId create_line_highlighter(HighlighterParameters params)
auto func = [=](const Context& context, HighlightFlags flags, auto func = [=](const Context& context, HighlightFlags flags,
DisplayBuffer& display_buffer, BufferRange) DisplayBuffer& display_buffer, BufferRange)
{ {
const LineCount line = str_to_int_ifp(expand(option_name, context, {}, EnvVarMap{})).value_or(0) - 1; const LineCount line = str_to_int_ifp(expand(option_name, context)).value_or(0) - 1;
if (line < 0) if (line < 0)
return; return;
@ -527,7 +527,7 @@ HighlighterAndId create_column_highlighter(HighlighterParameters params)
auto func = [=](const Context& context, HighlightFlags flags, auto func = [=](const Context& context, HighlightFlags flags,
DisplayBuffer& display_buffer, BufferRange) DisplayBuffer& display_buffer, BufferRange)
{ {
const CharCount column = str_to_int_ifp(expand(option_name, context, {}, EnvVarMap{})).value_or(0) - 1; const CharCount column = str_to_int_ifp(expand(option_name, context)).value_or(0) - 1;
if (column < 0) if (column < 0)
return; return;

View File

@ -381,8 +381,7 @@ void pipe(Context& context, NormalParams)
in += '\n'; in += '\n';
auto out = ShellManager::instance().eval( auto out = ShellManager::instance().eval(
real_cmd, context, in, real_cmd, context, in,
ShellManager::Flags::WaitForStdout, ShellManager::Flags::WaitForStdout).first;
{}, EnvVarMap{}).first;
if ((insert_eol or sel.max() == buffer.back_coord()) and if ((insert_eol or sel.max() == buffer.back_coord()) and
out.back() == '\n') out.back() == '\n')
@ -397,8 +396,7 @@ void pipe(Context& context, NormalParams)
for (auto& sel : selections) for (auto& sel : selections)
ShellManager::instance().eval(real_cmd, context, ShellManager::instance().eval(real_cmd, context,
content(buffer, sel), content(buffer, sel),
ShellManager::Flags::None, ShellManager::Flags::None);
{}, EnvVarMap{});
} }
}); });
} }
@ -425,9 +423,8 @@ void insert_output(Context& context, NormalParams)
if (real_cmd.empty()) if (real_cmd.empty())
return; return;
auto str = ShellManager::instance().eval(real_cmd, context, {}, auto str = ShellManager::instance().eval(
ShellManager::Flags::WaitForStdout, real_cmd, context, {}, ShellManager::Flags::WaitForStdout).first;
{}, EnvVarMap{}).first;
ScopedEdition edition(context); ScopedEdition edition(context);
context.selections().insert(str, mode); context.selections().insert(str, mode);
}); });
@ -781,8 +778,7 @@ void keep_pipe(Context& context, NormalParams)
for (auto& sel : context.selections()) for (auto& sel : context.selections())
{ {
if (shell_manager.eval(cmdline, context, content(buffer, sel), if (shell_manager.eval(cmdline, context, content(buffer, sel),
ShellManager::Flags::None, ShellManager::Flags::None).second == 0)
{}, EnvVarMap{}).second == 0)
keep.push_back(sel); keep.push_back(sel);
} }
if (keep.empty()) if (keep.empty())

View File

@ -16,6 +16,7 @@ namespace Kakoune
inline String option_to_string(StringView opt) { return opt.str(); } inline String option_to_string(StringView opt) { return opt.str(); }
inline void option_from_string(StringView str, String& opt) { opt = str.str(); } inline void option_from_string(StringView str, String& opt) { opt = str.str(); }
inline bool option_add(String& opt, const String& val) { opt += val; return not val.empty(); }
inline String option_to_string(int opt) { return to_string(opt); } inline String option_to_string(int opt) { return to_string(opt); }
inline void option_from_string(StringView str, int& opt) { opt = str_to_int(str); } inline void option_from_string(StringView str, int& opt) { opt = str_to_int(str); }

View File

@ -83,7 +83,7 @@ pid_t spawn_process(StringView cmdline, ConstArrayView<String> params, ConstArra
std::pair<String, int> ShellManager::eval( std::pair<String, int> ShellManager::eval(
StringView cmdline, const Context& context, StringView input, StringView cmdline, const Context& context, StringView input,
Flags flags, ConstArrayView<String> params, const EnvVarMap& env_vars) Flags flags, const ShellContext& shell_context)
{ {
static const Regex re(R"(\bkak_(\w+)\b)"); static const Regex re(R"(\bkak_(\w+)\b)");
@ -100,10 +100,10 @@ std::pair<String, int> ShellManager::eval(
if (find_if(kak_env, match_name) != kak_env.end()) if (find_if(kak_env, match_name) != kak_env.end())
continue; continue;
auto var_it = env_vars.find(name); auto var_it = shell_context.env_vars.find(name);
try try
{ {
const String& value = var_it != env_vars.end() ? const String& value = var_it != shell_context.env_vars.end() ?
var_it->value : get_val(name, context); var_it->value : get_val(name, context);
kak_env.push_back(format("kak_{}={}", name, value)); kak_env.push_back(format("kak_{}={}", name, value));
@ -111,7 +111,7 @@ std::pair<String, int> ShellManager::eval(
} }
Pipe child_stdin, child_stdout, child_stderr; Pipe child_stdin, child_stdout, child_stderr;
pid_t pid = spawn_process(cmdline, params, kak_env, pid_t pid = spawn_process(cmdline, shell_context.params, kak_env,
child_stdin, child_stdout, child_stderr); child_stdin, child_stdout, child_stderr);
child_stdin.close_read_fd(); child_stdin.close_read_fd();

View File

@ -14,6 +14,12 @@ class Context;
using EnvVarRetriever = std::function<String (StringView name, const Context&)>; using EnvVarRetriever = std::function<String (StringView name, const Context&)>;
struct ShellContext
{
ConstArrayView<String> params;
EnvVarMap env_vars;
};
class ShellManager : public Singleton<ShellManager> class ShellManager : public Singleton<ShellManager>
{ {
public: public:
@ -28,8 +34,7 @@ public:
std::pair<String, int> eval(StringView cmdline, const Context& context, std::pair<String, int> eval(StringView cmdline, const Context& context,
StringView input = {}, StringView input = {},
Flags flags = Flags::WaitForStdout, Flags flags = Flags::WaitForStdout,
ConstArrayView<String> params = {}, const ShellContext& shell_context = {});
const EnvVarMap& env_vars = EnvVarMap{});
void register_env_var(StringView str, bool prefix, EnvVarRetriever retriever); void register_env_var(StringView str, bool prefix, EnvVarRetriever retriever);
String get_val(StringView name, const Context& context) const; String get_val(StringView name, const Context& context) const;