/* 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)); }
/* 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); } }
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; }
/* 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; }
/* 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(>abs[current_tab]); assign_preview(>abs[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, >abs[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)); }
/* 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); }
/* 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)); }
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); }
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; }
/* 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; }
/* * 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; }
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; }
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); }
/* 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; }
/* * 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(); } }
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; }
/* * 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); } }
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; }