remove filters, use hooks instead

This commit is contained in:
Maxime Coste 2013-10-30 09:02:45 +00:00
parent 4c39743b69
commit 471aeaab9a
9 changed files with 6 additions and 276 deletions

View File

@ -464,34 +464,6 @@ existing highlighters are:
given flag in it for everly lines contained in the int-list option named given flag in it for everly lines contained in the int-list option named
<option_name>. <option_name>.
Filters
-------
Filters can be installed to interact with buffer modifications. They can be
added or removed with
-----------------------------------------------
:addfilter <filter_name> <filter_parameters...>
-----------------------------------------------
and
---------------------
:rmfilter <filter_id>
---------------------
exisiting filters are:
* +preserve_indent+: insert previous line indent when inserting a newline
* +cleanup_whitespaces+: remove trailing whitespaces on the previous line
when inserting an end-of-line.
* +expand_tabulations+: insert spaces instead of tab characters
* +regex <line_regex> <insert_regex> <replacement>+: when the current line regex
and inserted text regex matches, replace insereted text with the
replacement text. Capture groups are available through $[0-9] escape
sequence, and cursor position can be specified with $c.
* +group+: same as highlighters group
Hooks Hooks
----- -----

View File

@ -982,14 +982,11 @@ private:
void insert(Codepoint key) void insert(Codepoint key)
{ {
auto str = codepoint_to_str(key);
auto& buffer = m_edition.editor().buffer(); auto& buffer = m_edition.editor().buffer();
for (auto& sel : m_edition.editor().m_selections) for (auto& sel : m_edition.editor().selections())
{ buffer.insert(buffer.iterator_at(sel.last()), str);
auto content = codepoint_to_str(key); context().hooks().run_hook("InsertKey", str, context());
m_edition.editor().filters()(buffer, sel, content);
buffer.insert(buffer.iterator_at(sel.last()), content);
}
context().hooks().run_hook("InsertKey", codepoint_to_str(key), context());
} }
void prepare(InsertMode mode) void prepare(InsertMode mode)

View File

@ -10,7 +10,6 @@
#include "debug.hh" #include "debug.hh"
#include "event_manager.hh" #include "event_manager.hh"
#include "file.hh" #include "file.hh"
#include "filter.hh"
#include "highlighter.hh" #include "highlighter.hh"
#include "highlighters.hh" #include "highlighters.hh"
#include "client.hh" #include "client.hh"
@ -283,39 +282,6 @@ void rm_highlighter(CommandParameters params, Context& context)
group.remove(parser[0]); group.remove(parser[0]);
} }
void add_filter(CommandParameters params, Context& context)
{
ParametersParser parser(params, { { "group", true } }, ParametersParser::Flags::None, 1);
FilterRegistry& registry = FilterRegistry::instance();
auto begin = parser.begin();
const String& name = *begin;
std::vector<String> filter_params;
for (++begin; begin != parser.end(); ++begin)
filter_params.push_back(*begin);
Editor& editor = context.editor();
FilterGroup& group = parser.has_option("group") ?
get_group(editor.filters(), parser.option_value("group"))
: editor.filters();
auto& factory = registry[name];
group.append(factory(filter_params));
}
void rm_filter(CommandParameters params, Context& context)
{
ParametersParser parser(params, { { "group", true } }, ParametersParser::Flags::None, 1, 1);
Editor& editor = context.editor();
FilterGroup& group = parser.has_option("group") ?
get_group(editor.filters(), parser.option_value("group"))
: editor.filters();
group.remove(parser[0]);
}
static HookManager& get_hook_manager(const String& scope, Context& context) static HookManager& get_hook_manager(const String& scope, Context& context)
{ {
if (prefix_match("global", scope)) if (prefix_match("global", scope))
@ -838,11 +804,8 @@ void register_commands()
cm.register_commands({"nb", "namebuf"}, set_buffer_name); cm.register_commands({"nb", "namebuf"}, set_buffer_name);
auto get_highlighters = [](const Context& c) -> HighlighterGroup& { return c.window().highlighters(); }; auto get_highlighters = [](const Context& c) -> HighlighterGroup& { return c.window().highlighters(); };
auto get_filters = [](const Context& c) -> FilterGroup& { return c.window().filters(); };
cm.register_commands({ "ah", "addhl" }, add_highlighter, group_add_completer<HighlighterRegistry>(get_highlighters)); cm.register_commands({ "ah", "addhl" }, add_highlighter, group_add_completer<HighlighterRegistry>(get_highlighters));
cm.register_commands({ "rh", "rmhl" }, rm_highlighter, group_rm_completer(get_highlighters)); cm.register_commands({ "rh", "rmhl" }, rm_highlighter, group_rm_completer(get_highlighters));
cm.register_commands({ "af", "addfilter" }, add_filter, group_add_completer<FilterRegistry>(get_filters));
cm.register_commands({ "rf", "rmfilter" }, rm_filter, group_rm_completer(get_filters));
cm.register_command("hook", add_hook); cm.register_command("hook", add_hook);
cm.register_command("rmhooks", rm_hooks); cm.register_command("rmhooks", rm_hooks);

View File

@ -3,7 +3,6 @@
#include "buffer.hh" #include "buffer.hh"
#include "dynamic_selection_list.hh" #include "dynamic_selection_list.hh"
#include "filter.hh"
#include "memoryview.hh" #include "memoryview.hh"
namespace Kakoune namespace Kakoune
@ -82,11 +81,6 @@ public:
bool undo(); bool undo();
bool redo(); bool redo();
FilterGroup& filters() { return m_filters; }
CandidateList complete_filterid(const String& prefix,
size_t cursor_pos = String::npos);
bool is_editing() const { return m_edition_level!= 0; } bool is_editing() const { return m_edition_level!= 0; }
private: private:
friend struct scoped_edition; friend struct scoped_edition;
@ -104,7 +98,6 @@ private:
safe_ptr<Buffer> m_buffer; safe_ptr<Buffer> m_buffer;
DynamicSelectionList m_selections; DynamicSelectionList m_selections;
size_t m_main_sel; size_t m_main_sel;
FilterGroup m_filters;
}; };
struct scoped_edition struct scoped_edition

