Merge branch 'mawww:master' into master
This commit is contained in:
commit
0cf5105df1
53
colors/black-on-white.kak
Normal file
53
colors/black-on-white.kak
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
# Black-on-bright-white colorscheme for minimal distraction & maximal contrast.
|
||||||
|
# Works well with e-ink screens.
|
||||||
|
|
||||||
|
# For Code
|
||||||
|
face global value black
|
||||||
|
face global type black
|
||||||
|
face global variable black
|
||||||
|
face global module black
|
||||||
|
face global function black
|
||||||
|
face global string black
|
||||||
|
face global keyword black
|
||||||
|
face global operator black
|
||||||
|
face global attribute black
|
||||||
|
face global comment black
|
||||||
|
face global documentation comment
|
||||||
|
face global meta black
|
||||||
|
face global builtin black
|
||||||
|
|
||||||
|
# For markup
|
||||||
|
face global title black
|
||||||
|
face global header black
|
||||||
|
face global mono black
|
||||||
|
face global block black
|
||||||
|
face global link black
|
||||||
|
face global bullet black
|
||||||
|
face global list black
|
||||||
|
|
||||||
|
# builtin faces
|
||||||
|
face global Default black,bright-white
|
||||||
|
face global PrimarySelection black,rgb:cccccc+fg
|
||||||
|
face global SecondarySelection black,rgb:e0e0e0+fg
|
||||||
|
face global PrimaryCursor bright-white,black+fg
|
||||||
|
face global SecondaryCursor bright-white,rgb:777777+fg
|
||||||
|
face global PrimaryCursorEol black,rgb:777777+fg
|
||||||
|
face global SecondaryCursorEol black,rgb:aaaaaa+fg
|
||||||
|
face global LineNumbers black,bright-white
|
||||||
|
face global LineNumberCursor bright-white,black
|
||||||
|
face global MenuForeground bright-white,black+fg
|
||||||
|
face global MenuBackground black,rgb:e0e0e0+fg
|
||||||
|
face global MenuInfo black # Overridden by MenuForeground and MenuBackground
|
||||||
|
face global Information black,rgb:e0e0e0
|
||||||
|
face global Error bright-white,black
|
||||||
|
face global DiagnosticError black
|
||||||
|
face global DiagnosticWarning black
|
||||||
|
face global StatusLine black,bright-white
|
||||||
|
face global StatusLineMode black,bright-white
|
||||||
|
face global StatusLineInfo black,bright-white
|
||||||
|
face global StatusLineValue black,bright-white
|
||||||
|
face global StatusCursor bright-white,black
|
||||||
|
face global Prompt bright-white,black
|
||||||
|
face global MatchingChar black,bright-white+b
|
||||||
|
face global Whitespace black,bright-white+fd
|
||||||
|
face global BufferPadding black,bright-white
|
|
@ -59,5 +59,5 @@ for examples.
|
||||||
When the write end of the fifo is closed, the buffer becomes an ordinary
|
When the write end of the fifo is closed, the buffer becomes an ordinary
|
||||||
<<buffers#scratch-buffers,scratch buffer>>. When the buffer is deleted,
|
<<buffers#scratch-buffers,scratch buffer>>. When the buffer is deleted,
|
||||||
Kakoune closes the read end of the fifo, so any program writing to it
|
Kakoune closes the read end of the fifo, so any program writing to it
|
||||||
will receive `SIGPIPE`. This is useful as it permits to stop the writing
|
will receive `SIGPIPE`. This is useful as it permits stopping the writing
|
||||||
program when the buffer is deleted.
|
program when the buffer is deleted.
|
||||||
|
|
|
@ -417,7 +417,7 @@ The following expansions are supported (with required context _in italics_):
|
||||||
_in window scope_ +
|
_in window scope_ +
|
||||||
list of coordinates and dimensions of the buffer-space
|
list of coordinates and dimensions of the buffer-space
|
||||||
available on the current window, in the following format:
|
available on the current window, in the following format:
|
||||||
`<coord_x> <coord_y> <width> <height>`
|
`<coord_y> <coord_x> <height> <width>`
|
||||||
|
|
||||||
Values in the above list that do not mention a context are available
|
Values in the above list that do not mention a context are available
|
||||||
everywhere.
|
everywhere.
|
||||||
|
|
|
@ -113,7 +113,7 @@ add-highlighter window/ regex //\h*(TODO:)[^\n]* 0:cyan 1:yellow,red
|
||||||
|
|
||||||
capture_id can be either the capture number, or its name if a
|
capture_id can be either the capture number, or its name if a
|
||||||
named capture is used in the regex (See
|
named capture is used in the regex (See
|
||||||
<<regex#Groups, `:doc regex Groups`>>)
|
<<regex#groups, `:doc regex groups`>>)
|
||||||
|
|
||||||
*dynregex* <expression> <capture_id>:<face> ...::
|
*dynregex* <expression> <capture_id>:<face> ...::
|
||||||
similar to regex, but expand (like a command parameter would) the
|
similar to regex, but expand (like a command parameter would) the
|
||||||
|
|
|
@ -817,7 +817,7 @@ The following keys are recognized by this mode to help with editing
|
||||||
|
|
||||||
*<a-!>*::
|
*<a-!>*::
|
||||||
expand the typed expansions in currently entered text
|
expand the typed expansions in currently entered text
|
||||||
(See <<expansions#typed-expansions,`:doc expansions typed-expansions`>>)
|
(See <<expansions#,`:doc expansions`>>)
|
||||||
|
|
||||||
*<a-;>*, *<a-semicolon>*::
|
*<a-;>*, *<a-semicolon>*::
|
||||||
escape to normal mode for a single command
|
escape to normal mode for a single command
|
||||||
|
|
|
@ -85,7 +85,7 @@ See prompt commands <<keys#prompt-commands,`:doc keys prompt-commands`>>.
|
||||||
Mode entered with `<a-i>`, `<a-a>` and various combinations of `[]{}` keys.
|
Mode entered with `<a-i>`, `<a-a>` and various combinations of `[]{}` keys.
|
||||||
It aims at crafting semantic selections, often called *text-objects*.
|
It aims at crafting semantic selections, often called *text-objects*.
|
||||||
|
|
||||||
See object commands <<keys#object-commands,`:doc keys object-commands`>>.
|
See object commands <<keys#object-selection,`:doc keys object-selection`>>.
|
||||||
|
|
||||||
=== User mode
|
=== User mode
|
||||||
|
|
||||||
|
|
|
@ -22,5 +22,5 @@ define-command -hidden file-detection %{ evaluate-commands %sh{
|
||||||
fi
|
fi
|
||||||
} }
|
} }
|
||||||
|
|
||||||
hook global BufOpenFile .* file-detection
|
hook -group file-detection global BufOpenFile .* file-detection
|
||||||
hook global BufWritePost .* file-detection
|
hook -group file-detection global BufWritePost .* file-detection
|
||||||
|
|
|
@ -56,8 +56,8 @@ evaluate-commands %sh{
|
||||||
keywords='break default func interface select case defer go map struct
|
keywords='break default func interface select case defer go map struct
|
||||||
chan else goto package switch const fallthrough if range type
|
chan else goto package switch const fallthrough if range type
|
||||||
continue for import return var'
|
continue for import return var'
|
||||||
types='bool byte chan complex128 complex64 error float32 float64 int int16 int32
|
types='any bool byte chan comparable complex128 complex64 error float32 float64 int int16 int32
|
||||||
int64 int8 interface intptr map rune string struct uint uint16 uint32 uint64 uint8'
|
int64 int8 interface intptr map rune string struct uint uint16 uint32 uint64 uint8 uintptr'
|
||||||
values='false true nil iota'
|
values='false true nil iota'
|
||||||
functions='append cap close complex copy delete imag len make new panic print println real recover'
|
functions='append cap close complex copy delete imag len make new panic print println real recover'
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ add-highlighter shared/i3/single_string/ regex "#[0-9a-fA-F]{6}" 0:value
|
||||||
|
|
||||||
# attributes
|
# attributes
|
||||||
add-highlighter shared/i3/code/ regex "client\.(background|statusline|background|separator|statusline)" 1:attribute
|
add-highlighter shared/i3/code/ regex "client\.(background|statusline|background|separator|statusline)" 1:attribute
|
||||||
add-highlighter shared/i3/code/ regex "client\.(focused_inactive|focused|unfocused|urgent|inactive_workspace|urgent_workspace|focused_workspace|active_workspace|placeholder)" 1:attribute
|
add-highlighter shared/i3/code/ regex "client\.(focused_inactive|focused_tab_title|focused|unfocused|urgent|inactive_workspace|urgent_workspace|focused_workspace|active_workspace|placeholder)" 1:attribute
|
||||||
|
|
||||||
# Commands
|
# Commands
|
||||||
# ‾‾‾‾‾‾‾‾
|
# ‾‾‾‾‾‾‾‾
|
||||||
|
|
|
@ -39,7 +39,7 @@ define-command autorestore-restore-buffer \
|
||||||
## Replace the content of the buffer with the content of the backup file
|
## Replace the content of the buffer with the content of the backup file
|
||||||
echo -debug Restoring file: ${newer}
|
echo -debug Restoring file: ${newer}
|
||||||
|
|
||||||
execute-keys -draft %{ %d!cat<space>\"${newer}\"<ret>d }
|
execute-keys -draft %{%d!cat<space>\"${newer}\"<ret>jd}
|
||||||
|
|
||||||
## If the backup file has to be removed, issue the command once
|
## If the backup file has to be removed, issue the command once
|
||||||
## the current buffer has been saved
|
## the current buffer has been saved
|
||||||
|
|
|
@ -14,7 +14,8 @@ define-command format-selections -docstring "Format the selections individually"
|
||||||
echo "fail 'The option ''formatcmd'' must be set'"
|
echo "fail 'The option ''formatcmd'' must be set'"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
evaluate-commands -draft -no-hooks -save-regs '|' %{
|
evaluate-commands -draft -no-hooks -save-regs 'e|' %{
|
||||||
|
set-register e nop
|
||||||
set-register '|' %{
|
set-register '|' %{
|
||||||
format_in="$(mktemp "${TMPDIR:-/tmp}"/kak-formatter.XXXXXX)"
|
format_in="$(mktemp "${TMPDIR:-/tmp}"/kak-formatter.XXXXXX)"
|
||||||
format_out="$(mktemp "${TMPDIR:-/tmp}"/kak-formatter.XXXXXX)"
|
format_out="$(mktemp "${TMPDIR:-/tmp}"/kak-formatter.XXXXXX)"
|
||||||
|
@ -24,12 +25,13 @@ define-command format-selections -docstring "Format the selections individually"
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
cat "$format_out"
|
cat "$format_out"
|
||||||
else
|
else
|
||||||
printf 'eval -client %s %%{ fail formatter returned an error %s }\n' "$kak_client" "$?" | kak -p "$kak_session"
|
echo "set-register e fail formatter returned an error (exit code $?)" >"$kak_command_fifo"
|
||||||
cat "$format_in"
|
cat "$format_in"
|
||||||
fi
|
fi
|
||||||
rm -f "$format_in" "$format_out"
|
rm -f "$format_in" "$format_out"
|
||||||
}
|
}
|
||||||
execute-keys '|<ret>'
|
execute-keys '|<ret>'
|
||||||
|
%reg{e}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -157,7 +157,7 @@ define-command -params 1.. \
|
||||||
update_diff() {
|
update_diff() {
|
||||||
(
|
(
|
||||||
cd_bufdir
|
cd_bufdir
|
||||||
git --no-pager diff -U0 "$kak_buffile" | perl -e '
|
git --no-pager diff --no-ext-diff -U0 "$kak_buffile" | perl -e '
|
||||||
$flags = $ENV{"kak_timestamp"};
|
$flags = $ENV{"kak_timestamp"};
|
||||||
foreach $line (<STDIN>) {
|
foreach $line (<STDIN>) {
|
||||||
if ($line =~ /@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))?/) {
|
if ($line =~ /@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))?/) {
|
||||||
|
|
|
@ -2086,14 +2086,7 @@ const CommandDesc execute_keys_cmd = {
|
||||||
ScopedSetBool disable_keymaps(context.keymaps_disabled(), not parser.get_switch("with-maps"));
|
ScopedSetBool disable_keymaps(context.keymaps_disabled(), not parser.get_switch("with-maps"));
|
||||||
ScopedSetBool disable_hoooks(context.hooks_disabled(), not parser.get_switch("with-hooks"));
|
ScopedSetBool disable_hoooks(context.hooks_disabled(), not parser.get_switch("with-hooks"));
|
||||||
|
|
||||||
KeyList keys;
|
for (auto& key : parser | transform(parse_keys) | flatten())
|
||||||
for (auto& param : parser)
|
|
||||||
{
|
|
||||||
KeyList param_keys = parse_keys(param);
|
|
||||||
keys.insert(keys.end(), param_keys.begin(), param_keys.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& key : keys)
|
|
||||||
context.input_handler().handle_key(key);
|
context.input_handler().handle_key(key);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,9 @@ struct Array
|
||||||
T m_data[N];
|
T m_data[N];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T, typename... U> requires (std::is_same_v<T, U> and ...)
|
||||||
|
Array(T, U...) -> Array<T, 1 + sizeof...(U)>;
|
||||||
|
|
||||||
template<typename T, size_t N, size_t... Indices>
|
template<typename T, size_t N, size_t... Indices>
|
||||||
constexpr Array<T, N> make_array(const T (&data)[N], std::index_sequence<Indices...>)
|
constexpr Array<T, N> make_array(const T (&data)[N], std::index_sequence<Indices...>)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1694,19 +1694,12 @@ InputHandler::ScopedForceNormal::~ScopedForceNormal()
|
||||||
if (not m_mode)
|
if (not m_mode)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
kak_assert(m_handler.m_mode_stack.size() > 1);
|
|
||||||
|
|
||||||
if (m_mode == m_handler.m_mode_stack.back().get())
|
if (m_mode == m_handler.m_mode_stack.back().get())
|
||||||
m_handler.pop_mode(m_mode);
|
m_handler.pop_mode(m_mode);
|
||||||
else
|
else if (auto it = find(m_handler.m_mode_stack, m_mode);
|
||||||
{
|
it != m_handler.m_mode_stack.end())
|
||||||
auto it = find_if(m_handler.m_mode_stack,
|
|
||||||
[this](const RefPtr<InputMode>& m)
|
|
||||||
{ return m.get() == m_mode; });
|
|
||||||
kak_assert(it != m_handler.m_mode_stack.end());
|
|
||||||
m_handler.m_mode_stack.erase(it);
|
m_handler.m_mode_stack.erase(it);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_valid(Key key)
|
static bool is_valid(Key key)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#include "normal.hh"
|
#include "normal.hh"
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#include "buffer.hh"
|
#include "buffer.hh"
|
||||||
#include "buffer_manager.hh"
|
#include "buffer_manager.hh"
|
||||||
#include "buffer_utils.hh"
|
#include "buffer_utils.hh"
|
||||||
|
@ -31,8 +29,6 @@
|
||||||
namespace Kakoune
|
namespace Kakoune
|
||||||
{
|
{
|
||||||
|
|
||||||
using namespace std::placeholders;
|
|
||||||
|
|
||||||
enum class SelectMode
|
enum class SelectMode
|
||||||
{
|
{
|
||||||
Replace,
|
Replace,
|
||||||
|
@ -1302,7 +1298,15 @@ void select_object(Context& context, NormalParams params)
|
||||||
auto obj_it = find(selectors | transform(&ObjectType::key), key).base();
|
auto obj_it = find(selectors | transform(&ObjectType::key), key).base();
|
||||||
if (obj_it != std::end(selectors))
|
if (obj_it != std::end(selectors))
|
||||||
return select_and_set_last<mode>(
|
return select_and_set_last<mode>(
|
||||||
context, std::bind(obj_it->func, _1, _2, count, flags));
|
context, [=](Context& context, Selection& sel) { return obj_it->func(context, sel, count, flags); });
|
||||||
|
|
||||||
|
static constexpr auto regex_selector = [=](StringView open, StringView close, int count) {
|
||||||
|
return [open=Regex{open, RegexCompileFlags::Backward},
|
||||||
|
close=Regex{close, RegexCompileFlags::Backward},
|
||||||
|
count](Context& context, Selection& sel) {
|
||||||
|
return select_surrounding(context, sel, open, close, count, flags);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
if (key == 'c')
|
if (key == 'c')
|
||||||
{
|
{
|
||||||
|
@ -1323,17 +1327,13 @@ void select_object(Context& context, NormalParams params)
|
||||||
|
|
||||||
struct error : runtime_error { error(size_t) : runtime_error{"desc parsing failed, expected <open>,<close>"} {} };
|
struct error : runtime_error { error(size_t) : runtime_error{"desc parsing failed, expected <open>,<close>"} {} };
|
||||||
|
|
||||||
auto params = cmdline | split<StringView>(',', '\\') |
|
auto params = cmdline | split<StringView>(',', '\\')
|
||||||
transform(unescape<',', '\\'>) | static_gather<error, 2>();
|
| transform(unescape<',', '\\'>)
|
||||||
|
| static_gather<error, 2>();
|
||||||
if (params[0].empty() or params[1].empty())
|
if (params[0].empty() or params[1].empty())
|
||||||
throw error{0};
|
throw error{0};
|
||||||
|
|
||||||
select_and_set_last<mode>(
|
select_and_set_last<mode>(context, regex_selector(params[0], params[1], count));
|
||||||
context, std::bind(select_surrounding, _1, _2,
|
|
||||||
Regex{params[0], RegexCompileFlags::Backward},
|
|
||||||
Regex{params[1], RegexCompileFlags::Backward},
|
|
||||||
count, flags));
|
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1350,10 +1350,10 @@ void select_object(Context& context, NormalParams params)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr struct SurroundingPair
|
static constexpr struct
|
||||||
{
|
{
|
||||||
char opening;
|
char open;
|
||||||
char closing;
|
char close;
|
||||||
char name;
|
char name;
|
||||||
} surrounding_pairs[] = {
|
} surrounding_pairs[] = {
|
||||||
{ '(', ')', 'b' },
|
{ '(', ')', 'b' },
|
||||||
|
@ -1364,28 +1364,15 @@ void select_object(Context& context, NormalParams params)
|
||||||
{ '\'', '\'', 'q' },
|
{ '\'', '\'', 'q' },
|
||||||
{ '`', '`', 'g' },
|
{ '`', '`', 'g' },
|
||||||
};
|
};
|
||||||
auto pair_it = find_if(surrounding_pairs,
|
if (auto it = find_if(surrounding_pairs, [key](auto s) { return key == s.open or key == s.close or key == s.name; });
|
||||||
[key](const SurroundingPair& s) {
|
it != std::end(surrounding_pairs))
|
||||||
return key == s.opening or key == s.closing or
|
|
||||||
(s.name != 0 and key == s.name);
|
|
||||||
});
|
|
||||||
if (pair_it != std::end(surrounding_pairs))
|
|
||||||
return select_and_set_last<mode>(
|
return select_and_set_last<mode>(
|
||||||
context, std::bind(select_surrounding, _1, _2,
|
context, regex_selector(format("\\Q{}", it->open), format("\\Q{}", it->close), count));
|
||||||
Regex{format("\\Q{}", pair_it->opening), RegexCompileFlags::Backward},
|
|
||||||
Regex{format("\\Q{}", pair_it->closing), RegexCompileFlags::Backward},
|
|
||||||
count, flags));
|
|
||||||
|
|
||||||
if (not key.codepoint())
|
if (auto cp = key.codepoint(); cp and is_punctuation(*cp, {}))
|
||||||
return;
|
|
||||||
|
|
||||||
const Codepoint cp = *key.codepoint();
|
|
||||||
if (is_punctuation(cp, {}))
|
|
||||||
{
|
{
|
||||||
auto re = Regex{"\\Q" + to_string(cp), RegexCompileFlags::Backward};
|
auto re = "\\Q" + to_string(*cp);
|
||||||
return select_and_set_last<mode>(
|
return select_and_set_last<mode>(context, regex_selector(re, re, count));
|
||||||
context, std::bind(select_surrounding, _1, _2,
|
|
||||||
re, re, count, flags));
|
|
||||||
}
|
}
|
||||||
}, get_title(),
|
}, get_title(),
|
||||||
build_autoinfo_for_mapping(context, KeymapMode::Object,
|
build_autoinfo_for_mapping(context, KeymapMode::Object,
|
||||||
|
@ -1537,11 +1524,10 @@ void select_to_next_char(Context& context, NormalParams params)
|
||||||
constexpr auto new_flags = flags & SelectFlags::Extend ? SelectMode::Extend
|
constexpr auto new_flags = flags & SelectFlags::Extend ? SelectMode::Extend
|
||||||
: SelectMode::Replace;
|
: SelectMode::Replace;
|
||||||
select_and_set_last<new_flags>(
|
select_and_set_last<new_flags>(
|
||||||
context,
|
context, [cp=*cp, count=params.count] (auto& context, auto& sel) {
|
||||||
std::bind(flags & SelectFlags::Reverse ? select_to_reverse
|
auto& func = flags & SelectFlags::Reverse ? select_to_reverse : select_to;
|
||||||
: select_to,
|
return func(context, sel, cp, count, flags & SelectFlags::Inclusive);
|
||||||
_1, _2, *cp, params.count,
|
});
|
||||||
flags & SelectFlags::Inclusive));
|
|
||||||
}, get_title(), "enter char to select to");
|
}, get_title(), "enter char to select to");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,24 +7,29 @@ namespace Kakoune
|
||||||
{
|
{
|
||||||
|
|
||||||
UnitTest test_ranges{[] {
|
UnitTest test_ranges{[] {
|
||||||
auto check_equal = [](auto&& container, ConstArrayView<StringView> expected) {
|
using Strs = ConstArrayView<StringView>;
|
||||||
|
auto check_equal = [](auto&& container, auto&& expected) {
|
||||||
kak_assert(std::equal(container.begin(), container.end(), expected.begin(), expected.end()));
|
kak_assert(std::equal(container.begin(), container.end(), expected.begin(), expected.end()));
|
||||||
};
|
};
|
||||||
check_equal("a,b,c"_sv | split<StringView>(','), {"a", "b", "c"});
|
check_equal("a,b,c"_sv | split<StringView>(','), Strs{"a", "b", "c"});
|
||||||
check_equal(",b,c"_sv | split<StringView>(','), {"", "b", "c"});
|
check_equal(",b,c"_sv | split<StringView>(','), Strs{"", "b", "c"});
|
||||||
check_equal(",b,"_sv | split<StringView>(','), {"", "b", ""});
|
check_equal(",b,"_sv | split<StringView>(','), Strs{"", "b", ""});
|
||||||
check_equal(","_sv | split<StringView>(','), {"", ""});
|
check_equal(","_sv | split<StringView>(','), Strs{"", ""});
|
||||||
check_equal(""_sv | split<StringView>(','), {});
|
check_equal(""_sv | split<StringView>(','), Strs{});
|
||||||
|
|
||||||
check_equal("a,b,c,"_sv | split_after<StringView>(','), {"a,", "b,", "c,"});
|
check_equal("a,b,c,"_sv | split_after<StringView>(','), Strs{"a,", "b,", "c,"});
|
||||||
check_equal("a,b,c"_sv | split_after<StringView>(','), {"a,", "b,", "c"});
|
check_equal("a,b,c"_sv | split_after<StringView>(','), Strs{"a,", "b,", "c"});
|
||||||
|
|
||||||
check_equal(R"(a\,,\,b,\,)"_sv | split<StringView>(',', '\\')
|
check_equal(R"(a\,,\,b,\,)"_sv | split<StringView>(',', '\\')
|
||||||
| transform(unescape<',', '\\'>), {"a,", ",b", ","});
|
| transform(unescape<',', '\\'>), Strs{"a,", ",b", ","});
|
||||||
check_equal(R"(\,\,)"_sv | split<StringView>(',', '\\')
|
check_equal(R"(\,\,)"_sv | split<StringView>(',', '\\')
|
||||||
| transform(unescape<',', '\\'>), {",,"});
|
| transform(unescape<',', '\\'>), Strs{",,"});
|
||||||
check_equal(R"(\\,\\,)"_sv | split<StringView>(',', '\\')
|
check_equal(R"(\\,\\,)"_sv | split<StringView>(',', '\\')
|
||||||
| transform(unescape<',', '\\'>), {R"(\)", R"(\)", ""});
|
| transform(unescape<',', '\\'>), Strs{R"(\)", R"(\)", ""});
|
||||||
|
|
||||||
|
check_equal(Array{""_sv, "abc"_sv, ""_sv, "def"_sv, ""_sv} | flatten(), "abcdef"_sv);
|
||||||
|
check_equal(Vector<StringView>{"", ""} | flatten(), ""_sv);
|
||||||
|
check_equal(Vector<StringView>{} | flatten(), ""_sv);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
132
src/ranges.hh
132
src/ranges.hh
|
@ -24,13 +24,33 @@ decltype(auto) operator| (Range&& range, ViewFactory<Func> factory)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Range>
|
template<typename Range>
|
||||||
struct decay_range_impl { using type = std::remove_cvref_t<Range>; };
|
struct DecayRangeImpl { using type = std::remove_cvref_t<Range>; };
|
||||||
|
|
||||||
template<typename Range>
|
template<typename Range>
|
||||||
struct decay_range_impl<Range&> { using type = Range&; };
|
struct DecayRangeImpl<Range&> { using type = Range&; };
|
||||||
|
|
||||||
template<typename Range>
|
template<typename Range>
|
||||||
using decay_range = typename decay_range_impl<Range>::type;
|
using DecayRange = typename DecayRangeImpl<Range>::type;
|
||||||
|
|
||||||
|
template<typename Range>
|
||||||
|
struct RangeHolderImpl { using type = std::remove_cvref_t<Range>; };
|
||||||
|
|
||||||
|
template<typename Range>
|
||||||
|
struct RangeHolderImpl<Range&> {
|
||||||
|
struct type
|
||||||
|
{
|
||||||
|
Range* range{};
|
||||||
|
|
||||||
|
decltype(auto) begin() { return std::begin(*range); }
|
||||||
|
decltype(auto) end() { return std::end(*range); }
|
||||||
|
|
||||||
|
type& operator=(Range& r) { range = &r; return *this; }
|
||||||
|
operator Range&() { return *range; }
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Range>
|
||||||
|
using RangeHolder = typename RangeHolderImpl<Range>::type;
|
||||||
|
|
||||||
template<typename Range>
|
template<typename Range>
|
||||||
struct ReverseView
|
struct ReverseView
|
||||||
|
@ -47,11 +67,11 @@ struct ReverseView
|
||||||
Range m_range;
|
Range m_range;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline auto reverse()
|
constexpr auto reverse()
|
||||||
{
|
{
|
||||||
return ViewFactory{[](auto&& range) {
|
return ViewFactory{[](auto&& range) {
|
||||||
using Range = decltype(range);
|
using Range = decltype(range);
|
||||||
return ReverseView<decay_range<Range>>{std::forward<Range>(range)};
|
return ReverseView<DecayRange<Range>>{std::forward<Range>(range)};
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,11 +91,11 @@ struct SkipView
|
||||||
size_t m_skip_count;
|
size_t m_skip_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline auto skip(size_t count)
|
constexpr auto skip(size_t count)
|
||||||
{
|
{
|
||||||
return ViewFactory{[count](auto&& range) {
|
return ViewFactory{[count](auto&& range) {
|
||||||
using Range = decltype(range);
|
using Range = decltype(range);
|
||||||
return SkipView<decay_range<Range>>{std::forward<Range>(range), count};
|
return SkipView<DecayRange<Range>>{std::forward<Range>(range), count};
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,11 +109,11 @@ struct DropView
|
||||||
size_t m_drop_count;
|
size_t m_drop_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline auto drop(size_t count)
|
constexpr auto drop(size_t count)
|
||||||
{
|
{
|
||||||
return ViewFactory{[count](auto&& range) {
|
return ViewFactory{[count](auto&& range) {
|
||||||
using Range = decltype(range);
|
using Range = decltype(range);
|
||||||
return DropView<decay_range<Range>>{std::forward<Range>(range), count};
|
return DropView<DecayRange<Range>>{std::forward<Range>(range), count};
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,11 +167,11 @@ struct FilterView
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Filter>
|
template<typename Filter>
|
||||||
inline auto filter(Filter f)
|
constexpr auto filter(Filter f)
|
||||||
{
|
{
|
||||||
return ViewFactory{[f = std::move(f)](auto&& range) {
|
return ViewFactory{[f = std::move(f)](auto&& range) {
|
||||||
using Range = decltype(range);
|
using Range = decltype(range);
|
||||||
return FilterView<decay_range<Range>, Filter>{std::forward<Range>(range), std::move(f)};
|
return FilterView<DecayRange<Range>, Filter>{std::forward<Range>(range), std::move(f)};
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,11 +213,11 @@ struct EnumerateView
|
||||||
Range m_range;
|
Range m_range;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline auto enumerate()
|
constexpr auto enumerate()
|
||||||
{
|
{
|
||||||
return ViewFactory{[](auto&& range) {
|
return ViewFactory{[](auto&& range) {
|
||||||
using Range = decltype(range);
|
using Range = decltype(range);
|
||||||
return EnumerateView<decay_range<Range>>{std::forward<Range>(range)};
|
return EnumerateView<DecayRange<Range>>{std::forward<Range>(range)};
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,11 +272,11 @@ struct TransformView
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Transform>
|
template<typename Transform>
|
||||||
inline auto transform(Transform t)
|
constexpr auto transform(Transform t)
|
||||||
{
|
{
|
||||||
return ViewFactory{[t = std::move(t)](auto&& range) {
|
return ViewFactory{[t = std::move(t)](auto&& range) {
|
||||||
using Range = decltype(range);
|
using Range = decltype(range);
|
||||||
return TransformView<decay_range<Range>, Transform>{std::forward<Range>(range), std::move(t)};
|
return TransformView<DecayRange<Range>, Transform>{std::forward<Range>(range), std::move(t)};
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,7 +287,7 @@ template<typename T, typename U> requires std::is_same_v<std::remove_cvref_t<dec
|
||||||
struct is_pointer_like<T, U> : std::true_type {};
|
struct is_pointer_like<T, U> : std::true_type {};
|
||||||
|
|
||||||
template<typename M, typename T>
|
template<typename M, typename T>
|
||||||
inline auto transform(M T::*member)
|
constexpr auto transform(M T::*member)
|
||||||
{
|
{
|
||||||
return transform([member](auto&& arg) -> decltype(auto) {
|
return transform([member](auto&& arg) -> decltype(auto) {
|
||||||
using Arg = decltype(arg);
|
using Arg = decltype(arg);
|
||||||
|
@ -364,7 +384,7 @@ auto split(Element separator)
|
||||||
{
|
{
|
||||||
return ViewFactory{[s = std::move(separator)](auto&& range) {
|
return ViewFactory{[s = std::move(separator)](auto&& range) {
|
||||||
using Range = decltype(range);
|
using Range = decltype(range);
|
||||||
return SplitView<decay_range<Range>, false, false, Element, ValueType>{std::forward<Range>(range), std::move(s), {}};
|
return SplitView<DecayRange<Range>, false, false, Element, ValueType>{std::forward<Range>(range), std::move(s), {}};
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,7 +393,7 @@ auto split_after(Element separator)
|
||||||
{
|
{
|
||||||
return ViewFactory{[s = std::move(separator)](auto&& range) {
|
return ViewFactory{[s = std::move(separator)](auto&& range) {
|
||||||
using Range = decltype(range);
|
using Range = decltype(range);
|
||||||
return SplitView<decay_range<Range>, false, true, Element, ValueType>{std::forward<Range>(range), std::move(s), {}};
|
return SplitView<DecayRange<Range>, false, true, Element, ValueType>{std::forward<Range>(range), std::move(s), {}};
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,7 +402,79 @@ auto split(Element separator, Element escaper)
|
||||||
{
|
{
|
||||||
return ViewFactory{[s = std::move(separator), e = std::move(escaper)](auto&& range) {
|
return ViewFactory{[s = std::move(separator), e = std::move(escaper)](auto&& range) {
|
||||||
using Range = decltype(range);
|
using Range = decltype(range);
|
||||||
return SplitView<decay_range<Range>, true, false, Element, ValueType>{std::forward<Range>(range), std::move(s), std::move(e)};
|
return SplitView<DecayRange<Range>, true, false, Element, ValueType>{std::forward<Range>(range), std::move(s), std::move(e)};
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Range>
|
||||||
|
struct FlattenedView
|
||||||
|
{
|
||||||
|
using OuterIt = IteratorOf<Range>;
|
||||||
|
using InnerRange = ValueOf<Range>;
|
||||||
|
using InnerIt = IteratorOf<InnerRange>;
|
||||||
|
|
||||||
|
struct Iterator
|
||||||
|
{
|
||||||
|
using value_type = typename std::iterator_traits<InnerIt>::value_type;
|
||||||
|
using iterator_category = std::forward_iterator_tag;
|
||||||
|
using difference_type = std::size_t;
|
||||||
|
using reference = value_type&;
|
||||||
|
|
||||||
|
Iterator() = default;
|
||||||
|
Iterator(OuterIt begin, OuterIt end) : m_outer_it{begin}, m_outer_end{end}
|
||||||
|
{
|
||||||
|
find_next_inner();
|
||||||
|
}
|
||||||
|
|
||||||
|
decltype(auto) operator*() { return *m_inner_it; }
|
||||||
|
|
||||||
|
Iterator& operator++()
|
||||||
|
{
|
||||||
|
if (++m_inner_it == std::end(m_inner_range))
|
||||||
|
{
|
||||||
|
++m_outer_it;
|
||||||
|
find_next_inner();
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Iterator operator++(int) { auto copy = *this; ++*this; return copy; }
|
||||||
|
|
||||||
|
friend bool operator==(const Iterator& lhs, const Iterator& rhs)
|
||||||
|
{
|
||||||
|
return lhs.m_outer_it == rhs.m_outer_it and lhs.m_inner_it == rhs.m_inner_it;
|
||||||
|
}
|
||||||
|
|
||||||
|
void find_next_inner()
|
||||||
|
{
|
||||||
|
m_inner_it = InnerIt{};
|
||||||
|
for (; m_outer_it != m_outer_end; ++m_outer_it)
|
||||||
|
{
|
||||||
|
m_inner_range = *m_outer_it;
|
||||||
|
if (std::begin(m_inner_range) != std::end(m_inner_range))
|
||||||
|
{
|
||||||
|
m_inner_it = std::begin(m_inner_range);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OuterIt m_outer_it{};
|
||||||
|
OuterIt m_outer_end{};
|
||||||
|
InnerIt m_inner_it{};
|
||||||
|
RangeHolder<InnerRange> m_inner_range;
|
||||||
|
};
|
||||||
|
|
||||||
|
Iterator begin() const { return {std::begin(m_range), std::end(m_range)}; }
|
||||||
|
Iterator end() const { return {std::end(m_range), std::end(m_range)}; }
|
||||||
|
|
||||||
|
Range m_range;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr auto flatten()
|
||||||
|
{
|
||||||
|
return ViewFactory{[](auto&& range){
|
||||||
|
using Range = decltype(range);
|
||||||
|
return FlattenedView<DecayRange<Range>>{std::forward<Range>(range)};
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,7 +526,7 @@ struct ConcatView
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Range1, typename Range2>
|
template<typename Range1, typename Range2>
|
||||||
ConcatView<decay_range<Range1>, decay_range<Range2>> concatenated(Range1&& range1, Range2&& range2)
|
ConcatView<DecayRange<Range1>, DecayRange<Range2>> concatenated(Range1&& range1, Range2&& range2)
|
||||||
{
|
{
|
||||||
return {range1, range2};
|
return {range1, range2};
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,8 +88,8 @@ struct RefPtr
|
||||||
acquire();
|
acquire();
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool operator==(const RefPtr& lhs, const RefPtr& rhs) { return lhs.m_ptr == rhs.m_ptr; }
|
friend bool operator==(const RefPtr& lhs, const RefPtr& rhs) = default;
|
||||||
friend bool operator!=(const RefPtr& lhs, const RefPtr& rhs) { return lhs.m_ptr != rhs.m_ptr; }
|
friend bool operator==(const RefPtr& lhs, const T* rhs) { return lhs.m_ptr == rhs; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T* m_ptr = nullptr;
|
T* m_ptr = nullptr;
|
||||||
|
|
|
@ -605,8 +605,8 @@ const String& session_directory()
|
||||||
|
|
||||||
String session_path(StringView session)
|
String session_path(StringView session)
|
||||||
{
|
{
|
||||||
if (contains(session, '/'))
|
if (not all_of(session, is_identifier))
|
||||||
throw runtime_error{"session names cannot have slashes"};
|
throw runtime_error{format("invalid session name: '{}'", session)};
|
||||||
return format("{}/{}", session_directory(), session);
|
return format("{}/{}", session_directory(), session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -614,7 +614,10 @@ static sockaddr_un session_addr(StringView session)
|
||||||
{
|
{
|
||||||
sockaddr_un addr;
|
sockaddr_un addr;
|
||||||
addr.sun_family = AF_UNIX;
|
addr.sun_family = AF_UNIX;
|
||||||
strcpy(addr.sun_path, session_path(session).c_str());
|
String path = session_path(session);
|
||||||
|
if (path.length() + 1 > sizeof addr.sun_path)
|
||||||
|
throw runtime_error{format("socket path too long: '{}'", path)};
|
||||||
|
strcpy(addr.sun_path, path.c_str());
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -848,9 +851,6 @@ private:
|
||||||
Server::Server(String session_name, bool is_daemon)
|
Server::Server(String session_name, bool is_daemon)
|
||||||
: m_session{std::move(session_name)}, m_is_daemon{is_daemon}
|
: m_session{std::move(session_name)}, m_is_daemon{is_daemon}
|
||||||
{
|
{
|
||||||
if (not all_of(m_session, is_identifier))
|
|
||||||
throw runtime_error{format("invalid session name: '{}'", m_session)};
|
|
||||||
|
|
||||||
int listen_sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
int listen_sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
fcntl(listen_sock, F_SETFD, FD_CLOEXEC);
|
fcntl(listen_sock, F_SETFD, FD_CLOEXEC);
|
||||||
sockaddr_un addr = session_addr(m_session);
|
sockaddr_un addr = session_addr(m_session);
|
||||||
|
@ -885,9 +885,6 @@ Server::Server(String session_name, bool is_daemon)
|
||||||
|
|
||||||
bool Server::rename_session(StringView name)
|
bool Server::rename_session(StringView name)
|
||||||
{
|
{
|
||||||
if (not all_of(name, is_identifier))
|
|
||||||
throw runtime_error{format("invalid session name: '{}'", name)};
|
|
||||||
|
|
||||||
String old_socket_file = session_path(m_session);
|
String old_socket_file = session_path(m_session);
|
||||||
String new_socket_file = session_path(name);
|
String new_socket_file = session_path(name);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
i<a-;>,d<esc>
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
edit -scratch
|
||||||
|
map global user d :delete-buffer<ret>
|
Loading…
Reference in New Issue
Block a user