Beispiel #1
0
/* Switches to pane tab specified by its index if the index is valid. */
static void
tabs_goto_pane(int idx)
{
	pane_tabs_t *const ptabs = get_pane_tabs(curr_view);

	if(ptabs->current == idx)
	{
		return;
	}

	if(idx < 0 || idx >= (int)DA_SIZE(ptabs->tabs))
	{
		return;
	}

	ptabs->tabs[ptabs->current].view = *curr_view;
	assign_preview(&ptabs->tabs[ptabs->current].preview, &curr_stats.preview);
	*curr_view = ptabs->tabs[idx].view;
	assign_preview(&curr_stats.preview, &ptabs->tabs[idx].preview);
	ptabs->current = idx;

	stats_set_quickview(curr_stats.preview.on);
	ui_view_schedule_redraw(curr_view);

	load_view_options(curr_view);

	(void)vifm_chdir(flist_get_dir(curr_view));
}
Beispiel #2
0
/* Executes list of startup commands. */
static void
exec_startup_commands(const args_t *args)
{
	size_t i;
	for(i = 0; i < args->ncmds; ++i)
	{
		/* Make sure we're executing commands in correct directory. */
		(void)vifm_chdir(flist_get_dir(curr_view));

		(void)exec_commands(args->cmds[i], curr_view, CIT_COMMAND);
	}
}
Beispiel #3
0
char *
prepare_targets(FileView *view)
{
	if(view->selected_files > 0)
	{
		return expand_macros("%f", NULL, NULL, 1);
	}

	if(!flist_custom_active(view))
	{
		return strdup(".");
	}

	return (vifm_chdir(flist_get_dir(view)) == 0) ? strdup(".") : NULL;
}
Beispiel #4
0
/* Handles arguments received from remote instance. */
static void
parse_received_arguments(char *argv[])
{
	int argc = 0;
	args_t args = {};

	while(argv[argc] != NULL)
	{
		argc++;
	}

	(void)vifm_chdir(argv[0]);
	opterr = 0;
	args_parse(&args, argc, argv, argv[0]);
	args_process(&args, 0);

	exec_startup_commands(&args);
	args_free(&args);

	if(NONE(vle_mode_is, NORMAL_MODE, VIEW_MODE))
	{
		return;
	}

#ifdef _WIN32
	SwitchToThisWindow(GetConsoleWindow(), TRUE);
	BringWindowToTop(GetConsoleWindow());
	SetForegroundWindow(GetConsoleWindow());
#endif

	if(view_needs_cd(&lwin, args.lwin_path))
	{
		remote_cd(&lwin, args.lwin_path, args.lwin_handle);
	}

	if(view_needs_cd(&rwin, args.rwin_path))
	{
		remote_cd(&rwin, args.rwin_path, args.rwin_handle);
	}

	if(need_to_switch_active_pane(args.lwin_path, args.rwin_path))
	{
		change_window();
	}

	ui_sb_clear();
	curr_stats.save_msg = 0;
}
Beispiel #5
0
/* Switches to global tab specified by its index if the index is valid. */
static void
tabs_goto_global(int idx)
{
	if(current_tab == idx)
	{
		return;
	}

	//add by sim1 +++++++++++++++++++++++++++++
	if(idx < 0)
	{
		idx = last_tab;
	}
	//add by sim1 -----------------------------

	if(idx < 0 || idx >= (int)DA_SIZE(gtabs))
	{
		return;
	}

	gtabs[current_tab].left.tabs[gtabs[current_tab].left.current].view = lwin;
	gtabs[current_tab].right.tabs[gtabs[current_tab].right.current].view = rwin;
	capture_global_state(&gtabs[current_tab]);
	assign_preview(&gtabs[current_tab].preview, &curr_stats.preview);

	lwin = gtabs[idx].left.tabs[gtabs[idx].left.current].view;
	rwin = gtabs[idx].right.tabs[gtabs[idx].right.current].view;
	if(gtabs[idx].active_pane != (curr_view == &rwin))
	{
		swap_view_roles();
	}
	curr_stats.number_of_windows = (gtabs[idx].only_mode ? 1 : 2);
	curr_stats.split = gtabs[idx].split;
	curr_stats.splitter_pos = gtabs[idx].splitter_pos;
	assign_preview(&curr_stats.preview, &gtabs[idx].preview);

	last_tab = current_tab;  //add by sim1
	current_tab = idx;

	stats_set_quickview(curr_stats.preview.on);
	ui_view_schedule_redraw(&lwin);
	ui_view_schedule_redraw(&rwin);

	load_view_options(curr_view);

	(void)vifm_chdir(flist_get_dir(curr_view));
}
Beispiel #6
0
/* Fills list of complitions with executables in $PATH. */
static void
complete_command_name(const char beginning[])
{
	int i;
	char ** paths;
	size_t paths_count;

	paths = get_paths(&paths_count);
	for(i = 0; i < paths_count; i++)
	{
		if(vifm_chdir(paths[i]) == 0)
		{
			filename_completion(beginning, CT_EXECONLY);
		}
	}
	vle_compl_add_last_path_match(beginning);
}
Beispiel #7
0
/* Switches to pane tab specified by its index if the index is valid. */
static void
tabs_goto_pane(int idx)
{
	pane_tabs_t *const ptabs = get_pane_tabs(curr_view);

	if(ptabs->current == idx)
	{
		return;
	}

	//add by sim1 +++++++++++++++++++++++++++++++++++
	if(idx < 0)
	{
		idx = ptabs->last;
		if (idx == ptabs->current)
		{
			return;
		}
	}
	//add by sim1 -----------------------------------

	if(idx < 0 || idx >= (int)DA_SIZE(ptabs->tabs))
	{
		return;
	}

	ptabs->tabs[ptabs->current].view = *curr_view;
	assign_preview(&ptabs->tabs[ptabs->current].preview, &curr_stats.preview);
	*curr_view = ptabs->tabs[idx].view;
	assign_preview(&curr_stats.preview, &ptabs->tabs[idx].preview);

	ptabs->last = ptabs->current;  //add by sim1
	ptabs->current = idx;

	stats_set_quickview(curr_stats.preview.on);
	ui_view_schedule_redraw(curr_view);

	load_view_options(curr_view);

	(void)vifm_chdir(flist_get_dir(curr_view));

	//add by sim1 for test
	//ui_sb_msgf("tabs_goto_pane: curr=%d, last=%d, tabs=%d", ptabs->current, ptabs->last, (int)DA_SIZE(ptabs->tabs));
}
Beispiel #8
0
void
fuse_unmount_all(void)
{
	fuse_mount_t *runner;

	if(fuse_mounts == NULL)
	{
		return;
	}

	if(vifm_chdir("/") != 0)
	{
		return;
	}

	runner = fuse_mounts;
	while(runner != NULL)
	{
		char buf[14 + PATH_MAX + 1];
		char *escaped_filename;

		escaped_filename = escape_filename(runner->mount_point, 0);
		snprintf(buf, sizeof(buf), "%s %s", curr_stats.fuse_umount_cmd,
				escaped_filename);
		free(escaped_filename);

		(void)vifm_system(buf);
		if(path_exists(runner->mount_point, DEREF))
		{
			rmdir(runner->mount_point);
		}

		runner = runner->next;
	}

	leave_invalid_dir(&lwin);
	leave_invalid_dir(&rwin);
}
Beispiel #9
0
int
fuse_try_unmount(FileView *view)
{
	char buf[14 + PATH_MAX + 1];
	fuse_mount_t *runner, *trailer;
	int status;
	fuse_mount_t *sniffer;
	char *escaped_mount_point;

	runner = fuse_mounts;
	trailer = NULL;
	while(runner)
	{
		if(paths_are_equal(runner->mount_point, view->curr_dir))
		{
			break;
		}

		trailer = runner;
		runner = runner->next;
	}

	if(runner == NULL)
	{
		return 0;
	}

	/* we are exiting a top level dir */
	escaped_mount_point = escape_filename(runner->mount_point, 0);
	snprintf(buf, sizeof(buf), "%s %s 2> /dev/null", curr_stats.fuse_umount_cmd,
			escaped_mount_point);
	LOG_INFO_MSG("FUSE unmount command: `%s`", buf);
	free(escaped_mount_point);

	/* Have to chdir to parent temporarily, so that this DIR can be unmounted. */
	if(vifm_chdir(cfg.fuse_home) != 0)
	{
		show_error_msg("FUSE UMOUNT ERROR", "Can't chdir to FUSE home");
		return -1;
	}

	status_bar_message("FUSE unmounting selected file, please stand by..");
	status = background_and_wait_for_status(buf, 0, NULL);
	clean_status_bar();
	/* check child status */
	if(!WIFEXITED(status) || WEXITSTATUS(status))
	{
		werase(status_bar);
		show_error_msgf("FUSE UMOUNT ERROR", "Can't unmount %s.  It may be busy.",
				runner->source_file_name);
		(void)vifm_chdir(flist_get_dir(view));
		return -1;
	}

	/* remove the directory we created for the mount */
	if(path_exists(runner->mount_point, DEREF))
		rmdir(runner->mount_point);

	/* remove mount point from fuse_mount_t */
	sniffer = runner->next;
	if(trailer)
		trailer->next = sniffer ? sniffer : NULL;
	else
		fuse_mounts = sniffer;

	updir_from_mount(view, runner);
	free(runner);
	return 1;
}
Beispiel #10
0
/* mount_point should be an array of at least PATH_MAX characters
 * Returns non-zero on error. */
