// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
/// @file ex_cmds2.c
///
/// Some more functions for command line commands
#include <assert.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdbool.h>
#include <string.h>
#include "nvim/arglist.h"
#include "nvim/ascii.h"
#include "nvim/autocmd.h"
#include "nvim/globals.h"
#include "nvim/vim.h"
#ifdef HAVE_LOCALE_H
# include <locale.h>
#endif
#include "nvim/buffer.h"
#include "nvim/change.h"
#include "nvim/charset.h"
#include "nvim/eval.h"
#include "nvim/eval/vars.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
#include "nvim/ex_getln.h"
#include "nvim/fileio.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/ops.h"
#include "nvim/option.h"
#include "nvim/os/fs_defs.h"
#include "nvim/os/shell.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
#include "nvim/quickfix.h"
#include "nvim/runtime.h"
#include "nvim/strings.h"
#include "nvim/undo.h"
#include "nvim/window.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ex_cmds2.c.generated.h"
#endif
void ex_ruby(exarg_T *eap)
{
script_host_execute("ruby", eap);
}
void ex_rubyfile(exarg_T *eap)
{
script_host_execute_file("ruby", eap);
}
void ex_rubydo(exarg_T *eap)
{
script_host_do_range("ruby", eap);
}
void ex_python3(exarg_T *eap)
{
script_host_execute("python3", eap);
}
void ex_py3file(exarg_T *eap)
{
script_host_execute_file("python3", eap);
}
void ex_pydo3(exarg_T *eap)
{
script_host_do_range("python3", eap);
}
void ex_perl(exarg_T *eap)
{
script_host_execute("perl", eap);
}
void ex_perlfile(exarg_T *eap)
{
script_host_execute_file("perl", eap);
}
void ex_perldo(exarg_T *eap)
{
script_host_do_range("perl", eap);
}
/// If 'autowrite' option set, try to write the file.
/// Careful: autocommands may make "buf" invalid!
///
/// @return FAIL for failure, OK otherwise
int autowrite(buf_T *buf, int forceit)
{
int r;
bufref_T bufref;
if (!(p_aw || p_awa) || !p_write
// never autowrite a "nofile" or "nowrite" buffer
|| bt_dontwrite(buf)
|| (!forceit && buf->b_p_ro) || buf->b_ffname == NULL) {
return FAIL;
}
set_bufref(&bufref, buf);
r = buf_write_all(buf, forceit);
// Writing may succeed but the buffer still changed, e.g., when there is a
// conversion error. We do want to return FAIL then.
if (bufref_valid(&bufref) && bufIsChanged(buf)) {
r = FAIL;
}
return r;
}
/// Flush all buffers, except the ones that are readonly or are never written.
void autowrite_all(void)
{
if (!(p_aw || p_awa) || !p_write) {
return;
}
FOR_ALL_BUFFERS(buf) {
if (bufIsChanged(buf) && !buf->b_p_ro && !bt_dontwrite(buf)) {
bufref_T bufref;
set_bufref(&bufref, buf);
(void)buf_write_all(buf, false);
// an autocommand may have deleted the buffer
if (!bufref_valid(&bufref)) {
buf = firstbuf;
}
}
}
}
/// @return true if buffer was changed and cannot be abandoned.
/// For flags use the CCGD_ values.
bool check_changed(buf_T *buf, int flags)
{
int forceit = (flags & CCGD_FORCEIT);
bufref_T bufref;
set_bufref(&bufref, buf);
if (!forceit
&& bufIsChanged(buf)
&& ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
&& (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL)) {
if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) {
int count = 0;
if (flags & CCGD_ALLBUF) {
FOR_ALL_BUFFERS(buf2) {
if (bufIsChanged(buf2) && (buf2->b_ffname != NULL)) {
count++;
}
}
}
if (!bufref_valid(&bufref)) {
// Autocommand deleted buffer, oops! It's not changed now.
return false;
}
dialog_changed(buf, count > 1);
if (!bufref_valid(&bufref)) {
// Autocommand deleted buffer, oops! It's not changed now.
return false;
}
return bufIsChanged(buf);
}
if (flags & CCGD_EXCMD) {
no_write_message();
} else {
no_write_message_nobang(curbuf);
}
return true;
}
return false;
}
/// Ask the user what to do when abandoning a changed buffer.
/// Must check 'write' option first!
///
/// @param buf
/// @param checkall may abandon all changed buffers
void dialog_changed(buf_T *buf, bool checkall)
{
char buff[DIALOG_MSG_SIZE];
int ret;
// Init ea pseudo-structure, this is needed for the check_overwrite()
// function.
exarg_T ea = {
.append = false,
.forceit = false,
};
dialog_msg((char *)buff, _("Save changes to \"%s\"?"), buf->b_fname);
if (checkall) {
ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, (char_u *)buff, 1);
} else {
ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, (
|