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,
|
return ShellManager::instance().eval(content, context, shell_params,
|
||||||
env_vars);
|
env_vars);
|
||||||
case Token::Type::RegisterExpand:
|
case Token::Type::RegisterExpand:
|
||||||
if (content.length() != 1)
|
return RegisterManager::instance()[content].values(context)[0];
|
||||||
throw runtime_error("wrong register name: " + content);
|
|
||||||
return RegisterManager::instance()[content[0]].values(context)[0];
|
|
||||||
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::RawEval:
|
case Token::Type::RawEval:
|
||||||
|
|
|
@ -484,9 +484,14 @@ CandidateList complete_scope(StringView prefix)
|
||||||
const CommandDesc add_hook_cmd = {
|
const CommandDesc add_hook_cmd = {
|
||||||
"hook",
|
"hook",
|
||||||
nullptr,
|
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{
|
ParameterDesc{
|
||||||
SwitchMap{ { "id", { true, "set hook id" } } },
|
SwitchMap{ { "id", { true, "set hook id, see rmhooks" } } },
|
||||||
ParameterDesc::Flags::None, 4, 4
|
ParameterDesc::Flags::None, 4, 4
|
||||||
},
|
},
|
||||||
CommandFlags::None,
|
CommandFlags::None,
|
||||||
|
@ -521,7 +526,7 @@ const CommandDesc add_hook_cmd = {
|
||||||
const CommandDesc rm_hook_cmd = {
|
const CommandDesc rm_hook_cmd = {
|
||||||
"rmhooks",
|
"rmhooks",
|
||||||
nullptr,
|
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 },
|
ParameterDesc{ SwitchMap{}, ParameterDesc::Flags::None, 2, 2 },
|
||||||
CommandFlags::None,
|
CommandFlags::None,
|
||||||
CommandCompleter{},
|
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> params_to_shell(const ParametersParser& parser)
|
||||||
{
|
{
|
||||||
std::vector<String> vars;
|
std::vector<String> vars;
|
||||||
|
@ -579,14 +572,6 @@ void define_command(const ParametersParser& parser, Context& context)
|
||||||
String commands = parser[1];
|
String commands = parser[1];
|
||||||
Command cmd;
|
Command cmd;
|
||||||
ParameterDesc desc;
|
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"))
|
if (parser.has_option("shell-params"))
|
||||||
{
|
{
|
||||||
desc = ParameterDesc{ SwitchMap{}, ParameterDesc::Flags::SwitchesAsPositional };
|
desc = ParameterDesc{ SwitchMap{}, ParameterDesc::Flags::SwitchesAsPositional };
|
||||||
|
@ -669,16 +654,15 @@ const CommandDesc define_command_cmd = {
|
||||||
nullptr,
|
nullptr,
|
||||||
"def <switches> <name> <commands>: define a command named <name> corresponding to <commands>",
|
"def <switches> <name> <commands>: define a command named <name> corresponding to <commands>",
|
||||||
ParameterDesc{
|
ParameterDesc{
|
||||||
SwitchMap{ { "env-params", { false, "pass parameters as env variables param0..paramN" } },
|
SwitchMap{ { "shell-params", { false, "pass parameters to each shell escape as $0..$N" } },
|
||||||
{ "shell-params", { false, "pass parameters to each shell escape as $0..$N" } },
|
{ "allow-override", { false, "allow overriding an existing command" } },
|
||||||
{ "allow-override", { false, "allow overriding 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" } },
|
{ "file-completion", { false, "complete parameters using filename completion" } },
|
||||||
{ "client-completion", { false, "complete parameters using client name completion" } },
|
{ "client-completion", { false, "complete parameters using client name completion" } },
|
||||||
{ "buffer-completion", { false, "complete parameters using buffer name completion" } },
|
{ "buffer-completion", { false, "complete parameters using buffer name completion" } },
|
||||||
{ "shell-completion", { true, "complete the parameters using the given shell-script" } },
|
{ "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" } } },
|
|
||||||
ParameterDesc::Flags::None,
|
ParameterDesc::Flags::None,
|
||||||
2, 2
|
2, 2
|
||||||
},
|
},
|
||||||
|
@ -718,7 +702,8 @@ const CommandDesc echo_cmd = {
|
||||||
const CommandDesc debug_cmd = {
|
const CommandDesc debug_cmd = {
|
||||||
"debug",
|
"debug",
|
||||||
nullptr,
|
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 },
|
ParameterDesc{ SwitchMap{}, ParameterDesc::Flags::SwitchesOnlyAtStart, 1 },
|
||||||
CommandFlags::None,
|
CommandFlags::None,
|
||||||
CommandCompleter{},
|
CommandCompleter{},
|
||||||
|
@ -816,7 +801,7 @@ const CommandDesc declare_option_cmd = {
|
||||||
"decl",
|
"decl",
|
||||||
nullptr,
|
nullptr,
|
||||||
"decl <type> <name> [value]: declare option <name> of type <type>.\n"
|
"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"
|
"Available types:\n"
|
||||||
" int: integer\n"
|
" int: integer\n"
|
||||||
" bool: boolean (true/false or yes/no)\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)
|
KeymapManager& get_keymap_manager(const String& scope, Context& context)
|
||||||
{
|
{
|
||||||
if (prefix_match("global", scope))
|
if (prefix_match("global", scope))
|
||||||
|
@ -1064,7 +1048,7 @@ const CommandDesc exec_string_cmd = {
|
||||||
const CommandDesc eval_string_cmd = {
|
const CommandDesc eval_string_cmd = {
|
||||||
"eval",
|
"eval",
|
||||||
nullptr,
|
nullptr,
|
||||||
"eval <switches> <keys>: execute commands as if entered by user",
|
"eval <switches> <commands>...: execute commands as if entered by user",
|
||||||
context_wrap_params,
|
context_wrap_params,
|
||||||
CommandFlags::None,
|
CommandFlags::None,
|
||||||
CommandCompleter{},
|
CommandCompleter{},
|
||||||
|
@ -1275,9 +1259,7 @@ const CommandDesc set_register_cmd = {
|
||||||
CommandCompleter{},
|
CommandCompleter{},
|
||||||
[](const ParametersParser& parser, Context& context)
|
[](const ParametersParser& parser, Context& context)
|
||||||
{
|
{
|
||||||
if (parser[0].length() != 1)
|
RegisterManager::instance()[parser[0]] = memoryview<String>(parser[1]);
|
||||||
throw runtime_error("register names are single character");
|
|
||||||
RegisterManager::instance()[parser[0][0]] = memoryview<String>(parser[1]);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -451,12 +451,14 @@ public:
|
||||||
const bool reverse = (key == Key::BackTab);
|
const bool reverse = (key == Key::BackTab);
|
||||||
CandidateList& candidates = m_completions.candidates;
|
CandidateList& candidates = m_completions.candidates;
|
||||||
// first try, we need to ask our completer for completions
|
// first try, we need to ask our completer for completions
|
||||||
|
bool updated_completions = false;
|
||||||
if (candidates.empty())
|
if (candidates.empty())
|
||||||
{
|
{
|
||||||
refresh_completions(CompletionFlags::None);
|
refresh_completions(CompletionFlags::None);
|
||||||
|
|
||||||
if (candidates.empty())
|
if (candidates.empty())
|
||||||
return;
|
return;
|
||||||
|
updated_completions = true;
|
||||||
}
|
}
|
||||||
bool did_prefix = false;
|
bool did_prefix = false;
|
||||||
if (m_current_completion == -1 and
|
if (m_current_completion == -1 and
|
||||||
|
@ -481,7 +483,10 @@ public:
|
||||||
m_current_completion = it - candidates.begin();
|
m_current_completion = it - candidates.begin();
|
||||||
|
|
||||||
CharCount start = line.char_count_to(m_completions.start);
|
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)
|
if (not did_prefix)
|
||||||
|
@ -545,6 +550,7 @@ private:
|
||||||
{
|
{
|
||||||
if (not m_completer)
|
if (not m_completer)
|
||||||
return;
|
return;
|
||||||
|
m_current_completion = -1;
|
||||||
const String& line = m_line_editor.line();
|
const String& line = m_line_editor.line();
|
||||||
m_completions = m_completer(context(), flags, line,
|
m_completions = m_completer(context(), flags, line,
|
||||||
line.byte_count_to(m_line_editor.cursor_pos()));
|
line.byte_count_to(m_line_editor.cursor_pos()));
|
||||||
|
|
|
@ -106,7 +106,7 @@ void register_env_vars()
|
||||||
}, {
|
}, {
|
||||||
"reg_.+",
|
"reg_.+",
|
||||||
[](StringView name, const Context& context) -> String
|
[](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_.+",
|
"client_env_.+",
|
||||||
[](StringView name, const Context& context) -> String
|
[](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)
|
void on_term_resize(int)
|
||||||
{
|
{
|
||||||
ungetch(KEY_RESIZE);
|
resize_pending = 1;
|
||||||
EventManager::instance().force_signal(0);
|
EventManager::instance().force_signal(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static sig_atomic_t ctrl_c_pending = 0;
|
||||||
|
|
||||||
void on_sigint(int)
|
void on_sigint(int)
|
||||||
{
|
{
|
||||||
ungetch(CTRL('c'));
|
ctrl_c_pending = 1;
|
||||||
EventManager::instance().force_signal(0);
|
EventManager::instance().force_signal(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,6 +271,8 @@ void NCursesUI::draw(const DisplayBuffer& display_buffer,
|
||||||
const DisplayLine& status_line,
|
const DisplayLine& status_line,
|
||||||
const DisplayLine& mode_line)
|
const DisplayLine& mode_line)
|
||||||
{
|
{
|
||||||
|
check_resize();
|
||||||
|
|
||||||
LineCount line_index = 0;
|
LineCount line_index = 0;
|
||||||
for (const DisplayLine& line : display_buffer.lines())
|
for (const DisplayLine& line : display_buffer.lines())
|
||||||
{
|
{
|
||||||
|
@ -315,8 +321,29 @@ void NCursesUI::draw(const DisplayBuffer& display_buffer,
|
||||||
m_dirty = true;
|
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()
|
bool NCursesUI::is_key_available()
|
||||||
{
|
{
|
||||||
|
check_resize();
|
||||||
|
|
||||||
|
if (ctrl_c_pending)
|
||||||
|
return true;
|
||||||
|
|
||||||
timeout(0);
|
timeout(0);
|
||||||
const int c = getch();
|
const int c = getch();
|
||||||
if (c != ERR)
|
if (c != ERR)
|
||||||
|
@ -327,6 +354,14 @@ bool NCursesUI::is_key_available()
|
||||||
|
|
||||||
Key NCursesUI::get_key()
|
Key NCursesUI::get_key()
|
||||||
{
|
{
|
||||||
|
check_resize();
|
||||||
|
|
||||||
|
if (ctrl_c_pending)
|
||||||
|
{
|
||||||
|
ctrl_c_pending = false;
|
||||||
|
return ctrl('c');
|
||||||
|
}
|
||||||
|
|
||||||
const int c = getch();
|
const int c = getch();
|
||||||
if (c > 0 and c < 27)
|
if (c > 0 and c < 27)
|
||||||
{
|
{
|
||||||
|
@ -344,18 +379,6 @@ Key NCursesUI::get_key()
|
||||||
else
|
else
|
||||||
return Key::Escape;
|
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)
|
else switch (c)
|
||||||
{
|
{
|
||||||
case KEY_BACKSPACE: case 127: return Key::Backspace;
|
case KEY_BACKSPACE: case 127: return Key::Backspace;
|
||||||
|
|
|
@ -45,7 +45,7 @@ public:
|
||||||
|
|
||||||
static void abort();
|
static void abort();
|
||||||
private:
|
private:
|
||||||
friend void on_term_resize(int);
|
void check_resize();
|
||||||
void redraw();
|
void redraw();
|
||||||
void draw_line(const DisplayLine& line, CharCount col_index) const;
|
void draw_line(const DisplayLine& line, CharCount col_index) const;
|
||||||
|
|
||||||
|
|
|
@ -1078,15 +1078,19 @@ void copy_indent(Context& context, int selection)
|
||||||
if (selection == 0)
|
if (selection == 0)
|
||||||
selection = context.selections().main_index() + 1;
|
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();
|
auto it = line.begin();
|
||||||
while (it != line.end() and is_horizontal_blank(*it))
|
while (it != line.end() and is_horizontal_blank(*it))
|
||||||
++it;
|
++it;
|
||||||
const String indent{line.begin(), it};
|
const StringView indent = line.substr(0_byte, (int)(it-line.begin()));
|
||||||
|
|
||||||
ScopedEdition edition{context};
|
ScopedEdition edition{context};
|
||||||
for (auto& l : lines)
|
for (auto& l : lines)
|
||||||
{
|
{
|
||||||
|
if (l == ref_line)
|
||||||
|
continue;
|
||||||
|
|
||||||
auto& line = buffer[l];
|
auto& line = buffer[l];
|
||||||
ByteCount i = 0;
|
ByteCount i = 0;
|
||||||
while (i < line.length() and is_horizontal_blank(line[i]))
|
while (i < line.length() and is_horizontal_blank(line[i]))
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "register_manager.hh"
|
#include "register_manager.hh"
|
||||||
|
|
||||||
#include "assert.hh"
|
#include "assert.hh"
|
||||||
|
#include "id_map.hh"
|
||||||
#include "utils.hh"
|
#include "utils.hh"
|
||||||
|
|
||||||
namespace Kakoune
|
namespace Kakoune
|
||||||
|
@ -55,9 +56,25 @@ private:
|
||||||
RegisterRetriever m_function;
|
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)
|
if (not reg_ptr)
|
||||||
reg_ptr.reset(new StaticRegister());
|
reg_ptr.reset(new StaticRegister());
|
||||||
return *reg_ptr;
|
return *reg_ptr;
|
||||||
|
|
|
@ -16,7 +16,8 @@ using RegisterRetriever = std::function<std::vector<String> (const Context&)>;
|
||||||
class RegisterManager : public Singleton<RegisterManager>
|
class RegisterManager : public Singleton<RegisterManager>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Register& operator[](char reg);
|
Register& operator[](StringView reg);
|
||||||
|
Register& operator[](Codepoint c);
|
||||||
void register_dynamic_register(char reg, RegisterRetriever function);
|
void register_dynamic_register(char reg, RegisterRetriever function);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user