static int
fuse_mount(FileView *view, char file_full_path[], const char param[],
		const char program[], char mount_point[])
{
	/* TODO: refactor this function fuse_mount(). */

	int mount_point_id;
	char buf[2*PATH_MAX];
	char *escaped_filename;
	int foreground;
	char errors_file[PATH_MAX];
	int status;
	int cancelled;

	escaped_filename = escape_filename(get_current_file_name(view), 0);

	mount_point_id = get_last_mount_point_id(fuse_mounts);
	do
	{
		snprintf(mount_point, PATH_MAX, "%s/%03d_%s", cfg.fuse_home,
				++mount_point_id, get_current_file_name(view));
	}
	while(path_exists(mount_point, DEREF));
	if(os_mkdir(mount_point, S_IRWXU) != 0)
	{
		free(escaped_filename);
		show_error_msg("Unable to create FUSE mount directory", mount_point);
		return -1;
	}
	free(escaped_filename);

	/* Just before running the mount,
		 I need to chdir out temporarily from any FUSE mounted
		 paths, Otherwise the fuse-zip command fails with
		 "fusermount: failed to open current directory: permission denied"
		 (this happens when mounting JARs from mounted JARs) */
	if(vifm_chdir(cfg.fuse_home) != 0)
	{
		show_error_msg("FUSE MOUNT ERROR", "Can't chdir() to FUSE home");
		return -1;
	}

	format_mount_command(mount_point, file_full_path, param, program, sizeof(buf),
			buf, &foreground);

	status_bar_message("FUSE mounting selected file, please stand by..");

	if(foreground)
	{
		def_prog_mode();
		endwin();
	}

	generate_tmp_file_name("vifm.errors", errors_file, sizeof(errors_file));

	strcat(buf, " 2> ");
	strcat(buf, errors_file);
	LOG_INFO_MSG("FUSE mount command: `%s`", buf);
	status = background_and_wait_for_status(buf, !foreground, &cancelled);

	clean_status_bar();

	/* Check child process exit status. */
	if(!WIFEXITED(status) || WEXITSTATUS(status) != EXIT_SUCCESS)
	{
		FILE *ef;

		if(!WIFEXITED(status))
		{
			LOG_ERROR_MSG("FUSE mounter didn't exit!");
		}
		else
		{
			LOG_ERROR_MSG("FUSE mount command exit status: %d", WEXITSTATUS(status));
		}

		ef = os_fopen(errors_file, "r");
		if(ef == NULL)
		{
			LOG_SERROR_MSG(errno, "Failed to open temporary stderr file: %s",
					errors_file);
		}
		show_errors_from_file(ef, "FUSE mounter error");

		werase(status_bar);

		if(cancelled)
		{
			status_bar_message("FUSE mount cancelled");
			curr_stats.save_msg = 1;
		}
		else
		{
			show_error_msg("FUSE MOUNT ERROR", file_full_path);
		}

		if(unlink(errors_file) != 0)
		{
			LOG_SERROR_MSG(errno, "Error file deletion failure: %d", errors_file);
		}

		/* Remove the directory we created for the mount. */
		(void)rmdir(mount_point);

		(void)vifm_chdir(flist_get_dir(view));
		return -1;
	}
	unlink(errors_file);
	status_bar_message("FUSE mount success");

	register_mount(&fuse_mounts, file_full_path, mount_point, mount_point_id);

	return 0;
}
Beispiel #11
0
Datei: fuse.c Projekt: lyuts/vifm
/*
 * mount_point should be an array of at least PATH_MAX characters
 * Returns non-zero on error.
 */
