Skip to content

Commit

Permalink
Fix inline code and vertical bars in tables
Browse files Browse the repository at this point in the history
Fix inline code and code in tables

This removes support for empty inline code, and only trims inline code content
by one character on both sides, if both the initial and final character are a
space or a line feed.

Previously, inline code got preference over the table cell itself.
This was added due to GH-73 in GH-83 four years ago.

That behaviour does not match current GFM and lead to unexpected results in
GH-295, GH-320, and GH-396.

Related to GH-73.
Related to GH-83.
Closes GH-295.
Closes GH-320.
Closes GH-396.
Closes GH-420.

Reviewed-by: Merlijn Vos <merlijn@soverin.net>
  • Loading branch information
wooorm committed Jul 19, 2019
1 parent 475c72b commit 6282051
Show file tree
Hide file tree
Showing 43 changed files with 1,571 additions and 1,924 deletions.
115 changes: 58 additions & 57 deletions packages/remark-parse/lib/tokenize/code-inline.js
@@ -1,108 +1,109 @@
'use strict'

var locate = require('../locate/code-inline')
var whitespace = require('../util/is-markdown-whitespace-character')

module.exports = inlineCode
inlineCode.locator = locate

var graveAccent = '`'
var lineFeed = 10 // '\n'
var space = 32 // ' '
var graveAccent = 96 // '`'

