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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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