static int
fuse_mount(FileView *view, char *file_full_path, const char *param,
		const char *program, char *mount_point)
{
	/* TODO: refactor this function fuse_mount() */

	fuse_mount_t *runner = NULL;
	int mount_point_id = 0;
	fuse_mount_t *fuse_item = NULL;
	char buf[2*PATH_MAX];
	char *escaped_filename;
	int clear_before_mount = 0;
	char errors_file[PATH_MAX];
	int status;

	escaped_filename = escape_filename(get_current_file_name(view), 0);

	/* get mount_point_id + mount_point and set runner pointing to the list's
	 * tail */
	if(fuse_mounts != NULL)
	{
		runner = fuse_mounts;
		while(runner->next != NULL)
			runner = runner->next;
		mount_point_id = runner->mount_point_id;
	}
	do
	{
		snprintf(mount_point, PATH_MAX, "%s/%03d_%s", cfg.fuse_home,
				++mount_point_id, get_current_file_name(view));
	}
	while(path_exists(mount_point));
	if(make_dir(mount_point, S_IRWXU) != 0)
	{
		free(escaped_filename);
		show_error_msg("Unable to create FUSE mount directory", mount_point);
		return -1;
	}
	free(escaped_filename);

	/* Just before running the mount,
		 I need to chdir out temporarily from any FUSE mounted
		 paths, Otherwise the fuse-zip command fails with
		 "fusermount: failed to open current directory: permission denied"
		 (this happens when mounting JARs from mounted JARs) */
	if(vifm_chdir(cfg.fuse_home) != 0)
	{
		show_error_msg("FUSE MOUNT ERROR", "Can't chdir() to FUSE home");
		return -1;
	}

	clear_before_mount = format_mount_command(mount_point, file_full_path, param,
			program, sizeof(buf), buf);

	status_bar_message("FUSE mounting selected file, please stand by..");

	if(clear_before_mount)
	{
		def_prog_mode();
		endwin();
	}

	generate_tmp_file_name("vifm.errors", errors_file, sizeof(errors_file));

	strcat(buf, " 2> ");
	strcat(buf, errors_file);
	LOG_INFO_MSG("FUSE mount command: `%s`", buf);
	status = background_and_wait_for_status(buf);

	clean_status_bar();

	/* check child status */
	if(!WIFEXITED(status) || (WIFEXITED(status) && WEXITSTATUS(status)))
	{
		FILE *ef = fopen(errors_file, "r");
		print_errors(ef);
		unlink(errors_file);

		werase(status_bar);
		/* remove the directory we created for the mount */
		if(path_exists(mount_point))
			rmdir(mount_point);
		show_error_msg("FUSE MOUNT ERROR", file_full_path);
		(void)vifm_chdir(view->curr_dir);
		return -1;
	}
	unlink(errors_file);
	status_bar_message("FUSE mount success");

	fuse_item = malloc(sizeof(*fuse_item));
	copy_str(fuse_item->source_file_name, sizeof(fuse_item->source_file_name),
			file_full_path);
	strcpy(fuse_item->source_file_dir, view->curr_dir);
	canonicalize_path(mount_point, fuse_item->mount_point,
			sizeof(fuse_item->mount_point));
	fuse_item->mount_point_id = mount_point_id;
	fuse_item->next = NULL;
	if(fuse_mounts == NULL)
		fuse_mounts = fuse_item;
	else
		runner->next = fuse_item;

	return 0;
}
Beispiel #12
0
void
event_loop(const int *quit)
{
	/* TODO: refactor this function event_loop(). */

	LOG_FUNC_ENTER;

	const wchar_t *const prev_input_buf = curr_input_buf;
	const size_t *const prev_input_buf_pos = curr_input_buf_pos;

	wchar_t input_buf[128];
	size_t input_buf_pos;

	int last_result = 0;
	int wait_for_enter = 0;
	int wait_for_suggestion = 0;
	int timeout = cfg.timeout_len;

	input_buf[0] = L'\0';
	input_buf_pos = 0;
	curr_input_buf = &input_buf[0];
	curr_input_buf_pos = &input_buf_pos;

	/* Make sure to set the working directory once in order to have the
	 * desired state even before any events are processed. */
	(void)vifm_chdir(flist_get_dir(curr_view));

	while(!*quit)
	{
		wint_t c;
		size_t counter;
		int got_input;

		lwin.user_selection = 1;
		rwin.user_selection = 1;

		modes_pre();

		/* Waits for timeout then skips if no key press.  Short-circuit if we're not
		 * waiting for the next key after timeout. */
		do
		{
			const int actual_timeout = wait_for_suggestion
			                         ? MIN(timeout, cfg.sug.delay)
			                         : timeout;

			if(!ensure_term_is_ready())
			{
				wait_for_enter = 0;
				continue;
			}

			modes_periodic();

			bg_check();

			got_input = (get_char_async_loop(status_bar, &c, actual_timeout) != ERR);

			/* If suggestion delay timed out, reset it and wait the rest of the
			 * timeout. */
			if(!got_input && wait_for_suggestion)
			{
				wait_for_suggestion = 0;
				timeout -= actual_timeout;
				display_suggestion_box(input_buf);
				continue;
			}
			wait_for_suggestion = 0;

			if(!got_input && (input_buf_pos == 0 || last_result == KEYS_WAIT))
			{
				timeout = cfg.timeout_len;
				continue;
			}

			if(got_input && c == K(KEY_RESIZE))
			{
				modes_redraw();
				continue;
			}

			break;
		}
		while(1);

		suggestions_are_visible = 0;

		/* Ensure that current working directory is set correctly (some pieces of
		 * code rely on this, e.g. %c macro in current directory). */
		(void)vifm_chdir(flist_get_dir(curr_view));

		if(got_input)
		{
			if(wait_for_enter)
			{
				wait_for_enter = 0;
				curr_stats.save_msg = 0;
				ui_sb_clear();
				if(c == WC_CR)
				{
					continue;
				}
			}

			if(c == WC_C_z)
			{
				ui_shutdown();
				stop_process();
				continue;
			}

			if(input_buf_pos < ARRAY_LEN(input_buf) - 2)
			{
				input_buf[input_buf_pos++] = c;
				input_buf[input_buf_pos] = L'\0';
			}
			else
			{
				/* Recover from input buffer overflow by resetting its contents. */
				reset_input_buf(input_buf, &input_buf_pos);
				clear_input_bar();
				continue;
			}
		}

		counter = vle_keys_counter();
		if(!got_input && last_result == KEYS_WAIT_SHORT)
		{
			hide_suggestion_box();

			last_result = vle_keys_exec_timed_out(input_buf);
			counter = vle_keys_counter() - counter;
			assert(counter <= input_buf_pos);
			if(counter > 0)
			{
				memmove(input_buf, input_buf + counter,
						(wcslen(input_buf) - counter + 1)*sizeof(wchar_t));
			}
		}
		else
		{
			if(got_input)
			{
				curr_stats.save_msg = 0;
			}

			if(last_result == KEYS_WAIT || last_result == KEYS_WAIT_SHORT)
			{
				hide_suggestion_box();
			}

			last_result = vle_keys_exec(input_buf);

			counter = vle_keys_counter() - counter;
			assert(counter <= input_buf_pos);
			if(counter > 0)
			{
				input_buf_pos -= counter;
				memmove(input_buf, input_buf + counter,
						(wcslen(input_buf) - counter + 1)*sizeof(wchar_t));
			}

			if(last_result == KEYS_WAIT || last_result == KEYS_WAIT_SHORT)
			{
				if(should_display_suggestion_box())
				{
					wait_for_suggestion = 1;
				}

				if(got_input)
				{
					modupd_input_bar(input_buf);
				}

				if(last_result == KEYS_WAIT_SHORT && wcscmp(input_buf, L"\033") == 0)
				{
					timeout = 1;
				}

				if(counter > 0)
				{
					clear_input_bar();
				}

				if(!curr_stats.save_msg && curr_view->selected_files &&
						!vle_mode_is(CMDLINE_MODE))
				{
					print_selected_msg();
				}
				continue;
			}
		}

		timeout = cfg.timeout_len;

		process_scheduled_updates();

		reset_input_buf(input_buf, &input_buf_pos);
		clear_input_bar();

		if(ui_sb_multiline())
		{
			wait_for_enter = 1;
			update_all_windows();
			continue;
		}

		/* Ensure that current working directory is set correctly (some pieces of
		 * code rely on this).  PWD could be changed during command execution, but
		 * it should be correct for modes_post() in case of preview modes. */
		(void)vifm_chdir(flist_get_dir(curr_view));
		modes_post();
	}

	curr_input_buf = prev_input_buf;
	curr_input_buf_pos = prev_input_buf_pos;
}
Beispiel #13
0
void
vifm_restart(void)
{
	view_t *tmp_view;

	curr_stats.restart_in_progress = 1;

	/* All user mappings in all modes. */
	vle_keys_user_clear();

	/* User defined commands. */
	vle_cmds_run("comclear");

	/* Autocommands. */
	vle_aucmd_remove(NULL, NULL);

	/* All kinds of histories. */
	cfg_resize_histories(0);

	/* Session status.  Must be reset _before_ options, because options take some
	 * of values from status. */
	(void)stats_reset(&cfg);

	/* Options of current pane. */
	vle_opts_restore_defaults();
	/* Options of other pane. */
	tmp_view = curr_view;
	curr_view = other_view;
	load_view_options(other_view);
	vle_opts_restore_defaults();
	curr_view = tmp_view;

	/* File types and viewers. */
	ft_reset(curr_stats.exec_env_type == EET_EMULATOR_WITH_X);

	/* Undo list. */
	un_reset();

	/* Directory stack. */
	dir_stack_clear();

	/* Registers. */
	regs_reset();

	/* Clear all marks and bookmarks. */
	clear_all_marks();
	bmarks_clear();

	/* Reset variables. */
	clear_envvars();
	init_variables();
	/* This update is needed as clear_variables() will reset $PATH. */
	update_path_env(1);

	reset_views();
	read_info_file(1);
	flist_hist_save(&lwin, NULL, NULL, -1);
	flist_hist_save(&rwin, NULL, NULL, -1);

	/* Color schemes. */
	if(stroscmp(curr_stats.color_scheme, DEF_CS_NAME) != 0 &&
			cs_exists(curr_stats.color_scheme))
	{
		cs_load_primary(curr_stats.color_scheme);
	}
	else
	{
		cs_load_defaults();
	}
	cs_load_pairs();

	cfg_load();

	/* Reloading of tabs needs to happen after configuration is read so that new
	 * values from lwin and rwin got propagated. */
	tabs_reload();

	exec_startup_commands(&vifm_args);

	curr_stats.restart_in_progress = 0;

	/* Trigger auto-commands for initial directories. */
	(void)vifm_chdir(flist_get_dir(&lwin));
	vle_aucmd_execute("DirEnter", flist_get_dir(&lwin), &lwin);
	(void)vifm_chdir(flist_get_dir(&rwin));
	vle_aucmd_execute("DirEnter", flist_get_dir(&rwin), &rwin);

	update_screen(UT_REDRAW);
}
Beispiel #14
0
/* Entry-point.  Has same semantics as main(). */
static int
vifm_main(int argc, char *argv[])
{
	/* TODO: refactor vifm_main() function */

	static const int quit = 0;

	char **files = NULL;
	int nfiles = 0;
	int lwin_cv, rwin_cv;

	char dir[PATH_MAX + 1];
	if(get_start_cwd(dir, sizeof(dir)) != 0)
	{
		return -1;
	}

	args_parse(&vifm_args, argc, argv, dir);
	args_process(&vifm_args, 1);

	lwin_cv = (strcmp(vifm_args.lwin_path, "-") == 0 && vifm_args.lwin_handle);
	rwin_cv = (strcmp(vifm_args.rwin_path, "-") == 0 && vifm_args.rwin_handle);
	if(lwin_cv || rwin_cv)
	{
		files = read_stream_lines(stdin, &nfiles, 1, NULL, NULL);
		if(reopen_term_stdin() != 0)
		{
			free_string_array(files, nfiles);
			return EXIT_FAILURE;
		}
	}

	(void)setlocale(LC_ALL, "");
	srand(time(NULL));

	cfg_init();

	if(vifm_args.logging)
	{
		init_logger(1, vifm_args.startup_log_path);
	}

	init_filelists();
	tabs_init();
	regs_init();
	cfg_discover_paths();
	reinit_logger(cfg.log_file);

	/* Commands module also initializes bracket notation and variables. */
	init_commands();

	init_builtin_functions();
	update_path_env(1);

	if(stats_init(&cfg) != 0)
	{
		free_string_array(files, nfiles);

		puts("Error during session status initialization.");
		return -1;
	}

	/* Tell file type module what function to use to check availability of
	 * external programs. */
	ft_init(&external_command_exists);
	/* This should be called before loading any configuration file. */
	ft_reset(curr_stats.exec_env_type == EET_EMULATOR_WITH_X);

	init_option_handlers();

	if(!vifm_args.no_configs)
	{
		/* vifminfo must be processed this early so that it can restore last visited
		 * directory. */
		read_info_file(0);
	}

	curr_stats.ipc = ipc_init(vifm_args.server_name, &parse_received_arguments,
			&eval_received_expression);
	if(ipc_enabled() && curr_stats.ipc == NULL)
	{
		fputs("Failed to initialize IPC unit", stderr);
		return -1;
	}
	/* Export chosen server name to parsing unit. */
	{
		var_t var = var_from_str(ipc_get_name(curr_stats.ipc));
		setvar("v:servername", var);
		var_free(var);
	}

	args_process(&vifm_args, 0);

	bg_init();

	fops_init(&enter_prompt_mode, &prompt_msg_custom);

	set_view_path(&lwin, vifm_args.lwin_path);
	set_view_path(&rwin, vifm_args.rwin_path);

	if(need_to_switch_active_pane(vifm_args.lwin_path, vifm_args.rwin_path))
	{
		swap_view_roles();
	}

	load_initial_directory(&lwin, dir);
	load_initial_directory(&rwin, dir);

	/* Force split view when two paths are specified on command-line. */
	if(vifm_args.lwin_path[0] != '\0' && vifm_args.rwin_path[0] != '\0')
	{
		curr_stats.number_of_windows = 2;
	}

	/* Prepare terminal for further operations. */
	curr_stats.original_stdout = reopen_term_stdout();
	if(curr_stats.original_stdout == NULL)
	{
		free_string_array(files, nfiles);
		return -1;
	}

	if(!setup_ncurses_interface())
	{
		free_string_array(files, nfiles);
		return -1;
	}

	init_modes();
	un_init(&undo_perform_func, NULL, &ui_cancellation_requested,
			&cfg.undo_levels);
	load_view_options(curr_view);

	curr_stats.load_stage = 1;

	/* Make v:count exist during processing configuration. */
	set_count_vars(0);

	if(!vifm_args.no_configs)
	{
		load_scheme();
		cfg_load();
	}

	if(lwin_cv || rwin_cv)
	{
		flist_custom_set(lwin_cv ? &lwin : &rwin, "-", dir, files, nfiles);
	}
	free_string_array(files, nfiles);

	cs_load_pairs();
	cs_write();
	setup_signals();

	/* Ensure trash directories exist, it might not have been called during
	 * configuration file sourcing if there is no `set trashdir=...` command. */
	(void)set_trash_dir(cfg.trash_dir);

	check_path_for_file(&lwin, vifm_args.lwin_path, vifm_args.lwin_handle);
	check_path_for_file(&rwin, vifm_args.rwin_path, vifm_args.rwin_handle);

	curr_stats.load_stage = 2;

	/* Update histories of the views to ensure that their current directories,
	 * which might have been set using command-line parameters, are stored in the
	 * history.  This is not done automatically as history manipulation should be
	 * postponed until views are fully loaded, otherwise there is no correct
	 * information about current file and relative cursor position. */
	flist_hist_save(&lwin, NULL, NULL, -1);
	flist_hist_save(&rwin, NULL, NULL, -1);

	/* Trigger auto-commands for initial directories. */
	if(!lwin_cv)
	{
		(void)vifm_chdir(flist_get_dir(&lwin));
		vle_aucmd_execute("DirEnter", flist_get_dir(&lwin), &lwin);
	}
	if(!rwin_cv)
	{
		(void)vifm_chdir(flist_get_dir(&rwin));
		vle_aucmd_execute("DirEnter", flist_get_dir(&rwin), &rwin);
	}

	update_screen(UT_FULL);
	modes_update();

	/* Run startup commands after loading file lists into views, so that commands
	 * like +1 work. */
	exec_startup_commands(&vifm_args);

	curr_stats.load_stage = 3;

	event_loop(&quit);

	return 0;
}
Beispiel #15
0
/*
 * Main Loop
 * Everything is driven from this function with the exception of
 * signals which are handled in signals.c
 */
