mirror of
https://github.com/mawww/kakoune.git
synced 2024-12-18 17:02:06 +03:00
Merge branch 'master' into remove-buffer-change-listener
This commit is contained in:
commit
f54f8818c6
@ -313,9 +313,7 @@ String eval_token(const Token& token, Context& context,
|
||||
return ShellManager::instance().eval(content, context, shell_params,
|
||||
env_vars);
|
||||
case Token::Type::RegisterExpand:
|
||||
if (content.length() != 1)
|
||||
throw runtime_error("wrong register name: " + content);
|
||||
return RegisterManager::instance()[content[0]].values(context)[0];
|
||||
return RegisterManager::instance()[content].values(context)[0];
|
||||
case Token::Type::OptionExpand:
|
||||
return context.options()[content].get_as_string();
|
||||
case Token::Type::RawEval:
|
||||
|
@ -484,9 +484,14 @@ CandidateList complete_scope(StringView prefix)
|
||||
const CommandDesc add_hook_cmd = {
|
||||
"hook",
|
||||
nullptr,
|
||||
"hook <switches> <scope> <hook_name> <command>: add <command> to be executed on hook <hook_name> in <scope> context",
|
||||
"hook <switches> <scope> <hook_name> <command>: add <command> in <scope> to be executed on hook <hook_name>\n"
|
||||
"scope can be: \n"
|
||||
" * global: hook is executed for any buffer or window\n"
|
||||
" * buffer: hook is executed only for the current buffer\n"
|
||||
" (and any window for that buffer)\n"
|
||||
" * window: hook is executed only for the current window\n",
|
||||
ParameterDesc{
|
||||
SwitchMap{ { "id", { true, "set hook id" } } },
|
||||
SwitchMap{ { "id", { true, "set hook id, see rmhooks" } } },
|
||||
ParameterDesc::Flags::None, 4, 4
|
||||
},
|
||||
CommandFlags::None,
|
||||
@ -521,7 +526,7 @@ const CommandDesc add_hook_cmd = {
|
||||
const CommandDesc rm_hook_cmd = {
|
||||
"rmhooks",
|
||||
nullptr,
|
||||
"rmhooks <id>: remove all hooks that whose id is <id>",
|
||||
"rmhooks <id>: remove all hooks whose id is <id>",
|
||||
ParameterDesc{ SwitchMap{}, ParameterDesc::Flags::None, 2, 2 },
|
||||
CommandFlags::None,
|
||||
CommandCompleter{},
|
||||
@ -531,18 +536,6 @@ const CommandDesc rm_hook_cmd = {
|
||||
}
|
||||
};
|
||||
|
||||
EnvVarMap params_to_env_var_map(const ParametersParser& parser)
|
||||
{
|
||||
std::unordered_map<String, String> vars;
|
||||
char param_name[] = "param0";
|
||||
for (size_t i = 0; i < parser.positional_count(); ++i)
|
||||
{
|
||||
param_name[sizeof(param_name) - 2] = '0' + i;
|
||||
vars[param_name] = parser[i];
|
||||
}
|
||||
return vars;
|
||||
}
|
||||
|
||||
std::vector<String> params_to_shell(const ParametersParser& parser)
|
||||
{
|
||||
std::vector<String> vars;
|
||||
@ -579,14 +572,6 @@ void define_command(const ParametersParser& parser, Context& context)
|
||||
String commands = parser[1];
|
||||
Command cmd;
|
||||
ParameterDesc desc;
|
||||
if (parser.has_option("env-params"))
|
||||
{
|
||||
desc = ParameterDesc{ SwitchMap{}, ParameterDesc::Flags::SwitchesAsPositional };
|
||||
cmd = [=](const ParametersParser& parser, Context& context) {
|
||||
CommandManager::instance().execute(commands, context, {},
|
||||
params_to_env_var_map(parser));
|
||||
};
|
||||
}
|
||||
if (parser.has_option("shell-params"))
|
||||
{
|
||||
desc = ParameterDesc{ SwitchMap{}, ParameterDesc::Flags::SwitchesAsPositional };
|
||||
@ -669,16 +654,15 @@ const CommandDesc define_command_cmd = {
|
||||
nullptr,
|
||||
"def <switches> <name> <commands>: define a command named <name> corresponding to <commands>",
|
||||
ParameterDesc{
|
||||
SwitchMap{ { "env-params", { false, "pass parameters as env variables param0..paramN" } },
|
||||
{ "shell-params", { false, "pass parameters to each shell escape as $0..$N" } },
|
||||
{ "allow-override", { false, "allow overriding existing command" } },
|
||||
SwitchMap{ { "shell-params", { false, "pass parameters to each shell escape as $0..$N" } },
|
||||
{ "allow-override", { false, "allow overriding an existing command" } },
|
||||
{ "hidden", { false, "do not display the command in completion candidates" } },
|
||||
{ "alias", { true, "define an alias for this command" } },
|
||||
{ "docstring", { true, "define the documentation string for command" } },
|
||||
{ "file-completion", { false, "complete parameters using filename completion" } },
|
||||
{ "client-completion", { false, "complete parameters using client name completion" } },
|
||||
{ "buffer-completion", { false, "complete parameters using buffer name completion" } },
|
||||
{ "shell-completion", { true, "complete the parameters using the given shell-script" } },
|
||||
{ "hidden", { false, "do not display the command as completion candidate" } },
|
||||
{ "alias", { true, "define an alias for this command" } },
|
||||
{ "docstring", { true, "set docstring for command" } } },
|
||||
{ "shell-completion", { true, "complete the parameters using the given shell-script" } } },
|
||||
ParameterDesc::Flags::None,
|
||||
2, 2
|
||||
},
|
||||
@ -718,7 +702,8 @@ const CommandDesc echo_cmd = {
|
||||
const CommandDesc debug_cmd = {
|
||||
"debug",
|
||||
nullptr,
|
||||
"debug <params>...: write debug informations in debug buffer",
|
||||
"debug <command>: write some debug informations in the debug buffer\n"
|
||||
" existing commands: info",
|
||||
ParameterDesc{ SwitchMap{}, ParameterDesc::Flags::SwitchesOnlyAtStart, 1 },
|
||||
CommandFlags::None,
|
||||
CommandCompleter{},
|
||||
@ -816,7 +801,7 @@ const CommandDesc declare_option_cmd = {
|
||||
"decl",
|
||||
nullptr,
|
||||
"decl <type> <name> [value]: declare option <name> of type <type>.\n"
|
||||
"set its initial value to <value> if given\n"
|
||||
"set its initial value to <value> if given and if the option did not exist\n"
|
||||
"Available types:\n"
|
||||
" int: integer\n"
|
||||
" bool: boolean (true/false or yes/no)\n"
|
||||
@ -869,7 +854,6 @@ const CommandDesc declare_option_cmd = {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
KeymapManager& get_keymap_manager(const String& scope, Context& context)
|
||||
{
|
||||
if (prefix_match("global", scope))
|
||||
@ -1064,7 +1048,7 @@ const CommandDesc exec_string_cmd = {
|
||||
const CommandDesc eval_string_cmd = {
|
||||
"eval",
|
||||
nullptr,
|
||||
"eval <switches> <keys>: execute commands as if entered by user",
|
||||
"eval <switches> <commands>...: execute commands as if entered by user",
|
||||
context_wrap_params,
|
||||
CommandFlags::None,
|
||||
CommandCompleter{},
|
||||
@ -1275,9 +1259,7 @@ const CommandDesc set_register_cmd = {
|
||||
CommandCompleter{},
|
||||
[](const ParametersParser& parser, Context& context)
|
||||
{
|
||||
if (parser[0].length() != 1)
|
||||
throw runtime_error("register names are single character");
|
||||
RegisterManager::instance()[parser[0][0]] = memoryview<String>(parser[1]);
|
||||
RegisterManager::instance()[parser[0]] = memoryview<String>(parser[1]);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -451,12 +451,14 @@ public:
|
||||
const bool reverse = (key == Key::BackTab);
|
||||
CandidateList& candidates = m_completions.candidates;
|
||||
// first try, we need to ask our completer for completions
|
||||
bool updated_completions = false;
|
||||
if (candidates.empty())
|
||||
{
|
||||
refresh_completions(CompletionFlags::None);
|
||||
|
||||
if (candidates.empty())
|
||||
return;
|
||||
updated_completions = true;
|
||||
}
|
||||
bool did_prefix = false;
|
||||
if (m_current_completion == -1 and
|
||||
@ -481,7 +483,10 @@ public:
|
||||
m_current_completion = it - candidates.begin();
|
||||
|
||||
CharCount start = line.char_count_to(m_completions.start);
|
||||
did_prefix = prefix != line.substr(start, m_line_editor.cursor_pos() - start);
|
||||
// When we just updated completions, select the common
|
||||
// prefix even if it was the currently entered text.
|
||||
did_prefix = updated_completions or
|
||||
prefix != line.substr(start, m_line_editor.cursor_pos() - start);
|
||||
}
|
||||
}
|
||||
if (not did_prefix)
|
||||
@ -545,6 +550,7 @@ private:
|
||||
{
|
||||
if (not m_completer)
|
||||
return;
|
||||
m_current_completion = -1;
|
||||
const String& line = m_line_editor.line();
|
||||
m_completions = m_completer(context(), flags, line,
|
||||
line.byte_count_to(m_line_editor.cursor_pos()));
|
||||
|
@ -106,7 +106,7 @@ void register_env_vars()
|
||||
}, {
|
||||
"reg_.+",
|
||||
[](StringView name, const Context& context) -> String
|
||||
{ return RegisterManager::instance()[name[4]].values(context)[0]; }
|
||||
{ return RegisterManager::instance()[name.substr(4_byte)].values(context)[0]; }
|
||||
}, {
|
||||
"client_env_.+",
|
||||
[](StringView name, const Context& context) -> String
|
||||
|
@ -140,15 +140,19 @@ static void set_color(WINDOW* window, ColorPair colors)
|
||||
}
|
||||
}
|
||||
|
||||
static sig_atomic_t resize_pending = 0;
|
||||
|
||||
void on_term_resize(int)
|
||||
{
|
||||
ungetch(KEY_RESIZE);
|
||||
resize_pending = 1;
|
||||
EventManager::instance().force_signal(0);
|
||||
}
|
||||
|
||||
static sig_atomic_t ctrl_c_pending = 0;
|
||||
|
||||
void on_sigint(int)
|
||||
{
|
||||
ungetch(CTRL('c'));
|
||||
ctrl_c_pending = 1;
|
||||
EventManager::instance().force_signal(0);
|
||||
}
|
||||
|
||||
@ -267,6 +271,8 @@ void NCursesUI::draw(const DisplayBuffer& display_buffer,
|
||||
const DisplayLine& status_line,
|
||||
const DisplayLine& mode_line)
|
||||
{
|
||||
check_resize();
|
||||
|
||||
LineCount line_index = 0;
|
||||
for (const DisplayLine& line : display_buffer.lines())
|
||||
{
|
||||
@ -315,8 +321,29 @@ void NCursesUI::draw(const DisplayBuffer& display_buffer,
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
void NCursesUI::check_resize()
|
||||
{
|
||||
if (resize_pending)
|
||||
{
|
||||
int fd = open("/dev/tty", O_RDWR);
|
||||
winsize ws;
|
||||
if (ioctl(fd, TIOCGWINSZ, (void*)&ws) == 0)
|
||||
{
|
||||
close(fd);
|
||||
resizeterm(ws.ws_row, ws.ws_col);
|
||||
update_dimensions();
|
||||
}
|
||||
resize_pending = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool NCursesUI::is_key_available()
|
||||
{
|
||||
check_resize();
|
||||
|
||||
if (ctrl_c_pending)
|
||||
return true;
|
||||
|
||||
timeout(0);
|
||||
const int c = getch();
|
||||
if (c != ERR)
|
||||
@ -327,6 +354,14 @@ bool NCursesUI::is_key_available()
|
||||
|
||||
Key NCursesUI::get_key()
|
||||
{
|
||||
check_resize();
|
||||
|
||||
if (ctrl_c_pending)
|
||||
{
|
||||
ctrl_c_pending = false;
|
||||
return ctrl('c');
|
||||
}
|
||||
|
||||
const int c = getch();
|
||||
if (c > 0 and c < 27)
|
||||
{
|
||||
@ -344,18 +379,6 @@ Key NCursesUI::get_key()
|
||||
else
|
||||
return Key::Escape;
|
||||
}
|
||||
else if (c == KEY_RESIZE)
|
||||
{
|
||||
int fd = open("/dev/tty", O_RDWR);
|
||||
winsize ws;
|
||||
if (fd != -1 and ioctl(fd, TIOCGWINSZ, (void*)&ws) == 0)
|
||||
{
|
||||
close(fd);
|
||||
resizeterm(ws.ws_row, ws.ws_col);
|
||||
update_dimensions();
|
||||
}
|
||||
return Key::Invalid;
|
||||
}
|
||||
else switch (c)
|
||||
{
|
||||
case KEY_BACKSPACE: case 127: return Key::Backspace;
|
||||
|
@ -45,7 +45,7 @@ public:
|
||||
|
||||
static void abort();
|
||||
private:
|
||||
friend void on_term_resize(int);
|
||||
void check_resize();
|
||||
void redraw();
|
||||
void draw_line(const DisplayLine& line, CharCount col_index) const;
|
||||
|
||||
|
@ -1078,15 +1078,19 @@ void copy_indent(Context& context, int selection)
|
||||
if (selection == 0)
|
||||
selection = context.selections().main_index() + 1;
|
||||
|
||||
const String& line = buffer[selections[selection-1].min().line];
|
||||
auto ref_line = selections[selection-1].min().line;
|
||||
const String& line = buffer[ref_line];
|
||||
auto it = line.begin();
|
||||
while (it != line.end() and is_horizontal_blank(*it))
|
||||
++it;
|
||||
const String indent{line.begin(), it};
|
||||
const StringView indent = line.substr(0_byte, (int)(it-line.begin()));
|
||||
|
||||
ScopedEdition edition{context};
|
||||
for (auto& l : lines)
|
||||
{
|
||||
if (l == ref_line)
|
||||
continue;
|
||||
|
||||
auto& line = buffer[l];
|
||||
ByteCount i = 0;
|
||||
while (i < line.length() and is_horizontal_blank(line[i]))
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "register_manager.hh"
|
||||
|
||||
#include "assert.hh"
|
||||
#include "id_map.hh"
|
||||
#include "utils.hh"
|
||||
|
||||
namespace Kakoune
|
||||
@ -55,9 +56,25 @@ private:
|
||||
RegisterRetriever m_function;
|
||||
};
|
||||
|
||||
Register& RegisterManager::operator[](char reg)
|
||||
Register& RegisterManager::operator[](StringView reg)
|
||||
{
|
||||
auto& reg_ptr = m_registers[reg];
|
||||
if (reg.length() == 1)
|
||||
return (*this)[reg[0]];
|
||||
|
||||
static const id_map<Codepoint> reg_names = {
|
||||
{ "slash", '/' },
|
||||
{ "dquote", '"' },
|
||||
{ "pipe", '|' }
|
||||
};
|
||||
auto it = reg_names.find(reg);
|
||||
if (it == reg_names.end())
|
||||
throw runtime_error("no such register: " + reg);
|
||||
return (*this)[it->second];
|
||||
}
|
||||
|
||||
Register& RegisterManager::operator[](Codepoint c)
|
||||
{
|
||||
auto& reg_ptr = m_registers[c];
|
||||
if (not reg_ptr)
|
||||
reg_ptr.reset(new StaticRegister());
|
||||
return *reg_ptr;
|
||||
|
@ -16,7 +16,8 @@ using RegisterRetriever = std::function<std::vector<String> (const Context&)>;
|
||||
class RegisterManager : public Singleton<RegisterManager>
|
||||
{
|
||||
public:
|
||||
Register& operator[](char reg);
|
||||
Register& operator[](StringView reg);
|
||||
Register& operator[](Codepoint c);
|
||||
void register_dynamic_register(char reg, RegisterRetriever function);
|
||||
|
||||
protected:
|
||||
|
Loading…
Reference in New Issue
Block a user