Add scope class and encapsulate Options, Keymaps, Aliases and Hooks in it
This commit is contained in:
parent
8649371ff2
commit
e38ba6ce3d
|
@ -21,16 +21,13 @@ public:
|
|||
std::vector<StringView> aliases_for(StringView command) const;
|
||||
|
||||
private:
|
||||
friend class GlobalAliases;
|
||||
friend class Scope;
|
||||
AliasRegistry() {}
|
||||
|
||||
safe_ptr<AliasRegistry> m_parent;
|
||||
std::unordered_map<String, String> m_aliases;
|
||||
};
|
||||
|
||||
class GlobalAliases : public AliasRegistry, public Singleton<GlobalAliases>
|
||||
{};
|
||||
|
||||
}
|
||||
|
||||
#endif // alias_registry_hh_INCLUDED
|
||||
|
|
|
@ -16,18 +16,15 @@ namespace Kakoune
|
|||
|
||||
Buffer::Buffer(String name, Flags flags, std::vector<String> lines,
|
||||
time_t fs_timestamp)
|
||||
: m_name(flags & Flags::File ? real_path(parse_filename(name)) : std::move(name)),
|
||||
: Scope(GlobalScope::instance()),
|
||||
m_name(flags & Flags::File ? real_path(parse_filename(name)) : std::move(name)),
|
||||
m_flags(flags | Flags::NoUndo),
|
||||
m_history(), m_history_cursor(m_history.begin()),
|
||||
m_last_save_undo_index(0),
|
||||
m_fs_timestamp(fs_timestamp),
|
||||
m_hooks(GlobalHooks::instance()),
|
||||
m_options(GlobalOptions::instance()),
|
||||
m_keymaps(GlobalKeymaps::instance()),
|
||||
m_aliases(GlobalAliases::instance())
|
||||
m_fs_timestamp(fs_timestamp)
|
||||
{
|
||||
BufferManager::instance().register_buffer(*this);
|
||||
m_options.register_watcher(*this);
|
||||
options().register_watcher(*this);
|
||||
|
||||
if (lines.empty())
|
||||
lines.emplace_back("\n");
|
||||
|
@ -57,7 +54,7 @@ Buffer::Buffer(String name, Flags flags, std::vector<String> lines,
|
|||
// now we may begin to record undo data
|
||||
m_flags = flags;
|
||||
|
||||
for (auto& option : m_options.flatten_options())
|
||||
for (auto& option : options().flatten_options())
|
||||
on_option_changed(*option);
|
||||
}
|
||||
|
||||
|
@ -65,7 +62,7 @@ Buffer::~Buffer()
|
|||
{
|
||||
run_hook_in_own_context("BufClose", m_name);
|
||||
|
||||
m_options.unregister_watcher(*this);
|
||||
options().unregister_watcher(*this);
|
||||
BufferManager::instance().unregister_buffer(*this);
|
||||
m_values.clear();
|
||||
}
|
||||
|
@ -520,7 +517,7 @@ void Buffer::on_option_changed(const Option& option)
|
|||
void Buffer::run_hook_in_own_context(const String& hook_name, StringView param)
|
||||
{
|
||||
InputHandler hook_handler({ *this, Selection{} });
|
||||
m_hooks.run_hook(hook_name, param, hook_handler.context());
|
||||
hooks().run_hook(hook_name, param, hook_handler.context());
|
||||
}
|
||||
|
||||
ByteCoord Buffer::last_modification_coord() const
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
#ifndef buffer_hh_INCLUDED
|
||||
#define buffer_hh_INCLUDED
|
||||
|
||||
#include "alias_registry.hh"
|
||||
#include "coord.hh"
|
||||
#include "flags.hh"
|
||||
#include "hook_manager.hh"
|
||||
#include "option_manager.hh"
|
||||
#include "keymap_manager.hh"
|
||||
#include "safe_ptr.hh"
|
||||
#include "scope.hh"
|
||||
#include "interned_string.hh"
|
||||
#include "value.hh"
|
||||
|
||||
|
@ -71,7 +68,7 @@ private:
|
|||
// The Buffer class permits to read and mutate this file
|
||||
// representation. It also manage modifications undo/redo and
|
||||
// provides tools to deal with the line/column nature of text.
|
||||
class Buffer : public SafeCountable, public OptionManagerWatcher
|
||||
class Buffer : public SafeCountable, public OptionManagerWatcher, public Scope
|
||||
{
|
||||
public:
|
||||
enum class Flags
|
||||
|
@ -150,15 +147,6 @@ public:
|
|||
// notify the buffer that it was saved in the current state
|
||||
void notify_saved();
|
||||
|
||||
OptionManager& options() { return m_options; }
|
||||
const OptionManager& options() const { return m_options; }
|
||||
HookManager& hooks() { return m_hooks; }
|
||||
const HookManager& hooks() const { return m_hooks; }
|
||||
KeymapManager& keymaps() { return m_keymaps; }
|
||||
const KeymapManager& keymaps() const { return m_keymaps; }
|
||||
AliasRegistry& aliases() { return m_aliases; }
|
||||
const AliasRegistry& aliases() const { return m_aliases; }
|
||||
|
||||
ValueMap& values() const { return m_values; }
|
||||
|
||||
void run_hook_in_own_context(const String& hook_name, StringView param);
|
||||
|
@ -217,11 +205,6 @@ private:
|
|||
|
||||
time_t m_fs_timestamp;
|
||||
|
||||
OptionManager m_options;
|
||||
HookManager m_hooks;
|
||||
KeymapManager m_keymaps;
|
||||
AliasRegistry m_aliases;
|
||||
|
||||
// Values are just data holding by the buffer, so it is part of its
|
||||
// observable state
|
||||
mutable ValueMap m_values;
|
||||
|
|
113
src/commands.cc
113
src/commands.cc
|
@ -84,6 +84,26 @@ const ParameterDesc single_optional_name_param{
|
|||
|
||||
static constexpr auto scopes = { "global", "buffer", "window" };
|
||||
|
||||
Scope* get_scope_ifp(const String& scope, const Context& context)
|
||||
{
|
||||
if (prefix_match("global", scope))
|
||||
return &GlobalScope::instance();
|
||||
else if (prefix_match("buffer", scope))
|
||||
return &context.buffer();
|
||||
else if (prefix_match("window", scope))
|
||||
return &context.window();
|
||||
else if (prefix_match(scope, "buffer="))
|
||||
return &BufferManager::instance().get_buffer(scope.substr(7_byte));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Scope& get_scope(const String& scope, const Context& context)
|
||||
{
|
||||
if (auto s = get_scope_ifp(scope, context))
|
||||
return *s;
|
||||
throw runtime_error("error: no such scope " + scope);
|
||||
}
|
||||
|
||||
struct CommandDesc
|
||||
{
|
||||
const char* name;
|
||||
|
@ -495,24 +515,6 @@ const CommandDesc rm_highlighter_cmd = {
|
|||
}
|
||||
};
|
||||
|
||||
HookManager* get_hook_manager_ifp(const String& scope, const Context& context)
|
||||
{
|
||||
if (prefix_match("global", scope))
|
||||
return &GlobalHooks::instance();
|
||||
else if (prefix_match("buffer", scope))
|
||||
return &context.buffer().hooks();
|
||||
else if (prefix_match("window", scope))
|
||||
return &context.window().hooks();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HookManager& get_hook_manager(const String& scope, const Context& context)
|
||||
{
|
||||
if (auto manager = get_hook_manager_ifp(scope, context))
|
||||
return *manager;
|
||||
throw runtime_error("error: no such hook container " + scope);
|
||||
}
|
||||
|
||||
const CommandDesc add_hook_cmd = {
|
||||
"hook",
|
||||
nullptr,
|
||||
|
@ -557,14 +559,14 @@ const CommandDesc add_hook_cmd = {
|
|||
StringView group;
|
||||
if (parser.has_option("group"))
|
||||
group = parser.option_value("group");
|
||||
get_hook_manager(parser[0], context).add_hook(parser[1], group, hook_func);
|
||||
get_scope(parser[0], context).hooks().add_hook(parser[1], group, hook_func);
|
||||
}
|
||||
};
|
||||
|
||||
const CommandDesc rm_hook_cmd = {
|
||||
"rmhooks",
|
||||
nullptr,
|
||||
"rmhooks <group>: remove all hooks whose group is <group>",
|
||||
"rmhooks <scope> <group>: remove all hooks whose group is <group>",
|
||||
ParameterDesc{ SwitchMap{}, ParameterDesc::Flags::None, 2, 2 },
|
||||
CommandFlags::None,
|
||||
[](const Context& context, CompletionFlags flags,
|
||||
|
@ -576,15 +578,15 @@ const CommandDesc rm_hook_cmd = {
|
|||
prefix_complete(params[0].substr(0_byte, pos_in_token), scopes) };
|
||||
else if (token_to_complete == 1)
|
||||
{
|
||||
if (auto manager = get_hook_manager_ifp(params[0], context))
|
||||
if (auto scope = get_scope_ifp(params[0], context))
|
||||
return { 0_byte, params[0].length(),
|
||||
manager->complete_hook_group(params[1], pos_in_token) };
|
||||
scope->hooks().complete_hook_group(params[1], pos_in_token) };
|
||||
}
|
||||
return {};
|
||||
},
|
||||
[](const ParametersParser& parser, Context& context)
|
||||
{
|
||||
get_hook_manager(parser[0], context).remove_hooks(parser[1]);
|
||||
get_scope(parser[0], context).hooks().remove_hooks(parser[1]);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -712,17 +714,6 @@ const CommandDesc define_command_cmd = {
|
|||
define_command
|
||||
};
|
||||
|
||||
AliasRegistry& get_aliases(const String& scope, const Context& context)
|
||||
{
|
||||
if (prefix_match("global", scope))
|
||||
return GlobalAliases::instance();
|
||||
else if (prefix_match("buffer", scope))
|
||||
return context.buffer().aliases();
|
||||
else if (prefix_match("window", scope))
|
||||
return context.window().aliases();
|
||||
throw runtime_error("error: no such scope " + scope);
|
||||
}
|
||||
|
||||
const CommandDesc alias_cmd = {
|
||||
"alias",
|
||||
nullptr,
|
||||
|
@ -732,7 +723,7 @@ const CommandDesc alias_cmd = {
|
|||
CommandCompleter{},
|
||||
[](const ParametersParser& parser, Context& context)
|
||||
{
|
||||
AliasRegistry& aliases = get_aliases(parser[0], context);
|
||||
AliasRegistry& aliases = get_scope(parser[0], context).aliases();
|
||||
aliases.add_alias(parser[1], parser[2]);
|
||||
}
|
||||
};
|
||||
|
@ -747,7 +738,7 @@ const CommandDesc unalias_cmd = {
|
|||
CommandCompleter{},
|
||||
[](const ParametersParser& parser, Context& context)
|
||||
{
|
||||
AliasRegistry& aliases = get_aliases(parser[0], context);
|
||||
AliasRegistry& aliases = get_scope(parser[0], context).aliases();
|
||||
if (parser.positional_count() == 3 and
|
||||
aliases[parser[1]] != parser[2])
|
||||
return;
|
||||
|
@ -831,19 +822,6 @@ const CommandDesc source_cmd = {
|
|||
}
|
||||
};
|
||||
|
||||
OptionManager& get_options(const String& scope, const Context& context)
|
||||
{
|
||||
if (prefix_match("global", scope))
|
||||
return GlobalOptions::instance();
|
||||
else if (prefix_match("buffer", scope))
|
||||
return context.buffer().options();
|
||||
else if (prefix_match("window", scope))
|
||||
return context.window().options();
|
||||
else if (prefix_match(scope, "buffer="))
|
||||
return BufferManager::instance().get_buffer(scope.substr(7_byte)).options();
|
||||
throw runtime_error("error: no such option container " + scope);
|
||||
}
|
||||
|
||||
const CommandDesc set_option_cmd = {
|
||||
"set",
|
||||
nullptr,
|
||||
|
@ -863,14 +841,14 @@ const CommandDesc set_option_cmd = {
|
|||
prefix_complete(params[0].substr(0_byte, pos_in_token), scopes) };
|
||||
else if (token_to_complete == 1)
|
||||
{
|
||||
OptionManager& options = get_options(params[0], context);
|
||||
OptionManager& options = get_scope(params[0], context).options();
|
||||
return { 0_byte, params[1].length(),
|
||||
options.complete_option_name(params[1], pos_in_token) };
|
||||
}
|
||||
else if (token_to_complete == 2 and
|
||||
GlobalOptions::instance().option_exists(params[1]))
|
||||
GlobalScope::instance().option_registry().option_exists(params[1]))
|
||||
{
|
||||
OptionManager& options = get_options(params[0], context);
|
||||
OptionManager& options = get_scope(params[0], context).options();
|
||||
String val = options[params[1]].get_as_string();
|
||||
if (prefix_match(val, params[2]))
|
||||
return { 0_byte, params[2].length(), { std::move(val) } };
|
||||
|
@ -879,7 +857,7 @@ const CommandDesc set_option_cmd = {
|
|||
},
|
||||
[](const ParametersParser& parser, Context& context)
|
||||
{
|
||||
Option& opt = get_options(parser[0], context).get_local_option(parser[1]);
|
||||
Option& opt = get_scope(parser[0], context).options().get_local_option(parser[1]);
|
||||
if (parser.has_option("add"))
|
||||
opt.add_from_string(parser[2]);
|
||||
else
|
||||
|
@ -920,22 +898,22 @@ const CommandDesc declare_option_cmd = {
|
|||
if (parser.has_option("docstring"))
|
||||
docstring = parser.option_value("docstring");
|
||||
|
||||
GlobalOptions& opts = GlobalOptions::instance();
|
||||
OptionsRegistry& reg = GlobalScope::instance().option_registry();
|
||||
|
||||
if (parser[0] == "int")
|
||||
opt = &opts.declare_option<int>(parser[1], docstring, 0, flags);
|
||||
opt = ®.declare_option<int>(parser[1], docstring, 0, flags);
|
||||
else if (parser[0] == "bool")
|
||||
opt = &opts.declare_option<bool>(parser[1], docstring, 0, flags);
|
||||
opt = ®.declare_option<bool>(parser[1], docstring, 0, flags);
|
||||
else if (parser[0] == "str")
|
||||
opt = &opts.declare_option<String>(parser[1], docstring, "", flags);
|
||||
opt = ®.declare_option<String>(parser[1], docstring, "", flags);
|
||||
else if (parser[0] == "regex")
|
||||
opt = &opts.declare_option<Regex>(parser[1], docstring, Regex{}, flags);
|
||||
opt = ®.declare_option<Regex>(parser[1], docstring, Regex{}, flags);
|
||||
else if (parser[0] == "int-list")
|
||||
opt = &opts.declare_option<std::vector<int>>(parser[1], docstring, {}, flags);
|
||||
opt = ®.declare_option<std::vector<int>>(parser[1], docstring, {}, flags);
|
||||
else if (parser[0] == "str-list")
|
||||
opt = &opts.declare_option<std::vector<String>>(parser[1], docstring, {}, flags);
|
||||
opt = ®.declare_option<std::vector<String>>(parser[1], docstring, {}, flags);
|
||||
else if (parser[0] == "line-flag-list")
|
||||
opt = &opts.declare_option<std::vector<LineAndFlag>>(parser[1], docstring, {}, flags);
|
||||
opt = ®.declare_option<std::vector<LineAndFlag>>(parser[1], docstring, {}, flags);
|
||||
else
|
||||
throw runtime_error("unknown type " + parser[0]);
|
||||
|
||||
|
@ -944,15 +922,6 @@ const CommandDesc declare_option_cmd = {
|
|||
}
|
||||
};
|
||||
|
||||
KeymapManager& get_keymap_manager(const String& scope, Context& context)
|
||||
{
|
||||
if (prefix_match("global", scope)) return GlobalKeymaps::instance();
|
||||
if (prefix_match("buffer", scope)) return context.buffer().keymaps();
|
||||
if (prefix_match("window", scope)) return context.window().keymaps();
|
||||
|
||||
throw runtime_error("error: no such keymap container " + scope);
|
||||
}
|
||||
|
||||
KeymapMode parse_keymap_mode(const String& str)
|
||||
{
|
||||
if (prefix_match("normal", str)) return KeymapMode::Normal;
|
||||
|
@ -997,7 +966,7 @@ const CommandDesc map_key_cmd = {
|
|||
},
|
||||
[](const ParametersParser& parser, Context& context)
|
||||
{
|
||||
KeymapManager& keymaps = get_keymap_manager(parser[0], context);
|
||||
KeymapManager& keymaps = get_scope(parser[0], context).keymaps();
|
||||
KeymapMode keymap_mode = parse_keymap_mode(parser[1]);
|
||||
|
||||
KeyList key = parse_keys(parser[2]);
|
||||
|
@ -1419,7 +1388,7 @@ static void register_command(CommandManager& cm, const CommandDesc& c)
|
|||
{
|
||||
cm.register_command(c.name, c.func, c.docstring, c.params, c.flags, c.completer);
|
||||
if (c.alias)
|
||||
GlobalAliases::instance().add_alias(c.alias, c.name);
|
||||
GlobalScope::instance().aliases().add_alias(c.alias, c.name);
|
||||
}
|
||||
|
||||
void register_commands()
|
||||
|
|
|
@ -54,40 +54,33 @@ UserInterface& Context::ui() const
|
|||
return client().ui();
|
||||
}
|
||||
|
||||
OptionManager& Context::options() const
|
||||
Scope& Context::scope() const
|
||||
{
|
||||
if (has_window())
|
||||
return window().options();
|
||||
return window();
|
||||
if (has_buffer())
|
||||
return buffer().options();
|
||||
return GlobalOptions::instance();
|
||||
return buffer();
|
||||
return GlobalScope::instance();
|
||||
}
|
||||
|
||||
OptionManager& Context::options() const
|
||||
{
|
||||
return scope().options();
|
||||
}
|
||||
|
||||
HookManager& Context::hooks() const
|
||||
{
|
||||
if (has_window())
|
||||
return window().hooks();
|
||||
if (has_buffer())
|
||||
return buffer().hooks();
|
||||
return GlobalHooks::instance();
|
||||
return scope().hooks();
|
||||
}
|
||||
|
||||
KeymapManager& Context::keymaps() const
|
||||
{
|
||||
if (has_window())
|
||||
return window().keymaps();
|
||||
if (has_buffer())
|
||||
return buffer().keymaps();
|
||||
return GlobalKeymaps::instance();
|
||||
return scope().keymaps();
|
||||
}
|
||||
|
||||
AliasRegistry& Context::aliases() const
|
||||
{
|
||||
if (has_window())
|
||||
return window().aliases();
|
||||
if (has_buffer())
|
||||
return buffer().aliases();
|
||||
return GlobalAliases::instance();
|
||||
return scope().aliases();
|
||||
}
|
||||
|
||||
void Context::set_client(Client& client)
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace Kakoune
|
|||
class Window;
|
||||
class Buffer;
|
||||
class Client;
|
||||
class Scope;
|
||||
class InputHandler;
|
||||
class UserInterface;
|
||||
class DisplayLine;
|
||||
|
@ -58,6 +59,8 @@ public:
|
|||
void set_client(Client& client);
|
||||
void set_window(Window& window);
|
||||
|
||||
Scope& scope() const;
|
||||
|
||||
OptionManager& options() const;
|
||||
HookManager& hooks() const;
|
||||
KeymapManager& keymaps() const;
|
||||
|
|
|
@ -395,7 +395,7 @@ HighlighterAndId create_regex_option_highlighter(HighlighterParameters params)
|
|||
|
||||
String option_name = params[0];
|
||||
// verify option type now
|
||||
GlobalOptions::instance()[option_name].get<Regex>();
|
||||
GlobalScope::instance().options()[option_name].get<Regex>();
|
||||
|
||||
auto get_regex = [option_name](const Context& context){
|
||||
return context.options()[option_name].get<Regex>();
|
||||
|
@ -412,7 +412,7 @@ HighlighterAndId create_line_option_highlighter(HighlighterParameters params)
|
|||
String option_name = params[0];
|
||||
|
||||
get_face(facespec); // validate facespec
|
||||
GlobalOptions::instance()[option_name].get<int>(); // verify option type now
|
||||
GlobalScope::instance().options()[option_name].get<int>(); // verify option type now
|
||||
|
||||
auto func = [=](const Context& context, HighlightFlags flags,
|
||||
DisplayBuffer& display_buffer)
|
||||
|
@ -645,7 +645,7 @@ HighlighterAndId create_flag_lines_highlighter(HighlighterParameters params)
|
|||
Color bg = str_to_color(params[0]);
|
||||
|
||||
// throw if wrong option type
|
||||
GlobalOptions::instance()[option_name].get<std::vector<LineAndFlag>>();
|
||||
GlobalScope::instance().options()[option_name].get<std::vector<LineAndFlag>>();
|
||||
|
||||
auto func = [=](const Context& context, HighlightFlags flags,
|
||||
DisplayBuffer& display_buffer)
|
||||
|
|
|
@ -27,17 +27,12 @@ private:
|
|||
HookManager()
|
||||
: m_parent(nullptr) {}
|
||||
// the only one allowed to construct a root hook manager
|
||||
friend class GlobalHooks;
|
||||
friend class Scope;
|
||||
|
||||
HookManager* m_parent;
|
||||
std::unordered_map<String, id_map<HookFunc>> m_hook;
|
||||
};
|
||||
|
||||
class GlobalHooks : public HookManager,
|
||||
public Singleton<GlobalHooks>
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // hook_manager_hh_INCLUDED
|
||||
|
|
|
@ -34,7 +34,7 @@ private:
|
|||
KeymapManager()
|
||||
: m_parent(nullptr) {}
|
||||
// the only one allowed to construct a root map manager
|
||||
friend class GlobalKeymaps;
|
||||
friend class Scope;
|
||||
|
||||
KeymapManager* m_parent;
|
||||
|
||||
|
@ -43,11 +43,6 @@ private:
|
|||
Keymap m_mapping;
|
||||
};
|
||||
|
||||
class GlobalKeymaps : public KeymapManager,
|
||||
public Singleton<GlobalKeymaps>
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // keymap_manager_hh_INCLUDED
|
||||
|
|
68
src/main.cc
68
src/main.cc
|
@ -1,5 +1,4 @@
|
|||
#include "assert.hh"
|
||||
#include "alias_registry.hh"
|
||||
#include "buffer.hh"
|
||||
#include "buffer_manager.hh"
|
||||
#include "buffer_utils.hh"
|
||||
|
@ -12,15 +11,14 @@
|
|||
#include "face_registry.hh"
|
||||
#include "file.hh"
|
||||
#include "highlighters.hh"
|
||||
#include "hook_manager.hh"
|
||||
#include "keymap_manager.hh"
|
||||
#include "ncurses.hh"
|
||||
#include "option_manager.hh"
|
||||
#include "parameters_parser.hh"
|
||||
#include "register_manager.hh"
|
||||
#include "remote.hh"
|
||||
#include "shell_manager.hh"
|
||||
#include "scope.hh"
|
||||
#include "string.hh"
|
||||
#include "insert_completer.hh"
|
||||
#include "interned_string.hh"
|
||||
#include "window.hh"
|
||||
|
||||
|
@ -187,6 +185,52 @@ void register_registers()
|
|||
}
|
||||
}
|
||||
|
||||
void register_options()
|
||||
{
|
||||
OptionsRegistry& reg = GlobalScope::instance().option_registry();
|
||||
|
||||
reg.declare_option("tabstop", "size of a tab character", 8);
|
||||
reg.declare_option("indentwidth", "indentation width", 4);
|
||||
reg.declare_option("scrolloff",
|
||||
"number of lines and columns to keep visible main cursor when scrolling",
|
||||
CharCoord{0,0});
|
||||
reg.declare_option("eolformat", "end of line format: 'crlf' or 'lf'", "lf"_str);
|
||||
reg.declare_option("BOM", "insert a byte order mark when writing buffer",
|
||||
"no"_str);
|
||||
reg.declare_option("complete_prefix",
|
||||
"complete up to common prefix in tab completion",
|
||||
true);
|
||||
reg.declare_option("incsearch",
|
||||
"incrementaly apply search/select/split regex",
|
||||
true);
|
||||
reg.declare_option("autoinfo",
|
||||
"automatically display contextual help",
|
||||
1);
|
||||
reg.declare_option("autoshowcompl",
|
||||
"automatically display possible completions for prompts",
|
||||
true);
|
||||
reg.declare_option("aligntab",
|
||||
"use tab characters when possible for alignement",
|
||||
false);
|
||||
reg.declare_option("ignored_files",
|
||||
"patterns to ignore when completing filenames",
|
||||
Regex{R"(^(\..*|.*\.(o|so|a))$)"});
|
||||
reg.declare_option("disabled_hooks",
|
||||
"patterns to disable hooks whose group is matched",
|
||||
Regex{});
|
||||
reg.declare_option("filetype", "buffer filetype", ""_str);
|
||||
reg.declare_option("path", "path to consider when trying to find a file",
|
||||
std::vector<String>({ "./", "/usr/include" }));
|
||||
reg.declare_option("completers", "insert mode completers to execute.",
|
||||
std::vector<InsertCompleterDesc>({
|
||||
InsertCompleterDesc{ InsertCompleterDesc::Filename },
|
||||
InsertCompleterDesc{ InsertCompleterDesc::Word, "all"_str }
|
||||
}), OptionFlags::None);
|
||||
reg.declare_option("autoreload",
|
||||
"autoreload buffer when a filesystem modification is detected",
|
||||
Ask);
|
||||
}
|
||||
|
||||
void create_local_client(const String& init_command)
|
||||
{
|
||||
class LocalNCursesUI : public NCursesUI
|
||||
|
@ -298,10 +342,7 @@ int run_server(StringView session, StringView init_command,
|
|||
|
||||
StringRegistry string_registry;
|
||||
EventManager event_manager;
|
||||
GlobalOptions global_options;
|
||||
GlobalHooks global_hooks;
|
||||
GlobalKeymaps global_keymaps;
|
||||
GlobalAliases global_aliases;
|
||||
GlobalScope global_scope;
|
||||
ShellManager shell_manager;
|
||||
CommandManager command_manager;
|
||||
BufferManager buffer_manager;
|
||||
|
@ -313,6 +354,7 @@ int run_server(StringView session, StringView init_command,
|
|||
|
||||
run_unit_tests();
|
||||
|
||||
register_options();
|
||||
register_env_vars();
|
||||
register_registers();
|
||||
register_commands();
|
||||
|
@ -339,7 +381,7 @@ int run_server(StringView session, StringView init_command,
|
|||
|
||||
{
|
||||
Context empty_context;
|
||||
global_hooks.run_hook("KakBegin", "", empty_context);
|
||||
global_scope.hooks().run_hook("KakBegin", "", empty_context);
|
||||
}
|
||||
|
||||
if (not files.empty()) try
|
||||
|
@ -372,7 +414,7 @@ int run_server(StringView session, StringView init_command,
|
|||
|
||||
{
|
||||
Context empty_context;
|
||||
global_hooks.run_hook("KakEnd", "", empty_context);
|
||||
global_scope.hooks().run_hook("KakEnd", "", empty_context);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -381,14 +423,12 @@ int run_server(StringView session, StringView init_command,
|
|||
int run_filter(StringView keystr, memoryview<StringView> files)
|
||||
{
|
||||
StringRegistry string_registry;
|
||||
GlobalOptions global_options;
|
||||
GlobalHooks global_hooks;
|
||||
GlobalKeymaps global_keymaps;
|
||||
GlobalAliases global_aliases;
|
||||
GlobalScope global_scope;
|
||||
ShellManager shell_manager;
|
||||
BufferManager buffer_manager;
|
||||
RegisterManager register_manager;
|
||||
|
||||
register_options();
|
||||
register_env_vars();
|
||||
register_registers();
|
||||
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
#include "option_manager.hh"
|
||||
|
||||
#include "insert_completer.hh"
|
||||
|
||||
#include "assert.hh"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
||||
|
@ -128,49 +124,4 @@ void OptionManager::on_option_changed(const Option& option)
|
|||
watcher->on_option_changed(option);
|
||||
}
|
||||
|
||||
GlobalOptions::GlobalOptions()
|
||||
: OptionManager()
|
||||
{
|
||||
declare_option("tabstop", "size of a tab character", 8);
|
||||
declare_option("indentwidth", "indentation width", 4);
|
||||
declare_option("scrolloff",
|
||||
"number of lines and columns to keep visible main cursor when scrolling",
|
||||
CharCoord{0,0});
|
||||
declare_option("eolformat", "end of line format: 'crlf' or 'lf'", "lf"_str);
|
||||
declare_option("BOM", "insert a byte order mark when writing buffer",
|
||||
"no"_str);
|
||||
declare_option("complete_prefix",
|
||||
"complete up to common prefix in tab completion",
|
||||
true);
|
||||
declare_option("incsearch",
|
||||
"incrementaly apply search/select/split regex",
|
||||
true);
|
||||
declare_option("autoinfo",
|
||||
"automatically display contextual help",
|
||||
1);
|
||||
declare_option("autoshowcompl",
|
||||
"automatically display possible completions for prompts",
|
||||
true);
|
||||
declare_option("aligntab",
|
||||
"use tab characters when possible for alignement",
|
||||
false);
|
||||
declare_option("ignored_files",
|
||||
"patterns to ignore when completing filenames",
|
||||
Regex{R"(^(\..*|.*\.(o|so|a))$)"});
|
||||
declare_option("disabled_hooks",
|
||||
"patterns to disable hooks whose group is matched",
|
||||
Regex{});
|
||||
declare_option("filetype", "buffer filetype", ""_str);
|
||||
declare_option("path", "path to consider when trying to find a file",
|
||||
std::vector<String>({ "./", "/usr/include" }));
|
||||
declare_option("completers", "insert mode completers to execute.",
|
||||
std::vector<InsertCompleterDesc>({
|
||||
InsertCompleterDesc{ InsertCompleterDesc::Filename },
|
||||
InsertCompleterDesc{ InsertCompleterDesc::Word, "all"_str }
|
||||
}), OptionFlags::None);
|
||||
declare_option("autoreload",
|
||||
"autoreload buffer when a filesystem modification is detected",
|
||||
Ask);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -104,7 +104,8 @@ private:
|
|||
OptionManager()
|
||||
: m_parent(nullptr) {}
|
||||
// the only one allowed to construct a root option manager
|
||||
friend class GlobalOptions;
|
||||
friend class Scope;
|
||||
friend class OptionsRegistry;
|
||||
|
||||
template<typename MatchingFunc>
|
||||
CandidateList get_matching_names(MatchingFunc func);
|
||||
|
@ -186,34 +187,37 @@ auto find_option(T& container, const String& name) -> decltype(container.begin()
|
|||
return find_if(container, [&name](const ptr_type& opt) { return opt->name() == name; });
|
||||
}
|
||||
|
||||
class GlobalOptions : public OptionManager,
|
||||
public Singleton<GlobalOptions>
|
||||
class OptionsRegistry
|
||||
{
|
||||
public:
|
||||
GlobalOptions();
|
||||
OptionsRegistry(OptionManager& global_manager) : m_global_manager(global_manager) {}
|
||||
|
||||
template<typename T>
|
||||
Option& declare_option(const String& name, const String& docstring,
|
||||
const T& value,
|
||||
OptionFlags flags = OptionFlags::None)
|
||||
{
|
||||
auto it = find_option(m_options, name);
|
||||
if (it != m_options.end())
|
||||
auto& opts = m_global_manager.m_options;
|
||||
auto it = find_option(opts, name);
|
||||
if (it != opts.end())
|
||||
{
|
||||
if ((*it)->is_of_type<T>() and (*it)->flags() == flags)
|
||||
return **it;
|
||||
throw runtime_error("option " + name + " already declared with different type or flags");
|
||||
}
|
||||
m_descs.emplace_back(new OptionDesc{name, docstring, flags});
|
||||
m_options.emplace_back(new TypedOption<T>{*this, *m_descs.back(), value});
|
||||
return *m_options.back();
|
||||
opts.emplace_back(new TypedOption<T>{m_global_manager, *m_descs.back(), value});
|
||||
return *opts.back();
|
||||
}
|
||||
|
||||
bool option_exists(const String& name) const
|
||||
{
|
||||
return find_option(m_options, name) != m_options.end();
|
||||
return find_if(m_descs, [&name](const std::unique_ptr<OptionDesc>& opt) {
|
||||
return opt->name() == name;
|
||||
}) != m_descs.end();
|
||||
}
|
||||
private:
|
||||
OptionManager& m_global_manager;
|
||||
std::vector<std::unique_ptr<OptionDesc>> m_descs;
|
||||
};
|
||||
|
||||
|
|
53
src/scope.hh
Normal file
53
src/scope.hh
Normal file
|
@ -0,0 +1,53 @@
|
|||
#ifndef scope_hh_INCLUDED
|
||||
#define scope_hh_INCLUDED
|
||||
|
||||
#include "alias_registry.hh"
|
||||
#include "hook_manager.hh"
|
||||
#include "keymap_manager.hh"
|
||||
#include "option_manager.hh"
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
||||
class Scope
|
||||
{
|
||||
public:
|
||||
Scope(Scope& parent)
|
||||
: m_options(parent.options()),
|
||||
m_hooks(parent.hooks()),
|
||||
m_keymaps(parent.keymaps()),
|
||||
m_aliases(parent.aliases()) {}
|
||||
|
||||
OptionManager& options() { return m_options; }
|
||||
const OptionManager& options() const { return m_options; }
|
||||
HookManager& hooks() { return m_hooks; }
|
||||
const HookManager& hooks() const { return m_hooks; }
|
||||
KeymapManager& keymaps() { return m_keymaps; }
|
||||
const KeymapManager& keymaps() const { return m_keymaps; }
|
||||
AliasRegistry& aliases() { return m_aliases; }
|
||||
const AliasRegistry& aliases() const { return m_aliases; }
|
||||
|
||||
private:
|
||||
friend class GlobalScope;
|
||||
Scope() = default;
|
||||
|
||||
OptionManager m_options;
|
||||
HookManager m_hooks;
|
||||
KeymapManager m_keymaps;
|
||||
AliasRegistry m_aliases;
|
||||
};
|
||||
|
||||
class GlobalScope : public Scope, public Singleton<GlobalScope>
|
||||
{
|
||||
public:
|
||||
GlobalScope() : m_option_registry(m_options) {}
|
||||
|
||||
OptionsRegistry& option_registry() { return m_option_registry; }
|
||||
const OptionsRegistry& option_registry() const { return m_option_registry; }
|
||||
private:
|
||||
OptionsRegistry m_option_registry;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // scope_hh_INCLUDED
|
|
@ -18,22 +18,19 @@ void expand_tabulations(const Context& context, HighlightFlags flags, DisplayBuf
|
|||
void expand_unprintable(const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer);
|
||||
|
||||
Window::Window(Buffer& buffer)
|
||||
: m_buffer(&buffer),
|
||||
m_hooks(buffer.hooks()),
|
||||
m_options(buffer.options()),
|
||||
m_keymaps(buffer.keymaps()),
|
||||
m_aliases(buffer.aliases())
|
||||
: Scope(buffer),
|
||||
m_buffer(&buffer)
|
||||
{
|
||||
InputHandler hook_handler{{ *m_buffer, Selection{} }};
|
||||
hook_handler.context().set_window(*this);
|
||||
m_hooks.run_hook("WinCreate", buffer.name(), hook_handler.context());
|
||||
m_options.register_watcher(*this);
|
||||
hooks().run_hook("WinCreate", buffer.name(), hook_handler.context());
|
||||
options().register_watcher(*this);
|
||||
|
||||
m_builtin_highlighters.add_child({"tabulations"_str, make_simple_highlighter(expand_tabulations)});
|
||||
m_builtin_highlighters.add_child({"unprintable"_str, make_simple_highlighter(expand_unprintable)});
|
||||
m_builtin_highlighters.add_child({"selections"_str, make_simple_highlighter(highlight_selections)});
|
||||
|
||||
for (auto& option : m_options.flatten_options())
|
||||
for (auto& option : options().flatten_options())
|
||||
on_option_changed(*option);
|
||||
}
|
||||
|
||||
|
@ -41,8 +38,8 @@ Window::~Window()
|
|||
{
|
||||
InputHandler hook_handler{{ *m_buffer, Selection{} }};
|
||||
hook_handler.context().set_window(*this);
|
||||
m_hooks.run_hook("WinClose", buffer().name(), hook_handler.context());
|
||||
m_options.unregister_watcher(*this);
|
||||
hooks().run_hook("WinClose", buffer().name(), hook_handler.context());
|
||||
options().unregister_watcher(*this);
|
||||
}
|
||||
|
||||
void Window::display_line_at(LineCount buffer_line, LineCount display_line)
|
||||
|
@ -279,7 +276,7 @@ void Window::on_option_changed(const Option& option)
|
|||
String desc = option.name() + "=" + option.get_as_string();
|
||||
InputHandler hook_handler{{ *m_buffer, Selection{} }};
|
||||
hook_handler.context().set_window(*this);
|
||||
m_hooks.run_hook("WinSetOption", desc, hook_handler.context());
|
||||
hooks().run_hook("WinSetOption", desc, hook_handler.context());
|
||||
|
||||
// an highlighter might depend on the option, so we need to redraw
|
||||
forget_timestamp();
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
#ifndef window_hh_INCLUDED
|
||||
#define window_hh_INCLUDED
|
||||
|
||||
#include "alias_registry.hh"
|
||||
#include "completion.hh"
|
||||
#include "display_buffer.hh"
|
||||
#include "highlighter_group.hh"
|
||||
#include "selection.hh"
|
||||
#include "hook_manager.hh"
|
||||
#include "option_manager.hh"
|
||||
#include "keymap_manager.hh"
|
||||
#include "safe_ptr.hh"
|
||||
#include "scope.hh"
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
||||
// A Window is a view onto a Buffer
|
||||
class Window : public SafeCountable, public OptionManagerWatcher
|
||||
class Window : public SafeCountable, public OptionManagerWatcher, public Scope
|
||||
{
|
||||
public:
|
||||
Window(Buffer& buffer);
|
||||
|
@ -39,15 +36,6 @@ public:
|
|||
|
||||
Highlighter& highlighters() { return m_highlighters; }
|
||||
|
||||
OptionManager& options() { return m_options; }
|
||||
const OptionManager& options() const { return m_options; }
|
||||
HookManager& hooks() { return m_hooks; }
|
||||
const HookManager& hooks() const { return m_hooks; }
|
||||
KeymapManager& keymaps() { return m_keymaps; }
|
||||
const KeymapManager& keymaps() const { return m_keymaps; }
|
||||
AliasRegistry& aliases() { return m_aliases; }
|
||||
const AliasRegistry& aliases() const { return m_aliases; }
|
||||
|
||||
Buffer& buffer() const { return *m_buffer; }
|
||||
|
||||
size_t timestamp() const { return m_timestamp; }
|
||||
|
@ -67,11 +55,6 @@ private:
|
|||
CharCoord m_dimensions;
|
||||
DisplayBuffer m_display_buffer;
|
||||
|
||||
HookManager m_hooks;
|
||||
OptionManager m_options;
|
||||
KeymapManager m_keymaps;
|
||||
AliasRegistry m_aliases;
|
||||
|
||||
HighlighterGroup m_highlighters;
|
||||
HighlighterGroup m_builtin_highlighters;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user