Example #1
0
void
modes_pre(void)
{
	if(vle_mode_is(CMDLINE_MODE))
	{
		touchwin(status_bar);
		wrefresh(status_bar);
		return;
	}
	else if(ANY(vle_mode_is, SORT_MODE, CHANGE_MODE, ATTR_MODE))
	{
		return;
	}
	else if(vle_mode_is(VIEW_MODE))
	{
		view_pre();
		return;
	}
	else if(is_in_menu_like_mode())
	{
		menu_pre();
		return;
	}

	if(!curr_stats.save_msg)
	{
		clean_status_bar();
		wrefresh(status_bar);
	}
}
Example #2
0
File: menu.c Project: cfillion/vifm
/* Gives menu-specific keyboard routine to process the shortcut.  Returns zero
 * if the shortcut wasn't processed, otherwise non-zero is returned. */
static int
pass_combination_to_khandler(const wchar_t keys[])
{
	KHandlerResponse handler_response;

	if(menu->key_handler == NULL)
	{
		return 0;
	}

	handler_response = menu->key_handler(menu, keys);

	switch(handler_response)
	{
		case KHR_REFRESH_WINDOW:
			wrefresh(menu_win);
			return 1;
		case KHR_CLOSE_MENU:
			leave_menu_mode(1);
			return 1;
		case KHR_MORPHED_MENU:
			assert(!vle_mode_is(MENU_MODE) && "Wrong use of KHR_MORPHED_MENU.");
			return 1;
		case KHR_UNHANDLED:
			return 0;

		default:
			assert(0 && "Unknown menu-specific keyboard handler response.");
			return 0;
	}
}
Example #3
0
static void
keys_v(key_info_t key_info, keys_info_t *keys_info)
{
	vle_mode_set(vle_mode_is(NORMAL_MODE) ? VISUAL_MODE : NORMAL_MODE,
			VMT_PRIMARY);
	printf("v visual mode toggle\n");
}
Example #4
0
static void
remote_cd(view_t *view, const char path[], int handle)
{
	char buf[PATH_MAX + 1];

	if(view->explore_mode)
	{
		view_leave_mode();
	}

	if(view == other_view && vle_mode_is(VIEW_MODE))
	{
		view_leave_mode();
	}

	if(curr_stats.preview.on && (handle || view == other_view))
	{
		qv_toggle();
	}

	copy_str(buf, sizeof(buf), path);
	exclude_file_name(buf);

	(void)cd(view, view->curr_dir, buf);
	check_path_for_file(view, path, handle);
}
Example #5
0
File: menu.c Project: acklinr/vifm
static void
cmd_return(key_info_t key_info, keys_info_t *keys_info)
{
	static menu_data_t *saved_menu;

	vle_mode_set(NORMAL_MODE, VMT_PRIMARY);
	saved_menu = menu;
	if(menu->execute_handler != NULL && menu->execute_handler(view, menu))
	{
		vle_mode_set(MENU_MODE, VMT_PRIMARY);
		menu_full_redraw();
		return;
	}

	if(!vle_mode_is(MENU_MODE))
	{
		menus_reset_data(saved_menu);
	}
	else if(menu != saved_menu)
	{
		menus_reset_data(saved_menu);
		menu_partial_redraw();
	}

	update_ui_on_leaving();
}
Example #6
0
File: menu.c Project: cfillion/vifm
static void
cmd_ctrl_m(key_info_t key_info, keys_info_t *keys_info)
{
	static menu_info *saved_menu;

	vle_mode_set(NORMAL_MODE, VMT_PRIMARY);
	saved_menu = menu;
	if(menu->execute_handler != NULL && menu->execute_handler(curr_view, menu))
	{
		vle_mode_set(MENU_MODE, VMT_PRIMARY);
		menu_redraw();
		return;
	}

	if(!vle_mode_is(MENU_MODE))
	{
		reset_popup_menu(saved_menu);
	}
	else if(menu != saved_menu)
	{
		reset_popup_menu(saved_menu);
		update_menu();
	}

	update_ui_on_leaving();
}
Example #7
0
/* Checks whether suggestion box should be displayed.  Returns non-zero if so,
 * otherwise zero is returned. */