function inlineCode(eat, value, silent) {
var length = value.length
var index = 0
var queue = ''
var tickQueue = ''
var contentQueue
var subqueue
var count
var openingCount
var subvalue
var character
var found
var openingFenceEnd
var closingFenceStart
var closingFenceEnd
var code
var next
var found

while (index < length) {
if (value.charAt(index) !== graveAccent) {
if (value.charCodeAt(index) !== graveAccent) {
break
}

queue += graveAccent
index++
}

if (!queue) {
if (index === 0 || index === length) {
return
}

subvalue = queue
openingCount = index
queue = ''
next = value.charAt(index)
count = 0
openingFenceEnd = index
next = value.charCodeAt(index)

while (index < length) {
character = next
next = value.charAt(index + 1)

if (character === graveAccent) {
count++
tickQueue += character
} else {
count = 0
queue += character
}
code = next
next = value.charCodeAt(index + 1)

if (code === graveAccent) {
if (closingFenceStart === undefined) {
closingFenceStart = index
}

closingFenceEnd = index + 1

if (count && next !== graveAccent) {
if (count === openingCount) {
subvalue += queue + tickQueue
if (
next !== graveAccent &&
closingFenceEnd - closingFenceStart === openingFenceEnd
) {
found = true
break
}

queue += tickQueue
tickQueue = ''
} else if (closingFenceStart !== undefined) {
closingFenceStart = undefined
closingFenceEnd = undefined
}

index++
}

if (!found) {
if (openingCount % 2 !== 0) {
return
}

queue = ''
return
}

/* istanbul ignore if - never used (yet) */
if (silent) {
return true
}

contentQueue = ''
subqueue = ''
length = queue.length
index = -1

while (++index < length) {
character = queue.charAt(index)
// Remove the initial and final space (or line feed), iff they exist and there
// are non-space characters in the content.
index = openingFenceEnd
length = closingFenceStart
code = value.charCodeAt(index)
next = value.charCodeAt(length - 1)
found = false

if (
length - index > 2 &&
(code === space || code === lineFeed) &&
(next === space || next === lineFeed)
) {
index++
length--

if (whitespace(character)) {
subqueue += character
continue
}
while (index < length) {
code = value.charCodeAt(index)

if (subqueue) {
if (contentQueue) {
contentQueue += subqueue
if (code !== space && code !== lineFeed) {
found = true
break
}

subqueue = ''
index++
}

contentQueue += character
if (found === true) {
openingFenceEnd++
closingFenceStart--
}
}

return eat(subvalue)({type: 'inlineCode', value: contentQueue})
return eat(value.slice(0, closingFenceEnd))({
type: 'inlineCode',
value: value.slice(openingFenceEnd, closingFenceStart)
})
}
27 changes: 0 additions & 27 deletions packages/remark-parse/lib/tokenize/table.js
Expand Up @@ -10,7 +10,6 @@ var space = ' '
var dash = '-'
var colon = ':'
var backslash = '\\'
var graveAccent = '`'
var verticalBar = '|'

var minColumns = 1
Expand All @@ -35,8 +34,6 @@ function table(eat, value, silent) {
var align
var cell
var preamble
var count
var opening
var now
var position
var lineCount
Expand Down Expand Up @@ -162,8 +159,6 @@ function table(eat, value, silent) {
queue = ''
cell = ''
preamble = true
count = null
opening = null

while (index < length) {
character = line.charAt(index)
Expand All @@ -183,12 +178,6 @@ function table(eat, value, silent) {
if (preamble) {
eat(character)
} else {
if (character && opening) {
queue += character
index++
continue
}

if ((cell || character) && !preamble) {
subvalue = cell

Expand Down Expand Up @@ -227,22 +216,6 @@ function table(eat, value, silent) {
cell += line.charAt(index + 1)
index++
}

if (character === graveAccent) {
count = 1

while (line.charAt(index + 1) === character) {
cell += character
index++
count++
}

if (!opening) {
opening = count
} else if (count >= opening) {
opening = 0
}
}
}

preamble = false
Expand Down
36 changes: 29 additions & 7 deletions packages/remark-stringify/lib/visitors/inline-code.js
Expand Up @@ -5,8 +5,10 @@ var repeat = require('repeat-string')

module.exports = inlineCode

var space = ' '
var graveAccent = '`'
var graveAccentChar = '`'
var lineFeed = 10 // '\n'
var space = 32 // ' '
var graveAccent = 96 // '`'

// Stringify inline code.
//
Expand All @@ -25,17 +27,37 @@ var graveAccent = '`'
// ```
function inlineCode(node) {
var value = node.value
var ticks = repeat(graveAccent, streak(value, graveAccent) + 1)
var ticks = repeat(graveAccentChar, streak(value, graveAccentChar) + 1)
var start = ticks
var end = ticks
var head = value.charCodeAt(0)
var tail = value.charCodeAt(value.length - 1)
var wrap = false
var index
var length

if (value.charAt(0) === graveAccent) {
start += space
if (head === graveAccent || tail === graveAccent) {
wrap = true
} else if (value.length > 2 && ws(head) && ws(tail)) {
index = 1
length = value.length - 1

while (++index < length) {
if (!ws(value.charCodeAt(index))) {
wrap = true
break
}
}
}

if (value.charAt(value.length - 1) === graveAccent) {
end = space + end
if (wrap) {
start += ' '
end = ' ' + end
}

return start + value + end
}

function ws(code) {
return code === lineFeed || code === space
}
9 changes: 8 additions & 1 deletion test/fixtures/input/code-spans.text
Expand Up @@ -4,7 +4,7 @@ Fix for backticks within HTML tag: <span attr='`ticks`'>like this</span>

Here's how you put `` `backticks` `` in a code span.

Additionally, empty code spans are also supported: ``.
Empty code spans are not supported: ``.

Here’s an example, `` foo ` bar ``.

Expand All @@ -20,3 +20,10 @@ So is this `foo bar
And this `foo `` bar`

And `this\`but this is text`.

Whitespace only: ` `.

Whitespace only: ` `.

Whitespace only: `
`.
16 changes: 0 additions & 16 deletions test/fixtures/input/table-pipes-in-code.text

This file was deleted.

22 changes: 22 additions & 0 deletions test/fixtures/input/tables-with-pipes-and-code.text
@@ -0,0 +1,22 @@
Grave accent in cell:

| A | B |
|--------------|---|
| <kbd>`</kbd> | C |

Escaped grave accent in inline code in cell (is not an escape):

| A |
|-----|
| `\` |

“Empty” inline code:

| 1 | 2 | 3 |
|---|------|----|
| a | `` | |
| b | `` | `` |
| c | ` | ` |
| d | `|` |
| e | `\|` | |
| f | \| | |
2 changes: 1 addition & 1 deletion test/fixtures/tree/backslash-escapes.commonmark.json
Expand Up @@ -3967,7 +3967,7 @@
},
{
"type": "inlineCode",
"value": "\\",
"value": "\\\n",
"position": {
"start": {
"line": 218,
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/tree/backslash-escapes.json
Expand Up @@ -3696,7 +3696,7 @@
},
{
"type": "inlineCode",
"value": "\\",
"value": "\\\n",
"position": {
"start": {
"line": 218,
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/tree/backslash-escapes.nogfm.json
Expand Up @@ -3662,7 +3662,7 @@
},
{
"type": "inlineCode",
"value": "\\",
"value": "\\\n",
"position": {
"start": {
"line": 218,
Expand Down

0 comments on commit 6282051

Please sign in to comment.