pandoc icon indicating copy to clipboard operation
pandoc copied to clipboard

Priblem with passing multuple options of the same type

Open om-arino opened this issue 3 years ago • 2 comments

Hello, i like the wrapper a lot, but I've stumbled on an issue, which is crucial for my implementation, and it looks like a bug. When I pass multiple options of the same type, which are supported by pandoc ( you can pass multiple --metadata or --variable options), the wrapper passes on only the first one ... for example in

echo (new \Pandoc\Pandoc) ->from('markdown_mmd') ->inputFile(mmd_file($id)) ->option('standalone') ->option('self-contained') ->option('template',$okvir) ->option('css',$css) ->option('metadata-file', $yaml_file) ->option('metadata','x=y') ->option('metadata', 'n_izv_text='.$nizi['original']) ->to('html5') ->log($log_file) ->run(); I can access variable x in the template, but the n_izv_text or any other metadata does not get passed to template? Any ideas on why is that? Thank you in advance, Regards, Om

om-arino avatar Jun 30 '21 10:06 om-arino

Hi, to solve this issue I have this proposal:

edit pandoc->option:

    public function option($name, $value = false)
    {
        if(key_exists($name, $this->options)){
            if(is_array($value)){
                $this->options[$name] = array_merge($this->options[$name], $value);
            }else{
                array_push($this->options[$name], $value);
            }
        }else{
            $this->options[$name] = is_array($value) ? $value : [$value];
        }
        return $this;
    }

and pandoc->execute:


    public function execute(array $parameters = [])
    {
        $parameters = array_merge([
            $this->config['command'],
        ], $parameters);
        //new code start here
        if (!empty($this->options)) {
            foreach ($this->options as $name => $value) {
                foreach ($value as  $sub_value) {
                    if($sub_value !== false){
                        array_push($parameters, "--{$name}", $sub_value);
                    }else{
                        array_push($parameters, "--{$name}");
                    }
                }
            }
        }
        //new code ends here
        $process = new Process($parameters);

        if ($this->cwd) {
            $process->setWorkingDirectory($this->cwd);
        }

        if ($this->input) {
            $process->setInput($this->input);
        }

        $process->run();

        if (!$process->isSuccessful()) {
            $output = $process->getErrorOutput();

            if (strpos($output, "pandoc: {$this->inputFile}: openBinaryFile: does not exist") !== false) {
                throw new InputFileNotFound;
            }

            if (strpos($output, "pandoc: {$this->log}: openBinaryFile: does not exist") !== false) {
                throw new LogFileNotWriteable;
            }

            if (strpos($output, 'Unknown input format') !== false) {
                throw new UnknownInputFormat;
            }

            if (strpos($output, 'Unknown output format') !== false) {
                throw new UnknownOutputFormat;
            }

            if (strpos($output, 'not found') !== false) {
                throw new PandocNotFound;
            }

            throw new ProcessFailedException($process);
        }

        $output = $process->getOutput();

        if ($output === '') {
            return true;
        }

        return $output;
    }

And for the usage:

//preferred way:
 (new \Pandoc\Pandoc)
     ->option('metadata',   'x=y')
      ->option('metadata',  'a=b')

//optional way:
 (new \Pandoc\Pandoc)->option('metadata', [
    'x=y',
    'a=b'
])

dregini avatar Nov 12 '21 16:11 dregini

To make it more compatible with previous implementation another option could be this:

public function option($name, $value = false, $override = true)
{
    if($override){
        $this->options[$name] = [];
    }
    if(key_exists($name, $this->options)){
        if(is_array($value)){
            $this->options[$name] = array_merge($this->options[$name], $value);
        }else{
            array_push($this->options[$name], $value);
        }
    }else{
        $this->options[$name] = is_array($value) ? $value : [$value];
    }
    return $this;
}

$override is set to true by default to keep compatiblility to previous version. Because if a user was setting 2 times toc-depth (for example) the second one was kept and the first ignored.

so usage would be:

//preferred way:
 (new \Pandoc\Pandoc)
     ->option('metadata',   'x=y', true)
     ->option('metadata',  'a=b', true)
     ->option('toc-depth', 2) //ignored
     ->option('toc-depth', 4)

//optional way:
 (new \Pandoc\Pandoc)->option('metadata', [
    'x=y',
    'a=b'
], true)
     ->option('toc-depth', 2) //ignored
     ->option('toc-depth', 4)

Note: I don't know if is a non issue and pandoc himself understand to override previous value. I'm pretty new to pandoc.

dregini avatar Nov 12 '21 16:11 dregini