13

Not sure if anyone has come across this. I'm using PrismJS syntax highlighter to highlight code. Application is written in Reactjs and what I'm trying to do is inside a WYSIWYG editor I'm wrapping user selected text with pre + code when user wants to insert code block. PrismJS seems to tokenize elements correctly as you would expect:

enter image description here

But as you can probably see from the image above, everything is put into a single line. Rather then nice code block:

enter image description here

I'm not sure what's wrong, using css from prismjs site:

code[class*="language-"],
pre[class*="language-"] {
    color: black;
    background: none;
    text-shadow: 0 1px white;
    font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
    text-align: left;
    white-space: pre;
    word-spacing: normal;
    word-break: normal;
    word-wrap: normal;
    line-height: 1.5;

    -moz-tab-size: 4;
    -o-tab-size: 4;
    tab-size: 4;

    -webkit-hyphens: none;
    -moz-hyphens: none;
    -ms-hyphens: none;
    hyphens: none;
}

pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
    text-shadow: none;
    background: #b3d4fc;
}

pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
    text-shadow: none;
    background: #b3d4fc;
}

@media print {
    code[class*="language-"],
    pre[class*="language-"] {
        text-shadow: none;
    }
}

/* Code blocks */
pre[class*="language-"] {
    padding: 1em;
    margin: .5em 0;
    overflow: auto;
}

:not(pre) > code[class*="language-"],
pre[class*="language-"] {
    background: #f5f2f0;
}

/* Inline code */
:not(pre) > code[class*="language-"] {
    padding: .1em;
    border-radius: .3em;
    white-space: normal;
}

.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
    color: slategray;
}

.token.punctuation {
    color: #999;
}

.namespace {
    opacity: .7;
}

.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
    color: #905;
}

.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
    color: #690;
}

.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
    color: #9a6e3a;
    background: hsla(0, 0%, 100%, .5);
}

.token.atrule,
.token.attr-value,
.token.keyword {
    color: #07a;
}

.token.function,
.token.class-name {
    color: #dd4a68;
}

.token.regex,
.token.important,
.token.variable {
    color: #e90;
}

.token.important,
.token.bold {
    font-weight: bold;
}
.token.italic {
    font-style: italic;
}

.token.entity {
    cursor: help;
}

Here is outputted html: enter image description here

EDIT:

If adding word-wrap: pre-wrap this is the outcome: enter image description here

TSlegaitis
  • 1,231
  • 15
  • 29

6 Answers6

8

I had a similar issue when initializing the element manually. I stumbled upon this discussion, which had a fix that worked for me: https://github.com/PrismJS/prism/issues/1764

HTML - Load script with flag data-manual:

<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/prism.min.js" data-manual></script>

JS - Add the following hook:

Prism.hooks.add("before-highlight", function (env) {
    env.code = env.element.innerText;
});
Prism.highlightElement(code);

Working example: https://codepen.io/Ukmasmu/pen/xxZLwxG?editors=1010

Sever van Snugg
  • 571
  • 4
  • 12
6

Try to update the CSS file with:

white-space: pre-wrap

https://github.com/PrismJS/prism/issues/1237

mrkosima
  • 406
  • 5
  • 9
1

In case this is helpful for anyone else, I have a textarea that updates a code block as you type, and this worked for me:

<textarea onkeyup="this.onchange();" onchange="document.getElementById('query-highlighted').textContent = this.value; Prism.highlightAll();"></textarea>
<pre><code class="language-sql" id="query-highlighted"></code></pre>

Namely, I used .textContent = instead of .innerText = (the latter didn't preserve the line breaks as expected).

I was aided by Sever van Snugg's answer and the issue he linked.

MuffinTheMan
  • 1,509
  • 20
  • 25
1

1. Activate normalize whitespace plugin

I suggest you activate normalize whitespace plugin and set the break-lines property instead of manipulating prism.css file to using white-space: pre-wrap like this:

Prism.plugins.NormalizeWhitespace.setDefaults({
            'remove-trailing': true,
            'remove-indent': true,
            'left-trim': true,
            'right-trim': true,
            'break-lines': 60, //max number of characters in each line before break
});

I'm using the above approach in my blog, and it works like a charm. You can adjust the break-lines value according to your preferences of course.

2. Insert a line break tag <br> to break a line at will

Now that you set the break-line property after a certain maximum number of characters, you probably want to break some lines at will for cleaner code. To do so you need to insert a <br> tag where you want to have a break line.

NOTE: if you're using an html parser to parse dynamic content with prism

If you're using a parser to parse you dynamically generated html code as a string (from a database for example) and prims is not parsing your <br> tags you'll have to use before-sanity-check prism hook like this:

Prism.hooks.add('before-sanity-check', function (env) {
  env.element.innerHTML = env.element.innerHTML.replace(/<br>/g, '\n');
  env.code = env.element.textContent;
});

before highlighting, what the above code does is replacing <br> tags with \n since prism can't parse <br> as a line break.

0

Similar to the answer by Sever van Snugg, I use the following solution where the forEach loop highlights all the code nodes according to the style rules of the Prism CSS stylesheet used (because I have several code tags on a single page). I locate these scripts in the bottom of my HTML body:

<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.27.0/prism.min.js" data-manual></script>

<script>
    Prism.hooks.add("before-highlight", function (env) {
        env.code = env.element.innerText;
    });

    code = document.getElementsByTagName('code');
    Array.from(code).forEach(el => { Prism.highlightElement(el) });
</script>
0

I tried to mixed Markdown and Prismjs the trick is to replace '\n' with '\r\n' to keep breaklines.

    from bs4 import BeautifulSoup
    ...
    code_tag = soup.new_tag('code class="lang-%s"' % lang)
    code_tag.string = code.string.replace('\n','\r\n')
    code.replaceWith(code_tag)