kadet1090 / KeyLighter

Yet another syntax highlighter for PHP
https://keylighter.kadet.net
MIT License
32 stars 2 forks source link

Is it possible to specify which sort of language features get wrapped inside a span etc.? #3

Closed vdemsky closed 8 years ago

vdemsky commented 8 years ago

I apologize if the title is not clear as I wasn't sure what to call this. Essentially, if I run this on PHP code such as:

<?php

namespace MyNamespace;

The output would be:

<span class="language php"><span class="delimiter">&lt;?php</span>

<span class="keyword">namespace</span> MyNamespace<span class="operator punctuation">;</span>

In the above output, the word MyNamespace is not wrapped inside of a span or any other element. Is there a configurable option to wrap everything in a span or some other element or is there a place I could modify to do this. For my implementation, I would like to have every single word etc. wrapped in an element.

Thanks.

kadet1090 commented 8 years ago

It's not possible with option change, but that's why you can always write custom formatter. I don't exactly understand what behavior you want, wrap every single word with span, if it's not a part of token?

Formatter like that:

use Kadet\Highlighter\Formatter\FormatterInterface;

class MyHtmlFormatter implements FormatterInterface
{
    public function format(Tokens $tokens)
    {
        $source = $tokens->getSource();

        $result = '';
        $last   = 0;
        $level  = 0;

        /** @var Token $token */
        foreach ($tokens as $token) {
            $content = htmlspecialchars(substr($source, $last, $token->pos - $last));
            $result .= $level === 1 ? implode('', array_map(function($part) {
                return empty(trim($part)) ? $part : "<span>$part</span>";
            }, preg_split('/(\s+)/', $content, -1, PREG_SPLIT_DELIM_CAPTURE))) : $content;

            if ($token->isStart()) {
                $level++;
                $result .= '<span class="' . str_replace('.', ' ', $token->name) . '">';
            } else {
                $level--;
                $result .= '</span>';
            }

            $last = $token->pos;
        }
        $result .= substr($source, $last);

        return $result;
    }
}

should do the job, for your example file result is:

<span class="language php"><span class="delimiter">&lt;?php</span>

<span class="keyword">namespace</span> <span>MyNamespace</span><span class="operator punctuation">;</span></span>

You can use it in your code like that:

Highlighter\highlight(source, language, new MyHtmlFormatter());

But frankly, it just was not supposed to work like that. It could wrap any not matched string as some kind of "no token" token with relative ease (I'll consider implementation of that in library itself), but wrapping every non wrapped word seems like specific usecase to me.

vdemsky commented 8 years ago

Thank you for your help. For display in my application (which is web based), I was wanting to apply/interact with the various elements of the source. Consider the following:

<span class="keyword">namespace</span> MyNamespace<span class="operator punctuation">;</span>

If I wanted to animate the HTML output (for my UI) using CSS animations, I could create a selector for .keyword or .operator for example. In my UI, I'd also like to be able to use CSS selectors for something like MyNamespace. Since MyNamespace is not wrapped in an HTML element, it is more difficult to do that using CSS.

That is why I was wondering if it would be possible to wrap those sorts of things in a span (with a class) so I could still select those in CSS.

This is probably very specific to my app so no worries -- if you ever think it could be useful to more people, please feel free to work on it but I understand that it is very unique.

Thanks.