wcstring_list_t env_get_names(int flags) { scoped_lock lock(env_lock); wcstring_list_t result; std::set<wcstring> names; int show_local = flags & ENV_LOCAL; int show_global = flags & ENV_GLOBAL; int show_universal = flags & ENV_UNIVERSAL; env_node_t *n=top; const bool show_exported = (flags & ENV_EXPORT) || !(flags & ENV_UNEXPORT); const bool show_unexported = (flags & ENV_UNEXPORT) || !(flags & ENV_EXPORT); if (!show_local && !show_global && !show_universal) { show_local =show_universal = show_global=1; } if (show_local) { while (n) { if (n == global_env) break; add_key_to_string_set(n->env, &names, show_exported, show_unexported); if (n->new_scope) break; else n = n->next; } } if (show_global) { add_key_to_string_set(global_env->env, &names, show_exported, show_unexported); if (show_unexported) { result.insert(result.end(), env_electric.begin(), env_electric.end()); } if (show_exported) { result.push_back(L"COLUMNS"); result.push_back(L"LINES"); } } if (show_universal && uvars()) { const wcstring_list_t uni_list = uvars()->get_names(show_exported, show_unexported); names.insert(uni_list.begin(), uni_list.end()); } result.insert(result.end(), names.begin(), names.end()); return result; }
static std::map<wcstring, env_var_t> snapshot_vars(const wcstring_list_t &vars) { std::map<wcstring, env_var_t> result; for (wcstring_list_t::const_iterator it = vars.begin(), end = vars.end(); it != end; ++it) { result.insert(std::make_pair(*it, env_get_string(*it))); } return result; }
/** Erase from a list of wcstring values at specified indexes */ static void erase_values(wcstring_list_t &list, const std::vector<long> &indexes) { // Make a set of indexes. // This both sorts them into ascending order and removes duplicates. const std::set<long> indexes_set(indexes.begin(), indexes.end()); // Now walk the set backwards, so we encounter larger indexes first, and remove elements at the given (1-based) indexes. std::set<long>::const_reverse_iterator iter; for (iter = indexes_set.rbegin(); iter != indexes_set.rend(); iter++) { long val = *iter; if (val > 0 && val <= list.size()) { // One-based indexing! list.erase(list.begin() + val - 1); } } }
/** Merge multiple completions with the same description to the same line */ static void join_completions( wcstring_list_t lst ) { std::map<wcstring, long> desc_table; for( size_t i=0; i<lst.size(); i++ ) { const wchar_t *item = lst.at(i).c_str(); const wchar_t *desc = wcschr( item, COMPLETE_SEP ); long prev_idx; if( !desc ) continue; desc++; prev_idx = desc_table[desc] - 1; if( prev_idx == -1 ) { desc_table[desc] = (long)(i+1); } else { const wchar_t *old = lst.at(i).c_str(); const wchar_t *old_end = wcschr( old, COMPLETE_SEP ); if( old_end ) { wcstring foo; foo.append(old, old_end - old); foo.push_back(COMPLETE_ITEM_SEP); foo.append(item); lst.at(prev_idx) = foo; lst.at(i).clear(); } } } /* Remove empty strings */ lst.erase(remove(lst.begin(), lst.end(), wcstring()), lst.end()); }
/// Manipulate history of interactive commands executed by the user. int builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **argv) { wchar_t *cmd = argv[0]; int argc = builtin_count_args(argv); history_cmd_opts_t opts; int optind; int retval = parse_cmd_opts(opts, &optind, argc, argv, parser, streams); if (retval != STATUS_CMD_OK) return retval; if (opts.print_help) { builtin_print_help(parser, streams, cmd, streams.out); return STATUS_CMD_OK; } // Use the default history if we have none (which happens if invoked non-interactively, e.g. // from webconfig.py. history_t *history = reader_get_history(); if (!history) history = &history_t::history_with_name(L"fish"); // If a history command hasn't already been specified via a flag check the first word. // Note that this can be simplified after we eliminate allowing subcommands as flags. // See the TODO above regarding the `long_options` array. if (optind < argc) { hist_cmd_t subcmd = str_to_enum(argv[optind], hist_enum_map, hist_enum_map_len); if (subcmd != HIST_UNDEF) { if (!set_hist_cmd(cmd, &opts.hist_cmd, subcmd, streams)) { return STATUS_INVALID_ARGS; } optind++; } } // Every argument that we haven't consumed already is an argument for a subcommand (e.g., a // search term). const wcstring_list_t args(argv + optind, argv + argc); // Establish appropriate defaults. if (opts.hist_cmd == HIST_UNDEF) opts.hist_cmd = HIST_SEARCH; if (!opts.history_search_type_defined) { if (opts.hist_cmd == HIST_SEARCH) opts.search_type = HISTORY_SEARCH_TYPE_CONTAINS; if (opts.hist_cmd == HIST_DELETE) opts.search_type = HISTORY_SEARCH_TYPE_EXACT; } int status = STATUS_CMD_OK; switch (opts.hist_cmd) { case HIST_SEARCH: { if (!history->search(opts.search_type, args, opts.show_time_format, opts.max_items, opts.case_sensitive, opts.null_terminate, streams)) { status = STATUS_CMD_ERROR; } break; } case HIST_DELETE: { // TODO: Move this code to the history module and support the other search types // including case-insensitive matches. At this time we expect the non-exact deletions to // be handled only by the history function's interactive delete feature. if (opts.search_type != HISTORY_SEARCH_TYPE_EXACT) { streams.err.append_format(_(L"builtin history delete only supports --exact\n")); status = STATUS_INVALID_ARGS; break; } if (!opts.case_sensitive) { streams.err.append_format( _(L"builtin history delete only supports --case-sensitive\n")); status = STATUS_INVALID_ARGS; break; } for (wcstring_list_t::const_iterator iter = args.begin(); iter != args.end(); ++iter) { wcstring delete_string = *iter; if (delete_string[0] == '"' && delete_string[delete_string.length() - 1] == '"') { delete_string = delete_string.substr(1, delete_string.length() - 2); } history->remove(delete_string); } break; } case HIST_CLEAR: { CHECK_FOR_UNEXPECTED_HIST_ARGS(opts.hist_cmd) history->clear(); history->save(); break; } case HIST_MERGE: { CHECK_FOR_UNEXPECTED_HIST_ARGS(opts.hist_cmd) history->incorporate_external_changes(); break; } case HIST_SAVE: { CHECK_FOR_UNEXPECTED_HIST_ARGS(opts.hist_cmd) history->save(); break; } case HIST_UNDEF: { DIE("Unexpected HIST_UNDEF seen"); break; } } return status; }
bool list_contains_string(const wcstring_list_t &list, const wcstring &str) { return std::find(list.begin(), list.end(), str) != list.end(); }
/// Define a function. Calls into `function.cpp` to perform the heavy lifting of defining a /// function. int builtin_function(parser_t &parser, io_streams_t &streams, const wcstring_list_t &c_args, const wcstring &contents, int definition_line_offset) { // The wgetopt function expects 'function' as the first argument. Make a new wcstring_list with // that property. This is needed because this builtin has a different signature than the other // builtins. wcstring_list_t args = {L"function"}; args.insert(args.end(), c_args.begin(), c_args.end()); // Hackish const_cast matches the one in builtin_run. const null_terminated_array_t<wchar_t> argv_array(args); wchar_t **argv = const_cast<wchar_t **>(argv_array.get()); wchar_t *cmd = argv[0]; int argc = builtin_count_args(argv); // A valid function name has to be the first argument. wcstring function_name; int retval = validate_function_name(argc, argv, function_name, cmd, streams); if (retval != STATUS_CMD_OK) return retval; argv++; argc--; function_cmd_opts_t opts; int optind; retval = parse_cmd_opts(opts, &optind, argc, argv, parser, streams); if (retval != STATUS_CMD_OK) return retval; if (opts.print_help) { builtin_print_help(parser, streams, cmd, streams.err); return STATUS_CMD_OK; } if (argc != optind) { if (opts.named_arguments.size()) { for (int i = optind; i < argc; i++) { opts.named_arguments.push_back(argv[i]); } } else { streams.err.append_format(_(L"%ls: Unexpected positional argument '%ls'"), cmd, argv[optind]); return STATUS_INVALID_ARGS; } } // We have what we need to actually define the function. function_data_t d; d.name = function_name; if (!opts.description.empty()) d.description = opts.description; // d.description = opts.description; d.events.swap(opts.events); d.shadow_scope = opts.shadow_scope; d.named_arguments.swap(opts.named_arguments); d.inherit_vars.swap(opts.inherit_vars); for (size_t i = 0; i < d.events.size(); i++) { event_t &e = d.events.at(i); e.function_name = d.name; } d.definition = contents.c_str(); function_add(d, parser, definition_line_offset); // Handle wrap targets by creating the appropriate completions. for (size_t w = 0; w < opts.wrap_targets.size(); w++) { complete_add_wrapper(function_name, opts.wrap_targets.at(w)); } return STATUS_CMD_OK; }
/// Define a function. Calls into `function.cpp` to perform the heavy lifting of defining a /// function. int builtin_function(parser_t &parser, io_streams_t &streams, const wcstring_list_t &c_args, const parsed_source_ref_t &source, tnode_t<grammar::job_list> body) { assert(source && "Missing source in builtin_function"); // The wgetopt function expects 'function' as the first argument. Make a new wcstring_list with // that property. This is needed because this builtin has a different signature than the other // builtins. wcstring_list_t args = {L"function"}; args.insert(args.end(), c_args.begin(), c_args.end()); null_terminated_array_t<wchar_t> argv_array(args); wchar_t **argv = argv_array.get(); wchar_t *cmd = argv[0]; int argc = builtin_count_args(argv); // A valid function name has to be the first argument. wcstring function_name; int retval = validate_function_name(argc, argv, function_name, cmd, streams); if (retval != STATUS_CMD_OK) return retval; argv++; argc--; function_cmd_opts_t opts; int optind; retval = parse_cmd_opts(opts, &optind, argc, argv, parser, streams); if (retval != STATUS_CMD_OK) return retval; if (opts.print_help) { builtin_print_help(parser, streams, cmd, streams.err); return STATUS_CMD_OK; } if (argc != optind) { if (opts.named_arguments.size()) { for (int i = optind; i < argc; i++) { opts.named_arguments.push_back(argv[i]); } } else { streams.err.append_format(_(L"%ls: Unexpected positional argument '%ls'"), cmd, argv[optind]); return STATUS_INVALID_ARGS; } } // We have what we need to actually define the function. function_data_t d; d.name = function_name; if (!opts.description.empty()) d.description = opts.description; // d.description = opts.description; d.events.swap(opts.events); d.props.shadow_scope = opts.shadow_scope; d.props.named_arguments = std::move(opts.named_arguments); d.inherit_vars = std::move(opts.inherit_vars); for (size_t i = 0; i < d.events.size(); i++) { event_t &e = d.events.at(i); e.function_name = d.name; } d.props.parsed_source = source; d.props.body_node = body; function_add(std::move(d), parser); // Handle wrap targets by creating the appropriate completions. for (const wcstring &wt : opts.wrap_targets) complete_add_wrapper(function_name, wt); return STATUS_CMD_OK; }