mawww / kakoune

mawww's experiment for a better code editor
http://kakoune.org
The Unlicense
9.7k stars 705 forks source link

Fix inconsistent argument parsing #5189

Open PJungkamp opened 2 weeks ago

PJungkamp commented 2 weeks ago

Problem

There is no consistent way to open an arbitrary filename using the kak commandline.

Bad edgecases are:

  1. files named --help
  2. files that start with a -
  3. files that start with a +

Current Behaviour

  1. You can't open a file named --help from the command line.
  2. Filenames including an - can be opened by adding a -- parameter to separate them from options.
  3. Filenames starting with a + can be opened by adding a +0 to the end of the commandline. Only the last occurrence of a + prefixed parameter is used for positioning within the buffer.

This means that kak -- test0 +test1 -test2 +0 will open buffers for test0, +test1 and -test2 this works around 2 and 3. But kak -- --help +0 still shows the usage string.

To fix problem 1 you'd currently have to generate an argument to the -e switch that includes edit -- "some file" for each file you want to open. The generated kakoune script in turn would of course need to have the filenames escaped for kakoune...

Expected Behaviour

I want to be able to guarantee that kak -- <FILE> opens a file named <FILE> and does nothing else with the argument.

What did I do?

  1. I removed the --help special case. There's no nice way to make it work.
  2. I extended the ParametersParser to accept a +<line>:<column> switch according to it's current behaviour on the command line, except that it does respect the --.
  3. I replaced the +<line>:<col> special handling in main.cc with the new ParametersParser switch.

Other Sideeffects

The parsing of + and +: is currently not doing what is documented. It's implementation currently uses a gj instead of a ge command. This behaviour is fixed in the new implementation.

Consideration

PJungkamp commented 1 day ago

Searching for -- in the arguments introduces a subtle difference in behavior to the ParametersParser handling of --.

Doing a simple find(params, "--") search aborts at any --. The ParametersParser only respects the -- if it expects a switch.

Here's an example implementation:

auto dd = find(params, `--`);
auto parser = ParametersParser{Range{params.begin(), dd}, param_desc};
if (dd != params.end())
     ++dd;

auto position = find_if(parser, [](auto &p){ return p.starts_with("+"); });
std::optional<BufferCoord> init_coord = std::nullopt;
Vector<StringView> positonals{parser.begin(), position};
if (position != parser.end())
{
    positionals.insert(positionals.end(), position + 1, parser.end());
    // parse position
    init_coord = ...;
}
positionals.insert(positionals.end(), dd, params.end());

kak -s -- file would now throw an error because it's missing the session name between -s and --. It's now impossible to have -- as an argument to any command line switch. Passing a -- to -s is currently possible.

I find this significantly more complex than the WithCoord implementation while it's also more restrictive. I'd rather replace the ParametersParser entirely and do custom commandline handling to cover all edgecases properly, e.g. by introducing a CmdlineParametersParser.

@mawww Would you still prefer using something like my pseudo code above?