Merge remote-tracking branch 'lenormf/readonly-mode'
This commit is contained in:
commit
003cb8dfea
|
@ -231,6 +231,7 @@ Just running *kak* launch a new kak session with a client on local terminal.
|
||||||
read keystrokes as json on stdin.
|
read keystrokes as json on stdin.
|
||||||
* `-l`: list existing sessions, and check the dead ones
|
* `-l`: list existing sessions, and check the dead ones
|
||||||
* `-clear`: clear dead sessions socket files
|
* `-clear`: clear dead sessions socket files
|
||||||
|
* `-ro`: prevent modifications to all buffers from being saved to disk
|
||||||
|
|
||||||
At startup, if `-n` is not specified, Kakoune will try to source the file
|
At startup, if `-n` is not specified, Kakoune will try to source the file
|
||||||
`../share/kak/kakrc` relative to the kak binary. This kak file will then try
|
`../share/kak/kakrc` relative to the kak binary. This kak file will then try
|
||||||
|
@ -864,6 +865,9 @@ Some options are built in Kakoune, and can be used to control it's behaviour:
|
||||||
writing a buffer, this is autodetected on load.
|
writing a buffer, this is autodetected on load.
|
||||||
* `BOM` _enum(none|utf8)_: define if the file should be written
|
* `BOM` _enum(none|utf8)_: define if the file should be written
|
||||||
with an unicode byte order mark.
|
with an unicode byte order mark.
|
||||||
|
* `readonly` _bool_: prevent modifications from being saved to disk, all
|
||||||
|
buffers if set to `true` in the `global` scope, or current buffer if set in
|
||||||
|
the `buffer` scope.
|
||||||
* `incsearch` _bool_: execute search as it is typed
|
* `incsearch` _bool_: execute search as it is typed
|
||||||
* `aligntab` _bool_: use tabs for alignment command
|
* `aligntab` _bool_: use tabs for alignment command
|
||||||
* `autoinfo` _flags(command|onkey|normal)_: display automatic information
|
* `autoinfo` _flags(command|onkey|normal)_: display automatic information
|
||||||
|
|
|
@ -70,6 +70,11 @@ Builtin options
|
||||||
*BOM* 'enum(none|utf8)'::
|
*BOM* 'enum(none|utf8)'::
|
||||||
define if the file should be written with an unicode byte order mark
|
define if the file should be written with an unicode byte order mark
|
||||||
|
|
||||||
|
*readonly* 'bool'::
|
||||||
|
prevent modifications from being saved to disk, all
|
||||||
|
buffers if set to `true` in the `global` scope, or current buffer if set in
|
||||||
|
the `buffer` scope.
|
||||||
|
|
||||||
*incsearch* 'bool'::
|
*incsearch* 'bool'::
|
||||||
execute search as it is typed
|
execute search as it is typed
|
||||||
|
|
||||||
|
|
|
@ -606,6 +606,13 @@ void Buffer::set_fs_timestamp(timespec ts)
|
||||||
|
|
||||||
void Buffer::on_option_changed(const Option& option)
|
void Buffer::on_option_changed(const Option& option)
|
||||||
{
|
{
|
||||||
|
if (option.name() == "readonly")
|
||||||
|
{
|
||||||
|
if (option.get<bool>())
|
||||||
|
m_flags |= Flags::ReadOnly;
|
||||||
|
else
|
||||||
|
m_flags &= ~Flags::ReadOnly;
|
||||||
|
}
|
||||||
run_hook_in_own_context("BufSetOption",
|
run_hook_in_own_context("BufSetOption",
|
||||||
format("{}={}", option.name(), option.get_as_string()));
|
format("{}={}", option.name(), option.get_as_string()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,12 +101,13 @@ class Buffer : public SafeCountable, public OptionManagerWatcher, public Scope
|
||||||
public:
|
public:
|
||||||
enum class Flags
|
enum class Flags
|
||||||
{
|
{
|
||||||
None = 0,
|
None = 0,
|
||||||
File = 1 << 0,
|
File = 1 << 0,
|
||||||
New = 1 << 1,
|
New = 1 << 1,
|
||||||
Fifo = 1 << 2,
|
Fifo = 1 << 2,
|
||||||
NoUndo = 1 << 3,
|
NoUndo = 1 << 3,
|
||||||
Debug = 1 << 4
|
Debug = 1 << 4,
|
||||||
|
ReadOnly = 1 << 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
Buffer(String name, Flags flags, StringView data = {},
|
Buffer(String name, Flags flags, StringView data = {},
|
||||||
|
|
|
@ -87,7 +87,8 @@ void BufferManager::backup_modified_buffers()
|
||||||
{
|
{
|
||||||
for (auto& buf : m_buffers)
|
for (auto& buf : m_buffers)
|
||||||
{
|
{
|
||||||
if ((buf->flags() & Buffer::Flags::File) and buf->is_modified())
|
if ((buf->flags() & Buffer::Flags::File) and buf->is_modified()
|
||||||
|
and not (buf->flags() & Buffer::Flags::ReadOnly))
|
||||||
write_buffer_to_backup_file(*buf);
|
write_buffer_to_backup_file(*buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -239,6 +239,12 @@ void write_buffer(const ParametersParser& parser, Context& context, const ShellC
|
||||||
if (parser.positional_count() == 0 and !(buffer.flags() & Buffer::Flags::File))
|
if (parser.positional_count() == 0 and !(buffer.flags() & Buffer::Flags::File))
|
||||||
throw runtime_error("cannot write a non file buffer without a filename");
|
throw runtime_error("cannot write a non file buffer without a filename");
|
||||||
|
|
||||||
|
// if the buffer is in read-only mode and we try to save it directly
|
||||||
|
// or we try to write to it indirectly using e.g. a symlink, throw an error
|
||||||
|
if ((context.buffer().flags() & Buffer::Flags::ReadOnly)
|
||||||
|
and (parser.positional_count() == 0 or real_path(parser[0]) == buffer.name()))
|
||||||
|
throw runtime_error("cannot overwrite the buffer when in readonly mode");
|
||||||
|
|
||||||
auto filename = parser.positional_count() == 0 ?
|
auto filename = parser.positional_count() == 0 ?
|
||||||
buffer.name() : parse_filename(parser[0]);
|
buffer.name() : parse_filename(parser[0]);
|
||||||
write_buffer_to_file(buffer, filename);
|
write_buffer_to_file(buffer, filename);
|
||||||
|
@ -260,7 +266,8 @@ void write_all_buffers()
|
||||||
{
|
{
|
||||||
for (auto& buffer : BufferManager::instance())
|
for (auto& buffer : BufferManager::instance())
|
||||||
{
|
{
|
||||||
if ((buffer->flags() & Buffer::Flags::File) and buffer->is_modified())
|
if ((buffer->flags() & Buffer::Flags::File) and buffer->is_modified()
|
||||||
|
and !(buffer->flags() & Buffer::Flags::ReadOnly))
|
||||||
write_buffer_to_file(*buffer, buffer->name());
|
write_buffer_to_file(*buffer, buffer->name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
30
src/main.cc
30
src/main.cc
|
@ -265,6 +265,7 @@ void register_options()
|
||||||
reg.declare_option("modelinefmt", "format string used to generate the modeline",
|
reg.declare_option("modelinefmt", "format string used to generate the modeline",
|
||||||
"%val{bufname} %val{cursor_line}:%val{cursor_char_column} "_str);
|
"%val{bufname} %val{cursor_line}:%val{cursor_char_column} "_str);
|
||||||
reg.declare_option("debug", "various debug flags", DebugFlags::None);
|
reg.declare_option("debug", "various debug flags", DebugFlags::None);
|
||||||
|
reg.declare_option("readonly", "prevent buffers from being modified", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct convert_to_client_mode
|
struct convert_to_client_mode
|
||||||
|
@ -460,7 +461,7 @@ int run_client(StringView session, StringView init_command, UIType ui_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
int run_server(StringView session, StringView init_command,
|
int run_server(StringView session, StringView init_command,
|
||||||
bool ignore_kakrc, bool daemon, UIType ui_type,
|
bool ignore_kakrc, bool daemon, bool readonly, UIType ui_type,
|
||||||
ConstArrayView<StringView> files, ByteCoord target_coord)
|
ConstArrayView<StringView> files, ByteCoord target_coord)
|
||||||
{
|
{
|
||||||
static bool terminate = false;
|
static bool terminate = false;
|
||||||
|
@ -503,6 +504,8 @@ int run_server(StringView session, StringView init_command,
|
||||||
|
|
||||||
write_to_debug_buffer("*** This is the debug buffer, where debug info will be written ***");
|
write_to_debug_buffer("*** This is the debug buffer, where debug info will be written ***");
|
||||||
|
|
||||||
|
GlobalScope::instance().options().get_local_option("readonly").set(readonly);
|
||||||
|
|
||||||
Server server(session.empty() ? to_string(getpid()) : session.str());
|
Server server(session.empty() ? to_string(getpid()) : session.str());
|
||||||
|
|
||||||
bool startup_error = false;
|
bool startup_error = false;
|
||||||
|
@ -536,7 +539,9 @@ int run_server(StringView session, StringView init_command,
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
open_or_create_file_buffer(file);
|
Buffer *buffer = open_or_create_file_buffer(file);
|
||||||
|
if (readonly)
|
||||||
|
buffer->flags() |= Buffer::Flags::ReadOnly;
|
||||||
}
|
}
|
||||||
catch (Kakoune::runtime_error& error)
|
catch (Kakoune::runtime_error& error)
|
||||||
{
|
{
|
||||||
|
@ -741,7 +746,8 @@ int main(int argc, char* argv[])
|
||||||
{ "q", { false, "in filter mode, be quiet about errors applying keys" } },
|
{ "q", { false, "in filter mode, be quiet about errors applying keys" } },
|
||||||
{ "ui", { true, "set the type of user interface to use (ncurses, dummy, or json)" } },
|
{ "ui", { true, "set the type of user interface to use (ncurses, dummy, or json)" } },
|
||||||
{ "l", { false, "list existing sessions" } },
|
{ "l", { false, "list existing sessions" } },
|
||||||
{ "clear", { false, "clear dead sessions" } } }
|
{ "clear", { false, "clear dead sessions" } },
|
||||||
|
{ "ro", { false, "readonly mode" } } }
|
||||||
};
|
};
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -773,11 +779,11 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
if (auto session = parser.get_switch("p"))
|
if (auto session = parser.get_switch("p"))
|
||||||
{
|
{
|
||||||
for (auto opt : { "c", "n", "s", "d", "e" })
|
for (auto opt : { "c", "n", "s", "d", "e", "ro" })
|
||||||
{
|
{
|
||||||
if (parser.get_switch(opt))
|
if (parser.get_switch(opt))
|
||||||
{
|
{
|
||||||
write_stderr(format("error: -{} makes not sense with -p\n", opt));
|
write_stderr(format("error: -{} is incompatible with -p\n", opt));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -789,20 +795,27 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
if (auto keys = parser.get_switch("f"))
|
if (auto keys = parser.get_switch("f"))
|
||||||
{
|
{
|
||||||
|
if (parser.get_switch("ro"))
|
||||||
|
{
|
||||||
|
write_stderr("error: -ro is incompatible with -f\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
Vector<StringView> files;
|
Vector<StringView> files;
|
||||||
for (size_t i = 0; i < parser.positional_count(); ++i)
|
for (size_t i = 0; i < parser.positional_count(); ++i)
|
||||||
files.emplace_back(parser[i]);
|
files.emplace_back(parser[i]);
|
||||||
|
|
||||||
return run_filter(*keys, init_command, files, (bool)parser.get_switch("q"));
|
return run_filter(*keys, init_command, files,
|
||||||
|
(bool)parser.get_switch("q"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto server_session = parser.get_switch("c"))
|
if (auto server_session = parser.get_switch("c"))
|
||||||
{
|
{
|
||||||
for (auto opt : { "n", "s", "d" })
|
for (auto opt : { "n", "s", "d", "ro" })
|
||||||
{
|
{
|
||||||
if (parser.get_switch(opt))
|
if (parser.get_switch(opt))
|
||||||
{
|
{
|
||||||
write_stderr(format("error: -{} makes not sense with -c\n", opt));
|
write_stderr(format("error: -{} is incompatible with -c\n", opt));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -840,6 +853,7 @@ int main(int argc, char* argv[])
|
||||||
return run_server(session, init_command,
|
return run_server(session, init_command,
|
||||||
(bool)parser.get_switch("n"),
|
(bool)parser.get_switch("n"),
|
||||||
(bool)parser.get_switch("d"),
|
(bool)parser.get_switch("d"),
|
||||||
|
(bool)parser.get_switch("ro"),
|
||||||
ui_type, files, target_coord);
|
ui_type, files, target_coord);
|
||||||
}
|
}
|
||||||
catch (convert_to_client_mode& convert)
|
catch (convert_to_client_mode& convert)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user