/** Returns a description for the specified function */ static const wchar_t *complete_function_desc( const wchar_t *fn ) { const wchar_t *res = function_get_desc( fn ); if( !res ) res = function_get_definition( fn ); return res; }
static int report_function_metadata(const wchar_t *funcname, bool verbose, io_streams_t &streams, bool metadata_as_comments) { const wchar_t *path = L"n/a"; const wchar_t *autoloaded = L"n/a"; const wchar_t *shadows_scope = L"n/a"; wcstring description = L"n/a"; int line_number = 0; if (function_exists(funcname)) { auto props = function_get_properties(funcname); path = function_get_definition_file(funcname); if (path) { autoloaded = function_is_autoloaded(funcname) ? L"autoloaded" : L"not-autoloaded"; line_number = function_get_definition_lineno(funcname); } else { path = L"stdin"; } shadows_scope = props->shadow_scope ? L"scope-shadowing" : L"no-scope-shadowing"; function_get_desc(funcname, description); description = escape_string(description, ESCAPE_NO_QUOTED); } if (metadata_as_comments) { if (std::wcscmp(path, L"stdin")) { streams.out.append_format(L"# Defined in %ls @ line %d\n", path, line_number); } } else { streams.out.append_format(L"%ls\n", path); if (verbose) { streams.out.append_format(L"%ls\n", autoloaded); streams.out.append_format(L"%d\n", line_number); streams.out.append_format(L"%ls\n", shadows_scope); streams.out.append_format(L"%ls\n", description.c_str()); } } return STATUS_CMD_OK; }
/// Return a definition of the specified function. Used by the functions builtin. static wcstring functions_def(const wcstring &name) { CHECK(!name.empty(), L""); //!OCLINT(multiple unary operator) wcstring out; wcstring desc, def; function_get_desc(name, desc); function_get_definition(name, def); std::vector<std::shared_ptr<event_handler_t>> ev = event_get_function_handlers(name); out.append(L"function "); // Typically we prefer to specify the function name first, e.g. "function foo --description bar" // But If the function name starts with a -, we'll need to output it after all the options. bool defer_function_name = (name.at(0) == L'-'); if (!defer_function_name) { out.append(escape_string(name, true)); } if (!desc.empty()) { wcstring esc_desc = escape_string(desc, true); out.append(L" --description "); out.append(esc_desc); } auto props = function_get_properties(name); assert(props && "Should have function properties"); if (!props->shadow_scope) { out.append(L" --no-scope-shadowing"); } for (const auto &next : ev) { const event_description_t &d = next->desc; switch (d.type) { case event_type_t::signal: { append_format(out, L" --on-signal %ls", sig2wcs(d.param1.signal)); break; } case event_type_t::variable: { append_format(out, L" --on-variable %ls", d.str_param1.c_str()); break; } case event_type_t::exit: { if (d.param1.pid > 0) append_format(out, L" --on-process-exit %d", d.param1.pid); else append_format(out, L" --on-job-exit %d", -d.param1.pid); break; } case event_type_t::job_exit: { const job_t *j = job_t::from_job_id(d.param1.job_id); if (j) append_format(out, L" --on-job-exit %d", j->pgid); break; } case event_type_t::generic: { append_format(out, L" --on-event %ls", d.str_param1.c_str()); break; } case event_type_t::any: default: { DIE("unexpected next->type"); break; } } } const wcstring_list_t &named = props->named_arguments; if (!named.empty()) { append_format(out, L" --argument"); for (const auto &name : named) { append_format(out, L" %ls", name.c_str()); } } // Output the function name if we deferred it. if (defer_function_name) { out.append(L" -- "); out.append(escape_string(name, true)); } // Output any inherited variables as `set -l` lines. std::map<wcstring, env_var_t> inherit_vars = function_get_inherit_vars(name); for (const auto &kv : inherit_vars) { wcstring_list_t lst; kv.second.to_list(lst); // This forced tab is crummy, but we don't know what indentation style the function uses. append_format(out, L"\n\tset -l %ls", kv.first.c_str()); for (const auto &arg : lst) { wcstring earg = escape_string(arg, ESCAPE_ALL); out.push_back(L' '); out.append(earg); } } // This forced tab is sort of crummy - not all functions start with a tab. append_format(out, L"\n\t%ls", def.c_str()); // Append a newline before the 'end', unless there already is one there. if (!string_suffixes_string(L"\n", def)) { out.push_back(L'\n'); } out.append(L"end\n"); return out; }