add markdown for bold, italic, etc
This commit is contained in:
parent
134d666480
commit
7060919f76
104
src/core/MString.js
Normal file
104
src/core/MString.js
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* class for string iterations
|
||||||
|
* that is used by MarkdownParser.js
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default class MString {
|
||||||
|
constructor(text, start) {
|
||||||
|
this.txt = text;
|
||||||
|
this.iter = start || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
done() {
|
||||||
|
return (this.iter >= this.txt.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
moveForward() {
|
||||||
|
this.iter += 1;
|
||||||
|
return (this.iter < this.txt.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
setIter(iter) {
|
||||||
|
this.iter = iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
getChar() {
|
||||||
|
return this.txt[this.iter];
|
||||||
|
}
|
||||||
|
|
||||||
|
slice(start, end) {
|
||||||
|
return this.txt.slice(start, end || this.iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
has(str) {
|
||||||
|
return this.txt.startsWith(str, this.iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
move(cnt) {
|
||||||
|
this.iter += cnt;
|
||||||
|
return (this.iter < this.txt.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
skipSpaces(skipNewlines = false) {
|
||||||
|
for (;this.iter < this.txt.length; this.iter += 1) {
|
||||||
|
const chr = this.txt[this.iter];
|
||||||
|
if (chr !== ' ' && chr !== '\t' && (!skipNewlines || chr !== '\n')) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
countRepeatingCharacters() {
|
||||||
|
const chr = this.getChar();
|
||||||
|
let newIter = this.iter + 1;
|
||||||
|
for (;newIter < this.txt.length && this.txt[newIter] === chr;
|
||||||
|
newIter += 1
|
||||||
|
);
|
||||||
|
return newIter - this.iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
moveToNextLine() {
|
||||||
|
const lineEnd = this.txt.indexOf('\n', this.iter);
|
||||||
|
if (lineEnd === -1) {
|
||||||
|
this.iter = this.txt.length;
|
||||||
|
} else {
|
||||||
|
this.iter = lineEnd + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getLine() {
|
||||||
|
const startLine = this.iter;
|
||||||
|
this.moveToNextLine();
|
||||||
|
return this.txt.slice(startLine, this.iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
getIndent(tabWidth) {
|
||||||
|
let indent = 0;
|
||||||
|
while (this.iter < this.txt.length) {
|
||||||
|
const chr = this.getChar();
|
||||||
|
if (chr === '\t') {
|
||||||
|
indent += tabWidth;
|
||||||
|
} else if (chr === ' ') {
|
||||||
|
indent += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.iter += 1;
|
||||||
|
}
|
||||||
|
return indent;
|
||||||
|
}
|
||||||
|
|
||||||
|
goToCharInLine(chr) {
|
||||||
|
let { iter } = this;
|
||||||
|
for (;
|
||||||
|
iter < this.txt.length && this.txt[iter] !== '\n'
|
||||||
|
&& this.txt[iter] !== chr;
|
||||||
|
iter += 1
|
||||||
|
);
|
||||||
|
if (this.txt[iter] === chr) {
|
||||||
|
this.iter = iter;
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,147 +9,73 @@
|
||||||
* @flow
|
* @flow
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import MString from './MString';
|
||||||
|
|
||||||
let parseMText = () => {};
|
let parseMText = () => {};
|
||||||
|
|
||||||
class MString {
|
|
||||||
constructor(text, start) {
|
|
||||||
this.txt = text;
|
|
||||||
this.iter = start || 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
nextChar() {
|
|
||||||
this.iter += 1;
|
|
||||||
return this.txt[this.iter];
|
|
||||||
}
|
|
||||||
|
|
||||||
done() {
|
|
||||||
return (this.iter >= this.txt.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
moveForward() {
|
|
||||||
this.iter += 1;
|
|
||||||
return (this.iter < this.txt.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
setIter(iter) {
|
|
||||||
this.iter = iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
getChar() {
|
|
||||||
return this.txt[this.iter];
|
|
||||||
}
|
|
||||||
|
|
||||||
slice(start, end) {
|
|
||||||
return this.txt.slice(start, end || this.iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
has(str) {
|
|
||||||
return this.txt.startsWith(str, this.iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
move(cnt) {
|
|
||||||
this.iter += cnt;
|
|
||||||
return (this.iter < this.txt.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
skipSpaces(skipNewlines = false) {
|
|
||||||
for (;this.iter < this.txt.length; this.iter += 1) {
|
|
||||||
const chr = this.txt[this.iter];
|
|
||||||
if (chr !== ' ' && chr !== '\t' && (!skipNewlines || chr !== '\n')) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
countRepeatingCharacters() {
|
|
||||||
const chr = this.getChar();
|
|
||||||
let newIter = this.iter + 1;
|
|
||||||
for (;newIter < this.txt.length && this.txt[newIter] === chr;
|
|
||||||
newIter += 1
|
|
||||||
);
|
|
||||||
return newIter - this.iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
moveToNextLine() {
|
|
||||||
const lineEnd = this.txt.indexOf('\n', this.iter);
|
|
||||||
if (lineEnd === -1) {
|
|
||||||
this.iter = this.txt.length;
|
|
||||||
} else {
|
|
||||||
this.iter = lineEnd + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getLine() {
|
|
||||||
const startLine = this.iter;
|
|
||||||
this.moveToNextLine();
|
|
||||||
return this.txt.slice(startLine, this.iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
getIndent(tabWidth) {
|
|
||||||
let indent = 0;
|
|
||||||
while (this.iter < this.txt.length) {
|
|
||||||
const chr = this.getChar();
|
|
||||||
if (chr === '\t') {
|
|
||||||
indent += tabWidth;
|
|
||||||
} else if (chr === ' ') {
|
|
||||||
indent += 1;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
this.iter += 1;
|
|
||||||
}
|
|
||||||
return indent;
|
|
||||||
}
|
|
||||||
|
|
||||||
goToCharInLine(chr) {
|
|
||||||
let { iter } = this;
|
|
||||||
for (;
|
|
||||||
iter < this.txt.length && this.txt[iter] !== '\n'
|
|
||||||
&& this.txt[iter] !== chr;
|
|
||||||
iter += 1
|
|
||||||
);
|
|
||||||
if (this.txt[iter] === chr) {
|
|
||||||
this.iter = iter;
|
|
||||||
return iter;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse Paragraph till next newline
|
* Parse Paragraph till next newline or breakChar (for recursion)
|
||||||
*/
|
*/
|
||||||
function parseMParagraph(text, opts) {
|
const paraElems = ['*', '~', '+', '_'];
|
||||||
|
function parseMParagraph(text, opts, breakChar) {
|
||||||
const pArray = [];
|
const pArray = [];
|
||||||
let pStart = text.iter;
|
let pStart = text.iter;
|
||||||
let pEnd = 0;
|
let chr = null;
|
||||||
while (!text.done()) {
|
while (!text.done()) {
|
||||||
const chr = text.getChar();
|
chr = text.getChar();
|
||||||
let newElem = null;
|
|
||||||
if (chr === '`') {
|
if (chr === breakChar) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (chr === '\n') {
|
||||||
|
text.moveForward();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chr === '\\') {
|
||||||
|
/*
|
||||||
|
* escape character
|
||||||
|
*/
|
||||||
|
if (pStart !== text.iter) {
|
||||||
|
pArray.push(text.slice(pStart));
|
||||||
|
}
|
||||||
|
pStart = text.iter + 1;
|
||||||
|
text.moveForward();
|
||||||
|
}
|
||||||
|
else if (paraElems.includes(chr)) {
|
||||||
|
/*
|
||||||
|
* bold, cursive, underline, etc.
|
||||||
|
*/
|
||||||
|
const oldPos = text.iter;
|
||||||
|
text.moveForward();
|
||||||
|
const children = parseMParagraph(text, opts, chr);
|
||||||
|
if (text.getChar() === chr) {
|
||||||
|
if (pStart !== oldPos) {
|
||||||
|
pArray.push(text.slice(pStart, oldPos));
|
||||||
|
}
|
||||||
|
pArray.push([chr, children]);
|
||||||
|
pStart = text.iter + 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
text.setIter(oldPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (chr === '`') {
|
||||||
|
/*
|
||||||
|
* inline code
|
||||||
|
*/
|
||||||
const oldPos = text.iter;
|
const oldPos = text.iter;
|
||||||
text.moveForward();
|
text.moveForward();
|
||||||
if (text.goToCharInLine('`')) {
|
if (text.goToCharInLine('`')) {
|
||||||
newElem = ['c', text.slice(oldPos + 1)];
|
if (pStart !== oldPos) {
|
||||||
pEnd = oldPos;
|
pArray.push(text.slice(pStart, oldPos));
|
||||||
|
}
|
||||||
|
pArray.push(['c', text.slice(oldPos + 1)]);
|
||||||
|
pStart = text.iter + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
else if (text.startsWith('**', iter) {
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
if (pEnd) {
|
|
||||||
if (pStart !== pEnd) {
|
|
||||||
pArray.push(text.slice(pStart, pEnd));
|
|
||||||
}
|
|
||||||
pStart = text.iter + 1;
|
|
||||||
pEnd = 0;
|
|
||||||
pArray.push(newElem);
|
|
||||||
}
|
|
||||||
text.moveForward();
|
text.moveForward();
|
||||||
if (chr === '\n') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (pStart !== text.iter) {
|
if (pStart !== text.iter) {
|
||||||
pArray.push(text.slice(pStart));
|
pArray.push(text.slice(pStart));
|
||||||
|
|
|
@ -3,24 +3,42 @@
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const MarkdownParagraph = ({ pArray }) => (
|
const MarkdownParagraph = ({ pArray }) => pArray.map((part) => {
|
||||||
<p>
|
if (!Array.isArray(part)) {
|
||||||
{
|
return part;
|
||||||
pArray.map((part) => {
|
|
||||||
if (!Array.isArray(part)) {
|
|
||||||
return part;
|
|
||||||
}
|
|
||||||
const type = part[0];
|
|
||||||
switch (type) {
|
|
||||||
case 'c':
|
|
||||||
return (<code>{part[1]}</code>);
|
|
||||||
default:
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
</p>
|
const type = part[0];
|
||||||
);
|
switch (type) {
|
||||||
|
case 'c':
|
||||||
|
return (<code>{part[1]}</code>);
|
||||||
|
case '*':
|
||||||
|
return (
|
||||||
|
<strong>
|
||||||
|
<MarkdownParagraph pArray={part[1]} />
|
||||||
|
</strong>
|
||||||
|
);
|
||||||
|
case '~':
|
||||||
|
return (
|
||||||
|
<s>
|
||||||
|
<MarkdownParagraph pArray={part[1]} />
|
||||||
|
</s>
|
||||||
|
);
|
||||||
|
case '+':
|
||||||
|
return (
|
||||||
|
<em>
|
||||||
|
<MarkdownParagraph pArray={part[1]} />
|
||||||
|
</em>
|
||||||
|
);
|
||||||
|
case '_':
|
||||||
|
return (
|
||||||
|
<u>
|
||||||
|
<MarkdownParagraph pArray={part[1]} />
|
||||||
|
</u>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const Markdown = ({ mdArray }) => {
|
const Markdown = ({ mdArray }) => {
|
||||||
return mdArray.map((part) => {
|
return mdArray.map((part) => {
|
||||||
|
@ -54,7 +72,11 @@ const Markdown = ({ mdArray }) => {
|
||||||
}
|
}
|
||||||
/* Paragraph */
|
/* Paragraph */
|
||||||
case 'p': {
|
case 'p': {
|
||||||
return <MarkdownParagraph pArray={part[1]} />;
|
return (
|
||||||
|
<p>
|
||||||
|
<MarkdownParagraph pArray={part[1]} />
|
||||||
|
</p>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
/* Code Block */
|
/* Code Block */
|
||||||
case 'cb': {
|
case 'cb': {
|
||||||
|
|
|
@ -32,7 +32,7 @@ const App = () => {
|
||||||
parseText(evt.target.value, setDuration, setCmDuration, setMd);
|
parseText(evt.target.value, setDuration, setCmDuration, setMd);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<p>Parse-time: {duration}ms / commonmark: {cmDuration}</p>
|
<p>Parse-time: {duration}ms / commonmark: {cmDuration}ms</p>
|
||||||
<Markdown mdArray={md} />
|
<Markdown mdArray={md} />
|
||||||
<textarea
|
<textarea
|
||||||
cols="100"
|
cols="100"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user