From 16ace71839b74ca5d253faddaafb7e3886641acc Mon Sep 17 00:00:00 2001 From: Frank LENORMAND Date: Tue, 22 Dec 2020 09:54:38 +0300 Subject: =?UTF-8?q?src:=20Catch=20=E2=80=9Ckill=20exceptions=E2=80=9D?= =?UTF-8?q?=E2=80=99cleanly?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the `kill` command is called in the `-E` CLI flag, the resulting exception is not caught and crashes the server. This commit allows the server to terminate cleanly. Since `KakEnd` hooks also need to be executed should the user run a command like `kak -E 'kill 0'`, the execution of `KakBegin` hooks is now performed *before* the command provided in `-E` is executed. The documentation for `KakBegin` (executed after the `-E` command prior to this commit) consequently becomes more truthful, as it states: KakBegin session name kakoune has started, this hook is called just after reading the user configuration files Fixes #3972 --- src/main.cc | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/main.cc b/src/main.cc index fbb074a0..6e8189da 100644 --- a/src/main.cc +++ b/src/main.cc @@ -792,11 +792,22 @@ int run_server(StringView session, StringView server_init, " {}", error.what())); } + { + Context empty_context{Context::EmptyContextFlag{}}; + global_scope.hooks().run_hook(Hook::KakBegin, session, empty_context); + } + if (not server_init.empty()) try { Context init_context{Context::EmptyContextFlag{}}; command_manager.execute(server_init, init_context); } + catch (const kill_session& kill) + { + Context empty_context{Context::EmptyContextFlag{}}; + global_scope.hooks().run_hook(Hook::KakEnd, "", empty_context); + return kill.exit_status; + } catch (runtime_error& error) { startup_error = true; @@ -804,11 +815,6 @@ int run_server(StringView session, StringView server_init, " {}", error.what())); } - { - Context empty_context{Context::EmptyContextFlag{}}; - global_scope.hooks().run_hook(Hook::KakBegin, session, empty_context); - } - if (not files.empty()) try { // create buffers in reverse order so that the first given buffer -- cgit v1.2.3 From 8a5f449c180d76566eb3eefdb3efb3c7a0116531 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Sun, 4 Aug 2024 15:36:03 +1000 Subject: Move most code in regex_impl inside the anonymous namespace This is all internal code that should not be exposed. --- src/regex_impl.cc | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/regex_impl.cc b/src/regex_impl.cc index 9b307f23..c32917eb 100644 --- a/src/regex_impl.cc +++ b/src/regex_impl.cc @@ -19,6 +19,9 @@ namespace Kakoune constexpr Codepoint CompiledRegex::StartDesc::count; +namespace +{ + struct ParsedRegex { enum Op : char @@ -73,9 +76,6 @@ struct ParsedRegex uint32_t capture_count; }; -namespace -{ - template struct Children { @@ -123,12 +123,14 @@ struct Children const Index m_index; }; -} // Recursive descent parser based on naming used in the ECMAScript // standard, although the syntax is not fully compatible. struct RegexParser { + static ParsedRegex parse(StringView re) { return RegexParser{re}.m_parsed_regex; } + +private: RegexParser(StringView re) : m_regex{re}, m_pos{re.begin(), re} { @@ -138,11 +140,6 @@ struct RegexParser kak_assert(root == 0); } - ParsedRegex get_parsed_regex() { return std::move(m_parsed_regex); } - - static ParsedRegex parse(StringView re) { return RegexParser{re}.get_parsed_regex(); } - -private: struct InvalidPolicy { Codepoint operator()(Codepoint cp) const { throw regex_error{"Invalid utf8 in regex"}; } @@ -1084,6 +1081,8 @@ private: ParsedRegex& m_parsed_regex; }; +} + String dump_regex(const CompiledRegex& program) { String res; -- cgit v1.2.3 From 2ab35fbb23baad69792d4cf45a3af83e2227c5af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Arrufat?= Date: Sun, 4 Aug 2024 20:55:21 +0900 Subject: Add support for double underline --- src/commands.cc | 5 +++-- src/face.hh | 27 ++++++++++++++------------- src/face_registry.cc | 2 ++ src/json_ui.cc | 1 + src/terminal_ui.cc | 2 +- 5 files changed, 21 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/commands.cc b/src/commands.cc index d22c0647..e4a41ead 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -2482,8 +2482,9 @@ const CommandDesc set_face_cmd = { " [,[,]][+][@]\n" "colors are either a color name, rgb:######, or rgba:######## values.\n" "attributes is a combination of:\n" - " u: underline, c: curly underline, i: italic, b: bold,\n" - " r: reverse, s: strikethrough, B: blink, d: dim,\n" + " u: underline, c: curly underline, U: double underline,\n" + " i: italic, b: bold, r: reverse,\n" + " s: strikethrough, B: blink, d: dim,\n" " f: final foreground, g: final background,\n" " a: final attributes, F: same as +fga\n" "facespec can as well just be the name of another face.\n" diff --git a/src/face.hh b/src/face.hh index 1ed986ef..7e887705 100644 --- a/src/face.hh +++ b/src/face.hh @@ -9,19 +9,20 @@ namespace Kakoune enum class Attribute : int { - Normal = 0, - Underline = 1 << 1, - CurlyUnderline = 1 << 2, - Reverse = 1 << 3, - Blink = 1 << 4, - Bold = 1 << 5, - Dim = 1 << 6, - Italic = 1 << 7, - Strikethrough = 1 << 8, - FinalFg = 1 << 9, - FinalBg = 1 << 10, - FinalAttr = 1 << 11, - Final = FinalFg | FinalBg | FinalAttr + Normal = 0, + Underline = 1 << 1, + CurlyUnderline = 1 << 2, + DoubleUnderline = 1 << 3, + Reverse = 1 << 4, + Blink = 1 << 5, + Bold = 1 << 6, + Dim = 1 << 7, + Italic = 1 << 8, + Strikethrough = 1 << 9, + FinalFg = 1 << 10, + FinalBg = 1 << 11, + FinalAttr = 1 << 12, + Final = FinalFg | FinalBg | FinalAttr }; constexpr bool with_bit_ops(Meta::Type) { return true; } diff --git a/src/face_registry.cc b/src/face_registry.cc index d6c5cd53..ebb71986 100644 --- a/src/face_registry.cc +++ b/src/face_registry.cc @@ -50,6 +50,7 @@ FaceSpec parse_face(StringView facedesc) { case 'u': face.attributes |= Attribute::Underline; break; case 'c': face.attributes |= Attribute::CurlyUnderline; break; + case 'U': face.attributes |= Attribute::DoubleUnderline; break; case 'r': face.attributes |= Attribute::Reverse; break; case 'b': face.attributes |= Attribute::Bold; break; case 'B': face.attributes |= Attribute::Blink; break; @@ -78,6 +79,7 @@ String to_string(Attribute attributes) attrs[] { { Attribute::Underline, "u" }, { Attribute::CurlyUnderline, "c" }, + { Attribute::DoubleUnderline, "U" }, { Attribute::Reverse, "r" }, { Attribute::Blink, "B" }, { Attribute::Bold, "b" }, diff --git a/src/json_ui.cc b/src/json_ui.cc index 01768897..66674cf7 100644 --- a/src/json_ui.cc +++ b/src/json_ui.cc @@ -39,6 +39,7 @@ String to_json(Attribute attributes) attrs[] { { Attribute::Underline, "underline" }, { Attribute::CurlyUnderline, "curly_underline" }, + { Attribute::DoubleUnderline, "double_underline" }, { Attribute::Reverse, "reverse" }, { Attribute::Blink, "blink" }, { Attribute::Bold, "bold" }, diff --git a/src/terminal_ui.cc b/src/terminal_ui.cc index 33574e90..912dfb57 100644 --- a/src/terminal_ui.cc +++ b/src/terminal_ui.cc @@ -224,7 +224,7 @@ void TerminalUI::Screen::set_face(const Face& face, Writer& writer) static constexpr int fg_table[]{ 39, 30, 31, 32, 33, 34, 35, 36, 37, 90, 91, 92, 93, 94, 95, 96, 97 }; static constexpr int bg_table[]{ 49, 40, 41, 42, 43, 44, 45, 46, 47, 100, 101, 102, 103, 104, 105, 106, 107 }; static constexpr int ul_table[]{ 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; - static constexpr const char* attr_table[]{ "0", "4", "4:3", "7", "5", "1", "2", "3", "9" }; + static constexpr const char* attr_table[]{ "0", "4", "4:3", "21", "7", "5", "1", "2", "3", "9" }; auto set_color = [&](bool fg, const Color& color, bool join) { if (join) -- cgit v1.2.3 From 7093f142916d1e6887432dfd88697a1c2ed1b004 Mon Sep 17 00:00:00 2001 From: Enrico Zandomeni Borba Date: Sun, 4 Aug 2024 09:16:15 +0200 Subject: add scroll coordinates adds scroll amount in the upper 16-bits of `Key.modifiers`, reclaiming the space in `Key.key` for coordinates. Previously, while mouse events included their coordinates, scrolling did not. Scroll events are now emitted as . --- src/keys.cc | 3 ++- src/keys.hh | 1 + src/terminal_ui.cc | 9 ++++----- 3 files changed, 7 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/keys.cc b/src/keys.cc index 5ba44181..ad66658a 100644 --- a/src/keys.cc +++ b/src/keys.cc @@ -7,6 +7,7 @@ #include "utf8_iterator.hh" #include "utils.hh" #include "string_utils.hh" +#include "terminal_ui.hh" namespace Kakoune { @@ -196,7 +197,7 @@ String to_string(Key key) else if (key.modifiers & Key::Modifiers::MouseRelease) res = format("mouse:release:{}:{}.{}", key.mouse_button(), coord.line, coord.column); else if (key.modifiers & Key::Modifiers::Scroll) - res = format("scroll:{}", static_cast(key.key)); + res = format("scroll:{}:{}.{}", key.scroll_amount(), coord.line, coord.column); else if (key.modifiers & Key::Modifiers::Resize) res = format("resize:{}.{}", coord.line, coord.column); else diff --git a/src/keys.hh b/src/keys.hh index ccafe336..b4796ea5 100644 --- a/src/keys.hh +++ b/src/keys.hh @@ -91,6 +91,7 @@ struct Key constexpr DisplayCoord coord() const { return {(int)((key & 0xFFFF0000) >> 16), (int)(key & 0x0000FFFF)}; } constexpr MouseButton mouse_button() { return MouseButton{((int)modifiers & (int)Modifiers::MouseButtonMask) >> 6}; } + constexpr int scroll_amount() { return (int)modifiers >> 16; } static Modifiers to_modifier(MouseButton button) { return Key::Modifiers{((int)button << 6) & (int)Modifiers::MouseButtonMask}; } Optional codepoint() const; diff --git a/src/terminal_ui.cc b/src/terminal_ui.cc index 33574e90..01afab48 100644 --- a/src/terminal_ui.cc +++ b/src/terminal_ui.cc @@ -798,9 +798,8 @@ Optional TerminalUI::get_next_key() return Key{mod | Key::to_modifier(button), coord}; }; - auto mouse_scroll = [this](Key::Modifiers mod, bool down) -> Key { - return {mod | Key::Modifiers::Scroll, - (Codepoint)((down ? 1 : -1) * m_wheel_scroll_amount)}; + auto mouse_scroll = [this](Key::Modifiers mod, Codepoint coord, bool down) -> Key { + return {mod | Key::Modifiers::Scroll | (Key::Modifiers)((down ? m_wheel_scroll_amount : -1 * m_wheel_scroll_amount) << 16), coord}; }; auto masked_key = [&](Codepoint key, Codepoint shifted_key = 0) { @@ -921,8 +920,8 @@ Optional TerminalUI::get_next_key() else if (int guess = ffs(m_mouse_state) - 1; 0 <= guess and guess < 3) return mouse_button(mod, Key::MouseButton{guess}, coord, true); break; - case 64: return mouse_scroll(mod, false); - case 65: return mouse_scroll(mod, true); + case 64: return mouse_scroll(mod, coord, false); + case 65: return mouse_scroll(mod, coord, true); } return Key{Key::Modifiers::MousePos, coord}; } -- cgit v1.2.3 From f2e7498ccc56923b1871278ef4f75e5c0c935b40 Mon Sep 17 00:00:00 2001 From: Enrico Zandomeni Borba Date: Sun, 4 Aug 2024 18:41:49 +0200 Subject: fix mouse coord underflow previously, clicking on the status line if it is on the top of the window results on a coord.line = 1 << 16, or there abouts. This is because the expression (key & 0xFFFF0000) >> 16 results in an `shr` instruction which does not propagate the sign bit. Mouse event coordinates can be negative if the status line is on top and the status line is clicked. The new line (int32_t) (key & 0xFFFF0000) >> 16 properly propagates the sign bit, leading to the correct signed numeric line coordinate. --- src/keys.cc | 1 - src/keys.hh | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/keys.cc b/src/keys.cc index ad66658a..e08a6709 100644 --- a/src/keys.cc +++ b/src/keys.cc @@ -7,7 +7,6 @@ #include "utf8_iterator.hh" #include "utils.hh" #include "string_utils.hh" -#include "terminal_ui.hh" namespace Kakoune { diff --git a/src/keys.hh b/src/keys.hh index b4796ea5..3c5d7f4b 100644 --- a/src/keys.hh +++ b/src/keys.hh @@ -89,9 +89,9 @@ struct Key constexpr bool operator==(Key other) const { return val() == other.val(); } constexpr auto operator<=>(Key other) const { return val() <=> other.val(); } - constexpr DisplayCoord coord() const { return {(int)((key & 0xFFFF0000) >> 16), (int)(key & 0x0000FFFF)}; } + constexpr DisplayCoord coord() const { return {(int)((int32_t) (key & 0xFFFF0000) >> 16), (int)(key & 0x0000FFFF)}; } constexpr MouseButton mouse_button() { return MouseButton{((int)modifiers & (int)Modifiers::MouseButtonMask) >> 6}; } - constexpr int scroll_amount() { return (int)modifiers >> 16; } + constexpr int scroll_amount() { return (int32_t)modifiers >> 16; } static Modifiers to_modifier(MouseButton button) { return Key::Modifiers{((int)button << 6) & (int)Modifiers::MouseButtonMask}; } Optional codepoint() const; -- cgit v1.2.3 From 0fddb3fef8b668582c4b1246e0fb6fb1da0c6af7 Mon Sep 17 00:00:00 2001 From: Enrico Zandomeni Borba Date: Tue, 6 Aug 2024 09:03:38 +0200 Subject: fix mouse scrolling --- src/input_handler.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/input_handler.cc b/src/input_handler.cc index 2703b51a..94f4cb79 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -127,7 +127,10 @@ struct MouseHandler Buffer& buffer = context.buffer(); BufferCoord cursor; - constexpr auto modifiers = Key::Modifiers::Control | Key::Modifiers::Alt | Key::Modifiers::Shift | Key::Modifiers::MouseButtonMask; + // bits above these potentially store additional information + constexpr auto mask = (Key::Modifiers) 0x7FF; + constexpr auto modifiers = Key::Modifiers::Control | Key::Modifiers::Alt | Key::Modifiers::Shift | Key::Modifiers::MouseButtonMask | ~mask; + switch ((key.modifiers & ~modifiers).value) { case Key::Modifiers::MousePress: @@ -193,7 +196,7 @@ struct MouseHandler } case Key::Modifiers::Scroll: - scroll_window(context, static_cast(key.key), m_dragging ? OnHiddenCursor::MoveCursor : OnHiddenCursor::PreserveSelections); + scroll_window(context, key.scroll_amount(), m_dragging ? OnHiddenCursor::MoveCursor : OnHiddenCursor::PreserveSelections); return true; default: return false; -- cgit v1.2.3 From 6af7a847c74a05748ba139aed6386c0a6df0220b Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Thu, 8 Aug 2024 12:56:07 +1000 Subject: Delay NormalMode clearing of status line and info box to next idle A common pattern is for info/echo messages to be generated by idle hooks but the clearing of previous info/echo was done immediately on normal mode events. This led to flickering of the info box especially when a hook was repeatidly generating the same info (like moving a cursor in the same word where the hook reacts to the word under the cursor). --- src/client.hh | 2 ++ src/input_handler.cc | 49 ++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 40 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/client.hh b/src/client.hh index 75a2a02f..26486f8f 100644 --- a/src/client.hh +++ b/src/client.hh @@ -48,6 +48,8 @@ public: void info_show(DisplayLine title, DisplayLineList content, BufferCoord anchor, InfoStyle style); void info_show(StringView title, StringView content, BufferCoord anchor, InfoStyle style); void info_hide(bool even_modal = false); + bool info_pending() const { return m_ui_pending & PendingUI::InfoShow; }; + bool status_line_pending() const { return m_ui_pending & PendingUI::StatusLine; }; void print_status(DisplayLine status_line); const DisplayLine& current_status() const { return m_status_line; } diff --git a/src/input_handler.cc b/src/input_handler.cc index 2703b51a..89613aee 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -23,13 +23,6 @@ namespace Kakoune { -static void clear_info_and_echo(Context& context) -{ - context.print_status({}); - if (context.has_client()) - context.client().info_hide(); -} - class InputMode : public RefCountable { public: @@ -101,8 +94,6 @@ void InputMode::paste(StringView content) context().print_status({error.what().str(), context().faces()["Error"] }); context().hooks().run_hook(Hook::RuntimeError, error.what(), context()); } - - clear_info_and_echo(context()); } namespace InputModes @@ -221,6 +212,14 @@ constexpr StringView register_doc = class Normal : public InputMode { + enum class PendingClear + { + None = 0, + Info = 0b01, + StatusLine = 0b10 + }; + friend constexpr bool with_bit_ops(Meta::Type) { return true; } + public: Normal(InputHandler& input_handler, bool single_command = false) : InputMode(input_handler), @@ -228,6 +227,15 @@ public: context().flags() & Context::Flags::Draft ? Timer::Callback{} : [this](Timer&) { RefPtr keep_alive{this}; // hook could trigger pop_mode() + if (context().has_client()) + { + if (m_pending_clear & PendingClear::StatusLine) + context().client().print_status({}); + if (m_pending_clear & PendingClear::Info) + context().client().info_hide(); + } + m_pending_clear = PendingClear::None; + context().hooks().run_hook(Hook::NormalIdle, "", context()); }}, m_fs_check_timer{TimePoint::max(), @@ -275,6 +283,8 @@ public: void on_key(Key key, bool) override { + bool should_clear = false; + kak_assert(m_state != State::PopOnEnabled); ScopedSetBool set_in_on_key{m_in_on_key}; @@ -291,7 +301,7 @@ public: if (m_mouse_handler.handle_key(key, context())) { - clear_info_and_echo(context()); + should_clear = true; if (not transient) m_idle_timer.set_next_date(Clock::now() + get_idle_timeout(context())); @@ -338,7 +348,7 @@ public: m_state = State::PopOnEnabled; }); - clear_info_and_echo(context()); + should_clear = true; // Hack to parse keys sent by terminals using the 8th bit to mark the // meta key. In normal mode, give priority to a potential alt-key than @@ -369,7 +379,12 @@ public: context().hooks().run_hook(Hook::NormalKey, to_string(key), context()); if (enabled() and not transient) // The hook might have changed mode + { + if (should_clear and context().has_client()) + m_pending_clear = (context().client().info_pending() ? PendingClear::None : PendingClear::Info) + | (context().client().status_line_pending() ? PendingClear::None : PendingClear::StatusLine); m_idle_timer.set_next_date(Clock::now() + get_idle_timeout(context())); + } } ModeInfo mode_info() const override @@ -395,6 +410,17 @@ public: return {atoms, m_params}; } + void paste(StringView content) override + { + InputMode::paste(content); + if (not (context().flags() & Context::Flags::Draft)) + { + if (context().has_client()) + m_pending_clear = PendingClear::Info | PendingClear::StatusLine; + m_idle_timer.set_next_date(Clock::now() + get_idle_timeout(context())); + } + } + KeymapMode keymap_mode() const override { return KeymapMode::Normal; } StringView name() const override { return "normal"; } @@ -408,6 +434,7 @@ private: Timer m_idle_timer; Timer m_fs_check_timer; MouseHandler m_mouse_handler; + PendingClear m_pending_clear = PendingClear::None; enum class State { Normal, SingleCommand, PopOnEnabled }; State m_state; -- cgit v1.2.3 From a250b96c18659d34d50e13de8d5126ca7fed6814 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Mon, 12 Aug 2024 17:10:12 +1000 Subject: Move most info/status clear logic to client This makes it possible to remove the pending clears whenever an info/status line is explicitely added, removing a class of race conditions introduced by the previous implementation. --- src/client.cc | 19 +++++++++++++++++++ src/client.hh | 13 +++++++++++++ src/input_handler.cc | 22 +++------------------- 3 files changed, 35 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/client.cc b/src/client.cc index 7cfea960..8b084fd5 100644 --- a/src/client.cc +++ b/src/client.cc @@ -130,6 +130,7 @@ void Client::print_status(DisplayLine status_line) { m_status_line = std::move(status_line); m_ui_pending |= StatusLine; + m_pending_clear &= ~PendingClear::StatusLine; } @@ -467,6 +468,7 @@ void Client::info_show(DisplayLine title, DisplayLineList content, BufferCoord a m_info = Info{ std::move(title), std::move(content), anchor, {}, style }; m_ui_pending |= InfoShow; m_ui_pending &= ~InfoHide; + m_pending_clear &= ~PendingClear::Info; } void Client::info_show(StringView title, StringView content, BufferCoord anchor, InfoStyle style) @@ -490,4 +492,21 @@ void Client::info_hide(bool even_modal) m_ui_pending &= ~InfoShow; } +void Client::schedule_clear() +{ + if (not (m_ui_pending & InfoShow)) + m_pending_clear |= PendingClear::Info; + if (not (m_ui_pending & StatusLine)) + m_pending_clear |= PendingClear::StatusLine; +} + +void Client::clear_pending() +{ + if (m_pending_clear & PendingClear::StatusLine) + print_status({}); + if (m_pending_clear & PendingClear::Info) + info_hide(); + m_pending_clear = PendingClear::None; +} + } diff --git a/src/client.hh b/src/client.hh index 26486f8f..64262f91 100644 --- a/src/client.hh +++ b/src/client.hh @@ -56,6 +56,9 @@ public: DisplayCoord dimensions() const; + void schedule_clear(); + void clear_pending(); + void force_redraw(bool full = false); void redraw_ifn(); @@ -111,6 +114,16 @@ private: }; int m_ui_pending = 0; + enum class PendingClear + { + None = 0, + Info = 0b01, + StatusLine = 0b10 + }; + friend constexpr bool with_bit_ops(Meta::Type) { return true; } + PendingClear m_pending_clear = PendingClear::None; + + struct Menu { Vector items; diff --git a/src/input_handler.cc b/src/input_handler.cc index 89613aee..56999d45 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -212,14 +212,6 @@ constexpr StringView register_doc = class Normal : public InputMode { - enum class PendingClear - { - None = 0, - Info = 0b01, - StatusLine = 0b10 - }; - friend constexpr bool with_bit_ops(Meta::Type) { return true; } - public: Normal(InputHandler& input_handler, bool single_command = false) : InputMode(input_handler), @@ -228,13 +220,7 @@ public: Timer::Callback{} : [this](Timer&) { RefPtr keep_alive{this}; // hook could trigger pop_mode() if (context().has_client()) - { - if (m_pending_clear & PendingClear::StatusLine) - context().client().print_status({}); - if (m_pending_clear & PendingClear::Info) - context().client().info_hide(); - } - m_pending_clear = PendingClear::None; + context().client().clear_pending(); context().hooks().run_hook(Hook::NormalIdle, "", context()); }}, @@ -381,8 +367,7 @@ public: if (enabled() and not transient) // The hook might have changed mode { if (should_clear and context().has_client()) - m_pending_clear = (context().client().info_pending() ? PendingClear::None : PendingClear::Info) - | (context().client().status_line_pending() ? PendingClear::None : PendingClear::StatusLine); + context().client().schedule_clear(); m_idle_timer.set_next_date(Clock::now() + get_idle_timeout(context())); } } @@ -416,7 +401,7 @@ public: if (not (context().flags() & Context::Flags::Draft)) { if (context().has_client()) - m_pending_clear = PendingClear::Info | PendingClear::StatusLine; + context().client().schedule_clear(); m_idle_timer.set_next_date(Clock::now() + get_idle_timeout(context())); } } @@ -434,7 +419,6 @@ private: Timer m_idle_timer; Timer m_fs_check_timer; MouseHandler m_mouse_handler; - PendingClear m_pending_clear = PendingClear::None; enum class State { Normal, SingleCommand, PopOnEnabled }; State m_state; -- cgit v1.2.3 From 2d9886afe76adde9f33fc0c0454146176857a6f2 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Fri, 9 Aug 2024 18:15:32 +1000 Subject: Remove void_t and use requires instead --- src/meta.hh | 7 +------ src/regex_impl.hh | 5 +++-- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/meta.hh b/src/meta.hh index 15429ca8..151f1020 100644 --- a/src/meta.hh +++ b/src/meta.hh @@ -1,17 +1,12 @@ #ifndef meta_hh_INCLUDED #define meta_hh_INCLUDED -namespace Kakoune -{ -inline namespace Meta +namespace Kakoune::inline Meta { struct AnyType{}; template struct Type : AnyType {}; -template using void_t = void; - -} } #endif // meta_hh_INCLUDED diff --git a/src/regex_impl.hh b/src/regex_impl.hh index 07936027..b772169d 100644 --- a/src/regex_impl.hh +++ b/src/regex_impl.hh @@ -210,11 +210,12 @@ constexpr bool is_direction(RegexMode mode) (mode & ~(RegexMode::Forward | RegexMode::Backward)) == RegexMode{0}; } -template +template struct SentinelType { using Type = It; }; template -struct SentinelType> { using Type = typename It::Sentinel; }; + requires requires { typename It::Sentinel; } +struct SentinelType { using Type = typename It::Sentinel; }; template requires (has_direction(mode)) -- cgit v1.2.3 From 1a52006c3d215196997a2cd12450795d4ae4a1ca Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Fri, 9 Aug 2024 18:16:51 +1000 Subject: Extract format implementation to its own file Split it to avoid pulling all string_utils dependencies for just format. --- src/backtrace.cc | 2 +- src/color.cc | 2 +- src/face_registry.cc | 2 +- src/format.cc | 180 +++++++++++++++++++++++++++++++++++++++++++++++ src/format.hh | 81 +++++++++++++++++++++ src/highlighter_group.cc | 2 +- src/keymap_manager.cc | 2 +- src/parameters_parser.hh | 2 +- src/regex_impl.cc | 2 +- src/register_manager.cc | 2 +- src/string_utils.cc | 168 ------------------------------------------- src/string_utils.hh | 72 +------------------ src/terminal_ui.cc | 2 +- 13 files changed, 272 insertions(+), 247 deletions(-) create mode 100644 src/format.cc create mode 100644 src/format.hh (limited to 'src') diff --git a/src/backtrace.cc b/src/backtrace.cc index 1b3c6d09..04b772ad 100644 --- a/src/backtrace.cc +++ b/src/backtrace.cc @@ -1,7 +1,7 @@ #include "backtrace.hh" #include "string.hh" -#include "string_utils.hh" +#include "format.hh" #if defined(__GLIBC__) || defined(__APPLE__) # include diff --git a/src/color.cc b/src/color.cc index 145a5381..71ef46b6 100644 --- a/src/color.cc +++ b/src/color.cc @@ -2,7 +2,7 @@ #include "exception.hh" #include "ranges.hh" -#include "string_utils.hh" +#include "format.hh" #include diff --git a/src/face_registry.cc b/src/face_registry.cc index d6c5cd53..e4a0cf86 100644 --- a/src/face_registry.cc +++ b/src/face_registry.cc @@ -2,7 +2,7 @@ #include "exception.hh" #include "ranges.hh" -#include "string_utils.hh" +#include "format.hh" namespace Kakoune { diff --git a/src/format.cc b/src/format.cc new file mode 100644 index 00000000..685fa651 --- /dev/null +++ b/src/format.cc @@ -0,0 +1,180 @@ +#include "format.hh" + +#include "exception.hh" +#include "string_utils.hh" + +#include + +namespace Kakoune +{ + + +template +InplaceString to_string_impl(auto val, auto format) +{ + InplaceString res; + auto [end, errc] = std::to_chars(res.m_data, res.m_data + N, val, format); + if (errc != std::errc{}) + throw runtime_error("to_string error"); + res.m_length = end - res.m_data; + *end = '\0'; + return res; +} + +template +InplaceString to_string_impl(auto val) +{ + return to_string_impl(val, 10); +} + +InplaceString<15> to_string(int val) +{ + return to_string_impl<15>(val); +} + +InplaceString<15> to_string(unsigned val) +{ + return to_string_impl<15>(val); +} + +InplaceString<23> to_string(long int val) +{ + return to_string_impl<23>(val); +} + +InplaceString<23> to_string(long long int val) +{ + return to_string_impl<23>(val); +} + +InplaceString<23> to_string(unsigned long val) +{ + return to_string_impl<23>(val); +} + +InplaceString<23> to_string(Hex val) +{ + return to_string_impl<23>(val.val, 16); +} + +InplaceString<23> to_string(Grouped val) +{ + auto ungrouped = to_string_impl<23>(val.val); + + InplaceString<23> res; + for (int pos = 0, len = ungrouped.m_length; pos != len; ++pos) + { + if (res.m_length and ((len - pos) % 3) == 0) + res.m_data[res.m_length++] = ','; + res.m_data[res.m_length++] = ungrouped.m_data[pos]; + } + return res; +} + +InplaceString<23> to_string(float val) +{ +#if defined(__cpp_lib_to_chars) + return to_string_impl<23>(val, std::chars_format::general); +#else + InplaceString<23> res; + res.m_length = snprintf(res.m_data, 23, "%f", val); + return res; +#endif +} + +InplaceString<7> to_string(Codepoint c) +{ + InplaceString<7> res; + char* ptr = res.m_data; + utf8::dump(ptr, c); + res.m_length = (int)(ptr - res.m_data); + return res; +} + +template +void format_impl(StringView fmt, ArrayView params, AppendFunc append) +{ + int implicitIndex = 0; + for (auto it = fmt.begin(), end = fmt.end(); it != end;) + { + auto opening = std::find(it, end, '{'); + if (opening == end) + { + append(StringView{it, opening}); + break; + } + else if (opening != it and *(opening-1) == '\\') + { + append(StringView{it, opening-1}); + append('{'); + it = opening + 1; + } + else + { + append(StringView{it, opening}); + auto closing = std::find(opening, end, '}'); + if (closing == end) + throw runtime_error("format string error, unclosed '{'"); + + auto format = std::find(opening+1, closing, ':'); + const int index = opening+1 == format ? implicitIndex : str_to_int({opening+1, format}); + + if (index >= params.size()) + throw runtime_error("format string parameter index too big"); + + if (format != closing) + { + char padding = ' '; + if (*(++format) == '0') + { + padding = '0'; + ++format; + } + for (ColumnCount width = str_to_int({format, closing}), len = params[index].column_length(); + width > len; --width) + append(padding); + } + + append(params[index]); + implicitIndex = index+1; + it = closing+1; + } + } +} + +StringView format_to(ArrayView buffer, StringView fmt, ArrayView params) +{ + char* ptr = buffer.begin(); + const char* end = buffer.end(); + format_impl(fmt, params, [&](StringView s) mutable { + for (auto c : s) + { + if (ptr == end) + throw runtime_error("buffer is too small"); + *ptr++ = c; + } + }); + if (ptr == end) + throw runtime_error("buffer is too small"); + *ptr = 0; + + return { buffer.begin(), ptr }; +} + +void format_with(FunctionRef append, StringView fmt, ArrayView params) +{ + format_impl(fmt, params, append); +} + +String format(StringView fmt, ArrayView params) +{ + ByteCount size = fmt.length(); + for (auto& s : params) size += s.length(); + String res; + res.reserve(size); + + format_impl(fmt, params, [&](StringView s) { res += s; }); + return res; +} + +} diff --git a/src/format.hh b/src/format.hh new file mode 100644 index 00000000..652bc477 --- /dev/null +++ b/src/format.hh @@ -0,0 +1,81 @@ +#ifndef format_hh_INCLUDED +#define format_hh_INCLUDED + +#include "string.hh" +#include "utils.hh" + +namespace Kakoune +{ + +template +struct InplaceString +{ + static_assert(N < 256, "InplaceString cannot handle sizes >= 256"); + + constexpr operator StringView() const { return {m_data, ByteCount{m_length}}; } + operator String() const { return {m_data, ByteCount{m_length}}; } + + unsigned char m_length{}; + char m_data[N]; +}; + +struct Hex { size_t val; }; +constexpr Hex hex(size_t val) { return {val}; } + +struct Grouped { size_t val; }; +constexpr Grouped grouped(size_t val) { return {val}; } + +InplaceString<15> to_string(int val); +InplaceString<15> to_string(unsigned val); +InplaceString<23> to_string(long int val); +InplaceString<23> to_string(unsigned long val); +InplaceString<23> to_string(long long int val); +InplaceString<23> to_string(Hex val); +InplaceString<23> to_string(Grouped val); +InplaceString<23> to_string(float val); +InplaceString<7> to_string(Codepoint c); + +template +decltype(auto) to_string(const StronglyTypedNumber& val) +{ + return to_string((ValueType)val); +} + +namespace detail +{ + +template requires std::is_convertible_v +StringView format_param(const T& val) { return val; } + +template requires (not std::is_convertible_v) +decltype(auto) format_param(const T& val) { return to_string(val); } + +} + +String format(StringView fmt, ArrayView params); + +template +String format(StringView fmt, Types&&... params) +{ + return format(fmt, ArrayView{detail::format_param(std::forward(params))...}); +} + +StringView format_to(ArrayView buffer, StringView fmt, ArrayView params); + +template +StringView format_to(ArrayView buffer, StringView fmt, Types&&... params) +{ + return format_to(buffer, fmt, ArrayView{detail::format_param(std::forward(params))...}); +} + +void format_with(FunctionRef append, StringView fmt, ArrayView params); + +template +void format_with(FunctionRef append, StringView fmt, Types&&... params) +{ + return format_with(append, fmt, ArrayView{detail::format_param(std::forward(params))...}); +} + +} + +#endif // format_hh_INCLUDED diff --git a/src/highlighter_group.cc b/src/highlighter_group.cc index 813262c0..7802df94 100644 --- a/src/highlighter_group.cc +++ b/src/highlighter_group.cc @@ -1,7 +1,7 @@ #include "highlighter_group.hh" #include "ranges.hh" -#include "string_utils.hh" +#include "format.hh" namespace Kakoune { diff --git a/src/keymap_manager.cc b/src/keymap_manager.cc index 582a271d..583fb2e7 100644 --- a/src/keymap_manager.cc +++ b/src/keymap_manager.cc @@ -3,7 +3,7 @@ #include "array_view.hh" #include "assert.hh" #include "exception.hh" -#include "string_utils.hh" +#include "format.hh" #include diff --git a/src/parameters_parser.hh b/src/parameters_parser.hh index c11dc501..7d26c3bb 100644 --- a/src/parameters_parser.hh +++ b/src/parameters_parser.hh @@ -8,7 +8,7 @@ #include "optional.hh" #include "flags.hh" #include "string.hh" -#include "string_utils.hh" +#include "format.hh" #include diff --git a/src/regex_impl.cc b/src/regex_impl.cc index c32917eb..2cebf964 100644 --- a/src/regex_impl.cc +++ b/src/regex_impl.cc @@ -6,7 +6,7 @@ #include "unit_tests.hh" #include "utf8.hh" #include "utf8_iterator.hh" -#include "string_utils.hh" +#include "format.hh" #include "vector.hh" #include "utils.hh" diff --git a/src/register_manager.cc b/src/register_manager.cc index a189c5b6..bb198dc6 100644 --- a/src/register_manager.cc +++ b/src/register_manager.cc @@ -3,7 +3,7 @@ #include "assert.hh" #include "context.hh" #include "hash_map.hh" -#include "string_utils.hh" +#include "format.hh" namespace Kakoune { diff --git a/src/string_utils.cc b/src/string_utils.cc index c614d485..42b299f9 100644 --- a/src/string_utils.cc +++ b/src/string_utils.cc @@ -147,88 +147,6 @@ int str_to_int(StringView str) throw runtime_error{str + " is not a number"}; } -template -InplaceString to_string_impl(auto val, auto format) -{ - InplaceString res; - auto [end, errc] = std::to_chars(res.m_data, res.m_data + N, val, format); - if (errc != std::errc{}) - throw runtime_error("to_string error"); - res.m_length = end - res.m_data; - *end = '\0'; - return res; -} - -template -InplaceString to_string_impl(auto val) -{ - return to_string_impl(val, 10); -} - -InplaceString<15> to_string(int val) -{ - return to_string_impl<15>(val); -} - -InplaceString<15> to_string(unsigned val) -{ - return to_string_impl<15>(val); -} - -InplaceString<23> to_string(long int val) -{ - return to_string_impl<23>(val); -} - -InplaceString<23> to_string(long long int val) -{ - return to_string_impl<23>(val); -} - -InplaceString<23> to_string(unsigned long val) -{ - return to_string_impl<23>(val); -} - -InplaceString<23> to_string(Hex val) -{ - return to_string_impl<23>(val.val, 16); -} - -InplaceString<23> to_string(Grouped val) -{ - auto ungrouped = to_string_impl<23>(val.val); - - InplaceString<23> res; - for (int pos = 0, len = ungrouped.m_length; pos != len; ++pos) - { - if (res.m_length and ((len - pos) % 3) == 0) - res.m_data[res.m_length++] = ','; - res.m_data[res.m_length++] = ungrouped.m_data[pos]; - } - return res; -} - -InplaceString<23> to_string(float val) -{ -#if defined(__cpp_lib_to_chars) - return to_string_impl<23>(val, std::chars_format::general); -#else - InplaceString<23> res; - res.m_length = snprintf(res.m_data, 23, "%f", val); - return res; -#endif -} - -InplaceString<7> to_string(Codepoint c) -{ - InplaceString<7> res; - char* ptr = res.m_data; - utf8::dump(ptr, c); - res.m_length = (int)(ptr - res.m_data); - return res; -} - bool subsequence_match(StringView str, StringView subseq) { auto it = str.begin(); @@ -327,92 +245,6 @@ WrapView::Iterator& WrapView::Iterator::operator++() return *this; } -template -void format_impl(StringView fmt, ArrayView params, AppendFunc append) -{ - int implicitIndex = 0; - for (auto it = fmt.begin(), end = fmt.end(); it != end;) - { - auto opening = std::find(it, end, '{'); - if (opening == end) - { - append(StringView{it, opening}); - break; - } - else if (opening != it and *(opening-1) == '\\') - { - append(StringView{it, opening-1}); - append('{'); - it = opening + 1; - } - else - { - append(StringView{it, opening}); - auto closing = std::find(opening, end, '}'); - if (closing == end) - throw runtime_error("format string error, unclosed '{'"); - - auto format = std::find(opening+1, closing, ':'); - const int index = opening+1 == format ? implicitIndex : str_to_int({opening+1, format}); - - if (index >= params.size()) - throw runtime_error("format string parameter index too big"); - - if (format != closing) - { - char padding = ' '; - if (*(++format) == '0') - { - padding = '0'; - ++format; - } - for (ColumnCount width = str_to_int({format, closing}), len = params[index].column_length(); - width > len; --width) - append(padding); - } - - append(params[index]); - implicitIndex = index+1; - it = closing+1; - } - } -} - -StringView format_to(ArrayView buffer, StringView fmt, ArrayView params) -{ - char* ptr = buffer.begin(); - const char* end = buffer.end(); - format_impl(fmt, params, [&](StringView s) mutable { - for (auto c : s) - { - if (ptr == end) - throw runtime_error("buffer is too small"); - *ptr++ = c; - } - }); - if (ptr == end) - throw runtime_error("buffer is too small"); - *ptr = 0; - - return { buffer.begin(), ptr }; -} - -void format_with(FunctionRef append, StringView fmt, ArrayView params) -{ - format_impl(fmt, params, append); -} - -String format(StringView fmt, ArrayView params) -{ - ByteCount size = fmt.length(); - for (auto& s : params) size += s.length(); - String res; - res.reserve(size); - - format_impl(fmt, params, [&](StringView s) { res += s; }); - return res; -} - String double_up(StringView s, StringView characters) { String res; diff --git a/src/string_utils.hh b/src/string_utils.hh index 3034dfd5..24da0111 100644 --- a/src/string_utils.hh +++ b/src/string_utils.hh @@ -4,9 +4,10 @@ #include "string.hh" #include "enum.hh" #include "vector.hh" -#include "ranges.hh" #include "optional.hh" #include "utils.hh" +#include "format.hh" +#include "ranges.hh" namespace Kakoune { @@ -107,75 +108,6 @@ inline auto wrap_at(ColumnCount max_width) int str_to_int(StringView str); // throws on error Optional str_to_int_ifp(StringView str); -template -struct InplaceString -{ - static_assert(N < 256, "InplaceString cannot handle sizes >= 256"); - - constexpr operator StringView() const { return {m_data, ByteCount{m_length}}; } - operator String() const { return {m_data, ByteCount{m_length}}; } - - unsigned char m_length{}; - char m_data[N]; -}; - -struct Hex { size_t val; }; -constexpr Hex hex(size_t val) { return {val}; } - -struct Grouped { size_t val; }; -constexpr Grouped grouped(size_t val) { return {val}; } - -InplaceString<15> to_string(int val); -InplaceString<15> to_string(unsigned val); -InplaceString<23> to_string(long int val); -InplaceString<23> to_string(unsigned long val); -InplaceString<23> to_string(long long int val); -InplaceString<23> to_string(Hex val); -InplaceString<23> to_string(Grouped val); -InplaceString<23> to_string(float val); -InplaceString<7> to_string(Codepoint c); - -template -decltype(auto) to_string(const StronglyTypedNumber& val) -{ - return to_string((ValueType)val); -} - -namespace detail -{ - -template requires std::is_convertible_v -StringView format_param(const T& val) { return val; } - -template requires (not std::is_convertible_v) -decltype(auto) format_param(const T& val) { return to_string(val); } - -} - -String format(StringView fmt, ArrayView params); - -template -String format(StringView fmt, Types&&... params) -{ - return format(fmt, ArrayView{detail::format_param(std::forward(params))...}); -} - -StringView format_to(ArrayView buffer, StringView fmt, ArrayView params); - -template -StringView format_to(ArrayView buffer, StringView fmt, Types&&... params) -{ - return format_to(buffer, fmt, ArrayView{detail::format_param(std::forward(params))...}); -} - -void format_with(FunctionRef append, StringView fmt, ArrayView params); - -template -void format_with(FunctionRef append, StringView fmt, Types&&... params) -{ - return format_with(append, fmt, ArrayView{detail::format_param(std::forward(params))...}); -} - String double_up(StringView s, StringView characters); inline String quote(StringView s) diff --git a/src/terminal_ui.cc b/src/terminal_ui.cc index 33574e90..991cdecf 100644 --- a/src/terminal_ui.cc +++ b/src/terminal_ui.cc @@ -7,7 +7,7 @@ #include "file.hh" #include "keys.hh" #include "ranges.hh" -#include "string_utils.hh" +#include "format.hh" #include "diff.hh" #include -- cgit v1.2.3 From 1b2100753e4bdc65b1c6a78662ab5eeb7eaaa8d3 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Fri, 9 Aug 2024 18:31:26 +1000 Subject: Reduce exposed headers from context.hh --- src/context.cc | 34 +++++++++++++++++++++++++++++++--- src/context.hh | 45 ++++++++++++++++++++------------------------- 2 files changed, 51 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/context.cc b/src/context.cc index 46d9cd58..048da784 100644 --- a/src/context.cc +++ b/src/context.cc @@ -1,10 +1,8 @@ #include "context.hh" -#include "alias_registry.hh" #include "client.hh" -#include "face_registry.hh" +#include "scope.hh" #include "buffer_manager.hh" -#include "hook_manager.hh" #include "register_manager.hh" #include "window.hh" @@ -62,6 +60,12 @@ Scope& Context::scope(bool allow_local) const return GlobalScope::instance(); } +OptionManager& Context::options() const { return scope().options(); } +HookManager& Context::hooks() const { return scope().hooks(); } +KeymapManager& Context::keymaps() const { return scope().keymaps(); } +AliasRegistry& Context::aliases() const { return scope().aliases(); } +FaceRegistry& Context::faces(bool allow_local) const { return scope(allow_local).faces(); } + void Context::set_client(Client& client) { kak_assert(not has_client()); @@ -82,6 +86,12 @@ void Context::print_status(DisplayLine status) const client().print_status(std::move(status)); } +void Context::push_jump(bool force) +{ + if (force or not (m_flags & Flags::Draft)) + m_jump_list.push(selections()); +} + void JumpList::push(SelectionList jump, Optional index) { if (index) @@ -428,4 +438,22 @@ void Context::set_name(String name) { String old_name = std::exchange(m_name, std::move(name)); hooks().run_hook(Hook::ClientRenamed, format("{}:{}", old_name, m_name), *this); } + +ScopedEdition::ScopedEdition(Context& context) + : m_context{context}, + m_buffer{context.has_buffer() ? &context.buffer() : nullptr} +{ if (m_buffer) m_context.begin_edition(); } + +ScopedEdition::~ScopedEdition() { if (m_buffer) m_context.end_edition(); } + +ScopedSelectionEdition::ScopedSelectionEdition(Context& context) + : m_context{context}, + m_buffer{not (m_context.flags() & Context::Flags::Draft) and context.has_buffer() ? &context.buffer() : nullptr} +{ if (m_buffer) m_context.m_selection_history.begin_edition(); } + +ScopedSelectionEdition::ScopedSelectionEdition(ScopedSelectionEdition&& other) : m_context{other.m_context}, m_buffer{other.m_buffer} +{ other.m_buffer = nullptr; } + +ScopedSelectionEdition::~ScopedSelectionEdition() { if (m_buffer) m_context.m_selection_history.end_edition(); } + } diff --git a/src/context.hh b/src/context.hh index fb45fc2d..e1c0f657 100644 --- a/src/context.hh +++ b/src/context.hh @@ -4,20 +4,26 @@ #include "selection.hh" #include "optional.hh" #include "utils.hh" +#include "flags.hh" #include namespace Kakoune { +class Context; class Window; class Buffer; class Client; class Scope; class InputHandler; class DisplayLine; -class KeymapManager; + class AliasRegistry; +class FaceRegistry; +class OptionManager; +class KeymapManager; +class HookManager; enum Direction { Backward = -1, Forward = 1 }; @@ -104,11 +110,11 @@ public: Scope& scope(bool allow_local = true) const; Scope* local_scope() const { return m_local_scopes.empty() ? nullptr : m_local_scopes.back(); } - OptionManager& options() const { return scope().options(); } - HookManager& hooks() const { return scope().hooks(); } - KeymapManager& keymaps() const { return scope().keymaps(); } - AliasRegistry& aliases() const { return scope().aliases(); } - FaceRegistry& faces(bool allow_local = true) const { return scope(allow_local).faces(); } + OptionManager& options() const; + HookManager& hooks() const; + KeymapManager& keymaps() const; + AliasRegistry& aliases() const; + FaceRegistry& faces(bool allow_local = true) const; void print_status(DisplayLine status) const; @@ -132,11 +138,7 @@ public: Flags flags() const { return m_flags; } JumpList& jump_list() { return m_jump_list; } - void push_jump(bool force = false) - { - if (force or not (m_flags & Flags::Draft)) - m_jump_list.push(selections()); - } + void push_jump(bool force = false); template void set_last_select(Func&& last_select) { m_last_select = std::forward(last_select); } @@ -215,12 +217,9 @@ private: struct ScopedEdition { - ScopedEdition(Context& context) - : m_context{context}, - m_buffer{context.has_buffer() ? &context.buffer() : nullptr} - { if (m_buffer) m_context.begin_edition(); } - - ~ScopedEdition() { if (m_buffer) m_context.end_edition(); } + ScopedEdition(Context& context); + ~ScopedEdition(); + ScopedEdition(const ScopedEdition&) = delete; Context& context() const { return m_context; } private: @@ -230,14 +229,10 @@ private: struct ScopedSelectionEdition { - ScopedSelectionEdition(Context& context) - : m_context{context}, - m_buffer{not (m_context.flags() & Context::Flags::Draft) and context.has_buffer() ? &context.buffer() : nullptr} - { if (m_buffer) m_context.m_selection_history.begin_edition(); } - ScopedSelectionEdition(ScopedSelectionEdition&& other) : m_context{other.m_context}, m_buffer{other.m_buffer} - { other.m_buffer = nullptr; } - - ~ScopedSelectionEdition() { if (m_buffer) m_context.m_selection_history.end_edition(); } + ScopedSelectionEdition(Context& context); + ScopedSelectionEdition(ScopedSelectionEdition&& other); + ~ScopedSelectionEdition(); + private: Context& m_context; SafePtr m_buffer; -- cgit v1.2.3 From 6ed01f402b3a54495c8d9e462b7674864fbbe402 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Fri, 9 Aug 2024 18:33:32 +1000 Subject: Reduce headers dependency graph Move more code into the implementation files to reduce the amount of code pulled by headers. --- src/alias_registry.hh | 1 + src/assert.cc | 1 + src/completion.cc | 1 + src/display_buffer.hh | 2 ++ src/file.hh | 1 + src/hook_manager.hh | 1 + src/input_handler.hh | 1 + src/json.hh | 1 + src/json_ui.cc | 1 + src/keymap_manager.cc | 1 + src/keys.cc | 1 + src/normal.cc | 2 +- src/option_manager.hh | 1 + src/option_types.hh | 2 +- src/parameters_parser.cc | 1 + src/ranked_match.cc | 1 + src/regex_impl.cc | 1 + src/regex_impl.hh | 1 + src/register_manager.cc | 1 + src/register_manager.hh | 1 + src/selection.cc | 34 ++++++++++++++++++++++++++++++++++ src/selection.hh | 45 +++++++++++++++++---------------------------- src/selectors.hh | 1 + src/unicode.hh | 9 ++++++--- 24 files changed, 79 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/alias_registry.hh b/src/alias_registry.hh index 1b7a49eb..32f9e2fb 100644 --- a/src/alias_registry.hh +++ b/src/alias_registry.hh @@ -3,6 +3,7 @@ #include "safe_ptr.hh" #include "string.hh" +#include "ranges.hh" #include "hash_map.hh" namespace Kakoune diff --git a/src/assert.cc b/src/assert.cc index e755e8ba..7be769a1 100644 --- a/src/assert.cc +++ b/src/assert.cc @@ -1,6 +1,7 @@ #include "assert.hh" #include "backtrace.hh" +#include "format.hh" #include "buffer_utils.hh" #include "exception.hh" diff --git a/src/completion.cc b/src/completion.cc index 762a0413..60e79e07 100644 --- a/src/completion.cc +++ b/src/completion.cc @@ -2,6 +2,7 @@ #include "file.hh" #include "context.hh" #include "option_types.hh" +#include "option_manager.hh" #include "regex.hh" namespace Kakoune diff --git a/src/display_buffer.hh b/src/display_buffer.hh index c4ea6fb5..b1a18098 100644 --- a/src/display_buffer.hh +++ b/src/display_buffer.hh @@ -7,6 +7,8 @@ #include "string.hh" #include "vector.hh" #include "hash_map.hh" +#include "ranges.hh" + #include namespace Kakoune diff --git a/src/file.hh b/src/file.hh index cfc68ac2..9411fd78 100644 --- a/src/file.hh +++ b/src/file.hh @@ -6,6 +6,7 @@ #include "meta.hh" #include "string.hh" #include "units.hh" +#include "constexpr_utils.hh" #include "vector.hh" #include diff --git a/src/hook_manager.hh b/src/hook_manager.hh index bee06064..114deefd 100644 --- a/src/hook_manager.hh +++ b/src/hook_manager.hh @@ -6,6 +6,7 @@ #include "safe_ptr.hh" #include "meta.hh" #include "enum.hh" +#include "constexpr_utils.hh" #include diff --git a/src/input_handler.hh b/src/input_handler.hh index dd475c92..fa7c91b1 100644 --- a/src/input_handler.hh +++ b/src/input_handler.hh @@ -5,6 +5,7 @@ #include "constexpr_utils.hh" #include "context.hh" #include "env_vars.hh" +#include "enum.hh" #include "face.hh" #include "normal.hh" #include "optional.hh" diff --git a/src/json.hh b/src/json.hh index 84c14d36..6765c793 100644 --- a/src/json.hh +++ b/src/json.hh @@ -3,6 +3,7 @@ #include "hash_map.hh" #include "string.hh" +#include "string_utils.hh" #include "value.hh" namespace Kakoune diff --git a/src/json_ui.cc b/src/json_ui.cc index 01768897..1efbf2a5 100644 --- a/src/json_ui.cc +++ b/src/json_ui.cc @@ -8,6 +8,7 @@ #include "keys.hh" #include "ranges.hh" #include "string_utils.hh" +#include "format.hh" #include #include diff --git a/src/keymap_manager.cc b/src/keymap_manager.cc index 583fb2e7..8894267a 100644 --- a/src/keymap_manager.cc +++ b/src/keymap_manager.cc @@ -4,6 +4,7 @@ #include "assert.hh" #include "exception.hh" #include "format.hh" +#include "ranges.hh" #include diff --git a/src/keys.cc b/src/keys.cc index 5ba44181..4a14e0fc 100644 --- a/src/keys.cc +++ b/src/keys.cc @@ -6,6 +6,7 @@ #include "unit_tests.hh" #include "utf8_iterator.hh" #include "utils.hh" +#include "format.hh" #include "string_utils.hh" namespace Kakoune diff --git a/src/normal.cc b/src/normal.cc index ea183bc4..5a7c4e58 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -1841,7 +1841,7 @@ SelectionList read_selections_from_register(char reg, const Context& context) const auto buffer_name = StringView{ content[0].begin (), end_content[1].begin () - 1 }; Buffer& buffer = BufferManager::instance().get_buffer(buffer_name); - return selection_list_from_strings(buffer, ColumnType::Byte, content | skip(1), timestamp, main); + return selection_list_from_strings(buffer, ColumnType::Byte, content.subrange(1), timestamp, main); } enum class CombineOp diff --git a/src/option_manager.hh b/src/option_manager.hh index 3a4bb5a5..480b589b 100644 --- a/src/option_manager.hh +++ b/src/option_manager.hh @@ -8,6 +8,7 @@ #include "ranges.hh" #include "utils.hh" #include "vector.hh" +#include "format.hh" #include "string_utils.hh" #include diff --git a/src/option_types.hh b/src/option_types.hh index 40d367df..fedc476f 100644 --- a/src/option_types.hh +++ b/src/option_types.hh @@ -7,9 +7,9 @@ #include "flags.hh" #include "hash_map.hh" #include "option.hh" -#include "ranges.hh" #include "string.hh" #include "string_utils.hh" +#include "format.hh" #include "units.hh" #include diff --git a/src/parameters_parser.cc b/src/parameters_parser.cc index 75575323..5d2858ed 100644 --- a/src/parameters_parser.cc +++ b/src/parameters_parser.cc @@ -1,5 +1,6 @@ #include "parameters_parser.hh" +#include "ranges.hh" #include "flags.hh" namespace Kakoune diff --git a/src/ranked_match.cc b/src/ranked_match.cc index a13decdf..87bcece7 100644 --- a/src/ranked_match.cc +++ b/src/ranked_match.cc @@ -4,6 +4,7 @@ #include "unit_tests.hh" #include "utf8_iterator.hh" #include "optional.hh" +#include "ranges.hh" #include diff --git a/src/regex_impl.cc b/src/regex_impl.cc index 2cebf964..f6393b56 100644 --- a/src/regex_impl.cc +++ b/src/regex_impl.cc @@ -9,6 +9,7 @@ #include "format.hh" #include "vector.hh" #include "utils.hh" +#include "ranges.hh" #include #include diff --git a/src/regex_impl.hh b/src/regex_impl.hh index b772169d..7f3eb495 100644 --- a/src/regex_impl.hh +++ b/src/regex_impl.hh @@ -9,6 +9,7 @@ #include "utils.hh" #include +#include namespace Kakoune { diff --git a/src/register_manager.cc b/src/register_manager.cc index bb198dc6..254104a4 100644 --- a/src/register_manager.cc +++ b/src/register_manager.cc @@ -4,6 +4,7 @@ #include "context.hh" #include "hash_map.hh" #include "format.hh" +#include "hook_manager.hh" namespace Kakoune { diff --git a/src/register_manager.hh b/src/register_manager.hh index 2e760e6f..c7ca8590 100644 --- a/src/register_manager.hh +++ b/src/register_manager.hh @@ -6,6 +6,7 @@ #include "exception.hh" #include "utils.hh" #include "hash_map.hh" +#include "ranges.hh" #include "string.hh" #include "vector.hh" diff --git a/src/selection.cc b/src/selection.cc index f0f0270c..03dd4721 100644 --- a/src/selection.cc +++ b/src/selection.cc @@ -7,6 +7,8 @@ namespace Kakoune { +SelectionList::~SelectionList() = default; + SelectionList::SelectionList(Buffer& buffer, Selection s, size_t timestamp) : m_selections({ std::move(s) }), m_buffer(&buffer), m_timestamp(timestamp) { @@ -27,6 +29,11 @@ SelectionList::SelectionList(Buffer& buffer, Vector list, size_t time SelectionList::SelectionList(Buffer& buffer, Vector list) : SelectionList(buffer, std::move(list), buffer.timestamp()) {} +SelectionList::SelectionList(const SelectionList&) = default; +SelectionList::SelectionList(SelectionList&&) = default; +SelectionList& SelectionList::operator=(const SelectionList&) = default; +SelectionList& SelectionList::operator=(SelectionList&&) = default; + void SelectionList::remove(size_t index) { m_selections.erase(begin() + index); @@ -538,4 +545,31 @@ Selection selection_from_string(ColumnType column_type, const Buffer& buffer, St return Selection{anchor, cursor}; } +SelectionList selection_list_from_strings(Buffer& buffer, ColumnType column_type, ConstArrayView descs, size_t timestamp, size_t main, ColumnCount tabstop) +{ + if ((column_type != ColumnType::Byte and timestamp != buffer.timestamp()) or timestamp > buffer.timestamp()) + throw runtime_error{format("invalid timestamp '{}'", timestamp)}; + + auto from_string = [&](StringView desc) { + return selection_from_string(column_type, buffer, desc, tabstop); + }; + + auto sels = descs | transform(from_string) | gather>(); + if (sels.empty()) + throw runtime_error{"empty selection description"}; + if (main >= sels.size()) + throw runtime_error{"invalid main selection index"}; + + sort_selections(sels, main); + merge_overlapping_selections(sels, main); + if (timestamp < buffer.timestamp()) + update_selections(sels, main, buffer, timestamp); + else + clamp_selections(sels, buffer); + + SelectionList res{buffer, std::move(sels)}; + res.set_main_index(main); + return res; +} + } diff --git a/src/selection.hh b/src/selection.hh index 509a527d..ede4fa7b 100644 --- a/src/selection.hh +++ b/src/selection.hh @@ -1,13 +1,21 @@ #ifndef selection_hh_INCLUDED #define selection_hh_INCLUDED -#include "buffer.hh" +#include "coord.hh" +#include "range.hh" +#include "safe_ptr.hh" +#include "utils.hh" +#include "string.hh" +#include "vector.hh" #include namespace Kakoune { +class Buffer; +using BufferRange = Range; + using CaptureList = Vector; constexpr ColumnCount max_column{std::numeric_limits::max()}; @@ -84,11 +92,18 @@ struct SelectionList { static constexpr MemoryDomain Domain = MemoryDomain::Selections; + ~SelectionList(); SelectionList(Buffer& buffer, Selection s); SelectionList(Buffer& buffer, Selection s, size_t timestamp); SelectionList(Buffer& buffer, Vector s); SelectionList(Buffer& buffer, Vector s, size_t timestamp); + SelectionList(const SelectionList&); + SelectionList(SelectionList&&); + + SelectionList& operator=(const SelectionList&); + SelectionList& operator=(SelectionList&&); + void update(bool merge = true); void check_invariant() const; @@ -166,33 +181,7 @@ String selection_to_string(ColumnType column_type, const Buffer& buffer, const S String selection_list_to_string(ColumnType column_type, const SelectionList& selections, ColumnCount tabstop = -1); -template -SelectionList selection_list_from_strings(Buffer& buffer, ColumnType column_type, StringArray&& descs, size_t timestamp, size_t main, ColumnCount tabstop = -1) -{ - if ((column_type != ColumnType::Byte and timestamp != buffer.timestamp()) or timestamp > buffer.timestamp()) - throw runtime_error{format("invalid timestamp '{}'", timestamp)}; - - auto from_string = [&](StringView desc) { - return selection_from_string(column_type, buffer, desc, tabstop); - }; - - auto sels = descs | transform(from_string) | gather>(); - if (sels.empty()) - throw runtime_error{"empty selection description"}; - if (main >= sels.size()) - throw runtime_error{"invalid main selection index"}; - - sort_selections(sels, main); - merge_overlapping_selections(sels, main); - if (timestamp < buffer.timestamp()) - update_selections(sels, main, buffer, timestamp); - else - clamp_selections(sels, buffer); - - SelectionList res{buffer, std::move(sels)}; - res.set_main_index(main); - return res; -} +SelectionList selection_list_from_strings(Buffer& buffer, ColumnType column_type, ConstArrayView descs, size_t timestamp, size_t main, ColumnCount tabstop = -1); } diff --git a/src/selectors.hh b/src/selectors.hh index a9a61314..e947250f 100644 --- a/src/selectors.hh +++ b/src/selectors.hh @@ -6,6 +6,7 @@ #include "meta.hh" #include "unicode.hh" #include "vector.hh" +#include "constexpr_utils.hh" namespace Kakoune { diff --git a/src/unicode.hh b/src/unicode.hh index 0acf4005..5ce63f4b 100644 --- a/src/unicode.hh +++ b/src/unicode.hh @@ -5,7 +5,6 @@ #include #include "array_view.hh" -#include "ranges.hh" #include "units.hh" namespace Kakoune @@ -75,8 +74,12 @@ enum WordType { Word, WORD }; template inline bool is_word(Codepoint c, ConstArrayView extra_word_chars = {'_'}) noexcept { - return (c < 128 ? is_basic_alpha(c) or is_basic_digit(c) : iswalnum((wchar_t)c)) or - contains(extra_word_chars, c); + if (c < 128 ? is_basic_alpha(c) or is_basic_digit(c) : iswalnum((wchar_t)c)) + return true; + for (auto cp : extra_word_chars) + if (c == cp) + return true; + return false; } template<> -- cgit v1.2.3 From 560e3631ec57d34c679e6b0faec1e0efdd18d915 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Sat, 10 Aug 2024 11:26:26 +1000 Subject: Move debug utils to debug.hh/debug.cc Lots of code includes buffer_utils.hh just for write_to_debug_buffer which pulls many unnecessary dependencies. Reorganise to reduce compile times. --- src/assert.cc | 3 ++- src/buffer_utils.cc | 30 ------------------------------ src/client.cc | 1 + src/command_manager.cc | 4 +++- src/commands.cc | 1 + src/debug.cc | 39 +++++++++++++++++++++++++++++++++++++++ src/debug.hh | 40 ++++++++++++++++++++++++++++++++++++++++ src/hash_map.cc | 4 +++- src/highlighter.cc | 2 +- src/highlighter.hh | 5 ++++- src/highlighters.cc | 1 + src/hook_manager.cc | 2 +- src/input_handler.cc | 2 +- src/insert_completer.cc | 1 + src/main.cc | 3 ++- src/option.hh | 23 ----------------------- src/option_types.cc | 1 + src/profile.hh | 1 + src/register_manager.cc | 11 +++++++++++ src/register_manager.hh | 5 ++--- src/remote.cc | 2 +- src/shared_string.cc | 3 ++- src/shell_manager.cc | 2 +- src/window.cc | 4 +++- 24 files changed, 122 insertions(+), 68 deletions(-) create mode 100644 src/debug.cc create mode 100644 src/debug.hh (limited to 'src') diff --git a/src/assert.cc b/src/assert.cc index 7be769a1..6e5fc512 100644 --- a/src/assert.cc +++ b/src/assert.cc @@ -2,8 +2,9 @@ #include "backtrace.hh" #include "format.hh" -#include "buffer_utils.hh" +#include "file.hh" #include "exception.hh" +#include "debug.hh" #include #include diff --git a/src/buffer_utils.cc b/src/buffer_utils.cc index 6a66b000..28b2de05 100644 --- a/src/buffer_utils.cc +++ b/src/buffer_utils.cc @@ -271,36 +271,6 @@ Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, bool scroll return buffer; } -void write_to_debug_buffer(StringView str) -{ - if (not BufferManager::has_instance()) - { - write(2, str); - write(2, "\n"); - return; - } - - constexpr StringView debug_buffer_name = "*debug*"; - // Try to ensure we keep an empty line at the end of the debug buffer - // where the user can put its cursor to scroll with new messages - const bool eol_back = not str.empty() and str.back() == '\n'; - if (Buffer* buffer = BufferManager::instance().get_buffer_ifp(debug_buffer_name)) - { - buffer->flags() &= ~Buffer::Flags::ReadOnly; - auto restore = on_scope_end([buffer] { buffer->flags() |= Buffer::Flags::ReadOnly; }); - - buffer->insert(buffer->back_coord(), eol_back ? str : str + "\n"); - } - else - { - String line = str + (eol_back ? "\n" : "\n\n"); - create_buffer_from_string( - debug_buffer_name.str(), Buffer::Flags::NoUndo | Buffer::Flags::Debug | Buffer::Flags::ReadOnly, - line); - } -} - - auto to_string(Buffer::HistoryId id) { using Result = decltype(to_string(size_t{})); diff --git a/src/client.cc b/src/client.cc index 8b084fd5..77fb7dcc 100644 --- a/src/client.cc +++ b/src/client.cc @@ -4,6 +4,7 @@ #include "context.hh" #include "buffer_manager.hh" #include "buffer_utils.hh" +#include "debug.hh" #include "file.hh" #include "remote.hh" #include "option.hh" diff --git a/src/command_manager.cc b/src/command_manager.cc index f7d094bb..3e44ab1e 100644 --- a/src/command_manager.cc +++ b/src/command_manager.cc @@ -2,10 +2,11 @@ #include "alias_registry.hh" #include "assert.hh" -#include "buffer_utils.hh" #include "context.hh" +#include "debug.hh" #include "flags.hh" #include "file.hh" +#include "hook_manager.hh" #include "optional.hh" #include "option_types.hh" #include "profile.hh" @@ -13,6 +14,7 @@ #include "regex.hh" #include "register_manager.hh" #include "shell_manager.hh" +#include "scope.hh" #include "utils.hh" #include "unit_tests.hh" diff --git a/src/commands.cc b/src/commands.cc index d22c0647..8446edf5 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -8,6 +8,7 @@ #include "command_manager.hh" #include "completion.hh" #include "context.hh" +#include "debug.hh" #include "event_manager.hh" #include "face_registry.hh" #include "file.hh" diff --git a/src/debug.cc b/src/debug.cc new file mode 100644 index 00000000..55f7e4d3 --- /dev/null +++ b/src/debug.cc @@ -0,0 +1,39 @@ +#include "debug.hh" + +#include "buffer_manager.hh" +#include "buffer_utils.hh" +#include "utils.hh" + +namespace Kakoune +{ + +void write_to_debug_buffer(StringView str) +{ + if (not BufferManager::has_instance()) + { + write(2, str); + write(2, "\n"); + return; + } + + constexpr StringView debug_buffer_name = "*debug*"; + // Try to ensure we keep an empty line at the end of the debug buffer + // where the user can put its cursor to scroll with new messages + const bool eol_back = not str.empty() and str.back() == '\n'; + if (Buffer* buffer = BufferManager::instance().get_buffer_ifp(debug_buffer_name)) + { + buffer->flags() &= ~Buffer::Flags::ReadOnly; + auto restore = on_scope_end([buffer] { buffer->flags() |= Buffer::Flags::ReadOnly; }); + + buffer->insert(buffer->back_coord(), eol_back ? str : str + "\n"); + } + else + { + String line = str + (eol_back ? "\n" : "\n\n"); + create_buffer_from_string( + debug_buffer_name.str(), Buffer::Flags::NoUndo | Buffer::Flags::Debug | Buffer::Flags::ReadOnly, + line); + } +} + +} diff --git a/src/debug.hh b/src/debug.hh new file mode 100644 index 00000000..ec010460 --- /dev/null +++ b/src/debug.hh @@ -0,0 +1,40 @@ +#ifndef debug_hh_INCLUDED +#define debug_hh_INCLUDED + +#include "constexpr_utils.hh" +#include "enum.hh" +#include "flags.hh" + +namespace Kakoune +{ + +class StringView; + +enum class DebugFlags +{ + None = 0, + Hooks = 1 << 0, + Shell = 1 << 1, + Profile = 1 << 2, + Keys = 1 << 3, + Commands = 1 << 4, +}; + +constexpr bool with_bit_ops(Meta::Type) { return true; } + +constexpr auto enum_desc(Meta::Type) +{ + return make_array>({ + { DebugFlags::Hooks, "hooks" }, + { DebugFlags::Shell, "shell" }, + { DebugFlags::Profile, "profile" }, + { DebugFlags::Keys, "keys" }, + { DebugFlags::Commands, "commands" }, + }); +} + +void write_to_debug_buffer(StringView str); + +} + +#endif // debug_hh_INCLUDED diff --git a/src/hash_map.cc b/src/hash_map.cc index ae486490..c0afa4a2 100644 --- a/src/hash_map.cc +++ b/src/hash_map.cc @@ -2,10 +2,12 @@ #include "clock.hh" #include "string.hh" -#include "buffer_utils.hh" #include "unit_tests.hh" +#include "format.hh" +#include "debug.hh" #include +#include #include namespace Kakoune diff --git a/src/highlighter.cc b/src/highlighter.cc index 86da8ac6..c6b1a13d 100644 --- a/src/highlighter.cc +++ b/src/highlighter.cc @@ -1,6 +1,6 @@ #include "highlighter.hh" -#include "buffer_utils.hh" +#include "debug.hh" namespace Kakoune { diff --git a/src/highlighter.hh b/src/highlighter.hh index 925dcaa7..c1070d9a 100644 --- a/src/highlighter.hh +++ b/src/highlighter.hh @@ -3,9 +3,9 @@ #include "coord.hh" #include "completion.hh" -#include "display_buffer.hh" #include "exception.hh" #include "flags.hh" +#include "range.hh" #include "hash_map.hh" #include "array_view.hh" #include "string.hh" @@ -18,6 +18,9 @@ namespace Kakoune { class Context; +class DisplayBuffer; + +using BufferRange = Range; enum class HighlightPass { diff --git a/src/highlighters.cc b/src/highlighters.cc index 86985084..4b18a447 100644 --- a/src/highlighters.cc +++ b/src/highlighters.cc @@ -2,6 +2,7 @@ #include "assert.hh" #include "buffer_utils.hh" +#include "debug.hh" #include "changes.hh" #include "command_manager.hh" #include "context.hh" diff --git a/src/hook_manager.cc b/src/hook_manager.cc index a1b29434..00b38677 100644 --- a/src/hook_manager.cc +++ b/src/hook_manager.cc @@ -1,6 +1,6 @@ #include "hook_manager.hh" -#include "buffer_utils.hh" +#include "debug.hh" #include "clock.hh" #include "command_manager.hh" #include "context.hh" diff --git a/src/input_handler.cc b/src/input_handler.cc index 56999d45..615dbf10 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -1,7 +1,7 @@ #include "input_handler.hh" #include "buffer_manager.hh" -#include "buffer_utils.hh" +#include "debug.hh" #include "command_manager.hh" #include "client.hh" #include "event_manager.hh" diff --git a/src/insert_completer.cc b/src/insert_completer.cc index 73c08a43..b369359a 100644 --- a/src/insert_completer.cc +++ b/src/insert_completer.cc @@ -2,6 +2,7 @@ #include "buffer_manager.hh" #include "buffer_utils.hh" +#include "debug.hh" #include "client.hh" #include "command_manager.hh" #include "changes.hh" diff --git a/src/main.cc b/src/main.cc index e86ffae3..21cb0446 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,12 +1,13 @@ #include "assert.hh" #include "backtrace.hh" #include "buffer.hh" -#include "buffer_manager.hh" #include "buffer_utils.hh" +#include "buffer_manager.hh" #include "client_manager.hh" #include "command_manager.hh" #include "commands.hh" #include "context.hh" +#include "debug.hh" #include "event_manager.hh" #include "face_registry.hh" #include "file.hh" diff --git a/src/option.hh b/src/option.hh index 732fefca..b6edca0c 100644 --- a/src/option.hh +++ b/src/option.hh @@ -64,29 +64,6 @@ struct PrefixedList template using TimestampedList = PrefixedList; -enum class DebugFlags -{ - None = 0, - Hooks = 1 << 0, - Shell = 1 << 1, - Profile = 1 << 2, - Keys = 1 << 3, - Commands = 1 << 4, -}; - -constexpr bool with_bit_ops(Meta::Type) { return true; } - -constexpr auto enum_desc(Meta::Type) -{ - return make_array>({ - { DebugFlags::Hooks, "hooks" }, - { DebugFlags::Shell, "shell" }, - { DebugFlags::Profile, "profile" }, - { DebugFlags::Keys, "keys" }, - { DebugFlags::Commands, "commands" }, - }); -} - } #endif // option_hh_INCLUDED diff --git a/src/option_types.cc b/src/option_types.cc index a1eeb418..f005c1db 100644 --- a/src/option_types.cc +++ b/src/option_types.cc @@ -1,4 +1,5 @@ #include "option_types.hh" +#include "debug.hh" #include "unit_tests.hh" namespace Kakoune diff --git a/src/profile.hh b/src/profile.hh index 7feff017..f107ebd3 100644 --- a/src/profile.hh +++ b/src/profile.hh @@ -3,6 +3,7 @@ #include "option.hh" #include "clock.hh" +#include "option_manager.hh" namespace Kakoune { diff --git a/src/register_manager.cc b/src/register_manager.cc index 254104a4..b9d09a52 100644 --- a/src/register_manager.cc +++ b/src/register_manager.cc @@ -4,11 +4,22 @@ #include "context.hh" #include "hash_map.hh" #include "format.hh" +#include "ranges.hh" #include "hook_manager.hh" namespace Kakoune { +Register::RestoreInfo Register::save(const Context& context) +{ + return get(context) | gather(); +} + +void Register::restore(Context& context, const RestoreInfo& info) +{ + set(context, info, true); +} + void StaticRegister::set(Context& context, ConstArrayView values, bool) { m_content.assign(values.begin(), values.end()); diff --git a/src/register_manager.hh b/src/register_manager.hh index c7ca8590..9d843eff 100644 --- a/src/register_manager.hh +++ b/src/register_manager.hh @@ -6,7 +6,6 @@ #include "exception.hh" #include "utils.hh" #include "hash_map.hh" -#include "ranges.hh" #include "string.hh" #include "vector.hh" @@ -25,8 +24,8 @@ public: virtual const String& get_main(const Context& context, size_t main_index) = 0; using RestoreInfo = Vector; - RestoreInfo save(const Context& context) { return get(context) | gather(); } - void restore(Context& context, const RestoreInfo& info) { set(context, info, true); } + RestoreInfo save(const Context& context); + void restore(Context& context, const RestoreInfo& info); NestedBool& modified_hook_disabled() { return m_disable_modified_hook; } diff --git a/src/remote.cc b/src/remote.cc index 025a4458..97a62b02 100644 --- a/src/remote.cc +++ b/src/remote.cc @@ -1,7 +1,7 @@ #include "remote.hh" -#include "buffer_manager.hh" #include "buffer_utils.hh" +#include "debug.hh" #include "client_manager.hh" #include "command_manager.hh" #include "display_buffer.hh" diff --git a/src/shared_string.cc b/src/shared_string.cc index f88008b1..8b4f6e6e 100644 --- a/src/shared_string.cc +++ b/src/shared_string.cc @@ -1,5 +1,6 @@ #include "shared_string.hh" -#include "buffer_utils.hh" +#include "debug.hh" +#include "format.hh" namespace Kakoune { diff --git a/src/shell_manager.cc b/src/shell_manager.cc index 47432df5..d08c4dbd 100644 --- a/src/shell_manager.cc +++ b/src/shell_manager.cc @@ -1,6 +1,6 @@ #include "shell_manager.hh" -#include "buffer_utils.hh" +#include "debug.hh" #include "client.hh" #include "clock.hh" #include "context.hh" diff --git a/src/window.cc b/src/window.cc index e296a62d..e992af01 100644 --- a/src/window.cc +++ b/src/window.cc @@ -1,13 +1,15 @@ #include "window.hh" #include "assert.hh" +#include "buffer.hh" +#include "buffer_utils.hh" #include "clock.hh" #include "context.hh" #include "highlighter.hh" #include "hook_manager.hh" #include "input_handler.hh" #include "client.hh" -#include "buffer_utils.hh" +#include "debug.hh" #include "option.hh" #include "option_types.hh" #include "profile.hh" -- cgit v1.2.3 From 7a60ae9a7f7cb8feb9a688ecda8c1d59ccc0f0ad Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Wed, 14 Aug 2024 20:32:52 +1000 Subject: Add missing include for non libstdc++ builds --- src/string.hh | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/string.hh b/src/string.hh index 0ed1dc75..677f01f5 100644 --- a/src/string.hh +++ b/src/string.hh @@ -8,6 +8,7 @@ #include "units.hh" #include "utf8.hh" +#include namespace Kakoune { -- cgit v1.2.3 From c8f8548130d07c210d4fec0188f52633858ed228 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Wed, 14 Aug 2024 20:35:04 +1000 Subject: More include fixes --- src/format.cc | 1 + src/string_utils.cc | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/format.cc b/src/format.cc index 685fa651..4d53a687 100644 --- a/src/format.cc +++ b/src/format.cc @@ -4,6 +4,7 @@ #include "string_utils.hh" #include +#include namespace Kakoune { diff --git a/src/string_utils.cc b/src/string_utils.cc index 42b299f9..b6e06af2 100644 --- a/src/string_utils.cc +++ b/src/string_utils.cc @@ -5,7 +5,6 @@ #include "unit_tests.hh" #include -#include namespace Kakoune { -- cgit v1.2.3 From 203e3704d892f1eeac32fe35c97846f350184ec5 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Wed, 14 Aug 2024 21:32:03 +1000 Subject: Fix json-ui scroll support Add cursor coordinate parameters, and fix encoding to match the new one. --- src/json_ui.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/json_ui.cc b/src/json_ui.cc index 9d694c56..7f645605 100644 --- a/src/json_ui.cc +++ b/src/json_ui.cc @@ -284,12 +284,12 @@ void JsonUI::eval_json(const Value& json) } else if (method == "scroll") { - if (params.size() != 1) - throw invalid_rpc_request("scroll needs an amount"); - else if (not params[0].is_a()) - throw invalid_rpc_request("scroll amount is not an integer"); - m_on_key({Key::Modifiers::Scroll, (Codepoint)params[0].as()}); - + if (params.size() != 3) + throw invalid_rpc_request("scroll needs an amount and coordinates"); + else if (not params[0].is_a() or not params[1].is_a() or not params[2].is_a()) + throw invalid_rpc_request("scroll parameters are not integers"); + m_on_key({Key::Modifiers::Scroll | (Key::Modifiers)(params[0].as() << 16), + encode_coord({params[1].as(), params[2].as()})}); } else if (method == "menu_select") { -- cgit v1.2.3 From 01cb818c2077f5059bfa84834298bb813aa9baca Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Wed, 14 Aug 2024 22:04:35 +1000 Subject: Reduce number of included headers --- src/client.cc | 5 +++-- src/completion.hh | 1 - src/display_buffer.hh | 5 +---- src/shared_string.hh | 1 - src/shell_manager.cc | 3 +-- 5 files changed, 5 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/client.cc b/src/client.cc index 77fb7dcc..3f7494d9 100644 --- a/src/client.cc +++ b/src/client.cc @@ -1,7 +1,7 @@ #include "client.hh" -#include "face_registry.hh" #include "context.hh" +#include "face_registry.hh" #include "buffer_manager.hh" #include "buffer_utils.hh" #include "debug.hh" @@ -10,8 +10,9 @@ #include "option.hh" #include "option_types.hh" #include "client_manager.hh" -#include "command_manager.hh" #include "event_manager.hh" +#include "shell_manager.hh" +#include "command_manager.hh" #include "user_interface.hh" #include "window.hh" #include "hash_map.hh" diff --git a/src/completion.hh b/src/completion.hh index e9321d5a..78024e19 100644 --- a/src/completion.hh +++ b/src/completion.hh @@ -1,7 +1,6 @@ #ifndef completion_hh_INCLUDED #define completion_hh_INCLUDED -#include #include #include "units.hh" diff --git a/src/display_buffer.hh b/src/display_buffer.hh index b1a18098..613832dd 100644 --- a/src/display_buffer.hh +++ b/src/display_buffer.hh @@ -7,9 +7,6 @@ #include "string.hh" #include "vector.hh" #include "hash_map.hh" -#include "ranges.hh" - -#include namespace Kakoune { @@ -139,7 +136,7 @@ public: template iterator insert(iterator pos, It beg, It end) { - auto has_buffer_range = std::mem_fn(&DisplayAtom::has_buffer_range); + auto has_buffer_range = [](const DisplayAtom& atom) { return atom.has_buffer_range(); }; auto had_range = any_of(*this, has_buffer_range); if (auto first = std::find_if(beg, end, has_buffer_range); first != end) { diff --git a/src/shared_string.hh b/src/shared_string.hh index 78e9fef4..79c34830 100644 --- a/src/shared_string.hh +++ b/src/shared_string.hh @@ -6,7 +6,6 @@ #include "utils.hh" #include "hash_map.hh" -#include #include namespace Kakoune diff --git a/src/shell_manager.cc b/src/shell_manager.cc index d08c4dbd..7346f2c1 100644 --- a/src/shell_manager.cc +++ b/src/shell_manager.cc @@ -10,7 +10,6 @@ #include "face_registry.hh" #include "file.hh" #include "flags.hh" -#include "option.hh" #include "option_types.hh" #include "regex.hh" @@ -118,7 +117,7 @@ Shell spawn_shell(const char* shell, StringView cmdline, if (pid_t pid = vfork()) return {pid, std::move(stdin_pipe[1]), std::move(stdout_pipe[0]), std::move(stderr_pipe[0])}; - auto renamefd = [](int oldfd, int newfd) { + constexpr auto renamefd = [](int oldfd, int newfd) { if (oldfd == newfd) return; dup2(oldfd, newfd); -- cgit v1.2.3 From 449adb14a56f24fcfd9c836bcf69e1c4661fae89 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Mon, 12 Aug 2024 22:38:53 +1000 Subject: Remove tuple use from ranges.hh --- src/ranges.hh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/ranges.hh b/src/ranges.hh index 7b568cd2..1b6f8869 100644 --- a/src/ranges.hh +++ b/src/ranges.hh @@ -5,7 +5,6 @@ #include #include #include -#include #include "constexpr_utils.hh" @@ -191,7 +190,13 @@ struct EnumerateView Iterator(size_t index, RangeIt it) : m_index{index}, m_it{std::move(it)} {} - decltype(auto) operator*() { return std::tuple(m_index, *m_it); } + struct ValueType + { + size_t index; + decltype(*std::declval()) element; + }; + + ValueType operator*() { return {m_index, *m_it}; } Iterator& operator++() { ++m_index; ++m_it; return *this; } Iterator operator++(int) { auto copy = *this; ++(*this); return copy; } -- cgit v1.2.3 From b804693630f61be757413e6e5a700995be1b164b Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Mon, 12 Aug 2024 22:42:43 +1000 Subject: Remove unused wrap_to and reduce string_utils headers --- src/display_buffer.hh | 2 ++ src/format.cc | 1 + src/json.cc | 1 + src/option_types.hh | 1 + src/string_utils.cc | 73 +-------------------------------------------------- src/string_utils.hh | 40 +--------------------------- 6 files changed, 7 insertions(+), 111 deletions(-) (limited to 'src') diff --git a/src/display_buffer.hh b/src/display_buffer.hh index 613832dd..3a6ad0c2 100644 --- a/src/display_buffer.hh +++ b/src/display_buffer.hh @@ -8,6 +8,8 @@ #include "vector.hh" #include "hash_map.hh" +#include + namespace Kakoune { diff --git a/src/format.cc b/src/format.cc index 4d53a687..24f30681 100644 --- a/src/format.cc +++ b/src/format.cc @@ -3,6 +3,7 @@ #include "exception.hh" #include "string_utils.hh" +#include #include #include diff --git a/src/json.cc b/src/json.cc index 7323e2fe..93ffdcc4 100644 --- a/src/json.cc +++ b/src/json.cc @@ -5,6 +5,7 @@ #include "unit_tests.hh" #include "utils.hh" +#include #include namespace Kakoune diff --git a/src/option_types.hh b/src/option_types.hh index fedc476f..f6f89e8a 100644 --- a/src/option_types.hh +++ b/src/option_types.hh @@ -11,6 +11,7 @@ #include "string_utils.hh" #include "format.hh" #include "units.hh" +#include "ranges.hh" #include #include diff --git a/src/string_utils.cc b/src/string_utils.cc index b6e06af2..b76c7511 100644 --- a/src/string_utils.cc +++ b/src/string_utils.cc @@ -3,6 +3,7 @@ #include "exception.hh" #include "utf8_iterator.hh" #include "unit_tests.hh" +#include "ranges.hh" #include @@ -187,63 +188,6 @@ String expand_tabs(StringView line, ColumnCount tabstop, ColumnCount col) return res; } -WrapView::Iterator::Iterator(StringView text, ColumnCount max_width) - : m_remaining{text}, m_max_width{max_width} -{ - if (max_width <= 0) - throw runtime_error("Invalid max width"); - ++*this; -} - -WrapView::Iterator& WrapView::Iterator::operator++() -{ - using Utf8It = utf8::iterator; - Utf8It it{m_remaining.begin(), m_remaining}; - Utf8It last_word_end = it; - - while (it != m_remaining.end()) - { - const CharCategories cat = categorize(*it, {'_'}); - if (cat == CharCategories::EndOfLine) - { - m_current = StringView{m_remaining.begin(), it.base()}; - m_remaining = StringView{(it+1).base(), m_remaining.end()}; - return *this; - } - - Utf8It word_end = it+1; - while (word_end != m_remaining.end() and categorize(*word_end, {'_'}) == cat) - ++word_end; - - if (word_end > m_remaining.begin() and - utf8::column_distance(m_remaining.begin(), word_end.base()) >= m_max_width) - { - auto line_end = last_word_end <= m_remaining.begin() ? - Utf8It{utf8::advance(m_remaining.begin(), m_remaining.end(), m_max_width), m_remaining} - : last_word_end; - - m_current = StringView{m_remaining.begin(), line_end.base()}; - - while (line_end != m_remaining.end() and is_horizontal_blank(*line_end)) - ++line_end; - - if (line_end != m_remaining.end() and *line_end == '\n') - ++line_end; - - m_remaining = StringView{line_end.base(), m_remaining.end()}; - return *this; - } - if (cat == CharCategories::Word or cat == CharCategories::Punctuation) - last_word_end = word_end; - - if (word_end > m_remaining.begin()) - it = word_end; - } - m_current = m_remaining; - m_remaining = StringView{}; - return *this; -} - String double_up(StringView s, StringView characters) { String res; @@ -275,21 +219,6 @@ UnitTest test_string{[]() kak_assert(StringView{"youpi"}.ends_with("youpi")); kak_assert(not StringView{"youpi"}.ends_with("oup")); - auto wrapped = "wrap this paragraph\n respecting whitespaces and much_too_long_words" | wrap_at(16) | gather>(); - kak_assert(wrapped.size() == 6); - kak_assert(wrapped[0] == "wrap this"); - kak_assert(wrapped[1] == "paragraph"); - kak_assert(wrapped[2] == " respecting"); - kak_assert(wrapped[3] == "whitespaces and"); - kak_assert(wrapped[4] == "much_too_long_wo"); - kak_assert(wrapped[5] == "rds"); - - auto wrapped2 = "error: unknown type" | wrap_at(7) | gather>(); - kak_assert(wrapped2.size() == 3); - kak_assert(wrapped2[0] == "error:"); - kak_assert(wrapped2[1] == "unknown"); - kak_assert(wrapped2[2] == "type"); - kak_assert(trim_indent(" ") == ""); kak_assert(trim_indent("no-indent") == "no-indent"); kak_assert(trim_indent("\nno-indent") == "no-indent"); diff --git a/src/string_utils.hh b/src/string_utils.hh index 24da0111..7c115269 100644 --- a/src/string_utils.hh +++ b/src/string_utils.hh @@ -7,7 +7,7 @@ #include "optional.hh" #include "utils.hh" #include "format.hh" -#include "ranges.hh" +#include "constexpr_utils.hh" namespace Kakoune { @@ -67,44 +67,6 @@ bool subsequence_match(StringView str, StringView subseq); String expand_tabs(StringView line, ColumnCount tabstop, ColumnCount col = 0); -struct WrapView -{ - struct Iterator - { - using difference_type = ptrdiff_t; - using value_type = StringView; - using pointer = StringView*; - using reference = StringView&; - using iterator_category = std::forward_iterator_tag; - - Iterator(StringView text, ColumnCount max_width); - - Iterator& operator++(); - Iterator operator++(int) { auto copy = *this; ++(*this); return copy; } - - bool operator==(Iterator other) const { return m_remaining == other.m_remaining and m_current == other.m_current; } - StringView operator*() { return m_current; } - - private: - StringView m_current; - StringView m_remaining; - ColumnCount m_max_width; - }; - - Iterator begin() const { return {text, max_width}; } - Iterator end() const { return {{}, 1}; } - - StringView text; - ColumnCount max_width; -}; - -inline auto wrap_at(ColumnCount max_width) -{ - return ViewFactory{[=](StringView text) { - return WrapView{text, max_width}; - }}; -} - int str_to_int(StringView str); // throws on error Optional str_to_int_ifp(StringView str); -- cgit v1.2.3 From 65ac5d42c9209c4b89c590c93cfa8d985e66b168 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Thu, 15 Aug 2024 11:41:35 +1000 Subject: Remove unused ConstexprVector and rename constexpr_utils.hh to array.hh --- src/array.hh | 48 +++++++++++++++++++++++++++ src/buffer.hh | 2 +- src/client.hh | 2 +- src/constexpr_utils.hh | 90 -------------------------------------------------- src/debug.hh | 2 +- src/file.hh | 2 +- src/hook_manager.hh | 2 +- src/input_handler.hh | 2 +- src/option.hh | 2 +- src/ranges.hh | 2 +- src/selectors.hh | 2 +- src/string_utils.hh | 2 +- 12 files changed, 58 insertions(+), 100 deletions(-) create mode 100644 src/array.hh delete mode 100644 src/constexpr_utils.hh (limited to 'src') diff --git a/src/array.hh b/src/array.hh new file mode 100644 index 00000000..ec8b098b --- /dev/null +++ b/src/array.hh @@ -0,0 +1,48 @@ +#ifndef array_hh_INCLUDED +#define array_hh_INCLUDED + +#include +#include + +#include "array_view.hh" + +namespace Kakoune +{ + +template +struct Array +{ + constexpr size_t size() const { return N; } + constexpr const T& operator[](int i) const { return m_data[i]; } + constexpr const T* begin() const { return m_data; } + constexpr const T* end() const { return m_data+N; } + + constexpr T& operator[](int i) { return m_data[i]; } + constexpr T* begin() { return m_data; } + constexpr T* end() { return m_data+N; } + + constexpr operator ArrayView() { return {m_data, N}; } + constexpr operator ConstArrayView() const { return {m_data, N}; } + + 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) +{ + static_assert(sizeof...(Indices) == N, "size mismatch"); + return {{data[Indices]...}}; +} + +template +constexpr Array make_array(const T (&data)[N]) +{ + return make_array(data, std::make_index_sequence()); +} + +} + +#endif // array_hh_INCLUDED diff --git a/src/buffer.hh b/src/buffer.hh index 7b671c0e..ec2b9620 100644 --- a/src/buffer.hh +++ b/src/buffer.hh @@ -3,7 +3,7 @@ #include "clock.hh" #include "coord.hh" -#include "constexpr_utils.hh" +#include "array.hh" #include "enum.hh" #include "file.hh" #include "optional.hh" diff --git a/src/client.hh b/src/client.hh index 64262f91..05b091ae 100644 --- a/src/client.hh +++ b/src/client.hh @@ -1,7 +1,7 @@ #ifndef client_hh_INCLUDED #define client_hh_INCLUDED -#include "constexpr_utils.hh" +#include "array.hh" #include "display_buffer.hh" #include "env_vars.hh" #include "input_handler.hh" diff --git a/src/constexpr_utils.hh b/src/constexpr_utils.hh deleted file mode 100644 index f83faacb..00000000 --- a/src/constexpr_utils.hh +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef constexpr_utils_hh_INCLUDED -#define constexpr_utils_hh_INCLUDED - -#include -#include -#include - -#include "array_view.hh" - -namespace Kakoune -{ - -template -struct Array -{ - constexpr size_t size() const { return N; } - constexpr const T& operator[](int i) const { return m_data[i]; } - constexpr const T* begin() const { return m_data; } - constexpr const T* end() const { return m_data+N; } - - constexpr T& operator[](int i) { return m_data[i]; } - constexpr T* begin() { return m_data; } - constexpr T* end() { return m_data+N; } - - constexpr operator ArrayView() { return {m_data, N}; } - constexpr operator ConstArrayView() const { return {m_data, N}; } - - 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) -{ - static_assert(sizeof...(Indices) == N, "size mismatch"); - return {{data[Indices]...}}; -} - -template -constexpr Array make_array(const T (&data)[N]) -{ - return make_array(data, std::make_index_sequence()); -} - -template -struct ConstexprVector -{ - using iterator = T*; - using const_iterator = const T*; - - constexpr ConstexprVector() : m_size{0} {} - constexpr ConstexprVector(std::initializer_list items) - : m_size{items.size()} - { - T* ptr = m_data; - for (auto& item : items) - *ptr++ = std::move(item); - } - - constexpr bool empty() const { return m_size == 0; } - constexpr size_t size() const { return m_size; } - - constexpr void resize(size_t n, const T& val = {}) - { - if (n >= capacity) - throw "capacity exceeded"; - for (int i = m_size; i < n; ++i) - m_data[i] = val; - m_size = n; - kak_assert(this->size() == m_size); // check for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79520 - } - - constexpr T& operator[](size_t i) { return m_data[i]; } - constexpr const T& operator[](size_t i) const { return m_data[i]; } - - constexpr iterator begin() { return m_data; } - constexpr iterator end() { return m_data + m_size; } - - constexpr const_iterator begin() const { return m_data; } - constexpr const_iterator end() const { return m_data + m_size; } - - size_t m_size; - T m_data[capacity] = {}; -}; - -} - -#endif // constexpr_utils_hh_INCLUDED diff --git a/src/debug.hh b/src/debug.hh index ec010460..723bbb9e 100644 --- a/src/debug.hh +++ b/src/debug.hh @@ -1,7 +1,7 @@ #ifndef debug_hh_INCLUDED #define debug_hh_INCLUDED -#include "constexpr_utils.hh" +#include "array.hh" #include "enum.hh" #include "flags.hh" diff --git a/src/file.hh b/src/file.hh index 9411fd78..ead88c43 100644 --- a/src/file.hh +++ b/src/file.hh @@ -6,7 +6,7 @@ #include "meta.hh" #include "string.hh" #include "units.hh" -#include "constexpr_utils.hh" +#include "array.hh" #include "vector.hh" #include diff --git a/src/hook_manager.hh b/src/hook_manager.hh index 114deefd..ee1adafb 100644 --- a/src/hook_manager.hh +++ b/src/hook_manager.hh @@ -6,7 +6,7 @@ #include "safe_ptr.hh" #include "meta.hh" #include "enum.hh" -#include "constexpr_utils.hh" +#include "array.hh" #include diff --git a/src/input_handler.hh b/src/input_handler.hh index fa7c91b1..54c5fd5b 100644 --- a/src/input_handler.hh +++ b/src/input_handler.hh @@ -2,7 +2,7 @@ #define input_handler_hh_INCLUDED #include "completion.hh" -#include "constexpr_utils.hh" +#include "array.hh" #include "context.hh" #include "env_vars.hh" #include "enum.hh" diff --git a/src/option.hh b/src/option.hh index b6edca0c..7e29deb7 100644 --- a/src/option.hh +++ b/src/option.hh @@ -4,7 +4,7 @@ #include "enum.hh" #include "meta.hh" #include "vector.hh" -#include "constexpr_utils.hh" +#include "array.hh" namespace Kakoune { diff --git a/src/ranges.hh b/src/ranges.hh index 1b6f8869..af13d6f8 100644 --- a/src/ranges.hh +++ b/src/ranges.hh @@ -6,7 +6,7 @@ #include #include -#include "constexpr_utils.hh" +#include "array.hh" namespace Kakoune { diff --git a/src/selectors.hh b/src/selectors.hh index e947250f..e132d897 100644 --- a/src/selectors.hh +++ b/src/selectors.hh @@ -6,7 +6,7 @@ #include "meta.hh" #include "unicode.hh" #include "vector.hh" -#include "constexpr_utils.hh" +#include "array.hh" namespace Kakoune { diff --git a/src/string_utils.hh b/src/string_utils.hh index 7c115269..559a6867 100644 --- a/src/string_utils.hh +++ b/src/string_utils.hh @@ -7,7 +7,7 @@ #include "optional.hh" #include "utils.hh" #include "format.hh" -#include "constexpr_utils.hh" +#include "array.hh" namespace Kakoune { -- cgit v1.2.3 From 288db58d20f41a4a72a89024482157445373a596 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Thu, 15 Aug 2024 12:46:18 +1000 Subject: Remove some more unnecessary includes --- src/memory.hh | 1 - src/ref_ptr.hh | 4 +--- src/unicode.hh | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) (limited to 'src') diff --git a/src/memory.hh b/src/memory.hh index 8eff2d54..da1ca597 100644 --- a/src/memory.hh +++ b/src/memory.hh @@ -3,7 +3,6 @@ #include #include -#include #include "assert.hh" #include "meta.hh" diff --git a/src/ref_ptr.hh b/src/ref_ptr.hh index 4b576039..fcbd6a71 100644 --- a/src/ref_ptr.hh +++ b/src/ref_ptr.hh @@ -1,8 +1,6 @@ #ifndef ref_ptr_hh_INCLUDED #define ref_ptr_hh_INCLUDED -#include - namespace Kakoune { @@ -34,7 +32,7 @@ struct RefPtr ~RefPtr() noexcept { release(); } RefPtr(const RefPtr& other) : m_ptr(other.m_ptr) { acquire(); } RefPtr(RefPtr&& other) - noexcept(noexcept(std::declval().moved(nullptr))) + noexcept(noexcept(moved(nullptr))) : m_ptr(other.m_ptr) { other.m_ptr = nullptr; moved(&other); } RefPtr& operator=(const RefPtr& other) diff --git a/src/unicode.hh b/src/unicode.hh index 5ce63f4b..d655d155 100644 --- a/src/unicode.hh +++ b/src/unicode.hh @@ -2,7 +2,6 @@ #define unicode_hh_INCLUDED #include -#include #include "array_view.hh" #include "units.hh" -- cgit v1.2.3 From 221a538b452886a659f436c69243a66d21ae39f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Arrufat?= Date: Thu, 15 Aug 2024 23:19:24 +0900 Subject: Add double underline in main version notes --- src/main.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/main.cc b/src/main.cc index f9890eed..fc719519 100644 --- a/src/main.cc +++ b/src/main.cc @@ -48,6 +48,7 @@ struct { } constexpr version_notes[] = { { 0, "» kak_* appearing in shell arguments will be added to the environment\n" + "» {+U}double underline{} support\n" }, { 20240518, "» Fix tests failing on some platforms\n" -- cgit v1.2.3 From 64ed046e5a841520506e1954ff0bd756ea112d94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Arrufat?= Date: Fri, 16 Aug 2024 08:49:19 +0900 Subject: include headers cleanup --- src/alias_registry.cc | 1 - src/assert.cc | 1 - src/backtrace.cc | 1 - src/client.cc | 1 - src/client_manager.cc | 1 - src/command_manager.hh | 2 -- src/commands.cc | 1 - src/completion.hh | 1 - src/context.hh | 1 - src/debug.hh | 1 - src/display_buffer.cc | 1 - src/face_registry.hh | 1 - src/file.cc | 2 -- src/highlighter.cc | 1 + src/highlighter.hh | 2 -- src/highlighter_group.cc | 4 +++- src/highlighters.cc | 1 - src/hook_manager.cc | 1 - src/hook_manager.hh | 1 - src/input_handler.cc | 4 +--- src/insert_completer.cc | 1 - src/keymap_manager.cc | 3 --- src/keymap_manager.hh | 3 --- src/keys.cc | 1 - src/main.cc | 3 --- src/memory.hh | 1 - src/normal.cc | 2 -- src/option.hh | 4 ++-- src/option_manager.hh | 2 +- src/parameters_parser.hh | 1 - src/profile.hh | 3 ++- src/range.hh | 2 ++ src/regex_impl.cc | 1 - src/safe_ptr.hh | 1 - src/selection.cc | 1 - src/shared_string.hh | 1 - src/string_utils.cc | 2 -- src/string_utils.hh | 1 - src/terminal_ui.cc | 2 +- src/terminal_ui.hh | 1 - src/unique_descriptor.hh | 2 ++ src/units.hh | 1 - src/utf8.hh | 2 -- src/value.hh | 1 - src/window.cc | 1 - src/word_db.cc | 2 -- 46 files changed, 15 insertions(+), 59 deletions(-) (limited to 'src') diff --git a/src/alias_registry.cc b/src/alias_registry.cc index 96f2e4ef..4263c317 100644 --- a/src/alias_registry.cc +++ b/src/alias_registry.cc @@ -1,7 +1,6 @@ #include "alias_registry.hh" #include "command_manager.hh" -#include "ranges.hh" namespace Kakoune { diff --git a/src/assert.cc b/src/assert.cc index 6e5fc512..c27fb1e8 100644 --- a/src/assert.cc +++ b/src/assert.cc @@ -8,7 +8,6 @@ #include #include -#include namespace Kakoune { diff --git a/src/backtrace.cc b/src/backtrace.cc index 04b772ad..9c1df97a 100644 --- a/src/backtrace.cc +++ b/src/backtrace.cc @@ -1,7 +1,6 @@ #include "backtrace.hh" #include "string.hh" -#include "format.hh" #if defined(__GLIBC__) || defined(__APPLE__) # include diff --git a/src/client.cc b/src/client.cc index 77fb7dcc..80529ed3 100644 --- a/src/client.cc +++ b/src/client.cc @@ -2,7 +2,6 @@ #include "face_registry.hh" #include "context.hh" -#include "buffer_manager.hh" #include "buffer_utils.hh" #include "debug.hh" #include "file.hh" diff --git a/src/client_manager.cc b/src/client_manager.cc index 0ad5392f..3c8a7b6e 100644 --- a/src/client_manager.cc +++ b/src/client_manager.cc @@ -2,7 +2,6 @@ #include "buffer_manager.hh" #include "command_manager.hh" -#include "event_manager.hh" #include "face_registry.hh" #include "file.hh" #include "ranges.hh" diff --git a/src/command_manager.hh b/src/command_manager.hh index 878ca129..c0a2e878 100644 --- a/src/command_manager.hh +++ b/src/command_manager.hh @@ -1,7 +1,6 @@ #ifndef command_manager_hh_INCLUDED #define command_manager_hh_INCLUDED -#include "coord.hh" #include "completion.hh" #include "array_view.hh" #include "shell_manager.hh" @@ -12,7 +11,6 @@ #include "hash_map.hh" #include -#include namespace Kakoune { diff --git a/src/commands.cc b/src/commands.cc index 7c6fdb94..1d3f5a50 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -32,7 +32,6 @@ #include "user_interface.hh" #include "window.hh" -#include #include #include diff --git a/src/completion.hh b/src/completion.hh index e9321d5a..78024e19 100644 --- a/src/completion.hh +++ b/src/completion.hh @@ -1,7 +1,6 @@ #ifndef completion_hh_INCLUDED #define completion_hh_INCLUDED -#include #include #include "units.hh" diff --git a/src/context.hh b/src/context.hh index e1c0f657..ce17c3f7 100644 --- a/src/context.hh +++ b/src/context.hh @@ -4,7 +4,6 @@ #include "selection.hh" #include "optional.hh" #include "utils.hh" -#include "flags.hh" #include diff --git a/src/debug.hh b/src/debug.hh index ec010460..aa8b0f61 100644 --- a/src/debug.hh +++ b/src/debug.hh @@ -3,7 +3,6 @@ #include "constexpr_utils.hh" #include "enum.hh" -#include "flags.hh" namespace Kakoune { diff --git a/src/display_buffer.cc b/src/display_buffer.cc index 26c58754..bc934202 100644 --- a/src/display_buffer.cc +++ b/src/display_buffer.cc @@ -2,7 +2,6 @@ #include "assert.hh" #include "buffer.hh" -#include "buffer_utils.hh" #include "face_registry.hh" #include "utf8.hh" diff --git a/src/face_registry.hh b/src/face_registry.hh index 88e52980..110e9769 100644 --- a/src/face_registry.hh +++ b/src/face_registry.hh @@ -2,7 +2,6 @@ #define face_registry_hh_INCLUDED #include "face.hh" -#include "utils.hh" #include "hash_map.hh" #include "ranges.hh" #include "string.hh" diff --git a/src/file.cc b/src/file.cc index ca2d2834..ac19a089 100644 --- a/src/file.cc +++ b/src/file.cc @@ -4,12 +4,10 @@ #include "buffer.hh" #include "exception.hh" #include "flags.hh" -#include "option_types.hh" #include "event_manager.hh" #include "ranked_match.hh" #include "regex.hh" #include "string.hh" -#include "unicode.hh" #include #include diff --git a/src/highlighter.cc b/src/highlighter.cc index c6b1a13d..7a6b2155 100644 --- a/src/highlighter.cc +++ b/src/highlighter.cc @@ -1,6 +1,7 @@ #include "highlighter.hh" #include "debug.hh" +#include "flags.hh" namespace Kakoune { diff --git a/src/highlighter.hh b/src/highlighter.hh index c1070d9a..73520c53 100644 --- a/src/highlighter.hh +++ b/src/highlighter.hh @@ -3,8 +3,6 @@ #include "coord.hh" #include "completion.hh" -#include "exception.hh" -#include "flags.hh" #include "range.hh" #include "hash_map.hh" #include "array_view.hh" diff --git a/src/highlighter_group.cc b/src/highlighter_group.cc index 7802df94..57bbd7d2 100644 --- a/src/highlighter_group.cc +++ b/src/highlighter_group.cc @@ -1,7 +1,9 @@ #include "highlighter_group.hh" -#include "ranges.hh" +#include "flags.hh" #include "format.hh" +#include "ranges.hh" + namespace Kakoune { diff --git a/src/highlighters.cc b/src/highlighters.cc index 4b18a447..cccccffd 100644 --- a/src/highlighters.cc +++ b/src/highlighters.cc @@ -6,7 +6,6 @@ #include "changes.hh" #include "command_manager.hh" #include "context.hh" -#include "clock.hh" #include "display_buffer.hh" #include "face_registry.hh" #include "highlighter_group.hh" diff --git a/src/hook_manager.cc b/src/hook_manager.cc index 00b38677..ae3acf65 100644 --- a/src/hook_manager.cc +++ b/src/hook_manager.cc @@ -1,7 +1,6 @@ #include "hook_manager.hh" #include "debug.hh" -#include "clock.hh" #include "command_manager.hh" #include "context.hh" #include "display_buffer.hh" diff --git a/src/hook_manager.hh b/src/hook_manager.hh index 114deefd..f8e17d0b 100644 --- a/src/hook_manager.hh +++ b/src/hook_manager.hh @@ -1,7 +1,6 @@ #ifndef hook_manager_hh_INCLUDED #define hook_manager_hh_INCLUDED -#include "hash_map.hh" #include "completion.hh" #include "safe_ptr.hh" #include "meta.hh" diff --git a/src/input_handler.cc b/src/input_handler.cc index 8ab88f20..aa43783e 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -1,6 +1,6 @@ #include "input_handler.hh" -#include "buffer_manager.hh" +#include "buffer.hh" #include "debug.hh" #include "command_manager.hh" #include "client.hh" @@ -11,9 +11,7 @@ #include "option_types.hh" #include "regex.hh" #include "register_manager.hh" -#include "hash_map.hh" #include "user_interface.hh" -#include "utf8.hh" #include "window.hh" #include "word_db.hh" diff --git a/src/insert_completer.cc b/src/insert_completer.cc index b369359a..1e83a47e 100644 --- a/src/insert_completer.cc +++ b/src/insert_completer.cc @@ -17,7 +17,6 @@ #include "utf8_iterator.hh" #include "user_interface.hh" -#include #include namespace Kakoune diff --git a/src/keymap_manager.cc b/src/keymap_manager.cc index 8894267a..1d05d50c 100644 --- a/src/keymap_manager.cc +++ b/src/keymap_manager.cc @@ -1,13 +1,10 @@ #include "keymap_manager.hh" -#include "array_view.hh" #include "assert.hh" #include "exception.hh" #include "format.hh" #include "ranges.hh" -#include - namespace Kakoune { diff --git a/src/keymap_manager.hh b/src/keymap_manager.hh index 4819be05..233ed08b 100644 --- a/src/keymap_manager.hh +++ b/src/keymap_manager.hh @@ -1,12 +1,9 @@ #ifndef keymap_manager_hh_INCLUDED #define keymap_manager_hh_INCLUDED -#include "array_view.hh" #include "keys.hh" -#include "hash.hh" #include "string.hh" #include "hash_map.hh" -#include "utils.hh" #include "vector.hh" namespace Kakoune diff --git a/src/keys.cc b/src/keys.cc index 30aeaca7..4170ce98 100644 --- a/src/keys.cc +++ b/src/keys.cc @@ -5,7 +5,6 @@ #include "string.hh" #include "unit_tests.hh" #include "utf8_iterator.hh" -#include "utils.hh" #include "format.hh" #include "string_utils.hh" diff --git a/src/main.cc b/src/main.cc index f9890eed..2e1c6d38 100644 --- a/src/main.cc +++ b/src/main.cc @@ -17,7 +17,6 @@ #include "terminal_ui.hh" #include "option_types.hh" #include "parameters_parser.hh" -#include "profile.hh" #include "ranges.hh" #include "regex.hh" #include "register_manager.hh" @@ -26,9 +25,7 @@ #include "shared_string.hh" #include "shell_manager.hh" #include "string.hh" -#include "unit_tests.hh" #include "window.hh" -#include "clock.hh" #include #include diff --git a/src/memory.hh b/src/memory.hh index 8eff2d54..da1ca597 100644 --- a/src/memory.hh +++ b/src/memory.hh @@ -3,7 +3,6 @@ #include #include -#include #include "assert.hh" #include "meta.hh" diff --git a/src/normal.cc b/src/normal.cc index 5a7c4e58..689137ef 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -4,9 +4,7 @@ #include "buffer_manager.hh" #include "buffer_utils.hh" #include "changes.hh" -#include "client_manager.hh" #include "command_manager.hh" -#include "commands.hh" #include "context.hh" #include "diff.hh" #include "enum.hh" diff --git a/src/option.hh b/src/option.hh index b6edca0c..a27fc256 100644 --- a/src/option.hh +++ b/src/option.hh @@ -1,10 +1,10 @@ #ifndef option_hh_INCLUDED #define option_hh_INCLUDED -#include "enum.hh" +#include "exception.hh" #include "meta.hh" +#include "string.hh" #include "vector.hh" -#include "constexpr_utils.hh" namespace Kakoune { diff --git a/src/option_manager.hh b/src/option_manager.hh index 480b589b..c36aeb6d 100644 --- a/src/option_manager.hh +++ b/src/option_manager.hh @@ -5,8 +5,8 @@ #include "exception.hh" #include "hash_map.hh" #include "option.hh" +#include "option_types.hh" #include "ranges.hh" -#include "utils.hh" #include "vector.hh" #include "format.hh" #include "string_utils.hh" diff --git a/src/parameters_parser.hh b/src/parameters_parser.hh index 7d26c3bb..f1ff8b73 100644 --- a/src/parameters_parser.hh +++ b/src/parameters_parser.hh @@ -6,7 +6,6 @@ #include "meta.hh" #include "array_view.hh" #include "optional.hh" -#include "flags.hh" #include "string.hh" #include "format.hh" diff --git a/src/profile.hh b/src/profile.hh index f107ebd3..6c121731 100644 --- a/src/profile.hh +++ b/src/profile.hh @@ -1,8 +1,9 @@ #ifndef profile_hh_INCLUDED #define profile_hh_INCLUDED -#include "option.hh" #include "clock.hh" +#include "context.hh" +#include "debug.hh" #include "option_manager.hh" namespace Kakoune diff --git a/src/range.hh b/src/range.hh index a36386f2..6e72ffba 100644 --- a/src/range.hh +++ b/src/range.hh @@ -1,6 +1,8 @@ #ifndef range_hh_INCLUDED #define range_hh_INCLUDED +#include + namespace Kakoune { diff --git a/src/regex_impl.cc b/src/regex_impl.cc index f6393b56..4b404cfa 100644 --- a/src/regex_impl.cc +++ b/src/regex_impl.cc @@ -1,6 +1,5 @@ #include "regex_impl.hh" -#include "exception.hh" #include "string.hh" #include "unicode.hh" #include "unit_tests.hh" diff --git a/src/safe_ptr.hh b/src/safe_ptr.hh index 216a14ff..d08a9a79 100644 --- a/src/safe_ptr.hh +++ b/src/safe_ptr.hh @@ -3,7 +3,6 @@ // #define SAFE_PTR_TRACK_CALLSTACKS -#include "assert.hh" #include "ref_ptr.hh" #ifdef SAFE_PTR_TRACK_CALLSTACKS diff --git a/src/selection.cc b/src/selection.cc index 03dd4721..99b21c3e 100644 --- a/src/selection.cc +++ b/src/selection.cc @@ -2,7 +2,6 @@ #include "buffer_utils.hh" #include "changes.hh" -#include "utf8.hh" namespace Kakoune { diff --git a/src/shared_string.hh b/src/shared_string.hh index 78e9fef4..79c34830 100644 --- a/src/shared_string.hh +++ b/src/shared_string.hh @@ -6,7 +6,6 @@ #include "utils.hh" #include "hash_map.hh" -#include #include namespace Kakoune diff --git a/src/string_utils.cc b/src/string_utils.cc index b6e06af2..c4d093bc 100644 --- a/src/string_utils.cc +++ b/src/string_utils.cc @@ -4,8 +4,6 @@ #include "utf8_iterator.hh" #include "unit_tests.hh" -#include - namespace Kakoune { diff --git a/src/string_utils.hh b/src/string_utils.hh index 24da0111..105c22f8 100644 --- a/src/string_utils.hh +++ b/src/string_utils.hh @@ -5,7 +5,6 @@ #include "enum.hh" #include "vector.hh" #include "optional.hh" -#include "utils.hh" #include "format.hh" #include "ranges.hh" diff --git a/src/terminal_ui.cc b/src/terminal_ui.cc index 1ece515b..3dfdba90 100644 --- a/src/terminal_ui.cc +++ b/src/terminal_ui.cc @@ -1,6 +1,5 @@ #include "terminal_ui.hh" -#include "buffer_utils.hh" #include "display_buffer.hh" #include "event_manager.hh" #include "exception.hh" @@ -9,6 +8,7 @@ #include "ranges.hh" #include "format.hh" #include "diff.hh" +#include "string_utils.hh" #include diff --git a/src/terminal_ui.hh b/src/terminal_ui.hh index 85583a1d..64e3bfcf 100644 --- a/src/terminal_ui.hh +++ b/src/terminal_ui.hh @@ -6,7 +6,6 @@ #include "display_buffer.hh" #include "event_manager.hh" #include "face.hh" -#include "hash_map.hh" #include "optional.hh" #include "string.hh" #include "user_interface.hh" diff --git a/src/unique_descriptor.hh b/src/unique_descriptor.hh index c099c17e..0d925ef5 100644 --- a/src/unique_descriptor.hh +++ b/src/unique_descriptor.hh @@ -1,6 +1,8 @@ #ifndef fd_hh_INCLUDED #define fd_hh_INCLUDED +#include + namespace Kakoune { diff --git a/src/units.hh b/src/units.hh index 3bdfe253..ff4ed882 100644 --- a/src/units.hh +++ b/src/units.hh @@ -5,7 +5,6 @@ #include "hash.hh" #include -#include namespace Kakoune { diff --git a/src/utf8.hh b/src/utf8.hh index 6ef2f63d..0ba8bdef 100644 --- a/src/utf8.hh +++ b/src/utf8.hh @@ -6,8 +6,6 @@ #include "units.hh" #include "optional.hh" -#include - namespace Kakoune { diff --git a/src/value.hh b/src/value.hh index 2b9e0d22..f38e4fa2 100644 --- a/src/value.hh +++ b/src/value.hh @@ -2,7 +2,6 @@ #define value_hh_INCLUDED #include "hash_map.hh" -#include "units.hh" #include "meta.hh" #include diff --git a/src/window.cc b/src/window.cc index e992af01..c5fc44db 100644 --- a/src/window.cc +++ b/src/window.cc @@ -3,7 +3,6 @@ #include "assert.hh" #include "buffer.hh" #include "buffer_utils.hh" -#include "clock.hh" #include "context.hh" #include "highlighter.hh" #include "hook_manager.hh" diff --git a/src/word_db.cc b/src/word_db.cc index 755304ca..0a1873e7 100644 --- a/src/word_db.cc +++ b/src/word_db.cc @@ -2,9 +2,7 @@ #include "buffer.hh" #include "line_modification.hh" -#include "option_types.hh" #include "unit_tests.hh" -#include "utils.hh" #include "value.hh" namespace Kakoune -- cgit v1.2.3 From 59ca840a6570edd4d11bdf2da17209ead9bb6f3d Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sat, 17 Aug 2024 08:13:07 +0200 Subject: Decode kitty keyboard protocol's numlock keys Fixes numlock input on Alacritty. Closes #5214 --- src/terminal_ui.cc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src') diff --git a/src/terminal_ui.cc b/src/terminal_ui.cc index 1ece515b..2b0e7207 100644 --- a/src/terminal_ui.cc +++ b/src/terminal_ui.cc @@ -882,7 +882,23 @@ Optional TerminalUI::get_next_key() switch (params[0][0]) { // Treat numpad keys the same as their non-numpad counterparts. Could add a numpad modifier here. + case 57399: key = '0'; break; + case 57400: key = '1'; break; + case 57401: key = '2'; break; + case 57402: key = '3'; break; + case 57403: key = '4'; break; + case 57404: key = '5'; break; + case 57405: key = '6'; break; + case 57406: key = '7'; break; + case 57407: key = '8'; break; + case 57408: key = '9'; break; + case 57409: key = '.'; break; + case 57410: key = '/'; break; + case 57411: key = '*'; break; + case 57412: key = '-'; break; + case 57413: key = '+'; break; case 57414: key = Key::Return; break; + case 57415: key = '='; break; case 57417: key = Key::Left; break; case 57418: key = Key::Right; break; case 57419: key = Key::Up; break; -- cgit v1.2.3 From 2c923ba8272d455acd279951fee84bc2f6029051 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sat, 17 Aug 2024 08:13:08 +0200 Subject: Decode XTerm's formatOtherKeys=0 encoding When typing , XTerm sends \e[27;2;13~ Only when formatOtherKeys is set to 1 by the user, XTerm will send an equivalent CSI u encoding. --- src/terminal_ui.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/terminal_ui.cc b/src/terminal_ui.cc index 2b0e7207..fb8f1018 100644 --- a/src/terminal_ui.cc +++ b/src/terminal_ui.cc @@ -858,6 +858,8 @@ Optional TerminalUI::get_next_key() return masked_key(Key::F11 + params[0][0] - 23); case 25: case 26: return Key{Key::Modifiers::Shift, Key::F3 + params[0][0] - 25}; // rxvt style + case 27: + return masked_key(convert(static_cast(params[2][0]))); case 28: case 29: return Key{Key::Modifiers::Shift, Key::F5 + params[0][0] - 28}; // rxvt style case 31: case 32: -- cgit v1.2.3 From f4d8a831ff84eaf9280bf000133c661d4359bfa3 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sat, 17 Aug 2024 08:13:09 +0200 Subject: Don't interpret the \n input byte as We set both ICRNL and INLCR, so there is no translation of \r to \n and vice versa. This means that when the user presses the Enter key, we always receive \r. So a "\n" input byte can realistically only be sent by (or perhaps ), so we can interpret it as that. This intentionally breaks users that rely on doing the same thing as on terminals that fail to disambiguate those two (for example gnome-terminal). This seems unavoidable; better teach them to map separately sooner rather than later. --- src/terminal_ui.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/terminal_ui.cc b/src/terminal_ui.cc index fb8f1018..e5d2b56c 100644 --- a/src/terminal_ui.cc +++ b/src/terminal_ui.cc @@ -703,7 +703,7 @@ Optional TerminalUI::get_next_key() static constexpr auto control = [](char c) { return c & 037; }; auto convert = [this](Codepoint c) -> Codepoint { - if (c == control('m') or c == control('j')) + if (c == control('m')) return Key::Return; if (c == control('i')) return Key::Tab; -- cgit v1.2.3 From 193d4ba0234d7ab8e8afc2e6bfcbaf7d3d228491 Mon Sep 17 00:00:00 2001 From: Chris Webb Date: Fri, 23 Aug 2024 09:18:52 +0100 Subject: Add back for wcwidth in src/unicode.hh On a musl system with clang 18.1.8 linking against libc++, 64ed046e breaks the build with src/unicode.hh:105:24: error: use of undeclared identifier 'wcwidth' 105 | const auto width = wcwidth((wchar_t)c); though this doesn't happen on the same system with gcc 14.2.0 linking against libstdc++. Include again so wcwidth() is properly defined. --- src/unicode.hh | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/unicode.hh b/src/unicode.hh index d655d155..5ce63f4b 100644 --- a/src/unicode.hh +++ b/src/unicode.hh @@ -2,6 +2,7 @@ #define unicode_hh_INCLUDED #include +#include #include "array_view.hh" #include "units.hh" -- cgit v1.2.3 From 202747e68896aebbe38cc160391629e020f0c2a1 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Mon, 26 Aug 2024 20:23:29 +1000 Subject: Fix includes for debug build Looks like we've been over eager with removing unused includes and did not realize they were only unused in optimized builds. --- src/json.cc | 1 + src/main.cc | 2 ++ src/safe_ptr.hh | 1 + 3 files changed, 4 insertions(+) (limited to 'src') diff --git a/src/json.cc b/src/json.cc index 93ffdcc4..6b297dff 100644 --- a/src/json.cc +++ b/src/json.cc @@ -4,6 +4,7 @@ #include "string_utils.hh" #include "unit_tests.hh" #include "utils.hh" +#include "ranges.hh" #include #include diff --git a/src/main.cc b/src/main.cc index caf35fe0..69a71631 100644 --- a/src/main.cc +++ b/src/main.cc @@ -17,6 +17,7 @@ #include "terminal_ui.hh" #include "option_types.hh" #include "parameters_parser.hh" +#include "profile.hh" #include "ranges.hh" #include "regex.hh" #include "register_manager.hh" @@ -25,6 +26,7 @@ #include "shared_string.hh" #include "shell_manager.hh" #include "string.hh" +#include "unit_tests.hh" #include "window.hh" #include diff --git a/src/safe_ptr.hh b/src/safe_ptr.hh index d08a9a79..216a14ff 100644 --- a/src/safe_ptr.hh +++ b/src/safe_ptr.hh @@ -3,6 +3,7 @@ // #define SAFE_PTR_TRACK_CALLSTACKS +#include "assert.hh" #include "ref_ptr.hh" #ifdef SAFE_PTR_TRACK_CALLSTACKS -- cgit v1.2.3 From 9275d965a6952d44035fd0502ee0d3991352c460 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Mon, 26 Aug 2024 21:00:08 +1000 Subject: Do not gather full input data in a single string when piping Refactor ShellManager and pipe to feed lines from the buffer directly, this should reduce memory use when piping big chunks of buffers. The pipe output is still provided as a single big buffer. --- src/command_manager.cc | 3 ++- src/commands.cc | 2 +- src/normal.cc | 35 +++++++++++++++++++++++------------ src/shell_manager.cc | 14 +++++++++----- src/shell_manager.hh | 12 +++++++++++- 5 files changed, 46 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/command_manager.cc b/src/command_manager.cc index 3e44ab1e..fd32f93c 100644 --- a/src/command_manager.cc +++ b/src/command_manager.cc @@ -350,7 +350,8 @@ void expand_token(Token&& token, const Context& context, const ShellContext& she case Token::Type::ShellExpand: { auto str = ShellManager::instance().eval( - content, context, {}, ShellManager::Flags::WaitForStdout, + content, context, StringView{}, + ShellManager::Flags::WaitForStdout, shell_context).first; if (not str.empty() and str.back() == '\n') diff --git a/src/commands.cc b/src/commands.cc index 1d3f5a50..78193e57 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -277,7 +277,7 @@ struct ShellScriptCompleter { { "token_to_complete", to_string(token_to_complete) }, { "pos_in_token", to_string(pos_in_token) } } }; - String output = ShellManager::instance().eval(m_shell_script, context, {}, + String output = ShellManager::instance().eval(m_shell_script, context, StringView{}, ShellManager::Flags::WaitForStdout, shell_context).first; CandidateList candidates; diff --git a/src/normal.cc b/src/normal.cc index 689137ef..056f11de 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -535,9 +535,8 @@ void command(Context& context, NormalParams params) command(context, std::move(env_vars), params.reg); } -BufferCoord apply_diff(Buffer& buffer, BufferCoord pos, StringView before, StringView after) +BufferCoord apply_diff(Buffer& buffer, BufferCoord pos, ArrayView lines_before, StringView after) { - const auto lines_before = before | split_after('\n') | gather>(); const auto lines_after = after | split_after('\n') | gather>(); auto byte_count = [](auto&& lines, int first, int count) { @@ -601,26 +600,38 @@ void pipe(Context& context, NormalParams params) SelectionList selections = context.selections(); for (auto& sel : selections) { - const auto beg = changes_tracker.get_new_coord_tolerant(sel.min()); - const auto end = changes_tracker.get_new_coord_tolerant(sel.max()); + const auto first = changes_tracker.get_new_coord_tolerant(sel.min()); + const auto last = changes_tracker.get_new_coord_tolerant(sel.max()); + + Vector in_lines; + for (auto line = first.line; line <= last.line; ++line) + { + auto content = buffer[line]; + if (line == last.line) + content = content.substr(0, last.column + utf8::codepoint_size(content[last.column])); + if (line == first.line) + content = content.substr(first.column); + in_lines.push_back(content); + } - String in = buffer.string(beg, buffer.char_next(end)); // Needed in case we read selections inside the cmdline - context.selections_write_only().set({keep_direction(Selection{beg, end}, sel)}, 0); + context.selections_write_only().set({keep_direction(Selection{first, last}, sel)}, 0); String out = ShellManager::instance().eval( - cmdline, context, in, - ShellManager::Flags::WaitForStdout).first; + cmdline, context, + [it = in_lines.begin(), end = in_lines.end()]() mutable { + return (it != end) ? *it++ : StringView{}; + }, ShellManager::Flags::WaitForStdout).first; - if (in.back() != '\n' and not out.empty() and out.back() == '\n') + if (in_lines.back().back() != '\n' and not out.empty() and out.back() == '\n') out.resize(out.length()-1, 0); - auto new_end = apply_diff(buffer, beg, in, out); - if (new_end != beg) + auto new_end = apply_diff(buffer, first, in_lines, out); + if (new_end != first) { auto& min = sel.min(); auto& max = sel.max(); - min = beg; + min = first; max = buffer.char_prev(new_end); } else diff --git a/src/shell_manager.cc b/src/shell_manager.cc index 7346f2c1..6b656191 100644 --- a/src/shell_manager.cc +++ b/src/shell_manager.cc @@ -197,18 +197,22 @@ FDWatcher make_reader(int fd, String& contents, OnClose&& on_close) }}; } -FDWatcher make_pipe_writer(UniqueFd& fd, StringView contents) +FDWatcher make_pipe_writer(UniqueFd& fd, const FunctionRef& generator) { int flags = fcntl((int)fd, F_GETFL, 0); fcntl((int)fd, F_SETFL, flags | O_NONBLOCK); return {(int)fd, FdEvents::Write, EventMode::Urgent, - [contents, &fd](FDWatcher& watcher, FdEvents, EventMode) mutable { + [&generator, &fd, contents=generator()](FDWatcher& watcher, FdEvents, EventMode) mutable { while (fd_writable((int)fd)) { ssize_t size = ::write((int)fd, contents.begin(), (size_t)contents.length()); if (size > 0) + { contents = contents.substr(ByteCount{(int)size}); + if (contents.empty()) + contents = generator(); + } if (size == -1 and (errno == EAGAIN or errno == EWOULDBLOCK)) return; if (size < 0 or contents.empty()) @@ -263,7 +267,7 @@ struct CommandFifos } std::pair ShellManager::eval( - StringView cmdline, const Context& context, StringView input, + StringView cmdline, const Context& context, FunctionRef input_generator, Flags flags, const ShellContext& shell_context) { const DebugFlags debug_flags = context.options()["debug"].get(); @@ -290,13 +294,13 @@ std::pair ShellManager::eval( }); auto spawn_time = profile ? Clock::now() : Clock::time_point{}; - auto shell = spawn_shell(m_shell.c_str(), cmdline, shell_context.params, kak_env, not input.empty()); + auto shell = spawn_shell(m_shell.c_str(), cmdline, shell_context.params, kak_env, true); auto wait_time = Clock::now(); String stdout_contents, stderr_contents; auto stdout_reader = make_reader((int)shell.out, stdout_contents, [&](bool){ shell.out.close(); }); auto stderr_reader = make_reader((int)shell.err, stderr_contents, [&](bool){ shell.err.close(); }); - auto stdin_writer = make_pipe_writer(shell.in, input); + auto stdin_writer = make_pipe_writer(shell.in, input_generator); // block SIGCHLD to make sure we wont receive it before // our call to pselect, that will end up blocking indefinitly. diff --git a/src/shell_manager.hh b/src/shell_manager.hh index f6ef38a4..3dc62e0a 100644 --- a/src/shell_manager.hh +++ b/src/shell_manager.hh @@ -58,10 +58,20 @@ public: friend constexpr bool with_bit_ops(Meta::Type) { return true; } std::pair eval(StringView cmdline, const Context& context, - StringView input = {}, + FunctionRef stdin_generator, Flags flags = Flags::WaitForStdout, const ShellContext& shell_context = {}); + std::pair eval(StringView cmdline, const Context& context, + StringView stdin, + Flags flags = Flags::WaitForStdout, + const ShellContext& shell_context = {}) + { + return eval(cmdline, context, + [stdin]() mutable { return std::exchange(stdin, StringView{}); }, + flags, shell_context); + } + Shell spawn(StringView cmdline, const Context& context, bool open_stdin, -- cgit v1.2.3 From 6e5bc9dd6c477a71020dcbe6c7a387673825d941 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Wed, 28 Aug 2024 15:47:27 +0200 Subject: Fix use-after-free InsertCompletionHide touches used register Before performing the insertion, InsertCompleter::insert calls try_accept() to accept any selected completion candidate. If there is one, we fire InsertCompletionHide. If that one modifies the register used by , the inserted StringViews will be dangling. Fix this by running try_insert first, and read from the register later. Note that we call try_accept() twice but that's fine. It would probably make more sense to copy the register before calling insert() but I don't think it matters. Closes #5220 --- src/input_handler.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/input_handler.cc b/src/input_handler.cc index aa43783e..85a8fbc1 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -15,6 +15,7 @@ #include "window.hh" #include "word_db.hh" +#include #include #include @@ -1310,7 +1311,7 @@ public: auto cp = key.codepoint(); if (not cp or key == Key::Escape) return; - insert(RegisterManager::instance()[*cp].get(context())); + insert([&] { return RegisterManager::instance()[*cp].get(context()); }); }, "enter register name", register_doc.str()); update_completions = false; } @@ -1430,6 +1431,13 @@ private: }, false); } + template + void insert(Func&& lazy_strings) + { + m_completer.try_accept(); + insert(std::forward(lazy_strings)()); + } + void insert(Codepoint key) { String str{key}; -- cgit v1.2.3 From c1ce1d70146dd4b3cda76adc98bfac90da55d18c Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Mon, 2 Sep 2024 20:35:07 +1000 Subject: Explicitely call try_accept on InsertCompleter Calling it as part of the insert method was error prone and often led to slightly surprising behaviour, such as the hiding the menu on . --- src/input_handler.cc | 17 ++++++++--------- src/insert_completer.cc | 4 ++-- src/insert_completer.hh | 3 ++- 3 files changed, 12 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/input_handler.cc b/src/input_handler.cc index 85a8fbc1..0693bc43 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -1303,15 +1303,19 @@ public: selections.sort_and_merge_overlapping(); } else if (auto cp = key.codepoint()) + { + m_completer.try_accept(); insert(*cp); + } else if (key == ctrl('r')) { + m_completer.try_accept(); on_next_key_with_autoinfo(context(), "register", KeymapMode::None, [this](Key key, Context&) { auto cp = key.codepoint(); if (not cp or key == Key::Escape) return; - insert([&] { return RegisterManager::instance()[*cp].get(context()); }); + insert(RegisterManager::instance()[*cp].get(context())); }, "enter register name", register_doc.str()); update_completions = false; } @@ -1359,6 +1363,7 @@ public: } else if (key == ctrl('v')) { + m_completer.try_accept(); on_next_key_with_autoinfo(context(), "raw-insert", KeymapMode::None, [this, transient](Key key, Context&) { if (auto cp = get_raw_codepoint(key)) @@ -1387,6 +1392,7 @@ public: void paste(StringView content) override { + m_completer.try_accept(); insert(ConstArrayView{content}); m_idle_timer.set_next_date(Clock::now() + get_idle_timeout(context())); } @@ -1424,20 +1430,13 @@ private: template void insert(ConstArrayView strings) { - m_completer.try_accept(); + kak_assert(not m_completer.has_candidate_selected()); context().selections().for_each([strings, &buffer=context().buffer()] (size_t index, Selection& sel) { Kakoune::insert(buffer, sel, sel.cursor(), strings[std::min(strings.size()-1, index)]); }, false); } - template - void insert(Func&& lazy_strings) - { - m_completer.try_accept(); - insert(std::forward(lazy_strings)()); - } - void insert(Codepoint key) { String str{key}; diff --git a/src/insert_completer.cc b/src/insert_completer.cc index 1e83a47e..49bbd4ca 100644 --- a/src/insert_completer.cc +++ b/src/insert_completer.cc @@ -481,12 +481,12 @@ auto& get_last(BufferRange& range) { return range.end; } bool InsertCompleter::has_candidate_selected() const { - return m_current_candidate >= 0 and m_current_candidate < m_completions.candidates.size() - 1; + return m_completions.is_valid() and m_current_candidate >= 0 and m_current_candidate < m_completions.candidates.size() - 1; } void InsertCompleter::try_accept() { - if (m_completions.is_valid() and has_candidate_selected()) + if (has_candidate_selected()) reset(); } diff --git a/src/insert_completer.hh b/src/insert_completer.hh index c624639d..713cdedb 100644 --- a/src/insert_completer.hh +++ b/src/insert_completer.hh @@ -90,6 +90,8 @@ public: void explicit_line_buffer_complete(); void explicit_line_all_complete(); + bool has_candidate_selected() const; + private: bool setup_ifn(); @@ -98,7 +100,6 @@ private: void on_option_changed(const Option& opt) override; void menu_show(); - bool has_candidate_selected() const; Context& m_context; OptionManager& m_options; -- cgit v1.2.3 From 7e05dc8d2e0b4005176ccb8a52f77b11a40e17aa Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Sun, 8 Sep 2024 21:53:49 +1000 Subject: Add terminal_title terminal ui_option to control the title Use a separate option from terminal_set_title for simplicity. Fixes #2217 Closes #4265 --- src/main.cc | 1 + src/terminal_ui.cc | 16 ++++++++++------ src/terminal_ui.hh | 1 + 3 files changed, 12 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/main.cc b/src/main.cc index 69a71631..09c9b718 100644 --- a/src/main.cc +++ b/src/main.cc @@ -595,6 +595,7 @@ void register_options() " terminal_assistant clippy|cat|dilbert|none|off\n" " terminal_status_on_top bool\n" " terminal_set_title bool\n" + " terminal_title str\n" " terminal_enable_mouse bool\n" " terminal_synchronized bool\n" " terminal_wheel_scroll_amount int\n" diff --git a/src/terminal_ui.cc b/src/terminal_ui.cc index bcb0cde5..672626e4 100644 --- a/src/terminal_ui.cc +++ b/src/terminal_ui.cc @@ -609,16 +609,19 @@ void TerminalUI::draw_status(const DisplayLine& status_line, if (m_set_title) { Writer writer{STDOUT_FILENO}; - constexpr char suffix[] = " - Kakoune\007"; writer.write("\033]2;"); - // Fill title escape sequence buffer, removing non ascii characters - for (auto& atom : mode_line) - { - const auto str = atom.content(); + auto write_escaped = [&](StringView str) { for (auto it = str.begin(), end = str.end(); it != end; utf8::to_next(it, end)) writer.write((*it >= 0x20 and *it <= 0x7e) ? *it : '?'); + }; + if (not m_title) + { + for (auto& atom : mode_line) + write_escaped(atom.content()); } - writer.write(suffix); + else + write_escaped(*m_title); + writer.write(" - Kakoune\007"); } m_dirty = true; @@ -1554,6 +1557,7 @@ void TerminalUI::set_ui_options(const Options& options) m_status_on_top = find("terminal_status_on_top").map(to_bool).value_or(false); m_set_title = find("terminal_set_title").map(to_bool).value_or(true); + m_title = find("terminal_title").map([](StringView s) { return String{s}; }); auto synchronized = find("terminal_synchronized").map(to_bool); m_synchronized.set = (bool)synchronized; diff --git a/src/terminal_ui.hh b/src/terminal_ui.hh index 64e3bfcf..02085532 100644 --- a/src/terminal_ui.hh +++ b/src/terminal_ui.hh @@ -153,6 +153,7 @@ private: int m_shift_function_key = default_shift_function_key; bool m_set_title = true; + Optional m_title; struct Synchronized { -- cgit v1.2.3 From 54992c08aecb2fc91aecacccc15d3a17ae7390dc Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sat, 14 Sep 2024 12:25:02 +0200 Subject: rc git: teach "git apply" to work on content, not just diffs Staging/unstaging/reverting (parts of) the current buffer's file can be a common use case. Today "git apply" can do that based on a selection within a diff. When the selection is on uncommitted content, we can probably assume that the intent is to use the part of the selection that overlaps with the +-side of "git diff" (or "git diff --cached" for "git apply --cached"). Make "git apply" treat selections as content if the buffile is tracked by Git. This differentiator is not perfect but I don't know why anyone would want to use the existing "git apply" semantics on a tracked file. Maybe we should pick a different name. This feature couples well with "git show-diff", which shows all lines with unstaged changes (in future it should probably show staged changes as well). Whereas on diffs, "git apply" stages the entire hunk if the selection contains no newline, this does not happen when operating on content. I didn't yet try implementing that. I guess the hunks are not as explicit here. Closes #5225 --- src/main.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/main.cc b/src/main.cc index 09c9b718..5eb30bc6 100644 --- a/src/main.cc +++ b/src/main.cc @@ -48,6 +48,7 @@ struct { 0, "» kak_* appearing in shell arguments will be added to the environment\n" "» {+U}double underline{} support\n" + "» {+u}git apply{} can stage/revert selected changes to current buffer\n" }, { 20240518, "» Fix tests failing on some platforms\n" -- cgit v1.2.3 From 88fa43988acc2389d92ead46a41ff8c7f0608c1a Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Mon, 16 Sep 2024 07:25:02 +0100 Subject: Do not return beginning of buffer whenever display to buffer coord fails Use an empty Optional to show that resolution failed and just do not do anything in the mouse event handler in that case. --- src/input_handler.cc | 32 +++++++++++++++++++++----------- src/window.cc | 6 +++--- src/window.hh | 2 +- 3 files changed, 25 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/input_handler.cc b/src/input_handler.cc index 0693bc43..6c6439bb 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -116,7 +116,6 @@ struct MouseHandler return false; Buffer& buffer = context.buffer(); - BufferCoord cursor; // bits above these potentially store additional information constexpr auto mask = (Key::Modifiers) 0x7FF; constexpr auto modifiers = Key::Modifiers::Control | Key::Modifiers::Alt | Key::Modifiers::Shift | Key::Modifiers::MouseButtonMask | ~mask; @@ -128,20 +127,31 @@ struct MouseHandler { case Key::MouseButton::Right: { m_dragging.reset(); - cursor = context.window().buffer_coord(key.coord()); + auto cursor = context.window().buffer_coord(key.coord()); + if (not cursor) + { + context.ensure_cursor_visible = false; + return true; + } ScopedSelectionEdition selection_edition{context}; auto& selections = context.selections(); if (key.modifiers & Key::Modifiers::Control) - selections = {{selections.begin()->anchor(), cursor}}; + selections = {{selections.begin()->anchor(), *cursor}}; else - selections.main() = {selections.main().anchor(), cursor}; + selections.main() = {selections.main().anchor(), *cursor}; selections.sort_and_merge_overlapping(); return true; } case Key::MouseButton::Left: { m_dragging.reset(new ScopedSelectionEdition{context}); - m_anchor = context.window().buffer_coord(key.coord()); + auto anchor = context.window().buffer_coord(key.coord()); + if (not anchor) + { + context.ensure_cursor_visible = false; + return true; + } + m_anchor = *anchor; if (not (key.modifiers & Key::Modifiers::Control)) context.selections_write_only() = { buffer, m_anchor}; else @@ -159,28 +169,28 @@ struct MouseHandler } case Key::Modifiers::MouseRelease: { - if (not m_dragging) + auto cursor = context.window().buffer_coord(key.coord()); + if (not m_dragging or not cursor) { context.ensure_cursor_visible = false; return true; } auto& selections = context.selections(); - cursor = context.window().buffer_coord(key.coord()); - selections.main() = {buffer.clamp(m_anchor), cursor}; + selections.main() = {buffer.clamp(m_anchor), *cursor}; selections.sort_and_merge_overlapping(); m_dragging.reset(); return true; } case Key::Modifiers::MousePos: { - if (not m_dragging) + auto cursor = context.window().buffer_coord(key.coord()); + if (not m_dragging or not cursor) { context.ensure_cursor_visible = false; return true; } - cursor = context.window().buffer_coord(key.coord()); auto& selections = context.selections(); - selections.main() = {buffer.clamp(m_anchor), cursor}; + selections.main() = {buffer.clamp(m_anchor), *cursor}; selections.sort_and_merge_overlapping(); return true; } diff --git a/src/window.cc b/src/window.cc index c5fc44db..6db3a21a 100644 --- a/src/window.cc +++ b/src/window.cc @@ -312,13 +312,13 @@ Optional Window::display_position(BufferCoord coord) const return {}; } -BufferCoord Window::buffer_coord(DisplayCoord coord) const +Optional Window::buffer_coord(DisplayCoord coord) const { if (m_display_buffer.timestamp() != buffer().timestamp() or m_display_buffer.lines().empty()) - return {0, 0}; + return {}; if (coord <= 0_line) - coord = {0,0}; + coord = {}; if ((size_t)coord.line >= m_display_buffer.lines().size()) coord = DisplayCoord{(int)m_display_buffer.lines().size()-1, INT_MAX}; diff --git a/src/window.hh b/src/window.hh index 65253c87..95199187 100644 --- a/src/window.hh +++ b/src/window.hh @@ -38,7 +38,7 @@ public: const DisplayBuffer& update_display_buffer(const Context& context); Optional display_position(BufferCoord coord) const; - BufferCoord buffer_coord(DisplayCoord coord) const; + Optional buffer_coord(DisplayCoord coord) const; Buffer& buffer() const { return *m_buffer; } -- cgit v1.2.3 From 2e1e15106e4e16f8c4de43b87ec901f569a582cf Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Mon, 16 Sep 2024 07:39:21 +0100 Subject: Rename Window::display_position to display_coord --- src/client.cc | 4 ++-- src/input_handler.cc | 2 +- src/window.cc | 2 +- src/window.hh | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/client.cc b/src/client.cc index 0f1b8d5f..611216a7 100644 --- a/src/client.cc +++ b/src/client.cc @@ -256,7 +256,7 @@ void Client::redraw_ifn() if ((m_ui_pending & MenuShow) or update_menu_anchor) { auto anchor = m_menu.style == MenuStyle::Inline ? - window.display_position(m_menu.anchor) : DisplayCoord{}; + window.display_coord(m_menu.anchor) : DisplayCoord{}; if (not (m_ui_pending & MenuShow) and m_menu.ui_anchor != anchor) m_ui_pending |= anchor ? (MenuShow | MenuSelect) : MenuHide; m_menu.ui_anchor = anchor; @@ -276,7 +276,7 @@ void Client::redraw_ifn() if ((m_ui_pending & InfoShow) or update_info_anchor) { auto anchor = is_inline(m_info.style) ? - window.display_position(m_info.anchor) : DisplayCoord{}; + window.display_coord(m_info.anchor) : DisplayCoord{}; if (not (m_ui_pending & MenuShow) and m_info.ui_anchor != anchor) m_ui_pending |= anchor ? InfoShow : InfoHide; m_info.ui_anchor = anchor; diff --git a/src/input_handler.cc b/src/input_handler.cc index 6c6439bb..3ddbfdfb 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -50,7 +50,7 @@ public: virtual std::pair get_cursor_info() const { const auto cursor = context().selections().main().cursor(); - auto coord = context().window().display_position(cursor).value_or(DisplayCoord{}); + auto coord = context().window().display_coord(cursor).value_or(DisplayCoord{}); return {CursorMode::Buffer, coord}; } diff --git a/src/window.cc b/src/window.cc index 6db3a21a..520d77e1 100644 --- a/src/window.cc +++ b/src/window.cc @@ -296,7 +296,7 @@ BufferCoord find_buffer_coord(const DisplayLine& line, const Buffer& buffer, } } -Optional Window::display_position(BufferCoord coord) const +Optional Window::display_coord(BufferCoord coord) const { if (m_display_buffer.timestamp() != buffer().timestamp()) return {}; diff --git a/src/window.hh b/src/window.hh index 95199187..3e1e5f95 100644 --- a/src/window.hh +++ b/src/window.hh @@ -37,7 +37,7 @@ public: const DisplayBuffer& update_display_buffer(const Context& context); - Optional display_position(BufferCoord coord) const; + Optional display_coord(BufferCoord coord) const; Optional buffer_coord(DisplayCoord coord) const; Buffer& buffer() const { return *m_buffer; } -- cgit v1.2.3 From b4b3ddae0d93fbd652d1440f87541b81315838aa Mon Sep 17 00:00:00 2001 From: Chris Webb Date: Tue, 17 Sep 2024 13:35:08 +0100 Subject: Avoid stdin as a function parameter name 9275d96 introduces a use of stdin as a function parameter name, but POSIX allows stdin to be a macro, which will conflict with this. This breaks the build on musl systems. Rename in the same way as the previous fix for this in c7d887d. --- src/shell_manager.hh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/shell_manager.hh b/src/shell_manager.hh index 3dc62e0a..5b42d644 100644 --- a/src/shell_manager.hh +++ b/src/shell_manager.hh @@ -63,12 +63,12 @@ public: const ShellContext& shell_context = {}); std::pair eval(StringView cmdline, const Context& context, - StringView stdin, + StringView in, Flags flags = Flags::WaitForStdout, const ShellContext& shell_context = {}) { return eval(cmdline, context, - [stdin]() mutable { return std::exchange(stdin, StringView{}); }, + [in]() mutable { return std::exchange(in, StringView{}); }, flags, shell_context); } -- cgit v1.2.3 From 5e0f9a2ce0377d8b5aba71f2916a30257221bac8 Mon Sep 17 00:00:00 2001 From: Passw Date: Thu, 19 Sep 2024 18:54:23 +0800 Subject: add header file #incldue "format.hh" to fix building error about missing hex(...) function --- src/backtrace.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/backtrace.cc b/src/backtrace.cc index 9c1df97a..04b772ad 100644 --- a/src/backtrace.cc +++ b/src/backtrace.cc @@ -1,6 +1,7 @@ #include "backtrace.hh" #include "string.hh" +#include "format.hh" #if defined(__GLIBC__) || defined(__APPLE__) # include -- cgit v1.2.3 From ca7bc55cf5134b11451ca6b88d9fa0205bbaac66 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Tue, 22 Oct 2024 21:18:23 +1100 Subject: Run shell-script-completions asynchronously Share most logic with shell-script-candidates. Now that we do not block we can run the completion script implicitely instead of waiting for an explicit completion request with . Fixes #5245 --- src/commands.cc | 145 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 81 insertions(+), 64 deletions(-) (limited to 'src') diff --git a/src/commands.cc b/src/commands.cc index 78193e57..90f4520d 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -259,47 +259,101 @@ static Completions complete_command_name(const Context& context, CompletionFlags context, prefix.substr(0, cursor_pos)); } -struct ShellScriptCompleter +struct AsyncShellScript { - ShellScriptCompleter(String shell_script, - Completions::Flags flags = Completions::Flags::None) + AsyncShellScript(String shell_script, + Completions::Flags flags = Completions::Flags::None) : m_shell_script{std::move(shell_script)}, m_flags(flags) {} + AsyncShellScript(const AsyncShellScript& other) : m_shell_script{other.m_shell_script}, m_flags(other.m_flags) {} + AsyncShellScript& operator=(const AsyncShellScript& other) { m_shell_script = other.m_shell_script; m_flags = other.m_flags; return *this; } + +protected: + void spawn_script(const Context& context, const ShellContext& shell_context, auto&& handle_line) + { + m_handle_line = handle_line; + m_running_script.emplace(ShellManager::instance().spawn(m_shell_script, context, false, shell_context)); + m_watcher.emplace((int)m_running_script->out, FdEvents::Read, EventMode::Urgent, + [this, &input_handler=context.input_handler()](auto&&... args) { read_stdout(input_handler); }); + } + + void read_stdout(InputHandler& input_handler) + { + char buffer[2048]; + bool closed = false; + int fd = (int)m_running_script->out; + while (fd_readable(fd)) + { + int size = read(fd, buffer, sizeof(buffer)); + if (size == 0) + { + closed = true; + break; + } + m_stdout_buffer.insert(m_stdout_buffer.end(), buffer, buffer + size); + } + auto end = closed ? m_stdout_buffer.end() : find(m_stdout_buffer | reverse(), '\n').base(); + for (auto c : ArrayView(m_stdout_buffer.begin(), end) | split('\n') + | filter([](auto s) { return not s.empty(); })) + m_handle_line(c); + + m_stdout_buffer.erase(m_stdout_buffer.begin(), end); + + input_handler.refresh_ifn(); + if (closed) + { + m_running_script.reset(); + m_watcher.reset(); + m_handle_line = {}; + } + } + + String m_shell_script; + Optional m_running_script; + Optional m_watcher; + Vector m_stdout_buffer; + std::function m_handle_line; + Completions::Flags m_flags; +}; + +struct ShellScriptCompleter : AsyncShellScript +{ + using AsyncShellScript::AsyncShellScript; + Completions operator()(const Context& context, CompletionFlags flags, CommandParameters params, size_t token_to_complete, ByteCount pos_in_token) { - if (flags & CompletionFlags::Fast) // no shell on fast completion - return Completions{}; - - ShellContext shell_context{ - params, - { { "token_to_complete", to_string(token_to_complete) }, - { "pos_in_token", to_string(pos_in_token) } } - }; - String output = ShellManager::instance().eval(m_shell_script, context, StringView{}, - ShellManager::Flags::WaitForStdout, - shell_context).first; CandidateList candidates; - for (auto&& candidate : output | split('\n') - | filter([](auto s) { return not s.empty(); })) - candidates.push_back(candidate.str()); + if (m_last_token != token_to_complete or pos_in_token != m_last_pos_in_token) + { + ShellContext shell_context{ + params, + { { "token_to_complete", to_string(token_to_complete) }, + { "pos_in_token", to_string(pos_in_token) } } + }; + spawn_script(context, shell_context, [this](StringView line) { m_candidates.push_back(line.str()); }); + + candidates = std::move(m_candidates); // avoid completion menu flicker by keeping the previous result visible + m_candidates.clear(); + m_last_token = token_to_complete; + m_last_pos_in_token = pos_in_token; + } + else + candidates = m_candidates; return {0_byte, pos_in_token, std::move(candidates), m_flags}; } + private: - String m_shell_script; - Completions::Flags m_flags; + CandidateList m_candidates; + int m_last_token = -1; + ByteCount m_last_pos_in_token = -1; }; -struct ShellCandidatesCompleter +struct ShellCandidatesCompleter : AsyncShellScript { - ShellCandidatesCompleter(String shell_script, - Completions::Flags flags = Completions::Flags::None) - : m_shell_script{std::move(shell_script)}, m_flags(flags) {} - - ShellCandidatesCompleter(const ShellCandidatesCompleter& other) : m_shell_script{other.m_shell_script}, m_flags(other.m_flags) {} - ShellCandidatesCompleter& operator=(const ShellCandidatesCompleter& other) { m_shell_script = other.m_shell_script; m_flags = other.m_flags; return *this; } + using AsyncShellScript::AsyncShellScript; Completions operator()(const Context& context, CompletionFlags flags, CommandParameters params, size_t token_to_complete, @@ -311,9 +365,7 @@ struct ShellCandidatesCompleter params, { { "token_to_complete", to_string(token_to_complete) } } }; - m_running_script.emplace(ShellManager::instance().spawn(m_shell_script, context, false, shell_context)); - m_watcher.emplace((int)m_running_script->out, FdEvents::Read, EventMode::Urgent, - [this, &input_handler=context.input_handler()](auto&&... args) { read_candidates(input_handler); }); + spawn_script(context, shell_context, [this](StringView line) { m_candidates.emplace_back(line.str(), used_letters(line)); }); m_candidates.clear(); m_last_token = token_to_complete; } @@ -321,36 +373,6 @@ struct ShellCandidatesCompleter } private: - void read_candidates(InputHandler& input_handler) - { - char buffer[2048]; - bool closed = false; - int fd = (int)m_running_script->out; - while (fd_readable(fd)) - { - int size = read(fd, buffer, sizeof(buffer)); - if (size == 0) - { - closed = true; - break; - } - m_stdout_buffer.insert(m_stdout_buffer.end(), buffer, buffer + size); - } - - auto end = closed ? m_stdout_buffer.end() : find(m_stdout_buffer | reverse(), '\n').base(); - for (auto c : ArrayView(m_stdout_buffer.begin(), end) | split('\n') - | filter([](auto s) { return not s.empty(); })) - m_candidates.emplace_back(c.str(), used_letters(c)); - m_stdout_buffer.erase(m_stdout_buffer.begin(), end); - - input_handler.refresh_ifn(); - if (not closed) - return; - - m_running_script.reset(); - m_watcher.reset(); - } - Completions rank_candidates(StringView query) { UsedLetters query_letters = used_letters(query); @@ -377,13 +399,8 @@ private: return Completions{0_byte, query.length(), std::move(res), m_flags}; } - String m_shell_script; - Vector m_stdout_buffer; - Optional m_running_script; - Optional m_watcher; Vector, MemoryDomain::Completion> m_candidates; int m_last_token = -1; - Completions::Flags m_flags; }; template -- cgit v1.2.3 From 50917b39ca410feac0f8dbf37b6db408aeedc2b8 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Tue, 22 Oct 2024 21:18:23 +1100 Subject: Remove now unused CompletionFlags Since shell-script-completions now runs the script asynchronously and unconditionally, there is no use for the CompletionFlags::Fast anymore which means we can remove that type altogether. --- src/command_manager.cc | 23 +++++----- src/command_manager.hh | 7 ++- src/commands.cc | 112 +++++++++++++++++++++-------------------------- src/completion.cc | 3 +- src/completion.hh | 14 +----- src/input_handler.cc | 16 +++---- src/input_handler.hh | 3 +- src/normal.cc | 6 +-- src/parameters_parser.hh | 4 +- 9 files changed, 80 insertions(+), 108 deletions(-) (limited to 'src') diff --git a/src/command_manager.cc b/src/command_manager.cc index fd32f93c..e30f8a68 100644 --- a/src/command_manager.cc +++ b/src/command_manager.cc @@ -658,7 +658,7 @@ Completions CommandManager::complete_module_name(StringView query) const | transform(&ModuleMap::Item::key))}; } -static Completions complete_expansion(const Context& context, CompletionFlags flags, +static Completions complete_expansion(const Context& context, Token token, ByteCount start, ByteCount cursor_pos, ByteCount pos_in_token) { @@ -674,7 +674,7 @@ static Completions complete_expansion(const Context& context, CompletionFlags fl token.content, pos_in_token) }; case Token::Type::ShellExpand: - return offset_pos(shell_complete(context, flags, token.content, + return offset_pos(shell_complete(context, token.content, pos_in_token), start); case Token::Type::ValExpand: @@ -695,7 +695,7 @@ static Completions complete_expansion(const Context& context, CompletionFlags fl } } -static Completions complete_expand(const Context& context, CompletionFlags flags, +static Completions complete_expand(const Context& context, StringView prefix, ByteCount start, ByteCount cursor_pos, ByteCount pos_in_token) { @@ -713,7 +713,7 @@ static Completions complete_expand(const Context& context, CompletionFlags flags continue; if (token.type == Token::Type::Raw or token.type == Token::Type::RawQuoted) return {}; - return complete_expansion(context, flags, token, + return complete_expansion(context, token, start + token.pos, cursor_pos, pos_in_token - token.pos); } @@ -748,8 +748,7 @@ static Completions requote(Completions completions, Token::Type token_type) } Completions CommandManager::Completer::operator()( - const Context& context, CompletionFlags flags, - StringView command_line, ByteCount cursor_pos) + const Context& context, StringView command_line, ByteCount cursor_pos) { auto prefix = command_line.substr(0_byte, cursor_pos); CommandParser parser{prefix}; @@ -800,7 +799,7 @@ Completions CommandManager::Completer::operator()( case Token::Type::ShellExpand: case Token::Type::ValExpand: case Token::Type::FileExpand: - return complete_expansion(context, flags, token, start, cursor_pos, pos_in_token); + return complete_expansion(context, token, start, cursor_pos, pos_in_token); case Token::Type::Raw: case Token::Type::RawQuoted: @@ -840,7 +839,7 @@ Completions CommandManager::Completer::operator()( const auto& switch_desc = command.param_desc.switches.get(raw_params.at(raw_params.size() - 2).substr(1_byte)); if (not *switch_desc.arg_completer) return Completions{}; - return offset_pos(requote((*switch_desc.arg_completer)(context, flags, raw_params.back(), pos_in_token), token.type), start); + return offset_pos(requote((*switch_desc.arg_completer)(context, raw_params.back(), pos_in_token), token.type), start); } case ParametersParser::State::Positional: break; @@ -852,10 +851,10 @@ Completions CommandManager::Completer::operator()( Vector params{parser.begin(), parser.end()}; auto index = params.size() - 1; - return offset_pos(requote(m_command_completer(context, flags, params, index, pos_in_token), token.type), start); + return offset_pos(requote(m_command_completer(context, params, index, pos_in_token), token.type), start); } case Token::Type::Expand: - return complete_expand(context, flags, token.content, start, cursor_pos, pos_in_token); + return complete_expand(context, token.content, start, cursor_pos, pos_in_token); default: break; } @@ -863,7 +862,7 @@ Completions CommandManager::Completer::operator()( } Completions CommandManager::NestedCompleter::operator()( - const Context& context, CompletionFlags flags, CommandParameters params, + const Context& context, CommandParameters params, size_t token_to_complete, ByteCount pos_in_token) { StringView prefix = params[token_to_complete].substr(0, pos_in_token); @@ -881,7 +880,7 @@ Completions CommandManager::NestedCompleter::operator()( } return m_command_completer - ? m_command_completer(context, flags, params.subrange(1), token_to_complete-1, pos_in_token) + ? m_command_completer(context, params.subrange(1), token_to_complete-1, pos_in_token) : Completions{}; } diff --git a/src/command_manager.hh b/src/command_manager.hh index c0a2e878..3f18e423 100644 --- a/src/command_manager.hh +++ b/src/command_manager.hh @@ -22,7 +22,6 @@ using CommandFunc = std::function; using CommandCompleter = std::function; @@ -118,7 +117,7 @@ public: struct Completer { - Completions operator()(const Context& context, CompletionFlags flags, + Completions operator()(const Context& context, StringView command_line, ByteCount cursor_pos); private: @@ -128,8 +127,8 @@ public: struct NestedCompleter { - Completions operator()(const Context& context, CompletionFlags flags, - CommandParameters params, size_t token_to_complete, ByteCount pos_in_token); + Completions operator()(const Context& context, CommandParameters params, + size_t token_to_complete, ByteCount pos_in_token); private: String m_last_complete_command; diff --git a/src/commands.cc b/src/commands.cc index 90f4520d..bc11a945 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -83,7 +83,7 @@ template struct PerArgumentCommandCompleter; template<> struct PerArgumentCommandCompleter<> { - Completions operator()(const Context&, CompletionFlags, CommandParameters, + Completions operator()(const Context&, CommandParameters, size_t, ByteCount) const { return {}; } }; @@ -96,7 +96,7 @@ struct PerArgumentCommandCompleter : PerArgumentCommandCompl : PerArgumentCommandCompleter(std::forward(rest)...), m_completer(std::forward(completer)) {} - Completions operator()(const Context& context, CompletionFlags flags, + Completions operator()(const Context& context, CommandParameters params, size_t token_to_complete, ByteCount pos_in_token) { @@ -104,10 +104,10 @@ struct PerArgumentCommandCompleter : PerArgumentCommandCompl { const String& arg = token_to_complete < params.size() ? params[token_to_complete] : String(); - return m_completer(context, flags, arg, pos_in_token); + return m_completer(context, arg, pos_in_token); } return PerArgumentCommandCompleter::operator()( - context, flags, params.subrange(1), + context, params.subrange(1), token_to_complete-1, pos_in_token); } @@ -125,8 +125,8 @@ template auto add_flags(Completer completer, Completions::Flags completions_flags) { return [completer=std::move(completer), completions_flags] - (const Context& context, CompletionFlags flags, StringView prefix, ByteCount cursor_pos) { - Completions res = completer(context, flags, prefix, cursor_pos); + (const Context& context, StringView prefix, ByteCount cursor_pos) { + Completions res = completer(context, prefix, cursor_pos); res.flags |= completions_flags; return res; }; @@ -140,7 +140,7 @@ auto menu(Completer completer) template auto filename_completer = make_completer( - [](const Context& context, CompletionFlags flags, StringView prefix, ByteCount cursor_pos) + [](const Context& context, StringView prefix, ByteCount cursor_pos) { return Completions{ 0_byte, cursor_pos, complete_filename(prefix, context.options()["ignored_files"].get(), @@ -149,7 +149,7 @@ auto filename_completer = make_completer( template auto filename_arg_completer = - [](const Context& context, CompletionFlags flags, StringView prefix, ByteCount cursor_pos) -> Completions + [](const Context& context, StringView prefix, ByteCount cursor_pos) -> Completions { return { 0_byte, cursor_pos, complete_filename(prefix, context.options()["ignored_files"].get(), @@ -157,20 +157,19 @@ auto filename_arg_completer = menu ? Completions::Flags::Menu : Completions::Flags::None }; }; auto client_arg_completer = - [](const Context& context, CompletionFlags flags, StringView prefix, ByteCount cursor_pos) -> Completions + [](const Context& context, StringView prefix, ByteCount cursor_pos) -> Completions { return { 0_byte, cursor_pos, ClientManager::instance().complete_client_name(prefix, cursor_pos), Completions::Flags::Menu }; }; auto arg_completer = [](auto candidates) -> PromptCompleter { - return [=](const Context& context, CompletionFlags flags, StringView prefix, ByteCount cursor_pos) -> Completions { + return [=](const Context& context, StringView prefix, ByteCount cursor_pos) -> Completions { return Completions{ 0_byte, cursor_pos, complete(prefix, cursor_pos, candidates), Completions::Flags::Menu }; }; }; template -static Completions complete_buffer_name(const Context& context, CompletionFlags flags, - StringView prefix, ByteCount cursor_pos) +static Completions complete_buffer_name(const Context& context, StringView prefix, ByteCount cursor_pos) { struct RankedMatchAndBuffer : RankedMatch { @@ -219,7 +218,7 @@ template auto make_single_word_completer(Func&& func) { return make_completer( - [func = std::move(func)](const Context& context, CompletionFlags flags, + [func = std::move(func)](const Context& context, StringView prefix, ByteCount cursor_pos) -> Completions { auto candidate = { func(context) }; return { 0_byte, cursor_pos, complete(prefix, cursor_pos, candidate) }; }); @@ -230,21 +229,21 @@ const ParameterDesc single_param{ {}, ParameterDesc::Flags::None, 1, 1 }; const ParameterDesc single_optional_param{ {}, ParameterDesc::Flags::None, 0, 1 }; const ParameterDesc double_params{ {}, ParameterDesc::Flags::None, 2, 2 }; -static Completions complete_scope(const Context&, CompletionFlags, +static Completions complete_scope(const Context&, StringView prefix, ByteCount cursor_pos) { static constexpr StringView scopes[] = { "global", "buffer", "window", "local"}; return { 0_byte, cursor_pos, complete(prefix, cursor_pos, scopes) }; } -static Completions complete_scope_including_current(const Context&, CompletionFlags, +static Completions complete_scope_including_current(const Context&, StringView prefix, ByteCount cursor_pos) { static constexpr StringView scopes[] = { "global", "buffer", "window", "local", "current" }; return { 0_byte, cursor_pos, complete(prefix, cursor_pos, scopes) }; } -static Completions complete_scope_no_global(const Context&, CompletionFlags, +static Completions complete_scope_no_global(const Context&, StringView prefix, ByteCount cursor_pos) { static constexpr StringView scopes[] = { "buffer", "window", "local", "current" }; @@ -252,7 +251,7 @@ static Completions complete_scope_no_global(const Context&, CompletionFlags, } -static Completions complete_command_name(const Context& context, CompletionFlags, +static Completions complete_command_name(const Context& context, StringView prefix, ByteCount cursor_pos) { return CommandManager::instance().complete_command_name( @@ -320,7 +319,7 @@ struct ShellScriptCompleter : AsyncShellScript { using AsyncShellScript::AsyncShellScript; - Completions operator()(const Context& context, CompletionFlags flags, + Completions operator()(const Context& context, CommandParameters params, size_t token_to_complete, ByteCount pos_in_token) { @@ -355,7 +354,7 @@ struct ShellCandidatesCompleter : AsyncShellScript { using AsyncShellScript::AsyncShellScript; - Completions operator()(const Context& context, CompletionFlags flags, + Completions operator()(const Context& context, CommandParameters params, size_t token_to_complete, ByteCount pos_in_token) { @@ -412,9 +411,9 @@ struct PromptCompleterAdapter { if (not m_completer) return {}; - return [completer=std::move(m_completer)](const Context& context, CompletionFlags flags, + return [completer=std::move(m_completer)](const Context& context, StringView prefix, ByteCount cursor_pos) { - return completer(context, flags, {String{String::NoCopy{}, prefix}}, 0, cursor_pos); + return completer(context, {String{String::NoCopy{}, prefix}}, 0, cursor_pos); }; } @@ -1011,7 +1010,7 @@ static constexpr auto highlighter_scopes = { "global/", "buffer/", "window/", "s template Completions highlighter_cmd_completer( - const Context& context, CompletionFlags flags, CommandParameters params, + const Context& context, CommandParameters params, size_t token_to_complete, ByteCount pos_in_token) { if (token_to_complete == 0) @@ -1092,9 +1091,9 @@ const CommandDesc arrange_buffers_cmd = { ParameterDesc{{}, ParameterDesc::Flags::None, 1}, CommandFlags::None, CommandHelper{}, - [](const Context& context, CompletionFlags flags, CommandParameters params, size_t, ByteCount cursor_pos) + [](const Context& context, CommandParameters params, size_t, ByteCount cursor_pos) { - return menu(complete_buffer_name)(context, flags, params.back(), cursor_pos); + return menu(complete_buffer_name)(context, params.back(), cursor_pos); }, [](const ParametersParser& parser, Context&, const ShellContext&) { @@ -1192,8 +1191,7 @@ const CommandDesc remove_highlighter_cmd = { } }; -static Completions complete_hooks(const Context&, CompletionFlags, - StringView prefix, ByteCount cursor_pos) +static Completions complete_hooks(const Context&, StringView prefix, ByteCount cursor_pos) { return { 0_byte, cursor_pos, complete(prefix, cursor_pos, enum_desc(Meta::Type{}) | transform(&EnumDesc::name)) }; } @@ -1246,12 +1244,12 @@ const CommandDesc remove_hook_cmd = { double_params, CommandFlags::None, CommandHelper{}, - [](const Context& context, CompletionFlags flags, + [](const Context& context, CommandParameters params, size_t token_to_complete, ByteCount pos_in_token) -> Completions { if (token_to_complete == 0) - return menu(complete_scope)(context, flags, params[0], pos_in_token); + return menu(complete_scope)(context, params[0], pos_in_token); else if (token_to_complete == 1) { if (auto scope = get_scope_ifp(params[0], context)) @@ -1289,8 +1287,7 @@ Vector params_to_shell(const ParametersParser& parser) return vars; } -Completions complete_completer_type(const Context&, CompletionFlags, - StringView prefix, ByteCount cursor_pos) +Completions complete_completer_type(const Context&, StringView prefix, ByteCount cursor_pos) { static constexpr StringView completers[] = {"file", "client", "buffer", "shell-script", "shell-script-candidates", "command", "shell"}; return { 0_byte, cursor_pos, complete(prefix, cursor_pos, completers) }; @@ -1301,8 +1298,7 @@ CommandCompleter make_command_completer(StringView type, StringView param, Compl { if (type == "file") { - return [=](const Context& context, CompletionFlags flags, - CommandParameters params, + return [=](const Context& context, CommandParameters params, size_t token_to_complete, ByteCount pos_in_token) { const String& prefix = params[token_to_complete]; const auto& ignored_files = context.options()["ignored_files"].get(); @@ -1314,8 +1310,7 @@ CommandCompleter make_command_completer(StringView type, StringView param, Compl } else if (type == "client") { - return [=](const Context& context, CompletionFlags flags, - CommandParameters params, + return [=](const Context& context, CommandParameters params, size_t token_to_complete, ByteCount pos_in_token) { const String& prefix = params[token_to_complete]; @@ -1327,12 +1322,11 @@ CommandCompleter make_command_completer(StringView type, StringView param, Compl } else if (type == "buffer") { - return [=](const Context& context, CompletionFlags flags, - CommandParameters params, + return [=](const Context& context, CommandParameters params, size_t token_to_complete, ByteCount pos_in_token) { return add_flags(complete_buffer_name, completions_flags)( - context, flags, params[token_to_complete], pos_in_token); + context, params[token_to_complete], pos_in_token); }; } else if (type == "shell-script") @@ -1353,12 +1347,11 @@ CommandCompleter make_command_completer(StringView type, StringView param, Compl return CommandManager::NestedCompleter{}; else if (type == "shell") { - return [=](const Context& context, CompletionFlags flags, - CommandParameters params, + return [=](const Context& context, CommandParameters params, size_t token_to_complete, ByteCount pos_in_token) { return add_flags(shell_complete, completions_flags)( - context, flags, params[token_to_complete], pos_in_token); + context, params[token_to_complete], pos_in_token); }; } else @@ -1470,8 +1463,7 @@ const CommandDesc define_command_cmd = { define_command }; -static Completions complete_alias_name(const Context& context, CompletionFlags, - StringView prefix, ByteCount cursor_pos) +static Completions complete_alias_name(const Context& context, StringView prefix, ByteCount cursor_pos) { return { 0_byte, cursor_pos, complete(prefix, cursor_pos, context.aliases().flatten_aliases() @@ -1604,8 +1596,7 @@ const CommandDesc debug_cmd = { CommandFlags::None, CommandHelper{}, make_completer( - [](const Context& context, CompletionFlags flags, - StringView prefix, ByteCount cursor_pos) -> Completions { + [](const Context& context, StringView prefix, ByteCount cursor_pos) -> Completions { auto c = {"info", "buffers", "options", "memory", "shared-strings", "profile-hash-maps", "faces", "mappings", "regex", "registers"}; return { 0_byte, cursor_pos, complete(prefix, cursor_pos, c), Completions::Flags::Menu }; @@ -1789,12 +1780,11 @@ const CommandDesc set_option_cmd = { }, CommandFlags::None, option_doc_helper, - [](const Context& context, CompletionFlags flags, - CommandParameters params, size_t token_to_complete, - ByteCount pos_in_token) -> Completions + [](const Context& context, CommandParameters params, + size_t token_to_complete, ByteCount pos_in_token) -> Completions { if (token_to_complete == 0) - return menu(complete_scope_including_current)(context, flags, params[0], pos_in_token); + return menu(complete_scope_including_current)(context, params[0], pos_in_token); else if (token_to_complete == 1) return { 0_byte, params[1].length(), GlobalScope::instance().option_registry().complete_option_name(params[1], pos_in_token), @@ -1826,12 +1816,11 @@ const CommandDesc set_option_cmd = { } }; -Completions complete_option(const Context& context, CompletionFlags flags, - CommandParameters params, size_t token_to_complete, - ByteCount pos_in_token) +Completions complete_option(const Context& context, CommandParameters params, + size_t token_to_complete, ByteCount pos_in_token) { if (token_to_complete == 0) - return menu(complete_scope_no_global)(context, flags, params[0], pos_in_token); + return menu(complete_scope_no_global)(context, params[0], pos_in_token); else if (token_to_complete == 1) return { 0_byte, params[1].length(), GlobalScope::instance().option_registry().complete_option_name(params[1], pos_in_token), @@ -1900,7 +1889,7 @@ const CommandDesc declare_option_cmd = { CommandFlags::None, CommandHelper{}, make_completer( - [](const Context& context, CompletionFlags flags, + [](const Context& context, StringView prefix, ByteCount cursor_pos) -> Completions { auto c = {"int", "bool", "str", "regex", "int-list", "str-list", "completions", "line-specs", "range-specs", "str-to-str-map"}; return { 0_byte, cursor_pos, complete(prefix, cursor_pos, c), Completions::Flags::Menu }; @@ -1946,12 +1935,11 @@ const CommandDesc declare_option_cmd = { }; template -static Completions map_key_completer(const Context& context, CompletionFlags flags, - CommandParameters params, size_t token_to_complete, - ByteCount pos_in_token) +static Completions map_key_completer(const Context& context, CommandParameters params, + size_t token_to_complete, ByteCount pos_in_token) { if (token_to_complete == 0) - return menu(complete_scope)(context, flags, params[0], pos_in_token); + return menu(complete_scope)(context, params[0], pos_in_token); if (token_to_complete == 1) { auto& user_modes = get_scope(params[0], context).keymaps().user_modes(); @@ -2467,7 +2455,7 @@ const CommandDesc try_catch_cmd = { } }; -static Completions complete_face(const Context& context, CompletionFlags flags, +static Completions complete_face(const Context& context, StringView prefix, ByteCount cursor_pos) { return {0_byte, cursor_pos, @@ -2562,7 +2550,7 @@ const CommandDesc set_register_cmd = { CommandFlags::None, CommandHelper{}, make_completer( - [](const Context& context, CompletionFlags flags, + [](const Context& context, StringView prefix, ByteCount cursor_pos) -> Completions { return { 0_byte, cursor_pos, RegisterManager::instance().complete_register_name(prefix, cursor_pos) }; @@ -2612,7 +2600,7 @@ const CommandDesc change_directory_cmd = { CommandFlags::None, CommandHelper{}, make_completer( - [](const Context& context, CompletionFlags flags, + [](const Context& context, StringView prefix, ByteCount cursor_pos) -> Completions { return { 0_byte, cursor_pos, complete_filename(prefix, @@ -2713,7 +2701,7 @@ const CommandDesc enter_user_mode_cmd = { }, CommandFlags::None, CommandHelper{}, - [](const Context& context, CompletionFlags flags, + [](const Context& context, CommandParameters params, size_t token_to_complete, ByteCount pos_in_token) -> Completions { @@ -2767,7 +2755,7 @@ const CommandDesc require_module_cmd = { CommandFlags::None, CommandHelper{}, make_completer(menu( - [](const Context&, CompletionFlags, StringView prefix, ByteCount cursor_pos) { + [](const Context&, StringView prefix, ByteCount cursor_pos) { return CommandManager::instance().complete_module_name(prefix.substr(0, cursor_pos)); })), [](const ParametersParser& parser, Context& context, const ShellContext&) diff --git a/src/completion.cc b/src/completion.cc index 60e79e07..c44319d8 100644 --- a/src/completion.cc +++ b/src/completion.cc @@ -8,8 +8,7 @@ namespace Kakoune { -Completions shell_complete(const Context& context, CompletionFlags flags, - StringView prefix, ByteCount cursor_pos) +Completions shell_complete(const Context& context, StringView prefix, ByteCount cursor_pos) { ByteCount word_start = 0; ByteCount word_end = 0; diff --git a/src/completion.hh b/src/completion.hh index 78024e19..cef703a2 100644 --- a/src/completion.hh +++ b/src/completion.hh @@ -42,22 +42,12 @@ struct Completions : candidates(std::move(candidates)), start(start), end(end), flags{flags} {} }; -enum class CompletionFlags -{ - None = 0, - Fast = 1 << 0, -}; - -constexpr bool with_bit_ops(Meta::Type) { return true; } - -inline Completions complete_nothing(const Context&, CompletionFlags, - StringView, ByteCount cursor_pos) +inline Completions complete_nothing(const Context&, StringView, ByteCount cursor_pos) { return {cursor_pos, cursor_pos}; } -Completions shell_complete(const Context& context, CompletionFlags, - StringView, ByteCount cursor_pos); +Completions shell_complete(const Context& context, StringView, ByteCount cursor_pos); inline Completions offset_pos(Completions completion, ByteCount offset) { diff --git a/src/input_handler.cc b/src/input_handler.cc index 3ddbfdfb..0f2c8987 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -692,7 +692,7 @@ public: Timer::Callback{} : [this](Timer&) { RefPtr keep_alive{this}; // hook or m_callback could trigger pop_mode() if (m_auto_complete and m_refresh_completion_pending) - refresh_completions(CompletionFlags::Fast); + refresh_completions(); if (m_line_changed) { m_callback(m_line_editor.line(), PromptEvent::Change, context()); @@ -829,10 +829,10 @@ public: CandidateList& candidates = m_completions.candidates; if (m_auto_complete and m_refresh_completion_pending) - refresh_completions(CompletionFlags::Fast); + refresh_completions(); if (candidates.empty()) // manual completion, we need to ask our completer for completions { - refresh_completions(CompletionFlags::None); + refresh_completions(); if ((not m_prefix_in_completions and candidates.size() > 1) or candidates.size() > 2) return; @@ -890,7 +890,7 @@ public: }); if (m_explicit_completer) - refresh_completions(CompletionFlags::None); + refresh_completions(); }, "enter completion type", "f: filename\n" "w: buffer word\n"); @@ -901,7 +901,7 @@ public: m_auto_complete = not m_auto_complete; if (m_auto_complete) - refresh_completions(CompletionFlags::Fast); + refresh_completions(); else if (context().has_client()) { clear_completions(); @@ -996,7 +996,7 @@ private: template void use_explicit_completer(Completer&& completer) { - m_explicit_completer = [completer](const Context& context, CompletionFlags flags, StringView content, ByteCount cursor_pos) { + m_explicit_completer = [completer](const Context& context, StringView content, ByteCount cursor_pos) { Optional last_token; CommandParser parser{content.substr(0_byte, cursor_pos)}; while (auto token = parser.read_token(false)) @@ -1012,7 +1012,7 @@ private: }; } - void refresh_completions(CompletionFlags flags) + void refresh_completions() { try { @@ -1022,7 +1022,7 @@ private: return; m_current_completion = -1; const String& line = m_line_editor.line(); - m_completions = completer(context(), flags, line, + m_completions = completer(context(), line, line.byte_count_to(m_line_editor.cursor_pos())); if (not context().has_client()) return; diff --git a/src/input_handler.hh b/src/input_handler.hh index 54c5fd5b..32e9bfca 100644 --- a/src/input_handler.hh +++ b/src/input_handler.hh @@ -42,8 +42,7 @@ class InputMode; enum class KeymapMode : char; enum class CursorMode; -using PromptCompleter = std::function; +using PromptCompleter = std::function; enum class InsertMode : unsigned { Insert, diff --git a/src/normal.cc b/src/normal.cc index 056f11de..6aa5b703 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -491,9 +491,9 @@ void command(const Context& context, EnvVarMap env_vars, char reg = 0) ":", {}, default_command, context.faces()["Prompt"], PromptFlags::DropHistoryEntriesWithBlankPrefix, ':', - [completer=CommandManager::Completer{}](const Context& context, CompletionFlags flags, + [completer=CommandManager::Completer{}](const Context& context, StringView cmd_line, ByteCount pos) mutable { - return completer(context, flags, cmd_line, pos); + return completer(context, cmd_line, pos); }, [env_vars = std::move(env_vars), default_command](StringView cmdline, PromptEvent event, Context& context) { if (context.has_client()) @@ -842,7 +842,7 @@ void regex_prompt(Context& context, String prompt, char reg, RegexMode mode, Fun context.input_handler().prompt( std::move(prompt), {}, default_regex, context.faces()["Prompt"], PromptFlags::Search, reg, - [](const Context& context, CompletionFlags, StringView regex, ByteCount pos) -> Completions { + [](const Context& context, StringView regex, ByteCount pos) -> Completions { auto current_word = [](StringView s) { auto it = s.end(); while (it != s.begin() and is_word(*(it-1))) diff --git a/src/parameters_parser.hh b/src/parameters_parser.hh index f1ff8b73..1b91b6fc 100644 --- a/src/parameters_parser.hh +++ b/src/parameters_parser.hh @@ -40,9 +40,7 @@ struct wrong_argument_count : public parameter_error class Context; struct Completions; -enum class CompletionFlags; -using ArgCompleter = std::function; +using ArgCompleter = std::function; struct SwitchDesc { -- cgit v1.2.3 From b96e500ddb27f78f2478e69836d6502d4fdbe9c0 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Tue, 22 Oct 2024 21:34:31 +1100 Subject: Fork server to background on if session is daemonized Fixes #4957 --- src/main.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/main.cc b/src/main.cc index 5eb30bc6..ec2b80bd 100644 --- a/src/main.cc +++ b/src/main.cc @@ -703,7 +703,8 @@ std::unique_ptr create_local_ui(UIType ui_type) static SignalHandler old_handler = set_signal_handler(SIGTSTP, [](int sig) { if (ClientManager::instance().count() == 1 and - *ClientManager::instance().begin() == local_client) + *ClientManager::instance().begin() == local_client and + not Server::instance().is_daemon()) old_handler(sig); else { -- cgit v1.2.3 From be82047dbf5f74f123e925b96e0e13962a4e0c09 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Mon, 28 Oct 2024 12:21:09 +1100 Subject: Only check for ascii horizontal blanks during command parsing The general is_horizontal_blank supports various unicode blanks, but passing an utf8 continuation byte to it can lead to surprising results as we can match with 0xA0 (when char is unsigned). Fixes #5250 --- src/command_manager.cc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/command_manager.cc b/src/command_manager.cc index e30f8a68..0db97e94 100644 --- a/src/command_manager.cc +++ b/src/command_manager.cc @@ -179,6 +179,13 @@ ParseResult parse_quoted_balanced(ParseState& state) return {String{String::NoCopy{}, {beg, pos - terminated}}, terminated}; } +bool is_ascii_horizontal_blank(char c) +{ + return c == '\t' or + c == '\f' or + c == ' '; +} + String parse_unquoted(ParseState& state) { const char* beg = state.pos; @@ -189,7 +196,7 @@ String parse_unquoted(ParseState& state) while (state.pos != end) { const char c = *state.pos; - if (is_command_separator(c) or is_horizontal_blank(c)) + if (is_command_separator(c) or is_ascii_horizontal_blank(c)) { str += StringView{beg, state.pos}; if (state.pos != beg and *(state.pos - 1) == '\\') @@ -235,8 +242,8 @@ void skip_blanks_and_comments(ParseState& state) { while (state) { - const Codepoint c = *state.pos; - if (is_horizontal_blank(c)) + const char c = *state.pos; + if (is_ascii_horizontal_blank(c)) ++state.pos; else if (c == '\\' and state.pos + 1 != state.str.end() and state.pos[1] == '\n') -- cgit v1.2.3 From 6b9291104b72b678964024d35c3da5f34f86b2cb Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sun, 3 Nov 2024 14:06:48 +0100 Subject: Fix backward regex search ending in DOTALL I noticed that reverse searches ending in "." stopped working in version 2024.05.08: kak -n -e "exec %{%cfoobargjfoo.}' Bisects ca7471c25 (Compute StartDesc with an offset to effective start, 2024-03-18) which updated the find_next_start() logic for the forward case but not for backward case. Add a symmetrical change and test case, that seems to fix it. Not 100% sure if this is correct but feels so. --- src/regex_impl.cc | 11 +++++++++++ src/regex_impl.hh | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/regex_impl.cc b/src/regex_impl.cc index 4b404cfa..d86637cd 100644 --- a/src/regex_impl.cc +++ b/src/regex_impl.cc @@ -1593,6 +1593,17 @@ auto test_regex = UnitTest{[]{ kak_assert(not vm.exec("😄xoo", RegexExecFlags::None)); } + { + TestVM vm{"oo(.{3,4}|f)"}; + kak_assert(vm.backward_start_desc and vm.backward_start_desc->offset == 4); + for (int c = 0; c < CompiledRegex::StartDesc::count; ++c) + kak_assert(vm.backward_start_desc->map[c] == (c == 'f' or c == 'o')); + + kak_assert(vm.exec("ooxxx", RegexExecFlags::None)); + kak_assert(vm.exec("oofx", RegexExecFlags::None)); + kak_assert(not vm.exec("oox😄", RegexExecFlags::None)); + } + { auto eq = [](const CompiledRegex::NamedCapture& lhs, const CompiledRegex::NamedCapture& rhs) { diff --git a/src/regex_impl.hh b/src/regex_impl.hh index 7f3eb495..f62c31da 100644 --- a/src/regex_impl.hh +++ b/src/regex_impl.hh @@ -552,7 +552,7 @@ private: { auto prev = utf8::previous(pos, config.end); if (start_desc.map[static_cast(*prev)]) - return pos; + return utf8::advance(pos, start, CharCount(start_desc.offset)); pos = prev; } } -- cgit v1.2.3 From 8c49c8ee404fecc110338c08eeed515b63caa93c Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Mon, 4 Nov 2024 20:59:20 +1100 Subject: Highlight all atoms for the line regardless of has_buffer_range This changes the behaviour with say line numbers and other line flags, but can be opted out by using final faces Fixes #5253 --- src/highlighters.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/highlighters.cc b/src/highlighters.cc index cccccffd..25f93245 100644 --- a/src/highlighters.cc +++ b/src/highlighters.cc @@ -506,10 +506,8 @@ std::unique_ptr create_line_highlighter(HighlighterParameters param for (auto& atom : *it) { column += atom.length(); - if (!atom.has_buffer_range()) - continue; - - kak_assert(atom.begin().line == line); + if (atom.has_buffer_range() and atom.begin().line != line) + break; apply_face(face)(atom); } const ColumnCount remaining = context.context.window().dimensions().column - column; -- cgit v1.2.3 From d86e505fad397251a8a618c545a7d78f43a70a34 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Mon, 11 Nov 2024 13:28:27 +0100 Subject: Fail rename-session instead of creating overlong socket paths Commit 9cf8a3ccd (Check for buffer overflow when constructing the socket path., 2022-04-07) made $ kak -s $(printf %0100d) fail but forgot to do the same for $ kak -e "rename-session $(printf %0100d)" which silently succeeds, only to fail at the next $ echo nop | kak -p $(printf %0100d) Fatal error: socket path too long: '/run/user/1000/kakoune/0000...' Let's fail earlier. While at it, don't validate "m_session" redundantly. I'm not sure if we should validate the socket names in "kak -clear"; I guess it doesn't matter. --- src/remote.cc | 18 +++++++++--------- src/remote.hh | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/remote.cc b/src/remote.cc index 97a62b02..3ef2c152 100644 --- a/src/remote.cc +++ b/src/remote.cc @@ -619,21 +619,21 @@ const String& session_directory() return session_dir; } -String session_path(StringView session) +String session_path(StringView session, bool assume_valid) { - if (not all_of(session, is_identifier)) + if (not assume_valid and not all_of(session, is_identifier)) throw runtime_error{format("invalid session name: '{}'", session)}; - return format("{}/{}", session_directory(), session); + String path = format("{}/{}", session_directory(), session); + if (not assume_valid and path.length() + 1 > sizeof sockaddr_un{}.sun_path) + throw runtime_error{format("socket path too long: '{}'", path)}; + return path; } static sockaddr_un session_addr(StringView session) { sockaddr_un addr; addr.sun_family = AF_UNIX; - 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()); + strcpy(addr.sun_path, session_path(session).c_str()); return addr; } @@ -889,7 +889,7 @@ Server::Server(String session_name, bool is_daemon) bool Server::rename_session(StringView name) { - String old_socket_file = session_path(m_session); + String old_socket_file = session_path(m_session, true); String new_socket_file = session_path(name); if (file_exists(new_socket_file)) @@ -906,7 +906,7 @@ void Server::close_session(bool do_unlink) { if (do_unlink) { - String socket_file = session_path(m_session); + String socket_file = session_path(m_session, true); unlink(socket_file.c_str()); } m_listener->close_fd(); diff --git a/src/remote.hh b/src/remote.hh index 99e60cbd..dc6bc41f 100644 --- a/src/remote.hh +++ b/src/remote.hh @@ -46,7 +46,7 @@ private: void send_command(StringView session, StringView command); String get_user_name(); const String& session_directory(); -String session_path(StringView session); +String session_path(StringView session, bool assume_valid = false); struct Server : public Singleton { -- cgit v1.2.3 From e74a3ac6a3bad1b74af71aa0bfdacb41ffcb7355 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Sat, 16 Nov 2024 10:50:17 +1100 Subject: Run urgent event loop when blocking on opening a file for writing This makes cancel the writing operation if we block on trying to open a fifo with no reader. Fixes #5256 --- src/file.cc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/file.cc b/src/file.cc index ac19a089..f75b0685 100644 --- a/src/file.cc +++ b/src/file.cc @@ -280,9 +280,15 @@ template void write(int fd, StringView data); void write_to_file(StringView filename, StringView data) { - const int fd = open(filename.zstr(), O_CREAT | O_WRONLY | O_TRUNC, 0644); - if (fd == -1) - throw file_access_error(filename, strerror(errno)); + int fd = -1; + const int flags = O_CREAT | O_WRONLY | O_TRUNC | (EventManager::has_instance() ? O_NONBLOCK : 0); + while ((fd = open(filename.zstr(), flags, 0644)) == -1) + { + if (errno == ENXIO and EventManager::has_instance()) // trying to open a FIFO with no readers yet + EventManager::instance().handle_next_events(EventMode::Urgent, nullptr, false); + else + throw file_access_error(filename, strerror(errno)); + } auto close_fd = on_scope_end([fd]{ close(fd); }); write(fd, data); } -- cgit v1.2.3 From 9358c62bf2c26f5604ddffb7b41d55ff89a9e51f Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Fri, 22 Nov 2024 13:47:08 +1100 Subject: Take a timeout argument in EventManager::handle_next_events When provided, this gives the maximal time to wait before exiting handle_next_events. If not given handle_next_events will block, this provides a more flexible approach than the previous "block" boolean. Use this to wait for a millisecond between each try to open a fifo for writing. Fixes the 100% cpu usage discussed in github on commit e74a3ac6a3bad1b74af71aa0bfdacb41ffcb7355 --- src/event_manager.cc | 25 ++++++++++++------------- src/event_manager.hh | 7 ++++++- src/file.cc | 4 ++-- src/main.cc | 8 +++++--- 4 files changed, 25 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/event_manager.cc b/src/event_manager.cc index ed608fcc..01838de6 100644 --- a/src/event_manager.cc +++ b/src/event_manager.cc @@ -73,7 +73,7 @@ EventManager::~EventManager() kak_assert(m_timers.empty()); } -bool EventManager::handle_next_events(EventMode mode, sigset_t* sigmask, bool block) +bool EventManager::handle_next_events(EventMode mode, sigset_t* sigmask, Optional timeout) { int max_fd = 0; fd_set rfds, wfds, efds; @@ -97,12 +97,10 @@ bool EventManager::handle_next_events(EventMode mode, sigset_t* sigmask, bool bl FD_SET(fd, &efds); } - bool with_timeout = false; if (m_has_forced_fd) - block = false; + timeout.reset(); - timespec ts{}; - if (block and not m_timers.empty()) + if (not m_timers.empty()) { auto next_date = (*std::min_element( m_timers.begin(), m_timers.end(), [](Timer* lhs, Timer* rhs) { @@ -111,15 +109,16 @@ bool EventManager::handle_next_events(EventMode mode, sigset_t* sigmask, bool bl if (next_date != TimePoint::max()) { - with_timeout = true; - using namespace std::chrono; using ns = std::chrono::nanoseconds; - auto nsecs = std::max(ns(0), duration_cast(next_date - Clock::now())); - auto secs = duration_cast(nsecs); - ts = timespec{ (time_t)secs.count(), (long)(nsecs - secs).count() }; + auto remaining = std::max(Nanoseconds(0), + std::chrono::duration_cast(next_date - Clock::now())); + timeout = timeout ? std::min(*timeout, remaining) : remaining; } } - int res = pselect(max_fd + 1, &rfds, &wfds, &efds, - not block or with_timeout ? &ts : nullptr, sigmask); + auto ts = timeout.map([](auto nsecs) { + auto secs = std::chrono::duration_cast(nsecs); + return timespec{(time_t)secs.count(), (long)(nsecs - secs).count()}; + }); + int res = pselect(max_fd + 1, &rfds, &wfds, &efds, ts ? &*ts : nullptr, sigmask); // copy forced fds *after* select, so that signal handlers can write to // m_forced_fd, interupt select, and directly be serviced. @@ -164,7 +163,7 @@ void EventManager::force_signal(int fd) void EventManager::handle_urgent_events() { if (has_instance()) - instance().handle_next_events(EventMode::Urgent, nullptr, false); + instance().handle_next_events(EventMode::Urgent, nullptr, Nanoseconds{}); } diff --git a/src/event_manager.hh b/src/event_manager.hh index 68f6dee3..92d90105 100644 --- a/src/event_manager.hh +++ b/src/event_manager.hh @@ -4,6 +4,7 @@ #include "clock.hh" #include "meta.hh" #include "utils.hh" +#include "optional.hh" #include "vector.hh" #include @@ -87,10 +88,14 @@ private: class EventManager : public Singleton { public: + using Nanoseconds = std::chrono::nanoseconds; + EventManager(); ~EventManager(); - bool handle_next_events(EventMode mode, sigset_t* sigmask = nullptr, bool block = true); + // blocks until next event if no timeout given + bool handle_next_events(EventMode mode, sigset_t* sigmask = nullptr, + Optional timeout = {}); // force the watchers associated with fd to be executed // on next handle_next_events call. diff --git a/src/file.cc b/src/file.cc index f75b0685..262caa09 100644 --- a/src/file.cc +++ b/src/file.cc @@ -269,7 +269,7 @@ void write(int fd, StringView data) count -= written; } else if (errno == EAGAIN and not atomic and EventManager::has_instance()) - EventManager::instance().handle_next_events(EventMode::Urgent, nullptr, false); + EventManager::instance().handle_next_events(EventMode::Urgent, nullptr, std::chrono::nanoseconds{}); else throw file_access_error(format("fd: {}", fd), strerror(errno)); } @@ -285,7 +285,7 @@ void write_to_file(StringView filename, StringView data) while ((fd = open(filename.zstr(), flags, 0644)) == -1) { if (errno == ENXIO and EventManager::has_instance()) // trying to open a FIFO with no readers yet - EventManager::instance().handle_next_events(EventMode::Urgent, nullptr, false); + EventManager::instance().handle_next_events(EventMode::Urgent, nullptr, std::chrono::nanoseconds{1'000'000}); else throw file_access_error(filename, strerror(errno)); } diff --git a/src/main.cc b/src/main.cc index ec2b80bd..a7556905 100644 --- a/src/main.cc +++ b/src/main.cc @@ -908,14 +908,16 @@ int run_server(StringView session, StringView server_init, // Loop so that eventual inputs happening during the processing are handled as // well, avoiding unneeded redraws. - bool allow_blocking = not client_manager.has_pending_inputs(); + Optional timeout; + if (client_manager.has_pending_inputs()) + timeout = std::chrono::nanoseconds{}; try { - while (event_manager.handle_next_events(EventMode::Normal, nullptr, allow_blocking)) + while (event_manager.handle_next_events(EventMode::Normal, nullptr, timeout)) { if (client_manager.process_pending_inputs()) break; - allow_blocking = false; + timeout = std::chrono::nanoseconds{}; } } catch (const cancel&) {} -- cgit v1.2.3 From 5d378fa3a5139ca7c075ddf1a533856f53943f73 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Thu, 14 Nov 2024 11:38:22 +0100 Subject: Fix overlapping range passed to BufReadFifo in non-scrolling fifos On the first read from a nonscrolling fifo, we insert after the buffer contents (which is just "\n"), and later delete the redundant newline (582c3c56b (Do not add trailing newline to non-scrolling fifo buffers, 2024-01-28)). This deletion invalidates inserted ranges passed to BufReadFifo. Fix that. The test uses another fifo to pass ranges. I guess it could use "ui_out -until" as well but this seems simpler. The test script needs a fd but 3 and 4 are already taken so use 5. I didn't find a portable way to check if it's already taken. Fixes #5255 --- src/buffer_utils.cc | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/buffer_utils.cc b/src/buffer_utils.cc index 28b2de05..9a46504d 100644 --- a/src/buffer_utils.cc +++ b/src/buffer_utils.cc @@ -1,6 +1,7 @@ #include "buffer_utils.hh" #include "buffer_manager.hh" +#include "coord.hh" #include "event_manager.hh" #include "file.hh" #include "selection.hh" @@ -214,7 +215,7 @@ Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, bool scroll bool closed = false; size_t loop = 0; char data[buffer_size]; - BufferCoord insert_coord = m_buffer.back_coord(); + Optional insert_begin; const int fifo = fd(); { @@ -235,13 +236,19 @@ Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, bool scroll if (not m_scroll and (is_first or m_had_trailing_newline)) pos = m_buffer.next(pos); - pos = m_buffer.insert(pos, StringView(data, data+count)).end; + auto inserted_range = m_buffer.insert(pos, StringView(data, data+count)); + if (not insert_begin) + insert_begin = inserted_range.begin; + pos = inserted_range.end; bool have_trailing_newline = (data[count-1] == '\n'); if (not m_scroll) { if (is_first) + { m_buffer.erase({0,0}, m_buffer.next({0,0})); + --insert_begin->line; + } else if (not m_had_trailing_newline and have_trailing_newline) m_buffer.erase(m_buffer.prev(pos), pos); } @@ -250,10 +257,10 @@ Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, bool scroll while (++loop < max_loop and fd_readable(fifo)); } - if (insert_coord != m_buffer.back_coord()) + if (insert_begin) m_buffer.run_hook_in_own_context( Hook::BufReadFifo, - selection_to_string(ColumnType::Byte, m_buffer, {insert_coord, m_buffer.back_coord()})); + selection_to_string(ColumnType::Byte, m_buffer, {*insert_begin, m_buffer.back_coord()})); if (closed) m_buffer.values().erase(fifo_watcher_id); // will delete this -- cgit v1.2.3 From 658915086fc4883c45f1af98f1b37a01822e9feb Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sat, 23 Nov 2024 10:54:35 +0100 Subject: Fix BufReadFifo overlapping range on partial line As reported in [1], when reading from a fifo a buffer that is not newline-terminated, we add a newline automatically, and include that in the range reported to BufReadFifo. I'm not 100% sure if this is really wrong but since the typical consumer of BufReadFifo does something like select %val{hook_param} exec |grep foo it seems safe to remove this newline; doing so means that 1. "grep foo" will no longer see a newline in stdin, which seems good. 2. Kakoune will strip a trailing newline from the command output, since the input didn't have one. So the input is the same. Let's remove any artificially-added newline from the hook parameter. [1]: https://lists.sr.ht/~mawww/kakoune/%3CZzXjfXnETd2gbeXa@thristian.org%3E --- src/buffer_utils.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/buffer_utils.cc b/src/buffer_utils.cc index 9a46504d..5e55036c 100644 --- a/src/buffer_utils.cc +++ b/src/buffer_utils.cc @@ -258,9 +258,12 @@ Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, bool scroll } if (insert_begin) + { + auto insert_back = m_had_trailing_newline ? m_buffer.back_coord() : m_buffer.prev(m_buffer.back_coord()); m_buffer.run_hook_in_own_context( Hook::BufReadFifo, - selection_to_string(ColumnType::Byte, m_buffer, {*insert_begin, m_buffer.back_coord()})); + selection_to_string(ColumnType::Byte, m_buffer, {*insert_begin, insert_back})); + } if (closed) m_buffer.values().erase(fifo_watcher_id); // will delete this -- cgit v1.2.3 From c3b01a3c9caf030a8c6f6dca56688aca57a9248e Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Wed, 27 Nov 2024 11:13:35 +0100 Subject: Add back option to scroll in stdin buffers Commit 582c3c56b (Do not add trailing newline to non-scrolling fifo buffers, 2024-01-28) completely forgot about stdin buffers, breaking the ability to make them scrolling via "ge". For example while sleep 1; do seq $LINES date done | kak Let's fix that by adding the trailing newline back for stdin buffers. Unlike "edit -scroll", don't scroll until the user explicitly moves the cursor. --- src/buffer_utils.cc | 16 ++++++++++------ src/buffer_utils.hh | 3 ++- src/commands.cc | 2 +- src/main.cc | 2 +- src/remote.cc | 4 ++-- 5 files changed, 16 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/buffer_utils.cc b/src/buffer_utils.cc index 5e55036c..fc87fea5 100644 --- a/src/buffer_utils.cc +++ b/src/buffer_utils.cc @@ -166,7 +166,7 @@ void reload_file_buffer(Buffer& buffer) buffer.flags() &= ~Buffer::Flags::New; } -Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, bool scroll) +Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, AutoScroll scroll) { static ValueId fifo_watcher_id = get_free_value_id(); @@ -186,7 +186,7 @@ Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, bool scroll struct FifoWatcher : FDWatcher { - FifoWatcher(int fd, Buffer& buffer, bool scroll) + FifoWatcher(int fd, Buffer& buffer, AutoScroll scroll) : FDWatcher(fd, FdEvents::Read, EventMode::Normal, [](FDWatcher& watcher, FdEvents, EventMode mode) { if (mode == EventMode::Normal) @@ -233,7 +233,8 @@ Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, bool scroll auto pos = m_buffer.back_coord(); const bool is_first = pos == BufferCoord{0,0}; - if (not m_scroll and (is_first or m_had_trailing_newline)) + if ((m_scroll == AutoScroll::No and (is_first or m_had_trailing_newline)) + or (m_scroll == AutoScroll::NotInitially and is_first)) pos = m_buffer.next(pos); auto inserted_range = m_buffer.insert(pos, StringView(data, data+count)); @@ -242,14 +243,17 @@ Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, bool scroll pos = inserted_range.end; bool have_trailing_newline = (data[count-1] == '\n'); - if (not m_scroll) + if (m_scroll != AutoScroll::Yes) { if (is_first) { m_buffer.erase({0,0}, m_buffer.next({0,0})); --insert_begin->line; + if (m_scroll == AutoScroll::NotInitially) + m_buffer.insert(m_buffer.end_coord(), "\n"); } - else if (not m_had_trailing_newline and have_trailing_newline) + else if (m_scroll == AutoScroll::No and + not m_had_trailing_newline and have_trailing_newline) m_buffer.erase(m_buffer.prev(pos), pos); } m_had_trailing_newline = have_trailing_newline; @@ -270,7 +274,7 @@ Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, bool scroll } Buffer& m_buffer; - bool m_scroll; + AutoScroll m_scroll; bool m_had_trailing_newline = false; }; diff --git a/src/buffer_utils.hh b/src/buffer_utils.hh index e0b40425..bc0dab68 100644 --- a/src/buffer_utils.hh +++ b/src/buffer_utils.hh @@ -72,7 +72,8 @@ ColumnCount column_length(const Buffer& buffer, ColumnCount tabstop, LineCount l ByteCount get_byte_to_column(const Buffer& buffer, ColumnCount tabstop, DisplayCoord coord); -Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, bool scroll = false); +enum class AutoScroll { No, NotInitially, Yes }; +Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, AutoScroll scroll); Buffer* create_buffer_from_string(String name, Buffer::Flags flags, StringView data); Buffer* open_file_buffer(StringView filename, Buffer::Flags flags = Buffer::Flags::None); diff --git a/src/commands.cc b/src/commands.cc index bc11a945..90f7a23e 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -76,7 +76,7 @@ Buffer* open_fifo(StringView name, StringView filename, Buffer::Flags flags, boo if (fd < 0) throw runtime_error(format("unable to open '{}'", filename)); - return create_fifo_buffer(name.str(), fd, flags, scroll); + return create_fifo_buffer(name.str(), fd, flags, scroll ? AutoScroll::Yes : AutoScroll::No); } template struct PerArgumentCommandCompleter; diff --git a/src/main.cc b/src/main.cc index a7556905..e360a6d8 100644 --- a/src/main.cc +++ b/src/main.cc @@ -696,7 +696,7 @@ std::unique_ptr create_local_ui(UIType ui_type) int tty = open("/dev/tty", O_RDONLY); dup2(tty, 0); close(tty); - create_fifo_buffer("*stdin*", fd, Buffer::Flags::None); + create_fifo_buffer("*stdin*", fd, Buffer::Flags::None, AutoScroll::NotInitially); } auto ui = make_ui(ui_type); diff --git a/src/remote.cc b/src/remote.cc index 3ef2c152..f4e62419 100644 --- a/src/remote.cc +++ b/src/remote.cc @@ -806,8 +806,8 @@ private: auto env_vars = m_reader.read>(); if (auto stdin_fd = m_reader.ancillary_fd()) - create_fifo_buffer(generate_buffer_name("*stdin-{}*"), *stdin_fd, Buffer::Flags::None); - + create_fifo_buffer(generate_buffer_name("*stdin-{}*"), *stdin_fd, Buffer::Flags::None, + AutoScroll::NotInitially); auto* ui = new RemoteUI{sock, dimensions}; ClientManager::instance().create_client( std::unique_ptr(ui), pid, std::move(name), -- cgit v1.2.3 From 7ae1fd683defbd11b54ba7046df69be692ce4de5 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Thu, 28 Nov 2024 08:20:29 +1100 Subject: Raise the regex idle function call period to every 16M codepoint --- src/regex_impl.hh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/regex_impl.hh b/src/regex_impl.hh index f62c31da..56b1d867 100644 --- a/src/regex_impl.hh +++ b/src/regex_impl.hh @@ -490,12 +490,15 @@ private: constexpr bool search = mode & RegexMode::Search; constexpr bool any_match = mode & RegexMode::AnyMatch; uint16_t current_step = -1; + constexpr size_t idle_frequency = 255; // Run idle loop every 255 * 65536 == 16M codepoints + size_t wrap_count = 0; m_found_match = false; while (true) // Iterate on all codepoints and once at the end { if (++current_step == 0) { - idle_func(); + if ((++wrap_count % idle_frequency) == 0) + idle_func(); // We wrapped, avoid potential collision on inst.last_step by resetting them for (auto& inst : forward ? insts.subrange(0, m_program.first_backward_inst) -- cgit v1.2.3 From 8769b94eb25cd7402db6caa4f0d4b417f6365703 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Sat, 30 Nov 2024 12:27:11 +1100 Subject: Cache buffer lines ArrayView in BufferIterator The extra indirection of going through the buffer can be costly as the compiler does not know the buffer is not supposed to be mutated during iteration, so it has to actually reload the values which adds memory accesses in the Buffer instance which can be costly in say regex searches where memory access tends to dominate performance. Storing this in the BufferIterator lets the compiler put this info in registers and not reload it. --- src/buffer.hh | 2 ++ src/buffer.inl.hh | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/buffer.hh b/src/buffer.hh index ec2b9620..fd748213 100644 --- a/src/buffer.hh +++ b/src/buffer.hh @@ -95,6 +95,7 @@ public: private: SafePtr m_buffer; + ArrayView m_lines; BufferCoord m_coord; StringView m_line; }; @@ -122,6 +123,7 @@ public: ReadOnly = 1 << 6, }; friend constexpr bool with_bit_ops(Meta::Type) { return true; } + friend class BufferIterator; enum class HistoryId : size_t { First = 0, Invalid = (size_t)-1 }; diff --git a/src/buffer.inl.hh b/src/buffer.inl.hh index acaa699f..f3e46378 100644 --- a/src/buffer.inl.hh +++ b/src/buffer.inl.hh @@ -99,7 +99,7 @@ inline BufferCoord Buffer::end_coord() const } inline BufferIterator::BufferIterator(const Buffer& buffer, BufferCoord coord) noexcept - : m_buffer{&buffer}, m_coord{coord}, + : m_buffer{&buffer}, m_lines{buffer.m_lines}, m_coord{coord}, m_line{coord.line < buffer.line_count() ? (*m_buffer)[coord.line] : StringView{}} {} inline bool BufferIterator::operator==(const BufferIterator& iterator) const noexcept @@ -165,8 +165,8 @@ inline BufferIterator& BufferIterator::operator++() { if (++m_coord.column == m_line.length()) { - m_line = (++m_coord.line < m_buffer->line_count()) ? - (*m_buffer)[m_coord.line] : StringView{}; + m_line = ((size_t)++m_coord.line < m_lines.size()) ? + m_lines[(size_t)m_coord.line]->strview() : StringView{}; m_coord.column = 0; } return *this; @@ -176,7 +176,7 @@ inline BufferIterator& BufferIterator::operator--() { if (m_coord.column == 0) { - m_line = (*m_buffer)[--m_coord.line]; + m_line = m_lines[(size_t)--m_coord.line]->strview(); m_coord.column = m_line.length() - 1; } else -- cgit v1.2.3 From c52faded6fdba1297e1daf5894ccaa208b83ea7e Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Sun, 1 Dec 2024 19:36:44 +1100 Subject: Add specific start desc optimization for single possible start byte Use tighter codegen for that pretty common use case. --- src/regex_impl.cc | 3 +++ src/regex_impl.hh | 23 ++++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/regex_impl.cc b/src/regex_impl.cc index d86637cd..0789ef6d 100644 --- a/src/regex_impl.cc +++ b/src/regex_impl.cc @@ -1031,6 +1031,9 @@ private: not contains(start_desc.map, false)) return nullptr; + if (std::count(std::begin(start_desc.map), std::end(start_desc.map), true) == 1) + start_desc.start_byte = find(start_desc.map, true) - std::begin(start_desc.map); + return std::make_unique(start_desc); } diff --git a/src/regex_impl.hh b/src/regex_impl.hh index 56b1d867..ae46ae38 100644 --- a/src/regex_impl.hh +++ b/src/regex_impl.hh @@ -156,6 +156,7 @@ struct CompiledRegex : UseMemoryDomain { static constexpr Codepoint count = 256; using OffsetLimits = std::numeric_limits; + char start_byte = 0; uint8_t offset = 0; bool map[count]; }; @@ -270,7 +271,7 @@ public: }; Iterator start = forward ? begin : end; - if (const auto& start_desc = forward ? m_program.forward_start_desc : m_program.backward_start_desc) + if (const auto* start_desc = (forward ? m_program.forward_start_desc : m_program.backward_start_desc).get()) { if (search) { @@ -542,6 +543,26 @@ private: static Iterator find_next_start(Iterator start, const ExecConfig& config, const StartDesc& start_desc) { auto pos = start; + if (char start_byte = start_desc.start_byte) + { + while (pos != config.end) + { + if constexpr (forward) + { + if (*pos == start_byte) + return utf8::advance(pos, start, -CharCount(start_desc.offset)); + ++pos; + } + else + { + auto prev = utf8::previous(pos, config.end); + if (*prev == start_byte) + return utf8::advance(pos, start, CharCount(start_desc.offset)); + pos = prev; + } + } + } + while (pos != config.end) { static_assert(StartDesc::count <= 256, "start desc should be ascii only"); -- cgit v1.2.3 From 316bca9d6225007e32e89053dc3b8bd221d40b50 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Thu, 28 Nov 2024 13:24:47 +0100 Subject: Scrolling BufReadFifo to not not report final empty line Whereas nonscrolling fifos generally[^1] append to the very end of the buffer, scrolling fifos generally insert *before* the final empty line. This means that every single BufReadFifo hook in a scrolling fifo will report an additional newline. This is clearly wrong. Even reporting it only once would be wrong, because the newline is not added by a fifo read. This behavior has always existed for "edit -scroll -fifo" buffers. For stdin buffers, it was re-introduced in c3b01a3c9 (Add back option to scroll in stdin buffers, 2024-11-27). Fix this by ending the reported range before the final empty line. Handle one edge case: if the inserted range did not end with a newline, the final empty line collapses into the previous line. In this case we already don't report the newline because it's declared "artificially-added" by 658915086 (Fix BufReadFifo overlapping range on partial line, 2024-11-23). This fixes the problem described at https://github.com/mawww/kakoune/issues/5255#issuecomment-2505650511 Tests are copied verbatim from the no-scroll cases (not yet sure how to share logic / parameterize a test in a nice way): $ diff -ur test/commands/fifo-read-ranges{,-scroll} -edit -fifo fifo *fifo* +edit -fifo fifo -scroll *fifo* $ diff -ur test/commands/fifo-read-ranges-noeol{,-scroll} -edit -fifo fifo *fifo* +edit -fifo fifo -scroll *fifo* [^1]: unless the very last character is a fake newline (except for the first read, to not scroll) which we already don't report. --- src/buffer_utils.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/buffer_utils.cc b/src/buffer_utils.cc index fc87fea5..f311b4c6 100644 --- a/src/buffer_utils.cc +++ b/src/buffer_utils.cc @@ -263,7 +263,8 @@ Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, AutoScroll if (insert_begin) { - auto insert_back = m_had_trailing_newline ? m_buffer.back_coord() : m_buffer.prev(m_buffer.back_coord()); + auto insert_back = (m_had_trailing_newline and m_scroll == AutoScroll::No) + ? m_buffer.back_coord() : m_buffer.prev(m_buffer.back_coord()); m_buffer.run_hook_in_own_context( Hook::BufReadFifo, selection_to_string(ColumnType::Byte, m_buffer, {*insert_begin, insert_back})); -- cgit v1.2.3 From 6f29950e913a05bfad8baf1f515e36cf15dd2bb2 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Thu, 28 Nov 2024 13:24:48 +0100 Subject: Fix extra newline inserted into stdin buffers Commit c3b01a3c9 (Add back option to scroll in stdin buffers, 2024-11-27) missed the case where the initial read from stdin had no trailing newline: for i in $(seq 50); do printf .; sleep .1; done | kak After the first read, we transplant the initial newline to end. This creates an extra newline because we already added a fake newline to uphold buffer invariants. Fix that. --- src/buffer_utils.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/buffer_utils.cc b/src/buffer_utils.cc index f311b4c6..a4fb639b 100644 --- a/src/buffer_utils.cc +++ b/src/buffer_utils.cc @@ -249,7 +249,7 @@ Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, AutoScroll { m_buffer.erase({0,0}, m_buffer.next({0,0})); --insert_begin->line; - if (m_scroll == AutoScroll::NotInitially) + if (m_scroll == AutoScroll::NotInitially and have_trailing_newline) m_buffer.insert(m_buffer.end_coord(), "\n"); } else if (m_scroll == AutoScroll::No and -- cgit v1.2.3 From d29fa04adc6a15c8d62ffcd4390e5fc785d92b62 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Tue, 3 Dec 2024 21:26:57 +1100 Subject: Do not store buffer pointer in BufferIterator This makes BufferIterator smaller and trivially move/copyable --- src/buffer.cc | 12 ++++++------ src/buffer.hh | 13 ++++++++----- src/buffer.inl.hh | 40 ++++++++++++++++++++++------------------ 3 files changed, 36 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/buffer.cc b/src/buffer.cc index ada61ad8..f0205c54 100644 --- a/src/buffer.cc +++ b/src/buffer.cc @@ -570,17 +570,17 @@ void Buffer::notify_saved(FsStatus status) m_fs_status = status; } -BufferCoord Buffer::advance(BufferCoord coord, ByteCount count) const +BufferCoord Buffer::advance(ArrayView lines, BufferCoord coord, ByteCount count) { if (count > 0) { auto line = coord.line; count += coord.column; - while (count >= m_lines[line].length()) + while (count >= lines[(size_t)line]->length) { - count -= m_lines[line++].length(); - if (line == line_count()) - return end_coord(); + count -= lines[(size_t)line++]->length; + if ((size_t)line == lines.size()) + return line; } return { line, count }; } @@ -592,7 +592,7 @@ BufferCoord Buffer::advance(BufferCoord coord, ByteCount count) const { if (--line < 0) return {0, 0}; - count += m_lines[line].length(); + count += lines[(size_t)line]->length; } return { line, count }; } diff --git a/src/buffer.hh b/src/buffer.hh index fd748213..2b27f7c3 100644 --- a/src/buffer.hh +++ b/src/buffer.hh @@ -64,8 +64,9 @@ public: // costly, so this is not strictly random access using iterator_category = std::bidirectional_iterator_tag; - BufferIterator() noexcept : m_buffer{nullptr}, m_line{} {} + BufferIterator() = default; BufferIterator(const Buffer& buffer, BufferCoord coord) noexcept; + BufferIterator(ArrayView lines, BufferCoord coord) noexcept; bool operator== (const BufferIterator& iterator) const noexcept; auto operator<=>(const BufferIterator& iterator) const noexcept; @@ -75,7 +76,7 @@ public: const char& operator[](size_t n) const noexcept; size_t operator- (const BufferIterator& iterator) const; - explicit operator bool() const { return static_cast(m_buffer); } + explicit operator bool() const { return not m_lines.empty(); } BufferIterator operator+ (ByteCount size) const; BufferIterator operator- (ByteCount size) const; @@ -94,7 +95,6 @@ public: using Sentinel = BufferCoord; private: - SafePtr m_buffer; ArrayView m_lines; BufferCoord m_coord; StringView m_line; @@ -159,9 +159,12 @@ public: String string(BufferCoord begin, BufferCoord end) const; StringView substr(BufferCoord begin, BufferCoord end) const; + static BufferCoord advance(ArrayView lines, BufferCoord coord, ByteCount count); + static ByteCount distance(ArrayView lines, BufferCoord begin, BufferCoord end); + const char& byte_at(BufferCoord c) const; - ByteCount distance(BufferCoord begin, BufferCoord end) const; - BufferCoord advance(BufferCoord coord, ByteCount count) const; + ByteCount distance(BufferCoord begin, BufferCoord end) const { return distance(m_lines, begin, end); } + BufferCoord advance(BufferCoord coord, ByteCount count) const { return advance(m_lines, coord, count); } BufferCoord next(BufferCoord coord) const; BufferCoord prev(BufferCoord coord) const; diff --git a/src/buffer.inl.hh b/src/buffer.inl.hh index f3e46378..7465e532 100644 --- a/src/buffer.inl.hh +++ b/src/buffer.inl.hh @@ -27,16 +27,16 @@ inline BufferCoord Buffer::prev(BufferCoord coord) const return { coord.line, coord.column - 1 }; } -inline ByteCount Buffer::distance(BufferCoord begin, BufferCoord end) const +inline ByteCount Buffer::distance(ArrayView lines, BufferCoord begin, BufferCoord end) { if (begin > end) - return -distance(end, begin); + return -distance(lines, end, begin); if (begin.line == end.line) return end.column - begin.column; - ByteCount res = m_lines[begin.line].length() - begin.column; + ByteCount res = lines[(size_t)begin.line]->length - begin.column; for (LineCount l = begin.line+1; l < end.line; ++l) - res += m_lines[l].length(); + res += lines[(size_t)l]->length; res += end.column; return res; } @@ -99,18 +99,21 @@ inline BufferCoord Buffer::end_coord() const } inline BufferIterator::BufferIterator(const Buffer& buffer, BufferCoord coord) noexcept - : m_buffer{&buffer}, m_lines{buffer.m_lines}, m_coord{coord}, - m_line{coord.line < buffer.line_count() ? (*m_buffer)[coord.line] : StringView{}} {} + : BufferIterator{buffer.m_lines, coord} {} + +inline BufferIterator::BufferIterator(ArrayView lines, BufferCoord coord) noexcept + : m_lines{lines}, m_coord{coord}, + m_line{(size_t)coord.line < m_lines.size() ? m_lines[(size_t)coord.line]->strview() : StringView{}} {} inline bool BufferIterator::operator==(const BufferIterator& iterator) const noexcept { - kak_assert(m_buffer == iterator.m_buffer); + kak_assert(m_lines.pointer() == iterator.m_lines.pointer()); return m_coord == iterator.m_coord; } inline auto BufferIterator::operator<=>(const BufferIterator& iterator) const noexcept { - kak_assert(m_buffer == iterator.m_buffer); + kak_assert(m_lines.pointer() == iterator.m_lines.pointer()); return (m_coord <=> iterator.m_coord); } @@ -127,37 +130,38 @@ inline const char& BufferIterator::operator*() const noexcept inline const char& BufferIterator::operator[](size_t n) const noexcept { - return m_buffer->byte_at(m_buffer->advance(m_coord, n)); + auto coord = Buffer::advance(m_lines, m_coord, n); + return m_lines[(size_t)coord.line]->strview()[coord.column]; } inline size_t BufferIterator::operator-(const BufferIterator& iterator) const { - kak_assert(m_buffer == iterator.m_buffer); - return (size_t)m_buffer->distance(iterator.m_coord, m_coord); + kak_assert(m_lines.pointer() == iterator.m_lines.pointer()); + return (size_t)Buffer::distance(m_lines, iterator.m_coord, m_coord); } inline BufferIterator BufferIterator::operator+(ByteCount size) const { - kak_assert(m_buffer); - return { *m_buffer, m_buffer->advance(m_coord, size) }; + kak_assert(*this); + return { m_lines, Buffer::advance(m_lines, m_coord, size) }; } inline BufferIterator BufferIterator::operator-(ByteCount size) const { - return { *m_buffer, m_buffer->advance(m_coord, -size) }; + return { m_lines, Buffer::advance(m_lines, m_coord, -size) }; } inline BufferIterator& BufferIterator::operator+=(ByteCount size) { - m_coord = m_buffer->advance(m_coord, size); - m_line = (*m_buffer)[m_coord.line]; + m_coord = Buffer::advance(m_lines, m_coord, size); + m_line = m_lines[(size_t)m_coord.line]->strview(); return *this; } inline BufferIterator& BufferIterator::operator-=(ByteCount size) { - m_coord = m_buffer->advance(m_coord, -size); - m_line = (*m_buffer)[m_coord.line]; + m_coord = Buffer::advance(m_lines, m_coord, -size); + m_line = m_lines[(size_t)m_coord.line]->strview(); return *this; } -- cgit v1.2.3 From 19f23e0ff81d4b97a7b95567e7ce6f3b49bac81d Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Tue, 3 Dec 2024 21:29:47 +1100 Subject: Compact BufferIterator to avoid padding --- src/buffer.hh | 9 +++++---- src/buffer.inl.hh | 30 ++++++++++++++++-------------- 2 files changed, 21 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/buffer.hh b/src/buffer.hh index 2b27f7c3..50423502 100644 --- a/src/buffer.hh +++ b/src/buffer.hh @@ -66,7 +66,7 @@ public: BufferIterator() = default; BufferIterator(const Buffer& buffer, BufferCoord coord) noexcept; - BufferIterator(ArrayView lines, BufferCoord coord) noexcept; + BufferIterator(const StringDataPtr* lines, LineCount line_count, BufferCoord coord) noexcept; bool operator== (const BufferIterator& iterator) const noexcept; auto operator<=>(const BufferIterator& iterator) const noexcept; @@ -76,7 +76,7 @@ public: const char& operator[](size_t n) const noexcept; size_t operator- (const BufferIterator& iterator) const; - explicit operator bool() const { return not m_lines.empty(); } + explicit operator bool() const { return m_lines; } BufferIterator operator+ (ByteCount size) const; BufferIterator operator- (ByteCount size) const; @@ -95,9 +95,10 @@ public: using Sentinel = BufferCoord; private: - ArrayView m_lines; + const StringDataPtr* m_lines; + [[no_unique_address]] StringView m_line; + [[no_unique_address]] LineCount m_line_count; BufferCoord m_coord; - StringView m_line; }; using BufferLines = Vector; diff --git a/src/buffer.inl.hh b/src/buffer.inl.hh index 7465e532..890a5cbd 100644 --- a/src/buffer.inl.hh +++ b/src/buffer.inl.hh @@ -99,21 +99,23 @@ inline BufferCoord Buffer::end_coord() const } inline BufferIterator::BufferIterator(const Buffer& buffer, BufferCoord coord) noexcept - : BufferIterator{buffer.m_lines, coord} {} + : BufferIterator{buffer.m_lines.data(), buffer.line_count(), coord} {} -inline BufferIterator::BufferIterator(ArrayView lines, BufferCoord coord) noexcept - : m_lines{lines}, m_coord{coord}, - m_line{(size_t)coord.line < m_lines.size() ? m_lines[(size_t)coord.line]->strview() : StringView{}} {} +inline BufferIterator::BufferIterator(const StringDataPtr* lines, LineCount line_count, BufferCoord coord) noexcept + : m_lines{lines}, + m_line{coord.line < line_count ? m_lines[(size_t)coord.line]->strview() : StringView{}}, + m_line_count{line_count}, + m_coord{coord} {} inline bool BufferIterator::operator==(const BufferIterator& iterator) const noexcept { - kak_assert(m_lines.pointer() == iterator.m_lines.pointer()); + kak_assert(m_lines == iterator.m_lines); return m_coord == iterator.m_coord; } inline auto BufferIterator::operator<=>(const BufferIterator& iterator) const noexcept { - kak_assert(m_lines.pointer() == iterator.m_lines.pointer()); + kak_assert(m_lines == iterator.m_lines); return (m_coord <=> iterator.m_coord); } @@ -130,37 +132,37 @@ inline const char& BufferIterator::operator*() const noexcept inline const char& BufferIterator::operator[](size_t n) const noexcept { - auto coord = Buffer::advance(m_lines, m_coord, n); + auto coord = Buffer::advance({m_lines, (size_t)(int)m_line_count}, m_coord, n); return m_lines[(size_t)coord.line]->strview()[coord.column]; } inline size_t BufferIterator::operator-(const BufferIterator& iterator) const { - kak_assert(m_lines.pointer() == iterator.m_lines.pointer()); - return (size_t)Buffer::distance(m_lines, iterator.m_coord, m_coord); + kak_assert(m_lines == iterator.m_lines); + return (size_t)Buffer::distance({m_lines, (size_t)(int)m_line_count}, iterator.m_coord, m_coord); } inline BufferIterator BufferIterator::operator+(ByteCount size) const { kak_assert(*this); - return { m_lines, Buffer::advance(m_lines, m_coord, size) }; + return { m_lines, m_line_count, Buffer::advance({m_lines, (size_t)(int)m_line_count}, m_coord, size) }; } inline BufferIterator BufferIterator::operator-(ByteCount size) const { - return { m_lines, Buffer::advance(m_lines, m_coord, -size) }; + return { m_lines, m_line_count, Buffer::advance({m_lines, (size_t)(int)m_line_count}, m_coord, -size) }; } inline BufferIterator& BufferIterator::operator+=(ByteCount size) { - m_coord = Buffer::advance(m_lines, m_coord, size); + m_coord = Buffer::advance({m_lines, (size_t)(int)m_line_count}, m_coord, size); m_line = m_lines[(size_t)m_coord.line]->strview(); return *this; } inline BufferIterator& BufferIterator::operator-=(ByteCount size) { - m_coord = Buffer::advance(m_lines, m_coord, -size); + m_coord = Buffer::advance({m_lines, (size_t)(int)m_line_count}, m_coord, -size); m_line = m_lines[(size_t)m_coord.line]->strview(); return *this; } @@ -169,7 +171,7 @@ inline BufferIterator& BufferIterator::operator++() { if (++m_coord.column == m_line.length()) { - m_line = ((size_t)++m_coord.line < m_lines.size()) ? + m_line = ((size_t)++m_coord.line < m_line_count) ? m_lines[(size_t)m_coord.line]->strview() : StringView{}; m_coord.column = 0; } -- cgit v1.2.3 From dd1ea05bbcb989441ec5516d3b84562afa27d61a Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Tue, 3 Dec 2024 22:46:17 +1100 Subject: Various small code simplifications/tweaks in ThreadedRegexVM --- src/array_view.hh | 3 +++ src/regex_impl.hh | 30 +++++++++++++++--------------- 2 files changed, 18 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/array_view.hh b/src/array_view.hh index 98f3c811..1409ebc3 100644 --- a/src/array_view.hh +++ b/src/array_view.hh @@ -77,6 +77,9 @@ template requires std::contiguous_iterator ArrayView(It begin, It end) -> ArrayView>; +template +ArrayView(Container& c) -> ArrayView>; + template using ConstArrayView = ArrayView; diff --git a/src/regex_impl.hh b/src/regex_impl.hh index ae46ae38..4d28ab9b 100644 --- a/src/regex_impl.hh +++ b/src/regex_impl.hh @@ -275,7 +275,7 @@ public: { if (search) { - start = find_next_start(start, config, *start_desc); + start = find_next_start(start, config.end, *start_desc); if (start == config.end) // If start_desc is not null, it means we consume at least one char return false; } @@ -373,8 +373,9 @@ private: // Steps a thread until it consumes the current character, matches or fail [[gnu::always_inline]] - void step_thread(const Iterator& pos, Codepoint cp, uint16_t current_step, Thread thread, const ExecConfig& config) + void step_next_thread(const Iterator& pos, Codepoint cp, uint16_t current_step, const ExecConfig& config) { + Thread thread = m_threads.pop_current(); auto failed = [this, &thread]() { release_saves(thread.saves); }; @@ -481,9 +482,9 @@ private: m_captures = -1; m_threads.ensure_initial_capacity(); - ConstArrayView insts{m_program.instructions}; - const auto* first_inst = insts.begin() + (forward ? 0 : m_program.first_backward_inst); - m_threads.push_current({first_inst, -1}); + const auto insts = forward ? ArrayView(m_program.instructions).subrange(0, m_program.first_backward_inst) + : ArrayView(m_program.instructions).subrange(m_program.first_backward_inst); + m_threads.push_current({insts.begin(), -1}); const auto* start_desc = (forward ? m_program.forward_start_desc : m_program.backward_start_desc).get(); auto next_start = pos; @@ -502,8 +503,7 @@ private: idle_func(); // We wrapped, avoid potential collision on inst.last_step by resetting them - for (auto& inst : forward ? insts.subrange(0, m_program.first_backward_inst) - : insts.subrange(m_program.first_backward_inst)) + for (auto& inst : insts) inst.last_step = 0; current_step = 1; // step 0 is never valid } @@ -512,7 +512,7 @@ private: Codepoint cp = codepoint(next, config); while (not m_threads.current_is_empty()) - step_thread(pos, cp, current_step, m_threads.pop_current(), config); + step_next_thread(pos, cp, current_step, config); if (pos == config.end or (m_threads.next_is_empty() and (not search or m_found_match)) or @@ -528,24 +528,24 @@ private: if (start_desc) { if (pos == next_start) - next_start = find_next_start(next, config, *start_desc); + next_start = find_next_start(next, config.end, *start_desc); if (m_threads.next_is_empty()) next = next_start; } if (not start_desc or next == next_start) - m_threads.push_next({first_inst, -1}); + m_threads.push_next({insts.begin(), -1}); } pos = next; m_threads.swap_next(); } } - static Iterator find_next_start(Iterator start, const ExecConfig& config, const StartDesc& start_desc) + static Iterator find_next_start(Iterator start, Sentinel end, const StartDesc& start_desc) { auto pos = start; if (char start_byte = start_desc.start_byte) { - while (pos != config.end) + while (pos != end) { if constexpr (forward) { @@ -555,7 +555,7 @@ private: } else { - auto prev = utf8::previous(pos, config.end); + auto prev = utf8::previous(pos, end); if (*prev == start_byte) return utf8::advance(pos, start, CharCount(start_desc.offset)); pos = prev; @@ -563,7 +563,7 @@ private: } } - while (pos != config.end) + while (pos != end) { static_assert(StartDesc::count <= 256, "start desc should be ascii only"); if constexpr (forward) @@ -574,7 +574,7 @@ private: } else { - auto prev = utf8::previous(pos, config.end); + auto prev = utf8::previous(pos, end); if (start_desc.map[static_cast(*prev)]) return utf8::advance(pos, start, CharCount(start_desc.offset)); pos = prev; -- cgit v1.2.3 From dac922e24c48d297de063786be3065554409cc71 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Wed, 4 Dec 2024 22:18:51 +1100 Subject: Use default comparison impl for LineAndColumn and StronglyTypedNumber This is a bit simpler and should leave more leeway to the optimizer to detect it can compare the whole struct. --- src/coord.hh | 20 ++++++++------------ src/units.hh | 31 +++++++------------------------ 2 files changed, 15 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/coord.hh b/src/coord.hh index 8420dcee..30c4ce74 100644 --- a/src/coord.hh +++ b/src/coord.hh @@ -41,18 +41,8 @@ struct LineAndColumn return *static_cast(this); } - [[gnu::always_inline]] - constexpr friend auto operator<=>(const EffectiveType& lhs, const EffectiveType& rhs) - { - return (lhs.line != rhs.line) ? lhs.line <=> rhs.line - : lhs.column <=> rhs.column; - } - - [[gnu::always_inline]] - constexpr friend bool operator==(const EffectiveType& lhs, const EffectiveType& rhs) - { - return lhs.line == rhs.line and lhs.column == rhs.column; - } + constexpr friend auto operator<=>(const LineAndColumn& lhs, const LineAndColumn& rhs) = default; + constexpr friend bool operator==(const LineAndColumn& lhs, const LineAndColumn& rhs) = default; friend constexpr size_t hash_value(const EffectiveType& val) { @@ -65,6 +55,9 @@ struct BufferCoord : LineAndColumn [[gnu::always_inline]] constexpr BufferCoord(LineCount line = 0, ByteCount column = 0) : LineAndColumn{line, column} {} + + constexpr friend auto operator<=>(const BufferCoord& lhs, const BufferCoord& rhs) = default; + constexpr friend bool operator==(const BufferCoord& lhs, const BufferCoord& rhs) = default; }; struct DisplayCoord : LineAndColumn @@ -73,6 +66,9 @@ struct DisplayCoord : LineAndColumn constexpr DisplayCoord(LineCount line = 0, ColumnCount column = 0) : LineAndColumn{line, column} {} + constexpr friend auto operator<=>(const DisplayCoord& lhs, const DisplayCoord& rhs) = default; + constexpr friend bool operator==(const DisplayCoord& lhs, const DisplayCoord& rhs) = default; + static constexpr const char* option_type_name = "coord"; }; diff --git a/src/units.hh b/src/units.hh index ff4ed882..9d2511b9 100644 --- a/src/units.hh +++ b/src/units.hh @@ -16,7 +16,7 @@ public: StronglyTypedNumber() = default; [[gnu::always_inline]] - explicit constexpr StronglyTypedNumber(ValueType value) + constexpr StronglyTypedNumber(ValueType value) : m_value(value) { static_assert(std::is_base_of::value, @@ -82,13 +82,8 @@ public: RealType& operator%=(RealType other) { m_value %= other.m_value; return static_cast(*this); } - [[gnu::always_inline]] - constexpr friend bool operator==(RealType lhs, RealType rhs) - { return lhs.m_value == rhs.m_value; } - - [[gnu::always_inline]] - constexpr friend auto operator<=>(RealType lhs, RealType rhs) - { return lhs.m_value <=> rhs.m_value; } + constexpr friend bool operator==(StronglyTypedNumber lhs, StronglyTypedNumber rhs) = default; + constexpr friend auto operator<=>(StronglyTypedNumber lhs, StronglyTypedNumber rhs) = default; [[gnu::always_inline]] constexpr bool operator!() const @@ -110,10 +105,7 @@ protected: struct LineCount : public StronglyTypedNumber { - LineCount() = default; - - [[gnu::always_inline]] - constexpr LineCount(int value) : StronglyTypedNumber(value) {} + using StronglyTypedNumber::StronglyTypedNumber; }; [[gnu::always_inline]] @@ -124,10 +116,7 @@ inline constexpr LineCount operator"" _line(unsigned long long int value) struct ByteCount : public StronglyTypedNumber { - ByteCount() = default; - - [[gnu::always_inline]] - constexpr ByteCount(int value) : StronglyTypedNumber(value) {} + using StronglyTypedNumber::StronglyTypedNumber; }; [[gnu::always_inline]] @@ -142,10 +131,7 @@ Byte* operator+(Byte* ptr, ByteCount count) { return ptr + (int)count; } struct CharCount : public StronglyTypedNumber { - CharCount() = default; - - [[gnu::always_inline]] - constexpr CharCount(int value) : StronglyTypedNumber(value) {} + using StronglyTypedNumber::StronglyTypedNumber; }; [[gnu::always_inline]] @@ -156,10 +142,7 @@ inline constexpr CharCount operator"" _char(unsigned long long int value) struct ColumnCount : public StronglyTypedNumber { - ColumnCount() = default; - - [[gnu::always_inline]] - constexpr ColumnCount(int value) : StronglyTypedNumber(value) {} + using StronglyTypedNumber::StronglyTypedNumber; }; [[gnu::always_inline]] -- cgit v1.2.3 From 98ed5847de20f04d0595d5ac08da06ff8aa5c1b2 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Thu, 5 Dec 2024 18:40:55 +1100 Subject: Split utf8::read_codepoint between single byte and multibyte code Make read_codepoint_multibyte noinline so that the common case single byte case gets inlined. --- src/utf8.hh | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/utf8.hh b/src/utf8.hh index 0ba8bdef..e5643214 100644 --- a/src/utf8.hh +++ b/src/utf8.hh @@ -39,21 +39,12 @@ struct Pass } -// returns the codepoint of the character whose first byte -// is pointed by it template -Codepoint read_codepoint(Iterator& it, const Sentinel& end) +[[gnu::noinline]] +Codepoint read_codepoint_multibyte(Iterator& it, const Sentinel& end, char byte) noexcept(noexcept(InvalidPolicy{}(0))) { - if (it == end) - return InvalidPolicy{}(-1); - // According to rfc3629, UTF-8 allows only up to 4 bytes. - // (21 bits codepoint) - unsigned char byte = read(it); - if ((byte & 0x80) == 0) // 0xxxxxxx - return byte; - if (it == end) return InvalidPolicy{}(byte); @@ -81,6 +72,21 @@ Codepoint read_codepoint(Iterator& it, const Sentinel& end) return InvalidPolicy{}(byte); } +// returns the codepoint of the character whose first byte +// is pointed by it +template +Codepoint read_codepoint(Iterator& it, const Sentinel& end) + noexcept(noexcept(InvalidPolicy{}(0))) +{ + if (it == end) + return InvalidPolicy{}(-1); + unsigned char byte = read(it); + if ((byte & 0x80) == 0) [[likely]] // 0xxxxxxx + return byte; + return read_codepoint_multibyte(it, end, byte); +} + template Codepoint codepoint(Iterator it, const Sentinel& end) -- cgit v1.2.3 From ee4ba97e3ea6553cc224bc2942f59c603c07e82c Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Thu, 5 Dec 2024 21:59:36 +1100 Subject: Fix parameter passing in find_next_start --- src/regex_impl.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/regex_impl.hh b/src/regex_impl.hh index 4d28ab9b..4fea5cd3 100644 --- a/src/regex_impl.hh +++ b/src/regex_impl.hh @@ -540,7 +540,7 @@ private: } } - static Iterator find_next_start(Iterator start, Sentinel end, const StartDesc& start_desc) + static Iterator find_next_start(const Iterator& start, const Sentinel& end, const StartDesc& start_desc) { auto pos = start; if (char start_byte = start_desc.start_byte) -- cgit v1.2.3 From 34f8ca48844ce6f5321538c1d389ba788e80735a Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Mon, 9 Dec 2024 12:37:14 +1100 Subject: Tweak inlining around thread stack push/pulls Ensure push/pulls operations are inlined except for the uncommon grow. --- src/regex_impl.hh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/regex_impl.hh b/src/regex_impl.hh index 4fea5cd3..a23eefa7 100644 --- a/src/regex_impl.hh +++ b/src/regex_impl.hh @@ -678,10 +678,14 @@ private: bool current_is_empty() const { return m_current == m_next_begin; } bool next_is_empty() const { return m_next_end == m_next_begin; } + [[gnu::always_inline]] void push_current(Thread thread) { m_data[decrement(m_current)] = thread; grow_ifn(true); } + [[gnu::always_inline]] Thread pop_current() { return m_data[post_increment(m_current)]; } + [[gnu::always_inline]] void push_next(Thread thread) { m_data[post_increment(m_next_end)] = thread; grow_ifn(false); } + [[gnu::always_inline]] Thread pop_next() { return m_data[decrement(m_next_end)]; } void swap_next() @@ -701,11 +705,16 @@ private: m_capacity = initial_capacity; } + [[gnu::always_inline]] void grow_ifn(bool pushed_current) { - if (m_current != m_next_end) - return; + if (m_current == m_next_end) + grow(pushed_current); + } + [[gnu::noinline]] + void grow(bool pushed_current) + { const auto new_capacity = m_capacity * 2; Thread* new_data = new Thread[new_capacity]; Thread* old_data = m_data.get(); -- cgit v1.2.3 From 816a8c35a8cfa0cc8b7f9d80dd3c0e721ba3c273 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sun, 24 Nov 2024 10:19:31 +0100 Subject: Allow cancelling "write fifo" with Just like "echo -to-file fifo". --- src/file.cc | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/file.cc b/src/file.cc index 262caa09..64c9321a 100644 --- a/src/file.cc +++ b/src/file.cc @@ -277,18 +277,25 @@ void write(int fd, StringView data) template void write(int fd, StringView data); template void write(int fd, StringView data); - -void write_to_file(StringView filename, StringView data) +static int create_file(const char* filename) { - int fd = -1; + int fd; const int flags = O_CREAT | O_WRONLY | O_TRUNC | (EventManager::has_instance() ? O_NONBLOCK : 0); - while ((fd = open(filename.zstr(), flags, 0644)) == -1) + while ((fd = open(filename, flags, 0644)) == -1) { if (errno == ENXIO and EventManager::has_instance()) // trying to open a FIFO with no readers yet EventManager::instance().handle_next_events(EventMode::Urgent, nullptr, std::chrono::nanoseconds{1'000'000}); else - throw file_access_error(filename, strerror(errno)); + return -1; } + return fd; +} + +void write_to_file(StringView filename, StringView data) +{ + int fd = create_file(filename.zstr()); + if (fd == -1) + throw file_access_error(filename, strerror(errno)); auto close_fd = on_scope_end([fd]{ close(fd); }); write(fd, data); } @@ -357,7 +364,7 @@ void write_buffer_to_file(Buffer& buffer, StringView filename, char temp_filename[PATH_MAX]; const int fd = replace ? open_temp_file(filename, temp_filename) - : open(zfilename, O_CREAT | O_WRONLY | O_TRUNC, 0644); + : create_file(zfilename); if (fd == -1) { auto saved_errno = errno; -- cgit v1.2.3 From 7105584538f84d1c244809601fd3e573e8d6080c Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sun, 24 Nov 2024 10:19:32 +0100 Subject: Print elapsed time when blocked on opening file for writing Extract the logic for "waiting for shell to finish" and reuse it for potentially blocking calls to open() that use the O_WRONLY flags. --- src/client.cc | 32 ++++++++++++++++++++++++++++++++ src/client.hh | 14 ++++++++++++++ src/commands.cc | 6 +++--- src/file.cc | 18 ++++++++++++------ src/file.hh | 5 +++-- src/main.cc | 5 +++-- src/shell_manager.cc | 30 ++++++------------------------ 7 files changed, 73 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/client.cc b/src/client.cc index 611216a7..2fa8e8fb 100644 --- a/src/client.cc +++ b/src/client.cc @@ -1,5 +1,6 @@ #include "client.hh" +#include "clock.hh" #include "context.hh" #include "buffer_utils.hh" #include "debug.hh" @@ -509,4 +510,35 @@ void Client::clear_pending() m_pending_clear = PendingClear::None; } +constexpr std::chrono::seconds wait_timeout{1}; + +BusyIndicator::BusyIndicator(const Context& context, + std::function status_message, + TimePoint wait_time) + : m_context(context), + m_timer{wait_time + wait_timeout, + [this, status_message = std::move(status_message), wait_time](Timer& timer) { + if (not m_context.has_client()) + return; + using namespace std::chrono; + const auto now = Clock::now(); + timer.set_next_date(now + wait_timeout); + + auto& client = m_context.client(); + if (not m_previous_status) + m_previous_status = client.current_status(); + + client.print_status(status_message(duration_cast(now - wait_time))); + client.redraw_ifn(); + }, EventMode::Urgent} {} + +BusyIndicator::~BusyIndicator() +{ + if (m_previous_status and std::uncaught_exceptions() == 0) // restore the status line + { + m_context.print_status(std::move(*m_previous_status)); + m_context.client().redraw_ifn(); + } +} + } diff --git a/src/client.hh b/src/client.hh index 05b091ae..43584c42 100644 --- a/src/client.hh +++ b/src/client.hh @@ -2,6 +2,7 @@ #define client_hh_INCLUDED #include "array.hh" +#include "clock.hh" #include "display_buffer.hh" #include "env_vars.hh" #include "input_handler.hh" @@ -165,6 +166,19 @@ constexpr auto enum_desc(Meta::Type) }); } +class BusyIndicator +{ +public: + BusyIndicator(const Context& context, + std::function status_message, + TimePoint wait_time = Clock::now()); + ~BusyIndicator(); +private: + const Context& m_context; + Timer m_timer; + Optional m_previous_status; +}; + } #endif // client_hh_INCLUDED diff --git a/src/commands.cc b/src/commands.cc index 90f7a23e..0f892004 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -618,7 +618,7 @@ void do_write_buffer(Context& context, Optional filename, WriteFlags fla auto method = write_method.value_or_compute([&] { return context.options()["writemethod"].get(); }); context.hooks().run_hook(Hook::BufWritePre, effective_filename, context); - write_buffer_to_file(buffer, effective_filename, method, flags); + write_buffer_to_file(context, buffer, effective_filename, method, flags); context.hooks().run_hook(Hook::BufWritePost, effective_filename, context); } @@ -673,7 +673,7 @@ void write_all_buffers(const Context& context, bool sync = false, Optional(); }); auto flags = sync ? WriteFlags::Sync : WriteFlags::None; buffer->run_hook_in_own_context(Hook::BufWritePre, buffer->name(), context.name()); - write_buffer_to_file(*buffer, buffer->name(), method, flags); + write_buffer_to_file(context, *buffer, buffer->name(), method, flags); buffer->run_hook_in_own_context(Hook::BufWritePost, buffer->name(), context.name()); } } @@ -1555,7 +1555,7 @@ const CommandDesc echo_cmd = { message.push_back('\n'); if (auto filename = parser.get_switch("to-file")) - write_to_file(*filename, message); + write_to_file(context, *filename, message); else if (auto command = parser.get_switch("to-shell-script")) ShellManager::instance().eval(*command, context, message, ShellManager::Flags::None, shell_context); else if (parser.get_switch("debug")) diff --git a/src/file.cc b/src/file.cc index 64c9321a..2fbf2e78 100644 --- a/src/file.cc +++ b/src/file.cc @@ -2,6 +2,7 @@ #include "assert.hh" #include "buffer.hh" +#include "client.hh" #include "exception.hh" #include "flags.hh" #include "event_manager.hh" @@ -277,23 +278,28 @@ void write(int fd, StringView data) template void write(int fd, StringView data); template void write(int fd, StringView data); -static int create_file(const char* filename) +static int create_file(const Context& context, const char* filename) { int fd; const int flags = O_CREAT | O_WRONLY | O_TRUNC | (EventManager::has_instance() ? O_NONBLOCK : 0); + using namespace std::chrono; + BusyIndicator busy_indicator{context, [&](seconds elapsed) { + return DisplayLine{format("waiting to open file ({}s)", elapsed.count()), + context.faces()["Information"]}; + }}; while ((fd = open(filename, flags, 0644)) == -1) { if (errno == ENXIO and EventManager::has_instance()) // trying to open a FIFO with no readers yet - EventManager::instance().handle_next_events(EventMode::Urgent, nullptr, std::chrono::nanoseconds{1'000'000}); + EventManager::instance().handle_next_events(EventMode::Urgent, nullptr, nanoseconds{1'000'000}); else return -1; } return fd; } -void write_to_file(StringView filename, StringView data) +void write_to_file(const Context& context, StringView filename, StringView data) { - int fd = create_file(filename.zstr()); + int fd = create_file(context, filename.zstr()); if (fd == -1) throw file_access_error(filename, strerror(errno)); auto close_fd = on_scope_end([fd]{ close(fd); }); @@ -343,7 +349,7 @@ int open_temp_file(StringView filename) return open_temp_file(filename, buffer); } -void write_buffer_to_file(Buffer& buffer, StringView filename, +void write_buffer_to_file(const Context& context, Buffer& buffer, StringView filename, WriteMethod method, WriteFlags flags) { auto zfilename = filename.zstr(); @@ -364,7 +370,7 @@ void write_buffer_to_file(Buffer& buffer, StringView filename, char temp_filename[PATH_MAX]; const int fd = replace ? open_temp_file(filename, temp_filename) - : create_file(zfilename); + : create_file(context, zfilename); if (fd == -1) { auto saved_errno = errno; diff --git a/src/file.hh b/src/file.hh index ead88c43..a0b55e56 100644 --- a/src/file.hh +++ b/src/file.hh @@ -42,7 +42,8 @@ String read_fd(int fd, bool text = false); String read_file(StringView filename, bool text = false); template void write(int fd, StringView data); -void write_to_file(StringView filename, StringView data); +class Context; +void write_to_file(const Context&, StringView filename, StringView data); struct MappedFile { @@ -76,7 +77,7 @@ enum class WriteFlags }; constexpr bool with_bit_ops(Meta::Type) { return true; } -void write_buffer_to_file(Buffer& buffer, StringView filename, +void write_buffer_to_file(const Context& context, Buffer& buffer, StringView filename, WriteMethod method, WriteFlags flags); void write_buffer_to_fd(Buffer& buffer, int fd); void write_buffer_to_backup_file(Buffer& buffer); diff --git a/src/main.cc b/src/main.cc index e360a6d8..48368ab6 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1007,14 +1007,15 @@ int run_filter(StringView keystr, ConstArrayView files, bool quiet, } }; + Context empty_context{Context::EmptyContextFlag{}}; for (auto& file : files) { Buffer* buffer = open_file_buffer(file, Buffer::Flags::NoHooks); if (not suffix_backup.empty()) - write_buffer_to_file(*buffer, buffer->name() + suffix_backup, + write_buffer_to_file(empty_context, *buffer, buffer->name() + suffix_backup, WriteMethod::Overwrite, WriteFlags::None); apply_to_buffer(*buffer); - write_buffer_to_file(*buffer, buffer->name(), + write_buffer_to_file(empty_context, *buffer, buffer->name(), WriteMethod::Overwrite, WriteFlags::None); buffer_manager.delete_buffer(*buffer); } diff --git a/src/shell_manager.cc b/src/shell_manager.cc index 6b656191..0baf77c8 100644 --- a/src/shell_manager.cc +++ b/src/shell_manager.cc @@ -14,6 +14,7 @@ #include "regex.hh" #include +#include #include #include #include @@ -316,24 +317,11 @@ std::pair ShellManager::eval( bool failed = false; using namespace std::chrono; - static constexpr seconds wait_timeout{1}; - Optional previous_status; - Timer wait_timer{wait_time + wait_timeout, [&](Timer& timer) { - if (not context.has_client()) - return; - - const auto now = Clock::now(); - timer.set_next_date(now + wait_timeout); - auto& client = context.client(); - if (not previous_status) - previous_status = client.current_status(); - - client.print_status({format("waiting for shell command to finish{} ({}s)", - terminated ? " (shell terminated)" : "", - duration_cast(now - wait_time).count()), - context.faces()[failed ? "Error" : "Information"]}); - client.redraw_ifn(); - }, EventMode::Urgent}; + BusyIndicator busy_indicator{context, [&](seconds elapsed) { + return DisplayLine{format("waiting for shell command to finish{} ({}s)", + terminated ? " (shell terminated)" : "", elapsed.count()), + context.faces()[failed ? "Error" : "Information"]}; + }}; bool cancelling = false; while (not terminated or shell.in or @@ -373,12 +361,6 @@ std::pair ShellManager::eval( if (cancelling) throw cancel{}; - if (previous_status) // restore the status line - { - context.print_status(std::move(*previous_status)); - context.client().redraw_ifn(); - } - return { std::move(stdout_contents), WIFEXITED(status) ? WEXITSTATUS(status) : -1 }; } -- cgit v1.2.3 From 9c458c50661446fc6e7295787b06422137af099d Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Thu, 5 Dec 2024 19:22:03 +1100 Subject: Rework split between exec and exec_program method Split last iteration out of the loop so that optimizer can elide most comparisons between pos and config.end as its always different in the loop and equal at last call. --- src/regex_impl.hh | 83 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 42 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/regex_impl.hh b/src/regex_impl.hh index a23eefa7..2f7fad4e 100644 --- a/src/regex_impl.hh +++ b/src/regex_impl.hh @@ -260,8 +260,6 @@ public: if (flags & RegexExecFlags::NotInitialNull and begin == end) return false; - constexpr bool search = (mode & RegexMode::Search); - const ExecConfig config{ Sentinel{forward ? begin : end}, Sentinel{forward ? end : begin}, @@ -270,24 +268,11 @@ public: flags }; - Iterator start = forward ? begin : end; - if (const auto* start_desc = (forward ? m_program.forward_start_desc : m_program.backward_start_desc).get()) - { - if (search) - { - start = find_next_start(start, config.end, *start_desc); - if (start == config.end) // If start_desc is not null, it means we consume at least one char - return false; - } - else if (start != config.end) - { - const unsigned char c = forward ? *start : *utf8::previous(start, config.end); - if (not start_desc->map[c]) - return false; - } - } + exec_program(forward ? begin : end, config, idle_func); - return exec_program(std::move(start), config, idle_func); + while (not m_threads.next_is_empty()) + release_saves(m_threads.pop_next().saves); + return m_found_match; } ArrayView captures() const @@ -475,31 +460,44 @@ private: return failed(); } - bool exec_program(Iterator pos, const ExecConfig& config, auto&& idle_func) + void exec_program(const Iterator& start, const ExecConfig& config, auto&& idle_func) { kak_assert(m_threads.current_is_empty() and m_threads.next_is_empty()); + m_threads.ensure_initial_capacity(); release_saves(m_captures); m_captures = -1; - m_threads.ensure_initial_capacity(); + m_found_match = false; + + const auto* start_desc = (forward ? m_program.forward_start_desc : m_program.backward_start_desc).get(); + Iterator next_start = start; + if (start_desc) + { + if (mode & RegexMode::Search) + { + next_start = find_next_start(start, config.end, *start_desc); + if (next_start == config.end) // If start_desc is not null, it means we consume at least one char + return; + } + else if (start != config.end) + { + const unsigned char c = forward ? *start : *utf8::previous(start, config.end); + if (not start_desc->map[c]) + return; + } + } const auto insts = forward ? ArrayView(m_program.instructions).subrange(0, m_program.first_backward_inst) : ArrayView(m_program.instructions).subrange(m_program.first_backward_inst); m_threads.push_current({insts.begin(), -1}); - const auto* start_desc = (forward ? m_program.forward_start_desc : m_program.backward_start_desc).get(); - auto next_start = pos; - - constexpr bool search = mode & RegexMode::Search; - constexpr bool any_match = mode & RegexMode::AnyMatch; uint16_t current_step = -1; - constexpr size_t idle_frequency = 255; // Run idle loop every 255 * 65536 == 16M codepoints - size_t wrap_count = 0; - m_found_match = false; - while (true) // Iterate on all codepoints and once at the end + uint8_t idle_count = 0; // Run idle loop every 256 * 65536 == 16M codepoints + auto pos = next_start; + while (pos != config.end) { if (++current_step == 0) { - if ((++wrap_count % idle_frequency) == 0) + if (++idle_count == 0) idle_func(); // We wrapped, avoid potential collision on inst.last_step by resetting them @@ -514,16 +512,7 @@ private: while (not m_threads.current_is_empty()) step_next_thread(pos, cp, current_step, config); - if (pos == config.end or - (m_threads.next_is_empty() and (not search or m_found_match)) or - (m_found_match and any_match)) - { - while (not m_threads.next_is_empty()) - release_saves(m_threads.pop_next().saves); - return m_found_match; - } - - if (search and not m_found_match) + if ((mode & RegexMode::Search) and not m_found_match) { if (start_desc) { @@ -535,9 +524,21 @@ private: if (not start_desc or next == next_start) m_threads.push_next({insts.begin(), -1}); } + else if (m_threads.next_is_empty() or (m_found_match and (mode & RegexMode::AnyMatch))) + return; + pos = next; m_threads.swap_next(); } + + if (++current_step == 0) + { + for (auto& inst : insts) + inst.last_step = 0; + current_step = 1; // step 0 is never valid + } + while (not m_threads.current_is_empty()) + step_next_thread(pos, -1, current_step, config); } static Iterator find_next_start(const Iterator& start, const Sentinel& end, const StartDesc& start_desc) -- cgit v1.2.3