mirror of
https://github.com/MidnightCommander/mc
synced 2024-12-23 12:56:51 +03:00
fb48d4a295
The 'User Menu' entry is moved from 'File' submenu to 'Command' one. The 'Edit editor menu file' and 'Edit syntax file' entries are moved from main MC menu ('Command' submenu) to editor main menu ('Options' submenu) and renamed. src/cmd.c (check_for_default): moved to util.c and maken global. (menu_edit_cmd): rewritten to handle MC menu files only and renamed to edit_mc_menu_cmd. Editor relevant routines are moved to editor code. src/cmd.h: cleanup. src/main.c: main menu reorganization. src/user.h: moved editor macros to edit/edit.h. src/util.c, src/util.h: check_for_default function from src/cmd.h. Rewritten to use exist_file() function. edit/editcmddef.h: added new commands: CK_Load_Syntax_File and CK_Load_Menu_File. edit/edit.h: editor file macros from src/user.h. New type for file which is currently being edited. Modified edit_load_cmd function to be more advanced. edit/edit.c (edit_execute_cmd): handle new commands: CK_Load_Syntax_File and CK_Load_Menu_File. edit/editmenu.c: menu reorganization: moved two entries here from main MC menu. Added requireq handle functions. Small optimization: removed extra layer in menu entry handlers. edit/editcmd.c: menu and syntax files edit is implemented. Modified edit_load_cmd function to be more advanced.
2554 lines
64 KiB
C
2554 lines
64 KiB
C
/* editor high level editing commands
|
|
|
|
Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2004, 2005, 2006,
|
|
2007 Free Software Foundation, Inc.
|
|
|
|
Authors: 1996, 1997 Paul Sheer
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
02110-1301, USA.
|
|
|
|
*/
|
|
|
|
/** \file
|
|
* \brief Source: editor high level editing commands
|
|
* \author Paul Sheer
|
|
* \date 1996, 1997
|
|
*/
|
|
|
|
/* #define PIPE_BLOCKS_SO_READ_BYTE_BY_BYTE */
|
|
|
|
#include <config.h>
|
|
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <sys/stat.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "../src/global.h"
|
|
#include "../src/history.h"
|
|
|
|
#include "edit.h"
|
|
#include "editlock.h"
|
|
#include "editcmddef.h"
|
|
#include "edit-widget.h"
|
|
#include "editcmd_dialogs.h"
|
|
#include "../edit/etags.h"
|
|
#include "../src/panel.h"
|
|
|
|
#include "../src/tty.h" /* LINES */
|
|
#include "../src/widget.h" /* listbox_new() */
|
|
#include "../src/layout.h" /* clr_scr() */
|
|
#include "../src/main.h" /* mc_home source_codepage */
|
|
#include "../src/help.h" /* interactive_display() */
|
|
#include "../src/key.h" /* XCTRL */
|
|
#include "../src/wtools.h" /* message() */
|
|
#include "../src/charsets.h"
|
|
#include "../src/selcodepage.h"
|
|
#include "../src/strutil.h" /* utf string functions */
|
|
|
|
/* globals: */
|
|
|
|
/* search and replace: */
|
|
static int search_create_bookmark = 0;
|
|
/* static int search_in_all_charsets = 0; */
|
|
|
|
/* queries on a save */
|
|
int edit_confirm_save = 1;
|
|
|
|
static int edit_save_cmd (WEdit *edit);
|
|
static unsigned char *edit_get_block (WEdit *edit, long start,
|
|
long finish, int *l);
|
|
|
|
static void
|
|
edit_search_cmd_search_create_bookmark(WEdit * edit)
|
|
{
|
|
int found = 0, books = 0;
|
|
int l = 0, l_last = -1;
|
|
long q = 0;
|
|
gsize len = 0;
|
|
|
|
for (;;) {
|
|
if (!mc_search_run(edit->search, (void *) edit, q, edit->last_byte, &len))
|
|
break;
|
|
|
|
found++;
|
|
l += edit_count_lines (edit, q, edit->search->normal_offset);
|
|
if (l != l_last) {
|
|
book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
|
|
books++;
|
|
}
|
|
l_last = l;
|
|
q = edit->search->normal_offset + 1;
|
|
}
|
|
|
|
if (found) {
|
|
/* in response to number of bookmarks added because of string being found %d times */
|
|
message (D_NORMAL, _("Search"), _(" %d items found, %d bookmarks added "), found, books);
|
|
} else {
|
|
edit_error_dialog (_ ("Search"), _ (" Search string not found "));
|
|
}
|
|
}
|
|
|
|
static int
|
|
edit_search_cmd_callback(const void *user_data, gsize char_offset)
|
|
{
|
|
return edit_get_byte ((WEdit * )user_data, (long) char_offset);
|
|
}
|
|
|
|
void edit_help_cmd (WEdit * edit)
|
|
{
|
|
interactive_display (NULL, "[Internal File Editor]");
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
}
|
|
|
|
void edit_refresh_cmd (WEdit * edit)
|
|
{
|
|
#ifndef HAVE_SLANG
|
|
clr_scr();
|
|
do_refresh();
|
|
#else
|
|
{
|
|
int color;
|
|
edit_get_syntax_color (edit, -1, &color);
|
|
}
|
|
touchwin(stdscr);
|
|
#endif /* !HAVE_SLANG */
|
|
mc_refresh();
|
|
doupdate();
|
|
}
|
|
|
|
/* If 0 (quick save) then a) create/truncate <filename> file,
|
|
b) save to <filename>;
|
|
if 1 (safe save) then a) save to <tempnam>,
|
|
b) rename <tempnam> to <filename>;
|
|
if 2 (do backups) then a) save to <tempnam>,
|
|
b) rename <filename> to <filename.backup_ext>,
|
|
c) rename <tempnam> to <filename>. */
|
|
|
|
/* returns 0 on error, -1 on abort */
|
|
static int
|
|
edit_save_file (WEdit *edit, const char *filename)
|
|
{
|
|
char *p;
|
|
gchar *tmp;
|
|
long filelen = 0;
|
|
char *savename = 0;
|
|
gchar *real_filename;
|
|
int this_save_mode, fd = -1;
|
|
|
|
if (!filename)
|
|
return 0;
|
|
if (!*filename)
|
|
return 0;
|
|
|
|
if (*filename != PATH_SEP && edit->dir) {
|
|
real_filename = concat_dir_and_file (edit->dir, filename);
|
|
} else {
|
|
real_filename = g_strdup(filename);
|
|
}
|
|
|
|
this_save_mode = option_save_mode;
|
|
if (this_save_mode != EDIT_QUICK_SAVE) {
|
|
if (!vfs_file_is_local (real_filename) ||
|
|
(fd = mc_open (real_filename, O_RDONLY | O_BINARY)) == -1) {
|
|
/*
|
|
* The file does not exists yet, so no safe save or
|
|
* backup are necessary.
|
|
*/
|
|
this_save_mode = EDIT_QUICK_SAVE;
|
|
}
|
|
if (fd != -1)
|
|
mc_close (fd);
|
|
}
|
|
|
|
if (this_save_mode == EDIT_QUICK_SAVE &&
|
|
!edit->skip_detach_prompt) {
|
|
int rv;
|
|
struct stat sb;
|
|
|
|
rv = mc_stat (real_filename, &sb);
|
|
if (rv == 0 && sb.st_nlink > 1) {
|
|
rv = edit_query_dialog3 (_("Warning"),
|
|
_(" File has hard-links. Detach before saving? "),
|
|
_("&Yes"), _("&No"), _("&Cancel"));
|
|
switch (rv) {
|
|
case 0:
|
|
this_save_mode = EDIT_SAFE_SAVE;
|
|
/* fallthrough */
|
|
case 1:
|
|
edit->skip_detach_prompt = 1;
|
|
break;
|
|
default:
|
|
g_free(real_filename);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* Prevent overwriting changes from other editor sessions. */
|
|
if (rv == 0 && edit->stat1.st_mtime != 0 && edit->stat1.st_mtime != sb.st_mtime) {
|
|
|
|
/* The default action is "Cancel". */
|
|
query_set_sel(1);
|
|
|
|
rv = edit_query_dialog2 (
|
|
_("Warning"),
|
|
_("The file has been modified in the meantime. Save anyway?"),
|
|
_("&Yes"),
|
|
_("&Cancel"));
|
|
if (rv != 0){
|
|
g_free(real_filename);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (this_save_mode != EDIT_QUICK_SAVE) {
|
|
char *savedir, *saveprefix;
|
|
const char *slashpos;
|
|
slashpos = strrchr (real_filename, PATH_SEP);
|
|
if (slashpos) {
|
|
savedir = g_strdup (real_filename);
|
|
savedir[slashpos - real_filename + 1] = '\0';
|
|
} else
|
|
savedir = g_strdup (".");
|
|
saveprefix = concat_dir_and_file (savedir, "cooledit");
|
|
g_free (savedir);
|
|
fd = mc_mkstemps (&savename, saveprefix, NULL);
|
|
g_free (saveprefix);
|
|
if (!savename){
|
|
g_free(real_filename);
|
|
return 0;
|
|
}
|
|
/* FIXME:
|
|
* Close for now because mc_mkstemps use pure open system call
|
|
* to create temporary file and it needs to be reopened by
|
|
* VFS-aware mc_open().
|
|
*/
|
|
close (fd);
|
|
} else
|
|
savename = g_strdup (real_filename);
|
|
|
|
mc_chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
|
|
mc_chmod (savename, edit->stat1.st_mode);
|
|
|
|
if ((fd =
|
|
mc_open (savename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
|
|
edit->stat1.st_mode)) == -1)
|
|
goto error_save;
|
|
|
|
/* pipe save */
|
|
if ((p = edit_get_write_filter (savename, real_filename))) {
|
|
FILE *file;
|
|
|
|
mc_close (fd);
|
|
file = (FILE *) popen (p, "w");
|
|
|
|
if (file) {
|
|
filelen = edit_write_stream (edit, file);
|
|
#if 1
|
|
pclose (file);
|
|
#else
|
|
if (pclose (file) != 0) {
|
|
tmp = g_strconcat (_(" Error writing to pipe: "),
|
|
p, " ", (char *) NULL);
|
|
edit_error_dialog (_("Error"), tmp);
|
|
g_free(tmp);
|
|
g_free (p);
|
|
goto error_save;
|
|
}
|
|
#endif
|
|
} else {
|
|
tmp = g_strconcat (_(" Cannot open pipe for writing: "),
|
|
p, " ", (char *) NULL);
|
|
|
|
edit_error_dialog (_("Error"),
|
|
get_sys_error (tmp));
|
|
g_free (p);
|
|
g_free(tmp);
|
|
goto error_save;
|
|
}
|
|
g_free (p);
|
|
} else {
|
|
long buf;
|
|
buf = 0;
|
|
filelen = edit->last_byte;
|
|
while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) {
|
|
if (mc_write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE)
|
|
!= EDIT_BUF_SIZE) {
|
|
mc_close (fd);
|
|
goto error_save;
|
|
}
|
|
buf++;
|
|
}
|
|
if (mc_write
|
|
(fd, (char *) edit->buffers1[buf],
|
|
edit->curs1 & M_EDIT_BUF_SIZE) !=
|
|
(edit->curs1 & M_EDIT_BUF_SIZE)) {
|
|
filelen = -1;
|
|
} else if (edit->curs2) {
|
|
edit->curs2--;
|
|
buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
|
|
if (mc_write
|
|
(fd,
|
|
(char *) edit->buffers2[buf] + EDIT_BUF_SIZE -
|
|
(edit->curs2 & M_EDIT_BUF_SIZE) - 1,
|
|
1 + (edit->curs2 & M_EDIT_BUF_SIZE)) !=
|
|
1 + (edit->curs2 & M_EDIT_BUF_SIZE)) {
|
|
filelen = -1;
|
|
} else {
|
|
while (--buf >= 0) {
|
|
if (mc_write
|
|
(fd, (char *) edit->buffers2[buf],
|
|
EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
|
|
filelen = -1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
edit->curs2++;
|
|
}
|
|
if (mc_close (fd))
|
|
goto error_save;
|
|
|
|
/* Update the file information, especially the mtime. */
|
|
if (mc_stat (savename, &edit->stat1) == -1)
|
|
goto error_save;
|
|
}
|
|
|
|
if (filelen != edit->last_byte)
|
|
goto error_save;
|
|
|
|
if (this_save_mode == EDIT_DO_BACKUP) {
|
|
assert (option_backup_ext != NULL);
|
|
tmp = g_strconcat (real_filename, option_backup_ext,(char *) NULL);
|
|
if (mc_rename (real_filename, tmp) == -1){
|
|
g_free(tmp);
|
|
goto error_save;
|
|
}
|
|
}
|
|
|
|
if (this_save_mode != EDIT_QUICK_SAVE)
|
|
if (mc_rename (savename, real_filename) == -1)
|
|
goto error_save;
|
|
g_free (savename);
|
|
g_free(real_filename);
|
|
return 1;
|
|
error_save:
|
|
/* FIXME: Is this safe ?
|
|
* if (this_save_mode != EDIT_QUICK_SAVE)
|
|
* mc_unlink (savename);
|
|
*/
|
|
g_free(real_filename);
|
|
g_free (savename);
|
|
return 0;
|
|
}
|
|
|
|
void menu_save_mode_cmd (void)
|
|
{
|
|
#define DLG_X 38
|
|
#define DLG_Y 10
|
|
static char *str_result;
|
|
static int save_mode_new;
|
|
static const char *str[] =
|
|
{
|
|
N_("Quick save "),
|
|
N_("Safe save "),
|
|
N_("Do backups -->")};
|
|
|
|
static QuickWidget widgets[] =
|
|
{
|
|
{quick_button, 18, DLG_X, 7, DLG_Y, N_("&Cancel"), 0,
|
|
B_CANCEL, 0, 0, NULL, NULL, NULL},
|
|
{quick_button, 6, DLG_X, 7, DLG_Y, N_("&OK"), 0,
|
|
B_ENTER, 0, 0, NULL, NULL, NULL},
|
|
{quick_input, 23, DLG_X, 5, DLG_Y, 0, 9,
|
|
0, 0, &str_result, "edit-backup-ext", NULL, NULL},
|
|
{quick_label, 22, DLG_X, 4, DLG_Y, N_("Extension:"), 0,
|
|
0, 0, 0, NULL, NULL, NULL},
|
|
{quick_radio, 4, DLG_X, 3, DLG_Y, "", 3,
|
|
0, &save_mode_new, (char **) str, NULL, NULL, NULL},
|
|
NULL_QuickWidget};
|
|
static QuickDialog dialog =
|
|
{DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
|
|
widgets, 0};
|
|
static int i18n_flag = 0;
|
|
|
|
if (!i18n_flag) {
|
|
size_t i;
|
|
size_t maxlen = 0;
|
|
int dlg_x;
|
|
size_t l1;
|
|
|
|
/* OK/Cancel buttons */
|
|
l1 = str_term_width1 (_(widgets[0].text)) + str_term_width1 (_(widgets[1].text)) + 5;
|
|
maxlen = max (maxlen, l1);
|
|
|
|
for (i = 0; i < 3; i++ ) {
|
|
str[i] = _(str[i]);
|
|
maxlen = max (maxlen, (size_t) str_term_width1 (str[i]) + 7);
|
|
}
|
|
i18n_flag = 1;
|
|
|
|
dlg_x = maxlen + str_term_width1 (_(widgets[3].text)) + 5 + 1;
|
|
widgets[2].hotkey_pos = str_term_width1 (_(widgets[3].text)); /* input field length */
|
|
dlg_x = min (COLS, dlg_x);
|
|
dialog.xlen = dlg_x;
|
|
|
|
i = (dlg_x - l1)/3;
|
|
widgets[1].relative_x = i;
|
|
widgets[0].relative_x = i + str_term_width1 (_(widgets[1].text)) + i + 4;
|
|
|
|
widgets[2].relative_x = widgets[3].relative_x = maxlen + 2;
|
|
|
|
for (i = 0; i < sizeof (widgets)/sizeof (widgets[0]); i++)
|
|
widgets[i].x_divisions = dlg_x;
|
|
}
|
|
|
|
assert (option_backup_ext != NULL);
|
|
widgets[2].text = option_backup_ext;
|
|
widgets[4].value = option_save_mode;
|
|
if (quick_dialog (&dialog) != B_ENTER)
|
|
return;
|
|
option_save_mode = save_mode_new;
|
|
|
|
g_free (option_backup_ext);
|
|
option_backup_ext = str_result;
|
|
str_result = NULL;
|
|
}
|
|
|
|
void
|
|
edit_set_filename (WEdit *edit, const char *f)
|
|
{
|
|
g_free (edit->filename);
|
|
if (!f)
|
|
f = "";
|
|
edit->filename = g_strdup (f);
|
|
if (edit->dir == NULL && *f != PATH_SEP)
|
|
#ifdef USE_VFS
|
|
edit->dir = g_strdup (vfs_get_current_dir ());
|
|
#else
|
|
edit->dir = g_get_current_dir ();
|
|
#endif
|
|
}
|
|
|
|
/* Here we want to warn the users of overwriting an existing file,
|
|
but only if they have made a change to the filename */
|
|
/* returns 1 on success */
|
|
int
|
|
edit_save_as_cmd (WEdit *edit)
|
|
{
|
|
/* This heads the 'Save As' dialog box */
|
|
char *exp;
|
|
int save_lock = 0;
|
|
int different_filename = 0;
|
|
|
|
exp = input_expand_dialog (
|
|
_(" Save As "), _(" Enter file name: "),MC_HISTORY_EDIT_SAVE_AS, edit->filename);
|
|
edit_push_action (edit, KEY_PRESS + edit->start_display);
|
|
|
|
if (exp) {
|
|
if (!*exp) {
|
|
g_free (exp);
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
return 0;
|
|
} else {
|
|
int rv;
|
|
if (strcmp (edit->filename, exp)) {
|
|
int file;
|
|
different_filename = 1;
|
|
if ((file = mc_open (exp, O_RDONLY | O_BINARY)) != -1) {
|
|
/* the file exists */
|
|
mc_close (file);
|
|
/* Overwrite the current file or cancel the operation */
|
|
if (edit_query_dialog2
|
|
(_("Warning"),
|
|
_(" A file already exists with this name. "),
|
|
_("&Overwrite"), _("&Cancel"))) {
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
g_free (exp);
|
|
return 0;
|
|
}
|
|
}
|
|
save_lock = edit_lock_file (exp);
|
|
} else {
|
|
/* filenames equal, check if already locked */
|
|
if (!edit->locked && !edit->delete_file)
|
|
save_lock = edit_lock_file (exp);
|
|
}
|
|
|
|
rv = edit_save_file (edit, exp);
|
|
switch (rv) {
|
|
case 1:
|
|
/* Succesful, so unlock both files */
|
|
if (different_filename) {
|
|
if (save_lock)
|
|
edit_unlock_file (exp);
|
|
if (edit->locked)
|
|
edit->locked = edit_unlock_file (edit->filename);
|
|
} else {
|
|
if (edit->locked || save_lock)
|
|
edit->locked = edit_unlock_file (edit->filename);
|
|
}
|
|
|
|
edit_set_filename (edit, exp);
|
|
g_free (exp);
|
|
edit->modified = 0;
|
|
edit->delete_file = 0;
|
|
if (different_filename)
|
|
edit_load_syntax (edit, NULL, option_syntax_type);
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
return 1;
|
|
default:
|
|
edit_error_dialog (_(" Save As "),
|
|
get_sys_error (_
|
|
(" Cannot save file. ")));
|
|
/* fallthrough */
|
|
case -1:
|
|
/* Failed, so maintain modify (not save) lock */
|
|
if (save_lock)
|
|
edit_unlock_file (exp);
|
|
g_free (exp);
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
return 0;
|
|
}
|
|
|
|
/* {{{ Macro stuff starts here */
|
|
|
|
/* creates a macro file if it doesn't exist */
|
|
static FILE *edit_open_macro_file (const char *r)
|
|
{
|
|
gchar *filename;
|
|
FILE *fd;
|
|
int file;
|
|
filename = g_strconcat ( home_dir, PATH_SEP_STR MACRO_FILE, (char *) NULL);
|
|
if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1){
|
|
g_free(filename);
|
|
return 0;
|
|
}
|
|
close (file);
|
|
fd = fopen (filename, r);
|
|
g_free(filename);
|
|
return fd;
|
|
}
|
|
|
|
#define MAX_MACROS 1024
|
|
static int saved_macro[MAX_MACROS + 1];
|
|
static int saved_macros_loaded = 0;
|
|
|
|
/*
|
|
This is just to stop the macro file be loaded over and over for keys
|
|
that aren't defined to anything. On slow systems this could be annoying.
|
|
*/
|
|
static int
|
|
macro_exists (int k)
|
|
{
|
|
int i;
|
|
for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
|
|
if (saved_macro[i] == k)
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
/* returns 1 on error */
|
|
static int
|
|
edit_delete_macro (WEdit * edit, int k)
|
|
{
|
|
gchar *tmp, *tmp2;
|
|
struct macro macro[MAX_MACRO_LENGTH];
|
|
FILE *f, *g;
|
|
int s, i, n, j = 0;
|
|
|
|
(void) edit;
|
|
|
|
if (saved_macros_loaded)
|
|
if ((j = macro_exists (k)) < 0)
|
|
return 0;
|
|
tmp = g_strconcat (home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL);
|
|
g = fopen (tmp , "w");
|
|
g_free(tmp);
|
|
if (!g) {
|
|
edit_error_dialog (_(" Delete macro "),
|
|
get_sys_error (_(" Cannot open temp file ")));
|
|
return 1;
|
|
}
|
|
f = edit_open_macro_file ("r");
|
|
if (!f) {
|
|
edit_error_dialog (_(" Delete macro "),
|
|
get_sys_error (_(" Cannot open macro file ")));
|
|
fclose (g);
|
|
return 1;
|
|
}
|
|
for (;;) {
|
|
n = fscanf (f, ("key '%d 0': "), &s);
|
|
if (!n || n == EOF)
|
|
break;
|
|
n = 0;
|
|
while (fscanf (f, "%hd %hd, ", ¯o[n].command, ¯o[n].ch))
|
|
n++;
|
|
fscanf (f, ";\n");
|
|
if (s != k) {
|
|
fprintf (g, ("key '%d 0': "), s);
|
|
for (i = 0; i < n; i++)
|
|
fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch);
|
|
fprintf (g, ";\n");
|
|
}
|
|
}
|
|
fclose (f);
|
|
fclose (g);
|
|
tmp = g_strconcat (home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL);
|
|
tmp2 = g_strconcat (home_dir, PATH_SEP_STR MACRO_FILE, (char *) NULL);
|
|
if (rename ( tmp, tmp2) == -1) {
|
|
edit_error_dialog (_(" Delete macro "),
|
|
get_sys_error (_(" Cannot overwrite macro file ")));
|
|
g_free(tmp);
|
|
g_free(tmp2);
|
|
return 1;
|
|
}
|
|
g_free(tmp);
|
|
g_free(tmp2);
|
|
|
|
if (saved_macros_loaded)
|
|
memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
|
|
return 0;
|
|
}
|
|
|
|
/* returns 0 on error */
|
|
int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
|
|
{
|
|
FILE *f;
|
|
int s, i;
|
|
|
|
edit_push_action (edit, KEY_PRESS + edit->start_display);
|
|
s = editcmd_dialog_raw_key_query (_(" Save macro "),
|
|
_(" Press the macro's new hotkey: "), 1);
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
if (s) {
|
|
if (edit_delete_macro (edit, s))
|
|
return 0;
|
|
f = edit_open_macro_file ("a+");
|
|
if (f) {
|
|
fprintf (f, ("key '%d 0': "), s);
|
|
for (i = 0; i < n; i++)
|
|
fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch);
|
|
fprintf (f, ";\n");
|
|
fclose (f);
|
|
if (saved_macros_loaded) {
|
|
for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
|
|
saved_macro[i] = s;
|
|
}
|
|
return 1;
|
|
} else
|
|
edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void edit_delete_macro_cmd (WEdit * edit)
|
|
{
|
|
int command;
|
|
|
|
command = editcmd_dialog_raw_key_query (_ (" Delete macro "),
|
|
_ (" Press macro hotkey: "), 1);
|
|
|
|
if (!command)
|
|
return;
|
|
|
|
edit_delete_macro (edit, command);
|
|
}
|
|
|
|
/* return 0 on error */
|
|
int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
|
|
{
|
|
FILE *f;
|
|
int s, i = 0, found = 0;
|
|
|
|
(void) edit;
|
|
|
|
if (saved_macros_loaded)
|
|
if (macro_exists (k) < 0)
|
|
return 0;
|
|
|
|
if ((f = edit_open_macro_file ("r"))) {
|
|
struct macro dummy;
|
|
do {
|
|
int u;
|
|
u = fscanf (f, ("key '%d 0': "), &s);
|
|
if (!u || u == EOF)
|
|
break;
|
|
if (!saved_macros_loaded)
|
|
saved_macro[i++] = s;
|
|
if (!found) {
|
|
*n = 0;
|
|
while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %hd, ", ¯o[*n].command, ¯o[*n].ch))
|
|
(*n)++;
|
|
} else {
|
|
while (2 == fscanf (f, "%hd %hd, ", &dummy.command, &dummy.ch));
|
|
}
|
|
fscanf (f, ";\n");
|
|
if (s == k)
|
|
found = 1;
|
|
} while (!found || !saved_macros_loaded);
|
|
if (!saved_macros_loaded) {
|
|
saved_macro[i] = 0;
|
|
saved_macros_loaded = 1;
|
|
}
|
|
fclose (f);
|
|
return found;
|
|
} else
|
|
edit_error_dialog (_(" Load macro "),
|
|
get_sys_error (_(" Cannot open macro file ")));
|
|
return 0;
|
|
}
|
|
|
|
/* }}} Macro stuff starts here */
|
|
|
|
/* returns 1 on success */
|
|
int edit_save_confirm_cmd (WEdit * edit)
|
|
{
|
|
gchar *f = NULL;
|
|
|
|
if (edit_confirm_save) {
|
|
f = g_strconcat (_(" Confirm save file? : "), edit->filename, " ", NULL);
|
|
if (edit_query_dialog2 (_(" Save file "), f, _("&Save"), _("&Cancel"))){
|
|
g_free(f);
|
|
return 0;
|
|
}
|
|
g_free(f);
|
|
}
|
|
return edit_save_cmd (edit);
|
|
}
|
|
|
|
|
|
/* returns 1 on success */
|
|
static int
|
|
edit_save_cmd (WEdit *edit)
|
|
{
|
|
int res, save_lock = 0;
|
|
|
|
if (!edit->locked && !edit->delete_file)
|
|
save_lock = edit_lock_file (edit->filename);
|
|
res = edit_save_file (edit, edit->filename);
|
|
|
|
/* Maintain modify (not save) lock on failure */
|
|
if ((res > 0 && edit->locked) || save_lock)
|
|
edit->locked = edit_unlock_file (edit->filename);
|
|
|
|
/* On failure try 'save as', it does locking on its own */
|
|
if (!res)
|
|
return edit_save_as_cmd (edit);
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
if (res > 0) {
|
|
edit->delete_file = 0;
|
|
edit->modified = 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* returns 1 on success */
|
|
int edit_new_cmd (WEdit * edit)
|
|
{
|
|
if (edit->modified) {
|
|
if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("C&ontinue"), _ ("&Cancel"))) {
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
return 0;
|
|
}
|
|
}
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
|
|
return edit_renew (edit); /* if this gives an error, something has really screwed up */
|
|
}
|
|
|
|
/* returns 1 on error */
|
|
static int
|
|
edit_load_file_from_filename (WEdit * edit, char *exp)
|
|
{
|
|
int prev_locked = edit->locked;
|
|
char *prev_filename = g_strdup (edit->filename);
|
|
|
|
if (!edit_reload (edit, exp)) {
|
|
g_free (prev_filename);
|
|
return 1;
|
|
}
|
|
|
|
if (prev_locked)
|
|
edit_unlock_file (prev_filename);
|
|
g_free (prev_filename);
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
edit_load_syntax_file (WEdit * edit)
|
|
{
|
|
char *extdir;
|
|
int dir = 0;
|
|
|
|
if (geteuid () == 0) {
|
|
dir = query_dialog (_("Syntax file edit"),
|
|
_(" Which syntax file you want to edit? "), D_NORMAL, 2,
|
|
_("&User"), _("&System Wide"));
|
|
}
|
|
extdir = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
|
|
|
|
if (dir == 0) {
|
|
char *buffer;
|
|
|
|
buffer = concat_dir_and_file (home_dir, SYNTAX_FILE);
|
|
check_for_default (extdir, buffer);
|
|
edit_load_file_from_filename (edit, buffer);
|
|
g_free (buffer);
|
|
} else if (dir == 1)
|
|
edit_load_file_from_filename (edit, extdir);
|
|
|
|
g_free (extdir);
|
|
}
|
|
|
|
static void
|
|
edit_load_menu_file (WEdit * edit)
|
|
{
|
|
char *buffer;
|
|
char *menufile;
|
|
int dir = 0;
|
|
|
|
dir = query_dialog (
|
|
_(" Menu edit "),
|
|
_(" Which menu file do you want to edit? "), D_NORMAL,
|
|
geteuid() ? 2 : 3, _("&Local"), _("&User"), _("&System Wide")
|
|
);
|
|
|
|
menufile = concat_dir_and_file (mc_home, CEDIT_GLOBAL_MENU);
|
|
|
|
switch (dir) {
|
|
case 0:
|
|
buffer = g_strdup (CEDIT_LOCAL_MENU);
|
|
check_for_default (menufile, buffer);
|
|
chmod (buffer, 0600);
|
|
break;
|
|
|
|
case 1:
|
|
buffer = concat_dir_and_file (home_dir, CEDIT_HOME_MENU);
|
|
check_for_default (menufile, buffer);
|
|
break;
|
|
|
|
case 2:
|
|
buffer = concat_dir_and_file (mc_home, CEDIT_GLOBAL_MENU);
|
|
break;
|
|
|
|
default:
|
|
g_free (menufile);
|
|
return;
|
|
}
|
|
|
|
edit_load_file_from_filename (edit, buffer);
|
|
|
|
g_free (buffer);
|
|
g_free (menufile);
|
|
}
|
|
|
|
int
|
|
edit_load_cmd (WEdit *edit, edit_current_file_t what)
|
|
{
|
|
char *exp;
|
|
|
|
if (edit->modified
|
|
&& (edit_query_dialog2
|
|
(_("Warning"),
|
|
_(" Current text was modified without a file save. \n"
|
|
" Continue discards these changes. "),
|
|
_("C&ontinue"), _("&Cancel")) == 1)) {
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
return 0;
|
|
}
|
|
|
|
switch (what) {
|
|
case EDIT_FILE_COMMON:
|
|
exp = input_expand_dialog (_(" Load "), _(" Enter file name: "),
|
|
MC_HISTORY_EDIT_LOAD, edit->filename);
|
|
|
|
if (exp) {
|
|
if (*exp)
|
|
edit_load_file_from_filename (edit, exp);
|
|
g_free (exp);
|
|
}
|
|
break;
|
|
|
|
case EDIT_FILE_SYNTAX:
|
|
edit_load_syntax_file (edit);
|
|
break;
|
|
|
|
case EDIT_FILE_MENU:
|
|
edit_load_menu_file (edit);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
if mark2 is -1 then marking is from mark1 to the cursor.
|
|
Otherwise its between the markers. This handles this.
|
|
Returns 1 if no text is marked.
|
|
*/
|
|
int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
|
|
{
|
|
if (edit->mark1 != edit->mark2) {
|
|
if (edit->mark2 >= 0) {
|
|
*start_mark = min (edit->mark1, edit->mark2);
|
|
*end_mark = max (edit->mark1, edit->mark2);
|
|
} else {
|
|
*start_mark = min (edit->mark1, edit->curs1);
|
|
*end_mark = max (edit->mark1, edit->curs1);
|
|
edit->column2 = edit->curs_col;
|
|
}
|
|
return 0;
|
|
} else {
|
|
*start_mark = *end_mark = 0;
|
|
edit->column2 = edit->column1 = 0;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
#define space_width 1
|
|
|
|
static void
|
|
edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
|
|
{
|
|
long cursor;
|
|
int i, col;
|
|
cursor = edit->curs1;
|
|
col = edit_get_col (edit);
|
|
for (i = 0; i < size; i++) {
|
|
if (data[i] == '\n') { /* fill in and move to next line */
|
|
int l;
|
|
long p;
|
|
if (edit_get_byte (edit, edit->curs1) != '\n') {
|
|
l = width - (edit_get_col (edit) - col);
|
|
while (l > 0) {
|
|
edit_insert (edit, ' ');
|
|
l -= space_width;
|
|
}
|
|
}
|
|
for (p = edit->curs1;; p++) {
|
|
if (p == edit->last_byte) {
|
|
edit_cursor_move (edit, edit->last_byte - edit->curs1);
|
|
edit_insert_ahead (edit, '\n');
|
|
p++;
|
|
break;
|
|
}
|
|
if (edit_get_byte (edit, p) == '\n') {
|
|
p++;
|
|
break;
|
|
}
|
|
}
|
|
edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
|
|
l = col - edit_get_col (edit);
|
|
while (l >= space_width) {
|
|
edit_insert (edit, ' ');
|
|
l -= space_width;
|
|
}
|
|
continue;
|
|
}
|
|
edit_insert (edit, data[i]);
|
|
}
|
|
edit_cursor_move (edit, cursor - edit->curs1);
|
|
}
|
|
|
|
|
|
void
|
|
edit_block_copy_cmd (WEdit *edit)
|
|
{
|
|
long start_mark, end_mark, current = edit->curs1;
|
|
int size;
|
|
unsigned char *copy_buf;
|
|
|
|
edit_update_curs_col (edit);
|
|
if (eval_marks (edit, &start_mark, &end_mark))
|
|
return;
|
|
|
|
copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
|
|
|
|
/* all that gets pushed are deletes hence little space is used on the stack */
|
|
|
|
edit_push_markers (edit);
|
|
|
|
if (column_highlighting) {
|
|
edit_insert_column_of_text (edit, copy_buf, size,
|
|
abs (edit->column2 - edit->column1));
|
|
} else {
|
|
while (size--)
|
|
edit_insert_ahead (edit, copy_buf[size]);
|
|
}
|
|
|
|
g_free (copy_buf);
|
|
edit_scroll_screen_over_cursor (edit);
|
|
|
|
if (column_highlighting) {
|
|
edit_set_markers (edit, 0, 0, 0, 0);
|
|
edit_push_action (edit, COLUMN_ON);
|
|
column_highlighting = 0;
|
|
} else if (start_mark < current && end_mark > current)
|
|
edit_set_markers (edit, start_mark,
|
|
end_mark + end_mark - start_mark, 0, 0);
|
|
|
|
edit->force |= REDRAW_PAGE;
|
|
}
|
|
|
|
|
|
void
|
|
edit_block_move_cmd (WEdit *edit)
|
|
{
|
|
long count;
|
|
long current;
|
|
unsigned char *copy_buf;
|
|
long start_mark, end_mark;
|
|
int deleted = 0;
|
|
int x = 0;
|
|
|
|
if (eval_marks (edit, &start_mark, &end_mark))
|
|
return;
|
|
if (column_highlighting) {
|
|
edit_update_curs_col (edit);
|
|
x = edit->curs_col;
|
|
if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
|
|
if ((x > edit->column1 && x < edit->column2)
|
|
|| (x > edit->column2 && x < edit->column1))
|
|
return;
|
|
} else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
|
|
return;
|
|
|
|
if ((end_mark - start_mark) > option_max_undo / 2)
|
|
if (edit_query_dialog2
|
|
(_("Warning"),
|
|
_
|
|
(" Block is large, you may not be able to undo this action. "),
|
|
_("C&ontinue"), _("&Cancel")))
|
|
return;
|
|
|
|
edit_push_markers (edit);
|
|
current = edit->curs1;
|
|
if (column_highlighting) {
|
|
int size, c1, c2, line;
|
|
line = edit->curs_line;
|
|
if (edit->mark2 < 0)
|
|
edit_mark_cmd (edit, 0);
|
|
c1 = min (edit->column1, edit->column2);
|
|
c2 = max (edit->column1, edit->column2);
|
|
copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
|
|
if (x < c2) {
|
|
edit_block_delete_cmd (edit);
|
|
deleted = 1;
|
|
}
|
|
edit_move_to_line (edit, line);
|
|
edit_cursor_move (edit,
|
|
edit_move_forward3 (edit,
|
|
edit_bol (edit, edit->curs1),
|
|
x, 0) - edit->curs1);
|
|
edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
|
|
if (!deleted) {
|
|
line = edit->curs_line;
|
|
edit_update_curs_col (edit);
|
|
x = edit->curs_col;
|
|
edit_block_delete_cmd (edit);
|
|
edit_move_to_line (edit, line);
|
|
edit_cursor_move (edit,
|
|
edit_move_forward3 (edit,
|
|
edit_bol (edit,
|
|
edit->curs1),
|
|
x, 0) - edit->curs1);
|
|
}
|
|
edit_set_markers (edit, 0, 0, 0, 0);
|
|
edit_push_action (edit, COLUMN_ON);
|
|
column_highlighting = 0;
|
|
} else {
|
|
copy_buf = g_malloc (end_mark - start_mark);
|
|
edit_cursor_move (edit, start_mark - edit->curs1);
|
|
edit_scroll_screen_over_cursor (edit);
|
|
count = start_mark;
|
|
while (count < end_mark) {
|
|
copy_buf[end_mark - count - 1] = edit_delete (edit, 1);
|
|
count++;
|
|
}
|
|
edit_scroll_screen_over_cursor (edit);
|
|
edit_cursor_move (edit,
|
|
current - edit->curs1 -
|
|
(((current - edit->curs1) >
|
|
0) ? end_mark - start_mark : 0));
|
|
edit_scroll_screen_over_cursor (edit);
|
|
while (count-- > start_mark)
|
|
edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
|
|
edit_set_markers (edit, edit->curs1,
|
|
edit->curs1 + end_mark - start_mark, 0, 0);
|
|
}
|
|
edit_scroll_screen_over_cursor (edit);
|
|
g_free (copy_buf);
|
|
edit->force |= REDRAW_PAGE;
|
|
}
|
|
|
|
static void
|
|
edit_delete_column_of_text (WEdit * edit)
|
|
{
|
|
long p, q, r, m1, m2;
|
|
int b, c, d;
|
|
int n;
|
|
|
|
eval_marks (edit, &m1, &m2);
|
|
n = edit_move_forward (edit, m1, 0, m2) + 1;
|
|
c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
|
|
d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
|
|
|
|
b = min (c, d);
|
|
c = max (c, d);
|
|
|
|
while (n--) {
|
|
r = edit_bol (edit, edit->curs1);
|
|
p = edit_move_forward3 (edit, r, b, 0);
|
|
q = edit_move_forward3 (edit, r, c, 0);
|
|
if (p < m1)
|
|
p = m1;
|
|
if (q > m2)
|
|
q = m2;
|
|
edit_cursor_move (edit, p - edit->curs1);
|
|
while (q > p) { /* delete line between margins */
|
|
if (edit_get_byte (edit, edit->curs1) != '\n')
|
|
edit_delete (edit, 1);
|
|
q--;
|
|
}
|
|
if (n) /* move to next line except on the last delete */
|
|
edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
|
|
}
|
|
}
|
|
|
|
/* if success return 0 */
|
|
static int
|
|
edit_block_delete (WEdit *edit)
|
|
{
|
|
long count;
|
|
long start_mark, end_mark;
|
|
if (eval_marks (edit, &start_mark, &end_mark))
|
|
return 0;
|
|
if (column_highlighting && edit->mark2 < 0)
|
|
edit_mark_cmd (edit, 0);
|
|
if ((end_mark - start_mark) > option_max_undo / 2) {
|
|
/* Warning message with a query to continue or cancel the operation */
|
|
if (edit_query_dialog2
|
|
(_("Warning"),
|
|
_
|
|
(" Block is large, you may not be able to undo this action. "),
|
|
_("C&ontinue"), _("&Cancel"))) {
|
|
return 1;
|
|
}
|
|
}
|
|
edit_push_markers (edit);
|
|
edit_cursor_move (edit, start_mark - edit->curs1);
|
|
edit_scroll_screen_over_cursor (edit);
|
|
count = start_mark;
|
|
if (start_mark < end_mark) {
|
|
if (column_highlighting) {
|
|
if (edit->mark2 < 0)
|
|
edit_mark_cmd (edit, 0);
|
|
edit_delete_column_of_text (edit);
|
|
} else {
|
|
while (count < end_mark) {
|
|
edit_delete (edit, 1);
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
edit_set_markers (edit, 0, 0, 0, 0);
|
|
edit->force |= REDRAW_PAGE;
|
|
return 0;
|
|
}
|
|
|
|
/* returns 1 if canceelled by user */
|
|
int edit_block_delete_cmd (WEdit * edit)
|
|
{
|
|
long start_mark, end_mark;
|
|
if (eval_marks (edit, &start_mark, &end_mark)) {
|
|
edit_delete_line (edit);
|
|
return 0;
|
|
}
|
|
return edit_block_delete (edit);
|
|
}
|
|
|
|
#define INPUT_INDEX 9
|
|
|
|
static gboolean
|
|
editcmd_find (WEdit *edit, gsize *len)
|
|
{
|
|
gsize search_start = edit->search_start;
|
|
gsize search_end;
|
|
|
|
if (edit->replace_backwards) {
|
|
search_end = edit->curs1-1;
|
|
while ((int) search_start >= 0) {
|
|
if (search_end - search_start > edit->search->original_len && mc_search_is_fixed_search_str(edit->search))
|
|
search_end = search_start + edit->search->original_len +1;
|
|
if ( mc_search_run(edit->search, (void *) edit, search_start, search_end, len))
|
|
{
|
|
return TRUE;
|
|
}
|
|
search_start--;
|
|
}
|
|
edit->search->error_str = g_strdup(_(" Search string not found "));
|
|
} else {
|
|
return mc_search_run(edit->search, (void *) edit, edit->search_start, edit->last_byte, len);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
|
|
(and the above) routines to work properly - paul */
|
|
|
|
#define is_digit(x) ((x) >= '0' && (x) <= '9')
|
|
|
|
static char *
|
|
edit_replace_cmd__conv_to_display(char *str)
|
|
{
|
|
#ifdef HAVE_CHARSET
|
|
GString *tmp;
|
|
tmp = str_convert_to_display (str);
|
|
|
|
if (tmp && tmp->len){
|
|
g_free(str);
|
|
str = tmp->str;
|
|
}
|
|
g_string_free (tmp, FALSE);
|
|
return str;
|
|
#else
|
|
return g_strdup(str);
|
|
#endif
|
|
}
|
|
|
|
static char *
|
|
edit_replace_cmd__conv_to_input(char *str)
|
|
{
|
|
#ifdef HAVE_CHARSET
|
|
GString *tmp;
|
|
tmp = str_convert_to_input (str);
|
|
|
|
if (tmp && tmp->len){
|
|
g_free(str);
|
|
str = tmp->str;
|
|
}
|
|
g_string_free (tmp, FALSE);
|
|
return str;
|
|
#else
|
|
return g_strdup(str);
|
|
#endif
|
|
}
|
|
/* call with edit = 0 before shutdown to close memory leaks */
|
|
void
|
|
edit_replace_cmd (WEdit *edit, int again)
|
|
{
|
|
/* 1 = search string, 2 = replace with */
|
|
static char *saved1 = NULL; /* saved default[123] */
|
|
static char *saved2 = NULL;
|
|
char *input1 = NULL; /* user input from the dialog */
|
|
char *input2 = NULL;
|
|
char *str_for_prompt_dialog = NULL;
|
|
int replace_yes;
|
|
long times_replaced = 0, last_search;
|
|
gboolean once_found = FALSE;
|
|
|
|
if (!edit) {
|
|
g_free (saved1), saved1 = NULL;
|
|
g_free (saved2), saved2 = NULL;
|
|
return;
|
|
}
|
|
|
|
last_search = edit->last_byte;
|
|
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
|
|
if (again && !saved1 && !saved2)
|
|
again = 0;
|
|
|
|
if (again) {
|
|
input1 = g_strdup (saved1 ? saved1 : "");
|
|
input2 = g_strdup (saved2 ? saved2 : "");
|
|
} else {
|
|
char *disp1 = edit_replace_cmd__conv_to_display(g_strdup (saved1 ? saved1 : ""));
|
|
char *disp2 = edit_replace_cmd__conv_to_display(g_strdup (saved2 ? saved2 : ""));
|
|
|
|
edit_push_action (edit, KEY_PRESS + edit->start_display);
|
|
|
|
editcmd_dialog_replace_show (edit, disp1, disp2, &input1, &input2 );
|
|
|
|
g_free (disp1);
|
|
g_free (disp2);
|
|
|
|
str_for_prompt_dialog = g_strdup(input2);
|
|
|
|
if (input1 == NULL || *input1 == '\0') {
|
|
edit->force = REDRAW_COMPLETELY;
|
|
goto cleanup;
|
|
}
|
|
|
|
input1 = edit_replace_cmd__conv_to_input(input1);
|
|
input2 = edit_replace_cmd__conv_to_input(input2);
|
|
|
|
g_free (saved1), saved1 = g_strdup (input1);
|
|
g_free (saved2), saved2 = g_strdup (input2);
|
|
|
|
if (edit->search)
|
|
{
|
|
mc_search_free(edit->search);
|
|
edit->search = NULL;
|
|
}
|
|
}
|
|
|
|
if (!edit->search)
|
|
{
|
|
edit->search = mc_search_new(input1, -1);
|
|
if (edit->search == NULL)
|
|
{
|
|
edit->search_start = edit->curs1;
|
|
return;
|
|
}
|
|
edit->search->search_type = edit->search_type;
|
|
edit->search->is_all_charsets = edit->all_codepages;
|
|
edit->search->is_case_sentitive = edit->replace_case;
|
|
edit->search->search_fn = edit_search_cmd_callback;
|
|
}
|
|
|
|
if (edit->found_len && edit->search_start == edit->found_start + 1
|
|
&& edit->replace_backwards)
|
|
edit->search_start--;
|
|
|
|
if (edit->found_len && edit->search_start == edit->found_start - 1
|
|
&& !edit->replace_backwards)
|
|
edit->search_start++;
|
|
|
|
do {
|
|
gsize len = 0;
|
|
long new_start;
|
|
|
|
if (! editcmd_find(edit, &len))
|
|
{
|
|
if (!(edit->search->error == MC_SEARCH_E_OK || (once_found && edit->search->error == MC_SEARCH_E_NOTFOUND)))
|
|
{
|
|
edit_error_dialog (_ ("Search"), edit->search->error_str);
|
|
}
|
|
break;
|
|
}
|
|
once_found = TRUE;
|
|
new_start = edit->search->normal_offset;
|
|
|
|
edit->search_start = new_start = edit->search->normal_offset;
|
|
/*returns negative on not found or error in pattern */
|
|
|
|
if (edit->search_start >= 0) {
|
|
int i;
|
|
|
|
edit->found_start = edit->search_start;
|
|
i = edit->found_len = len;
|
|
|
|
edit_cursor_move (edit, edit->search_start - edit->curs1);
|
|
edit_scroll_screen_over_cursor (edit);
|
|
|
|
replace_yes = 1;
|
|
|
|
if (edit->replace_mode==0) {
|
|
int l;
|
|
l = edit->curs_row - edit->num_widget_lines / 3;
|
|
if (l > 0)
|
|
edit_scroll_downward (edit, l);
|
|
if (l < 0)
|
|
edit_scroll_upward (edit, -l);
|
|
|
|
edit_scroll_screen_over_cursor (edit);
|
|
edit->force |= REDRAW_PAGE;
|
|
edit_render_keypress (edit);
|
|
|
|
/*so that undo stops at each query */
|
|
edit_push_key_press (edit);
|
|
|
|
switch (editcmd_dialog_replace_prompt_show (edit, str_for_prompt_dialog, /* and prompt 2/3 down */
|
|
-1,
|
|
-1)) {
|
|
case B_ENTER:
|
|
break;
|
|
case B_SKIP_REPLACE:
|
|
replace_yes = 0;
|
|
break;
|
|
case B_REPLACE_ALL:
|
|
edit->replace_mode=1;
|
|
break;
|
|
case B_REPLACE_ONE:
|
|
break;
|
|
case B_CANCEL:
|
|
replace_yes = 0;
|
|
break;
|
|
}
|
|
}
|
|
if (replace_yes) { /* delete then insert new */
|
|
GString *repl_str, *tmp_str;
|
|
tmp_str = g_string_new(input2);
|
|
|
|
repl_str = mc_search_prepare_replace_str (edit->search, tmp_str);
|
|
g_string_free(tmp_str, TRUE);
|
|
if (edit->search->error != MC_SEARCH_E_OK)
|
|
{
|
|
edit_error_dialog (_ ("Replace"), edit->search->error_str);
|
|
break;
|
|
}
|
|
|
|
while (i--)
|
|
edit_delete (edit, 1);
|
|
|
|
while (++i < repl_str->len)
|
|
edit_insert (edit, repl_str->str[i]);
|
|
|
|
g_string_free(repl_str, TRUE);
|
|
edit->found_len = i;
|
|
}
|
|
/* so that we don't find the same string again */
|
|
if (edit->replace_backwards) {
|
|
last_search = edit->search_start;
|
|
edit->search_start--;
|
|
} else {
|
|
edit->search_start += i;
|
|
last_search = edit->last_byte;
|
|
}
|
|
edit_scroll_screen_over_cursor (edit);
|
|
} else {
|
|
const char *msg = _(" Replace ");
|
|
/* try and find from right here for next search */
|
|
edit->search_start = edit->curs1;
|
|
edit_update_curs_col (edit);
|
|
|
|
edit->force |= REDRAW_PAGE;
|
|
edit_render_keypress (edit);
|
|
if (times_replaced) {
|
|
message (D_NORMAL, msg, _(" %ld replacements made. "),
|
|
times_replaced);
|
|
} else
|
|
query_dialog (msg, _(" Search string not found "),
|
|
D_NORMAL, 1, _("&OK"));
|
|
edit->replace_mode = -1;
|
|
}
|
|
} while (edit->replace_mode >0);
|
|
|
|
edit->force = REDRAW_COMPLETELY;
|
|
edit_scroll_screen_over_cursor (edit);
|
|
cleanup:
|
|
g_free (str_for_prompt_dialog);
|
|
g_free (input1);
|
|
g_free (input2);
|
|
}
|
|
|
|
|
|
void edit_search_cmd (WEdit * edit, int again)
|
|
{
|
|
char *search_string = NULL, *search_string_dup = NULL;
|
|
|
|
gsize len = 0;
|
|
|
|
if (!edit)
|
|
return;
|
|
|
|
if (edit->search != NULL)
|
|
search_string_dup = search_string = g_strndup(edit->search->original, edit->search->original_len);
|
|
|
|
if (!again)
|
|
{
|
|
#ifdef HAVE_CHARSET
|
|
GString *tmp;
|
|
if (search_string && *search_string)
|
|
{
|
|
tmp = str_convert_to_display (search_string);
|
|
|
|
g_free(search_string_dup);
|
|
search_string_dup = NULL;
|
|
|
|
if (tmp && tmp->len)
|
|
search_string = search_string_dup = tmp->str;
|
|
g_string_free (tmp, FALSE);
|
|
}
|
|
#endif /* HAVE_CHARSET */
|
|
editcmd_dialog_search_show (edit, &search_string);
|
|
#ifdef HAVE_CHARSET
|
|
if (search_string && *search_string)
|
|
{
|
|
tmp = str_convert_to_input (search_string);
|
|
if (tmp && tmp->len)
|
|
search_string = tmp->str;
|
|
|
|
g_string_free (tmp, FALSE);
|
|
|
|
if (search_string_dup)
|
|
g_free(search_string_dup);
|
|
}
|
|
#endif /* HAVE_CHARSET */
|
|
|
|
edit_push_action (edit, KEY_PRESS + edit->start_display);
|
|
|
|
if (!search_string)
|
|
{
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
edit_scroll_screen_over_cursor (edit);
|
|
return;
|
|
}
|
|
|
|
if (edit->search)
|
|
{
|
|
mc_search_free(edit->search);
|
|
edit->search = NULL;
|
|
}
|
|
}
|
|
|
|
if (!edit->search)
|
|
{
|
|
edit->search = mc_search_new(search_string, -1);
|
|
if (edit->search == NULL)
|
|
{
|
|
edit->search_start = edit->curs1;
|
|
return;
|
|
}
|
|
edit->search->search_type = edit->search_type;
|
|
edit->search->is_all_charsets = edit->all_codepages;
|
|
edit->search->is_case_sentitive = edit->replace_case;
|
|
edit->search->search_fn = edit_search_cmd_callback;
|
|
}
|
|
|
|
if (search_create_bookmark)
|
|
{
|
|
edit_search_cmd_search_create_bookmark(edit);
|
|
}
|
|
else
|
|
{
|
|
if (edit->found_len && edit->search_start == edit->found_start + 1 && edit->replace_backwards)
|
|
edit->search_start--;
|
|
|
|
if (edit->found_len && edit->search_start == edit->found_start - 1 && !edit->replace_backwards)
|
|
edit->search_start++;
|
|
|
|
|
|
if (editcmd_find(edit, &len))
|
|
{
|
|
edit->found_start = edit->search_start = edit->search->normal_offset;
|
|
edit->found_len = len;
|
|
|
|
edit_cursor_move (edit, edit->search_start - edit->curs1);
|
|
edit_scroll_screen_over_cursor (edit);
|
|
if (edit->replace_backwards)
|
|
edit->search_start--;
|
|
else
|
|
edit->search_start++;
|
|
}
|
|
else
|
|
{
|
|
edit->search_start = edit->curs1;
|
|
if (edit->search->error_str)
|
|
edit_error_dialog (_ ("Search"), edit->search->error_str);
|
|
}
|
|
}
|
|
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
edit_scroll_screen_over_cursor (edit);
|
|
}
|
|
|
|
|
|
/*
|
|
* Check if it's OK to close the editor. If there are unsaved changes,
|
|
* ask user. Return 1 if it's OK to exit, 0 to continue editing.
|
|
*/
|
|
int
|
|
edit_ok_to_exit (WEdit *edit)
|
|
{
|
|
if (!edit->modified)
|
|
return 1;
|
|
|
|
switch (edit_query_dialog3
|
|
(_("Quit"), _(" File was modified, Save with exit? "),
|
|
_("&Cancel quit"), _("&Yes"), _("&No"))) {
|
|
case 1:
|
|
edit_push_markers (edit);
|
|
edit_set_markers (edit, 0, 0, 0, 0);
|
|
if (!edit_save_cmd (edit))
|
|
return 0;
|
|
break;
|
|
case 2:
|
|
break;
|
|
case 0:
|
|
case -1:
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
#define TEMP_BUF_LEN 1024
|
|
|
|
/* Return a null terminated length of text. Result must be g_free'd */
|
|
static unsigned char *
|
|
edit_get_block (WEdit *edit, long start, long finish, int *l)
|
|
{
|
|
unsigned char *s, *r;
|
|
r = s = g_malloc (finish - start + 1);
|
|
if (column_highlighting) {
|
|
*l = 0;
|
|
/* copy from buffer, excluding chars that are out of the column 'margins' */
|
|
while (start < finish) {
|
|
int c, x;
|
|
x = edit_move_forward3 (edit, edit_bol (edit, start), 0,
|
|
start);
|
|
c = edit_get_byte (edit, start);
|
|
if ((x >= edit->column1 && x < edit->column2)
|
|
|| (x >= edit->column2 && x < edit->column1) || c == '\n') {
|
|
*s++ = c;
|
|
(*l)++;
|
|
}
|
|
start++;
|
|
}
|
|
} else {
|
|
*l = finish - start;
|
|
while (start < finish)
|
|
*s++ = edit_get_byte (edit, start++);
|
|
}
|
|
*s = 0;
|
|
return r;
|
|
}
|
|
|
|
/* save block, returns 1 on success */
|
|
int
|
|
edit_save_block (WEdit * edit, const char *filename, long start,
|
|
long finish)
|
|
{
|
|
int len, file;
|
|
|
|
if ((file =
|
|
mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
|
|
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY)) == -1)
|
|
return 0;
|
|
|
|
if (column_highlighting) {
|
|
unsigned char *block, *p;
|
|
int r;
|
|
p = block = edit_get_block (edit, start, finish, &len);
|
|
while (len) {
|
|
r = mc_write (file, p, len);
|
|
if (r < 0)
|
|
break;
|
|
p += r;
|
|
len -= r;
|
|
}
|
|
g_free (block);
|
|
} else {
|
|
unsigned char *buf;
|
|
int i = start, end;
|
|
len = finish - start;
|
|
buf = g_malloc (TEMP_BUF_LEN);
|
|
while (start != finish) {
|
|
end = min (finish, start + TEMP_BUF_LEN);
|
|
for (; i < end; i++)
|
|
buf[i - start] = edit_get_byte (edit, i);
|
|
len -= mc_write (file, (char *) buf, end - start);
|
|
start = end;
|
|
}
|
|
g_free (buf);
|
|
}
|
|
mc_close (file);
|
|
if (len)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
/* copies a block to clipboard file */
|
|
static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
|
|
{
|
|
int ret;
|
|
gchar *tmp;
|
|
tmp = g_strconcat (home_dir, PATH_SEP_STR CLIP_FILE, (char *) NULL);
|
|
ret = edit_save_block (edit, tmp, start, finish);
|
|
g_free(tmp);
|
|
return ret;
|
|
}
|
|
|
|
|
|
void edit_paste_from_history (WEdit *edit)
|
|
{
|
|
(void) edit;
|
|
edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
|
|
}
|
|
|
|
int edit_copy_to_X_buf_cmd (WEdit * edit)
|
|
{
|
|
long start_mark, end_mark;
|
|
if (eval_marks (edit, &start_mark, &end_mark))
|
|
return 0;
|
|
if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
|
|
edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
|
|
return 1;
|
|
}
|
|
edit_mark_cmd (edit, 1);
|
|
return 0;
|
|
}
|
|
|
|
int edit_cut_to_X_buf_cmd (WEdit * edit)
|
|
{
|
|
long start_mark, end_mark;
|
|
if (eval_marks (edit, &start_mark, &end_mark))
|
|
return 0;
|
|
if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
|
|
edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
|
|
return 1;
|
|
}
|
|
edit_block_delete_cmd (edit);
|
|
edit_mark_cmd (edit, 1);
|
|
return 0;
|
|
}
|
|
|
|
void edit_paste_from_X_buf_cmd (WEdit * edit)
|
|
{
|
|
gchar *tmp;
|
|
tmp = g_strconcat (home_dir, PATH_SEP_STR CLIP_FILE, (char *) NULL);
|
|
edit_insert_file (edit, tmp);
|
|
g_free(tmp);
|
|
}
|
|
|
|
|
|
/*
|
|
* Ask user for the line and go to that line.
|
|
* Negative numbers mean line from the end (i.e. -1 is the last line).
|
|
*/
|
|
void
|
|
edit_goto_cmd (WEdit *edit)
|
|
{
|
|
char *f;
|
|
static long line = 0; /* line as typed, saved as default */
|
|
long l;
|
|
char *error;
|
|
char s[32];
|
|
|
|
g_snprintf (s, sizeof (s), "%ld", line);
|
|
f = input_dialog (_(" Goto line "), _(" Enter line: "), MC_HISTORY_EDIT_GOTO_LINE,
|
|
line ? s : "");
|
|
if (!f)
|
|
return;
|
|
|
|
if (!*f) {
|
|
g_free (f);
|
|
return;
|
|
}
|
|
|
|
l = strtol (f, &error, 0);
|
|
if (*error) {
|
|
g_free (f);
|
|
return;
|
|
}
|
|
|
|
line = l;
|
|
if (l < 0)
|
|
l = edit->total_lines + l + 2;
|
|
edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
|
|
edit_move_to_line (edit, l - 1);
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
g_free (f);
|
|
}
|
|
|
|
|
|
/* Return 1 on success */
|
|
int
|
|
edit_save_block_cmd (WEdit *edit)
|
|
{
|
|
long start_mark, end_mark;
|
|
char *exp, *tmp;
|
|
if (eval_marks (edit, &start_mark, &end_mark))
|
|
return 1;
|
|
tmp = g_strconcat (home_dir, PATH_SEP_STR CLIP_FILE, (char *) NULL);
|
|
exp =
|
|
input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
|
|
MC_HISTORY_EDIT_SAVE_BLOCK,
|
|
tmp);
|
|
g_free(tmp);
|
|
edit_push_action (edit, KEY_PRESS + edit->start_display);
|
|
if (exp) {
|
|
if (!*exp) {
|
|
g_free (exp);
|
|
return 0;
|
|
} else {
|
|
if (edit_save_block (edit, exp, start_mark, end_mark)) {
|
|
g_free (exp);
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
return 1;
|
|
} else {
|
|
g_free (exp);
|
|
edit_error_dialog (_(" Save Block "),
|
|
get_sys_error (_
|
|
(" Cannot save file. ")));
|
|
}
|
|
}
|
|
}
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* returns 1 on success */
|
|
int
|
|
edit_insert_file_cmd (WEdit *edit)
|
|
{
|
|
gchar *tmp;
|
|
char *exp;
|
|
|
|
tmp = g_strconcat (home_dir, PATH_SEP_STR CLIP_FILE, (char *) NULL);
|
|
exp = input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
|
|
MC_HISTORY_EDIT_INSERT_FILE,
|
|
tmp);
|
|
g_free(tmp);
|
|
edit_push_action (edit, KEY_PRESS + edit->start_display);
|
|
if (exp) {
|
|
if (!*exp) {
|
|
g_free (exp);
|
|
return 0;
|
|
} else {
|
|
if (edit_insert_file (edit, exp)) {
|
|
g_free (exp);
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
return 1;
|
|
} else {
|
|
g_free (exp);
|
|
edit_error_dialog (_(" Insert File "),
|
|
get_sys_error (_
|
|
(" Cannot insert file. ")));
|
|
}
|
|
}
|
|
}
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
return 0;
|
|
}
|
|
|
|
/* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
|
|
int edit_sort_cmd (WEdit * edit)
|
|
{
|
|
static char *old = 0;
|
|
char *exp, *tmp;
|
|
long start_mark, end_mark;
|
|
int e;
|
|
|
|
if (eval_marks (edit, &start_mark, &end_mark)) {
|
|
edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
|
|
return 0;
|
|
}
|
|
tmp = g_strconcat (home_dir, PATH_SEP_STR BLOCK_FILE, (char *) NULL);
|
|
edit_save_block (edit, tmp, start_mark, end_mark);
|
|
g_free(tmp);
|
|
|
|
exp = input_dialog (_(" Run Sort "),
|
|
_(" Enter sort options (see manpage) separated by whitespace: "),
|
|
MC_HISTORY_EDIT_SORT, (old != NULL) ? old : "");
|
|
|
|
if (!exp)
|
|
return 1;
|
|
g_free (old);
|
|
old = exp;
|
|
tmp = g_strconcat (" sort ", exp, " ", home_dir, PATH_SEP_STR BLOCK_FILE, " > ", home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL);
|
|
e = system (tmp);
|
|
g_free(tmp);
|
|
if (e) {
|
|
if (e == -1 || e == 127) {
|
|
edit_error_dialog (_(" Sort "),
|
|
get_sys_error (_(" Cannot execute sort command ")));
|
|
} else {
|
|
char q[8];
|
|
sprintf (q, "%d ", e);
|
|
tmp = g_strconcat (_(" Sort returned non-zero: "), q, (char *) NULL);
|
|
edit_error_dialog (_(" Sort "), tmp);
|
|
g_free(tmp);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
|
|
if (edit_block_delete_cmd (edit))
|
|
return 1;
|
|
tmp = g_strconcat (home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL);
|
|
edit_insert_file (edit, tmp);
|
|
g_free(tmp);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Ask user for a command, execute it and paste its output back to the
|
|
* editor.
|
|
*/
|
|
int
|
|
edit_ext_cmd (WEdit *edit)
|
|
{
|
|
char *exp, *tmp;
|
|
int e;
|
|
|
|
exp =
|
|
input_dialog (_("Paste output of external command"),
|
|
_("Enter shell command(s):"),
|
|
MC_HISTORY_EDIT_PASTE_EXTCMD, NULL);
|
|
|
|
if (!exp)
|
|
return 1;
|
|
|
|
tmp = g_strconcat (exp, " > ", home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL);
|
|
e = system (tmp);
|
|
g_free(tmp);
|
|
g_free (exp);
|
|
|
|
if (e) {
|
|
edit_error_dialog (_("External command"),
|
|
get_sys_error (_("Cannot execute command")));
|
|
return -1;
|
|
}
|
|
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
tmp = g_strconcat (home_dir, PATH_SEP_STR TEMP_FILE, (char *) NULL);
|
|
edit_insert_file (edit, tmp);
|
|
g_free(tmp);
|
|
return 0;
|
|
}
|
|
|
|
/* if block is 1, a block must be highlighted and the shell command
|
|
processes it. If block is 0 the shell command is a straight system
|
|
command, that just produces some output which is to be inserted */
|
|
void
|
|
edit_block_process_cmd (WEdit *edit, const char *shell_cmd, int block)
|
|
{
|
|
long start_mark, end_mark;
|
|
char buf[BUFSIZ];
|
|
FILE *script_home = NULL;
|
|
FILE *script_src = NULL;
|
|
FILE *block_file = NULL;
|
|
gchar *o, *h, *b, *tmp;
|
|
char *quoted_name = NULL;
|
|
|
|
o = g_strconcat (mc_home, shell_cmd, (char *) NULL); /* original source script */
|
|
h = g_strconcat (home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, (char *) NULL); /* home script */
|
|
b = g_strconcat (home_dir, PATH_SEP_STR BLOCK_FILE, (char *) NULL); /* block file */
|
|
|
|
if (!(script_home = fopen (h, "r"))) {
|
|
if (!(script_home = fopen (h, "w"))) {
|
|
tmp = g_strconcat (_("Error creating script:"), h, (char *) NULL);
|
|
edit_error_dialog ("", get_sys_error (tmp));
|
|
g_free(tmp);
|
|
goto edit_block_process_cmd__EXIT;
|
|
}
|
|
if (!(script_src = fopen (o, "r"))) {
|
|
o = g_strconcat (mc_home_alt, shell_cmd, (char *) NULL);
|
|
if (!(script_src = fopen (o, "r"))) {
|
|
fclose (script_home);
|
|
unlink (h);
|
|
tmp = g_strconcat (_("Error reading script:"), o, (char *) NULL);
|
|
edit_error_dialog ("", get_sys_error (tmp));
|
|
g_free(tmp);
|
|
goto edit_block_process_cmd__EXIT;
|
|
}
|
|
}
|
|
while (fgets (buf, sizeof (buf), script_src))
|
|
fputs (buf, script_home);
|
|
if (fclose (script_home)) {
|
|
tmp = g_strconcat (_("Error closing script:"), h, (char *) NULL);
|
|
edit_error_dialog ("", get_sys_error (tmp));
|
|
g_free(tmp);
|
|
goto edit_block_process_cmd__EXIT;
|
|
}
|
|
chmod (h, 0700);
|
|
tmp = g_strconcat (_("Script created:"), h, (char *) NULL);
|
|
edit_error_dialog ("", get_sys_error (tmp));
|
|
g_free(tmp);
|
|
}
|
|
|
|
open_error_pipe ();
|
|
|
|
if (block) { /* for marked block run indent formatter */
|
|
if (eval_marks (edit, &start_mark, &end_mark)) {
|
|
edit_error_dialog (_("Process block"),
|
|
_
|
|
(" You must first highlight a block of text. "));
|
|
goto edit_block_process_cmd__EXIT;
|
|
}
|
|
edit_save_block (edit, b, start_mark, end_mark);
|
|
quoted_name = name_quote (edit->filename, 0);
|
|
/*
|
|
* Run script.
|
|
* Initial space is to avoid polluting bash history.
|
|
* Arguments:
|
|
* $1 - name of the edited file (to check its extension etc).
|
|
* $2 - file containing the current block.
|
|
* $3 - file where error messages should be put
|
|
* (for compatibility with old scripts).
|
|
*/
|
|
tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ", quoted_name,
|
|
" ", home_dir, PATH_SEP_STR BLOCK_FILE " /dev/null", (char *) NULL);
|
|
system (tmp);
|
|
g_free(tmp);
|
|
} else {
|
|
/*
|
|
* No block selected, just execute the command for the file.
|
|
* Arguments:
|
|
* $1 - name of the edited file.
|
|
*/
|
|
tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
|
|
quoted_name, (char *) NULL);
|
|
system (tmp);
|
|
g_free(tmp);
|
|
}
|
|
g_free (quoted_name);
|
|
close_error_pipe (D_NORMAL, NULL);
|
|
|
|
edit_refresh_cmd (edit);
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
|
|
/* insert result block */
|
|
if (block) {
|
|
if (edit_block_delete_cmd (edit))
|
|
goto edit_block_process_cmd__EXIT;
|
|
edit_insert_file (edit, b);
|
|
if ((block_file = fopen (b, "w")))
|
|
fclose (block_file);
|
|
goto edit_block_process_cmd__EXIT;
|
|
}
|
|
edit_block_process_cmd__EXIT:
|
|
g_free(b);
|
|
g_free(h);
|
|
g_free(o);
|
|
return;
|
|
}
|
|
|
|
/* prints at the cursor */
|
|
/* returns the number of chars printed */
|
|
int edit_print_string (WEdit * e, const char *s)
|
|
{
|
|
int i = 0;
|
|
while (s[i])
|
|
edit_execute_cmd (e, -1, (unsigned char) s[i++]);
|
|
e->force |= REDRAW_COMPLETELY;
|
|
edit_update_screen (e);
|
|
return i;
|
|
}
|
|
|
|
|
|
static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
|
|
{
|
|
FILE *p = 0;
|
|
char *s;
|
|
|
|
to = name_quote (to, 0);
|
|
subject = name_quote (subject, 0);
|
|
cc = name_quote (cc, 0);
|
|
s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "" , cc, " ", to, (char *) NULL);
|
|
g_free (to);
|
|
g_free (subject);
|
|
g_free (cc);
|
|
|
|
if (s) {
|
|
p = popen (s, "w");
|
|
g_free (s);
|
|
}
|
|
|
|
if (p) {
|
|
long i;
|
|
for (i = 0; i < edit->last_byte; i++)
|
|
fputc (edit_get_byte (edit, i), p);
|
|
pclose (p);
|
|
}
|
|
}
|
|
|
|
#define MAIL_DLG_HEIGHT 12
|
|
|
|
void edit_mail_dialog (WEdit * edit)
|
|
{
|
|
char *tmail_to;
|
|
char *tmail_subject;
|
|
char *tmail_cc;
|
|
|
|
static char *mail_cc_last = 0;
|
|
static char *mail_subject_last = 0;
|
|
static char *mail_to_last = 0;
|
|
|
|
QuickDialog Quick_input =
|
|
{50, MAIL_DLG_HEIGHT, -1, 0, N_(" Mail "),
|
|
"[Input Line Keys]", 0, 0};
|
|
|
|
QuickWidget quick_widgets[] =
|
|
{
|
|
{quick_button, 6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
|
|
0, NULL, NULL, NULL},
|
|
{quick_button, 2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), 0, B_ENTER, 0,
|
|
0, NULL, NULL, NULL},
|
|
{quick_input, 3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, 0,
|
|
0, "mail-dlg-input", NULL, NULL},
|
|
{quick_label, 2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to"), 0, 0, 0,
|
|
0, 0, NULL, NULL},
|
|
{quick_input, 3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, 0,
|
|
0, "mail-dlg-input-2", NULL, NULL},
|
|
{quick_label, 2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject"), 0, 0, 0,
|
|
0, 0, NULL, NULL},
|
|
{quick_input, 3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, 0,
|
|
0, "mail-dlg-input-3", NULL, NULL},
|
|
{quick_label, 2, 50, 3, MAIL_DLG_HEIGHT, N_(" To"), 0, 0, 0,
|
|
0, 0, NULL, NULL},
|
|
{quick_label, 2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
|
|
0, 0, NULL, NULL},
|
|
NULL_QuickWidget};
|
|
|
|
quick_widgets[2].str_result = &tmail_cc;
|
|
quick_widgets[2].text = mail_cc_last ? mail_cc_last : "";
|
|
quick_widgets[4].str_result = &tmail_subject;
|
|
quick_widgets[4].text = mail_subject_last ? mail_subject_last : "";
|
|
quick_widgets[6].str_result = &tmail_to;
|
|
quick_widgets[6].text = mail_to_last ? mail_to_last : "";
|
|
|
|
Quick_input.widgets = quick_widgets;
|
|
|
|
if (quick_dialog (&Quick_input) != B_CANCEL) {
|
|
g_free (mail_cc_last);
|
|
g_free (mail_subject_last);
|
|
g_free (mail_to_last);
|
|
mail_cc_last = tmail_cc;
|
|
mail_subject_last = tmail_subject;
|
|
mail_to_last = tmail_to;
|
|
pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
|
|
}
|
|
}
|
|
|
|
|
|
/*******************/
|
|
/* Word Completion */
|
|
/*******************/
|
|
|
|
|
|
/* find first character of current word */
|
|
static int edit_find_word_start (WEdit *edit, long *word_start, int *word_len)
|
|
{
|
|
int i, c, last;
|
|
|
|
/* return if at begin of file */
|
|
if (edit->curs1 <= 0)
|
|
return 0;
|
|
|
|
c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
|
|
/* return if not at end or in word */
|
|
if (isspace (c) || !(isalnum (c) || c == '_'))
|
|
return 0;
|
|
|
|
/* search start of word to be completed */
|
|
for (i = 2;; i++) {
|
|
/* return if at begin of file */
|
|
if (edit->curs1 - i < 0)
|
|
return 0;
|
|
|
|
last = c;
|
|
c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
|
|
|
|
if (!(isalnum (c) || c == '_')) {
|
|
/* return if word starts with digit */
|
|
if (isdigit (last))
|
|
return 0;
|
|
|
|
*word_start = edit->curs1 - (i - 1); /* start found */
|
|
*word_len = i - 1;
|
|
break;
|
|
}
|
|
}
|
|
/* success */
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* (re)set search parameters to the given values */
|
|
static void edit_set_search_parameters (WEdit *edit, int replace_mode, int rb, int rc)
|
|
{
|
|
edit->replace_mode = replace_mode;
|
|
edit->replace_backwards = rb;
|
|
edit->replace_case = rc;
|
|
}
|
|
|
|
|
|
#define MAX_WORD_COMPLETIONS 100 /* in listbox */
|
|
|
|
/* collect the possible completions */
|
|
static int
|
|
edit_collect_completions (WEdit *edit, long start, int word_len,
|
|
char *match_expr, struct selection *compl,
|
|
int *num)
|
|
{
|
|
int len = 0, max_len = 0, i, skip;
|
|
unsigned char *bufpos;
|
|
|
|
(void) match_expr;
|
|
/* collect max MAX_WORD_COMPLETIONS completions */
|
|
while (*num < MAX_WORD_COMPLETIONS) {
|
|
/* get next match */
|
|
/*
|
|
start =
|
|
edit_find (start - 1, (unsigned char *) match_expr, &len,
|
|
edit->last_byte, edit_get_byte_ptr, (void *) edit, 0);
|
|
*/
|
|
start = -1;
|
|
/* not matched */
|
|
if (start < 0)
|
|
break;
|
|
|
|
/* add matched completion if not yet added */
|
|
bufpos =
|
|
&edit->
|
|
buffers1[start >> S_EDIT_BUF_SIZE][start & M_EDIT_BUF_SIZE];
|
|
skip = 0;
|
|
for (i = 0; i < *num; i++) {
|
|
if (strncmp
|
|
((char *) &compl[i].text[word_len],
|
|
(char *) &bufpos[word_len], max (len,
|
|
compl[i].len) -
|
|
word_len) == 0) {
|
|
skip = 1;
|
|
break; /* skip it, already added */
|
|
}
|
|
}
|
|
if (skip)
|
|
continue;
|
|
|
|
compl[*num].text = g_malloc (len + 1);
|
|
compl[*num].len = len;
|
|
for (i = 0; i < len; i++)
|
|
compl[*num].text[i] = *(bufpos + i);
|
|
compl[*num].text[i] = '\0';
|
|
(*num)++;
|
|
|
|
/* note the maximal length needed for the completion dialog */
|
|
if (len > max_len)
|
|
max_len = len;
|
|
}
|
|
return max_len;
|
|
}
|
|
|
|
/*
|
|
* Complete current word using regular expression search
|
|
* backwards beginning at the current cursor position.
|
|
*/
|
|
void
|
|
edit_complete_word_cmd (WEdit *edit)
|
|
{
|
|
int word_len = 0, i, num_compl = 0, max_len;
|
|
long word_start = 0;
|
|
unsigned char *bufpos;
|
|
char *match_expr;
|
|
struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
|
|
|
|
/* don't want to disturb another search */
|
|
int old_replace_mode = edit->replace_mode;
|
|
int old_rb = edit->replace_backwards;
|
|
int old_rc = edit->replace_case;
|
|
|
|
/* search start of word to be completed */
|
|
if (!edit_find_word_start (edit, &word_start, &word_len))
|
|
return;
|
|
|
|
/* prepare match expression */
|
|
bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
|
|
[word_start & M_EDIT_BUF_SIZE];
|
|
|
|
match_expr = g_strdup_printf ("%.*s[a-zA-Z_0-9]+", word_len, bufpos);
|
|
/* init search: backward, regexp, whole word, case sensitive */
|
|
edit_set_search_parameters (edit, 0, 1, 1);
|
|
|
|
/* collect the possible completions */
|
|
/* start search from curs1 down to begin of file */
|
|
max_len =
|
|
edit_collect_completions (edit, word_start, word_len, match_expr,
|
|
(struct selection *) &compl, &num_compl);
|
|
|
|
if (num_compl > 0) {
|
|
/* insert completed word if there is only one match */
|
|
if (num_compl == 1) {
|
|
for (i = word_len; i < compl[0].len; i++)
|
|
edit_insert (edit, *(compl[0].text + i));
|
|
}
|
|
/* more than one possible completion => ask the user */
|
|
else {
|
|
/* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
|
|
/* !!! pressed again the selection dialog pops up, but that !!! */
|
|
/* !!! seems to require a further internal state !!! */
|
|
/*beep (); */
|
|
|
|
/* let the user select the preferred completion */
|
|
editcmd_dialog_completion_show (edit, max_len, word_len,
|
|
(struct selection *) &compl,
|
|
num_compl);
|
|
}
|
|
}
|
|
|
|
g_free (match_expr);
|
|
/* release memory before return */
|
|
for (i = 0; i < num_compl; i++)
|
|
g_free (compl[i].text);
|
|
|
|
/* restore search parameters */
|
|
edit_set_search_parameters (edit, old_replace_mode, old_rb, old_rc);
|
|
}
|
|
|
|
void
|
|
edit_select_codepage_cmd (WEdit *edit)
|
|
{
|
|
#ifdef HAVE_CHARSET
|
|
do_select_codepage ();
|
|
if ( get_codepage_id (source_codepage) )
|
|
edit->utf8 = str_isutf8 (get_codepage_id (source_codepage));
|
|
edit->force = REDRAW_COMPLETELY;
|
|
edit_refresh_cmd (edit);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
edit_insert_literal_cmd (WEdit *edit)
|
|
{
|
|
int char_for_insertion =
|
|
editcmd_dialog_raw_key_query (_(" Insert Literal "),
|
|
_(" Press any key: "), 0);
|
|
edit_execute_key_command (edit, -1,
|
|
ascii_alpha_to_cntrl (char_for_insertion));
|
|
}
|
|
|
|
void
|
|
edit_execute_macro_cmd (WEdit *edit)
|
|
{
|
|
int command =
|
|
CK_Macro (editcmd_dialog_raw_key_query
|
|
(_(" Execute Macro "), _(" Press macro hotkey: "),
|
|
1));
|
|
if (command == CK_Macro (0))
|
|
command = CK_Insert_Char;
|
|
|
|
edit_execute_key_command (edit, command, -1);
|
|
}
|
|
|
|
void
|
|
edit_begin_end_macro_cmd(WEdit *edit)
|
|
{
|
|
int command;
|
|
|
|
/* edit is a pointer to the widget */
|
|
if (edit) {
|
|
command =
|
|
edit->macro_i <
|
|
0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
|
|
edit_execute_key_command (edit, command, -1);
|
|
}
|
|
}
|
|
|
|
int
|
|
edit_load_forward_cmd (WEdit *edit)
|
|
{
|
|
if (edit->modified) {
|
|
if (edit_query_dialog2
|
|
(_("Warning"),
|
|
_(" Current text was modified without a file save. \n"
|
|
" Continue discards these changes. "), _("C&ontinue"),
|
|
_("&Cancel"))) {
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
return 0;
|
|
}
|
|
}
|
|
if ( edit_stack_iterator + 1 < MAX_HISTORY_MOVETO ) {
|
|
if ( edit_history_moveto[edit_stack_iterator + 1].line < 1 ) {
|
|
return 1;
|
|
}
|
|
edit_stack_iterator++;
|
|
if ( edit_history_moveto[edit_stack_iterator].filename ) {
|
|
edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
|
|
edit_history_moveto[edit_stack_iterator].line);
|
|
return 0;
|
|
} else {
|
|
return 1;
|
|
}
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
int
|
|
edit_load_back_cmd (WEdit *edit)
|
|
{
|
|
if (edit->modified) {
|
|
if (edit_query_dialog2
|
|
(_("Warning"),
|
|
_(" Current text was modified without a file save. \n"
|
|
" Continue discards these changes. "), _("C&ontinue"),
|
|
_("&Cancel"))) {
|
|
edit->force |= REDRAW_COMPLETELY;
|
|
return 0;
|
|
}
|
|
}
|
|
if ( edit_stack_iterator > 0 ) {
|
|
edit_stack_iterator--;
|
|
if ( edit_history_moveto[edit_stack_iterator].filename ) {
|
|
edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
|
|
edit_history_moveto[edit_stack_iterator].line);
|
|
return 0;
|
|
} else {
|
|
return 1;
|
|
}
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
void
|
|
edit_get_match_keyword_cmd (WEdit *edit)
|
|
{
|
|
int word_len = 0;
|
|
int num_def = 0;
|
|
int max_len = 0;
|
|
int i;
|
|
long word_start = 0;
|
|
unsigned char *bufpos;
|
|
char *match_expr;
|
|
char *path = NULL;
|
|
char *ptr = NULL;
|
|
char *tagfile = NULL;
|
|
|
|
etags_hash_t def_hash[MAX_DEFINITIONS];
|
|
|
|
for ( i = 0; i < MAX_DEFINITIONS; i++) {
|
|
def_hash[i].filename = NULL;
|
|
}
|
|
|
|
/* search start of word to be completed */
|
|
if (!edit_find_word_start (edit, &word_start, &word_len))
|
|
return;
|
|
|
|
/* prepare match expression */
|
|
bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
|
|
[word_start & M_EDIT_BUF_SIZE];
|
|
match_expr = g_strdup_printf ("%.*s", word_len, bufpos);
|
|
|
|
ptr = g_get_current_dir ();
|
|
path = g_strconcat (ptr, G_DIR_SEPARATOR_S, (char *) NULL);
|
|
g_free (ptr);
|
|
|
|
/* Recursive search file 'TAGS' in parent dirs */
|
|
do {
|
|
ptr = g_path_get_dirname (path);
|
|
g_free(path); path = ptr;
|
|
g_free (tagfile);
|
|
tagfile = g_build_filename (path, TAGS_NAME, (char *) NULL);
|
|
if ( exist_file (tagfile) )
|
|
break;
|
|
} while (strcmp( path, G_DIR_SEPARATOR_S) != 0);
|
|
|
|
if (tagfile){
|
|
num_def = etags_set_definition_hash(tagfile, path, match_expr, (etags_hash_t *) &def_hash);
|
|
g_free (tagfile);
|
|
}
|
|
g_free (path);
|
|
|
|
max_len = MAX_WIDTH_DEF_DIALOG;
|
|
word_len = 0;
|
|
if ( num_def > 0 ) {
|
|
editcmd_dialog_select_definition_show (edit, match_expr, max_len, word_len,
|
|
(etags_hash_t *) &def_hash,
|
|
num_def);
|
|
}
|
|
g_free (match_expr);
|
|
}
|
|
|
|
void
|
|
edit_move_block_to_right (WEdit * edit)
|
|
{
|
|
long start_mark, end_mark;
|
|
long cur_bol, start_bol;
|
|
|
|
if ( eval_marks (edit, &start_mark, &end_mark) )
|
|
return;
|
|
|
|
start_bol = edit_bol (edit, start_mark);
|
|
cur_bol = edit_bol (edit, end_mark - 1);
|
|
do {
|
|
edit_cursor_move (edit, cur_bol - edit->curs1);
|
|
if ( option_fill_tabs_with_spaces ) {
|
|
if ( option_fake_half_tabs ) {
|
|
insert_spaces_tab (edit, 1);
|
|
} else {
|
|
insert_spaces_tab (edit, 0);
|
|
}
|
|
} else {
|
|
edit_insert (edit, '\t');
|
|
}
|
|
edit_cursor_move (edit, edit_bol (edit, cur_bol) - edit->curs1);
|
|
if ( cur_bol == 0 ) {
|
|
break;
|
|
}
|
|
cur_bol = edit_bol (edit, cur_bol - 1);
|
|
} while (cur_bol >= start_bol) ;
|
|
edit->force |= REDRAW_PAGE;
|
|
}
|
|
|
|
void
|
|
edit_move_block_to_left (WEdit * edit)
|
|
{
|
|
long start_mark, end_mark;
|
|
long cur_bol, start_bol;
|
|
int i, del_tab_width;
|
|
int next_char;
|
|
|
|
if ( eval_marks (edit, &start_mark, &end_mark) )
|
|
return;
|
|
|
|
start_bol = edit_bol (edit, start_mark);
|
|
cur_bol = edit_bol (edit, end_mark - 1);
|
|
do {
|
|
edit_cursor_move (edit, cur_bol - edit->curs1);
|
|
if (option_fake_half_tabs) {
|
|
del_tab_width = HALF_TAB_SIZE;
|
|
} else {
|
|
del_tab_width = option_tab_spacing;
|
|
}
|
|
next_char = edit_get_byte (edit, edit->curs1);
|
|
if ( next_char == '\t' ) {
|
|
edit_delete (edit, 1);
|
|
} else if ( next_char == ' ' ) {
|
|
for (i = 1; i <= del_tab_width; i++) {
|
|
if ( next_char == ' ' ) {
|
|
edit_delete (edit, 1);
|
|
}
|
|
next_char = edit_get_byte (edit, edit->curs1);
|
|
}
|
|
}
|
|
if ( cur_bol == 0 ) {
|
|
break;
|
|
}
|
|
cur_bol = edit_bol (edit, cur_bol - 1);
|
|
} while (cur_bol >= start_bol) ;
|
|
edit->force |= REDRAW_PAGE;
|
|
}
|