Fixed Additional language for [code=...]

CMTV

Well-known member
Affected version
2.0
I tried to follow an algorithm of adding custom language for [code] bbcode proposed by @Chris D .

It is not working.

I tried to figure what is going wrong and here is what I found. I will use Scala language here as an example.

The proposed method is working fine if we set "scala" directly in data-lang="{{$language ?: ''}}" attribute in bb_code_tag_code template.
So this code will properly color all scala code blocks:
HTML:
<pre class="bbCodeCode" dir="ltr" data-xf-init="code-block" data-lang="scala"><code>{$content}</code></pre>

This means there is a problem with $language parameter (in fact, it is empty) that gets passed in bb_code_tag_code template.

The problem appear at renderTagCode(...) function in XF\BbCode\Renderer\Html.php:
PHP:
public function renderTagCode(array $children, $option, array $tag, array $options)
{
    $content = $this->renderSubTree($children, $options);
    // a bit like ltrim, but only remove blank lines, not leading tabs on the first line
    $content = preg_replace('#^([ \t]*\r?\n)+#', '', $content);
    $content = rtrim($content);

    /** @var \XF\Data\CodeLanguage $codeLanguages */
    $codeLanguages = \XF::app()->data('XF:CodeLanguage');
    $allowedLanguages = $codeLanguages->getSupportedLanguages(true);

    ///////////////////////////////////////////////////
    // HERE WE DO HAVE "scala" IN $language variable
    ///////////////////////////////////////////////////

    $language = strtolower(preg_replace('#[^a-z0-9_-]#i', '-', $option));
    if (isset($allowedLanguages[$language]))
    {
        $config = $allowedLanguages[$language];
    }
    else
    {
        /////////////////////////////////////////////////
        // HERE $language FOR "scala" is set to ''
        /////////////////////////////////////////////////

        $config = [];
        $language = '';
    }

    if (!is_array($this->allowedCodeLanguages))
    {
        $this->allowedCodeLanguages = preg_split('/\r?\n/', \XF::options()->allowedCodeLanguages);
    }

    if (!in_array($language, $this->allowedCodeLanguages))
    {
        $language = '';
    }

    return $this->getRenderedCode($content, $language, $config);
}

So the problem is within the XF\Data\CodeLanguage.php file. All available languages are simply hardcoded there...
PHP:
$languages = [
            'apacheconf' => [],
            'bash' => [
                'modes' => 'shell'
            ],
            'c' => [
                'modes' => 'clike',
                'mime' => 'text/x-csrc'
            ],
            'clike' => [
                'modes' => 'clike',
                'mime' => 'text/x-csrc'
            ],
/* ... */

At the end of this file there is an interesting if:
PHP:
if ($filterDisabled)
{
    $enabledLanguages = preg_split('/\r?\n/', \XF::options()->allowedCodeLanguages);
    $languages = array_intersect_key($languages, array_flip($enabledLanguages));
}

return $languages;

Conclusion
Custom languages (like 'scala') are not working because they can not pass through array_intersect_key function. They do not pass through because $filterDisabled is set to true when calling getSupportedLanguages(true) in Html.php. Setting it to false will not work because in that case getSupportedLanguages(false) will simply return hardcoded languages.

So this needs to be fixed I think.
 
You're absolutely right. This was somewhat short sighted so some changes have been made here.

The primary focus of the hard coded stuff at the top, is the configuration for the CodeMirror code editor, but it unintentionally ended up being only restricted to that list.

As the CodeMirror configuration is more complicated, we've added a new "code_languages" code event, so if an add-on developer does wish to add support for a language within Code Mirror (or modify existing ones) then that's how to do it.

The end result of this change is that languages added to the option will appear in the code editor list (you will need to add a phrase so that is named correctly) and they will display highlighted in the post (as long as the appropriate Prism language JS has been added) but the code editor itself will be in plain text (unless the advanced configuration is added via a code event).

So, that should make this one fixed for the next release.
 
Top Bottom