| 'use strict' |
| |
| var markdownLineEnding = require('../character/markdown-line-ending.js') |
| |
| var codeText = { |
| name: 'codeText', |
| tokenize: tokenizeCodeText, |
| resolve: resolveCodeText, |
| previous: previous |
| } |
| |
| function resolveCodeText(events) { |
| var tailExitIndex = events.length - 4 |
| var headEnterIndex = 3 |
| var index |
| var enter // If we start and end with an EOL or a space. |
| |
| if ( |
| (events[headEnterIndex][1].type === 'lineEnding' || |
| events[headEnterIndex][1].type === 'space') && |
| (events[tailExitIndex][1].type === 'lineEnding' || |
| events[tailExitIndex][1].type === 'space') |
| ) { |
| index = headEnterIndex // And we have data. |
| |
| while (++index < tailExitIndex) { |
| if (events[index][1].type === 'codeTextData') { |
| // Then we have padding. |
| events[tailExitIndex][1].type = events[headEnterIndex][1].type = |
| 'codeTextPadding' |
| headEnterIndex += 2 |
| tailExitIndex -= 2 |
| break |
| } |
| } |
| } // Merge adjacent spaces and data. |
| |
| index = headEnterIndex - 1 |
| tailExitIndex++ |
| |
| while (++index <= tailExitIndex) { |
| if (enter === undefined) { |
| if (index !== tailExitIndex && events[index][1].type !== 'lineEnding') { |
| enter = index |
| } |
| } else if ( |
| index === tailExitIndex || |
| events[index][1].type === 'lineEnding' |
| ) { |
| events[enter][1].type = 'codeTextData' |
| |
| if (index !== enter + 2) { |
| events[enter][1].end = events[index - 1][1].end |
| events.splice(enter + 2, index - enter - 2) |
| tailExitIndex -= index - enter - 2 |
| index = enter + 2 |
| } |
| |
| enter = undefined |
| } |
| } |
| |
| return events |
| } |
| |
| function previous(code) { |
| // If there is a previous code, there will always be a tail. |
| return ( |
| code !== 96 || |
| this.events[this.events.length - 1][1].type === 'characterEscape' |
| ) |
| } |
| |
| function tokenizeCodeText(effects, ok, nok) { |
| var sizeOpen = 0 |
| var size |
| var token |
| return start |
| |
| function start(code) { |
| effects.enter('codeText') |
| effects.enter('codeTextSequence') |
| return openingSequence(code) |
| } |
| |
| function openingSequence(code) { |
| if (code === 96) { |
| effects.consume(code) |
| sizeOpen++ |
| return openingSequence |
| } |
| |
| effects.exit('codeTextSequence') |
| return gap(code) |
| } |
| |
| function gap(code) { |
| // EOF. |
| if (code === null) { |
| return nok(code) |
| } // Closing fence? |
| // Could also be data. |
| |
| if (code === 96) { |
| token = effects.enter('codeTextSequence') |
| size = 0 |
| return closingSequence(code) |
| } // Tabs don’t work, and virtual spaces don’t make sense. |
| |
| if (code === 32) { |
| effects.enter('space') |
| effects.consume(code) |
| effects.exit('space') |
| return gap |
| } |
| |
| if (markdownLineEnding(code)) { |
| effects.enter('lineEnding') |
| effects.consume(code) |
| effects.exit('lineEnding') |
| return gap |
| } // Data. |
| |
| effects.enter('codeTextData') |
| return data(code) |
| } // In code. |
| |
| function data(code) { |
| if ( |
| code === null || |
| code === 32 || |
| code === 96 || |
| markdownLineEnding(code) |
| ) { |
| effects.exit('codeTextData') |
| return gap(code) |
| } |
| |
| effects.consume(code) |
| return data |
| } // Closing fence. |
| |
| function closingSequence(code) { |
| // More. |
| if (code === 96) { |
| effects.consume(code) |
| size++ |
| return closingSequence |
| } // Done! |
| |
| if (size === sizeOpen) { |
| effects.exit('codeTextSequence') |
| effects.exit('codeText') |
| return ok(code) |
| } // More or less accents: mark as data. |
| |
| token.type = 'codeTextData' |
| return data(code) |
| } |
| } |
| |
| module.exports = codeText |