void
main_loop(void)
{
	LOG_FUNC_ENTER;

	int last_result = 0;
	int wait_enter = 0;
	int timeout = cfg.timeout_len;

	buf[0] = L'\0';
	while(1)
	{
		wchar_t c;
		size_t counter;
		int ret;

		is_term_working();

#ifdef _WIN32
		update_win_console();
#endif

		lwin.user_selection = 1;
		rwin.user_selection = 1;

		if(curr_stats.too_small_term > 0)
		{
			touchwin(stdscr);
			wrefresh(stdscr);

			mvwin(status_bar, 0, 0);
			wresize(status_bar, getmaxy(stdscr), getmaxx(stdscr));
			werase(status_bar);
			waddstr(status_bar, "Terminal is too small for vifm");
			touchwin(status_bar);
			wrefresh(status_bar);

#ifndef _WIN32
			pause();
#endif
			continue;
		}
		else if(curr_stats.too_small_term < 0)
		{
			wtimeout(status_bar, 0);
			while(wget_wch(status_bar, (wint_t*)&c) != ERR);
			curr_stats.too_small_term = 0;
			modes_redraw();
			wtimeout(status_bar, cfg.timeout_len);

			wait_enter = 0;
			curr_stats.save_msg = 0;
			status_bar_message("");
		}

		modes_pre();

		/* This waits for timeout then skips if no keypress. */
		ret = read_char(status_bar, (wint_t*)&c, timeout);

		/* Ensure that current working directory is set correctly (some pieces of
		 * code rely on this). */
		(void)vifm_chdir(curr_view->curr_dir);

		if(ret != ERR && pos != ARRAY_LEN(buf) - 2)
		{
			if(c == L'\x1a') /* Ctrl-Z */
			{
				def_prog_mode();
				endwin();
#ifndef _WIN32
				{
					void (*saved_stp_sig_handler)(int) = signal(SIGTSTP, SIG_DFL);
					kill(0, SIGTSTP);
					signal(SIGTSTP, saved_stp_sig_handler);
				}
#endif
				continue;
			}

			if(wait_enter)
			{
				wait_enter = 0;
				curr_stats.save_msg = 0;
				clean_status_bar();
				if(c == L'\x0d')
					continue;
			}

			buf[pos++] = c;
			buf[pos] = L'\0';
		}

		if(wait_enter && ret == ERR)
			continue;

		counter = get_key_counter();
		if(ret == ERR && last_result == KEYS_WAIT_SHORT)
		{
			last_result = execute_keys_timed_out(buf);
			counter = get_key_counter() - counter;
			assert(counter <= pos);
			if(counter > 0)
			{
				memmove(buf, buf + counter,
						(wcslen(buf) - counter + 1)*sizeof(wchar_t));
			}
		}
		else
		{
			if(ret != ERR)
				curr_stats.save_msg = 0;
			last_result = execute_keys(buf);
			counter = get_key_counter() - counter;
			assert(counter <= pos);
			if(counter > 0)
			{
				pos -= counter;
				memmove(buf, buf + counter,
						(wcslen(buf) - counter + 1)*sizeof(wchar_t));
			}
			if(last_result == KEYS_WAIT || last_result == KEYS_WAIT_SHORT)
			{
				if(ret != ERR)
					modupd_input_bar(buf);
				if(last_result == KEYS_WAIT_SHORT && wcscmp(buf, L"\033") == 0)
					timeout = 1;
				if(counter > 0)
					clear_input_bar();

				if(!curr_stats.save_msg && curr_view->selected_files &&
						get_mode() != CMDLINE_MODE)
					print_selected_msg();
				continue;
			}
		}

		timeout = cfg.timeout_len;

		process_scheduled_updates();

		pos = 0;
		buf[0] = L'\0';
		clear_input_bar();

		if(is_status_bar_multiline())
		{
			wait_enter = 1;
			update_all_windows();
			continue;
		}

		/* Ensure that current working directory is set correctly (some pieces of
		 * code rely on this).  PWD could be changed during command execution, but
		 * it should be correct for modes_post() in case of preview modes. */
		(void)vifm_chdir(curr_view->curr_dir);
		modes_post();
	}
}
Beispiel #16
0
void
event_loop(const int *quit)
{
	/* TODO: refactor this function event_loop(). */

	LOG_FUNC_ENTER;

	const wchar_t *const prev_input_buf = curr_input_buf;
	const size_t *const prev_input_buf_pos = curr_input_buf_pos;

	wchar_t input_buf[128];
	size_t input_buf_pos;

	int last_result = 0;
	int wait_for_enter = 0;
	int timeout = cfg.timeout_len;

	input_buf[0] = L'\0';
	input_buf_pos = 0;
	curr_input_buf = &input_buf[0];
	curr_input_buf_pos = &input_buf_pos;

	while(!*quit)
	{
		wint_t c;
		size_t counter;
		int got_input;

		if(!ensure_term_is_ready())
		{
			wait_for_enter = 0;
			continue;
		}

		lwin.user_selection = 1;
		rwin.user_selection = 1;

		modes_pre();

		/* Waits for timeout then skips if no keypress.  Short-circuit if we're not
		 * waiting for the next key after timeout. */
		do
		{
			modes_periodic();

			check_background_jobs();

			got_input = get_char_async_loop(status_bar, &c, timeout) != ERR;
			if(!got_input && input_buf_pos == 0)
			{
				timeout = cfg.timeout_len;
				continue;
			}
			break;
		}
		while(1);

		/* Ensure that current working directory is set correctly (some pieces of
		 * code rely on this). */
		(void)vifm_chdir(flist_get_dir(curr_view));

		if(got_input)
		{
			if(wait_for_enter)
			{
				wait_for_enter = 0;
				curr_stats.save_msg = 0;
				clean_status_bar();
				if(c == L'\x0d')
				{
					continue;
				}
			}

			if(c == L'\x1a') /* Ctrl-Z */
			{
				def_prog_mode();
				endwin();
				stop_process();
				continue;
			}

			if(input_buf_pos < ARRAY_LEN(input_buf) - 2)
			{
				input_buf[input_buf_pos++] = c;
				input_buf[input_buf_pos] = L'\0';
			}
			else
			{
				/* Recover from input buffer overflow by resetting its contents. */
				reset_input_buf(input_buf, &input_buf_pos);
				clear_input_bar();
				continue;
			}
		}

		counter = get_key_counter();
		if(!got_input && last_result == KEYS_WAIT_SHORT)
		{
			last_result = execute_keys_timed_out(input_buf);
			counter = get_key_counter() - counter;
			assert(counter <= input_buf_pos);
			if(counter > 0)
			{
				memmove(input_buf, input_buf + counter,
						(wcslen(input_buf) - counter + 1)*sizeof(wchar_t));
			}
		}
		else
		{
			if(got_input)
			{
				curr_stats.save_msg = 0;
			}

			last_result = execute_keys(input_buf);

			counter = get_key_counter() - counter;
			assert(counter <= input_buf_pos);
			if(counter > 0)
			{
				input_buf_pos -= counter;
				memmove(input_buf, input_buf + counter,
						(wcslen(input_buf) - counter + 1)*sizeof(wchar_t));
			}

			if(last_result == KEYS_WAIT || last_result == KEYS_WAIT_SHORT)
			{
				if(got_input)
				{
					modupd_input_bar(input_buf);
				}

				if(last_result == KEYS_WAIT_SHORT && wcscmp(input_buf, L"\033") == 0)
				{
					timeout = 1;
				}

				if(counter > 0)
				{
					clear_input_bar();
				}

				if(!curr_stats.save_msg && curr_view->selected_files &&
						!vle_mode_is(CMDLINE_MODE))
				{
					print_selected_msg();
				}
				continue;
			}
		}

		timeout = cfg.timeout_len;

		process_scheduled_updates();

		reset_input_buf(input_buf, &input_buf_pos);
		clear_input_bar();

		if(is_status_bar_multiline())
		{
			wait_for_enter = 1;
			update_all_windows();
			continue;
		}

		/* Ensure that current working directory is set correctly (some pieces of
		 * code rely on this).  PWD could be changed during command execution, but
		 * it should be correct for modes_post() in case of preview modes. */
		(void)vifm_chdir(flist_get_dir(curr_view));
		modes_post();
	}

	curr_input_buf = prev_input_buf;
	curr_input_buf_pos = prev_input_buf_pos;
}
Beispiel #17
0
/*
 * type: CT_*
 */
