wcstring parser_t::current_line() { if (execution_contexts.empty()) { return wcstring(); } const parse_execution_context_t *context = execution_contexts.back(); assert(context != NULL); int source_offset = context->get_current_source_offset(); if (source_offset < 0) { return wcstring(); } const int lineno = this->get_lineno(); const wchar_t *file = this->current_filename(); wcstring prefix; /* If we are not going to print a stack trace, at least print the line number and filename */ if (!get_is_interactive() || is_function()) { if (file) { append_format(prefix, _(L"%ls (line %d): "), user_presentable_path(file).c_str(), lineno); } else if (is_within_fish_initialization) { append_format(prefix, L"%ls: ", _(L"Startup"), lineno); } else { append_format(prefix, L"%ls: ", _(L"Standard input"), lineno); } } bool is_interactive = get_is_interactive(); bool skip_caret = is_interactive && ! is_function(); /* Use an error with empty text */ assert(source_offset >= 0); parse_error_t empty_error = {}; empty_error.source_start = source_offset; wcstring line_info = empty_error.describe_with_prefix(context->get_source(), prefix, is_interactive, skip_caret); if (! line_info.empty()) { line_info.push_back(L'\n'); } line_info.append(this->stack_trace()); return line_info; }
void parser_t::get_backtrace(const wcstring &src, const parse_error_list_t &errors, wcstring *output) const { assert(output != NULL); if (! errors.empty()) { const parse_error_t &err = errors.at(0); const bool is_interactive = get_is_interactive(); // Determine if we want to try to print a caret to point at the source error // The err.source_start <= src.size() check is due to the nasty way that slices work, // which is by rewriting the source (!) size_t which_line = 0; bool skip_caret = true; if (err.source_start != SOURCE_LOCATION_UNKNOWN && err.source_start <= src.size()) { // Determine which line we're on which_line = 1 + std::count(src.begin(), src.begin() + err.source_start, L'\n'); // Don't include the caret if we're interactive, this is the first line of text, and our source is at its beginning, because then it's obvious skip_caret = (is_interactive && which_line == 1 && err.source_start == 0); } wcstring prefix; const wchar_t *filename = this->current_filename(); if (filename) { if (which_line > 0) { prefix = format_string(_(L"%ls (line %lu): "), user_presentable_path(filename).c_str(), which_line); } else { prefix = format_string(_(L"%ls: "), user_presentable_path(filename).c_str()); } } else { prefix = L"fish: "; } const wcstring description = err.describe_with_prefix(src, prefix, is_interactive, skip_caret); if (! description.empty()) { output->append(description); output->push_back(L'\n'); } output->append(this->stack_trace()); } }
/** Properly sets all locale information */ static void handle_locale() { const env_var_t lc_all = env_get_string(L"LC_ALL"); const wcstring old_locale = wsetlocale(LC_MESSAGES, NULL); /* Array of locale constants corresponding to the local variable names defined in locale_variable */ static const int cat[] = { 0, LC_ALL, LC_COLLATE, LC_CTYPE, LC_MESSAGES, LC_MONETARY, LC_NUMERIC, LC_TIME } ; if (!lc_all.missing()) { wsetlocale(LC_ALL, lc_all.c_str()); } else { const env_var_t lang = env_get_string(L"LANG"); if (!lang.missing()) { wsetlocale(LC_ALL, lang.c_str()); } for (int i=2; locale_variable[i]; i++) { const env_var_t val = env_get_string(locale_variable[i]); if (!val.missing()) { wsetlocale(cat[i], val.c_str()); } } } const wcstring new_locale = wsetlocale(LC_MESSAGES, NULL); if (old_locale != new_locale) { /* Try to make change known to gettext. Both changing _nl_msg_cat_cntr and calling dcgettext might potentially tell some gettext implementation that the translation strings should be reloaded. We do both and hope for the best. */ extern int _nl_msg_cat_cntr; _nl_msg_cat_cntr++; fish_dcgettext("fish", "Changing language to English", LC_MESSAGES); if (get_is_interactive()) { debug(2, _(L"Changing language to English")); } } }