mirror of
https://github.com/mawww/kakoune.git
synced 2024-09-11 13:00:41 +03:00
Compare commits
11 Commits
171bce85da
...
63cf7812a3
Author | SHA1 | Date | |
---|---|---|---|
|
63cf7812a3 | ||
|
560e3631ec | ||
|
6ed01f402b | ||
|
1b2100753e | ||
|
1a52006c3d | ||
|
2d9886afe7 | ||
|
a250b96c18 | ||
|
714d3fddac | ||
|
f9570947eb | ||
|
38e71f45ad | ||
|
26561eea1d |
10
doc/kak.1
10
doc/kak.1
@ -24,6 +24,10 @@
|
||||
.Op Ar file ...
|
||||
.
|
||||
.Nm
|
||||
.Fl quote Sy raw|shell|kakoune
|
||||
.Op Ar string ...
|
||||
.
|
||||
.Nm
|
||||
.Fl p Ar session_id
|
||||
.
|
||||
.Nm
|
||||
@ -151,6 +155,12 @@ Begin in
|
||||
.Em readonly mode ,
|
||||
all the buffers opened will not be written to disk.
|
||||
.
|
||||
.It Fl quote Sy raw|shell|kakoune Op Ar string ...
|
||||
Escape one or more
|
||||
.Ar strings
|
||||
for interpolation into kakoune or shell scripts.
|
||||
Multiple strings will be escaped first and then joined with spaces inbetween.
|
||||
.
|
||||
.It Sy + Ns Ar line Ns Oo Sy \&: Ns Ar column Oc | Sy +:
|
||||
Specify a target line and column for the first file.
|
||||
When the plus sign is followed by only a colon, then the cursor is sent
|
||||
|
@ -12,8 +12,6 @@ declare-option -docstring "amount of lines that will be checked at the beginning
|
||||
|
||||
define-command -hidden modeline-parse-impl %{
|
||||
evaluate-commands %sh{
|
||||
kakquote() { printf "%s" "$*" | sed "s/'/''/g; 1s/^/'/; \$s/\$/'/"; }
|
||||
|
||||
# Translate a vim option into the corresponding kakoune one
|
||||
translate_opt_vim() {
|
||||
local key="$1"
|
||||
@ -54,7 +52,7 @@ define-command -hidden modeline-parse-impl %{
|
||||
return;;
|
||||
esac
|
||||
|
||||
printf 'set-option buffer %s %s\n' "${key}" "$(kakquote "${value}")"
|
||||
printf 'set-option buffer %s %s\n' "${key}" "$(kak -quote kakoune -- "${value}")"
|
||||
}
|
||||
|
||||
# Pass a few whitelisted options to kakoune directly
|
||||
@ -64,19 +62,19 @@ define-command -hidden modeline-parse-impl %{
|
||||
|
||||
case "${key}" in
|
||||
scrolloff|tabstop|indentwidth|autowrap_column|eolformat|filetype|BOM|spell_lang);;
|
||||
*) printf 'echo -debug %s' "$(kakquote "Unsupported kakoune variable: ${key}")" \
|
||||
*) printf 'echo -debug %s' "$(kak -quote kakoune -- "Unsupported kakoune variable: ${key}")" \
|
||||
| kak -p "${kak_session}"
|
||||
return;;
|
||||
esac
|
||||
|
||||
printf 'set-option buffer %s %s\n' "${key}" "$(kakquote "${value}")"
|
||||
printf 'set-option buffer %s %s\n' "${key}" "$(kak -quote kakoune -- "${value}")"
|
||||
}
|
||||
|
||||
case "${kak_selection}" in
|
||||
*vi:*|*vim:*) type_selection="vim";;
|
||||
*kak:*|*kakoune:*) type_selection="kakoune";;
|
||||
*)
|
||||
printf 'fail %s\n' "$(kakquote "Unsupported modeline format: ${kak_selection}")"
|
||||
printf 'fail %s\n' "$(kak -quote kakoune -- "Unsupported modeline format: ${kak_selection}")"
|
||||
exit 1 ;;
|
||||
esac
|
||||
|
||||
|
@ -148,9 +148,6 @@ define-command -params 1.. \
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
kakquote() {
|
||||
printf "%s" "$1" | sed "s/'/''/g; 1s/^/'/; \$s/\$/'/"
|
||||
}
|
||||
|
||||
show_git_cmd_output() {
|
||||
local filetype
|
||||
@ -255,7 +252,7 @@ define-command -params 1.. \
|
||||
n=$#
|
||||
eval set -- "$(cat ${kak_response_fifo})" "$@"
|
||||
if [ $# -eq $((n+1)) ]; then
|
||||
echo fail -- "$(kakquote "$1")"
|
||||
echo fail -- "$(kak -quote kakoune -- "$1")"
|
||||
exit
|
||||
fi
|
||||
commit=$1
|
||||
@ -266,15 +263,15 @@ define-command -params 1.. \
|
||||
# Log commit and file name because they are only echoed briefly
|
||||
# and not shown elsewhere (we don't have a :messages buffer).
|
||||
message="Blaming $file as of $(git rev-parse --short $commit)"
|
||||
echo "echo -debug -- $(kakquote "$message")"
|
||||
echo "echo -debug -- $(kak -quote kakoune -- "$message")"
|
||||
on_close_fifo="
|
||||
execute-keys -client ${kak_client} ${cursor_line}g<a-h>${cursor_column}lh
|
||||
evaluate-commands -client ${kak_client} %{
|
||||
set-option buffer git_blob $(kakquote "$commit:$file")
|
||||
git blame $(for arg; do kakquote "$arg"; printf " "; done)
|
||||
set-option buffer git_blob $(kak -quote kakoune -- "$commit:$file")
|
||||
git blame $(kak -quote kakoune -- "$@")
|
||||
hook -once window NormalIdle .* %{
|
||||
execute-keys vv
|
||||
echo -markup -- $(kakquote "{Information}{\\}$message. Press <ret> to jump to blamed commit")
|
||||
echo -markup -- $(kak -quote kakoune -- "{Information}{\\}$message. Press <ret> to jump to blamed commit")
|
||||
}
|
||||
}
|
||||
" show_git_cmd_output show "$commit:$file"
|
||||
@ -565,7 +562,7 @@ define-command -params 1.. \
|
||||
'
|
||||
eval set -- "$(cat ${kak_response_fifo})"
|
||||
if [ $# -eq 1 ]; then
|
||||
echo fail -- "$(kakquote "$1")"
|
||||
echo fail -- "$(kak -quote kakoune -- "$1")"
|
||||
exit
|
||||
fi
|
||||
starting_commit=$1
|
||||
|
@ -31,9 +31,6 @@ define-command menu -params 1.. -docstring %{
|
||||
printf %s "$2"
|
||||
exit
|
||||
fi
|
||||
shellquote() {
|
||||
printf "'%s'" "$(printf %s "$1" | sed "s/'/'\\\\''/g; s/§/§§/g; $2")"
|
||||
}
|
||||
cases=
|
||||
select_cases=
|
||||
completion=
|
||||
@ -43,43 +40,45 @@ define-command menu -params 1.. -docstring %{
|
||||
command=$2
|
||||
completion="${completion}${title}${nl}"
|
||||
cases="${cases}
|
||||
($(shellquote "$title" s/¶/¶¶/g))
|
||||
printf '%s\\n' $(shellquote "$command" s/¶/¶¶/g)
|
||||
$(kak -quote shell -- "$title"))
|
||||
printf '%s\\n' $(kak -quote shell -- "$command")
|
||||
;;"
|
||||
if $select_cmds; then
|
||||
select_command=$3
|
||||
select_cases="${select_cases}
|
||||
($(shellquote "$title" s/¶/¶¶/g))
|
||||
printf '%s\\n' $(shellquote "$select_command" s/¶/¶¶/g)
|
||||
$(kak -quote shell -- "$title"))
|
||||
printf '%s\\n' $(kak -quote shell -- "$select_command")
|
||||
;;"
|
||||
fi
|
||||
shift $stride
|
||||
done
|
||||
printf "\
|
||||
prompt '' %%§
|
||||
evaluate-commands %%sh¶
|
||||
case \"\$kak_text\" in \
|
||||
%s
|
||||
(*) echo fail -- no such item: \"'\$(printf %%s \"\$kak_text\" | sed \"s/'/''/g\")'\" ;;
|
||||
esac
|
||||
¶
|
||||
§" "$cases"
|
||||
|
||||
printf "%s" "prompt '' $(kak -quote kakoune -- "
|
||||
evaluate-commands %sh$(kak -quote kakoune -- '
|
||||
case "$kak_text" in
|
||||
'"${cases}"'
|
||||
*) echo fail -- no such item: "$(kak -quote kakoune -- "$kak_text")"
|
||||
esac
|
||||
')
|
||||
")"
|
||||
|
||||
if $select_cmds; then
|
||||
printf " \
|
||||
-on-change %%§
|
||||
evaluate-commands %%sh¶
|
||||
case \"\$kak_text\" in \
|
||||
%s
|
||||
(*) : ;;
|
||||
esac
|
||||
¶
|
||||
§" "$select_cases"
|
||||
printf "%s" " -on-change $(kak -quote kakoune -- "
|
||||
evaluate-commands %sh$(kak -quote kakoune -- '
|
||||
case "$kak_text" in
|
||||
'"$select_cases"'
|
||||
*) : ;;
|
||||
esac
|
||||
')
|
||||
")"
|
||||
fi
|
||||
|
||||
if [ -n "$on_abort" ]; then
|
||||
printf " -on-abort '%s'" "$(printf %s "$on_abort" | sed "s/'/''/g")"
|
||||
printf "%s" " -on-abort $(kak -quote kakoune -- "$on_abort")"
|
||||
fi
|
||||
printf ' -menu -shell-script-candidates %%§
|
||||
printf %%s %s
|
||||
§\n' "$(shellquote "$completion")"
|
||||
|
||||
printf "%s\n" " -menu -shell-script-candidates $(kak -quote kakoune -- "
|
||||
printf %s $(kak -quote shell -- "$completion")
|
||||
")"
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "safe_ptr.hh"
|
||||
#include "string.hh"
|
||||
#include "ranges.hh"
|
||||
#include "hash_map.hh"
|
||||
|
||||
namespace Kakoune
|
||||
|
@ -1,8 +1,10 @@
|
||||
#include "assert.hh"
|
||||
|
||||
#include "backtrace.hh"
|
||||
#include "buffer_utils.hh"
|
||||
#include "format.hh"
|
||||
#include "file.hh"
|
||||
#include "exception.hh"
|
||||
#include "debug.hh"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "backtrace.hh"
|
||||
|
||||
#include "string.hh"
|
||||
#include "string_utils.hh"
|
||||
#include "format.hh"
|
||||
|
||||
#if defined(__GLIBC__) || defined(__APPLE__)
|
||||
# include <execinfo.h>
|
||||
|
@ -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{}));
|
||||
|
@ -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"
|
||||
@ -130,6 +131,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 +469,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 +493,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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<PendingClear>) { return true; }
|
||||
PendingClear m_pending_clear = PendingClear::None;
|
||||
|
||||
|
||||
struct Menu
|
||||
{
|
||||
Vector<DisplayLine> items;
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include "exception.hh"
|
||||
#include "ranges.hh"
|
||||
#include "string_utils.hh"
|
||||
#include "format.hh"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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"
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "file.hh"
|
||||
#include "context.hh"
|
||||
#include "option_types.hh"
|
||||
#include "option_manager.hh"
|
||||
#include "regex.hh"
|
||||
|
||||
namespace Kakoune
|
||||
|
@ -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<size_t> 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(); }
|
||||
|
||||
}
|
||||
|
@ -4,20 +4,26 @@
|
||||
#include "selection.hh"
|
||||
#include "optional.hh"
|
||||
#include "utils.hh"
|
||||
#include "flags.hh"
|
||||
|
||||
#include <functional>
|
||||
|
||||
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<typename Func>
|
||||
void set_last_select(Func&& last_select) { m_last_select = std::forward<Func>(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(Context& context);
|
||||
ScopedSelectionEdition(ScopedSelectionEdition&& other);
|
||||
~ScopedSelectionEdition();
|
||||
|
||||
~ScopedSelectionEdition() { if (m_buffer) m_context.m_selection_history.end_edition(); }
|
||||
private:
|
||||
Context& m_context;
|
||||
SafePtr<Buffer> m_buffer;
|
||||
|
39
src/debug.cc
Normal file
39
src/debug.cc
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
40
src/debug.hh
Normal file
40
src/debug.hh
Normal file
@ -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<DebugFlags>) { return true; }
|
||||
|
||||
constexpr auto enum_desc(Meta::Type<DebugFlags>)
|
||||
{
|
||||
return make_array<EnumDesc<DebugFlags>>({
|
||||
{ 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
|
@ -7,6 +7,8 @@
|
||||
#include "string.hh"
|
||||
#include "vector.hh"
|
||||
#include "hash_map.hh"
|
||||
#include "ranges.hh"
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace Kakoune
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include "exception.hh"
|
||||
#include "ranges.hh"
|
||||
#include "string_utils.hh"
|
||||
#include "format.hh"
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "meta.hh"
|
||||
#include "string.hh"
|
||||
#include "units.hh"
|
||||
#include "constexpr_utils.hh"
|
||||
#include "vector.hh"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
180
src/format.cc
Normal file
180
src/format.cc
Normal file
@ -0,0 +1,180 @@
|
||||
#include "format.hh"
|
||||
|
||||
#include "exception.hh"
|
||||
#include "string_utils.hh"
|
||||
|
||||
#include <charconv>
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
||||
|
||||
template<size_t N>
|
||||
InplaceString<N> to_string_impl(auto val, auto format)
|
||||
{
|
||||
InplaceString<N> 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<size_t N>
|
||||
InplaceString<N> to_string_impl(auto val)
|
||||
{
|
||||
return to_string_impl<N>(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<typename AppendFunc>
|
||||
void format_impl(StringView fmt, ArrayView<const StringView> 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<char> buffer, StringView fmt, ArrayView<const StringView> 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<void (StringView)> append, StringView fmt, ArrayView<const StringView> params)
|
||||
{
|
||||
format_impl(fmt, params, append);
|
||||
}
|
||||
|
||||
String format(StringView fmt, ArrayView<const StringView> 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;
|
||||
}
|
||||
|
||||
}
|
81
src/format.hh
Normal file
81
src/format.hh
Normal file
@ -0,0 +1,81 @@
|
||||
#ifndef format_hh_INCLUDED
|
||||
#define format_hh_INCLUDED
|
||||
|
||||
#include "string.hh"
|
||||
#include "utils.hh"
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
||||
template<size_t N>
|
||||
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<typename RealType, typename ValueType>
|
||||
decltype(auto) to_string(const StronglyTypedNumber<RealType, ValueType>& val)
|
||||
{
|
||||
return to_string((ValueType)val);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename T> requires std::is_convertible_v<T, StringView>
|
||||
StringView format_param(const T& val) { return val; }
|
||||
|
||||
template<typename T> requires (not std::is_convertible_v<T, StringView>)
|
||||
decltype(auto) format_param(const T& val) { return to_string(val); }
|
||||
|
||||
}
|
||||
|
||||
String format(StringView fmt, ArrayView<const StringView> params);
|
||||
|
||||
template<typename... Types>
|
||||
String format(StringView fmt, Types&&... params)
|
||||
{
|
||||
return format(fmt, ArrayView<const StringView>{detail::format_param(std::forward<Types>(params))...});
|
||||
}
|
||||
|
||||
StringView format_to(ArrayView<char> buffer, StringView fmt, ArrayView<const StringView> params);
|
||||
|
||||
template<typename... Types>
|
||||
StringView format_to(ArrayView<char> buffer, StringView fmt, Types&&... params)
|
||||
{
|
||||
return format_to(buffer, fmt, ArrayView<const StringView>{detail::format_param(std::forward<Types>(params))...});
|
||||
}
|
||||
|
||||
void format_with(FunctionRef<void (StringView)> append, StringView fmt, ArrayView<const StringView> params);
|
||||
|
||||
template<typename... Types>
|
||||
void format_with(FunctionRef<void (StringView)> append, StringView fmt, Types&&... params)
|
||||
{
|
||||
return format_with(append, fmt, ArrayView<const StringView>{detail::format_param(std::forward<Types>(params))...});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // format_hh_INCLUDED
|
@ -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 <random>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Kakoune
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "highlighter.hh"
|
||||
|
||||
#include "buffer_utils.hh"
|
||||
#include "debug.hh"
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
@ -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<BufferCoord>;
|
||||
|
||||
enum class HighlightPass
|
||||
{
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "highlighter_group.hh"
|
||||
|
||||
#include "ranges.hh"
|
||||
#include "string_utils.hh"
|
||||
#include "format.hh"
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "assert.hh"
|
||||
#include "buffer_utils.hh"
|
||||
#include "debug.hh"
|
||||
#include "changes.hh"
|
||||
#include "command_manager.hh"
|
||||
#include "context.hh"
|
||||
|
@ -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"
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "safe_ptr.hh"
|
||||
#include "meta.hh"
|
||||
#include "enum.hh"
|
||||
#include "constexpr_utils.hh"
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
@ -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"
|
||||
@ -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<PendingClear>) { return true; }
|
||||
|
||||
public:
|
||||
Normal(InputHandler& input_handler, bool single_command = false)
|
||||
: InputMode(input_handler),
|
||||
@ -228,13 +220,7 @@ public:
|
||||
Timer::Callback{} : [this](Timer&) {
|
||||
RefPtr<InputMode> 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;
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "hash_map.hh"
|
||||
#include "string.hh"
|
||||
#include "string_utils.hh"
|
||||
#include "value.hh"
|
||||
|
||||
namespace Kakoune
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "keys.hh"
|
||||
#include "ranges.hh"
|
||||
#include "string_utils.hh"
|
||||
#include "format.hh"
|
||||
|
||||
#include <cstdio>
|
||||
#include <utility>
|
||||
|
@ -3,7 +3,8 @@
|
||||
#include "array_view.hh"
|
||||
#include "assert.hh"
|
||||
#include "exception.hh"
|
||||
#include "string_utils.hh"
|
||||
#include "format.hh"
|
||||
#include "ranges.hh"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "unit_tests.hh"
|
||||
#include "utf8_iterator.hh"
|
||||
#include "utils.hh"
|
||||
#include "format.hh"
|
||||
#include "string_utils.hh"
|
||||
|
||||
namespace Kakoune
|
||||
|
11
src/main.cc
11
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"
|
||||
@ -1103,6 +1104,7 @@ int main(int argc, char* argv[])
|
||||
{ "debug", { ArgCompleter{}, "initial debug option value" } },
|
||||
{ "version", { {}, "display kakoune version and exit" } },
|
||||
{ "ro", { {}, "readonly mode" } },
|
||||
{ "quote", { ArgCompleter{}, "echo each argument with the given quoting (raw, kakoune, or shell)" } },
|
||||
{ "help", { {}, "display a help message and quit" } } }
|
||||
};
|
||||
|
||||
@ -1153,6 +1155,13 @@ int main(int argc, char* argv[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (auto quoting = parser.get_switch("quote"))
|
||||
{
|
||||
write_stdout(join(parser | transform(quoter(option_from_string(Meta::Type<Quoting>{}, *quoting))),
|
||||
' ', false));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (auto session = parser.get_switch("p"))
|
||||
{
|
||||
for (auto opt : { "c", "n", "s", "d", "e", "E", "ro" })
|
||||
|
@ -1,17 +1,12 @@
|
||||
#ifndef meta_hh_INCLUDED
|
||||
#define meta_hh_INCLUDED
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
inline namespace Meta
|
||||
namespace Kakoune::inline Meta
|
||||
{
|
||||
|
||||
struct AnyType{};
|
||||
template<typename T> struct Type : AnyType {};
|
||||
|
||||
template<typename T> using void_t = void;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // meta_hh_INCLUDED
|
||||
|
@ -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
|
||||
|
@ -64,29 +64,6 @@ struct PrefixedList
|
||||
template<typename T>
|
||||
using TimestampedList = PrefixedList<size_t, T>;
|
||||
|
||||
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<DebugFlags>) { return true; }
|
||||
|
||||
constexpr auto enum_desc(Meta::Type<DebugFlags>)
|
||||
{
|
||||
return make_array<EnumDesc<DebugFlags>>({
|
||||
{ DebugFlags::Hooks, "hooks" },
|
||||
{ DebugFlags::Shell, "shell" },
|
||||
{ DebugFlags::Profile, "profile" },
|
||||
{ DebugFlags::Keys, "keys" },
|
||||
{ DebugFlags::Commands, "commands" },
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // option_hh_INCLUDED
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "ranges.hh"
|
||||
#include "utils.hh"
|
||||
#include "vector.hh"
|
||||
#include "format.hh"
|
||||
#include "string_utils.hh"
|
||||
|
||||
#include <memory>
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "option_types.hh"
|
||||
#include "debug.hh"
|
||||
#include "unit_tests.hh"
|
||||
|
||||
namespace Kakoune
|
||||
|
@ -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 <tuple>
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "parameters_parser.hh"
|
||||
|
||||
#include "ranges.hh"
|
||||
#include "flags.hh"
|
||||
|
||||
namespace Kakoune
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "optional.hh"
|
||||
#include "flags.hh"
|
||||
#include "string.hh"
|
||||
#include "string_utils.hh"
|
||||
#include "format.hh"
|
||||
|
||||
#include <functional>
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "option.hh"
|
||||
#include "clock.hh"
|
||||
#include "option_manager.hh"
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "unit_tests.hh"
|
||||
#include "utf8_iterator.hh"
|
||||
#include "optional.hh"
|
||||
#include "ranges.hh"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -6,9 +6,10 @@
|
||||
#include "unit_tests.hh"
|
||||
#include "utf8.hh"
|
||||
#include "utf8_iterator.hh"
|
||||
#include "string_utils.hh"
|
||||
#include "format.hh"
|
||||
#include "vector.hh"
|
||||
#include "utils.hh"
|
||||
#include "ranges.hh"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "utils.hh"
|
||||
|
||||
#include <bit>
|
||||
#include <algorithm>
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
@ -210,11 +211,12 @@ constexpr bool is_direction(RegexMode mode)
|
||||
(mode & ~(RegexMode::Forward | RegexMode::Backward)) == RegexMode{0};
|
||||
}
|
||||
|
||||
template<typename It, typename=void>
|
||||
template<typename It>
|
||||
struct SentinelType { using Type = It; };
|
||||
|
||||
template<typename It>
|
||||
struct SentinelType<It, void_t<typename It::Sentinel>> { using Type = typename It::Sentinel; };
|
||||
requires requires { typename It::Sentinel; }
|
||||
struct SentinelType<It> { using Type = typename It::Sentinel; };
|
||||
|
||||
template<typename Iterator, RegexMode mode>
|
||||
requires (has_direction(mode))
|
||||
|
@ -3,11 +3,23 @@
|
||||
#include "assert.hh"
|
||||
#include "context.hh"
|
||||
#include "hash_map.hh"
|
||||
#include "string_utils.hh"
|
||||
#include "format.hh"
|
||||
#include "ranges.hh"
|
||||
#include "hook_manager.hh"
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
||||
Register::RestoreInfo Register::save(const Context& context)
|
||||
{
|
||||
return get(context) | gather<RestoreInfo>();
|
||||
}
|
||||
|
||||
void Register::restore(Context& context, const RestoreInfo& info)
|
||||
{
|
||||
set(context, info, true);
|
||||
}
|
||||
|
||||
void StaticRegister::set(Context& context, ConstArrayView<String> values, bool)
|
||||
{
|
||||
m_content.assign(values.begin(), values.end());
|
||||
|
@ -24,8 +24,8 @@ public:
|
||||
virtual const String& get_main(const Context& context, size_t main_index) = 0;
|
||||
|
||||
using RestoreInfo = Vector<String, MemoryDomain::Registers>;
|
||||
RestoreInfo save(const Context& context) { return get(context) | gather<RestoreInfo>(); }
|
||||
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; }
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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<Selection> list, size_t time
|
||||
SelectionList::SelectionList(Buffer& buffer, Vector<Selection> 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<String> 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<Vector<Selection>>();
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 <limits>
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
||||
class Buffer;
|
||||
using BufferRange = Range<BufferCoord>;
|
||||
|
||||
using CaptureList = Vector<String, MemoryDomain::Selections>;
|
||||
|
||||
constexpr ColumnCount max_column{std::numeric_limits<int>::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<Selection> s);
|
||||
SelectionList(Buffer& buffer, Vector<Selection> 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<typename StringArray>
|
||||
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<Vector<Selection>>();
|
||||
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<String> descs, size_t timestamp, size_t main, ColumnCount tabstop = -1);
|
||||
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "meta.hh"
|
||||
#include "unicode.hh"
|
||||
#include "vector.hh"
|
||||
#include "constexpr_utils.hh"
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "shared_string.hh"
|
||||
#include "buffer_utils.hh"
|
||||
#include "debug.hh"
|
||||
#include "format.hh"
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "shell_manager.hh"
|
||||
|
||||
#include "buffer_utils.hh"
|
||||
#include "debug.hh"
|
||||
#include "client.hh"
|
||||
#include "clock.hh"
|
||||
#include "context.hh"
|
||||
|
@ -147,88 +147,6 @@ int str_to_int(StringView str)
|
||||
throw runtime_error{str + " is not a number"};
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
InplaceString<N> to_string_impl(auto val, auto format)
|
||||
{
|
||||
InplaceString<N> 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<size_t N>
|
||||
InplaceString<N> to_string_impl(auto val)
|
||||
{
|
||||
return to_string_impl<N>(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<typename AppendFunc>
|
||||
void format_impl(StringView fmt, ArrayView<const StringView> 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<char> buffer, StringView fmt, ArrayView<const StringView> 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<void (StringView)> append, StringView fmt, ArrayView<const StringView> params)
|
||||
{
|
||||
format_impl(fmt, params, append);
|
||||
}
|
||||
|
||||
String format(StringView fmt, ArrayView<const StringView> 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;
|
||||
|
@ -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<int> str_to_int_ifp(StringView str);
|
||||
|
||||
template<size_t N>
|
||||
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<typename RealType, typename ValueType>
|
||||
decltype(auto) to_string(const StronglyTypedNumber<RealType, ValueType>& val)
|
||||
{
|
||||
return to_string((ValueType)val);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename T> requires std::is_convertible_v<T, StringView>
|
||||
StringView format_param(const T& val) { return val; }
|
||||
|
||||
template<typename T> requires (not std::is_convertible_v<T, StringView>)
|
||||
decltype(auto) format_param(const T& val) { return to_string(val); }
|
||||
|
||||
}
|
||||
|
||||
String format(StringView fmt, ArrayView<const StringView> params);
|
||||
|
||||
template<typename... Types>
|
||||
String format(StringView fmt, Types&&... params)
|
||||
{
|
||||
return format(fmt, ArrayView<const StringView>{detail::format_param(std::forward<Types>(params))...});
|
||||
}
|
||||
|
||||
StringView format_to(ArrayView<char> buffer, StringView fmt, ArrayView<const StringView> params);
|
||||
|
||||
template<typename... Types>
|
||||
StringView format_to(ArrayView<char> buffer, StringView fmt, Types&&... params)
|
||||
{
|
||||
return format_to(buffer, fmt, ArrayView<const StringView>{detail::format_param(std::forward<Types>(params))...});
|
||||
}
|
||||
|
||||
void format_with(FunctionRef<void (StringView)> append, StringView fmt, ArrayView<const StringView> params);
|
||||
|
||||
template<typename... Types>
|
||||
void format_with(FunctionRef<void (StringView)> append, StringView fmt, Types&&... params)
|
||||
{
|
||||
return format_with(append, fmt, ArrayView<const StringView>{detail::format_param(std::forward<Types>(params))...});
|
||||
}
|
||||
|
||||
String double_up(StringView s, StringView characters);
|
||||
|
||||
inline String quote(StringView s)
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "file.hh"
|
||||
#include "keys.hh"
|
||||
#include "ranges.hh"
|
||||
#include "string_utils.hh"
|
||||
#include "format.hh"
|
||||
#include "diff.hh"
|
||||
|
||||
#include <algorithm>
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <cwchar>
|
||||
|
||||
#include "array_view.hh"
|
||||
#include "ranges.hh"
|
||||
#include "units.hh"
|
||||
|
||||
namespace Kakoune
|
||||
@ -75,8 +74,12 @@ enum WordType { Word, WORD };
|
||||
template<WordType word_type = Word>
|
||||
inline bool is_word(Codepoint c, ConstArrayView<Codepoint> 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<>
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user