void
filename_completion(const char *str, CompletionType type)
{
	/* TODO refactor filename_completion(...) function */
	DIR * dir;
	char * dirname;
	char * filename;
	char * temp;

	if(str[0] == '~' && strchr(str, '/') == NULL)
	{
		char *const tilde_expanded = expand_tilde(str);
		vle_compl_add_path_match(tilde_expanded);
		free(tilde_expanded);
		return;
	}

	dirname = expand_tilde(str);
	filename = strdup(dirname);

	temp = cmds_expand_envvars(dirname);
	free(dirname);
	dirname = temp;

	temp = strrchr(dirname, '/');
	if(temp != NULL && type != CT_FILE && type != CT_FILE_WOE)
	{
		strcpy(filename, ++temp);
		*temp = '\0';
	}
	else
	{
		dirname = realloc(dirname, 2);
		strcpy(dirname, ".");
	}

#ifdef _WIN32
	if(is_unc_root(dirname) ||
			(stroscmp(dirname, ".") == 0 && is_unc_root(curr_view->curr_dir)) ||
			(stroscmp(dirname, "/") == 0 && is_unc_path(curr_view->curr_dir)))
	{
		char buf[PATH_MAX];
		if(!is_unc_root(dirname))
			snprintf(buf,
					strchr(curr_view->curr_dir + 2, '/') - curr_view->curr_dir + 1, "%s",
					curr_view->curr_dir);
		else
			snprintf(buf, sizeof(buf), "%s", dirname);

		complete_with_shared(buf, filename);
		free(filename);
		free(dirname);
		return;
	}
	if(is_unc_path(curr_view->curr_dir))
	{
		char buf[PATH_MAX];
		if(is_path_absolute(dirname) && !is_unc_root(curr_view->curr_dir))
			snprintf(buf,
					strchr(curr_view->curr_dir + 2, '/') - curr_view->curr_dir + 2, "%s",
					curr_view->curr_dir);
		else
			snprintf(buf, sizeof(buf), "%s", curr_view->curr_dir);
		strcat(buf, dirname);
		chosp(buf);
		(void)replace_string(&dirname, buf);
	}
#endif

	dir = opendir(dirname);

	if(dir == NULL || vifm_chdir(dirname) != 0)
	{
		vle_compl_add_path_match(filename);
	}
	else
	{
		filename_completion_internal(dir, dirname, filename, type);
		(void)vifm_chdir(curr_view->curr_dir);
	}

	free(filename);
	free(dirname);

	if(dir != NULL)
	{
		closedir(dir);
	}
}
Beispiel #18
0
int
main(int argc, char *argv[])
{
	/* TODO: refactor main() function */

	static const int quit = 0;

	char dir[PATH_MAX];
	char **files = NULL;
	int nfiles = 0;

	if(get_cwd(dir, sizeof(dir)) == NULL)
	{
		perror("getcwd");
		return -1;
	}

	(void)vifm_chdir(dir);
	args_parse(&vifm_args, argc, argv, dir);
	args_process(&vifm_args, 1);

	if(strcmp(vifm_args.lwin_path, "-") == 0 ||
			strcmp(vifm_args.rwin_path, "-") == 0)
	{
		files = read_stream_lines(stdin, &nfiles, 1, NULL, NULL);
		if(reopen_term_stdin() != 0)
		{
			return EXIT_FAILURE;
		}
	}

	(void)setlocale(LC_ALL, "");
	srand(time(NULL));

	cfg_init();

	if(vifm_args.logging)
	{
		init_logger(1, vifm_args.startup_log_path);
	}

	init_filelists();
	regs_init();
	cfg_discover_paths();
	reinit_logger(cfg.log_file);

	/* Commands module also initializes bracket notation and variables. */
	init_commands();

	init_builtin_functions();
	update_path_env(1);

	if(init_status(&cfg) != 0)
	{
		puts("Error during session status initialization.");
		return -1;
	}

	/* Tell file type module what function to use to check availability of
	 * external programs. */
	ft_init(&external_command_exists);
	/* This should be called before loading any configuration file. */
	ft_reset(curr_stats.exec_env_type == EET_EMULATOR_WITH_X);

	init_option_handlers();

	if(!vifm_args.no_configs)
	{
		/* vifminfo must be processed this early so that it can restore last visited
		 * directory. */
		read_info_file(0);
	}

	ipc_init(vifm_args.server_name, &parse_received_arguments);
	/* Export chosen server name to parsing unit. */
	{
		var_val_t value = { .string = (char *)ipc_get_name() };
		var_t var = var_new(VTYPE_STRING, value);
		setvar("v:servername", var);
		var_free(var);
	}

	args_process(&vifm_args, 0);

	bg_init();

	fops_init(&enter_prompt_mode, &prompt_msg_custom);

	set_view_path(&lwin, vifm_args.lwin_path);
	set_view_path(&rwin, vifm_args.rwin_path);

	if(need_to_switch_active_pane(vifm_args.lwin_path, vifm_args.rwin_path))
	{
		swap_view_roles();
	}

	load_initial_directory(&lwin, dir);
	load_initial_directory(&rwin, dir);

	/* Force split view when two paths are specified on command-line. */
	if(vifm_args.lwin_path[0] != '\0' && vifm_args.rwin_path[0] != '\0')
	{
		curr_stats.number_of_windows = 2;
	}

	/* Prepare terminal for further operations. */
	curr_stats.original_stdout = reopen_term_stdout();
	if(curr_stats.original_stdout == NULL)
	{
		return -1;
	}

	if(!setup_ncurses_interface())
	{
		return -1;
	}

	{
		const colmgr_conf_t colmgr_conf = {
			.max_color_pairs = COLOR_PAIRS,
			.max_colors = COLORS,
			.init_pair = &init_pair,
			.pair_content = &pair_content,
			.pair_in_use = &pair_in_use,
			.move_pair = &move_pair,
		};
		colmgr_init(&colmgr_conf);
	}

	init_modes();
	init_undo_list(&undo_perform_func, NULL, &ui_cancellation_requested,
			&cfg.undo_levels);
	load_view_options(curr_view);

	curr_stats.load_stage = 1;

	if(!vifm_args.no_configs)
	{
		load_scheme();
		cfg_load();

		if(strcmp(vifm_args.lwin_path, "-") == 0)
		{
			flist_custom_set(&lwin, "-", dir, files, nfiles);
		}
		else if(strcmp(vifm_args.rwin_path, "-") == 0)
		{
			flist_custom_set(&rwin, "-", dir, files, nfiles);
		}
	}
	/* Load colors in any case to load color pairs. */
	cs_load_pairs();

	cs_write();
	setup_signals();

	/* Ensure trash directories exist, it might not have been called during
	 * configuration file sourcing if there is no `set trashdir=...` command. */
	(void)set_trash_dir(cfg.trash_dir);

	check_path_for_file(&lwin, vifm_args.lwin_path, vifm_args.lwin_handle);
	check_path_for_file(&rwin, vifm_args.rwin_path, vifm_args.rwin_handle);

	curr_stats.load_stage = 2;

	/* Update histories of the views to ensure that their current directories,
	 * which might have been set using command-line parameters, are stored in the
	 * history.  This is not done automatically as history manipulation should be
	 * postponed until views are fully loaded, otherwise there is no correct
	 * information about current file and relative cursor position. */
	flist_hist_save(&lwin, NULL, NULL, -1);
	flist_hist_save(&rwin, NULL, NULL, -1);

	/* Trigger auto-commands for initial directories. */
	vle_aucmd_execute("DirEnter", lwin.curr_dir, &lwin);
	vle_aucmd_execute("DirEnter", rwin.curr_dir, &rwin);

	update_screen(UT_FULL);
	modes_update();

	/* Run startup commands after loading file lists into views, so that commands
	 * like +1 work. */
	exec_startup_commands(&vifm_args);

	curr_stats.load_stage = 3;

	event_loop(&quit);

	return 0;
}

/* Checks whether pair is being used at the moment.  Returns non-zero if so and
 * zero otherwise. */
static int
pair_in_use(short int pair)
{
	int i;

	for(i = 0; i < MAXNUM_COLOR; ++i)
	{
		if(cfg.cs.pair[i] == pair || lwin.cs.pair[i] == pair ||
				rwin.cs.pair[i] == pair)
		{
			return 1;
		}
	}

	return 0;
}