static int
should_display_suggestion_box(void)
{
	if((cfg.sug.flags & SF_NORMAL) && vle_mode_is(NORMAL_MODE))
	{
		return 1;
	}
	if((cfg.sug.flags & SF_VISUAL) && vle_mode_is(VISUAL_MODE))
	{
		return 1;
	}
	if((cfg.sug.flags & SF_VIEW) && vle_mode_is(VIEW_MODE))
	{
		return 1;
	}
	return 0;
}
Example #8
0
void
clear_input_bar(void)
{
	if(uses_input_bar[vle_mode_get()] && !vle_mode_is(VISUAL_MODE))
	{
		clear_num_window();
	}
}
Example #9
0
static void
cmd_return(key_info_t key_info, keys_info_t *keys_info)
{
	update_marks(view);
	if(vle_mode_is(VISUAL_MODE))
	{
		vle_mode_set(NORMAL_MODE, VMT_PRIMARY);
	}
}
Example #10
0
File: menu.c Project: acklinr/vifm
void
menu_reenter_mode(menu_data_t *m)
{
	assert(vle_mode_is(MENU_MODE) && "Can't reenter if not in menu mode.");
	assert(m->len > 0 && "Menu cannot be empty.");

	menus_replace_data(m);
	menus_full_redraw(m->state);
	menu = m;
}
Example #11
0
void
modes_statusbar_update(void)
{
	if(curr_stats.save_msg)
	{
		if(vle_mode_is(VISUAL_MODE))
		{
			update_vmode_input();
		}
	}
	else if(curr_view->selected_files || vle_mode_is(VISUAL_MODE))
	{
		print_selected_msg();
	}
	else
	{
		clean_status_bar();
	}
}
Example #12
0
void
modes_update(void)
{
	if(vle_mode_is(CMDLINE_MODE))
	{
		redraw_cmdline();
		return;
	}
	else if(vle_mode_is(MENU_MODE))
	{
		menu_redraw();
		return;
	}
	else if(vle_mode_is(FILE_INFO_MODE))
	{
		redraw_file_info_dialog();
		return;
	}

	touchwin(stdscr);
	update_all_windows();

	if(vle_mode_is(SORT_MODE))
	{
		redraw_sort_dialog();
	}
	else if(vle_mode_is(CHANGE_MODE))
	{
		redraw_change_dialog();
	}
	else if(vle_mode_is(ATTR_MODE))
	{
		redraw_attr_dialog();
	}
}
Example #13
0
void
modupd_input_bar(wchar_t *str)
{
	if(vle_mode_is(VISUAL_MODE))
	{
		clear_input_bar();
	}

	if(uses_input_bar[vle_mode_get()])
	{
		update_input_bar(str);
	}
}
Example #14
0
void
modes_post(void)
{
	if(ANY(vle_mode_is, CMDLINE_MODE, SORT_MODE, CHANGE_MODE, ATTR_MODE))
	{
		return;
	}
	else if(vle_mode_is(VIEW_MODE))
	{
		view_post();
		return;
	}
	else if(is_in_menu_like_mode())
	{
		menu_post();
		return;
	}

	update_screen(curr_stats.need_update);

	if(curr_stats.save_msg)
	{
		status_bar_message(NULL);
	}

	if(!vle_mode_is(FILE_INFO_MODE) && curr_view->list_rows > 0)
	{
		if(!is_status_bar_multiline())
		{
			update_stat_window(curr_view);
			ui_ruler_update(curr_view);
		}
	}

	modes_statusbar_update();
}
Example #15
0
void
print_selected_msg(void)
{
	if(vle_mode_is(VISUAL_MODE))
	{
		status_bar_messagef("-- %s -- ", describe_visual_mode());
		update_vmode_input();
	}
	else
	{
		status_bar_messagef("%d %s selected", curr_view->selected_files,
				curr_view->selected_files == 1 ? "file" : "files");
	}
	curr_stats.save_msg = 2;
}
Example #16
0
void
view_explore_mode_quit(FileView *view)
{
	assert(!vle_mode_is(VIEW_MODE) && "Unexpected mode.");
	if(!view->explore_mode)
	{
		return;
	}

	view->explore_mode = 0;

	reset_view_info(&view_info[(view == &lwin) ? VI_LWIN : VI_RWIN]);

	redraw_view(view);
	ui_view_title_update(view);
}
Example #17
0
File: menu.c Project: acklinr/vifm
/* Leaves menu mode, possibly resetting selection.  Does nothing if current mode
 * isn't menu mode. */