View File

@ -1,35 +0,0 @@
#ifndef filter_hh_INCLUDED
#define filter_hh_INCLUDED
#include "function_group.hh"
#include "function_registry.hh"
#include "memoryview.hh"
#include "string.hh"
#include "utils.hh"
#include <functional>
namespace Kakoune
{
class Buffer;
struct Selection;
// A Filter is a function which is applied to a Buffer and a pending
// Modification in order to mutate the Buffer or the Modification
// prior to it's application.
using FilterFunc = std::function<void (Buffer& buffer, Selection& selection, String& content)>;
using FilterAndId = std::pair<String, FilterFunc>;
using FilterGroup = FunctionGroup<Buffer&, Selection&, String&>;
using FilterParameters = memoryview<String>;
using FilterFactory = std::function<FilterAndId (FilterParameters params)>;
struct FilterRegistry : FunctionRegistry<FilterFactory>,
Singleton<FilterRegistry>
{};
}
#endif // filter_hh_INCLUDED

View File

@ -1,144 +0,0 @@
#include "filters.hh"
#include "buffer.hh"
#include "selection.hh"
namespace Kakoune
{
void preserve_indent(Buffer& buffer, Selection& selection, String& content)
{
if (content == "\n")
{
BufferCoord line_begin{selection.last().line, 0};
auto first_non_white = buffer.iterator_at(line_begin);
while ((*first_non_white == '\t' or *first_non_white == ' ') and
first_non_white != buffer.end())
++first_non_white;
content += buffer.string(line_begin, first_non_white.coord());
}
}
void cleanup_whitespaces(Buffer& buffer, Selection& selection, String& content)
{
const auto position = buffer.iterator_at(selection.last());
if (content[0] == '\n' and position != buffer.begin())
{
auto whitespace_start = position-1;
while ((*whitespace_start == ' ' or *whitespace_start == '\t') and
whitespace_start != buffer.begin())
--whitespace_start;
++whitespace_start;
if (whitespace_start != position)
buffer.erase(whitespace_start, position);
}
}
void expand_tabulations(Buffer& buffer, Selection& selection, String& content)
{
const int tabstop = buffer.options()["tabstop"].get<int>();
if (content == "\t")
{
int column = 0;
const auto position = buffer.iterator_at(selection.last());
for (auto it = buffer.iterator_at(selection.last().line);
it != position; ++it)
{
kak_assert(*it != '\n');
if (*it == '\t')
column += tabstop - (column % tabstop);
else
++column;
}
CharCount count = tabstop - (column % tabstop);
content = String(' ', count);
}
}
struct RegexFilter
{
RegexFilter(const String& line_match, const String& insert_match,
const String& replacement)
: m_line_match(line_match.c_str()), m_insert_match(insert_match.c_str()),
m_replacement(replacement.c_str()) {}
void operator() (Buffer& buffer, Selection& selection, String& content)
{
const auto position = buffer.iterator_at(selection.last());
auto line_begin = buffer.iterator_at(selection.last().line);
boost::match_results<BufferIterator> results;
if (boost::regex_match(content.c_str(), m_insert_match) and
boost::regex_match(line_begin, position, results, m_line_match))
{
content = results.format(m_replacement.c_str());
auto it = std::find(content.begin(), content.end(), '$');
if (it != content.end())
{
++it;
if (it != content.end() && *it == 'c')
{
String suffix(it+1, content.end());
content = String(content.begin(), it-1);
buffer.insert(position, suffix);
auto& first = selection.first();
auto& last = selection.last();
if (first == last)
first = buffer.advance(first, -suffix.length());
last = buffer.advance(last, -suffix.length());
}
}
}
}
private:
Regex m_line_match;
Regex m_insert_match;
String m_replacement;
};
FilterAndId regex_filter_factory(FilterParameters params)
{
if (params.size() != 3)
throw runtime_error("wrong parameter count");
return FilterAndId{"re" + params[0] + "__" + params[1],
RegexFilter{params[0], params[1], params[2]}};
}
template<void (*filter_func)(Buffer&, Selection&, String&)>
class SimpleFilterFactory
{
public:
SimpleFilterFactory(const String& id) : m_id(id) {}
FilterAndId operator()(FilterParameters params) const
{
return FilterAndId(m_id, FilterFunc(filter_func));
}
private:
String m_id;
};
FilterAndId filter_group_factory(FilterParameters params)
{
if (params.size() != 1)
throw runtime_error("wrong parameter count");
return FilterAndId(params[0], FilterGroup());
}
void register_filters()
{
FilterRegistry& registry = FilterRegistry::instance();
registry.register_func("preserve_indent", SimpleFilterFactory<preserve_indent>("preserve_indent"));
registry.register_func("cleanup_whitespaces", SimpleFilterFactory<cleanup_whitespaces>("cleanup_whitespaces"));
registry.register_func("expand_tabulations", SimpleFilterFactory<expand_tabulations>("expand_tabulations"));
registry.register_func("regex", regex_filter_factory);
registry.register_func("group", filter_group_factory);
}
}

