From 293a02bfa0bb091fa180bbda546894d2c355914b Mon Sep 17 00:00:00 2001 From: Ameer Ghani Date: Mon, 4 Apr 2022 23:09:28 -0400 Subject: [PATCH 02/19] rc/filetype/go: add new go 1.18 predeclared identifiers Go 1.18 introduces the `any` and `comparable` predeclared identifiers. Modify the list of identifiers here, so syntax highlighting will catch these new identifiers. See https://go.dev/ref/spec#Predeclared_identifiers. --- rc/filetype/go.kak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rc/filetype/go.kak b/rc/filetype/go.kak index a0a33ae4..8e091f64 100644 --- a/rc/filetype/go.kak +++ b/rc/filetype/go.kak @@ -56,7 +56,7 @@ evaluate-commands %sh{ keywords='break default func interface select case defer go map struct chan else goto package switch const fallthrough if range type 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' values='false true nil iota' functions='append cap close complex copy delete imag len make new panic print println real recover' From f29ff7e3c642fc38de659ec5535fa00bbe74323f Mon Sep 17 00:00:00 2001 From: Ameer Ghani Date: Mon, 4 Apr 2022 23:14:31 -0400 Subject: [PATCH 03/19] rc/filetype/go: uintptr type missing syntax highlighting --- rc/filetype/go.kak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rc/filetype/go.kak b/rc/filetype/go.kak index 8e091f64..c993c889 100644 --- a/rc/filetype/go.kak +++ b/rc/filetype/go.kak @@ -57,7 +57,7 @@ evaluate-commands %sh{ chan else goto package switch const fallthrough if range type continue for import return var' 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' functions='append cap close complex copy delete imag len make new panic print println real recover' From 9e6b678cf709986e3ee83d1354da577f7f436c47 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Thu, 7 Apr 2022 21:23:10 +1000 Subject: [PATCH 04/19] Do all session name validation in session_path(). --- src/remote.cc | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/remote.cc b/src/remote.cc index e6992c20..7a8f0d02 100644 --- a/src/remote.cc +++ b/src/remote.cc @@ -605,8 +605,8 @@ const String& session_directory() String session_path(StringView session) { - if (contains(session, '/')) - throw runtime_error{"session names cannot have slashes"}; + if (not all_of(session, is_identifier)) + throw runtime_error{format("invalid session name: '{}'", session)}; return format("{}/{}", session_directory(), session); } @@ -848,9 +848,6 @@ private: Server::Server(String session_name, bool 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); fcntl(listen_sock, F_SETFD, FD_CLOEXEC); sockaddr_un addr = session_addr(m_session); @@ -885,9 +882,6 @@ Server::Server(String session_name, bool is_daemon) 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 new_socket_file = session_path(name); From 9cf8a3ccd6531c2cf2695b4598c6ceff75ed2dc9 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Thu, 7 Apr 2022 21:36:15 +1000 Subject: [PATCH 05/19] Check for buffer overflow when constructing the socket path. --- src/remote.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/remote.cc b/src/remote.cc index 7a8f0d02..63a7fecf 100644 --- a/src/remote.cc +++ b/src/remote.cc @@ -614,7 +614,10 @@ static sockaddr_un session_addr(StringView session) { sockaddr_un addr; 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; } From 7c43a4b51ba9f93ee1f83198e52dc064e5b43b52 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Tue, 29 Mar 2022 22:36:01 +0200 Subject: [PATCH 06/19] doc: fix dead links to doc pages --- doc/pages/highlighters.asciidoc | 2 +- doc/pages/keys.asciidoc | 2 +- doc/pages/modes.asciidoc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/pages/highlighters.asciidoc b/doc/pages/highlighters.asciidoc index ffd15fa1..098089dd 100644 --- a/doc/pages/highlighters.asciidoc +++ b/doc/pages/highlighters.asciidoc @@ -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 named capture is used in the regex (See - <>) + <>) *dynregex* : ...:: similar to regex, but expand (like a command parameter would) the diff --git a/doc/pages/keys.asciidoc b/doc/pages/keys.asciidoc index e117b532..e26d6925 100644 --- a/doc/pages/keys.asciidoc +++ b/doc/pages/keys.asciidoc @@ -817,7 +817,7 @@ The following keys are recognized by this mode to help with editing **:: expand the typed expansions in currently entered text - (See <>) + (See <>) **, **:: escape to normal mode for a single command diff --git a/doc/pages/modes.asciidoc b/doc/pages/modes.asciidoc index 0424509c..754dda5b 100644 --- a/doc/pages/modes.asciidoc +++ b/doc/pages/modes.asciidoc @@ -85,7 +85,7 @@ See prompt commands <>. Mode entered with ``, `` and various combinations of `[]{}` keys. It aims at crafting semantic selections, often called *text-objects*. -See object commands <>. +See object commands <>. === User mode From 019a73f4b9aa3909923ac48665d4be7af37fb0f4 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sun, 20 Feb 2022 08:53:31 +0100 Subject: [PATCH 07/19] rc i3: highlight sway's focused_tab_title option Not sure if this should support sway-specific extensions but it doesn't hurt. --- rc/filetype/i3.kak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rc/filetype/i3.kak b/rc/filetype/i3.kak index 6b37eb96..73c3ed5f 100644 --- a/rc/filetype/i3.kak +++ b/rc/filetype/i3.kak @@ -63,7 +63,7 @@ add-highlighter shared/i3/single_string/ regex "#[0-9a-fA-F]{6}" 0:value # attributes 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 # ‾‾‾‾‾‾‾‾ From a0477b10163e210df4803943794ab1ff7da2c429 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sat, 9 Apr 2022 14:38:32 +0200 Subject: [PATCH 08/19] rc format: restore in-client error when formatcmd fails Commit 5b1f9255 (rc: Use the standard `fail` command to report errors, 2019-11-14) replaced uses of "echo -markup {Error}" with "fail". This made format-buffer do echo "eval -client $kak_client %{ fail }" | kak -p $kak_session Unfortunately "fail" fails in the client spawned by "kak -p" and not in $kak_client where the user would see the message. Correct this. While at it, clarify the error message, so users immediately know that the number is the exit code. Fixes #3254 --- rc/tools/format.kak | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rc/tools/format.kak b/rc/tools/format.kak index 72d71430..2435af0c 100644 --- a/rc/tools/format.kak +++ b/rc/tools/format.kak @@ -14,7 +14,8 @@ define-command format-selections -docstring "Format the selections individually" echo "fail 'The option ''formatcmd'' must be set'" fi } - evaluate-commands -draft -no-hooks -save-regs '|' %{ + evaluate-commands -draft -no-hooks -save-regs 'e|' %{ + set-register e nop set-register '|' %{ format_in="$(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 cat "$format_out" 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" fi rm -f "$format_in" "$format_out" } execute-keys '|' + %reg{e} } } From f0122f10df0b2cfbf43ccd3b2b5b57bb9823ffd6 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Wed, 16 Mar 2022 20:45:43 +0100 Subject: [PATCH 09/19] Add black-on-white colorscheme Kakoune doesn't have an equivalent of Vim's ":syntax off". This colorscheme is as close as it gets: it uses various shades of grey for cursors, selections and completion/info boxes, and black/white for everything else. The high-contrast makes it ideal for bright settings. I also have the dual white-on-black colorscheme but it's not tested much, so I left it on my "colorschemes" branch. --- colors/black-on-white.kak | 53 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 colors/black-on-white.kak diff --git a/colors/black-on-white.kak b/colors/black-on-white.kak new file mode 100644 index 00000000..f5e5b64e --- /dev/null +++ b/colors/black-on-white.kak @@ -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 From dbc88281c707f62b52893850c712db2196e8a136 Mon Sep 17 00:00:00 2001 From: Pound_Hash Date: Sun, 10 Apr 2022 21:49:54 -0700 Subject: [PATCH 10/19] Fixed grammar; rendered the construction parallel. --- doc/pages/buffers.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/pages/buffers.asciidoc b/doc/pages/buffers.asciidoc index fc750c7b..ae7c04e9 100644 --- a/doc/pages/buffers.asciidoc +++ b/doc/pages/buffers.asciidoc @@ -59,5 +59,5 @@ for examples. When the write end of the fifo is closed, the buffer becomes an ordinary <>. When the buffer is deleted, 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. From e40ff99eaea0cc67a61cb13be24ae3dda1ae0315 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Mon, 11 Apr 2022 19:48:57 +1000 Subject: [PATCH 11/19] Code style cleanups around object selection code --- src/normal.cc | 66 ++++++++++++++++++++------------------------------- 1 file changed, 26 insertions(+), 40 deletions(-) diff --git a/src/normal.cc b/src/normal.cc index 15f07211..25df66b3 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -1,7 +1,5 @@ #include "normal.hh" -#include - #include "buffer.hh" #include "buffer_manager.hh" #include "buffer_utils.hh" @@ -31,8 +29,6 @@ namespace Kakoune { -using namespace std::placeholders; - enum class SelectMode { Replace, @@ -1302,7 +1298,15 @@ void select_object(Context& context, NormalParams params) auto obj_it = find(selectors | transform(&ObjectType::key), key).base(); if (obj_it != std::end(selectors)) return select_and_set_last( - 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') { @@ -1323,17 +1327,13 @@ void select_object(Context& context, NormalParams params) struct error : runtime_error { error(size_t) : runtime_error{"desc parsing failed, expected ,"} {} }; - auto params = cmdline | split(',', '\\') | - transform(unescape<',', '\\'>) | static_gather(); - + auto params = cmdline | split(',', '\\') + | transform(unescape<',', '\\'>) + | static_gather(); if (params[0].empty() or params[1].empty()) throw error{0}; - select_and_set_last( - context, std::bind(select_surrounding, _1, _2, - Regex{params[0], RegexCompileFlags::Backward}, - Regex{params[1], RegexCompileFlags::Backward}, - count, flags)); + select_and_set_last(context, regex_selector(params[0], params[1], count)); }); return; } @@ -1350,10 +1350,10 @@ void select_object(Context& context, NormalParams params) return; } - static constexpr struct SurroundingPair + static constexpr struct { - char opening; - char closing; + char open; + char close; char name; } surrounding_pairs[] = { { '(', ')', 'b' }, @@ -1364,28 +1364,15 @@ void select_object(Context& context, NormalParams params) { '\'', '\'', 'q' }, { '`', '`', 'g' }, }; - auto pair_it = find_if(surrounding_pairs, - [key](const SurroundingPair& s) { - return key == s.opening or key == s.closing or - (s.name != 0 and key == s.name); - }); - if (pair_it != std::end(surrounding_pairs)) + if (auto it = find_if(surrounding_pairs, [key](auto s) { return key == s.open or key == s.close or key == s.name; }); + it != std::end(surrounding_pairs)) return select_and_set_last( - context, std::bind(select_surrounding, _1, _2, - Regex{format("\\Q{}", pair_it->opening), RegexCompileFlags::Backward}, - Regex{format("\\Q{}", pair_it->closing), RegexCompileFlags::Backward}, - count, flags)); + context, regex_selector(format("\\Q{}", it->open), format("\\Q{}", it->close), count)); - if (not key.codepoint()) - return; - - const Codepoint cp = *key.codepoint(); - if (is_punctuation(cp, {})) + if (auto cp = key.codepoint(); cp and is_punctuation(*cp, {})) { - auto re = Regex{"\\Q" + to_string(cp), RegexCompileFlags::Backward}; - return select_and_set_last( - context, std::bind(select_surrounding, _1, _2, - re, re, count, flags)); + auto re = "\\Q" + to_string(*cp); + return select_and_set_last(context, regex_selector(re, re, count)); } }, get_title(), 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 : SelectMode::Replace; select_and_set_last( - context, - std::bind(flags & SelectFlags::Reverse ? select_to_reverse - : select_to, - _1, _2, *cp, params.count, - flags & SelectFlags::Inclusive)); + context, [cp=*cp, count=params.count] (auto& context, auto& sel) { + auto& func = flags & SelectFlags::Reverse ? select_to_reverse : select_to; + return func(context, sel, cp, count, flags & SelectFlags::Inclusive); + }); }, get_title(), "enter char to select to"); } From 90db664635013f6e857ec696403f2164032410a8 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Tue, 12 Apr 2022 12:49:19 +1000 Subject: [PATCH 12/19] Fix crash when deleting a buffer from a user mapping Deleting a buffer resets normal mode on all clients that were displaing that buffer, but ScopedForceNormalMode that are used from user mode do not take this possiblity into account on destruction, which leads to deleting the last normal mode from the context, ending up with an empty mode stack. Fixes #3909 --- src/input_handler.cc | 9 ++------- src/ref_ptr.hh | 4 ++-- .../3909-crash-on-closing-buffer-with-user-mapping/cmd | 1 + .../3909-crash-on-closing-buffer-with-user-mapping/in | 1 + .../3909-crash-on-closing-buffer-with-user-mapping/out | 1 + .../3909-crash-on-closing-buffer-with-user-mapping/rc | 2 ++ 6 files changed, 9 insertions(+), 9 deletions(-) create mode 100644 test/regression/3909-crash-on-closing-buffer-with-user-mapping/cmd create mode 100644 test/regression/3909-crash-on-closing-buffer-with-user-mapping/in create mode 100644 test/regression/3909-crash-on-closing-buffer-with-user-mapping/out create mode 100644 test/regression/3909-crash-on-closing-buffer-with-user-mapping/rc diff --git a/src/input_handler.cc b/src/input_handler.cc index 8adbbcee..26d255c0 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -1698,14 +1698,9 @@ InputHandler::ScopedForceNormal::~ScopedForceNormal() if (m_mode == m_handler.m_mode_stack.back().get()) m_handler.pop_mode(m_mode); - else - { - auto it = find_if(m_handler.m_mode_stack, - [this](const RefPtr& m) - { return m.get() == m_mode; }); - kak_assert(it != m_handler.m_mode_stack.end()); + else if (auto it = find(m_handler.m_mode_stack, m_mode); + it != m_handler.m_mode_stack.end()) m_handler.m_mode_stack.erase(it); - } } static bool is_valid(Key key) diff --git a/src/ref_ptr.hh b/src/ref_ptr.hh index 235ee2a3..4b576039 100644 --- a/src/ref_ptr.hh +++ b/src/ref_ptr.hh @@ -88,8 +88,8 @@ struct RefPtr 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) { return lhs.m_ptr != rhs.m_ptr; } + friend bool operator==(const RefPtr& lhs, const RefPtr& rhs) = default; + friend bool operator==(const RefPtr& lhs, const T* rhs) { return lhs.m_ptr == rhs; } private: T* m_ptr = nullptr; diff --git a/test/regression/3909-crash-on-closing-buffer-with-user-mapping/cmd b/test/regression/3909-crash-on-closing-buffer-with-user-mapping/cmd new file mode 100644 index 00000000..b870f425 --- /dev/null +++ b/test/regression/3909-crash-on-closing-buffer-with-user-mapping/cmd @@ -0,0 +1 @@ +i,d diff --git a/test/regression/3909-crash-on-closing-buffer-with-user-mapping/in b/test/regression/3909-crash-on-closing-buffer-with-user-mapping/in new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/test/regression/3909-crash-on-closing-buffer-with-user-mapping/in @@ -0,0 +1 @@ + diff --git a/test/regression/3909-crash-on-closing-buffer-with-user-mapping/out b/test/regression/3909-crash-on-closing-buffer-with-user-mapping/out new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/test/regression/3909-crash-on-closing-buffer-with-user-mapping/out @@ -0,0 +1 @@ + diff --git a/test/regression/3909-crash-on-closing-buffer-with-user-mapping/rc b/test/regression/3909-crash-on-closing-buffer-with-user-mapping/rc new file mode 100644 index 00000000..13e1f91e --- /dev/null +++ b/test/regression/3909-crash-on-closing-buffer-with-user-mapping/rc @@ -0,0 +1,2 @@ +edit -scratch +map global user d :delete-buffer From 0f966e656b40ede30c3c8ebfad6f1659907bcd20 Mon Sep 17 00:00:00 2001 From: Andrew Vos Date: Tue, 12 Apr 2022 16:26:38 +0100 Subject: [PATCH 13/19] Disable external diff tools when diffing buffer There is a bug that causes `:git show-diff` to fail when using an external diff, for example difftastic. This change ensures that we don't use an external diff tool when diffing the current buffer. --- rc/tools/git.kak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rc/tools/git.kak b/rc/tools/git.kak index 3b53ebd1..e65374c6 100644 --- a/rc/tools/git.kak +++ b/rc/tools/git.kak @@ -157,7 +157,7 @@ define-command -params 1.. \ update_diff() { ( 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"}; foreach $line () { if ($line =~ /@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))?/) { From 3ab88f4b7c7574acb74e547b8113be5aeb1b09d1 Mon Sep 17 00:00:00 2001 From: throwawayaccount12345-1 <77868642+throwawayaccount12345-1@users.noreply.github.com> Date: Wed, 20 Apr 2022 23:11:10 -0300 Subject: [PATCH 14/19] rc file-detection hook group Add a group to the `file-detection` hooks. There's no way to remove hooks without a group. With this patch, you'll be able to remove those `file-detection` hooks manually. There's no need for two separate groups since if you wanted to remove only one, you could run `remove-hooks` and then only add one again. Related: #3670 --- rc/detection/file.kak | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rc/detection/file.kak b/rc/detection/file.kak index 99e0b05b..c7073865 100644 --- a/rc/detection/file.kak +++ b/rc/detection/file.kak @@ -22,5 +22,5 @@ define-command -hidden file-detection %{ evaluate-commands %sh{ fi } } -hook global BufOpenFile .* file-detection -hook global BufWritePost .* file-detection +hook -group file-detection global BufOpenFile .* file-detection +hook -group file-detection global BufWritePost .* file-detection From 3b0f69a6d68d1a8a5d0abcf8a611f401cf0bb9af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20Ros=C3=A9n?= Date: Fri, 22 Apr 2022 21:26:15 +0200 Subject: [PATCH 15/19] Fix documentation for %val{window_range} Makes line and column be the right way around in the docs. --- doc/pages/expansions.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/pages/expansions.asciidoc b/doc/pages/expansions.asciidoc index d2374398..674f5707 100644 --- a/doc/pages/expansions.asciidoc +++ b/doc/pages/expansions.asciidoc @@ -417,7 +417,7 @@ The following expansions are supported (with required context _in italics_): _in window scope_ + list of coordinates and dimensions of the buffer-space available on the current window, in the following format: - ` ` + ` ` Values in the above list that do not mention a context are available everywhere. From 81b520847cb62b8c4b9bc1776d879d8010d43cd6 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Fri, 15 Apr 2022 17:37:23 +1000 Subject: [PATCH 16/19] Introduce a flatten range adapter and use it in execute_keys_cmd This avoids allocating a KeyList vector in which to flatten all the different arguments and simplifies the client logic. --- src/commands.cc | 9 +--- src/ranges.cc | 27 ++++++---- src/ranges.hh | 132 ++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 129 insertions(+), 39 deletions(-) diff --git a/src/commands.cc b/src/commands.cc index 2b419e76..3cfd8b73 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -2086,14 +2086,7 @@ const CommandDesc execute_keys_cmd = { ScopedSetBool disable_keymaps(context.keymaps_disabled(), not parser.get_switch("with-maps")); ScopedSetBool disable_hoooks(context.hooks_disabled(), not parser.get_switch("with-hooks")); - KeyList keys; - for (auto& param : parser) - { - KeyList param_keys = parse_keys(param); - keys.insert(keys.end(), param_keys.begin(), param_keys.end()); - } - - for (auto& key : keys) + for (auto& key : parser | transform(parse_keys) | flatten()) context.input_handler().handle_key(key); }); } diff --git a/src/ranges.cc b/src/ranges.cc index 11885ad1..4fe2a418 100644 --- a/src/ranges.cc +++ b/src/ranges.cc @@ -7,24 +7,29 @@ namespace Kakoune { UnitTest test_ranges{[] { - auto check_equal = [](auto&& container, ConstArrayView expected) { + using Strs = ConstArrayView; + auto check_equal = [](auto&& container, auto&& expected) { kak_assert(std::equal(container.begin(), container.end(), expected.begin(), expected.end())); }; - check_equal("a,b,c"_sv | split(','), {"a", "b", "c"}); - check_equal(",b,c"_sv | split(','), {"", "b", "c"}); - check_equal(",b,"_sv | split(','), {"", "b", ""}); - check_equal(","_sv | split(','), {"", ""}); - check_equal(""_sv | split(','), {}); + check_equal("a,b,c"_sv | split(','), Strs{"a", "b", "c"}); + check_equal(",b,c"_sv | split(','), Strs{"", "b", "c"}); + check_equal(",b,"_sv | split(','), Strs{"", "b", ""}); + check_equal(","_sv | split(','), Strs{"", ""}); + check_equal(""_sv | split(','), Strs{}); - check_equal("a,b,c,"_sv | split_after(','), {"a,", "b,", "c,"}); - check_equal("a,b,c"_sv | split_after(','), {"a,", "b,", "c"}); + check_equal("a,b,c,"_sv | split_after(','), Strs{"a,", "b,", "c,"}); + check_equal("a,b,c"_sv | split_after(','), Strs{"a,", "b,", "c"}); check_equal(R"(a\,,\,b,\,)"_sv | split(',', '\\') - | transform(unescape<',', '\\'>), {"a,", ",b", ","}); + | transform(unescape<',', '\\'>), Strs{"a,", ",b", ","}); check_equal(R"(\,\,)"_sv | split(',', '\\') - | transform(unescape<',', '\\'>), {",,"}); + | transform(unescape<',', '\\'>), Strs{",,"}); check_equal(R"(\\,\\,)"_sv | split(',', '\\') - | 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{"", ""} | flatten(), ""_sv); + check_equal(Vector{} | flatten(), ""_sv); }}; } diff --git a/src/ranges.hh b/src/ranges.hh index cf436880..a86b9e2b 100644 --- a/src/ranges.hh +++ b/src/ranges.hh @@ -24,13 +24,33 @@ decltype(auto) operator| (Range&& range, ViewFactory factory) } template -struct decay_range_impl { using type = std::remove_cvref_t; }; +struct DecayRangeImpl { using type = std::remove_cvref_t; }; template -struct decay_range_impl { using type = Range&; }; +struct DecayRangeImpl { using type = Range&; }; template -using decay_range = typename decay_range_impl::type; +using DecayRange = typename DecayRangeImpl::type; + +template +struct RangeHolderImpl { using type = std::remove_cvref_t; }; + +template +struct RangeHolderImpl { + 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 +using RangeHolder = typename RangeHolderImpl::type; template struct ReverseView @@ -47,11 +67,11 @@ struct ReverseView Range m_range; }; -inline auto reverse() +constexpr auto reverse() { return ViewFactory{[](auto&& range) { using Range = decltype(range); - return ReverseView>{std::forward(range)}; + return ReverseView>{std::forward(range)}; }}; } @@ -71,11 +91,11 @@ struct SkipView size_t m_skip_count; }; -inline auto skip(size_t count) +constexpr auto skip(size_t count) { return ViewFactory{[count](auto&& range) { using Range = decltype(range); - return SkipView>{std::forward(range), count}; + return SkipView>{std::forward(range), count}; }}; } @@ -89,11 +109,11 @@ struct DropView size_t m_drop_count; }; -inline auto drop(size_t count) +constexpr auto drop(size_t count) { return ViewFactory{[count](auto&& range) { using Range = decltype(range); - return DropView>{std::forward(range), count}; + return DropView>{std::forward(range), count}; }}; } @@ -147,11 +167,11 @@ struct FilterView }; template -inline auto filter(Filter f) +constexpr auto filter(Filter f) { return ViewFactory{[f = std::move(f)](auto&& range) { using Range = decltype(range); - return FilterView, Filter>{std::forward(range), std::move(f)}; + return FilterView, Filter>{std::forward(range), std::move(f)}; }}; } @@ -193,11 +213,11 @@ struct EnumerateView Range m_range; }; -inline auto enumerate() +constexpr auto enumerate() { return ViewFactory{[](auto&& range) { using Range = decltype(range); - return EnumerateView>{std::forward(range)}; + return EnumerateView>{std::forward(range)}; }}; } @@ -252,11 +272,11 @@ struct TransformView }; template -inline auto transform(Transform t) +constexpr auto transform(Transform t) { return ViewFactory{[t = std::move(t)](auto&& range) { using Range = decltype(range); - return TransformView, Transform>{std::forward(range), std::move(t)}; + return TransformView, Transform>{std::forward(range), std::move(t)}; }}; } @@ -267,7 +287,7 @@ template requires std::is_same_v : std::true_type {}; template -inline auto transform(M T::*member) +constexpr auto transform(M T::*member) { return transform([member](auto&& arg) -> decltype(auto) { using Arg = decltype(arg); @@ -364,7 +384,7 @@ auto split(Element separator) { return ViewFactory{[s = std::move(separator)](auto&& range) { using Range = decltype(range); - return SplitView, false, false, Element, ValueType>{std::forward(range), std::move(s), {}}; + return SplitView, false, false, Element, ValueType>{std::forward(range), std::move(s), {}}; }}; } @@ -373,7 +393,7 @@ auto split_after(Element separator) { return ViewFactory{[s = std::move(separator)](auto&& range) { using Range = decltype(range); - return SplitView, false, true, Element, ValueType>{std::forward(range), std::move(s), {}}; + return SplitView, false, true, Element, ValueType>{std::forward(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) { using Range = decltype(range); - return SplitView, true, false, Element, ValueType>{std::forward(range), std::move(s), std::move(e)}; + return SplitView, true, false, Element, ValueType>{std::forward(range), std::move(s), std::move(e)}; + }}; +} + +template +struct FlattenedView +{ + using OuterIt = IteratorOf; + using InnerRange = ValueOf; + using InnerIt = IteratorOf; + + struct Iterator + { + using value_type = typename std::iterator_traits::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 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>{std::forward(range)}; }}; } @@ -434,7 +526,7 @@ struct ConcatView }; template -ConcatView, decay_range> concatenated(Range1&& range1, Range2&& range2) +ConcatView, DecayRange> concatenated(Range1&& range1, Range2&& range2) { return {range1, range2}; } From 52a7c58670bb5e891b535a8d72187490c2ee7d37 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sun, 24 Apr 2022 19:56:32 +0200 Subject: [PATCH 17/19] rc autorestore: fix regression due to ! breaking change Commit 85b78dda (src: Select the data inserted by `!` and ``, merged on 2021-03-06) broke autorestore by making it delete the restored content. I've been using it for 6 months but never noticed since I didn't use autorestore Reproducer: HOME=$PWD kak -s foo README.asciidoc -e 'exec iUNSAVED-CONTENT' # In another terminal: ps aux | awk '/kak -s foo/ {print $2; exit}' | xargs kill -HUP HOME=$PWD kak -s foo README.asciidoc Delete the trailing newline instead of the restored content. While at it, remove some commands from execute-keys, to make it work on the breaking-cleanups branch which swaps and ",". Closes #4335 --- rc/tools/autorestore.kak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rc/tools/autorestore.kak b/rc/tools/autorestore.kak index d3e60994..52febe3a 100644 --- a/rc/tools/autorestore.kak +++ b/rc/tools/autorestore.kak @@ -39,7 +39,7 @@ define-command autorestore-restore-buffer \ ## Replace the content of the buffer with the content of the backup file echo -debug Restoring file: ${newer} - execute-keys -draft %{ %d!cat\"${newer}\"d } + execute-keys -draft %{%d!cat\"${newer}\"jd} ## If the backup file has to be removed, issue the command once ## the current buffer has been saved From 8a7109f9c54185b27f36859fdb379a67899ee4e4 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Tue, 26 Apr 2022 13:26:02 +0200 Subject: [PATCH 18/19] Fix compilation due to failing template deduction for aggregates gcc 11.2.0 compiles us just fine but clang 13.0.1 fails with this error clang++ -DKAK_DEBUG -O0 -pedantic -std=c++2a -g -Wall -Wextra -Wno-unused-parameter -Wno-sign-compare -Wno-address -frelaxed-template-template-args -Wno-ambiguous-reversed-operator -MD -MP -MF .ranges.debug.d -c -o .ranges.debug.o ranges.cc ranges.cc:30:17: error: no viable constructor or deduction guide for deduction of template arguments of 'Array' check_equal(Array{{""_sv, "abc"_sv, ""_sv, "def"_sv, ""_sv}} | flatten(), "abcdef"_sv); ^ ./constexpr_utils.hh:14:8: note: candidate template ignored: couldn't infer template argument 'T' struct Array ^ ./constexpr_utils.hh:14:8: note: candidate function template not viable: requires 0 arguments, but 1 was provided 1 error generated. The same error can be reproduced with this C++ input template struct Array { T m_data[N]; }; void test() { (void)Array{{1, 2}}; } Since "Array" has no constructor, the compiler uses aggregate initialization. Only recent g++ seems to be smart enough to deduce template arguments in this case. Help other compilers by adding a deduction guide. The deduction guide needs to count the array elements to infer the array size, hence we need to remove braces. Happily, this is allowed and it's also what std::array does. Closes #4597 --- src/constexpr_utils.hh | 3 +++ src/ranges.cc | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/constexpr_utils.hh b/src/constexpr_utils.hh index d9ba2abb..f83faacb 100644 --- a/src/constexpr_utils.hh +++ b/src/constexpr_utils.hh @@ -28,6 +28,9 @@ struct Array T m_data[N]; }; +template requires (std::is_same_v and ...) +Array(T, U...) -> Array; + template constexpr Array make_array(const T (&data)[N], std::index_sequence) { diff --git a/src/ranges.cc b/src/ranges.cc index 4fe2a418..b8fb6703 100644 --- a/src/ranges.cc +++ b/src/ranges.cc @@ -27,7 +27,7 @@ UnitTest test_ranges{[] { check_equal(R"(\\,\\,)"_sv | split(',', '\\') | transform(unescape<',', '\\'>), Strs{R"(\)", R"(\)", ""}); - check_equal(Array{{""_sv, "abc"_sv, ""_sv, "def"_sv, ""_sv}} | flatten(), "abcdef"_sv); + check_equal(Array{""_sv, "abc"_sv, ""_sv, "def"_sv, ""_sv} | flatten(), "abcdef"_sv); check_equal(Vector{"", ""} | flatten(), ""_sv); check_equal(Vector{} | flatten(), ""_sv); }}; From 5c6238ef113da8c2844ff9bcfa27c87e3473c150 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Sun, 1 May 2022 20:59:29 +1000 Subject: [PATCH 19/19] Remove invalid assert in ScopedForceNormal destructor commit 90db664635013f6e857ec696403f2164032410a8 introduced logic to handle the case where the mode had been removed, but did not get rid of the assert. --- src/input_handler.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/input_handler.cc b/src/input_handler.cc index 26d255c0..9b1857a8 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -1694,8 +1694,6 @@ InputHandler::ScopedForceNormal::~ScopedForceNormal() if (not m_mode) return; - kak_assert(m_handler.m_mode_stack.size() > 1); - if (m_mode == m_handler.m_mode_stack.back().get()) m_handler.pop_mode(m_mode); else if (auto it = find(m_handler.m_mode_stack, m_mode);