Filenames with spaces; output beside the input file; warning fixes (from dev c08eb1bbfa4c)

- Filenames may contain spaces: quote on the command line; filename
  lists use a standalone "/" separator; unseparated names that do not
  exist are rejoined into names that do (announced); leading ~ expands.
- Without -o, output is written to the input file's directory; -o fully
  specifies the output directory and basename.
- "Word not parsed" warnings now appear without -v, only for text that
  survives removal, with correct line numbers.
- New tst/filename_test.sh regression suite.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-26 23:22:59 +02:00
parent d9c98ac86d
commit fd9a370af7
21 changed files with 430 additions and 34 deletions

View File

@@ -35,7 +35,11 @@ int main(int argc, char* argv[])
args.describe();
}
std::string input_text = args.as_string("s");
std::vector<std::string> input_filenames = args.as_vector("filenames");
// argv boundaries are authoritative (a shell-quoted "my file.kt" is
// one element); group_filename_tokens adds the standalone-"/" list
// form, the existence rescue for unquoted spaces, and ~ expansion.
std::vector<std::string> input_filenames =
group_filename_tokens(args.as_vector("filenames"));
if (input_text.empty() && input_filenames.empty()) {
throw Argument_error(
@@ -44,8 +48,8 @@ int main(int argc, char* argv[])
auto [target, output_dir, output_basename, output_filename,
write_files, display_only] =
parse_args(input_filenames, args.as_string("t"), args.as_string("o"),
args.as_bool("d"));
parse_args(input_filenames, args.as_string("t"),
expand_tilde(args.as_string("o")), args.as_bool("d"));
if (*(output_filename.end() - 1) == '*'
&& !display_only) {
@@ -61,7 +65,11 @@ int main(int argc, char* argv[])
M.m_state.set("K_output_dir", output_dir);
M.m_state.set("K_output_basename", output_basename);
M.m_state.set("K_stdout_only", display_only ? "true" : "false");
M.m_state.set("K_input_filenames", join(input_filenames, " "));
// The list form uses the standalone-"/" separator (filenames may
// contain spaces); K_input_filename is the single root input file.
M.m_state.set("K_input_filenames", join(input_filenames, " / "));
M.m_state.set("K_input_filename",
input_filenames.empty() ? "" : input_filenames[0]);
M.m_state.set("K_verbose_level", std::to_string(verbose_level));
if (!input_filenames.empty()) {