static void
leave_menu_mode(int reset_selection)
{
	/* Some menu implementation could have switched mode from one of handlers. */
	if(!vle_mode_is(MENU_MODE))
	{
		return;
	}

	menus_reset_data(menu);

	if(reset_selection)
	{
		flist_sel_stash(view);
		redraw_view(view);
	}

	vle_mode_set(NORMAL_MODE, VMT_PRIMARY);

	update_ui_on_leaving();
}
Example #18
0
File: menu.c Project: cfillion/vifm
/* Leaves menu mode, possibly resetting selection.  Does nothing if current mode
 * isn't menu mode. */
static void
leave_menu_mode(int reset_selection)
{
	/* Some menu implementation could have switched mode from one of handlers. */
	if(!vle_mode_is(MENU_MODE))
	{
		return;
	}

	reset_popup_menu(menu);

	if(reset_selection)
	{
		clean_selected_files(view);
		redraw_view(view);
	}

	vle_mode_set(NORMAL_MODE, VMT_PRIMARY);

	update_ui_on_leaving();
}
Example #19
0
void
leave_visual_mode(int save_msg, int goto_top, int clear_selection)
{
	if(goto_top)
	{
		int ub = check_mark_directory(view, '<');
		if(ub != -1)
			view->list_pos = ub;
	}

	if(clear_selection)
	{
		reset_search_results(view);
		restore_selection_flags(view);
		redraw_view(view);
	}

	curr_stats.save_msg = save_msg;
	if(vle_mode_is(VISUAL_MODE))
	{
		vle_mode_set(NORMAL_MODE, VMT_PRIMARY);
	}
}
Example #20
0
void
modes_redraw(void)
{
	LOG_FUNC_ENTER;

	static int in_here;

	if(curr_stats.load_stage < 2)
	{
		return;
	}

	if(in_here++ > 0)
	{
		/* TODO: is this still needed?  Update scheduling might have solved issues
		 * caused by asynchronous execution of this function in the past. */
		return;
	}

	if(curr_stats.term_state != TS_NORMAL)
	{
		update_screen(UT_REDRAW);
		goto finish;
	}

	if(vle_mode_is(CMDLINE_MODE))
	{
		redraw_cmdline();
		goto finish;
	}
	else if(vle_primary_mode_is(MENU_MODE))
	{
		menu_redraw();
		if(vle_mode_is(MSG_MODE))
		{
			redraw_msg_dialog(0);
		}
		goto finish;
	}
	else if(vle_mode_is(FILE_INFO_MODE))
	{
		redraw_file_info_dialog();
		goto finish;
	}

	update_screen(UT_REDRAW);

	if(curr_stats.save_msg)
	{
		status_bar_message(NULL);
	}

	if(vle_mode_is(SORT_MODE))
	{
		redraw_sort_dialog();
	}
	else if(vle_mode_is(CHANGE_MODE))
	{
		redraw_change_dialog();
	}
	else if(vle_mode_is(ATTR_MODE))
	{
		redraw_attr_dialog();
	}
	else if(vle_mode_is(VIEW_MODE))
	{
		view_redraw();
	}
	else if(vle_mode_is(MSG_MODE))
	{
		redraw_msg_dialog(0);
	}

finish:
	if(--in_here > 0)
	{
		modes_redraw();
	}
}
Example #21
0
/* Returns negative value in case of error */
static int
execute_command(FileView *view, const char command[], int menu)
{
	int id;
	int result;

	if(command == NULL)
	{
		flist_sel_stash_if_nonempty(view);
		return 0;
	}

	command = skip_to_cmd_name(command);

	if(command[0] == '"')
		return 0;

	if(command[0] == '\0' && !menu)
	{
		flist_sel_stash_if_nonempty(view);
		return 0;
	}

	if(!menu)
	{
		init_cmds(1, &cmds_conf);
		cmds_conf.begin = 0;
		cmds_conf.current = view->list_pos;
		cmds_conf.end = view->list_rows - 1;
	}

	id = get_cmd_id(command);

	if(!cmd_should_be_processed(id))
	{
		return 0;
	}

	if(id == USER_CMD_ID)
	{
		char undo_msg[COMMAND_GROUP_INFO_LEN];

		snprintf(undo_msg, sizeof(undo_msg), "in %s: %s",
				replace_home_part(flist_get_dir(view)), command);

		cmd_group_begin(undo_msg);
		cmd_group_end();
	}

	keep_view_selection = 0;
	result = execute_cmd(command);

	if(result >= 0)
		return result;

	switch(result)
	{
		case CMDS_ERR_LOOP:
			status_bar_error("Loop in commands");
			break;
		case CMDS_ERR_NO_MEM:
			status_bar_error("Unable to allocate enough memory");
			break;
		case CMDS_ERR_TOO_FEW_ARGS:
			status_bar_error("Too few arguments");
			break;
		case CMDS_ERR_TRAILING_CHARS:
			status_bar_error("Trailing characters");
			break;
		case CMDS_ERR_INCORRECT_NAME:
			status_bar_error("Incorrect command name");
			break;
		case CMDS_ERR_NEED_BANG:
			status_bar_error("Add bang to force");
			break;
		case CMDS_ERR_NO_BUILTIN_REDEFINE:
			status_bar_error("Can't redefine builtin command");
			break;
		case CMDS_ERR_INVALID_CMD:
			status_bar_error("Invalid command name");
			break;
		case CMDS_ERR_NO_BANG_ALLOWED:
			status_bar_error("No ! is allowed");
			break;
		case CMDS_ERR_NO_RANGE_ALLOWED:
			status_bar_error("No range is allowed");
			break;
		case CMDS_ERR_NO_QMARK_ALLOWED:
			status_bar_error("No ? is allowed");
			break;
		case CMDS_ERR_INVALID_RANGE:
			/* message dialog is enough */
			break;
		case CMDS_ERR_NO_SUCH_UDF:
			status_bar_error("No such user defined command");
			break;
		case CMDS_ERR_UDF_IS_AMBIGUOUS:
			status_bar_error("Ambiguous use of user-defined command");
			break;
		case CMDS_ERR_ZERO_COUNT:
			status_bar_error("Zero count");
			break;
		case CMDS_ERR_INVALID_ARG:
			status_bar_error("Invalid argument");
			break;
		case CMDS_ERR_CUSTOM:
			/* error message is posted by command handler */
			break;
		default:
			status_bar_error("Unknown error");
			break;
	}

	if(!menu && vle_mode_is(NORMAL_MODE))
	{
		flist_sel_stash_if_nonempty(view);
	}

	return -1;
}
Example #22
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;
}
Example #23
0
static void
status_bar_message_i(const char message[], int error)
{
	/* TODO: Refactor this function status_bar_message_i() */

	static char *msg;
	static int err;

	int len;
	const char *p, *q;
	int lines;
	int status_bar_lines;
	size_t screen_length;
	const char *out_msg;
	char truncated_msg[2048];

	if(curr_stats.load_stage == 0)
	{
		return;
	}

	if(message != NULL)
	{
		if(replace_string(&msg, message))
		{
			return;
		}

		err = error;

		save_status_bar_msg(msg);
	}

	if(msg == NULL || vle_mode_is(CMDLINE_MODE))
	{
		return;
	}

	p = msg;
	q = msg - 1;
	status_bar_lines = 0;
	len = getmaxx(stdscr);
	while((q = strchr(q + 1, '\n')) != NULL)
	{
		status_bar_lines += DIV_ROUND_UP(q - p, len );
		if(q == p)
		{
			++status_bar_lines;
		}
		p = q + 1;
	}
	if(*p == '\0')
	{
		++status_bar_lines;
	}
	screen_length = utf8_strsw(p);
	status_bar_lines += DIV_ROUND_UP(screen_length, len);
	if(status_bar_lines == 0)
	{
		status_bar_lines = 1;
	}

	lines = status_bar_lines;
	if(status_bar_lines > 1 || screen_length > (size_t)getmaxx(status_bar))
	{
		++lines;
	}

	out_msg = msg;

	if(lines > 1)
	{
		if(cfg.trunc_normal_sb_msgs && !err && curr_stats.allow_sb_msg_truncation)
		{
			truncate_with_ellipsis(msg, getmaxx(stdscr) - FIELDS_WIDTH(),
					truncated_msg);
			out_msg = truncated_msg;
			lines = 1;
		}
		else
		{
			const int extra = DIV_ROUND_UP(ARRAY_LEN(PRESS_ENTER_MSG) - 1, len) - 1;
			lines += extra;
		}
	}

	if(lines > getmaxy(stdscr))
	{
		lines = getmaxy(stdscr);
	}

	(void)ui_stat_reposition(lines);
	mvwin(status_bar, getmaxy(stdscr) - lines, 0);
	if(lines == 1)
	{
		wresize(status_bar, lines, getmaxx(stdscr) - FIELDS_WIDTH());
	}
	else
	{
		wresize(status_bar, lines, getmaxx(stdscr));
	}
	checked_wmove(status_bar, 0, 0);

	if(err)
	{
		col_attr_t col = cfg.cs.color[CMD_LINE_COLOR];
		mix_colors(&col, &cfg.cs.color[ERROR_MSG_COLOR]);
		wattron(status_bar, COLOR_PAIR(colmgr_get_pair(col.fg, col.bg)) | col.attr);
	}
	else
	{
		int attr = cfg.cs.color[CMD_LINE_COLOR].attr;
		wattron(status_bar, COLOR_PAIR(cfg.cs.pair[CMD_LINE_COLOR]) | attr);
	}
	werase(status_bar);

	wprint(status_bar, out_msg);
	multiline_status_bar = lines > 1;
	if(multiline_status_bar)
	{
		checked_wmove(status_bar,
				lines - DIV_ROUND_UP(ARRAY_LEN(PRESS_ENTER_MSG), len), 0);
		wclrtoeol(status_bar);
		if(lines < status_bar_lines)
			wprintw(status_bar, "%d of %d lines.  ", lines, status_bar_lines);
		wprintw(status_bar, "%s", PRESS_ENTER_MSG);
	}

	wattrset(status_bar, 0);

	update_all_windows();
	/* This is needed because update_all_windows() doesn't call doupdate() if
	 * curr_stats.load_stage == 1. */
	doupdate();
}
Example #24
0
/* Expands macros in the *format string advancing the pointer as it goes.  The
 * opt represents conditional expression state, should be zero for non-recursive
 * calls.  Returns newly allocated string, which should be freed by the
 * caller. */
