kakoune/src/input_handler.hh

213 lines
5.6 KiB
C++
Raw Normal View History

#ifndef input_handler_hh_INCLUDED
#define input_handler_hh_INCLUDED
#include "completion.hh"
#include "constexpr_utils.hh"
#include "context.hh"
#include "env_vars.hh"
#include "face.hh"
2013-12-15 20:41:32 +01:00
#include "normal.hh"
#include "keys.hh"
#include "string.hh"
#include "utils.hh"
#include "safe_ptr.hh"
#include "display_buffer.hh"
#include "event_manager.hh"
namespace Kakoune
{
enum class PromptEvent
{
Change,
Abort,
Validate
};
using PromptCallback = std::function<void (StringView, PromptEvent, Context&)>;
2023-08-12 19:10:52 +02:00
enum class PromptFlags
{
None = 0,
Password = 1 << 0,
DropHistoryEntriesWithBlankPrefix = 1 << 1,
Search = 1 << 2,
};
constexpr bool with_bit_ops(Meta::Type<PromptFlags>) { return true; }
using KeyCallback = std::function<void (Key, Context&)>;
class InputMode;
2015-04-11 18:22:37 +02:00
enum class KeymapMode : char;
enum class CursorMode;
2019-01-24 11:02:07 +01:00
using PromptCompleter = std::function<Completions (const Context&, CompletionFlags,
StringView, ByteCount)>;
enum class InsertMode : unsigned
{
Insert,
Append,
Replace,
InsertAtLineBegin,
AppendAtLineEnd,
OpenLineBelow,
OpenLineAbove
};
2019-01-24 11:02:07 +01:00
struct ModeInfo
{
DisplayLine display_line;
std::optional<NormalParams> normal_params;
};
class InputHandler : public SafeCountable
{
public:
InputHandler(SelectionList selections,
Context::Flags flags = Context::Flags::None,
String name = "");
~InputHandler();
// switch to insert mode
void insert(InsertMode mode, int count);
// repeat last insert mode key sequence
void repeat_last_insert();
// insert a string without affecting the mode stack
void paste(StringView content);
// enter prompt mode, callback is called on each change,
// abort or validation with corresponding PromptEvent value
// returns to normal mode after validation if callback does
// not change the mode itself
void prompt(StringView prompt, String initstr, String emptystr,
2019-06-05 15:19:27 +02:00
Face prompt_face, PromptFlags flags, char history_register,
2019-01-24 11:02:07 +01:00
PromptCompleter completer, PromptCallback callback);
void set_prompt_face(Face prompt_face);
Disable history only for prompts that are never shown in the UI My terminal allows to map <c-[> and <esc> independently. I like to use <c-[> as escape key so I have this mapping: map global prompt <c-[> <esc> Unfortunately, this is not equivalent to <esc>. Since mappings are run with history disabled, <c-[> will not add the command to the prompt history. So disabling command history inside mappings is wrong in case the command prompt was created before mapping execution. The behavior should be: "a prompt that is both created and closed inside a noninteractive context does not add to prompt history", where "noninteractive" means inside a mapping, hook, command, execute-keys or evaluate-commands. Implement this behavior, it should better meet user expectations. Scripts can always use "set-register" to add to history. Here are my test cases: 1. Basic regression test (needs above mapping): :nop should be added to history<c-[> --- 2. Create the prompt in a noninteractive context: :exec %{:} now we're back in the interactive context, so we can type: nop should be added to history<ret> --- 3. To check if it works for nested prompts, first set up this mapping. map global prompt <c-j> '<a-semicolon>:nop should NOT be added to history<ret>' map global prompt <c-h> '<a-semicolon>:nop should be added to history first' Then type :nop should be added to history second<c-j><c-h><ret><ret> the inner command run by <c-j> should not be added to history because it only existed in a noninteractive context. --- See also the discussion https://github.com/mawww/kakoune/pull/4692 We could automate the tests if we had a test setup that allowed feeding interactive key input into Kakoune instead of using "execute-commands". Some projects use tmux, or maybe we can mock the terminal.
2022-08-29 08:00:53 +02:00
bool history_enabled() const;
// execute callback on next keypress and returns to normal mode
// if callback does not change the mode itself
void on_next_key(StringView mode_name, KeymapMode mode, KeyCallback callback,
Timer::Callback idle_callback = Timer::Callback{});
// process the given key
void handle_key(Key key);
void refresh_ifn();
void start_recording(char reg);
bool is_recording() const;
void stop_recording();
char recording_reg() const { return m_recording_reg; }
void reset_normal_mode();
Context& context() { return m_context; }
const Context& context() const { return m_context; }
ModeInfo mode_info() const;
std::pair<CursorMode, DisplayCoord> get_cursor_info() const;
// Force an input handler into normal mode temporarily
struct ScopedForceNormal
{
ScopedForceNormal(InputHandler& handler, NormalParams params);
~ScopedForceNormal();
private:
InputHandler& m_handler;
InputMode* m_mode;
};
private:
Context m_context;
friend class InputMode;
Vector<RefPtr<InputMode>, MemoryDomain::Client> m_mode_stack;
InputMode& current_mode() const { return *m_mode_stack.back(); }
void push_mode(InputMode* new_mode);
void pop_mode(InputMode* current_mode);
struct Insertion{
NestedBool recording;
InsertMode mode;
Vector<Key> keys;
bool disable_hooks;
int count;
} m_last_insert = { {}, InsertMode::Insert, {}, false, 1 };
char m_recording_reg = 0;
String m_recorded_keys;
int m_recording_level = -1;
int m_handle_key_level = 0;
};
enum class AutoInfo
{
None = 0,
Command = 1 << 0,
OnKey = 1 << 1,
Normal = 1 << 2
};
constexpr bool with_bit_ops(Meta::Type<AutoInfo>) { return true; }
constexpr auto enum_desc(Meta::Type<AutoInfo>)
{
return make_array<EnumDesc<AutoInfo>>({
{ AutoInfo::Command, "command"},
{ AutoInfo::OnKey, "onkey"},
{ AutoInfo::Normal, "normal" }
});
}
enum class AutoComplete
{
None = 0,
Insert = 0b01,
Prompt = 0b10
};
constexpr bool with_bit_ops(Meta::Type<AutoComplete>) { return true; }
constexpr auto enum_desc(Meta::Type<AutoComplete>)
{
return make_array<EnumDesc<AutoComplete>>({
{ AutoComplete::Insert, "insert"},
{ AutoComplete::Prompt, "prompt" }
});
}
bool should_show_info(AutoInfo mask, const Context& context);
bool show_auto_info_ifn(StringView title, StringView info, AutoInfo mask, const Context& context);
void hide_auto_info_ifn(const Context& context, bool hide);
template<typename Cmd>
void on_next_key_with_autoinfo(const Context& context, StringView mode_name,
KeymapMode keymap_mode, Cmd cmd,
String title, String info)
{
context.input_handler().on_next_key(mode_name,
keymap_mode, [cmd](Key key, Context& context) mutable {
bool hide = should_show_info(AutoInfo::OnKey, context);
hide_auto_info_ifn(context, hide);
cmd(key, context);
2023-08-12 19:10:52 +02:00
}, [&context, title=std::move(title), info=std::move(info)](Timer&) {
show_auto_info_ifn(title, info, AutoInfo::OnKey, context);
2023-08-12 19:10:52 +02:00
});
}
enum class OnHiddenCursor {
PreserveSelections,
MoveCursor,
MoveCursorAndAnchor,
};
void scroll_window(Context& context, LineCount offset, OnHiddenCursor on_hidden_cursor);
}
#endif // input_handler_hh_INCLUDED