Merge branch 'master' into remove-buffer-change-listener

This commit is contained in:
Maxime Coste 2014-06-09 19:29:40 +01:00
commit f54f8818c6
9 changed files with 93 additions and 62 deletions

View File

@ -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:

View File

@ -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]);
}
};

View File

@ -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()));

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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]))

View File

@ -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;

View File

@ -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: