Merge branch 'mawww:master' into master

This commit is contained in:
in0ni 2022-05-03 22:15:42 -04:00 committed by GitHub
commit 0cf5105df1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 242 additions and 113 deletions

53
colors/black-on-white.kak Normal file
View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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+))?/) {

View File

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

View File

@ -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...>)
{ {

View File

@ -1694,18 +1694,11 @@ 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)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1 @@
i<a-;>,d<esc>

View File

@ -0,0 +1,2 @@
edit -scratch
map global user d :delete-buffer<ret>