1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 07:08:10 +00:00

LibLine: Add support for ^X^E

This keybind opens the current buffer in an editor (determined by
EDITOR from the env, or the default_text_editor key in the config file,
and set to /bin/TextEditor by default), and later reads the file back
into the buffer.
Pretty handy :^)
This commit is contained in:
AnotherTest 2021-04-17 21:41:38 +04:30 committed by Linus Groh
parent 258a49346d
commit b58dbc29fc
3 changed files with 108 additions and 1 deletions

View file

@ -24,12 +24,16 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <AK/ScopeGuard.h>
#include <AK/ScopedValueRollback.h>
#include <AK/StringBuilder.h>
#include <AK/TemporaryChange.h>
#include <LibCore/File.h>
#include <LibLine/Editor.h>
#include <ctype.h>
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
namespace {
constexpr u32 ctrl(char c) { return c & 0x3f; }
@ -522,4 +526,91 @@ void Editor::uppercase_word()
case_change_word(CaseChangeOp::Uppercase);
}
void Editor::edit_in_external_editor()
{
const auto* editor_command = getenv("EDITOR");
if (!editor_command)
editor_command = m_configuration.m_default_text_editor.characters();
char file_path[] = "/tmp/line-XXXXXX";
auto fd = mkstemp(file_path);
if (fd < 0) {
perror("mktemp");
return;
}
{
auto* fp = fdopen(fd, "rw");
if (!fp) {
perror("fdopen");
return;
}
StringBuilder builder;
builder.append(Utf32View { m_buffer.data(), m_buffer.size() });
auto view = builder.string_view();
size_t remaining_size = view.length();
while (remaining_size > 0)
remaining_size = fwrite(view.characters_without_null_termination() - remaining_size, sizeof(char), remaining_size, fp);
fclose(fp);
}
ScopeGuard remove_temp_file_guard {
[fd, file_path] {
close(fd);
unlink(file_path);
}
};
Vector<const char*> args { editor_command, file_path, nullptr };
auto pid = vfork();
if (pid == -1) {
perror("vfork");
return;
}
if (pid == 0) {
execvp(editor_command, const_cast<char* const*>(args.data()));
perror("execv");
_exit(126);
} else {
int wstatus = 0;
do {
waitpid(pid, &wstatus, 0);
} while (errno == EINTR);
if (!(WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0))
return;
}
{
auto file_or_error = Core::File::open(file_path, Core::IODevice::OpenMode::ReadOnly);
if (file_or_error.is_error())
return;
auto file = file_or_error.release_value();
auto contents = file->read_all();
StringView data { contents };
while (data.ends_with('\n'))
data = data.substring_view(0, data.length() - 1);
m_cursor = 0;
m_chars_touched_in_the_middle = m_buffer.size();
m_buffer.clear_with_capacity();
m_refresh_needed = true;
Utf8View view { data };
if (view.validate()) {
for (auto cp : view)
insert(cp);
} else {
for (auto ch : data)
insert(ch);
}
}
}
}