View File

@ -1,13 +0,0 @@
#ifndef filters_hh_INCLUDED
#define filters_hh_INCLUDED
#include "filter.hh"
namespace Kakoune
{
void register_filters();
}
#endif // filters_hh_INCLUDED

View File

@ -9,7 +9,6 @@
#include "debug.hh" #include "debug.hh"
#include "event_manager.hh" #include "event_manager.hh"
#include "file.hh" #include "file.hh"
#include "filters.hh"
#include "highlighters.hh" #include "highlighters.hh"
#include "hook_manager.hh" #include "hook_manager.hh"
#include "ncurses.hh" #include "ncurses.hh"
@ -271,7 +270,6 @@ int kakoune(memoryview<String> params)
BufferManager buffer_manager; BufferManager buffer_manager;
RegisterManager register_manager; RegisterManager register_manager;
HighlighterRegistry highlighter_registry; HighlighterRegistry highlighter_registry;
FilterRegistry filter_registry;
ColorRegistry color_registry; ColorRegistry color_registry;
ClientManager client_manager; ClientManager client_manager;
@ -281,7 +279,6 @@ int kakoune(memoryview<String> params)
register_registers(); register_registers();
register_commands(); register_commands();
register_highlighters(); register_highlighters();
register_filters();
write_debug("*** This is the debug buffer, where debug info will be written ***"); write_debug("*** This is the debug buffer, where debug info will be written ***");
write_debug("pid: " + to_string(getpid())); write_debug("pid: " + to_string(getpid()));

View File

@ -4,10 +4,10 @@ hook global BufCreate (.*/)?(kakrc|.*.kak) %{
hook global WinSetOption filetype=kak %{ hook global WinSetOption filetype=kak %{
addhl group kak-highlight addhl group kak-highlight
addhl -group kak-highlight regex \<(hook|rmhooks|addhl|rmhl|addfilter|rmfilter|exec|eval|source|runtime|def|decl|echo|edit|set)\> 0:keyword addhl -group kak-highlight regex \<(hook|rmhooks|addhl|rmhl|add|exec|eval|source|runtime|def|decl|echo|edit|set)\> 0:keyword
addhl -group kak-highlight regex \<(default|black|red|green|yellow|blue|magenta|cyan|white)\> 0:value addhl -group kak-highlight regex \<(default|black|red|green|yellow|blue|magenta|cyan|white)\> 0:value
addhl -group kak-highlight regex (?<=\<hook)\h+((global|buffer|window)|(\S+))\h+(\S+)\h+(\H+) 2:attribute 3:error 4:identifier 5:string addhl -group kak-highlight regex (?<=\<hook)\h+((global|buffer|window)|(\S+))\h+(\S+)\h+(\H+) 2:attribute 3:error 4:identifier 5:string
addhl -group kak-highlight regex (?<=\<set)\h+((global|buffer|window)|(\S+))\h+(\S+)\h+(\H+) 2:attribute 3:error 4:identifier 5:value addhl -group kak-highlight regex (?<=\<set)\h+((global|buffer|window)|(\S+))\h+(\S+)\h+(\S+) 2:attribute 3:error 4:identifier 5:value
addhl -group kak-highlight regex (?<=\<regex)\h+(\S+) 1:string addhl -group kak-highlight regex (?<=\<regex)\h+(\S+) 1:string
addhl -group kak-highlight regex (["'])(?:\\\1|.)*?\1 0:string addhl -group kak-highlight regex (["'])(?:\\\1|.)*?\1 0:string
addhl -group kak-highlight regex (^|\h)\#[^\n]*\n 0:comment addhl -group kak-highlight regex (^|\h)\#[^\n]*\n 0:comment