static char *
parse_view_macros(FileView *view, const char **format, const char macros[],
		int opt)
{
	const dir_entry_t *const entry = &view->dir_entry[view->list_pos];
	char *result = strdup("");
	size_t len = 0;
	char c;
	int nexpansions = 0;

	while((c = **format) != '\0')
	{
		size_t width = 0;
		int left_align = 0;
		char buf[PATH_MAX];
		const char *const next = ++*format;
		int skip, ok;

		if(c != '%' || (!char_is_one_of(macros, *next) && !isdigit(*next)))
		{
			if(strappendch(&result, &len, c) != 0)
			{
				break;
			}
			continue;
		}

		if(*next == '-')
		{
			left_align = 1;
			++*format;
		}

		while(isdigit(**format))
		{
			width = width*10 + *(*format)++ - '0';
		}
		c = *(*format)++;

		skip = 0;
		ok = 1;
		switch(c)
		{
			case 't':
				format_entry_name(entry, sizeof(buf), buf);
				break;
			case 'A':
#ifndef _WIN32
				get_perm_string(buf, sizeof(buf), entry->mode);
#else
				snprintf(buf, sizeof(buf), "%s", attr_str_long(entry->attrs));
#endif
				break;
			case 'u':
				get_uid_string(entry, 0, sizeof(buf), buf);
				break;
			case 'g':
				get_gid_string(entry, 0, sizeof(buf), buf);
				break;
			case 's':
				friendly_size_notation(entry->size, sizeof(buf), buf);
				break;
			case 'E':
				{
					uint64_t size = 0;
					if(view->selected_files > 0)
					{
						int i;
						for(i = 0; i < view->list_rows; i++)
						{
							if(view->dir_entry[i].selected)
							{
								size += get_file_size_by_entry(view, i);
							}
						}
					}
					/* Make exception for VISUAL_MODE, since it can contain empty
					 * selection when cursor is on ../ directory. */
					else if(!vle_mode_is(VISUAL_MODE))
					{
						size = get_file_size_by_entry(view, view->list_pos);
					}
					friendly_size_notation(size, sizeof(buf), buf);
				}
				break;
			case 'd':
				{
					struct tm *tm_ptr = localtime(&entry->mtime);
					strftime(buf, sizeof(buf), cfg.time_format, tm_ptr);
				}
				break;
			case '-':
				skip = expand_num(buf, sizeof(buf), view->filtered);
				break;
			case 'l':
				skip = expand_num(buf, sizeof(buf), view->list_pos + 1);
				break;
			case 'L':
				skip = expand_num(buf, sizeof(buf), view->list_rows + view->filtered);
				break;
			case 'S':
				skip = expand_num(buf, sizeof(buf), view->list_rows);
				break;
			case '%':
				snprintf(buf, sizeof(buf), "%%");
				break;
			case '[':
				{
					char *const opt_str = parse_view_macros(view, format, macros, 1);
					copy_str(buf, sizeof(buf), opt_str);
					free(opt_str);
					break;
				}
			case ']':
				if(opt)
				{
					if(nexpansions == 0)
					{
						replace_string(&result, "");
					}
					return result;
				}
				else
				{
					LOG_INFO_MSG("Unmatched %]", c);
					ok = 0;
				}
				break;

			default:
				LOG_INFO_MSG("Unexpected %%-sequence: %%%c", c);
				ok = 0;
				break;
		}

		if(!ok)
		{
			*format = next;
			if(strappendch(&result, &len, '%') != 0)
			{
				break;
			}
			continue;
		}

		check_expanded_str(buf, skip, &nexpansions);
		stralign(buf, width, ' ', left_align);

		if(strappend(&result, &len, buf) != 0)
		{
			break;
		}
	}

	/* Unmatched %[. */
	if(opt)
	{
		(void)strprepend(&result, &len, "%[");
	}

	return result;
}
Example #25
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;
}
Example #26
0
void
quick_view_file(FileView *view)
{
	char path[PATH_MAX];
	const dir_entry_t *entry;

	if(curr_stats.load_stage < 2)
	{
		return;
	}

	if(vle_mode_is(VIEW_MODE))
	{
		return;
	}

	if(curr_stats.number_of_windows == 1)
	{
		return;
	}

	if(draw_abandoned_view_mode())
	{
		return;
	}

	ui_view_erase(other_view);

	entry = &view->dir_entry[view->list_pos];
	get_full_path_of(entry, sizeof(path), path);

	switch(view->dir_entry[view->list_pos].type)
	{
		case FT_CHAR_DEV:
			mvwaddstr(other_view->win, LINE, COL, "File is a Character Device");
			break;
		case FT_BLOCK_DEV:
			mvwaddstr(other_view->win, LINE, COL, "File is a Block Device");
			break;
#ifndef _WIN32
		case FT_SOCK:
			mvwaddstr(other_view->win, LINE, COL, "File is a Socket");
			break;
#endif
		case FT_FIFO:
			mvwaddstr(other_view->win, LINE, COL, "File is a Named Pipe");
			break;
		case FT_LINK:
			if(get_link_target_abs(path, entry->origin, path, sizeof(path)) != 0)
			{
				mvwaddstr(other_view->win, LINE, COL, "Cannot resolve Link");
				break;
			}
			if(!ends_with_slash(path) && is_dir(path))
			{
				strncat(path, "/", sizeof(path) - strlen(path) - 1);
			}
			/* break intensionally omitted */
		case FT_UNK:
		default:
			{
				const char *viewer;
				FILE *fp;

				char *const typed_fname = get_typed_fname(path);
				viewer = ft_get_viewer(typed_fname);
				free(typed_fname);

				if(viewer == NULL && is_dir(path))
				{
					mvwaddstr(other_view->win, LINE, COL, "File is a Directory");
					break;
				}
				if(is_null_or_empty(viewer))
				{
					fp = os_fopen(path, "rb");
				}
				else
				{
					fp = use_info_prog(viewer);
				}

				if(fp == NULL)
				{
					mvwaddstr(other_view->win, LINE, COL, "Cannot open file");
					break;
				}

				ui_view_clear(other_view);
				wattrset(other_view->win, 0);
				view_file(fp, cfg.wrap_quick_view);

				fclose(fp);
				break;
			}
	}
	refresh_view_win(other_view);

	ui_view_title_update(other_view);
}
Example #27
0
/* Expands macros in the *format string advancing the pointer as it goes.  The
 * opt represents conditional expression state, should be zero for non-recursive
 * calls.  Returns newly allocated string, which should be freed by the
 * caller. */
