diff --git a/expand.cpp b/expand.cpp index 10e3cbf40..f743f8ab6 100644 --- a/expand.cpp +++ b/expand.cpp @@ -1602,6 +1602,31 @@ static void unexpand_tildes(const wcstring &input, std::vector *co } } +// If the given path contains the user's home directory, replace that with a tilde +// We don't try to be smart about case insensitivity, etc. +wcstring replace_home_directory_with_tilde(const wcstring &str) +{ + // only absolute paths get this treatment + wcstring result = str; + if (string_prefixes_string(L"/", result)) + { + wcstring home_directory = L"~"; + expand_tilde(home_directory); + if (! string_suffixes_string(L"/", home_directory)) + { + home_directory.push_back(L'/'); + } + + // Now check if the home_directory prefixes the string + if (string_prefixes_string(home_directory, result)) + { + // Success + result.replace(0, home_directory.size(), L"~/"); + } + } + return result; +} + /** Remove any internal separators. Also optionally convert wildcard characters to regular equivalents. This is done to support EXPAND_SKIP_WILDCARDS. diff --git a/expand.h b/expand.h index 4893d2b92..803513c2a 100644 --- a/expand.h +++ b/expand.h @@ -176,6 +176,9 @@ wcstring expand_escape_variable(const wcstring &in); */ void expand_tilde(wcstring &input); +/** Perform the opposite of tilde expansion on the string, which is modified in place */ +wcstring replace_home_directory_with_tilde(const wcstring &str); + /** Test if the specified argument is clean, i.e. it does not contain any tokens which need to be expanded or otherwise altered. Clean diff --git a/parser.cpp b/parser.cpp index abfb88160..ee6948a85 100644 --- a/parser.cpp +++ b/parser.cpp @@ -312,6 +312,13 @@ static const struct block_lookup_entry block_lookup[]= static bool job_should_skip_elseif(const job_t *job, const block_t *current_block); +// Given a file path, return something nicer. Currently we just "unexpand" tildes. +static wcstring user_presentable_path(const wcstring &path) +{ + return replace_home_directory_with_tilde(path); +} + + parser_t::parser_t(enum parser_type_t type, bool errors) : parser_type(type), show_errors(errors), @@ -324,7 +331,6 @@ parser_t::parser_t(enum parser_type_t type, bool errors) : current_block(NULL), block_io(shared_ptr()) { - } /* A pointer to the principal parser (which is a static local) */ @@ -363,7 +369,7 @@ void parser_t::push_block(block_t *newv) const enum block_type_t type = newv->type(); newv->src_lineno = parser_t::get_lineno(); newv->src_filename = parser_t::current_filename()?intern(parser_t::current_filename()):0; - + newv->outer = current_block; if (current_block && current_block->skip) newv->mark_as_fake(); @@ -844,13 +850,13 @@ void parser_t::stack_trace(block_t *b, wcstring &buff) const { const source_block_t *sb = static_cast(b); const wchar_t *source_dest = sb->source_file; - append_format(buff, _(L"from sourcing file '%ls',\n"), source_dest); + append_format(buff, _(L"from sourcing file %ls\n"), user_presentable_path(source_dest).c_str()); break; } case FUNCTION_CALL: { const function_block_t *fb = static_cast(b); - append_format(buff, _(L"in function '%ls',\n"), fb->name.c_str()); + append_format(buff, _(L"in function '%ls'\n"), fb->name.c_str()); break; } case SUBST: @@ -868,14 +874,14 @@ void parser_t::stack_trace(block_t *b, wcstring &buff) const if (file) { append_format(buff, - _(L"\tcalled on line %d of file '%ls',\n"), + _(L"\tcalled on line %d of file %ls\n"), b->src_lineno, - file); + user_presentable_path(file).c_str()); } else { append_format(buff, - _(L"\tcalled on standard input,\n")); + _(L"\tcalled on standard input\n")); } if (b->type() == FUNCTION_CALL) @@ -2611,6 +2617,7 @@ int parser_t::eval(const wcstring &cmd_str, const io_chain_t &io, enum block_typ tokenizer_t local_tokenizer(cmd, 0); scoped_push tokenizer_push(¤t_tokenizer, &local_tokenizer); + scoped_push tokenizer_pos_push(¤t_tokenizer_pos, 0); error_code = 0; @@ -2897,31 +2904,12 @@ struct block_info_t block_type_t type; //type of the block }; -/* Append a syntax error to the given error list */ -static bool append_syntax_error(parse_error_list_t *errors, const parse_node_t &node, const wchar_t *fmt, ...) -{ - parse_error_t error; - error.source_start = node.source_start; - error.source_length = node.source_length; - error.code = parse_error_syntax; - - va_list va; - va_start(va, fmt); - error.text = vformat_string(fmt, va); - va_end(va); - - errors->push_back(error); - return true; -} - 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); - output->append(err.describe(src)); - output->push_back(L'\n'); // Determine which line we're on assert(err.source_start <= src.size()); @@ -2930,13 +2918,16 @@ void parser_t::get_backtrace(const wcstring &src, const parse_error_list_t &erro const wchar_t *filename = this->current_filename(); if (filename) { - append_format(*output, _(L"line %lu of '%ls'\n"), which_line, filename); + append_format(*output, _(L"fish: line %lu of %ls:\n"), which_line, user_presentable_path(filename).c_str()); } else { - append_format(*output, L"%ls: ", _(L"Standard input"), which_line); + append_format(*output, L"fish: %ls:", _(L"Error:")); } + output->append(err.describe(src)); + output->push_back(L'\n'); + this->stack_trace(current_block, *output); } }