static LineWithAttrs
parse_view_macros(view_t *view, const char **format, const char macros[],
		int opt)
{
	const dir_entry_t *const curr = get_current_entry(view);
	LineWithAttrs result = { .line = strdup(""), .attrs = strdup("") };
	char c;
	int nexpansions = 0;
	int has_expander = 0;

	if(curr == NULL)
	{
		return result;
	}

	while((c = **format) != '\0')
	{
		size_t width = 0;
		int left_align = 0;
		char buf[PATH_MAX + 1];
		const char *const next = ++*format;
		int skip, ok;

		if(c != '%' ||
				(!char_is_one_of(macros, *next) && !isdigit(*next) &&
				 (*next != '=' || has_expander)))
		{
			if(strappendch(&result.line, &result.line_len, c) != 0)
			{
				break;
			}
			continue;
		}

		if(*next == '=')
		{
			(void)sync_attrs(&result, 0);

			if(strappend(&result.line, &result.line_len, "%=") != 0 ||
					strappendch(&result.attrs, &result.attrs_len, '=') != 0)
			{
				break;
			}
			++*format;
			has_expander = 1;
			continue;
		}

		if(*next == '-')
		{
			left_align = 1;
			++*format;
		}

		while(isdigit(**format))
		{
			width = width*10 + *(*format)++ - '0';
		}
		c = *(*format)++;

		skip = 0;
		ok = 1;
		buf[0] = '\0';
		switch(c)
		{
			case 'a':
				friendly_size_notation(get_free_space(curr_view->curr_dir), sizeof(buf),
						buf);
				break;
			case 't':
				format_entry_name(curr, NF_FULL, sizeof(buf), buf);
				break;
			case 'T':
				if(curr->type == FT_LINK)
				{
					char full_path[PATH_MAX + 1];
					char link_path[PATH_MAX + 1];  //add by sim1
					get_full_path_of(curr, sizeof(full_path), full_path);
					//mod by sim1 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
					if(get_link_target(full_path, link_path, sizeof(link_path)) != 0)
					{
						copy_str(buf, sizeof(buf), "Failed to resolve link");
					}
					else
					{
						snprintf(buf, sizeof(buf), " -> %s", link_path);
					}
					//mod by sim1 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
				}
				break;
			case 'f':
				get_short_path_of(view, curr, NF_FULL, 0, sizeof(buf), buf);
				break;
			case 'A':
#ifndef _WIN32
				get_perm_string(buf, sizeof(buf), curr->mode);
#else
				copy_str(buf, sizeof(buf), attr_str_long(curr->attrs));
#endif
				break;
			case 'u':
				get_uid_string(curr, 0, sizeof(buf), buf);
				break;
			case 'g':
				get_gid_string(curr, 0, sizeof(buf), buf);
				break;
			case 's':
				friendly_size_notation(fentry_get_size(view, curr), sizeof(buf), buf);
				break;
			//add by sim1 ************************************************
			case 'r':
				{
					char path[PATH_MAX] = {0};
					get_full_path_at(view, view->list_pos, sizeof(path), path);
					(void)get_rating_string(buf, sizeof(buf), path);
				}
				break;
			case 'n':
				{
					int nitems = !fentry_is_dir(curr) ? 0 : (int)fentry_get_nitems(view, curr);
					snprintf(buf, sizeof(buf), "%d", nitems);
				}
				break;
			//add by sim1 ************************************************
			case 'E':
				{
					uint64_t size = 0U;

					typedef int (*iter_f)(view_t *view, dir_entry_t **entry);
					/* No current element for visual mode, since it can contain truly
					 * empty selection when cursor is on ../ directory. */
					iter_f iter = vle_mode_is(VISUAL_MODE) ? &iter_selected_entries
					                                       : &iter_selection_or_current;

					dir_entry_t *entry = NULL;
					while(iter(view, &entry))
					{
						size += fentry_get_size(view, entry);
					}

					friendly_size_notation(size, sizeof(buf), buf);
				}
				break;
			case 'd':
				{
					struct tm *tm_ptr = localtime(&curr->mtime);
					strftime(buf, sizeof(buf), cfg.time_format, tm_ptr);
				}
				break;
			case '-':
			case 'x':
				skip = expand_num(buf, sizeof(buf), view->filtered);
				break;
			case 'l':
				skip = expand_num(buf, sizeof(buf), view->list_pos + 1);
				break;
			case 'L':
				skip = expand_num(buf, sizeof(buf), view->list_rows + view->filtered);
				break;
			case 'S':
				skip = expand_num(buf, sizeof(buf), view->list_rows);
				break;
			case '%':
				copy_str(buf, sizeof(buf), "%");
				break;
			case 'z':
				copy_str(buf, sizeof(buf), get_tip());
				break;
			case 'D':
				if(curr_stats.number_of_windows == 1)
				{
					view_t *const other = (view == curr_view) ? other_view : curr_view;
					//mod by sim1
					//copy_str(buf, sizeof(buf), replace_home_part(other->curr_dir));
					snprintf(buf, sizeof(buf), " ‖ %s", replace_home_part(other->curr_dir));
				}
				break;
			case '[':
				{
					LineWithAttrs opt = parse_view_macros(view, format, macros, 1);
					copy_str(buf, sizeof(buf), opt.line);
					free(opt.line);

					char *attrs = opt.attrs;
					if(sync_attrs(&result, 0) && opt.attrs_len > 0U)
					{
						if(*attrs != ' ')
						{
							result.attrs[result.attrs_len - 1U] = *attrs;
						}
						++attrs;
					}
					strappend(&result.attrs, &result.attrs_len, attrs);
					free(opt.attrs);
					break;
				}
			case ']':
				if(opt)
				{
					if(nexpansions == 0)
					{
						replace_string(&result.line, "");
						replace_string(&result.attrs, "");
						result.line_len = 0U;
						result.attrs_len = 0U;
					}
					if(sync_attrs(&result, 0))
					{
						result.attrs[--result.attrs_len] = '\0';
					}
					return result;
				}

				LOG_INFO_MSG("Unmatched %%]");
				ok = 0;
				break;
			case '{':
				{
					/* Try to find matching closing bracket
					 * TODO: implement the way to escape it, so that the expr may contain
					 * closing brackets */
					const char *e = strchr(*format, '}');
					char *expr = NULL, *resstr = NULL;
					var_t res = var_false();
					ParsingErrors parsing_error;

					/* If there's no matching closing bracket, just add the opening one
					 * literally */
					if(e == NULL)
					{
						ok = 0;
						break;
					}

					/* Create a NULL-terminated copy of the given expr.
					 * TODO: we could temporarily use buf for that, to avoid extra
					 * allocation, but explicitly named variable reads better. */
					expr = calloc(e - (*format) + 1 /* NUL-term */, 1);
					memcpy(expr, *format, e - (*format));

					/* Try to parse expr, and convert the res to string if succeed. */
					parsing_error = parse(expr, 0, &res);
					if(parsing_error == PE_NO_ERROR)
					{
						resstr = var_to_str(res);
					}

					if(resstr != NULL)
					{
						copy_str(buf, sizeof(buf), resstr);
					}
					else
					{
						copy_str(buf, sizeof(buf), "<Invalid expr>");
					}

					var_free(res);
					free(resstr);
					free(expr);

					*format = e + 1 /* closing bracket */;
				}
				break;
			case '*':
				if(width > 9)
				{
					snprintf(buf, sizeof(buf), "%%%d*", (int)width);
					width = 0;
					break;
				}
				(void)sync_attrs(&result, 1);
				result.attrs[result.attrs_len - 1] = '0' + width;
				width = 0;
				break;

			default:
				LOG_INFO_MSG("Unexpected %%-sequence: %%%c", c);
				ok = 0;
				break;
		}

		if(char_is_one_of("tTAugsEd", c) && fentry_is_fake(curr))
		{
			buf[0] = '\0';
		}

		if(!ok)
		{
			*format = next;
			if(strappendch(&result.line, &result.line_len, '%') != 0)
			{
				break;
			}
			continue;
		}

		check_expanded_str(buf, skip, &nexpansions);
		stralign(buf, width, ' ', left_align);

		if(strappend(&result.line, &result.line_len, buf) != 0)
		{
			break;
		}
	}

	/* Unmatched %[. */
	if(opt)
	{
		(void)strprepend(&result.line, &result.line_len, "%[");
	}

	if(sync_attrs(&result, 0))
	{
		result.attrs[--result.attrs_len] = '\0';
	}
	return result;
}

/* Makes sure that result->attrs has at least as many elements as result->line
 * contains characters + extra_width.  Returns non-zero if result->attrs has
 * extra characters compared to result->line. */
static int
sync_attrs(LineWithAttrs *result, int extra_width)
{
	const size_t nchars = utf8_strsw(result->line) + extra_width;
	if(result->attrs_len < nchars)
	{
		char *const new_attrs = format_str("%s%*s", result->attrs,
				(int)(nchars - result->attrs_len), "");
		free(result->attrs);
		result->attrs = new_attrs;
		result->attrs_len = nchars;
	}
	return (result->attrs_len > nchars);
}

/* Prints number into the buffer.  Returns non-zero if numeric value is
 * "empty" (zero). */
static int
expand_num(char buf[], size_t buf_len, int val)
{
	snprintf(buf, buf_len, "%d", val);
	return (val == 0);
}